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

:root {
  --nav-h: 52px;
  --panel-w: min(340px, 100%);
  --accent: #ffd54f;
  --dark-bg: #0d1b2a;
  --card-bg: #152642;
  --card-bg-raised: #1c3459;
  --text: #e8f0ff;
  --sub: #9ab3d4;

  /* Matches the shared platform type scale (Little Explorers hub / Water Cycle) */
  --font-display: 'Fredoka', system-ui, sans-serif;
  --font-body: 'Quicksand', system-ui, -apple-system, sans-serif;

  --shadow-sm: 0 2px 6px rgba(0,0,0,.25);
  --shadow-md: 0 6px 18px rgba(0,0,0,.3);
  --shadow-lg: 0 14px 36px rgba(0,0,0,.4);
}

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-body);
  font-weight: 600;
  background: var(--dark-bg);
  color: var(--text);
  overflow-x: hidden;
}

h1, h2, h3, .tab, .play-btn, .launch-btn, .nav-story-btn, .read-aloud-btn,
.object-card-name, .gas-card-name, .gas-name, .detail-name, .story-title,
.cloud-result-title, .readout-value, .sound-toggle, .home-btn {
  font-family: var(--font-display);
}

/* ── NAV ─────────────────────────────────────── */
.top-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 8px 0 6px;
  background: rgba(13,27,42,.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid rgba(255,255,255,.08);
  z-index: 100;
  gap: 4px;
}

.home-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  font-size: 15px;
  border-radius: 50%;
  background: rgba(255,255,255,.08);
  text-decoration: none;
  transition: transform .15s;
}
.home-btn:hover { transform: scale(1.1); }

.nav-left {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.sound-toggle {
  flex-shrink: 0;
  background: rgba(13,27,42,.92);
  border: 1px solid rgba(255,255,255,.14);
  color: var(--text);
  font-size: 18px;
  line-height: 1;
  padding: 6px 10px;
  border-radius: 9px;
  cursor: pointer;
  margin-right: 8px;
  transition: transform .12s ease, border-color .15s ease, background .15s ease;
}
.sound-toggle:hover { transform: scale(1.08); border-color: rgba(255,255,255,.3); }
.sound-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.logo { font-size: 26px; }

h1 {
  margin: 0;
  font-size: 15px;
  line-height: 1.1;
  font-weight: 700;
}
h1 small {
  display: block;
  font-size: 12px;
  color: var(--sub);
  font-weight: 500;
}

.nav-tabs {
  display: flex;
  gap: 4px;
  min-width: 0;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* legacy Edge */
  -webkit-overflow-scrolling: touch;
  /* Fade hint at the trailing edge so a scrollable-but-clipped tab bar reads as
     "more to see" rather than looking cut off — real signal, not decoration. */
  mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 18px), transparent 100%);
}
.nav-tabs::-webkit-scrollbar { display: none; } /* Chrome/Safari/newer Edge */

.tab {
  background: transparent;
  border: none;
  color: var(--sub);
  padding: 8px 14px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  border-radius: 20px;
  transition: all .2s;
  flex-shrink: 0;
  scroll-snap-align: start;
}
.tab.active {
  background: rgba(255,213,79,.15);
  color: var(--accent);
}
.tab:hover:not(.active) { color: var(--text); }

/* Narrow phones / Fold-7 cover screen (~340-400px): six tabs plus the logo and
   sound toggle can't all fit even with the bar scrollable, and a partly-hidden
   "Story Time" tab is easy to miss entirely on a screen this size — found via
   automated Playwright testing 2026-08-22 (the tab was literally unreachable).
   Shrink to fit more of the bar in view, and drop the header subtitle so
   nav-left stops eating tab-bar width. */
@media (max-width: 430px) {
  .nav-left h1 small { display: none; }
  .nav-left h1 { font-size: 13px; }
  .tab { padding: 7px 10px; font-size: 12px; }
  .sound-toggle { padding: 5px 8px; font-size: 16px; }
}

/* ── VIEWS ───────────────────────────────────── */
.view {
  display: none;
  padding-top: calc(var(--nav-h) + 12px);
  min-height: calc(100vh - var(--nav-h));
}
.view.active { display: block; animation: view-in .3s ease both; }
@keyframes view-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .view.active { animation: none; } }

h2 {
  font-size: 22px;
  margin: 0 0 6px;
  text-align: center;
}
.subtitle {
  text-align: center;
  color: var(--sub);
  font-size: 13px;
  margin: 0 0 18px;
  padding: 0 16px;
}

/* ── LAYERS VIEW ─────────────────────────────── */
.atmo-wrapper {
  position: relative;
  display: flex;
  height: calc(100vh - var(--nav-h) - 30px);
  overflow: hidden;
}

#atmo-svg-container {
  flex: 1;
  position: relative;
  cursor: pointer;
}

.hint-text.tap-hint {
  position: absolute;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,.5);
  backdrop-filter: blur(4px);
  padding: 6px 14px;
  border-radius: 20px;
  font-size: 13px;
  color: #fff;
  white-space: nowrap;
  z-index: 10;
  animation: pulse 2s infinite;
  pointer-events: none;
}
@keyframes pulse {
  0%,100% { opacity: 1; }
  50% { opacity: .7; }
}

/* SVG layer bands */
.layer-band {
  cursor: pointer;
  transition: filter .2s;
}
.layer-band:hover { filter: brightness(1.3); }

/* Per-layer atmospheric detail (2026-08-22 visual pass) -- see
   addAtmosphericDetail() in app.js for what generates these elements. */
.atmo-star {
  fill: #fff;
  pointer-events: none;
  animation: atmo-twinkle 2.6s ease-in-out infinite;
}
@keyframes atmo-twinkle {
  0%, 100% { opacity: .25; }
  50% { opacity: 1; }
}

.atmo-aurora {
  pointer-events: none;
  filter: blur(2px);
  animation: atmo-aurora-drift 9s ease-in-out infinite;
}
.atmo-aurora-1 { animation-duration: 12s; animation-direction: reverse; }
@keyframes atmo-aurora-drift {
  0%, 100% { transform: translateX(0); opacity: .18; }
  50% { transform: translateX(14px); opacity: .32; }
}

.atmo-meteor {
  pointer-events: none;
  transform: translate(-40px, var(--meteor-y, 0));
  animation: atmo-meteor-sweep 4.5s cubic-bezier(.3,0,.7,1) infinite;
  animation-delay: 1.5s;
  opacity: 0;
}
.atmo-meteor-trail { opacity: .8; }
@keyframes atmo-meteor-sweep {
  0%   { transform: translate(-40px, var(--meteor-y, 0)) rotate(0deg); opacity: 0; }
  6%   { opacity: 1; }
  22%  { transform: translate(calc(100% + 40px), calc(var(--meteor-y, 0) - 60px)) rotate(0deg); opacity: 0; }
  100% { opacity: 0; }
}

.atmo-wisp {
  pointer-events: none;
  animation: atmo-wisp-drift 14s ease-in-out infinite;
}
@keyframes atmo-wisp-drift {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(18px); }
}

.atmo-cloud {
  pointer-events: none;
  animation: atmo-cloud-drift 16s ease-in-out infinite;
}
@keyframes atmo-cloud-drift {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(16px); }
}

@media (prefers-reduced-motion: reduce) {
  .atmo-star, .atmo-aurora, .atmo-meteor, .atmo-wisp, .atmo-cloud { animation: none !important; }
}
.layer-label {
  pointer-events: none;
  fill: #fff;
  font-weight: 600;
  text-shadow: 0 2px 8px rgba(0,0,0,.8);
  paint-order: stroke;
  stroke: rgba(0,0,0,.5);
  stroke-width: 3px;
}
.layer-altitude {
  pointer-events: none;
  fill: rgba(255,255,255,.65);
  font-size: 12px;
}
.layer-emoji-svg {
  pointer-events: none;
  user-select: none;
}

.selected-band { outline: 3px solid var(--accent) !important; outline-offset: -3px; }

/* Detail panel */
.detail-panel {
  position: absolute;
  right: 0; top: 0; bottom: 0;
  width: min(340px, 100vw);
  background: linear-gradient(180deg, #1a2f4d 0%, #0d1b2a 100%);
  border-left: 1px solid rgba(255,255,255,.1);
  box-shadow: var(--shadow-lg);
  overflow-y: auto;
  z-index: 20;
  transform: translateX(100%);
  transition: transform .32s cubic-bezier(.2,.8,.3,1);
  padding: 20px 16px;
  display: flex;
  flex-direction: column;
}
.detail-panel.visible { transform: translateX(0); }

#close-detail {
  position: absolute;
  top: 10px; right: 10px;
  background: transparent;
  border: none;
  color: var(--sub);
  font-size: 24px;
  cursor: pointer;
  line-height: 1;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  transition: all .2s;
}
#close-detail:hover { background: rgba(255,255,255,.1); color: #fff; }

.detail-emoji {
  font-size: 48px;
  margin-bottom: 4px;
}
.detail-name {
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 2px;
}
.detail-altitude-range {
  font-size: 13px;
  color: var(--sub);
  margin-bottom: 14px;
}

/* Reuses Story Time's already-generated narration clips so a kid who can't
   read yet (or just doesn't want to) can still get every layer read to them
   right where they tapped, not only in the dedicated Story Time tab. */
.read-aloud-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(255,213,79,.14);
  border: 1px solid rgba(255,213,79,.35);
  color: var(--accent);
  border-radius: 20px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  margin-bottom: 12px;
  transition: all .2s;
}
.read-aloud-btn:hover { background: rgba(255,213,79,.22); transform: scale(1.03); }
.read-aloud-btn:active { transform: scale(.97); }
.read-aloud-btn.reading {
  background: linear-gradient(90deg, #ffd54f, #ffb74d);
  color: #26200a;
  animation: read-aloud-pulse 1s ease-in-out infinite;
}
@keyframes read-aloud-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,213,79,.4); }
  50% { box-shadow: 0 0 0 6px rgba(255,213,79,0); }
}
.detail-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--accent);
  margin-bottom: 12px;
}
.facts-list {
  list-style: none;
  padding: 0; margin: 0;
}
.fact-item {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 12px;
  font-size: 14px;
  line-height: 1.45;
}
.fact-bullet {
  width: 8px; height: 8px;
  background: var(--accent);
  border-radius: 50%;
  margin-top: 5px;
  flex-shrink: 0;
}

.fun-fact-box {
  background: rgba(255,213,79,.1);
  border-left: 3px solid var(--accent);
  padding: 12px 14px;
  border-radius: 0 8px 8px 0;
  margin: 14px 0;
  font-size: 13px;
  line-height: 1.5;
}
.fun-fact-box strong { color: var(--accent); }

.vehicles-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
}
.vehicle-tag {
  background: rgba(255,255,255,.08);
  padding: 4px 10px;
  border-radius: 14px;
  font-size: 12px;
}

.temp-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(100,180,255,.15);
  color: #7ec8ff;
  padding: 4px 10px;
  border-radius: 14px;
  font-size: 12px;
  margin-top: 10px;
}

/* ── GASES VIEW ──────────────────────────────── */
/* Horizontal padding only -- was `padding: 0 16px`, which as an ID selector
   silently overrides .view's padding-top (IDs beat classes regardless of
   source order), zeroing the clearance meant to keep content out from under
   the fixed nav. Always sat too close to the nav for both views; only became
   an interaction bug once the "Why It Stays" read-aloud button landed right at
   the top of that view (found 2026-08-22 via a click that kept hitting the nav
   instead of the button). */
#view-gases, #view-why { padding-left: 16px; padding-right: 16px; }

#gases-chart {
  /* Was aspect-ratio:1, reserving a full square region for what actually
     renders as a short horizontal bar + legend -- left a large empty gap
     before the gas cards below. Found in the 2026-08-22 UI review; height
     should follow its actual content, not a leftover square assumption. */
  position: relative;
  width: 100%;
  max-width: 380px;
  margin: 0 auto 24px;
}

.gas-bar-list {
  list-style: none;
  padding: 0; margin: 0;
  max-width: 380px;
  margin: 0 auto 24px;
}
.gas-bar-row {
  margin-bottom: 12px;
}
.gas-bar-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
  font-size: 14px;
}
.gas-name { font-weight: 600; }
.gas-pct { color: var(--sub); font-size: 13px; }
.gas-bar-track {
  height: 14px;
  background: rgba(255,255,255,.08);
  border-radius: 7px;
  overflow: hidden;
}
.gas-bar-fill {
  height: 100%;
  border-radius: 7px;
  transition: width 1s ease-out;
}

/* Made Of view animation (2026-08-22, Ryan: "turn all of it into
   animations"). The stacked bar's segments use flex-grow for proportional
   layout, so the grow-in effect animates transform:scaleX (which doesn't
   touch layout) rather than width (which would). */
.gas-seg-grow {
  transform: scaleX(0);
  transform-origin: left;
  animation: gas-seg-grow-in .8s cubic-bezier(.2,.8,.3,1) forwards;
}
@keyframes gas-seg-grow-in { to { transform: scaleX(1); } }

.gas-particles { position: absolute; top: -30px; left: 0; right: 0; height: 26px; pointer-events: none; }
.gas-particle {
  position: absolute;
  top: 10px;
  width: 5px; height: 5px;
  border-radius: 50%;
  opacity: 0;
  animation: gas-particle-float 4s ease-in-out infinite;
}
@keyframes gas-particle-float {
  0%   { transform: translateY(0); opacity: 0; }
  15%  { opacity: .8; }
  85%  { opacity: .8; }
  100% { transform: translateY(-22px); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .gas-seg-grow { animation: none; transform: scaleX(1); }
  .gas-particle { animation: none; opacity: 0; }
}

.gas-facts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  max-width: 420px;
  margin: 0 auto;
}
.gas-card {
  background: var(--card-bg-raised);
  border-radius: 14px;
  padding: 14px;
  text-align: center;
  box-shadow: var(--shadow-sm);
  transition: transform .15s ease, box-shadow .15s ease;
  opacity: 0;
  animation: gas-card-in .4s cubic-bezier(.2,.8,.3,1.1) forwards;
}
@keyframes gas-card-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.gas-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
@media (prefers-reduced-motion: reduce) { .gas-card { animation: none; opacity: 1; } }
.gas-card-emoji { font-size: 32px; }
.gas-card-name { font-weight: 600; font-size: 14px; margin-top: 4px; }
.gas-card-pct { color: var(--sub); font-size: 12px; }
.gas-card-desc { font-size: 12px; color: var(--sub); line-height: 1.45; margin-top: 8px; text-align: left; }

/* ── WHY VIEW ────────────────────────────────── */
.why-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding-bottom: 30px;
}

.earth-diagram {
  width: 100%;
  max-width: 320px;
}

/* Why It Stays diagram animation (2026-08-22, Ryan: "turn all of it into
   animations"). Was a fully static SVG -- rings, arrows, and two frozen
   balloon states, no motion anywhere. transform-box:fill-box makes each
   ring/arrow scale/animate around its OWN geometric center rather than the
   SVG viewport origin (the default, which would make it drift sideways). */
.why-ring {
  transform-box: fill-box;
  transform-origin: center;
  animation: why-ring-breathe 4s ease-in-out infinite;
}
@keyframes why-ring-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}

.why-gravity-arrow {
  stroke-dasharray: 4 4;
  animation: why-arrow-flow 1s linear infinite;
}
@keyframes why-arrow-flow { to { stroke-dashoffset: -16; } }

.why-balloon { animation: why-balloon-rise 6s ease-in-out infinite; }
@keyframes why-balloon-rise {
  0%   { transform: translate(90px, 170px) scale(.55); opacity: 0; }
  8%   { opacity: .9; }
  50%  { transform: translate(155px, 90px) scale(1); opacity: 1; }
  92%  { opacity: .9; }
  100% { transform: translate(220px, 32px) scale(1.45); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .why-ring, .why-gravity-arrow, .why-balloon { animation: none !important; opacity: 1; }
}
.why-text {
  font-size: 15px;
  line-height: 1.7;
  max-width: 520px;
}
.why-text p { margin-bottom: 14px; }

.fun-callout {
  display: flex;
  gap: 12px;
  background: rgba(255,213,79,.08);
  border-left: 3px solid var(--accent);
  padding: 14px 16px;
  border-radius: 0 10px 10px 0;
  margin: 16px 0;
  font-size: 14px;
  line-height: 1.55;
}
.callout-icon { font-size: 24px; flex-shrink: 0; }

.pressure-chart {
  margin-top: 24px;
  width: 100%;
  max-width: 520px;
}
.pc-row {
  display: grid;
  grid-template-columns: 80px 1fr 44px;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.pc-altitude {
  font-size: 12px;
  color: var(--sub);
  text-align: right;
  white-space: nowrap;
}
.pc-track {
  height: 12px;
  background: rgba(255,255,255,.07);
  border-radius: 6px;
  overflow: hidden;
}
.pc-fill {
  height: 100%;
  background: linear-gradient(90deg, #ffd54f, #ff8a65);
  border-radius: 6px;
  transition: width 1.2s ease-out;
}
.pc-value {
  font-size: 12px;
  color: var(--sub);
}

/* ── FLY VIEW (flight sim) ───────────────────── */
.fly-view { padding-bottom: 30px; }
.fly-layout {
  display: flex;
  gap: 18px;
  align-items: stretch;
  max-width: 720px;
  margin: 0 auto;
  width: calc(100% - 24px);
}
.fly-stage-wrap {
  position: relative;
  flex: 0 0 min(46vw, 300px);
  display: flex;
  flex-direction: column;
}
.fly-groundbar {
  height: 22px;
  background: linear-gradient(180deg, #6fbf5a, #3e7d3a);
  border-radius: 8px 8px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
  letter-spacing: .5px;
}
.fly-stage {
  position: relative;
  height: min(56vh, 520px);
  overflow: hidden;
  border-radius: 12px;
  border: 1px solid rgba(255,255,255,.12);
  background: #0a1626;
}
/* backdrop layer bands (positioned by JS with % heights) */
.fly-band {
  position: absolute;
  left: 0; right: 0;
  pointer-events: none;
}
.fly-band-name {
  position: absolute;
  left: 8px;
  top: 4px;
  font-size: 12px;
  color: rgba(255,255,255,.5);
  pointer-events: none;
  white-space: nowrap;
}
#fly-object {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  font-size: 34px;
  line-height: 1;
  will-change: bottom;
  filter: drop-shadow(0 4px 6px rgba(0,0,0,.5));
  transition: none;
}
/* altitude ruler ticks on the stage's right edge */
.fly-tick {
  position: absolute;
  right: 0;
  width: 14px;
  border-top: 1px dashed rgba(255,255,255,.18);
  font-size: 12px;
  color: rgba(255,255,255,.45);
  text-align: left;
  padding-left: 17px;
  pointer-events: none;
}
.fly-readout {
  margin-top: 10px;
  background: var(--card-bg-raised);
  border-radius: 14px;
  padding: 12px 14px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 16px;
  box-shadow: var(--shadow-sm);
}
.readout-item { display: flex; flex-direction: column; }
.readout-label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--sub);
}
.readout-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.readout-value small { font-size: 12px; color: var(--sub); font-weight: 500; }
.density-bar-wrap {
  grid-column: span 2;
  height: 10px;
  background: rgba(255,255,255,.07);
  border-radius: 5px;
  overflow: hidden;
}
.density-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #7ec8ff, #b3e5fc);
  transition: width .2s linear;
}

.fly-side {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}
.object-picker {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.object-card {
  background: var(--card-bg-raised);
  border: 2px solid transparent;
  border-radius: 14px;
  padding: 12px 10px;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: all .18s;
  position: relative;
}
.object-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.object-card:active { transform: scale(.96); }
.object-card.selected {
  border-color: var(--accent);
  background: rgba(255,213,79,.08);
}
.object-card-emoji { font-size: 30px; }
.object-card-name { font-weight: 700; font-size: 13px; margin-top: 4px; }
.object-card-cap {
  font-size: 12px;
  color: var(--sub);
  margin-top: 2px;
  line-height: 1.35;
}
.launch-btn {
  background: linear-gradient(90deg, #ffd54f, #ffb74d);
  color: #26200a;
  border: none;
  border-radius: 26px;
  padding: 14px 20px;
  font-size: 16px;
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(255,213,79,.25);
  transition: all .2s;
}
.launch-btn:hover:not(.disabled) { transform: scale(1.03); }
.launch-btn:active:not(.disabled) { transform: scale(.96); box-shadow: 0 2px 6px rgba(255,213,79,.25); }
.launch-btn.disabled { filter: grayscale(.7); opacity: .6; cursor: default; box-shadow: none; }

.fly-callout {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: rgba(126,200,255,.1);
  border-left: 3px solid #7ec8ff;
  border-radius: 0 10px 10px 0;
  padding: 12px 14px;
  animation: callout-in .35s ease;
}
@keyframes callout-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.fly-callout.hidden { display: none; }
#fly-callout-emoji { font-size: 28px; line-height: 1.2; }
#fly-callout-text { font-size: 13px; line-height: 1.5; color: var(--text); }
#fly-callout-text strong { color: #bfe3ff; }
.fly-final-msg {
  margin-top: 4px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
}

@media (max-width: 560px) {
  .fly-layout { flex-direction: column-reverse; width: calc(100% - 24px); align-items: stretch; }
  .fly-stage-wrap { flex: none; order: -1; max-width: 340px; margin: 0 auto; width: 100%; }
  .fly-stage { height: 42vh; }
  .object-picker { grid-template-columns: repeat(4, 1fr); gap: 6px; }
  .object-card { padding: 8px 4px; }
  .object-card-emoji { font-size: 24px; }
  .object-card-name { font-size: 12px; }
  .object-card-cap { display: none; }
}
/* hide capacity caption room on very narrow: handled by media above */

/* ── Cloud Lab view ─────────────────────── */
.clouds-layout {
  display: flex;
  gap: 20px;
  align-items: stretch;
  margin: 18px auto 0;
  max-width: 720px;
}
.clouds-sky {
  position: relative;
  flex: 1 1 42%;
  min-height: 190px;
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(#bfe3ff 0%, #eaf6ff 60%, #ffffff 100%);
  box-shadow: inset 0 0 40px rgba(255,255,255,.7), 0 4px 18px rgba(0,0,0,.25);
  transition: filter .35s ease;
}
.clouds-sky[data-mood="clear"]   { background: linear-gradient(#4d9de8 0%, #a5d3ff 55%, #dff0ff 100%); }
.clouds-sky[data-mood="high"]    { background: linear-gradient(#5ba3e6 0%, #c3e2ff 60%, #f0faff 100%); }
.clouds-sky[data-mood="mid"]     { background: linear-gradient(#5b7fae 0%, #9fb8cf 55%, #d9e6ef 100%); }
.clouds-sky[data-mood="low"]     { background: linear-gradient(#3d5a78 0%, #7d9ab5 45%, #c0d2df 100%); }
.sky-badge {
  position: absolute;
  top: 10px;
  left: 12px;
  font-size: 12px;
  color: rgba(30,60,90,.8);
  background: rgba(255,255,255,.65);
  padding: 4px 10px;
  border-radius: 999px;
}
.sky-big-cloud {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(64px, 16vw, 120px);
  filter: drop-shadow(0 8px 18px rgba(0,0,0,.18));
  animation: cloud-bob 3.2s ease-in-out infinite;
  pointer-events: none;
}
@keyframes cloud-bob {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(-6px) scale(1.04); }
}

.clouds-controls {
  flex: 1 1 58%;
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--panel, #ffffff14);
  backdrop-filter: blur(6px);
  border-radius: 16px;
  padding: 16px;
}
.slider-row label {
  display: block;
  font-weight: 700;
  margin-bottom: 8px;
  color: var(--text, #eaf4ff);
  font-size: 14px;
}
input[type="range"] {
  width: 100%;
  height: 12px;
  accent-color: var(--accent, #ffd54f);
  cursor: grab;
}
input[type="range"]:active { cursor: grabbing; }
.tiny-note {
  font-size: 12px;
  color: var(--sub, #9ab3d4);
  line-height: 1.4;
  margin-top: auto;
  text-align: left;
}

.cloud-result {
  max-width: 720px;
  margin: 18px auto 0;
  background: var(--card-bg-raised);
  border-radius: 18px;
  padding: 18px 16px;
  box-shadow: var(--shadow-md);
  animation: callout-in .35s ease;
}
.cloud-result.hidden { display: none; }
.cloud-result-emoji {
  font-size: clamp(52px, 12vw, 78px);
  text-align: center;
  line-height: 1.1;
}
.cloud-result-title {
  text-align: center;
  font-size: clamp(19px, 4.5vw, 24px);
  margin: 8px 0 4px;
  color: var(--accent, #ffd54f);
}
.cloud-result-desc {
  text-align: center;
  line-height: 1.55;
  color: var(--text, #eaf4ff);
  font-size: clamp(13px, 3vw, 15px);
  max-width: 56ch;
  margin: 0 auto 14px;
}
.cloud-clue { text-align: left; }
.cloud-replay {
  margin-top: 14px;
  width: 100%;
  background: transparent;
  border: 2px dashed var(--sub, #9ab3d4);
  color: var(--sub, #9ab3d4);
  padding: 10px;
  border-radius: 12px;
  cursor: pointer;
  font-weight: 700;
  transition: all .2s;
}
.cloud-replay:hover { border-color: var(--accent, #ffd54f); color: var(--accent, #ffd54f); }

/* ── STORY TIME view ──────────────────────── */
.story-view {
  padding-bottom: 30px;
}
.story-reader {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  max-width: 560px;
  margin: 0 auto;
}
.story-art {
  /* Was a fixed circular "porthole" sized for a single emoji glyph -- full
     illustrated scenes (see STORY_SCENES in app.js) read better as a rounded
     rectangle so nothing meaningful gets clipped by a circle mask, matching
     the same treatment used in Water Cycle's story-art. */
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: var(--card-bg);
  border-radius: var(--radius-lg, 24px);
  overflow: hidden;
  box-shadow: inset 0 4px 20px rgba(0,0,0,.3), 0 6px 24px rgba(0,0,0,.35);
  margin: 0 auto;
}
.story-emoji { font-size: clamp(64px, 20vw, 104px); line-height: 1; }

/* Per-page story illustrations (see STORY_SCENES in app.js) -- reuses the
   EXACT same keyframes as the Layers view's per-layer atmospheric detail
   (atmo-twinkle, atmo-aurora-drift, atmo-meteor-sweep, atmo-wisp-drift,
   atmo-cloud-drift -- defined earlier in this file) so the storybook feels
   like the same illustrated world as the interactive Layers tab, not a
   different art style. Built 2026-08-22 at Ryan's request. */
.story-scene { width: 100%; height: 100%; display: block; animation: scene-in .4s cubic-bezier(.2,.8,.3,1.1) both; }
@keyframes scene-in { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }

.story-star { fill: #fff; animation: atmo-twinkle 2.6s ease-in-out infinite; }
.story-star-big { fill: #ffd54f; animation: atmo-twinkle 2s ease-in-out infinite; }
.story-cloud-puffs { animation: atmo-cloud-drift 16s ease-in-out infinite; }
.story-wisp { animation: atmo-wisp-drift 14s ease-in-out infinite; }
.story-wisp-2 { animation-duration: 18s; animation-direction: reverse; }
.story-aurora { filter: blur(2px); animation: atmo-aurora-drift 9s ease-in-out infinite; }
.story-aurora-b { animation-duration: 12s; animation-direction: reverse; }
.story-meteor {
  animation: atmo-meteor-sweep 4s cubic-bezier(.3,0,.7,1) infinite;
  animation-delay: 1s;
  opacity: 0;
}
.story-wave-arm { animation: story-wave 1.6s ease-in-out infinite; transform-origin: -9px 2px; }
@keyframes story-wave { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(18deg); } }

@media (prefers-reduced-motion: reduce) {
  .story-scene, .story-star, .story-star-big, .story-cloud-puffs, .story-wisp,
  .story-aurora, .story-meteor, .story-wave-arm { animation: none !important; opacity: 1; }
}
.story-title {
  text-align: center;
  font-size: clamp(20px, 5vw, 26px);
  font-weight: 700;
  margin: 2px 0;
  color: var(--text);
}
.story-subtitle {
  text-align: center;
  color: var(--sub);
  font-size: 14px;
  max-width: 50ch;
  margin: 0;
  line-height: 1.45;
}
/* Narration script the kid reads along to — large and easy. */
.story-script {
  width: 100%;
  text-align: center;
  background: var(--card-bg);
  border-radius: 16px;
  padding: 18px 20px;
  font-size: clamp(19px, 5.5vw, 24px);
  line-height: 1.55;
  color: var(--text);
  box-shadow: inset 0 2px 10px rgba(0,0,0,.2);
}
.play-btn {
  /* primary action — glowing like .launch-btn */
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
  background: linear-gradient(90deg, #ffd54f, #ffb74d);
  color: #26200a;
  border: none;
  border-radius: 30px;
  padding: 16px 26px;
  font-size: 17px;
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 5px 18px rgba(255,213,79,.35);
  transition: all .2s;
}
.play-btn:hover:not(.playing) { transform: scale(1.04); }
.play-btn:active { transform: scale(.97); }
.play-icon { font-size: 18px; line-height: 1; }
.story-nav {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  max-width: 420px;
  margin-top: 4px;
}
.nav-story-btn {
  flex: 0 1 auto;
  background: var(--card-bg);
  border: 2px solid transparent;
  color: var(--text);
  padding: 12px 14px;
  min-width: 92px;
  border-radius: 16px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: all .2s;
}
.nav-story-btn:hover { border-color: var(--accent); }
.nav-story-btn:active { transform: scale(.94); }
.nav-story-btn:disabled { opacity: .4; cursor: default; filter: grayscale(.6); }
.story-counter {
  flex: 1;
  text-align: center;
  color: var(--sub);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.story-hint {
  text-align: center;
  color: var(--sub);
  font-size: 13px;
  line-height: 1.4;
  max-width: 48ch;
  margin-top: 4px;
}
#story-load-note {
  align-self: center;
  max-width: 48ch;
  word-break: break-word;
}

@media (max-width: 560px) {
  .story-reader { gap: 14px; }
  .nav-story-btn { width: calc(50% - 8px); padding: 12px 6px; }
  .play-btn { padding: 16px 24px; }
}

@media (max-width: 520px) {
  .story-nav { max-width: none; }
}

/* ── RESPONSIVE: narrow foldable (~340px) ─────── */
@media (max-width: 520px) {
  .detail-panel {
    /* Was `position: fixed`, which positions relative to the VIEWPORT and so
       escapes .atmo-wrapper's `overflow: hidden` clipping entirely (only a
       transform/filter-creating ancestor makes fixed descendants relative to
       it instead) -- the panel's hidden state (translateY(100%), ~680px on a
       typical phone) then expanded the whole PAGE's scrollable area to cover
       that off-screen geometry, leaving a large empty scrollable void below
       the real content that a child could swipe into. `absolute` positions
       relative to .atmo-wrapper (already `position: relative` +
       `overflow: hidden`), which correctly clips it and produces the exact
       same full-screen slide-up visual with none of the phantom scroll.
       Found 2026-08-22 after Ryan reported the Layers view being confusing
       for a child -- confirmed via document.body.scrollHeight nearly double
       the viewport height. */
    position: absolute;
    inset: 0;
    width: 100% !important;
    transform: translateY(100%);
    z-index: 200;
  }
  .detail-panel.visible { transform: translateY(0); }
  h1 small { display: none; }
}

@media (max-width: 340px) {
  .nav-left h1 { font-size: 0; }
  .tab { padding: 6px 8px; font-size: 12px; }
}

/* ── "Read this page" button, lives IN THE NAV BAR ───────────────────────
   Was a fixed bottom-right floating button -- found as a real bug 2026-08-22:
   it physically overlapped whatever content a view happened to render near
   the bottom of the viewport (Story Time's "Next" button, Cloud Lab's replay
   button). Padding-bottom on the view container does NOT fix this -- it only
   adds scrollable space AFTER existing content, it never moves already-
   flowed content up off a fixed-position overlay. The nav bar is a protected
   zone nothing else ever renders into, so a button placed there can never
   collide with per-view content. */
.read-page-btn {
  flex-shrink: 0;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: linear-gradient(135deg, #ffd54f, #ffb74d);
  border: none;
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform .15s;
}
.read-page-btn:active { transform: scale(.9); }
.read-page-icon { font-size: 16px; }
.read-page-btn.reading { animation: read-page-pulse 1s ease-in-out infinite; }
@keyframes read-page-pulse {
  0%, 100% { box-shadow: var(--shadow-sm), 0 0 0 0 rgba(255,213,79,.5); }
  50% { box-shadow: var(--shadow-sm), 0 0 0 8px rgba(255,213,79,0); }
}
@media (prefers-reduced-motion: reduce) { .read-page-btn.reading { animation: none; } }
