:root {
  --bg-top: #1d2e31;
  --bg-bottom: #253538;
  --panel: rgba(34, 47, 50, 0.96);
  --dock: rgba(40, 55, 58, 0.95);
  --border: rgba(120, 175, 165, 0.28);
  --ink: #d8eae8;
  --muted: #7eaaa6;
  /* The fill behind a selected card. Darkened from #1a8a7a, which put its near-white
     label at 4.13:1 — under the 4.5:1 AA needs for text this size. #177a6c reads 5.07:1
     and is close enough that nothing else in the palette had to move. */
  --teal-900: #177a6c;
  --teal-700: #22a090;
  --focus: #4db8ff;
  --focus-glow: #ffd166;
  --shadow: 0 16px 40px rgba(0, 0, 0, 0.55);
  --radius-xl: 24px;
  --radius-lg: 18px;
  --radius-md: 14px;
  --radius-sm: 10px;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  overflow: hidden;
}

body {
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(ellipse at 30% 0%, rgba(180, 140, 40, 0.14), transparent 40%),
    radial-gradient(ellipse at 80% 100%, rgba(10, 60, 70, 0.35), transparent 45%),
    linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bottom) 100%);
  color: var(--ink);
  font-family: Roboto, Arial, sans-serif;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

button, input { font: inherit; }
button { cursor: pointer; }

button:focus-visible,
input:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--focus-glow);
}

/* FULL BLEED (Ben): the scene runs to the glass. Every inset from the window edge
   down to the canvas is gone — no app padding, no panel frame, no rounded corners —
   and the year strip runs to the edges too. Only the on-canvas floats keep a small
   inset of their own so they do not touch the edge. */
#sim-app {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 0;
}

#stage-panel {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0;
  padding: 0;
  border-radius: 0;
  border: 0;
  background: var(--panel);
  overflow: hidden;
}

#canvas-frame {
  position: relative;
  min-height: 0;
  overflow: hidden;
  border-radius: 0;
  background:
    radial-gradient(ellipse at 50% 2%, rgba(255, 226, 160, 0.30), transparent 42%),
    radial-gradient(ellipse at 50% 100%, rgba(70, 108, 116, 0.42), transparent 52%),
    linear-gradient(180deg, #47606a 0%, #33474f 52%, #22333a 100%);
  box-shadow: inset 0 0 0 1px rgba(150, 195, 190, 0.20);
}

#sim-canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

/* The canvas is the sim's main control surface — tabindex=0, role=application, and the
   depth, trees and channel keys all live on it — so it has to show when it holds focus.
   Drawn inside the frame, in the light blue that reads against a dark 3D scene, with a
   soft inner glow so the ring survives wherever the diorama happens to be pale. */
#sim-canvas:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: -3px;
  box-shadow: inset 0 0 0 7px rgba(77, 184, 255, 0.30);
}

/* ── Year track ──────────────────────────────────────────────────────────── */

#year-track {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 14px;
  pointer-events: none;
}

#year-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
}

#year-head strong {
  font-size: 18px;
  font-weight: 700;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

#year-head span {
  font-size: 14px;
  font-weight: 500;
  color: #dfeeea;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

#year-bar {
  position: relative;
  height: 22px;
  border-radius: 11px;
  background: rgba(12, 22, 24, 0.55);
  border: 1px solid rgba(190, 225, 218, 0.34);
  overflow: hidden;
}

#year-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: linear-gradient(90deg, rgba(34, 160, 144, 0.85), rgba(120, 200, 120, 0.85));
  transition: width 0.1s linear;
}

#year-marker {
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: 0%;
  width: 3px;
  border-radius: 2px;
  background: #ffd166;
  box-shadow: 0 0 6px rgba(255, 209, 102, 0.9);
  transition: left 0.1s linear;
}

.year-band {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid rgba(190, 225, 218, 0.26);
}

.year-band:last-child { border-right: none; }

.year-band span {
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: #eaf6f3;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
  white-space: nowrap;
  overflow: hidden;
  padding: 0 4px;
}

@media (max-width: 640px) {
  .year-band span { display: none; }
}

/* Labels that sit on the diorama and name the control underneath them. Sentence case, not
   uppercase: these are words a third grader reads and says out loud, and the two badges
   have to match each other. */
.interaction-hint {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(12, 22, 24, 0.78);
  border: 1px solid rgba(130, 180, 170, 0.26);
  color: #cfe8e2;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.2px;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.interaction-hint.hidden { opacity: 0; }

/* Setup controls step off the diorama while a year is running. Not merely dimmed: a
   greyed control still invites a press, and there is nothing here a student should be
   pressing until the year is over. */
.interaction-hint.locked {
  opacity: 0;
  pointer-events: none;
}

/* Anchored to a place in the 3D scene rather than a corner of the frame; JS sets
   left/top from the projected world point each frame. */
.scene-badge {
  top: 0;
  left: 0;
  right: auto;
  transform: translate(-50%, -50%);
  border-color: rgba(160, 216, 232, 0.45);
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* The depth badge is a real control, not a caption: it is a second grab handle for the
   knob it sits beside, so it takes pointer events and drags vertically. It is a much
   bigger target than the knob, which matters for the age band. */
.depth-badge {
  pointer-events: auto;
  gap: 4px;
  padding: 4px 8px;
  cursor: ns-resize;
  touch-action: none;
  user-select: none;
}

/* The channel badge presses too, so all three scene labels are handles rather than one
   caption among two controls — and a label that takes hover is the only way it can carry a
   tooltip like the other two. The groove underneath still works; this is a second target. */
.channel-badge {
  pointer-events: auto;
  cursor: pointer;
  user-select: none;
}

/* The trees badge is a tap target: one press moves to the next of the three states. */
.trees-badge {
  pointer-events: auto;
  gap: 7px;
  padding: 4px 8px;
  cursor: pointer;
  user-select: none;
}

/* Carousel dots: how many states there are, and which one you are on. */
.badge-dots {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-left: 2px;
  border-left: 1px solid rgba(160, 216, 232, 0.28);
  margin-left: 1px;
}

.badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  border: 1px solid rgba(190, 230, 240, 0.6);
  background: transparent;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.badge-dot:first-child { margin-left: 3px; }
.badge-dot.on { background: #eafaff; border-color: #eafaff; }

.depth-badge .hint-label strong,
.trees-badge .hint-label strong {
  color: #eafaff;
  font-weight: 700;
}

.scene-badge.hot {
  background: rgba(30, 74, 84, 0.92);
  border-color: #9fd8e8;
  color: #eafaff;
}

/* ── Control tooltip ─────────────────────────────────────────────────────── */

#tip {
  position: fixed;
  z-index: 60;
  max-width: 290px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  background: #08181a;
  border: 1px solid rgba(150, 200, 192, 0.4);
  color: #eaf7f4;
  font-size: 13.5px;
  line-height: 1.45;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.12s ease, transform 0.12s ease;
}

#tip.show {
  opacity: 1;
  transform: translateY(0);
}

/* ── Controls dock ───────────────────────────────────────────────────────── */

#controls-dock {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-lg);
  background: var(--dock);
  border: 1px solid var(--border);
}

.control-card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 8px 12px 10px;
  border-radius: var(--radius-md);
  background: rgba(12, 20, 22, 0.55);
  border: 1px solid rgba(90, 140, 130, 0.16);
}

.card-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--muted);
}

.seg-btns {
  display: flex;
  gap: 5px;
}

.seg-btn {
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(110, 160, 150, 0.26);
  background: rgba(30, 44, 46, 0.9);
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.seg-btn:hover { background: rgba(42, 62, 64, 0.95); }

.seg-btn.active {
  background: var(--teal-900);
  border-color: var(--teal-700);
  color: #f2fffc;
}

/* ── Species toggles ─────────────────────────────────────────────────────── */

.species-card { flex: 1 1 320px; }

.species-btns {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.species-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px 5px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(110, 160, 150, 0.26);
  background: rgba(30, 44, 46, 0.9);
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.species-btn canvas {
  display: block;
  width: 38px;
  height: 28px;
  border-radius: 5px;
  /* A pool-water ground behind the animal, since these are all aquatic forms. */
  background: rgba(74, 144, 168, 0.42);
}

.species-btn:hover:not(:disabled) { background: rgba(42, 62, 64, 0.95); }

/* Dimmed while a year runs, not hidden: these cards double as the key for what is in the
   pool, and that is exactly what a student wants to read WHILE watching the year. */
.species-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.species-btn.active {
  background: var(--teal-900);
  border-color: var(--teal-700);
  color: #f2fffc;
}

/* ── Arrivals legend ─────────────────────────────────────────────────────── */
/* Reads as a key, not a control: no fill, no pressed state, dimmed when the animal is
   not in the pool. Dimming rather than hiding so a student can see these exist and learn
   what brings them. */

/* Stacked on purpose: the toggles wrap unpredictably, and a vertical divider between
   them and the arrivals ended up orphaned at the right edge whenever they did. */
.species-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.arrival-split {
  height: 1px;
  margin: 2px 0 0;
  background: rgba(140, 190, 180, 0.26);
}

.arrival-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.arrival-heading {
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.3px;
  color: var(--muted);
}

.arrival-items {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* Dimming the whole row to 0.38 put this text at 1.99:1, which is unreadable and well
   under AA — and it is a key, so it has to be read in exactly the state that says the
   animal is absent. The absent/present difference is carried by the ICON instead, which
   no contrast rule applies to, while the words stay at full opacity. */
.arrival-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 2px;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  transition: color 0.2s ease;
}

.arrival-item.here { color: #e6f5f1; }

.arrival-item.here canvas {
  opacity: 1;
  filter: none;
}

.arrival-item canvas {
  display: block;
  width: 38px;
  height: 28px;
  border-radius: 5px;
  background: rgba(74, 144, 168, 0.42);
  opacity: 0.42;
  filter: saturate(0.3);
  transition: opacity 0.2s ease, filter 0.2s ease;
}

.arrival-item.here canvas {
  opacity: 1;
  filter: none;
}

.arrival-item .arrival-note {
  font-size: 12.5px;
  font-weight: 400;
  color: var(--muted);
}

/* ── Info dialog ─────────────────────────────────────────────────────────── */

/* Verbatim copy of the boilerplate block, not a per-sim restyle (machine-verifiable
   COLOR-2 / TYPO-4). The dialog is Tuva Sims chrome, not the sim's: the shared toolbar
   injects #info-dialog-scoped rules after this stylesheet and wins on specificity, so a
   per-sim recolor here is dead weight that only drifts. This sim used to carry a green
   header, its own tab pills and its own dialog typography. */
#info-dialog {
  border: none;
  border-radius: 12px;
  padding: 0;
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 80px);
  overflow: hidden;
  margin: auto;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.22);
  background: #ffffff;
}

#info-dialog::backdrop {
  background: rgba(30, 16, 48, 0.55);
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: #5c4738;
  color: #ffffff;
}

.dialog-header h2 {
  font-size: 16px;
  font-weight: 600;
}

#dialog-close-btn {
  background: transparent;
  border: none;
  color: #ffffff;
  font-size: 18px;
  cursor: pointer;
  width: 32px;
  height: 32px;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

#dialog-close-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

#dialog-close-btn:focus-visible {
  outline: 3px solid var(--focus-glow);
  outline-offset: 2px;
}

.dialog-tabs {
  display: flex;
  border-bottom: 2px solid #E5EAE9;
  background: #F8FBFB;
}

.tab-btn {
  flex: 1;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -2px;
  padding: 10px 0;
  font-family: Roboto, Arial, sans-serif;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.tab-btn:hover {
  color: #5c4738;
}

.tab-btn.active,
.tab-btn[aria-selected="true"] {
  color: #5c4738;
  border-bottom-color: #5c4738;
}

.tab-btn:focus-visible {
  outline: 3px solid var(--focus-glow);
  outline-offset: -3px;
}

.dialog-body {
  padding: 16px 20px;
  overflow-y: auto;
  max-height: calc(100vh - 240px);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
}

.dialog-body h3 {
  font-size: 14px;
  font-weight: 600;
  color: #5c4738;
  margin-top: 14px;
  margin-bottom: 6px;
}

.dialog-body h3:first-child {
  margin-top: 0;
}

.dialog-body p {
  margin-bottom: 8px;
}

.dialog-body ul,
.dialog-body ol {
  padding-left: 20px;
  margin-bottom: 8px;
}

.dialog-body li {
  margin-bottom: 4px;
}

#info-dialog summary {
  cursor: pointer;
  font-weight: 600;
  color: #5c4738;
  margin-top: 12px;
}

.standard-tag {
  display: inline-block;
  padding: 1px 7px;
  margin-right: 5px;
  border-radius: 5px;
  background: #e7f1f0;
  color: #004445;
  font-weight: 600;
  font-size: 13px;
}

@media (max-width: 720px) {
  #controls-dock { gap: 0; padding: 0; }   /* full bleed holds on narrow screens too */
  .control-card { padding: 6px 9px 8px; }
  .seg-btn { padding: 6px 9px; font-size: 12px; }
  .species-btn { font-size: 14px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THREE CARDS ACROSS THE BOTTOM, and one colour system running through them.

   The year the frog had, the year it was given, and the body that lived it were
   spread between an overlay on the canvas and a dock underneath, which put the
   cause, the record and the body in three different places. Proximity does the
   work now, and a shared hue does the rest: each lever, the state it drives and
   the structure it tests are the same colour, so the connection is seen rather
   than explained.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* A type scale with a 12px floor, which is what the responsive-layout playbook
     already requires for content text; this sheet had 25 declarations under it.
     Size differences are made upward from the floor, never downward. */
  --fs-sm: 12px;    /* labels, notes, band text, month and season names */
  --fs-md: 13px;    /* structure names, lever names */
  --fs-lg: 15px;    /* card headings */

  --hue-gut:   #6fbf5a;   /* the gut, feeding, and the insect lever   */
  --hue-skin:  #3fb5b5;   /* the skin, sheltering, and the rain lever */
  --hue-breed: #b57cd8;   /* ovaries and vocal sac, the pool lever    */
  --hue-liver: #8fbcd9;   /* the liver, freezing, and autumn          */
  --hue-legs:  #d98a3c;   /* shared machinery: no lever of its own    */
  --hue-fat:   #e8b23c;   /* likewise                                */
}

#controls-dock {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: stretch;
  gap: 0;
  padding: 0;
}
.card {
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* 4px sides, not 8: enough that the row labels are not welded to the glass, little
     enough that the year strip reaches it */
  padding: 4px 4px 5px;
  border-radius: 0;
  background: rgba(12, 20, 22, 0.5);
  /* one hairline along the top is all the separation the strip needs from the scene;
     side and bottom borders would re-draw the frame full bleed just removed */
  border: 0;
  border-top: 1px solid rgba(90, 140, 130, 0.18);
}
.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.card-head h3 { margin: 0; font-size: var(--fs-lg); font-weight: 600; letter-spacing: .02em; }
.card-note { font-size: var(--fs-sm); opacity: 0.6; }
.card-note strong { font-weight: 600; opacity: 0.95; }

#dock-actions {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Card 1: the year ─────────────────────────────────────────────────────── */
#gantt-wrap { position: relative; width: 100%; }
#year-strip { display: flex; flex-direction: column; gap: 2px; }
/* A narrow label column, so three rows can say which is which without a legend. */
.strip-row {
  display: grid;
  grid-template-columns: 62px 1fr;
  align-items: center;
  gap: 7px;
}
.strip-label { text-align: right; font-size: var(--fs-sm); opacity: 0.6; line-height: 1.1; }
.strip-row .cells { display: grid; }
.strip-row.seasons .cells > div {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: .06em;
  opacity: 0.5;
  border-left: 1px solid rgba(255, 255, 255, 0.10);
  padding-left: 4px;
}
.strip-row.months .cells > div { font-size: var(--fs-sm); opacity: 0.55; }
/* Shorter per row now that the card holds three of them, and it no longer has to
   double as an editing surface with touch targets. */
.strip-track {
  position: relative;
  height: 20px;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.05);
}
.strip-track .cell { border-left: 1px solid rgba(255, 255, 255, 0.06); }
/* The two conditions that decide what the frog can do, drawn into the record. */
.strip-track .cell.dry {
  background: repeating-linear-gradient(45deg,
    rgba(214, 178, 92, 0.20), rgba(214, 178, 92, 0.20) 3px,
    rgba(214, 178, 92, 0.06) 3px, rgba(214, 178, 92, 0.06) 6px);
}
.strip-track .cell.cold { background: rgba(150, 200, 235, 0.12); }

.band {
  position: absolute;
  top: 2px;
  height: 16px;
  border-radius: 4px;
  padding: 0 5px;
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: #08171a;
  white-space: nowrap;
  overflow: hidden;
  /* Lever changes SLIDE and GROW the bands instead of teleporting them (Ben: an instant
     repaint invites change blindness). Long enough to see, short enough not to lag the
     click; disabled under reduced motion. */
  transition: left 480ms ease, width 480ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .band { transition: none; }
}
.band .gl { width: 11px; height: 11px; flex: 0 0 11px; }
/* Making eggs is not a state - it runs behind whatever else is happening - so it is
   a strip along the bottom rather than a band of its own. */
/* The eggs sliver is gone: making eggs has a row of its own, because nobody could
   read a 4px strip along the bottom of somebody else's band. */
.band.running { box-shadow: 0 0 0 2px #fff, 0 0 9px 2px rgba(255, 255, 255, 0.45); z-index: 2; }

.hue-gut   { background: var(--hue-gut); }
.hue-skin  { background: var(--hue-skin); }
.hue-breed { background: var(--hue-breed); }
.hue-liver { background: var(--hue-liver); }
.hue-legs  { background: var(--hue-legs); }
.hue-fat   { background: var(--hue-fat); }

#run-cursor {
  position: absolute;
  display: none;
  background: rgba(255, 255, 255, 0.13);
  border-radius: 2px;
  pointer-events: none;
  z-index: 3;
  top: 0; width: 10px; height: 0;
}
#run-cursor::after {
  content: '';
  position: absolute;
  left: 50%; top: 0; bottom: 0;
  width: 2px; margin-left: -1px;
  background: #ff5a4d;
  border-radius: 1px;
}

/* ── Card 2: the levers ───────────────────────────────────────────────────── */
/* TWO BY TWO, not four stacked. Four rows of label-above-buttons came to 259px and
   dragged all three cards to 296px, taking half the screen from the scene. Paired up,
   the card is 112px and the scene keeps its height. */
#env-panel { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 8px; }
.env-row {
  display: block;
  min-width: 0;
  padding-left: 6px;
  border-left: 3px solid transparent;
  background: none;
}
.env-row.hue-gut   { border-left-color: var(--hue-gut); background: none; }
.env-row.hue-skin  { border-left-color: var(--hue-skin); background: none; }
.env-row.hue-breed { border-left-color: var(--hue-breed); background: none; }
.env-row.hue-liver { border-left-color: var(--hue-liver); background: none; }
.env-label b { display: block; font-size: var(--fs-md); font-weight: 500; line-height: 1.15; }
.env-label i { font-size: var(--fs-sm); font-style: normal; opacity: 0.6; }
.seg { display: flex; margin-top: 3px; border-radius: 6px; overflow: hidden;
  border: 1px solid var(--border); }
.seg-btn {
  flex: 1 1 0;
  font: inherit; font-size: var(--fs-sm);
  padding: 3px 5px; min-height: 27px;
  border: 0; background: rgba(12, 20, 22, 0.6); color: var(--ink); cursor: pointer;
}
.seg-btn + .seg-btn { border-left: 1px solid var(--border); }
.seg-btn.on { background: #0d6b5c; font-weight: 700; }

/* ── Card 3: the body ─────────────────────────────────────────────────────── */
#parts-panel { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 8px; }
.part-col { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.col-head {
  font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .07em;
  opacity: 0.5; padding-left: 2px;
}
.part-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  width: 100%;
  padding: 3px 6px;
  border: 1px solid transparent;
  border-left: 3px solid transparent;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
}
.part-row:hover { background: rgba(255, 255, 255, 0.12); }
.part-row.hue-gut   { border-left-color: var(--hue-gut); background: rgba(255,255,255,.05); }
.part-row.hue-skin  { border-left-color: var(--hue-skin); background: rgba(255,255,255,.05); }
.part-row.hue-breed { border-left-color: var(--hue-breed); background: rgba(255,255,255,.05); }
.part-row.hue-liver { border-left-color: var(--hue-liver); background: rgba(255,255,255,.05); }
.part-row.hue-legs  { border-left-color: var(--hue-legs); background: rgba(255,255,255,.05); }
.part-row.hue-fat   { border-left-color: var(--hue-fat); background: rgba(255,255,255,.05); }
.part-name { font-size: var(--fs-md); font-weight: 500; }
.part-where { display: none; }      /* the column heading already says it */
.part-bar { height: 5px; border-radius: 3px; background: rgba(255,255,255,.14); overflow: hidden; }
.part-bar > i { display: block; height: 100%; width: 0; transition: width .14s linear; }
#bar-fat { background: var(--hue-fat); }
#bar-gut { background: var(--hue-gut); }
#bar-gly { background: var(--hue-liver); }
#bar-egg { background: var(--hue-breed); }
.part-row.picked { box-shadow: inset 0 0 0 1px var(--focus); }
/* The working glow carries the structure's OWN hue, not a colourless white: one colour runs
   through the lever, the timeline block and the structure, and this is the third of the three.
   Each row already carries its hue-X class; --c localizes it for the shadow. */
.part-row.hue-gut   { --c: var(--hue-gut); }
.part-row.hue-skin  { --c: var(--hue-skin); }
.part-row.hue-breed { --c: var(--hue-breed); }
.part-row.hue-liver { --c: var(--hue-liver); }
.part-row.hue-legs  { --c: var(--hue-legs); }
.part-row.hue-fat   { --c: var(--hue-fat); }
.part-row.working {
  background: color-mix(in srgb, var(--c, #ffffff) 20%, transparent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--c, #ffffff) 55%, transparent);
}
/* A lever was just moved: its target structure answers in the same hue. */
@keyframes part-pulse {
  0%   { box-shadow: 0 0 0 0 var(--c, #fff); }
  45%  { box-shadow: 0 0 0 4px color-mix(in srgb, var(--c, #fff) 65%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.part-row.pulse { animation: part-pulse 1.3s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .part-row.pulse { animation: none; outline: 2px solid var(--c, #fff); }
}
#part-detail {
  margin: 6px 0 0; font-size: var(--fs-sm); line-height: 1.35;
  opacity: 0; max-height: 0; overflow: hidden; transition: opacity .15s;
}
#part-detail.shown { opacity: 0.95; max-height: 9em; }
#doing-now { margin: 5px 0 0; font-size: var(--fs-sm); line-height: 1.3; opacity: 0.8; min-height: 1.3em; }

@media (max-width: 900px) {
  #controls-dock { grid-template-columns: 1fr 1fr; }
  .card-year { grid-column: 1 / -1; }
}

/* Carried forward from the deleted authoring CSS: the glyph inside a band. */
.gl { width: 13px; height: 13px; flex: 0 0 13px; display: block; }
.band .gl { width: 12px; height: 12px; flex: 0 0 12px; opacity: 0.85; }

/* 12px text needs more room than 9.5px did. */
.strip-track { height: 22px; }
.band { height: 18px; }
.strip-row { grid-template-columns: 74px 1fr; }
.part-row { padding: 4px 7px; }
.part-bar { height: 6px; }
.col-head { letter-spacing: .05em; }


/* ── MOMENT CARD ────────────────────────────────────────────────────────────
   The sim's own pauses: a small card over the lower canvas while the scene keeps
   animating behind it. Deliberately compact — the frog is the exhibit, the card is
   the label beside it. */
#moment-card {
  position: absolute;
  left: 50%;
  top: 12px;
  transform: translateX(-50%);
  width: max-content;
  max-width: min(420px, calc(100% - 28px));
  background: rgba(16, 26, 27, 0.92);
  border: 1px solid #3c4a4c;
  border-radius: 10px;
  padding: 10px 14px 12px;
  z-index: 25;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.4);
}
#moment-card h3 { margin: 0 0 4px; font-size: 14px; color: #ffd166; }
#moment-card p { margin: 0 0 8px; font-size: var(--fs-sm); line-height: 1.45; color: var(--ink); }
#moment-continue {
  font: 600 12px Roboto, Arial, sans-serif;
  color: #10221f;
  background: #ffd166;
  border: none;
  border-radius: 6px;
  padding: 5px 14px;
  cursor: pointer;
}
#moment-continue:focus-visible { outline: 3px solid var(--focus-glow); outline-offset: 2px; }
#moment-xray {
  font: 600 12px Roboto, Arial, sans-serif;
  color: var(--ink);
  background: transparent;
  border: 1px solid #4a5a5c;
  border-radius: 6px;
  padding: 4px 12px;
  margin-left: 8px;
  cursor: pointer;
}
#moment-xray[aria-pressed="true"] { background: #2c4a4e; border-color: var(--hue-skin); color: #d8f4f2; }
#moment-xray:focus-visible { outline: 3px solid var(--focus-glow); outline-offset: 2px; }
#pause-wrap {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-sm);
  color: var(--muted);
  cursor: pointer;
}
#pause-wrap input { accent-color: var(--hue-skin); }

/* ── INSIDE-VIEW FRAME ──────────────────────────────────────────────────────
   Shown only while the anatomy view is up. A vignette pulls the eye to the frog,
   corner brackets frame it where it stands on screen (positioned per frame from
   the frog's projected position), and a chip says what mode this is — the answer
   to "what's going on?" the first time the sim enters the X-ray by itself. */
#xray-frame {
  position: absolute;
  inset: 0;
  z-index: 20;              /* over the canvas, under the moment card (25) */
  pointer-events: none;
}
#xf-vignette {
  position: absolute;
  inset: 0;
  /* centre + radius set from JS as --cx/--cy/--cr, in % of the frame */
  background: radial-gradient(circle at var(--cx, 50%) var(--cy, 45%),
    transparent var(--cr, 22%), rgba(8, 14, 15, 0.38) calc(var(--cr, 22%) + 26%));
}
#xf-box {
  position: absolute;       /* left/top/width/height set from JS, centred on the frog */
  transition: opacity 0.35s ease;
}
.xf-c {
  position: absolute;
  width: 22%;
  height: 22%;
  max-width: 34px;
  max-height: 34px;
  border: 0 solid rgba(236, 244, 244, 0.9);
  filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.55));
}
.xf-tl { top: 0;    left: 0;   border-top-width: 2px;    border-left-width: 2px;  border-top-left-radius: 6px; }
.xf-tr { top: 0;    right: 0;  border-top-width: 2px;    border-right-width: 2px; border-top-right-radius: 6px; }
.xf-bl { bottom: 0; left: 0;   border-bottom-width: 2px; border-left-width: 2px;  border-bottom-left-radius: 6px; }
.xf-br { bottom: 0; right: 0;  border-bottom-width: 2px; border-right-width: 2px; border-bottom-right-radius: 6px; }
#xf-chip {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 10px);
  transform: translateX(-50%);
  width: max-content;
  padding: 6px 18px;
  border-radius: 999px;
  background: rgba(16, 26, 27, 0.92);
  border: 1px solid rgba(236, 244, 244, 0.6);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .04em;
  color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
/* ease in rather than pop: the brackets settle onto the frog */
#xray-frame.xf-in #xf-box { animation: xfSettle 0.45s ease-out; }
@keyframes xfSettle {
  from { transform: scale(1.18); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #xray-frame.xf-in #xf-box { animation: none; }
}

/* ── SOUND TOGGLE (in the shared toolbar, animal_sense_explorer's pattern) ──── */
#audio-toggle-btn svg { stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
#audio-toggle-btn .audio-icon-on  { display: none; }
#audio-toggle-btn .audio-icon-off { display: block; }
#audio-toggle-btn.audio-on .audio-icon-off { display: none; }
#audio-toggle-btn.audio-on .audio-icon-on  { display: block; }

/* ── HUD PROTOTYPES (?hud=lines / ?hud=plate) ───────────────────────────────
   Two candidate answers to the same problem: the body-panel bars never met the
   animated frog. "lines" is the game-HUD sketch — the body card's rows live
   top-left on the canvas, and during X-ray a leader line runs from each row to
   its structure. "plate" is the specimen-plate counter — only the true resources
   sit in the corner, and during X-ray each structure carries its own labelled
   chip. Both retire the bottom body card so the canvas gets its height back. */
.hud-mode #controls-dock { grid-template-columns: minmax(0, 1fr); }
/* The body card is screen-reader-only: clipped, not display:none, so assistive tech
   still reads the full structure rows the sighted user now gets as plate chips. Its
   buttons carry tabindex=-1 so keyboard focus never lands on invisible controls. */
.hud-mode .card-body {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

#hud-strip {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 21;
  display: flex;
  flex-direction: column;
  gap: 3px;
  /* no overflow clipping: the row tooltips hang below the strip */
  padding: 7px 9px 8px;
  border-radius: 10px;
  background: rgba(16, 26, 27, 0.78);
  border: 1px solid rgba(90, 140, 130, 0.25);
  min-width: 138px;
}
#hud-strip .hud-head {
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: 0.55;
  margin-bottom: 2px;
}
.hud-row {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 7px;
  padding: 2px 4px 2px 6px;
  border-left: 3px solid var(--row-hue, #888);
  border-radius: 4px;
  font-size: var(--fs-sm);
  line-height: 1.25;
}
.hud-row.no-bar { grid-template-columns: auto; }
.hud-row.working { background: rgba(255, 255, 255, 0.08); }
.hud-row .hud-bar {
  display: block;
  height: 5px;
  min-width: 46px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.hud-row .hud-bar i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 3px;
  background: var(--row-hue, #888);
  transition: width 0.3s ease;
}
/* EQUAL TRACKS (Ben): the label column was auto per row, so "Fat store" left a shorter
   bar than "Liver" and the fills could not be compared. Subgrid shares one label column
   across the rows; browsers without it keep the old per-row layout. */
@supports (grid-template-columns: subgrid) {
  #hud-strip { display: grid; grid-template-columns: max-content 1fr; }
  #hud-strip .hud-head { grid-column: 1 / -1; }
  .hud-row { grid-column: 1 / -1; grid-template-columns: subgrid; }
  .hud-row.no-bar { grid-column: 1 / -1; grid-template-columns: 1fr; }
}
/* Teachable rows (Ben): each is focusable, and hover or keyboard focus opens one plain
   sentence saying what the bar measures. */
.hud-row[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  left: 0;
  top: calc(100% + 5px);
  width: 200px;
  padding: 6px 9px;
  border-radius: 8px;
  background: rgba(12, 20, 21, 0.95);
  border: 1px solid rgba(90, 140, 130, 0.4);
  color: var(--ink, #e8e4d6);
  font-size: var(--fs-sm);
  line-height: 1.35;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
  z-index: 30;
}
.hud-row[data-tip]:hover::after,
.hud-row[data-tip]:focus-visible::after { opacity: 1; }
.hud-row:focus-visible { outline: 2px solid var(--row-hue, #888); outline-offset: 1px; }

#hud-svg {
  position: absolute;
  inset: 0;
  z-index: 20;
  pointer-events: none;
}

#hud-chips { position: absolute; inset: 0; z-index: 21; pointer-events: none; }
.hud-chip {
  position: absolute;
  transform: translate(-50%, -135%);
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(16, 26, 27, 0.86);
  border: 1px solid var(--row-hue, #888);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
}
#chip-note {
  position: absolute;
  z-index: 26;
  width: 215px;
  padding: 7px 10px;
  border-radius: 8px;
  border: 1px solid rgba(90, 140, 130, 0.4);
  border-left: 3px solid var(--note-hue, #888);
  background: rgba(12, 20, 21, 0.94);
  color: var(--ink, #e8e4d6);
  font-size: var(--fs-sm);
  line-height: 1.4;
  pointer-events: none;
}
#chip-note b { color: var(--note-hue, #ddd); }
.hud-chip .hud-bar {
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.14);
  overflow: hidden;
}
.hud-chip .hud-bar i { display: block; height: 100%; width: 0; background: var(--row-hue, #888); }
.hud-chip.focused {
  background: rgba(28, 46, 46, 0.95);
  box-shadow: 0 0 8px var(--row-hue, #888);
}
.hud-chip:focus-visible { outline: 2px solid #ffd166; outline-offset: 2px; }

/* ── THE KIND OF YEAR, floated top-right over the canvas ────────────────────
   Docked at the bottom, the folded summary wasted a whole card of space (Ben).
   Here it starts as four levers stacked vertically and SHRINKS — animated via the
   grid-rows trick — down to the summary list once the year starts. */
#env-float {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 22;
  width: 236px;
  padding: 7px 10px 8px;
  border-radius: 10px;
  background: rgba(16, 26, 27, 0.84);
  border: 1px solid rgba(90, 140, 130, 0.25);
}
#env-float .card-head { display: block; margin-bottom: 5px; }
#env-float .card-head h3 { font-size: var(--fs-md); white-space: nowrap; }
#env-float .card-note { display: block; font-size: 10px; margin-top: 1px; }
#env-float #env-panel { grid-template-columns: 1fr; gap: 7px; }
#env-float .env-body {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 0.5s ease;
}
#env-float .env-inner { overflow: hidden; min-height: 0; }
#env-float.folded .env-body { grid-template-rows: 0fr; }
#env-float.folded .env-inner { visibility: hidden; transition: visibility 0s 0.5s; }
#env-float.folded .card-note { visibility: hidden; }
@media (prefers-reduced-motion: reduce) {
  #env-float .env-body { transition: none; }
}
#env-summary {
  margin: 2px 0 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--fs-sm);
  line-height: 1.35;
  animation: envSumIn 0.4s ease 0.3s backwards;
}
@keyframes envSumIn { from { opacity: 0; } }
#env-summary .env-sum { opacity: 0.9; }
#env-summary .env-sum b { font-weight: 600; color: var(--sum-hue, var(--ink)); margin-right: 3px; }

/* ── SPOTLIGHT HIERARCHY on the plate ───────────────────────────────────────
   While a moment (or a tap) puts one structure on stage, its chip pulses on the
   same ~1 s clock as the organ's 3D glow and the others recede — still legible,
   still tappable, no longer competing. */
.hud-chip.dim { opacity: 0.45; }
.hud-chip.dim:hover, .hud-chip.dim:focus-visible { opacity: 0.9; }
.hud-chip.focused {
  font-weight: 600;
  animation: chipPulse 0.98s ease-in-out infinite;
}
@keyframes chipPulse {
  0%, 100% { box-shadow: 0 0 4px var(--row-hue, #888); }
  50%      { box-shadow: 0 0 15px var(--row-hue, #888); }
}
@media (prefers-reduced-motion: reduce) {
  .hud-chip.focused { animation: none; box-shadow: 0 0 10px var(--row-hue, #888); }
}

/* ── KEY MOMENTS ON THE TIMELINE ────────────────────────────────────────────
   Ben's design: a thin hue-coloured line cuts across all three rows at each
   pause's week, and a high-contrast diamond sits on the line, centred in the
   row the moment belongs to. Not interactive; the active pair pulses on the
   same ~1 s clock as the rest of the spotlight system. */
#moment-markers { position: absolute; inset: 0; pointer-events: none; }
.moment-line {
  position: absolute;
  width: 2px;
  transform: translateX(-50%);
  background: var(--mark-hue, #ffd166);
  opacity: 0.30;
  border-radius: 1px;
  transition: opacity 0.3s ease;
}
.moment-line.active { opacity: 0.85; box-shadow: 0 0 5px var(--mark-hue, #ffd166); }
.moment-line.passed { opacity: 0.12; }
.moment-mark {
  position: absolute;
  width: 9px;
  height: 9px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: var(--mark-hue, #ffd166);
  border: 1.5px solid #fff;
  border-radius: 1.5px;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
  opacity: 0.95;
  z-index: 2;
  transition: opacity 0.3s ease;
}
.moment-mark.active { animation: markPulse 0.98s ease-in-out infinite; }
@keyframes markPulse {
  0%, 100% { box-shadow: 0 0 2px var(--mark-hue, #ffd166); transform: translate(-50%, -50%) rotate(45deg) scale(1.1); }
  50%      { box-shadow: 0 0 10px var(--mark-hue, #ffd166); transform: translate(-50%, -50%) rotate(45deg) scale(1.55); }
}
@media (prefers-reduced-motion: reduce) {
  .moment-mark.active { animation: none; transform: translate(-50%, -50%) rotate(45deg) scale(1.4); box-shadow: 0 0 8px var(--mark-hue, #ffd166); }
}
.moment-mark.passed { opacity: 0.35; border-color: rgba(255, 255, 255, 0.5); }

/* ── CAMERA READOUT (frogdebug only) ────────────────────────────────────────
   For choosing the sim's opening camera by flying to a shot and reading the two
   numbers that define it back. Deliberately plain and selectable. */
#cam-readout {
  position: absolute;
  left: 10px;
  bottom: 10px;
  z-index: 30;
  padding: 7px 10px;
  border-radius: 8px
;  background: rgba(8, 14, 15, 0.88);
  border: 1px solid rgba(120, 200, 190, 0.35);
  color: #d8f0ec;
  font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  white-space: pre;
  user-select: text;
  pointer-events: auto;
}
#cam-readout b { color: #ffd166; font-weight: 600; }
#cam-readout .paste { color: #9fe8c8; }

/* ── THE YEAR IN REVIEW ─────────────────────────────────────────────────────
   Opens with the last key moment: what the stores ended at, and how each of the
   four jobs a body does actually went. */
#year-review {
  position: absolute;
  left: 50%;
  /* clear of the moment card, which sits at the top of the canvas */
  top: 162px;
  transform: translateX(-50%);
  z-index: 27;
  width: min(560px, calc(100% - 40px));
  height: fit-content;
  max-height: calc(100% - 180px);
  overflow: auto;
  padding: 14px 18px 16px;
  border-radius: 12px;
  background: rgba(12, 22, 24, 0.94);
  border: 1px solid rgba(120, 200, 190, 0.35);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
}
#year-review h4 { margin: 0 0 10px; font-size: 15px; color: #ffd166; }
#year-review .yr-sub { font-size: var(--fs-sm); opacity: 0.75; margin: -6px 0 12px; }
.yr-store { display: grid; grid-template-columns: 96px 1fr 44px; align-items: center; gap: 8px; margin-bottom: 5px; font-size: var(--fs-sm); }
.yr-store .yr-bar { height: 9px; border-radius: 5px; background: rgba(255,255,255,.1); overflow: hidden; }
.yr-store .yr-bar i { display: block; height: 100%; border-radius: 5px; background: var(--yr-hue, #888); transition: width 0.8s ease; }
.yr-store .yr-num { text-align: right; opacity: 0.8; font-variant-numeric: tabular-nums; }
#year-review .yr-jobs { margin: 12px 0 0; padding: 0 0 0 18px; list-style: disc outside; }
#year-review .yr-jobs li { margin-bottom: 6px; font-size: var(--fs-sm); line-height: 1.4; }
#year-review .yr-jobs li::marker { color: var(--tuva-cream, #d8d3c2); }
#year-review .yr-env { margin: 12px 0 0; padding: 0 0 0 18px; list-style: disc outside; }
#year-review .yr-env li { margin-bottom: 5px; font-size: var(--fs-sm); line-height: 1.4; }
#year-review .yr-env li::marker { color: var(--tuva-cream, #d8d3c2); }
#year-review h5 { margin: 14px 0 4px; font-size: var(--fs-sm); opacity: 0.85; }
/* the same button family as the card's X-ray button, so it reads as pressable (Ben) */
#review-btn {
  font: 600 12px Roboto, Arial, sans-serif;
  color: var(--ink);
  background: #22383b;
  border: 1px solid #4a5a5c;
  border-radius: 6px;
  padding: 4px 12px;
  margin-left: 8px;
  cursor: pointer;
}
#review-btn:hover { background: #2c4a4e; }
#review-btn:focus-visible { outline: 3px solid var(--focus-glow); outline-offset: 2px; }
#year-review .yr-job-name { font-weight: 600; }
