/* Plate Tectonics
 *
 * A warm dark chrome around a lit cut-open block of the Earth. The dark surround
 * is a deliberate departure from the house cream page (COLOR-3): the sim looks
 * down into rock and mantle, and a cream page put a bright band around a dark
 * subsurface. Raised for the exceptions ledger.
 */

:root {
  --accent:       #004445;
  --accent-light: #006668;
  --focus-glow:   #FFD166;
  /* --ink stays the boilerplate's dark value, because the info-dialog block is a
     verbatim copy of the boilerplate's and colours its body text with it on a
     WHITE dialog. Redefining --ink for the dark surround put cream text on white
     at about 1.2:1 and made the whole dialog unreadable. The dark chrome gets its
     own token instead. */
  --ink:          #2C3E3E;
  --chrome-ink:   #F0E6DA;
  /* Same story as --ink: the boilerplate dialog block colours its inactive tab
     label with var(--muted) on a near-white surface, so a warm tan here dropped it
     to 2.2:1. The boilerplate value stays and the dark chrome gets its own. */
  --muted:        #5A6E6E;
  --chrome-muted: #C4A589;

  --bg-top:    #161318;
  --bg-bottom: #1D1716;
  --panel:     rgba(26, 22, 22, 0.96);
  --dock:      rgba(34, 28, 27, 0.94);
  --border:    rgba(150, 110, 80, 0.22);
  --pick:      #B5562A;      /* the chosen option in a group */
  --pick-edge: #D06A34;
  --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(200, 120, 50, 0.12), transparent 42%),
    radial-gradient(ellipse at 80% 100%, rgba(120, 40, 20, 0.30), transparent 48%),
    linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bottom) 100%);
  color: var(--chrome-ink);
  font-family: Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

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

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

/* ── Accessibility ── */
.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;
}

/* ── Stage ── */
#sim-app {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 10px;
}

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

#canvas-frame {
  position: relative;
  min-height: 0;
  overflow: hidden;
  border-radius: 20px;
  background:
    linear-gradient(180deg, #cfe6f5 0%, #aecde4 28%, #2a2230 70%, #1a1014 100%);
  box-shadow: inset 0 0 0 1px rgba(150, 110, 80, 0.18);
}

#canvas-frame::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.18), transparent 22%);
}

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

/* Two-tone, because the scene behind it runs from #CFE6F5 sky at the top to almost
   black at the bottom and no single colour contrasts with both. Measured: a single
   #60A5FA ring was 1.6:1 against the sky it was mostly drawn on. The gold reads on
   the dark half, the near-black reads on the pale half, and one of them is always
   the one you can see. */
#sim-canvas:focus-visible {
  outline: 3px solid #FFD166;
  outline-offset: -3px;
  box-shadow: inset 0 0 0 6px #16121A;
}

/* ── The geologic clock ── */
#time-chip {
  position: absolute;
  top: 14px;
  left: 14px;
  display: inline-flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 16px;
  border-radius: 16px;
  background: rgba(20, 12, 10, 0.80);
  border: 1px solid rgba(210, 130, 70, 0.30);
  backdrop-filter: blur(10px);
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.35);
  z-index: 6;
}

.hud-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--chrome-muted);
}

.hud-value {
  font-size: 24px;
  font-weight: 700;
  line-height: 1;
  color: #FFE7C4;
}

.hud-sub {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: rgba(235, 200, 170, 0.80);
  margin-top: 2px;
}

/* Scale-bar end labels, positioned in JS under the 3D ruler's end ticks. */
.scale-label {
  position: absolute;
  transform: translate(-50%, -50%);
  color: #F3E2C8;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  z-index: 5;
}

/* Feature callouts, positioned in JS over the landform they name. */
#feature-labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 5;
}

.feature-label {
  position: absolute;
  transform: translate(-50%, -50%);
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(18, 10, 8, 0.82);
  border: 1px solid rgba(255, 200, 140, 0.45);
  color: #FFE9CF;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
  opacity: 0;
  transition: opacity 0.5s ease;
}

.feature-label.feature-visible { opacity: 1; }


/* ── The key-moment card ──
   Centred absolutely, so it needs width: max-content. With width: auto and
   translateX(-50%) the box shrink-fits to nothing. */
/* Anchored at the BOTTOM of the frame. At the top it sat over the subject of its
   own caption: the rift valley, the ridge axis and the range crest all sit in the
   middle of the scene, and a card above them covered the thing being described.
   Bottom-centre also puts the reading order in a straight line: the scene, then
   what is happening, then where it happened on the timeline. */
#moment-card {
  /* At the LEFT edge, not centred: centred, the card covered the middle of the
     scene, which is where every beat's subject is, and on a small screen it
     covered most of the animation. Each beat shifts its subject toward the right
     half to meet it. */
  position: absolute;
  left: 14px;
  bottom: 14px;
  width: max-content;
  max-width: min(400px, calc(48% - 20px));
  /* In a short frame the card can be taller than the scene it sits over. Capped
     against the frame's own height so it always leaves the scene visible above it,
     and scrolls rather than growing past the top of the frame. */
  max-height: calc(100% - 24px);
  overflow-y: auto;
  padding: 12px 16px 14px;
  border-radius: 14px;
  background: rgba(18, 11, 9, 0.93);
  border: 1px solid rgba(255, 200, 140, 0.42);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(10px);
  z-index: 20;
}

.moment-eyebrow {
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--pick-edge);
}

#moment-card h2 {
  margin: 3px 0 6px;
  font-size: 16px;
  font-weight: 700;
  color: #FFE7C4;
}

#moment-card p {
  margin: 0 0 8px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--chrome-ink);
}

#moment-note {
  font-size: 12px;
  line-height: 1.4;
  color: rgba(235, 200, 170, 0.78);
}

#moment-btn {
  min-height: 32px;
  padding: 0 18px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(90, 190, 90, 0.42);
  background: #1F7A32;
  color: #FFFFFF;
  font-size: 14px;
  font-weight: 700;
}

#moment-btn:hover { background: #259039; }

/* ── The timeline ── */
#timeline {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(150, 110, 80, 0.20);
  background: var(--dock);
}

#timeline.is-held { border-color: var(--focus-glow); }

.tl-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--chrome-muted);
  white-space: nowrap;
}

/* 28px, to hold three things at three heights: axis ticks crossing the line, the
   badges centred on it, and the ambient-earthquake notches below it. The badge is
   drawn at 13px, which is the size that reads, but WCAG 2.2 2.5.8 asks for a 24 by 24
   CSS-pixel hit box on anything interactive, so the button is the target and its
   ::before is the diamond. */
#tl-track {
  position: relative;
  flex: 1;
  min-width: 0;
  /* 46px, for four things at four heights: the axis ticks crossing the line, the
     badges centred on it, the earthquake notches just under it, and the year under
     each tick. It was 28px when the years lived beside the strip instead. */
  height: 46px;
  align-self: center;
}

#tl-track::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 12px;
  height: 3px;
  border-radius: 2px;
  /* Was 0.22, which composited to 1.26:1 against the strip. A badge only means
     "23 million years" if the whole extent of the track can be seen. */
  background: rgba(196, 165, 137, 0.55);
}

#tl-fill {
  position: absolute;
  left: 0;
  top: 12px;
  height: 3px;
  width: 0;
  border-radius: 2px;
  background: var(--pick-edge);
}

/* One every ten million years. They cross the line so they read as a ruler rather
   than as things that happened. */
.tl-axis {
  position: absolute;
  top: 7px;
  width: 2px;
  height: 13px;
  border-radius: 1px;
  background: rgba(196, 165, 137, 0.75);
  transform: translateX(-50%);
}

/* The first and last tick sit ON the ends, so they are nudged fully inside rather
   than centred on a point half of which is off the track. */
.tl-axis.tl-first { transform: translateX(0); }
.tl-axis.tl-last { transform: translateX(-100%); }

/* The year under each tick. */
.tl-num {
  position: absolute;
  top: 25px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: var(--chrome-muted);
  transform: translateX(-50%);
}
.tl-num.tl-first { transform: translateX(0); }
.tl-num.tl-last { transform: translateX(-100%); }

/* Taller, brighter and outlined, because it was two small warm bars on one track:
   the playhead was hard to tell from an ambient earthquake tick. */
#tl-head {
  position: absolute;
  top: 3px;
  width: 4px;
  height: 22px;
  border-radius: 2px;
  background: #FFE7C4;
  box-shadow: 0 0 0 1px rgba(20, 12, 10, 0.9);
  transform: translateX(-50%);
}

#timeline.is-held #tl-head { background: var(--focus-glow); }

.tl-mark {
  position: absolute;
  top: 2px;
  width: 24px;
  height: 24px;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  transform: translateX(-50%);
  cursor: pointer;
}

.tl-mark::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 13px;
  height: 13px;
  transform: translate(-50%, -50%) rotate(45deg);
  border: 2px solid var(--pick-edge);
  border-radius: 3px;
  background: var(--pick-edge);
}

.tl-mark:hover:not(:disabled)::before { background: var(--pick); }

/* Waiting to happen: hollow, dimmer, and not a pointer, because there is nothing to
   press yet. It fills in when its moment fires. */
.tl-mark.tl-waiting {
  cursor: default;
}

/* Hollow, not dashed. A dashed 2px border on a 13px rotated square breaks into four
   corner ticks and reads as a pair of angle brackets rather than a diamond. */
.tl-mark.tl-waiting::before {
  background: #241B18;
  border-color: rgba(196, 165, 137, 0.85);
}

.tl-mark.active::before {
  background: var(--focus-glow);
  border-color: var(--focus-glow);
  animation: tlPulse 1.6s ease-in-out infinite;
}

.tl-mark:focus-visible {
  outline: 3px solid var(--focus-glow);
  outline-offset: 1px;
  border-radius: 4px;
}

@keyframes tlPulse {
  0%, 100% { transform: translate(-50%, -50%) rotate(45deg) scale(1); }
  50%      { transform: translate(-50%, -50%) rotate(45deg) scale(1.3); }
}

@media (prefers-reduced-motion: reduce) {
  .tl-mark.active::before { animation: none; }
}

/* ── Controls dock ── */
/* Wrapping, always. Adding a third motion option pushed the button group past its
   card from about 1040px down: at 800px the button ended 73px past the card, painted
   over the LEFT PLATE card next to it, and shoved the Run button off the frame. The
   only breakpoint was at 680px, so the whole 1040-to-680 band was broken. Cards now
   claim a width that fits their content and wrap when they cannot all fit. */
#controls-dock {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: stretch;
}

.control-card {
  flex: 1 1 auto;
  min-width: 0;
  padding: 9px 11px;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(150, 110, 80, 0.20);
  background: var(--dock);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.ctrl-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--chrome-muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Wrapping inside the card. Letting the buttons shrink instead traded the earlier
   overflow for clipped labels: "Push together" came out as "Push togeth". A third
   option in this group is what made the difference, so the group wraps and the
   labels stay whole. */
.btn-group { display: flex; flex-wrap: wrap; gap: 3px; }

.choice-btn {
  flex: 1 1 auto;
  min-height: 30px;
  padding: 0 6px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(180, 120, 80, 0.30);
  background: rgba(255, 255, 255, 0.05);
  color: var(--chrome-muted);
  font-size: 14px;
  font-weight: 700;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  white-space: nowrap;
}

.choice-btn.active {
  background: var(--pick);
  color: #FFFFFF;
  border-color: var(--pick-edge);
}

.choice-btn:hover:not(.active):not(:disabled) {
  background: rgba(255, 255, 255, 0.11);
  color: var(--chrome-ink);
}

.choice-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.choice-card { flex: 1 1 200px; min-width: 172px; }
.speed-card { flex: 0 1 170px; min-width: 150px; }

.speed-btns { display: flex; flex-wrap: wrap; gap: 4px; }

.speed-btn {
  flex: 1;
  min-height: 26px;
  padding: 0 7px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(180, 120, 80, 0.30);
  background: rgba(255, 255, 255, 0.05);
  color: var(--chrome-muted);
  font-size: 14px;
  font-weight: 700;
  transition: background 0.15s, color 0.15s;
}

.speed-btn.active {
  background: var(--pick);
  color: #FFFFFF;
  border-color: var(--pick-edge);
}

.speed-btn:hover:not(.active) {
  background: rgba(255, 255, 255, 0.11);
  color: var(--chrome-ink);
}

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

/* ── Info dialog ──
   The dialog is Tuva Sims "chrome", so its accent is espresso (#5c4738),
   NOT the sim's green var(--accent). Header = purple with white text; active
   tab / h3 / footer button = purple; tabs/footer surface = #F8FBFB; body text =
   var(--ink). The shared toolbar stylesheet also injects these purple rules
   (scoped to #info-dialog) so existing green sims reskin automatically — keep
   this block in sync with it; do not redefine per sim. */
#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;
}

/* The boilerplate paints this ring in --focus-glow gold, inset, on the #F8FBFB tab
   strip: measured 1.33:1, effectively invisible. The dialog is a light surface, so
   its focus ring has to be dark. Worth taking back to the boilerplate, since every
   sim that copies the block has the same ring. */
.tab-btn:focus-visible {
  outline: 3px solid #2C3E3E;
  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;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  padding: 12px 20px;
  border-top: 1px solid #E5EAE9;
  background: #F8FBFB;
}

.dialog-close-footer {
  background: #5c4738;
  color: #ffffff;
  border: none;
  border-radius: 6px;
  padding: 8px 20px;
  font-family: Roboto, Arial, sans-serif;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s;
}

.dialog-close-footer:hover {
  background: #7d6c60;
}

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


/* In a short frame the card was 180px of a 224px scene: every beat showed text over
   nothing. Capped to half the frame and set in the 12px floor so the geology it is
   describing stays on screen. */
/* A SHORT viewport, which is what a 200% browser zoom on a laptop produces. The
   stage grid gives the scene whatever is left after the timeline and the dock,
   and below about 560px that was nothing: the frame's minimum height pushed it
   under the timeline, and the timeline and dock painted over the block. Here the
   page scrolls instead. The scene keeps a fixed working height and the timeline
   and controls stack under it (WCAG 1.4.4 resize text, 1.4.10 reflow). */
@media (max-height: 560px) {
  html, body { height: auto; min-height: 100%; overflow: auto; }
  #sim-app, #stage-panel { flex: none; min-height: 0; overflow: visible; }
  #stage-panel { grid-template-rows: 280px auto auto; }
  #canvas-frame { height: 280px; min-height: 280px; }
}

@media (max-height: 640px) {
  #moment-card {
    max-height: 52%;
    max-width: min(520px, calc(100% - 16px));
    padding: 8px 12px 10px;
    bottom: 8px;
  }
  #moment-card h2 { font-size: 14px; margin: 2px 0 3px; }
  #moment-card p { font-size: 12px; line-height: 1.35; margin: 0 0 5px; }
  #moment-note { font-size: 12px; }
  #moment-btn { min-height: 28px; }
}

@media (max-width: 680px) {
  #sim-app { padding: 6px; }
  #timeline { gap: 6px; padding: 6px 8px; }
  /* Six years do not fit across a 260px track, and "50 million yr" alone is 90px
     of it. The ticks all stay; only the numbers between the ends go. */
  .tl-num:not(.tl-first):not(.tl-last) { display: none; }
    /* Two thirds of the width at most, so the right third of a short canvas still
     shows the subject each beat shifts there. Full width, the card was the whole
     animation on a phone. */
  #moment-card { bottom: 10px; padding: 10px 12px 12px; max-width: min(400px, 66%); max-height: 60%; }
  /* The second paragraph is the supplementary note. On a phone it pushed the
     Continue button below the card's fold, and the announcement at the start of
     every beat already reads the note aloud, so nothing a screen reader hears is
     lost by hiding it here. */
  #moment-note { display: none; }
  #moment-card h2 { font-size: 14px; }
  #moment-card p { font-size: 12px; }
  #stage-panel { gap: 6px; padding: 6px; }
  #canvas-frame { min-height: 220px; border-radius: 16px; }
  #time-chip { padding: 7px 11px; top: 9px; left: 9px; }
  .hud-value { font-size: 20px; }
  #controls-dock { gap: 5px; flex-wrap: wrap; }
  .control-card { padding: 7px 9px; border-radius: 14px; }
  .choice-card { flex: 1 1 calc(50% - 4px); min-width: 120px; }
  .speed-card { flex: 1 1 100%; flex-direction: row; align-items: center; gap: 8px; }
  .choice-btn { font-size: 12px; min-height: 26px; }
  .speed-btn { font-size: 12px; }
}

/* ── The debug view ────────────────────────────────────────────────────────
   Only ever in the DOM when the page is opened with ?debug=1, so none of this
   is on a student's screen. Styled to stay out of the way of the scene it is
   describing: mono, small, and translucent over the sky. */
#dbg-panel {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 520px;
  max-height: calc(100% - 16px);
  overflow: auto;
  z-index: 40;
  padding: 8px 10px 10px;
  border-radius: 8px;
  background: rgba(18, 14, 12, 0.88);
  border: 1px solid rgba(196, 165, 137, 0.45);
  color: #F0E6DA;
  font: 11px/1.45 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
#dbg-panel .dbg-hd {
  font-weight: 700;
  letter-spacing: 0.06em;
  color: #FFD9A8;
  margin-bottom: 4px;
}
#dbg-panel .dbg-hint { font-weight: 400; color: #C4A589; letter-spacing: 0; }
#dbg-panel .dbg-pose { color: #C4A589; margin-bottom: 6px; }
#dbg-panel .dbg-btns { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
#dbg-panel button {
  font: inherit;
  padding: 3px 7px;
  border-radius: 5px;
  cursor: pointer;
  color: #F0E6DA;
  background: #3A2C25;
  border: 1px solid rgba(196, 165, 137, 0.5);
}
#dbg-panel button:hover { background: #4A3830; }
#dbg-panel .dbg-row {
  display: grid;
  grid-template-columns: 16px 122px 1fr;
  align-items: baseline;
  gap: 4px;
  cursor: pointer;
}
#dbg-panel .dbg-row.dbg-idle { opacity: 0.45; }
#dbg-panel .dbg-row:hover { background: rgba(255, 255, 255, 0.06); }
#dbg-panel .dbg-name { color: #F0E6DA; }
/* Wrapping, so the reason a mesh is out of bounds is readable rather than clipped
   at the panel's edge, which is the one line you actually came here to read. */
#dbg-panel .dbg-ext { color: #9FB39F; }
#dbg-panel .dbg-ext.dbg-out { color: #FF9B7A; font-weight: 700; }
.dbg-axis-label {
  position: absolute;
  z-index: 39;
  transform: translate(-50%, -50%);
  font: 700 13px/1 ui-monospace, Menlo, Consolas, monospace;
  text-shadow: 0 0 4px #000, 0 0 4px #000;
  pointer-events: none;
}


/* ── Full bleed ─────────────────────────────────────────────────────────────
   The animation runs edge to edge and the cards lose their outer padding: on a
   small screen the frame around the canvas and the gutters around the controls
   were a fifth of the height between them. Appended last so it wins the cascade
   at every width. */
#sim-app { padding: 0; gap: 6px; }
#stage-panel { padding: 0; border: 0; border-radius: 0; gap: 6px; }
#canvas-frame { border-radius: 0; box-shadow: none; }
#timeline { margin: 0 6px; }
#controls-dock { gap: 6px; margin: 0 6px 6px; }
.control-card { padding: 6px 8px; border-radius: 12px; }
/* Dragging the block turns it, so a finger on it must not scroll the page. */
#sim-canvas { touch-action: none; }
