/* Earth, Sun, and Moon */

:root {
  --accent:       #004445;   /* Tuva green */
  --accent-light: #006668;
  --ink:          #2C3E3E;
  --muted:        #5A6E6E;

  /* The Tuva green, lifted until it works on a dark shell. #004445 against this
     panel is 1.3:1, so a selected button drawn in it would be invisible. This
     is the same hue raised until white text on it clears 4.5:1 (5.19:1) and a
     selected button clears 3:1 against an unselected one (3.31:1), so the
     pressed state reads without relying on hue. */
  --accent-on-dark: #12797B;
  --accent-edge:    #5FD6D8;

  /* Scene chrome. The subject is the night sky, so the shell is a deep blue
     rather than the usual light page: a bright frame around a black starfield
     reads as a hole in the page and washes the terminator out. This is a
     COLOR-3 departure; the Exceptions ledger row is pending sign-off, and the
     reasoning is in simulations/ai-context/earth_sun_moon-build-notes.md. */
  --shell-top:    #16203a;
  --shell-bottom: #080c17;
  --panel:        rgba(20, 29, 51, 0.96);
  --card:         rgba(33, 46, 76, 0.72);
  --border:       rgba(150, 183, 235, 0.24);
  --scene-ink:    #EAF0FB;
  --scene-muted:  #A9BBD8;
  --sun:          #FFCC66;
  --pin:          #FF8A3D;
  --focus-glow:   #FFD166;   /* the boilerplate's focus role colour */

  --radius-xl: 22px;
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius-sm: 9px;
  --shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}

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

/* An author display rule outranks the UA stylesheet's [hidden] rule, so every
   element that toggles with `hidden` needs this to actually hide. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

body {
  background: linear-gradient(180deg, var(--shell-top) 0%, var(--shell-bottom) 100%);
  color: var(--scene-ink);
}

button, input { font: inherit; }
button { cursor: pointer; font-family: Roboto, Arial, sans-serif; }
button:focus-visible {
  outline: 3px solid var(--focus-glow);
  box-shadow: 0 0 0 6px rgba(6, 10, 20, 0.62);
  outline-offset: 2px;
}

.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;
}

/* ── Layout ────────────────────────────────────────────────────────────────
   The scene takes the slack; the meter strip and the side panel size to their
   own content. Nothing here hard-codes a height, so the canvas frame is
   whatever is left after the controls have been laid out. */

#sim-app {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* Full bleed: nothing between the picture and the edge of the frame. The
     controls sit flush against it rather than floating in a padded box. */
  padding: 0;
}

#stage-panel {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(252px, 27%, 336px);
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "scene panel";
  gap: 0;
  padding: 0;
  border-radius: 0;
  border: 0;
  background: var(--panel);
  overflow: hidden;
}

/* Short frames: the readouts keep their size and the spacing gives way, so no
   control is ever clipped out of reach. */
@media (max-height: 700px) {
  #side-panel { gap: 4px; }
  .card { padding: 6px 9px; gap: 1px; }
  .opt-btn { min-height: 32px; padding: 5px 7px; }
  #phase-disc { width: 44px; height: 44px; }
}

#canvas-frame {
  grid-area: scene;
  position: relative;
  min-height: 0;
  overflow: hidden;
  border-radius: 0;
  background: #05070e;
}

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

#sim-canvas:focus-visible {
  outline: 3px solid var(--focus-glow);
  box-shadow: 0 0 0 6px rgba(6, 10, 20, 0.62);
  outline-offset: -3px;   /* inset, so the frame does not clip the ring */
}

#canvas-frame.is-booting > *:not(#sim-canvas) { opacity: 0; }

/* ── The second panel ─────────────────────────────────────────────────────
   One card: a picture with the words about it underneath. The sim sizes the
   picture to sit exactly over the region the renderer draws the second view
   into, and the caption takes whatever height its own words need. */

.inset-panel {
  position: absolute;
  left: 0; top: 0;
  width: 10px;                       /* replaced by the sim */
  border: 2px solid rgba(160, 195, 245, 0.55);
  border-radius: 12px;
  /* Transparent, and this matters: the renderer draws the second view into the
     canvas *behind* this element, so any ground of its own paints over the
     picture. An opaque panel turned Earth from the side into a silhouette. */
  background: transparent;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  z-index: 3;
}

.inset-pic {
  position: relative;
  height: 10px;                      /* replaced by the sim */
  background: transparent;
}

/* The caption has its own ground, because it is words rather than picture. */
.inset-cap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 7px 9px 8px;
  border-top: 1px solid rgba(150, 183, 235, 0.22);
  background: rgba(12, 19, 36, 0.88);
  backdrop-filter: blur(3px);
}

.inset-cap-value {
  font-size: 14px;
  font-weight: 700;
  color: #FFFFFF;
  line-height: 1.25;
}

.inset-cap-line {
  font-size: 12px;
  line-height: 1.4;
  color: var(--scene-muted);
}

.inset-cap-graph { display: flex; flex-direction: column; gap: 3px; }
.inset-cap-graph[hidden] { display: none; }

.inset-cap-graph-title {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--scene-muted);
}

/* Sized by the sim, which also draws it. Height in CSS pixels; the backing
   store is scaled by the device pixel ratio. */
/* Sized by the sim, which also draws it. The plot, a month axis under it, and
   for the eclipse curve two rows of key. */
#cap-canvas { display: block; width: 100%; height: 81px; cursor: ew-resize; }
#cap-graph.has-key #cap-canvas { height: 113px; }

/* Folded into the side panel on a narrow frame, where a caption under a
   hundred-pixel picture would be more wrap than words. */
.inset-cap.in-panel {
  margin-bottom: 4px;
  padding: 12px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--card);
  gap: 3px;
}

.view-tag {
  position: absolute;
  left: 12px; top: 12px;
  padding: 4px 9px;
  border-radius: var(--radius-sm);
  background: rgba(8, 13, 26, 0.74);
  border: 1px solid rgba(150, 183, 235, 0.28);
  color: var(--scene-ink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  pointer-events: none;
  white-space: nowrap;
}

.pip-tag { left: 6px; top: 6px; font-size: 12px; padding: 3px 7px; }

/* ── Sky aiming buttons, shown only while the sky is the large view ───────── */

.sky-aim {
  position: absolute;
  /* Above the scale strip, which lies along the bottom of the picture. */
  left: 12px; bottom: calc(var(--meter-h, 0px) + 10px);
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  max-width: calc(100% - 24px);
}

.aim-btn {
  min-height: 34px;
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(150, 183, 235, 0.34);
  background: rgba(12, 19, 36, 0.86);
  color: var(--scene-ink);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}
.aim-btn:hover { background: rgba(28, 43, 76, 0.92); }

/* ── The exaggeration meter ────────────────────────────────────────────────
   Evidence statement 1b. It sits under the picture in both layouts so it is
   never scrolled out of sight. */

.scale-meter {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 6px 12px;
  border-top: 1px solid rgba(255, 204, 102, 0.26);
  background: rgba(20, 16, 8, 0.72);
  color: #F6E7C4;
  font-size: 12px;
  line-height: 1.45;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
}

.scale-claim { font-weight: 600; }

.scale-more {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #F6E7C4;
  cursor: pointer;
}

.scale-more svg { width: 15px; height: 15px; display: block; }
.scale-more:hover { background: rgba(255, 204, 102, 0.18); }
.scale-more:focus-visible { outline: 3px solid var(--focus-glow); outline-offset: 1px; }
.scale-more[aria-expanded="true"] { background: rgba(255, 204, 102, 0.22); }

/* The numbers, once asked for. Full width, so they wrap under the claim rather
   than squeezing it. */
.scale-detail {
  flex: 1 0 100%;
  margin: 0;
  color: #EBD9B4;
  line-height: 1.45;
}

/* The eclipse badge floats over the picture, clear of both readout sets and of
   the scale strip, because it is an announcement rather than a reading. */
.eclipse-badge {
  position: absolute;
  /* Left, not centred. Centred it ran underneath the second panel in the
     opposite corner, which is exactly where the eclipse is being drawn. The
     panel publishes its own width so this can stop short of it. */
  left: 12px;
  right: calc(var(--inset-w, 0px) + 22px);
  bottom: calc(var(--meter-h, 0px) + 12px);
  z-index: 4;
  margin: 0;
  width: fit-content;
  max-width: 560px;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  border: 1px solid rgba(255, 190, 120, 0.55);
  background: rgba(52, 30, 12, 0.90);
  color: #FFE9C8;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
  pointer-events: none;
}

/* Two small buttons inside the clock card, so direction reads as part of the
   clock rather than as another control group. */
.clock-dir { margin-top: 8px; gap: 6px; }

/* The two familiar transport glyphs rather than the words, which read as a pair
   at a glance where "Backward" and "Forward" had to be read one at a time. The
   words survive as each button's accessible name. */
.clock-dir .opt-btn {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px 8px;
  min-height: 30px;
}

.clock-dir svg { width: 22px; height: 14px; display: block; fill: currentColor; }

/* ── The key moment ────────────────────────────────────────────────────────
   Sits low and centre-left, clear of the second panel, and holds the clock until
   it is dismissed. Warmer than the rest of the chrome because it is an
   announcement rather than a reading, and the same warm family as the eclipse
   badge it replaces at that moment. */
.moment-bar {
  position: absolute;
  left: 12px;
  right: calc(var(--inset-w, 0px) + 22px);
  bottom: calc(var(--meter-h, 0px) + 12px);
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 14px;
  width: fit-content;
  max-width: 620px;
  padding: 11px 13px 11px 15px;
  border-radius: var(--radius-md);
  border: 1px solid rgba(255, 190, 120, 0.62);
  background: rgba(52, 30, 12, 0.94);
  color: #FFE9C8;
  box-shadow: var(--shadow);
}

.moment-bar[hidden] { display: none; }
.moment-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }

.moment-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #FFCC66;
}

.moment-caption { font-size: 14px; font-weight: 600; line-height: 1.4; }
.moment-note { font-size: 12px; line-height: 1.4; color: #E8CFA8; }
.moment-note:empty { display: none; }

.moment-acts { display: flex; flex-direction: column; gap: 6px; flex: none; }

.moment-btn {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  padding: 7px 13px;
  border-radius: var(--radius-sm);
  border: 1px solid #FFCC66;
  background: #FFCC66;
  color: #2A1B08;
  cursor: pointer;
}

.moment-btn-quiet { background: transparent; color: #FFE9C8; }
.moment-btn-quiet[hidden] { display: none; }
.moment-btn:focus-visible { outline: 3px solid var(--focus-glow); outline-offset: 2px; }

/* While a moment holds, everything that is not the moment steps back, so the
   thing being announced is what the eye lands on. Nothing is removed. */
/* The class is on the picture, so only what is drawn over the picture steps
   back. The clock card in the panel stays as it is: during a moment the date is
   one of the things worth reading. */
.view-tag, .sky-aim, .scale-meter {
  transition: opacity 0.35s ease;
}

.moment-held .view-tag,
.moment-held .sky-aim,
.moment-held .scale-meter { opacity: 0.3; }

@media (prefers-reduced-motion: reduce) {
  .view-tag, .sky-aim, .scale-meter { transition: none; }
}

@media (max-width: 860px) {
  .moment-bar { right: 12px; max-width: none; width: auto; flex-direction: column; align-items: stretch; }
  .moment-acts { flex-direction: row; }
}

/* ── The lens buttons in the panel ─────────────────────────────────────────
   The same four drawings as the start screen, small, in a two-by-two grid. With
   the old controls gone the panel had room to make the one remaining choice
   look like the choice it is. */
.lens-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.lens-btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 8px 8px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--scene-ink);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.12s ease, background 0.12s ease;
}

.lens-btn svg { width: 64px; height: 64px; display: block; }

.lens-btn:hover { border-color: rgba(255, 224, 138, 0.7); }
.lens-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-glow); }

/* The one that is running. A tinted card with a matching border was too quiet
   to find at a glance, so this is a bright ring drawn inside the border, a
   lighter card, and a bar across the top — three things saying the same thing,
   none of which moves the button by a pixel. */
.lens-btn.is-on {
  border-color: var(--accent-edge);
  background: rgba(18, 121, 123, 0.42);
  color: #FFFFFF;
  box-shadow: inset 0 0 0 2px var(--accent-edge), 0 2px 12px rgba(95, 214, 216, 0.22);
}

.lens-btn.is-on::before {
  content: "";
  position: absolute;
  left: 22%;
  right: 22%;
  top: 0;
  height: 4px;
  border-radius: 0 0 4px 4px;
  background: var(--accent-edge);
}

.lens-btn.is-on svg { filter: drop-shadow(0 0 6px rgba(95, 214, 216, 0.45)); }

/* The selected button's inset ring is set on box-shadow, which is the property
   the focus glow uses too, so without this the glow was simply overwritten and
   focus on the running pattern was invisible. Both shadows, in one declaration. */
.lens-btn.is-on:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent-edge), 0 0 0 3px var(--focus-glow);
}

@media (max-height: 700px) {
  .lens-btn svg { width: 48px; height: 48px; }
  .lens-btn { padding: 6px 6px 5px; }
}

/* ── The start screen ──────────────────────────────────────────────────────
   Over the whole stage until a lens is chosen. Four large buttons with a drawing
   each, on the same dark ground as the scene so the transition is a lift, not a
   cut. */
.start-screen {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: radial-gradient(130% 100% at 50% 12%, #1b2740 0%, #111a2c 50%, #070b14 100%);
}

.start-inner { width: min(880px, 100%); }

.start-screen h2 {
  margin: 0 0 22px;
  text-align: center;
  color: #FFFFFF;
  font-size: clamp(20px, 2.6vw, 28px);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.start-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.start-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 18px 14px 16px;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(150, 183, 235, 0.32);
  background: rgba(33, 46, 76, 0.72);
  color: var(--scene-ink);
  font: inherit;
  cursor: pointer;
  text-align: center;
  transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}

.start-btn:hover, .start-btn:focus-visible {
  border-color: rgba(255, 224, 138, 0.8);
  background: rgba(45, 62, 98, 0.86);
  transform: translateY(-2px);
  outline: none;
}

.start-btn:focus-visible { box-shadow: 0 0 0 3px var(--focus-glow); }

.start-btn svg { width: 100%; max-width: 150px; height: auto; display: block; }

.start-name { font-size: 18px; font-weight: 700; color: #FFFFFF; }
.start-sub  { font-size: 13px; line-height: 1.35; color: var(--scene-muted); }

@media (max-width: 720px) {
  .start-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .start-btn svg { max-width: 90px; }
}

/* ── Choosing a lens moves the buttons to where they live ──────────────────
   The backdrop lifts off the stage while the four drawings fly out of it and
   into their slots in the panel, which sit empty until the art lands in them.
   A student who has watched the choice travel knows where to go to change it. */
/* Two steps, not one. The cards and the heading go as soon as a choice is made,
   and the backdrop holds until the drawings have landed: lifting it while they
   were still in the air pulled the eye onto the stage and the buttons arrived
   unwatched. */
.start-screen { transition: opacity 0.38s ease; }
.start-screen.is-choosing { pointer-events: none; }
.start-screen.is-choosing .start-btn { opacity: 0; transition: opacity 0.1s linear; }
.start-screen.is-choosing h2 { opacity: 0; transition: opacity 0.18s linear; }
.start-screen.is-leaving { opacity: 0; }
.start-screen.is-leaving .start-btn:hover { transform: none; }

#lens-row.is-arriving .lens-btn svg { opacity: 0; }

.lens-flight { position: fixed; inset: 0; z-index: 9000; pointer-events: none; }
.lens-flight-item { position: fixed; transform-origin: 50% 50%; }
.lens-flight-item svg { width: 100%; height: 100%; display: block; }

@media (prefers-reduced-motion: reduce) {
  .start-screen { transition: none; }
}

/* ── Side panel ───────────────────────────────────────────────────────────── */

#side-panel {
  grid-area: panel;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  /* The stage no longer has padding, so the panel carries its own. The top
     padding belongs to the first section instead, so every section is spaced
     the same way. */
  padding: 0 10px 10px 12px;
  border-left: 1px solid var(--border);
}

/* ── Three sections, not a stack of boxes ──────────────────────────────────
   A frame round the clock and none round its neighbours made the clock the odd
   one out, and six pixels of gap left all three crowding each other. A rule
   between them with room either side says the same thing more quietly: what to
   watch, when it is, and where you are standing. */
.panel-part {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 13px 0 15px;
}

.panel-part + .panel-part { border-top: 1px solid var(--border); }

/* The clock's lines sit closer together than a group of buttons wants to. */
#card-clock { gap: 2px; }

/* The clock keeps its type and loses its frame: it is a section now. */
.card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 7px 10px;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(150, 183, 235, 0.18);
  background: var(--card);
}

/* The three section labels — Pattern, Date and time at your pin, Where you
   stand on Earth — are one rule, so they cannot drift apart. */
.card-label,
.group-label {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--scene-muted);
}

.card-value { font-size: 18px; font-weight: 700; line-height: 1.2; color: #FFFFFF; }
.card-sub   { font-size: 14px; line-height: 1.35; color: var(--scene-ink); }
.card-note  { font-size: 12px; line-height: 1.35; color: var(--scene-muted); }
.card-note:empty { display: none; }

.moon-row { display: flex; align-items: center; gap: 9px; }
.moon-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
#phase-disc { width: 52px; height: 52px; flex-shrink: 0; }

.bar-label { margin-top: 3px; font-size: 12px; color: var(--scene-muted); }

.bar {
  display: block;
  height: 8px;
  border-radius: 5px;
  background: rgba(10, 16, 30, 0.7);
  border: 1px solid rgba(150, 183, 235, 0.24);
  overflow: hidden;
}

.bar-fill {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, #FFB020 0%, #FFE08A 100%);
  transition: width 0.25s ease;
}

/* Four latitudes at once, on the same date. The standard asks the student to see
   that sunlight "hits different parts of the curved Earth at different angles",
   which one bar at a time cannot show: you had to move the pin and remember. */
.lat-bars {
  list-style: none;
  margin: 3px 0 0;
  padding: 0;
  display: grid;
  gap: 3px;
}

.lat-bars li {
  display: grid;
  grid-template-columns: 74px 1fr 34px;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--scene-muted);
}

.lat-bars .lat-name { text-align: right; }
.lat-bars .lat-deg { font-variant-numeric: tabular-nums; text-align: right; }

/* The pin's own latitude, so the student can tell which row is theirs.
   --ink is the dark-text token and this panel is dark, so it has to be
   --scene-ink here; --ink rendered the student's own row invisible. */
.lat-bars li.is-here { color: var(--scene-ink); font-weight: 700; }
.lat-bars li.is-here .bar { border-color: rgba(255, 200, 120, 0.7); }

/* No sunlight at all today: polar night. The bar is empty, so the row says so. */
.lat-bars li.is-dark .bar-fill { background: none; }

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

.control-group { display: flex; flex-direction: column; gap: 4px; }



.btn-row { display: flex; gap: 5px; }
.btn-row-wrap { flex-wrap: wrap; }

.opt-btn {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 34px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  /* 0.65 alpha, not 0.3: the button fill barely differs from the card behind
     it, so this border is the boundary, and a boundary needs 3:1. It measures
     4.29:1 against the fill and 3.61:1 against the card. */
  border: 1px solid rgba(150, 183, 235, 0.65);
  background: rgba(16, 24, 44, 0.8);
  color: var(--scene-ink);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
}

.opt-btn:hover { background: rgba(30, 46, 80, 0.9); }

.opt-btn.is-on {
  background: var(--accent-on-dark);
  border-color: var(--accent-edge);
  color: #FFFFFF;
  /* A thicker ring as well as a different colour, so the pressed state is not
     carried by hue alone. Inset, so nothing shifts. */
  box-shadow: inset 0 0 0 2px var(--accent-edge);
}

.opt-btn:disabled { opacity: 0.42; cursor: not-allowed; }

/* ── Keyboard proxies ──────────────────────────────────────────────────────
   Transparent stand-ins placed over the bodies a mouse can drag, so the same
   moves are reachable from the keyboard. They never take the pointer. */

#kb-layer { position: absolute; inset: 0; pointer-events: none; z-index: 3; }

.kb-proxy {
  position: absolute;
  margin: 0; padding: 0; border: 0;
  border-radius: 50%;
  background: transparent;
  pointer-events: none;
}

/* :focus, not :focus-visible. These are only ever reached by keyboard, and a
   div[tabindex] focused by script does not reliably match :focus-visible. */
.kb-proxy:focus {
  outline: 3px solid var(--focus-glow);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px rgba(255, 209, 102, 0.38);
}

/* ── Narrow frames ────────────────────────────────────────────────────────
   One column. The scene keeps the slack, the meter stays under it, and the
   panel takes what is left with its own scroll. */

@media (max-width: 860px) {
  #stage-panel {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(190px, 1fr) minmax(0, auto);
    grid-template-areas:
      "scene"
      "panel";
  }
  #side-panel { border-left: 0; border-top: 1px solid var(--border); }
  /* The scene keeps the slack; the panel scrolls inside whatever is left. */
  #side-panel { max-height: 38vh; }
}

@media (max-width: 560px) {
  #side-panel { padding: 8px; }
  .view-tag { left: 8px; top: 8px; font-size: 12px; }
  .sky-aim { left: 8px; bottom: calc(var(--meter-h, 0px) + 6px); }
  .card-value { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .bar-fill { transition: none; }
}

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

.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;
}

.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;
}
