:root {
  --bg-dark: #05080C;
  --border-dark: rgba(255, 255, 255, 0.08);
  --text: #F1F5F9;
  --text-dim: #93A0B8;
  --accent: #818CF8;
  --correct: #38BDF8;
  --incorrect: #ED7071;

  /* categorical palette used for category/domain badges + bars + rings, cycled by index */
  --pal-0: #A78BFA;
  --pal-1: #38BDF8;
  --pal-2: #FBBF24;
  --pal-3: #F472B6;
  --pal-4: #34D399;
  --pal-5: #818CF8;
  --pal-6: #FB7185;
  --pal-7: #2DD4BF;
  --pal-8: #FACC15;
  --pal-9: #60A5FA;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  height: 100%;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg-dark);
  color: var(--text);
  overscroll-behavior: none;
}

#app {
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* ============================= INFOGRAPHIC (top 2/3) ============================= */

#infographic-panel {
  position: relative;
  flex: 2 1 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 10px 12px 6px;
  /* Dark cosmic base: left side stays near-black/navy, a soft teal atmosphere
     builds toward the upper-right, per spec. */
  background:
    radial-gradient(ellipse 70% 55% at 88% 6%, rgba(20, 130, 140, 0.16), transparent 65%),
    radial-gradient(ellipse 60% 45% at 100% 0%, rgba(8, 35, 42, 0.6), transparent 70%),
    linear-gradient(120deg, #02080F 0%, #05101A 55%, #06111B 100%);
  border-bottom: 1px solid var(--border-dark);
  overflow: hidden;
}

#stars {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.star {
  position: absolute;
  background: white;
  border-radius: 50%;
  opacity: 0.6;
  animation: twinkle 3s ease-in-out infinite;
}

@keyframes twinkle {
  0%, 100% { opacity: 0.15; }
  50% { opacity: 0.85; }
}

/* --- Top panel: header + legend + stat pills, all inside one glassy bordered card ---
   Every size in this block uses clamp(min, Nvh, max) instead of a fixed
   value - on a real narrow/tall phone this header was eating a big fixed
   chunk of the whole top panel's height (sized/tested against a wider
   screenshot earlier), leaving too little room for the category grid below
   it, whose cards then got clipped. vh (not vw) on purpose: the constraint
   here is genuinely about how much of the viewport's HEIGHT this takes.
   The vh coefficients are calibrated so the ORIGINAL (max) size is only
   reached around a ~1050px-tall viewport - comfortably above every real
   phone, so real phones always get a real reduction - and a real device at
   ~780px viewport height lands at roughly 70-75% of the original size. An
   earlier pass used larger vh coefficients that hit their own max on a real
   phone's actual height, making the clamp a no-op - this was recalculated
   against real numbers, not guessed. */
.top-panel {
  position: relative;
  flex: 0 0 auto;
  border: 1.5px solid transparent;
  border-radius: 18px;
  padding: clamp(5px, 1.15vh, 12px) clamp(6px, 1.35vh, 14px) clamp(4px, 0.95vh, 10px);
  backdrop-filter: blur(6px);
  /* Layered backgrounds fake a gradient border: the fill layers (clipped to
     padding-box) paint a horizontal dark navy -> teal interior gradient, the
     last layer (clipped to border-box) paints the stroke itself as a muted
     metallic champagne gradient instead of one flat color. */
  background:
    linear-gradient(90deg, #080D18 0%, #0B1620 55%, #0C2027 100%) padding-box,
    linear-gradient(155deg, #AAA080 0%, #8D846C 45%, #625D4F 100%) border-box;
  box-shadow:
    0 3px 8px rgba(0, 0, 0, 0.55),
    0 0 4px rgba(190, 170, 120, 0.12),
    inset 0 1px 1px rgba(255, 255, 255, 0.05),
    inset 0 0 18px rgba(0, 0, 0, 0.30);
}

#recap-header {
  position: relative;
  text-align: center;
  flex: 0 0 auto;
  padding-bottom: clamp(3px, 1.15vh, 12px);
}

#recap-header h1 {
  margin: 0;
  font-size: clamp(0.85rem, 2.3vh, 1.5rem);
  font-weight: 300;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #D7E5F7;
  text-shadow: 0 0 4px rgba(180, 215, 255, 0.35), 0 0 12px rgba(120, 180, 255, 0.12);
}

/* --- Tier legend --- */
.tier-legend {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1px, 0.4vh, 4px) clamp(4px, 1.15vh, 12px);
  margin: clamp(1px, 0.4vh, 4px) 0 clamp(3px, 0.8vh, 8px);
}

.tier-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: clamp(0.55rem, 1.25vh, 0.8rem);
  color: #C7CFDA;
  font-weight: 500;
  white-space: nowrap;
}

.tier-dot {
  width: clamp(6px, 1.05vh, 11px);
  height: clamp(6px, 1.05vh, 11px);
  border-radius: 50%;
  flex-shrink: 0;
  background: radial-gradient(circle at 35% 30%, #fff 0%, currentColor 45%, currentColor 100%);
  box-shadow: 0 0 6px 1px currentColor, 0 0 2px 0 rgba(255, 255, 255, 0.6);
}

/* --- Radial wheel (one wedge per answered category, colored by accuracy tier) --- */
.ring-section {
  position: relative;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Turns this box into a query container, so .ring-square below can size
     itself as a percentage of ring-section's own actual width/height (cqw/
     cqh) - i.e. the real leftover space flexbox already computed for it.
     This replaces a JS approach that tried to re-derive that same number by
     manually summing sibling heights, which was consistently landing on a
     smaller value than the real available space. */
  container-type: size;
}

/* The largest square that fits ring-section's box: whichever of its width
   or height is smaller, at 100%. No JS, no measurement, always correct and
   updates immediately on any resize/orientation/layout change. */
.ring-square {
  position: relative;
  width: min(100cqw, 100cqh);
  height: min(100cqw, 100cqh);
}

.ring-diagram, .ring-diagram-svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.ring-label-name {
  font-size: 11px;
  font-weight: 700;
}

.ring-label-pct {
  font-size: 9.5px;
  font-weight: 600;
  fill: #93A0B8;
}

/* --- Category grid (alternate view - see CATEGORY_VIEW_MODE in app.js) ---
   Lists every category up front (25 today, see allCategories in app.js) as a
   fixed 5x5 grid that fills the section's full height via
   grid-template-rows: repeat(5, 1fr) instead of sizing cards to their
   content - that's what actually guarantees every row is visible with no
   scrolling and nothing clipped top or bottom, on any screen height. Cards
   are ordered highest score first (top-left) to lowest (bottom-right) - see
   the sort in buildCategoryGrid - grid items fill left-to-right/top-to-
   bottom in DOM order, so no extra CSS positioning is needed for that. */
.ring-section.grid-mode {
  align-items: center;
  justify-content: center;
  container-type: normal;
}

/* Slightly smaller than the full section (92%, centered) so cards read as
   slightly smaller/more compact than edge-to-edge - the actual card size is
   still driven by grid-template-rows/columns dividing this box, not a
   fixed px value, so it still scales with screen size. */
.ring-section.grid-mode .ring-square {
  width: 92%;
  height: 92%;
}

.category-grid {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
  gap: 6px;
  /* More top/bottom than left/right - the top and bottom rows were sitting
     right against the score panel above and the divider below with no
     breathing room. box-sizing:border-box (set globally) means this eats
     into the same fixed height as everything else, it doesn't grow it. */
  padding: 18px 6px;
}

.category-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* flex-end (not center) so the name+percentage always sit flush against
     the card's bottom edge as a unit - the percentage's position ends up
     the same across every card regardless of whether the name above it
     wrapped to 1 line or 3, instead of drifting depending on name length. */
  justify-content: flex-end;
  gap: 2px;
  min-width: 0;
  min-height: 0;
  border-radius: 10px;
  padding: 4px 3px;
  text-align: center;
  overflow: hidden;
  /* Same "known-good" smoked-glass fill used on .stat-block / .answer-btn
     (see handoff doc design log - don't redesign this part), border/glow
     color swapped per-card to the category's accuracy tier via currentColor. */
  background:
    linear-gradient(180deg, rgba(65, 76, 89, 0.70) 0%, rgba(24, 34, 46, 0.80) 100%),
    linear-gradient(135deg, rgba(25, 65, 70, 0.15), transparent 60%),
    rgba(31, 43, 55, 0.75);
  border: 1.5px solid currentColor;
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.12),
    inset 0 -3px 8px rgba(0, 0, 0, 0.18),
    0 0 8px -2px currentColor;
}

.category-card-name {
  /* Height = exactly 2 lines at CATEGORY_NAME_MAX_PX, but that height is no
     longer a hand-picked guess (a fixed 26px turned out shorter than some
     real phones' actual card height, silently deleting the 2nd line via
     overflow:hidden instead of just crowding it) - sizeCategoryGrid() in
     app.js measures this device's real card size and sets
     --category-name-height/--category-pct-font accordingly, before this
     value is read. The 26px/11px here are just a pre-JS fallback. Whatever
     the height ends up being, it NEVER changes based on the name's actual
     length - a 1-line name ("Sports") sits on the top line and leaves the
     2nd line's space empty rather than the box shrinking to fit it; a name
     that's too long for 2 lines at full size gets shrunk (see
     fitCategoryGridText in app.js) instead of adding a 3rd line or
     truncating. Either way every card's name box is the same height, so
     .category-card-pct right below it always lands in the same spot. */
  height: var(--category-name-height, 26px);
  font-size: 11px; /* fallback/initial value; fitCategoryGridText sets the real size inline */
  font-weight: 700;
  line-height: 1.15;
  color: #E7EEF9;
  overflow: hidden;
  width: 100%;
  /* Every wrapped word (single unbreakable names like "Entertainment", or
     the longest word in a multi-word name that still overflows) is
     hyphenated manually in JS (fitCategoryCardName in app.js) - a real "-"
     character inserted at a measured break point. CSS hyphens:auto is
     deliberately NOT used: it only inserts a break where the browser/OS
     has a dictionary entry, which is inconsistent word-to-word and left
     some names with no visible "-" at all. overflow-wrap is kept as a
     last-resort fallback; word-break:break-word is deliberately NOT used,
     it can break without ever showing a "-". */
  overflow-wrap: break-word;
}

.category-card-pct {
  font-size: var(--category-pct-font, 0.95rem);
  font-weight: 800;
  color: currentColor;
  flex-shrink: 0;
}

/* Categories with no answers yet: same layout, muted so the ones you've
   actually made progress on stand out. */
.category-card-empty {
  opacity: 0.55;
}

.category-card-empty .category-card-pct {
  font-weight: 700;
}

/* --- Stats strip: streak/timing stats in a horizontal row below the wheel ---
   Same vh-clamp treatment as .top-panel above - this row (icon + label +
   value in 3 pills) was the single biggest fixed-size contributor to the
   header eating too much of a real phone's vertical space. */
.stats-strip {
  flex: 0 0 auto;
  display: flex;
  gap: 6px;
  margin-top: clamp(2px, 0.6vh, 6px);
  margin-bottom: 2px;
}

.stat-block {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(3px, 0.8vh, 8px);
  /* Smoked glass: a soft vertical light-to-dark gradient with a faint teal
     tint layered over a translucent charcoal base, on a brushed silver
     (not gold) border. */
  background:
    linear-gradient(180deg, rgba(65, 76, 89, 0.70) 0%, rgba(24, 34, 46, 0.80) 100%),
    linear-gradient(135deg, rgba(25, 65, 70, 0.15), transparent 60%),
    rgba(31, 43, 55, 0.75);
  border: 1px solid rgba(166, 174, 185, 0.65);
  border-radius: 14px;
  padding: clamp(2px, 0.7vh, 7px) clamp(3px, 0.8vh, 8px);
  min-width: 0;
  text-align: center;
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.12),
    inset 0 -4px 12px rgba(0, 0, 0, 0.18),
    0 4px 8px rgba(0, 0, 0, 0.30);
}

.stat-block-icon {
  /* Temporarily hidden to save vertical space (see stats-strip complaint in
     mobile testing) - the trophy/bolt/dartboard SVGs are untouched in
     index.html, just not displayed. Delete this line to bring them back;
     .stat-block's existing flex centering + text-align:center already puts
     the label above the value, both centered, with no icon taking up room
     beside them, so nothing else needs to change to restore this either. */
  display: none;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
}

.stat-block-icon-svg {
  width: clamp(15px, 2.9vh, 30px);
  height: clamp(15px, 2.9vh, 30px);
  display: block;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}

.stat-block-label {
  font-size: clamp(0.42rem, 1.05vh, 0.68rem);
  color: #D3D8E0;
  text-transform: uppercase;
  font-weight: 400;
  letter-spacing: 0.03em;
}

.stat-block-value {
  font-size: clamp(0.75rem, 2.4vh, 1.55rem);
  font-weight: 600;
  line-height: 1.2;
  text-shadow: 0 0 3px currentColor;
}

.stat-block-gold .stat-block-value { color: #FFC44A; }
.stat-block-blue .stat-block-value { color: #31DDE6; }
/* Overall Score's value color is set inline in JS to match the same
   accuracy-tier color used on the wheel instead of a fixed color, so a 0%
   score reads as red like it does everywhere else. */

.empty-note {
  font-size: 0.62rem;
  color: var(--text-dim);
  text-align: center;
  padding: 0 4px;
  margin: auto;
}

/* ============================= ANSWER PANEL (bottom 1/3) ============================= */

#answer-panel {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  padding: 10px 10px 8px;
  min-height: 0;
  gap: 5px;
  /* Nearly-black navy glass, darkening toward the bottom - the starfield
     above should read as fully absorbed by the time it reaches here. */
  background: linear-gradient(180deg, rgba(3, 10, 18, 0.90) 0%, rgba(2, 8, 16, 0.97) 50%, rgba(1, 6, 12, 1) 100%);
  border-top: 1px solid rgba(150, 180, 205, 0.5);
}

#nav-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 0 4px;
}

.nav-btn {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid rgba(100, 150, 175, 0.55);
  /* Dark metallic/glass dome: brighter upper-left, fading to near-black
     lower-right, plus a faint cyan rim. */
  background: radial-gradient(circle at 30% 25%, #2E4658 0%, #122431 55%, #06121C 100%);
  box-shadow:
    inset 0 1px 1px rgba(210, 235, 250, 0.15),
    inset 0 -3px 6px rgba(0, 0, 0, 0.4),
    0 0 8px rgba(30, 180, 220, 0.12);
  font-size: 1.3rem;
  font-weight: 700;
  color: #9CCFE2;
  text-shadow: 0 0 3px rgba(80, 210, 255, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  flex-shrink: 0;
}

.nav-btn:disabled {
  opacity: 0.3;
}

#question-jump {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.question-jump-label {
  /* Reduced one step (was 0.95rem) to help make room for a larger, easier
     to use question-number input below; nudged back up slightly (0.8rem)
     for legibility. This only affects the label's own box - the divider
     line above it is #answer-panel's border-top, an unrelated sibling
     element, so it doesn't move regardless of this font size. */
  font-size: 0.85rem;
  font-weight: 400;
  color: #C4CEDA;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  /* Relative offset nudges the text up in place - doesn't move the divider
     line above (unrelated element) or the number box below (this doesn't
     affect layout flow, just where the text paints). */
  position: relative;
  top: -3px;
}

.question-jump-row {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  color: #BFCBDD;
  font-weight: 400;
  text-shadow: 0 0 4px rgba(130, 170, 220, 0.12);
}

.jump-number-wrap {
  position: relative;
  display: inline-flex;
}

#jumpInput {
  /* Bigger tap target/readability per explicit feedback that this was
     cramped to type into - wider (was 4.6em, then 6em), taller padding
     (was 5px, then 10px top/bottom), larger font (was 1.15rem, then
     1.4rem). Stepper arrows removed (redundant with the ‹ › nav buttons),
     so padding is now symmetric left/right. */
  width: 4.95em;
  text-align: center;
  font-size: 1.55rem;
  padding: 8px 8px;
  border: 1.5px solid #13CBE8;
  border-radius: 10px;
  font-weight: 500;
  color: #EDF4F7;
  background: linear-gradient(180deg, #162934 0%, #07131D 100%);
  box-shadow:
    inset 0 0 8px rgba(25, 210, 235, 0.12),
    0 0 6px rgba(20, 210, 235, 0.35),
    0 0 14px rgba(20, 210, 235, 0.12);
}

#nav-hint {
  flex: 0 0 auto;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 400;
  color: #BAC5D3;
  margin-top: -2px;
  margin-bottom: 2px;
}

#answers-grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 10px;
  min-height: 0;
}

/* Unified cyan smoked-glass control modules - all four buttons share
   identical construction and the same #38BDF8 accent, no per-letter
   rainbow coding. Pure CSS gradients/box-shadow, no SVG/mask/clip-path. */
.answer-btn {
  position: relative;
  overflow: hidden;
  /* Same smoked-glass card treatment as the stat-block pills up top
     (Best Streak / Current Streak / Overall Score) - a simple two-layer
     gradient over a translucent base, on a thin silver border. This is
     the known-good, proven-to-render-cleanly version; the earlier
     multi-layer faceted attempt kept producing visible seams. */
  background:
    linear-gradient(180deg, rgba(65, 76, 89, 0.70) 0%, rgba(24, 34, 46, 0.80) 100%),
    linear-gradient(135deg, rgba(25, 65, 70, 0.15), transparent 60%),
    rgba(31, 43, 55, 0.75);
  border: 1px solid rgba(166, 174, 185, 0.65);
  border-radius: 14px;
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.12),
    inset 0 -4px 12px rgba(0, 0, 0, 0.18),
    0 4px 8px rgba(0, 0, 0, 0.30);
  font-size: 0.92rem;
  font-weight: 600;
  color: #EEF1F3;
  padding: 6px 10px;
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  line-height: 1.15;
}

.answer-letter {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  align-self: center;
  border-radius: 50%;
  border: 1px solid #1595B3;
  border-top-color: #27BAD7;
  border-left-color: #27BAD7;
  box-shadow:
    inset -3px -4px 8px rgba(0, 0, 0, 0.55),
    inset 3px 3px 6px rgba(0, 0, 0, 0.20),
    inset 0 0 12px rgba(0, 0, 0, 0.45),
    0 3px 8px rgba(0, 0, 0, 0.60),
    0 0 6px rgba(56, 189, 248, 0.20);
  background-image:
    linear-gradient(180deg, #70D8FC 0%, #38BDF8 50%, #199FD4 100%),
    radial-gradient(circle at 35% 30%, #12303C 0%, #081923 45%, #02080E 100%);
  background-clip: text, border-box;
  -webkit-background-clip: text, border-box;
  color: transparent;
  font-size: 1.05rem;
  font-weight: 700;
  text-shadow: 0 0 4px rgba(56, 189, 248, 0.50), 0 0 10px rgba(56, 189, 248, 0.20);
  display: flex;
  align-items: center;
  justify-content: center;
}

.answer-text {
  position: relative;
  z-index: 1;
  flex: 1;
  min-width: 0;
  /* Stretch to the button's full height (overriding the row's own
     align-items: center) so JS can reliably compare scrollHeight against
     clientHeight to detect overflow and shrink the font to fit. */
  align-self: stretch;
  display: flex;
  align-items: center;
  overflow: hidden;
  font-size: 1.05rem;
  line-height: 1.2;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
  /* Safety net for a long single word (e.g. "Paleontologist") that's still
     too wide even at fitAnswerText's smallest font size in app.js - without
     this, a word with no space to wrap at just runs past the box edge and
     overflow:hidden above silently clips it instead of wrapping (2026-08-26
     fix, see fitAnswerText's comment in app.js for the full story). */
  overflow-wrap: break-word;
}

.answer-btn:active:not(:disabled) {
  transform: scale(0.97);
}

.answer-btn.correct {
  /* Rich glowing blue gradient fill + layered outer glow, instead of a
     flat color swap, for the correct answer. */
  background: linear-gradient(135deg, #041B4D 0%, #0A3FA8 45%, var(--correct) 100%);
  border-color: var(--correct);
  box-shadow:
    0 0 8px rgba(56, 189, 248, 0.9),
    0 0 20px rgba(56, 189, 248, 0.6),
    0 0 44px rgba(56, 189, 248, 0.35),
    inset 0 0 18px rgba(120, 200, 255, 0.25);
  color: #FFFFFF;
}

.answer-btn.incorrect {
  background: var(--incorrect);
  border-color: var(--incorrect);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);
  color: #3A0A0A;
}

.answer-btn.correct .answer-letter {
  background-image: none;
  background-color: #041B4D;
  background-clip: border-box;
  -webkit-background-clip: border-box;
  color: #FFFFFF;
  box-shadow: 0 0 8px rgba(56, 189, 248, 0.7);
  border-color: var(--correct);
  text-shadow: none;
}

.answer-btn.incorrect .answer-letter {
  background-image: none;
  background-color: #3A0A0A;
  background-clip: border-box;
  -webkit-background-clip: border-box;
  color: #FFFFFF;
  box-shadow: none;
  border-color: transparent;
  text-shadow: none;
}

/* The dark drop-shadow on .answer-text is tuned for the dark idle glass
   background - against the flat bright green/red resolved fill it just
   reads as a blurry smudge behind the letters, so drop it here. */
.answer-btn.correct .answer-text,
.answer-btn.incorrect .answer-text {
  text-shadow: none;
}

.answer-btn:disabled {
  opacity: 1;
}

/* ============================= HELP / INSTRUCTIONS ============================= */
/* Shown once, automatically, the first time a phone opens the page - no
   manual reopen trigger, per explicit "only needs to show up once and at
   the beginning" direction. (During testing, clear this browser's
   localStorage - key INTRO_SEEN_KEY in app.js - to see it again.) */

.help-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(2, 6, 10, 0.72);
  backdrop-filter: blur(4px);
  transition: opacity 0.15s ease;
}

.help-overlay.hidden {
  display: none;
}

.help-card {
  width: 100%;
  max-width: 360px;
  max-height: 88vh;
  overflow-y: auto;
  border-radius: 18px;
  border: 1.5px solid transparent;
  padding: 20px 18px 16px;
  /* Same gradient-border treatment as .top-panel, so this reads as part of
     the same visual system rather than a generic browser-style modal. */
  background:
    linear-gradient(90deg, #080D18 0%, #0B1620 55%, #0C2027 100%) padding-box,
    linear-gradient(155deg, #AAA080 0%, #8D846C 45%, #625D4F 100%) border-box;
  box-shadow:
    0 8px 24px rgba(0, 0, 0, 0.6),
    inset 0 1px 1px rgba(255, 255, 255, 0.05),
    inset 0 0 18px rgba(0, 0, 0, 0.30);
}

.help-card h2 {
  margin: 0 0 16px;
  text-align: center;
  /* Floor equals the old fixed 1.15rem (18.4px), so this is a strict
     increase at every width; grows up to 1.3rem (20.8px) by ~390px and
     holds there. */
  font-size: clamp(1.15rem, 5.4vw, 1.3rem);
  font-weight: 300;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #D7E5F7;
  text-shadow: 0 0 4px rgba(180, 215, 255, 0.35), 0 0 12px rgba(120, 180, 255, 0.12);
}

/* Horizontal scroll-snap carousel - gives native swipe for free, no touch-
   gesture JS needed. Next/Back buttons below just scroll it programmatically. */
.help-carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-bottom: 14px;
}

.help-carousel::-webkit-scrollbar {
  display: none;
}

.help-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 10px 8px;
  min-height: 150px;
  /* Whole slide is a tap target (see helpCarousel click handler in app.js -
     left half of the card goes back, right half advances/closes), so make
     that obvious this isn't just static text. */
  cursor: pointer;
}

.help-slide p {
  margin: 0;
  /* Scales with viewport width (not a fixed size) so it reads larger on
     typical phones while still shrinking gracefully on anything narrower
     than ~360px instead of overflowing/wrapping badly. Verified via a
     Python sweep across 320/360/375/390/430px: every value here comes out
     at or above the old fixed 0.95rem (15.2px) - floor is 320px -> 16.6px,
     and it reaches its 1.15rem (18.4px) ceiling by 360px and holds there. */
  font-size: clamp(0.95rem, 5.2vw, 1.15rem);
  line-height: 1.5;
  color: #C4CEDA;
}

.help-slide p strong {
  color: #EDF4F7;
  font-weight: 700;
}

.help-dismiss-btn {
  /* Not full-width like the old single-card version - this now sits inside
     one slide among plain text, so it reads as a clear CTA rather than a
     footer bar spanning the whole card. */
  width: 80%;
  padding: 12px;
  border-radius: 10px;
  border: 1.5px solid #13CBE8;
  background: linear-gradient(180deg, #162934 0%, #07131D 100%);
  color: #EDF4F7;
  /* Same responsive-scaling approach as .help-slide p; floor (1rem/16px) is
     already >= the old fixed 1rem, so this is a strict increase at every
     width, not just the wider ones. */
  font-size: clamp(1rem, 4.6vw, 1.1rem);
  font-weight: 600;
  cursor: pointer;
  box-shadow:
    inset 0 0 8px rgba(25, 210, 235, 0.12),
    0 0 6px rgba(20, 210, 235, 0.35),
    0 0 14px rgba(20, 210, 235, 0.12);
}

.help-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
}

.help-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(150, 180, 205, 0.35);
}

.help-dot.active {
  background: #13CBE8;
  box-shadow: 0 0 6px rgba(20, 210, 235, 0.6);
}

/* ============================= RESET SCORE ============================= */

#resetBtn {
  position: absolute;
  top: 0;
  right: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid rgba(150, 195, 220, 0.55);
  background: radial-gradient(circle at 30% 25%, #2E4658 0%, #122431 55%, #06121C 100%);
  color: #9CCFE2;
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
  box-shadow:
    inset 0 1px 1px rgba(210, 235, 250, 0.15),
    inset 0 -2px 4px rgba(0, 0, 0, 0.4),
    0 0 6px rgba(30, 180, 220, 0.15);
}

/* Reuses .help-overlay/.help-card for the same dimmed backdrop + gradient-
   border card shell as the intro carousel, so this reads as part of the
   same visual system instead of a second, differently-styled modal type. */
.reset-warning {
  margin: 0 0 20px;
  text-align: center;
  font-size: clamp(0.9rem, 4.2vw, 1.05rem);
  line-height: 1.5;
  color: #C4CEDA;
}

.reset-btn-row {
  display: flex;
  gap: 10px;
}

.reset-cancel-btn {
  flex: 1 1 0;
  padding: 12px;
  border-radius: 10px;
  border: 1.5px solid rgba(150, 180, 205, 0.5);
  background: linear-gradient(180deg, #1B2530 0%, #0B131B 100%);
  color: #C4CEDA;
  font-size: 1rem;
  font-weight: 600;
}

/* Destructive action gets the app's "weak/incorrect" red instead of the
   cyan used everywhere else, so it visually signals "this is different
   from a normal confirm" before the player even reads the label. */
.reset-confirm-btn {
  flex: 1 1 0;
  padding: 12px;
  border-radius: 10px;
  border: 1.5px solid #ED7071;
  background: linear-gradient(180deg, #3A1414 0%, #1A0707 100%);
  color: #FFD9D9;
  font-size: 1rem;
  font-weight: 700;
  box-shadow:
    inset 0 0 8px rgba(237, 112, 113, 0.15),
    0 0 6px rgba(237, 112, 113, 0.35),
    0 0 14px rgba(237, 112, 113, 0.12);
}

