/* Showcase theme for the app copy (play.html). Loaded after the app's own
   inline styles, so everything here is an override. Palette stays the app's;
   this layer brings the engraved-editorial look: Fraunces display type, mono
   labels, square plate cards, the amber accent, and a wider frame so the
   Atlas map gets real room. */

:root{
  --radius:3px;
  --radius-sm:3px;
  --amber:#C8862F;
  --amber-soft:#D9A45B;
}

/* ---------- Frame: use the screen ---------- */
.wrap{max-width:1240px;}
@media (min-width:1560px){.wrap{max-width:1420px;}}
@media (min-width:2200px){.wrap{max-width:1560px;}}

/* ---------- Masthead ---------- */
/* ONE bar, everywhere: same fixed geometry, same brand, menu and account
   chip, always white on dark. Only its backing breathes: transparent over
   the Home hero, and the engraved band cross-fades in when scrolling or
   stepping into a working tab. */
/* No overflow clipping here: the account menu drops below the bar and must
   hang free (the band pseudos are inset:0, so nothing else can bleed). */
.masthead{
  position:fixed;top:0;left:0;right:0;z-index:30;
  padding:0;
  background:none;
}
/* The band is the hero's own top strip, reproduced layer for layer: the
   ::before carries the same cover-cropped artwork and the ::after the same
   veil, both anchored to the viewport (background-attachment:fixed), so the
   bar shows exactly what the front page shows at scroll zero, at any screen
   size. Both fade as one. */
.masthead::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:#0F3B4C url("assets/hero.webp") center 38%/cover no-repeat;
  background-attachment:fixed;
  opacity:1;transition:opacity .45s ease;
}
.masthead::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    var(--grain) repeat,
    linear-gradient(92deg, rgba(13,34,44,.84) 0%, rgba(13,34,44,.5) 38%, rgba(13,34,44,.1) 64%, rgba(13,34,44,0) 78%),
    linear-gradient(180deg, rgba(15,59,76,.5) 0%, rgba(15,59,76,.16) 32%, rgba(14,37,48,.38) 74%, rgba(13,31,40,.85) 100%);
  background-blend-mode:overlay,normal,normal;
  background-attachment:fixed;
  opacity:1;transition:opacity .45s ease;
}
/* The bar goes clear wherever the page paints its own backdrop behind it:
   over the Home hero, and on the dark map shell tabs (Atlas, Practice,
   Quiz, Leaderboards), where the band's lighter strip used to sit against
   the page's darker engraving as a visible seam. Paper pages (Options,
   History, Admin) keep the band: the bar's text is white. */
body:has(#panel-home.active) .masthead.mast-clear::before,
body:has(#panel-home.active) .masthead.mast-clear::after,
body:has(#panel-study.active) .masthead.mast-clear::before,
body:has(#panel-study.active) .masthead.mast-clear::after,
body:has(#panel-quiz.active) .masthead.mast-clear::before,
body:has(#panel-quiz.active) .masthead.mast-clear::after,
body:has(#panel-test.active) .masthead.mast-clear::before,
body:has(#panel-test.active) .masthead.mast-clear::after,
body:has(#panel-ranks.active) .masthead.mast-clear::before,
body:has(#panel-ranks.active) .masthead.mast-clear::after{opacity:0;}
/* Navigation away from Home turns the band on in the same frame */
.masthead.mast-snap::before,.masthead.mast-snap::after{transition:none;}
@media (prefers-reduced-motion: reduce){
  .masthead::before,.masthead::after{transition:none;}
}
/* Fixed-attachment backgrounds are unreliable on mobile Safari; small
   screens get a pre-baked copy of the same strip instead. */
@media (max-width:820px){
  .masthead::before{
    background:#0F3B4C url("assets/bar-strip.webp") top center/cover no-repeat;
    background-attachment:scroll;
  }
  .masthead::after{display:none;}
}
.masthead > *{position:relative;z-index:1;}
.mast-top{margin-bottom:0;padding:13px clamp(16px,3vw,28px);flex-wrap:wrap;row-gap:8px;}
/* The old in-masthead hero block is retired; Home carries the presentation */
.masthead-inner{display:none;padding:14px clamp(16px,3vw,28px) 34px;}
.brand-home{margin:0;line-height:1;display:flex;}
.masthead .brand-q-dark{display:none;}

/* Content clears the fixed bar; Home's hero runs full-bleed beneath it */
.wrap{padding-top:calc(var(--mast-h, 64px) + 24px);}
body:has(#panel-home.active) .wrap{padding-top:0;padding-bottom:0;}
body:has(#panel-home.active) .event-banner{display:none;}
.brand-home{display:flex;align-items:center;gap:11px;text-decoration:none;}
.brand-q{height:34px;width:auto;display:block;filter:drop-shadow(0 1px 4px rgba(13,31,40,.5));}
.brand-word{
  font-family:var(--serif);font-weight:600;font-size:20px;color:#fff;
  letter-spacing:.01em;white-space:nowrap;
  text-shadow:0 1px 8px rgba(13,31,40,.6);
}
.brand-word em{font-style:italic;font-weight:400;color:var(--amber-soft);}
.brandblock h1{
  font-family:var(--serif);font-weight:600;
  font-size:clamp(25px,3.4vw,42px);line-height:1.12;
  text-shadow:0 2px 24px rgba(13,31,40,.5);
}
.subtitle{color:rgba(255,255,255,.88);}
.mast-stats{
  font-family:var(--mono);letter-spacing:.04em;
  background:rgba(13,34,44,.42);border:1px solid rgba(255,255,255,.14);
  border-radius:3px;padding:10px 14px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}

/* ---------- Tabs: mono, underline-active, amber ---------- */
.masthead .tabs .tab{
  font-family:var(--mono);font-size:12px;letter-spacing:.13em;text-transform:uppercase;
  background:transparent;border:0;border-radius:0;
  color:rgba(255,255,255,.74);padding:10px 12px;
  border-bottom:2px solid transparent;
}
.masthead .tabs .tab:hover{color:#fff;background:transparent;}
.masthead .tabs .tab[aria-selected="true"]{
  color:#fff;background:transparent;border-bottom-color:var(--amber);
}
.masthead .tab-div{background:rgba(255,255,255,.28);}

/* ---------- Control bars ---------- */
.scope-pill,.mode-seg button,.tc-pill{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.07em;text-transform:uppercase;
}
.scope-pill[aria-pressed="true"],.tc-pill.active{letter-spacing:.07em;}

/* The event pill wears the legacy tournament gold so it reads as a
   happening, not another region; selected trades the teal fill for gold. */
.tc-pill--event{
  border-color:rgba(200,134,47,.55);color:#8A6A1C;
  background-color:var(--surface);
  background-image:linear-gradient(180deg, rgba(255,214,110,.28), rgba(255,214,110,.06));
}
.tc-pill--event:hover:not(:disabled):not(.active){color:#6D5314;border-color:#C8862F;}
.tc-pill--event.active{
  color:#fff;border-color:#B8892A;
  background-color:#B8892A;
  background-image:linear-gradient(180deg,#D9A93C,#B8892A);
}
:root[data-theme="dark"] .tc-pill--event{color:#E3C06A;border-color:rgba(217,169,60,.55);}
:root[data-theme="dark"] .tc-pill--event:hover:not(:disabled):not(.active){color:#F0D089;border-color:#D9A93C;}
:root[data-theme="dark"] .tc-pill--event.active{color:#fff;}

/* ---------- Display type through the panels ---------- */
.home-h2,.panel h2,.panel h3,.tr-title,.tr-cel-head{
  font-family:var(--serif);font-weight:600;letter-spacing:0;
}
.panel-lede{color:var(--muted);}

/* ---------- Buttons: amber primary, deep text ---------- */
.cta-main,.btn-primary,.home-cta .cta-main{
  background:var(--amber);color:#0F3B4C;border:0;font-weight:600;
}
.cta-main:hover,.btn-primary:hover,.home-cta .cta-main:hover{background:var(--amber-soft);color:#0F3B4C;}
/* ... and it stays amber when it can't be pressed, so the greyed weight is
   the only thing that changed (see the base sheet's :disabled rule) */
.btn-primary:disabled:hover{background:var(--amber);color:#0F3B4C;}
.cta-alt:hover{color:var(--brand);}

/* ---------- Home ---------- */
.home{max-width:960px;margin:0 auto;}
.home-card{
  border:1px solid var(--line-strong);
  transition:transform .18s ease, box-shadow .18s ease;
}
.home-card:hover{transform:translateY(-3px);box-shadow:0 14px 30px -16px rgba(21,34,43,.3);}
.home-kicker{font-family:var(--mono);letter-spacing:.16em;text-transform:uppercase;font-size:11px;}

/* ---------- Atlas: give the map the screen ---------- */
/* The region bar sits above the plates (outside the map box) at full panel
   width; the extra 46px in the height budget is that bar's row + margin. */
.study-layout{height:clamp(500px,calc(100dvh - 221px),1150px);gap:24px;}
/* The bar rides the dark map shell in both themes, so its legacy dividers
   speak white there instead of the paper-toned --line-strong. */
#studyArea .study-cont-bar .scope-div{background:rgba(255,255,255,.28);}
.study-map-pane{flex:1.75;}
.study-map-pane,.study-list-pane{border-color:var(--line-strong);}
/* Where the map stops and the list starts is the reader's call on the page
   too, not only in fullscreen: the same rail, the same one number
   (--atlas-split, the map pane's share of the row). The rail simply takes
   the place of the gutter, being exactly as wide as the gap it replaces,
   and it takes its own width out of the sum first, so the two plates and
   the divider add up to the row exactly at any split. The default is the
   1.75:1 the layout has always shipped, so an Atlas nobody has dragged
   looks exactly as it did.

   Side by side only. Stacked (the phone rule below) the panes are not a
   box to divide: the layout is height:auto, the map is capped and the list
   runs on down the page, so there is nothing to negotiate and the rail
   stays hidden. Fullscreen is where a phone gets the two-pane split.

   The flex:1.75 above stays as the fallback: a fractional viewport (page
   zoom) can land between the two breakpoints, and a row with no rail must
   still be a row that adds up. */
@media (min-width:821px){
  .study-layout{gap:0;--atlas-rail:24px;}
  .study-map-pane{flex:0 0 calc((100% - var(--atlas-rail)) * var(--atlas-split, .64));}
  .study-list-pane{flex:1 1 0;}
  /* Above both plates: their shadows spill into the gutter the rail lives in */
  .study-split{display:flex;z-index:11;}
  /* Maximized: the losing plate leaves the flow altogether, its border and
     its scrollbar with it (the fullscreen rule further down, same reason). */
  .study-layout[data-atlas-collapsed="map"] .study-map-pane,
  .study-layout[data-atlas-collapsed="list"] .study-list-pane{display:none;}
}
@media (max-width:820px){
  /* The desktop height above would otherwise beat the app's own stacked
     phone rule (same specificity, this sheet loads later), squeezing the
     list into a sliver; restore the natural page-flow list. */
  .study-layout{height:auto;}
  #studyMap .africa-map{max-height:48vh;}
}

/* ---------- Account chip ---------- */
.acct-signin{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;
}

/* ---------- Small consistencies ---------- */
:focus-visible{outline:2px solid var(--amber);outline-offset:2px;}
.study-ghead,.study-hint{font-family:var(--mono);letter-spacing:.08em;text-transform:uppercase;}
.both-step{font-family:var(--mono);}

/* ==========================================================================
   Panels as engraved plates
   ========================================================================== */
:root{
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  --plate-shadow:0 1px 2px rgba(21,34,43,.06),0 14px 40px -18px rgba(21,34,43,.25);
  --paper-map:linear-gradient(180deg,#F8FBFC,#EDF3F5);
}

/* Atlas: the map sits on faintly tinted engraved paper */
.study-map-pane{position:relative;background:#F8FBFC;box-shadow:var(--plate-shadow);}
.study-map-pane::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:var(--paper-map);
}
.study-map-pane::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:var(--grain) repeat;opacity:.22;
}
.study-map-pane > *{position:relative;z-index:1;}
.study-list-pane{box-shadow:var(--plate-shadow);}

/* Question cards: plate with an amber top rule, and a framed map that uses
   the room a desktop gives it */
.card{
  border-color:var(--line-strong);border-top:2px solid var(--amber);
  box-shadow:var(--plate-shadow);
}
.card{padding:26px 28px 26px;}
.card-map--main{
  box-sizing:border-box;padding:8px;
  border:1px solid var(--line);background:var(--paper-map);
}
/* The question map grows with the screen, but never at the cost of pushing
   the answer box out of view. On desktop the pane spans the WHOLE card and
   budgets its height against the viewport (the fullscreen pane mechanics,
   inline): the SVG letterboxes inside, so wide continents finally spend the
   card's width while tall ones keep the same height the old fixed-width
   tiers allowed, and the answer box never sits lower than it used to. */
@media (min-width:1024px){
  .card-map--main{width:100%;aspect-ratio:auto;height:min(56vh,520px);}
}
@media (min-height:980px) and (min-width:1400px){.card-map--main{height:min(58vh,600px);}}
@media (min-height:1150px) and (min-width:1600px){.card-map--main{height:min(60vh,860px);}}
.card-flag{width:min(500px,100%);}
.answer-row,.answer-block{max-width:520px;}
.answer-row input{border-radius:3px;}
.answer-row input:focus{border-color:var(--amber);box-shadow:0 0 0 3px rgba(200,134,47,.18);}

/* Quiet buttons and segmented controls speak mono */
.btn-quiet{
  font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  border-radius:3px;
}
.lb-periods{border-radius:3px;}
.lb-periods button{font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;}

/* Event banner: a plate with a gold spine instead of a rounded toast */
.event-banner{
  border-radius:3px;border:1px solid var(--line-strong);border-left:4px solid var(--amber);
  background:var(--surface);box-shadow:var(--shadow-sm);
}

/* Empty and setup boxes: solid plates, no dashes */
.empty,.th-setup{border-style:solid;border-radius:3px;}
.th-row,.th-click{border-radius:3px;}
.th-click.open{border-bottom-left-radius:0;border-bottom-right-radius:0;}
.th-title{font-family:var(--mono);letter-spacing:.12em;}
.th-title::before{content:"";display:inline-block;width:7px;height:7px;background:var(--amber);margin-right:9px;}

/* Dialogs share the plate language */
.auth-modal{border-radius:3px;}
.auth-modal h3{font-family:var(--serif);font-weight:600;}

/* ---------- App footer, same as the landing ---------- */
.app-foot{background:#0B2028;text-align:center;padding:36px 20px 40px;}
.app-foot .foot-links{display:flex;justify-content:center;flex-wrap:wrap;gap:clamp(18px,4vw,40px);}
.app-foot .foot-links a{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.15em;text-transform:uppercase;
  text-decoration:none;color:rgba(255,255,255,.62);padding:4px 0;
  border-bottom:2px solid transparent;transition:color .16s ease,border-color .16s ease;
}
.app-foot .foot-links a:hover{color:#fff;border-bottom-color:var(--amber);}
.app-foot .foot-brand{
  margin:20px 0 0;font-family:var(--serif);font-weight:600;font-size:16px;
  color:rgba(255,255,255,.5);
}
.app-foot .foot-brand em{font-style:italic;font-weight:400;color:var(--amber-soft);opacity:.8;}

/* On phones the Atlas map pane sticks below the fixed bar, not under it.
   Last in the file on purpose: the plate section above sets
   position:relative for its paper pseudo-elements and must lose here. */
@media (max-width:820px){
  .study-map-pane{position:sticky;top:calc(var(--mast-h, 64px) + 6px);}
}

/* ==========================================================================
   Feature round: session dialog, quiz pickers, fullscreen, dark map shell
   ========================================================================== */

/* Max button on the rotation steppers */
.rc-max{width:auto;padding:0 9px;font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;}

/* Practice session dialog */
.sess-overlay{position:fixed;inset:0;z-index:60;background:rgba(11,32,40,.55);display:flex;align-items:center;justify-content:center;padding:18px;}
.sess-overlay[hidden]{display:none;}
.sess-modal{
  background:var(--surface);border:1px solid var(--line-strong);border-top:3px solid var(--amber);
  border-radius:3px;max-width:580px;width:100%;padding:22px 24px 20px;box-shadow:var(--plate-shadow);
  max-height:calc(100dvh - 40px);overflow:auto;
}
.sess-modal h3{font-family:var(--serif);font-weight:600;font-size:24px;margin:0 0 8px;}
.sess-lede{font-size:13.5px;color:var(--muted);margin:0 0 16px;line-height:1.55;}
.sess-field{margin:0 0 12px;}
.sess-lab{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin:0 0 7px;}
.sess-field .test-cont-bar{justify-content:flex-start;margin:0;}
.sess-carry{display:flex;gap:11px;align-items:flex-start;font-size:12.5px;color:var(--muted);line-height:1.5;margin:16px 0 18px;cursor:pointer;}
.sess-carry input{margin-top:3px;accent-color:var(--brand);}
.sess-carry b{color:var(--ink);font-weight:600;}
.sess-actions{display:flex;justify-content:flex-end;gap:10px;}

/* Quiz start box: pickers + personal best + timer */
.ts-pickers{margin:16px auto 6px;}
.ts-pickers .test-cont-bar{margin:0 0 8px;}
.ts-best{font-family:var(--mono);font-size:12px;letter-spacing:.04em;color:var(--muted);margin:10px 0 2px;}
.ts-best b{color:var(--brand);}
.ts-login label{font-weight:700;}
.test-timer{font-family:var(--mono);font-size:12px;letter-spacing:.1em;color:var(--muted);text-align:center;margin:2px 0 4px;}

/* Fullscreen atlas: one toggle on the map pane takes the whole Atlas, map
   and list together, full screen. Inside, the layout is the everyday one
   (same panes, same list): the extra room goes to the map, and the taller
   pane simply shows more rows (or more flags) at its usual reading width. */
.fs-btn{
  position:absolute;top:8px;left:8px;z-index:6;width:27px;height:27px;border-radius:6px;
  border:1px solid var(--line-strong);background:var(--surface);color:var(--muted);
  font-size:14px;line-height:1;cursor:pointer;opacity:.6;transition:opacity .15s ease;
}
.fs-btn:hover{opacity:1;color:var(--brand);border-color:var(--brand);}
/* The CSS fullscreen is what every iOS device gets (see toggleFs), so the
   page under it has to sit perfectly still: overflow:hidden stops the
   scroll, and overscroll-behavior stops the rubber band, which on iOS drags
   the fixed overlay along with it and reads as the screen coming loose.
   Inside, a list that reaches its end must not hand the rest of the gesture
   to the document either. */
body.fs-lock{overflow:hidden;overscroll-behavior:none;}
html:has(> body.fs-lock){overscroll-behavior:none;}
.fs-mode{overscroll-behavior:contain;}
#studyArea.fs-mode{position:fixed;inset:0;z-index:70;}
#studyArea:fullscreen,#studyArea.fs-mode{
  overflow:auto;box-sizing:border-box;
  display:flex;flex-direction:column;
  padding:clamp(10px,1.8vh,22px) clamp(12px,1.8vw,26px);
  background:
    linear-gradient(180deg, rgba(10,29,38,.93), rgba(12,38,49,.88) 42%, rgba(9,26,34,.94)),
    #0F3B4C url("assets/hero.webp") center 38%/cover no-repeat;
  background-attachment:fixed;
}
/* Practice and Quiz fullscreen share the Atlas shell: the question area
   becomes the screen, on the same engraved night backdrop. The card floats
   centered (margin:auto, so a tall report simply scrolls instead of
   clipping its top) at a reading width; the corner toggle rides the
   viewport, not the scroll. */
#quizArea,#testArea{position:relative;}
.fs-btn.fs-btn-r{left:auto;right:8px;}
#quizArea.fs-mode,#testArea.fs-mode{position:fixed;inset:0;z-index:70;}
#quizArea:fullscreen,#quizArea.fs-mode,
#testArea:fullscreen,#testArea.fs-mode{
  overflow:auto;box-sizing:border-box;
  display:flex;flex-direction:column;
  padding:clamp(10px,2vh,26px) clamp(12px,2.5vw,30px);
  background:
    linear-gradient(180deg, rgba(10,29,38,.93), rgba(12,38,49,.88) 42%, rgba(9,26,34,.94)),
    #0F3B4C url("assets/hero.webp") center 38%/cover no-repeat;
  background-attachment:fixed;
}
#quizArea:fullscreen > :not(.fs-btn),#quizArea.fs-mode > :not(.fs-btn),
#testArea:fullscreen > :not(.fs-btn),#testArea.fs-mode > :not(.fs-btn){
  margin:auto;width:min(880px,100%);
}
#quizArea:fullscreen > .fs-btn,#quizArea.fs-mode > .fs-btn,
#testArea:fullscreen > .fs-btn,#testArea.fs-mode > .fs-btn{
  position:fixed;top:12px;right:12px;opacity:.85;
}
/* Practice's card is normally squared off against the practice bar above
   it; fullscreen has no bar, so the card gets its corners back (the
   everyday rule carries two ids, hence the heavy selector). */
#panel-quiz #quizArea:fullscreen .card,#panel-quiz #quizArea.fs-mode .card{
  border-radius:var(--radius);padding-top:clamp(14px,2.2vh,26px);
}
/* The question card becomes the screen. The card grows to fill the
   viewport (flex, in the shell's column; the report keeps its centered
   reading card) and the question head hands every spare pixel to the
   map or flag pane, whose SVG / image letterboxes itself inside. All
   growth lives on the pane, and the panes are scoped to the question
   heads so the report's own #reportMap keeps its everyday sizing. */
/* flex 1 1 + min-height:0 + the max-height cap: the card fills exactly
   the screen, no more, so a tall continent's intrinsic SVG height can
   never push the input below the fold; the min-height:0 chain down to
   the pane lets the SVG letterbox inside whatever is left instead. */
#quizArea:fullscreen > .card,#quizArea.fs-mode > .card,
#testArea:fullscreen > .card:not(.test-report),#testArea.fs-mode > .card:not(.test-report){
  flex:1 1 auto;min-height:0;max-height:100%;
  margin:0 auto;display:flex;flex-direction:column;box-sizing:border-box;
  width:min(1680px,100%);
  padding:clamp(14px,2.2vh,26px) clamp(18px,2.5vw,44px) clamp(14px,2.2vh,26px);
}
#quizArea:fullscreen .q-prompt,#quizArea.fs-mode .q-prompt,
#testArea:fullscreen .q-prompt,#testArea.fs-mode .q-prompt{margin:4px 0 6px;}
#quizArea:fullscreen > .card > .card-main,#quizArea.fs-mode > .card > .card-main,
#testArea:fullscreen > .card:not(.test-report) > .card-main,#testArea.fs-mode > .card:not(.test-report) > .card-main{
  flex:1;display:flex;flex-direction:column;min-height:0;
}
#quizArea:fullscreen #qHead,#quizArea.fs-mode #qHead,
#testArea:fullscreen #testHead,#testArea.fs-mode #testHead{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
}
#quizArea:fullscreen #qHead .card-map--main,#quizArea.fs-mode #qHead .card-map--main,
#testArea:fullscreen #testHead .card-map--main,#testArea.fs-mode #testHead .card-map--main{
  flex:1 1 auto;min-height:120px;width:100%;aspect-ratio:auto;margin:8px 0 12px;
}
#quizArea:fullscreen #qHead .card-flag,#quizArea.fs-mode #qHead .card-flag,
#testArea:fullscreen #testHead .card-flag,#testArea.fs-mode #testHead .card-flag{
  flex:1 1 auto;min-height:120px;width:100%;margin:8px 0 12px;
  display:flex;flex-direction:column;
}
#quizArea:fullscreen #qHead .card-flag .fl-big,#quizArea.fs-mode #qHead .card-flag .fl-big,
#testArea:fullscreen #testHead .card-flag .fl-big,#testArea.fs-mode #testHead .card-flag .fl-big{
  flex:1 1 auto;min-height:0;width:auto;max-width:100%;margin:0 auto;
  aspect-ratio:auto;object-fit:contain;
}
/* While the phone keyboard is up, the card stops tracking the layout
   viewport (which the keyboard does NOT shrink) and pins itself to the
   visual viewport instead: wireKeyboardFit keeps --kb-vh/--kb-top in step
   with visualViewport, and the flex layout above then hands the map every
   pixel the prompt and answer rows leave over. Nothing is JS-measured
   inside the card, so a feedback row growing or the phone rotating simply
   reflows the same rules. The container goes overflow:hidden so the
   browser's focus-reveal PANS the visual viewport (which we track)
   instead of scrolling the card out from under the pin. (These land
   after the rules above; theme.css loads after the inline sheet that
   owns kb-compact, whose fixed-height map rule they also override.) */
body.kb-compact #quizArea:fullscreen,body.kb-compact #quizArea.fs-mode,
body.kb-compact #testArea:fullscreen,body.kb-compact #testArea.fs-mode{overflow:hidden;}
body.kb-compact #quizArea:fullscreen > .card,body.kb-compact #quizArea.fs-mode > .card,
body.kb-compact #testArea:fullscreen > .card:not(.test-report),body.kb-compact #testArea.fs-mode > .card:not(.test-report){
  flex:none;height:var(--kb-vh,100%);max-height:var(--kb-vh,100%);
  margin-top:var(--kb-top,0px);
}
body.kb-compact #quizArea:fullscreen #qHead .card-map--main,body.kb-compact #quizArea.fs-mode #qHead .card-map--main,
body.kb-compact #testArea:fullscreen #testHead .card-map--main,body.kb-compact #testArea.fs-mode #testHead .card-map--main{
  flex:1 1 auto;height:auto;min-height:80px;width:100%;margin:4px 0 8px;
}
body.kb-compact #quizArea:fullscreen #qHead .card-flag,body.kb-compact #quizArea.fs-mode #qHead .card-flag,
body.kb-compact #testArea:fullscreen #testHead .card-flag,body.kb-compact #testArea.fs-mode #testHead .card-flag{
  flex:1 1 auto;min-height:80px;margin:4px 0 8px;
}
body.kb-compact #quizArea:fullscreen #qHead .card-flag .fl-big,body.kb-compact #quizArea.fs-mode #qHead .card-flag .fl-big,
body.kb-compact #testArea:fullscreen #testHead .card-flag .fl-big,body.kb-compact #testArea.fs-mode #testHead .card-flag .fl-big{
  flex:1 1 auto;height:auto;min-height:0;width:auto;
}
/* Landscape PHONES are the one shape where stacking cannot work: the
   screen is only ~400px tall, so a map-over-input stack leaves a
   letterbox strip of map. Only here does the answer column move beside
   the map: the map keeps the full height on the left, the input and
   actions ride the right, and the card runs edge to edge like portrait.
   Everything is a media query, so rotating the phone mid-session
   reflows instantly, native fullscreen and fallback alike. */
@media (orientation:landscape) and (max-height:520px){
  #quizArea:fullscreen,#quizArea.fs-mode,
  #testArea:fullscreen,#testArea.fs-mode{padding:0;}
  #quizArea:fullscreen > .card,#quizArea.fs-mode > .card,
  #testArea:fullscreen > .card:not(.test-report),#testArea.fs-mode > .card:not(.test-report){
    width:100%;border-left:0;border-right:0;border-radius:0;
    padding:6px max(12px,env(safe-area-inset-right,0px)) 8px max(12px,env(safe-area-inset-left,0px));
  }
  #panel-quiz #quizArea:fullscreen .card,#panel-quiz #quizArea.fs-mode .card{
    border-radius:0;padding-top:6px;
  }
  #quizArea:fullscreen > .card > .card-main,#quizArea.fs-mode > .card > .card-main,
  #testArea:fullscreen > .card:not(.test-report) > .card-main,#testArea.fs-mode > .card:not(.test-report) > .card-main{
    display:grid;column-gap:16px;
    grid-template-columns:minmax(0,1fr) minmax(230px,320px);
    grid-template-rows:1fr auto auto 1fr;
  }
  #quizArea:fullscreen #qHead,#quizArea.fs-mode #qHead,
  #testArea:fullscreen #testHead,#testArea.fs-mode #testHead{
    grid-row:1 / 5;grid-column:1;
  }
  #quizArea:fullscreen .card .answer-block,#quizArea.fs-mode .card .answer-block,
  #testArea:fullscreen .card:not(.test-report) .answer-block,#testArea.fs-mode .card:not(.test-report) .answer-block{
    grid-row:2;grid-column:2;width:100%;
  }
  #quizArea:fullscreen .card .card-secondary,#quizArea.fs-mode .card .card-secondary,
  #testArea:fullscreen .card:not(.test-report) .card-secondary,#testArea.fs-mode .card:not(.test-report) .card-secondary{
    grid-row:3;grid-column:2;margin-top:10px;
  }
  #quizArea:fullscreen #qHead .card-map--main,#quizArea.fs-mode #qHead .card-map--main,
  #testArea:fullscreen #testHead .card-map--main,#testArea.fs-mode #testHead .card-map--main{margin:4px 0 2px;}
  /* Enter/Tab hints mean nothing to a touch keyboard and the column is
     cramped; the wrapping quiz pills stay clear of the corner toggle */
  #quizArea:fullscreen .kbd-hint,#quizArea.fs-mode .kbd-hint,
  #testArea:fullscreen .kbd-hint,#testArea.fs-mode .kbd-hint{display:none;}
  #testArea:fullscreen .test-cont-bar,#testArea.fs-mode .test-cont-bar{margin:0 34px 2px;}
}
/* Portrait devices: when the keyboard opens only the TOP of the screen
   stays visible, and the iPhone fallback keeps the browser chrome, so
   top pixels are the scarcest thing on the page. Fullscreen therefore
   pins the question to the very top and runs the card edge to edge;
   the input rides at the bottom, where the rising keyboard meets it. */
@media (orientation:portrait){
  #quizArea:fullscreen,#quizArea.fs-mode,
  #testArea:fullscreen,#testArea.fs-mode{padding:0;}
  #quizArea:fullscreen > .card,#quizArea.fs-mode > .card,
  #testArea:fullscreen > .card:not(.test-report),#testArea.fs-mode > .card:not(.test-report){
    width:100%;border-left:0;border-right:0;border-radius:0;
    padding:10px 14px calc(12px + env(safe-area-inset-bottom,0px));
  }
  /* outranks the corner-restore rule above (it carries two ids) */
  #panel-quiz #quizArea:fullscreen .card,#panel-quiz #quizArea.fs-mode .card{
    border-radius:0;padding-top:10px;
  }
  /* with the keyboard up the card bottoms out on the keyboard, not the
     device edge; the safe-area strip is behind the keys, reclaim it */
  body.kb-compact #quizArea:fullscreen > .card,body.kb-compact #quizArea.fs-mode > .card,
  body.kb-compact #testArea:fullscreen > .card:not(.test-report),body.kb-compact #testArea.fs-mode > .card:not(.test-report){
    padding-bottom:10px;
  }
  #quizArea:fullscreen .q-prompt,#quizArea.fs-mode .q-prompt,
  #testArea:fullscreen .q-prompt,#testArea.fs-mode .q-prompt{margin:2px 0 4px;}
  #quizArea:fullscreen #qHead .card-map--main,#quizArea.fs-mode #qHead .card-map--main,
  #testArea:fullscreen #testHead .card-map--main,#testArea.fs-mode #testHead .card-map--main{margin:6px 0 8px;}
  /* keep the wrapping continent pills clear of the fixed corner toggle */
  #testArea:fullscreen .test-cont-bar,#testArea.fs-mode .test-cont-bar{margin:0 34px 4px;}
}
/* The region bar keeps its band above the panes; the layout takes every
   remaining pixel instead of a hard viewport calc, so bar + map + list
   always fit the screen together. */
#studyArea:fullscreen .study-cont-bar,#studyArea.fs-mode .study-cont-bar{flex:none;}
#studyArea:fullscreen .study-layout,#studyArea.fs-mode .study-layout{
  flex:1 1 auto;min-height:0;height:auto;
}
/* How the screen is divided is the reader's call in here, so the two panes
   are sized off one number (--atlas-split, the map's share of the layout)
   and the rail between them is the control that sets it. The rail takes its
   own width out of the sum first, so the panes and the divider add up to
   the screen exactly, at any split. */
#studyArea:fullscreen .study-layout,#studyArea.fs-mode .study-layout{
  gap:0;--atlas-rail:24px;
}
#studyArea:fullscreen .study-map-pane,#studyArea.fs-mode .study-map-pane{
  flex:0 0 calc((100% - var(--atlas-rail)) * var(--atlas-split, .72));min-width:0;
}
#studyArea:fullscreen .study-list-pane,#studyArea.fs-mode .study-list-pane{
  flex:1 1 0;min-width:0;
}
/* Maximized: the losing pane leaves the flow altogether. A flex child
   squeezed to zero still draws its border and can still show a scrollbar,
   which reads as a seam rather than as a full-screen map. */
#studyArea:fullscreen .study-layout[data-atlas-collapsed="map"] .study-map-pane,
#studyArea.fs-mode .study-layout[data-atlas-collapsed="map"] .study-map-pane,
#studyArea:fullscreen .study-layout[data-atlas-collapsed="list"] .study-list-pane,
#studyArea.fs-mode .study-layout[data-atlas-collapsed="list"] .study-list-pane{display:none;}

/* The rail itself: a grip in the middle of it and an arrow either side of
   the grip that takes the split all the way. The geometry is shared with
   the page (the Atlas section near the top of this file); what fullscreen
   adds is the hairline down its length, because in there the panes run
   edge to edge and the rail is the only thing marking where one ends. On
   the page the two plates draw their own edges, so the line stays away
   until you go near the rail. Either way nothing announces itself at rest,
   which is all a divider should be. */
.study-split{
  flex:0 0 var(--atlas-rail,24px);align-self:stretch;position:relative;
  flex-direction:column;align-items:center;justify-content:center;gap:58px;
}
.study-split::before{
  content:"";position:absolute;top:0;bottom:0;left:50%;width:1px;
  background:transparent;transition:background .15s ease;
}
.study-split:hover::before,.study-split.dragging::before{background:var(--line);}
#studyArea:fullscreen .study-split,#studyArea.fs-mode .study-split{display:flex;}
#studyArea:fullscreen .study-split::before,#studyArea.fs-mode .study-split::before{
  background:var(--line);
}
#studyArea:fullscreen .study-split:hover::before,#studyArea.fs-mode .study-split:hover::before,
#studyArea:fullscreen .study-split.dragging::before,#studyArea.fs-mode .study-split.dragging::before{
  background:var(--line-strong);
}
.study-split .ss-bar{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  cursor:col-resize;touch-action:none;border-radius:2px;
}
.study-split .ss-bar:focus-visible{outline:2px solid var(--amber);outline-offset:-2px;}
.study-split .ss-grip{
  display:block;width:3px;height:32px;border-radius:2px;background:var(--line-strong);
  transition:background .15s ease,height .18s ease;
}
.study-split .ss-bar:hover .ss-grip,.study-split .ss-bar:focus-visible .ss-grip,
.study-split.dragging .ss-grip{background:var(--amber);height:64px;}
.study-split .ss-end{
  position:relative;z-index:2;width:20px;height:20px;padding:0;border-radius:3px;
  border:1px solid var(--line-strong);background:var(--surface);color:var(--muted);
  font-size:8px;line-height:1;cursor:pointer;opacity:0;
  transition:opacity .15s ease,color .15s ease,border-color .15s ease;
}
.study-split:hover .ss-end,.study-split:focus-within .ss-end{opacity:1;}
.study-split .ss-end:hover{color:var(--amber);border-color:var(--amber);}
/* No hover to reveal them on a touch screen, so they simply live there */
@media (hover:none){.study-split .ss-end{opacity:.9;}}
/* While a pane is maximized the arrow that brings the other one back is
   the way back, and a way back may not hide behind a hover: the split
   persists, so the reader can meet a collapsed pane on a fresh page. */
.study-layout[data-atlas-collapsed="list"] .ss-map,
.study-layout[data-atlas-collapsed="map"] .ss-list{opacity:1;}

/* Stacked (a phone, or anything narrow): the same rail turned on its side.
   Fullscreen keeps the two-pane split here rather than falling back to the
   everyday scrolling column, which is the whole point of going fullscreen
   on a phone: the map takes the top half, the list scrolls under it, and
   the rail moves the line between them. */
@media (max-width:820px){
  #studyArea:fullscreen .study-layout,#studyArea.fs-mode .study-layout{
    flex:1 1 auto;min-height:0;height:auto;
  }
  /* The everyday phone layout sticks the map pane below the fixed masthead
     (the rule further up in this file); fullscreen has no masthead, so the
     pane pins to the very top and the map may spend the reclaimed room. */
  #studyArea:fullscreen .study-map-pane,#studyArea.fs-mode .study-map-pane{
    position:relative;top:auto;min-height:0;padding:10px 12px 8px;
    flex:0 0 calc((100% - var(--atlas-rail)) * var(--atlas-split, .55));
  }
  #studyArea:fullscreen .study-list-pane,#studyArea.fs-mode .study-list-pane{
    flex:1 1 0;min-height:0;overflow:auto;
  }
  /* Restore the filling map the everyday stacked rules turn off */
  #studyArea:fullscreen #studyMapWrap,#studyArea.fs-mode #studyMapWrap{flex:1;min-height:0;}
  #studyArea:fullscreen #studyMap,#studyArea.fs-mode #studyMap{position:absolute;inset:0;}
  #studyArea:fullscreen #studyMap .africa-map,#studyArea.fs-mode #studyMap .africa-map{
    height:100%;max-height:none;
  }
  #studyArea:fullscreen #studyMap .map-ph,#studyArea.fs-mode #studyMap .map-ph{height:100%;}
  #studyArea:fullscreen .study-split,#studyArea.fs-mode .study-split{
    flex-direction:row;flex-basis:var(--atlas-rail,24px);
  }
  #studyArea:fullscreen .study-split::before,#studyArea.fs-mode .study-split::before{
    top:50%;bottom:auto;left:0;right:0;width:auto;height:1px;
  }
  #studyArea:fullscreen .study-split .ss-bar,#studyArea.fs-mode .study-split .ss-bar{
    cursor:row-resize;
  }
  #studyArea:fullscreen .study-split .ss-grip,#studyArea.fs-mode .study-split .ss-grip{
    width:32px;height:3px;
  }
  #studyArea:fullscreen .study-split .ss-bar:hover .ss-grip,#studyArea.fs-mode .study-split .ss-bar:hover .ss-grip,
  #studyArea:fullscreen .study-split.dragging .ss-grip,#studyArea.fs-mode .study-split.dragging .ss-grip{
    width:64px;height:3px;
  }
  /* The hint line under the map is a luxury on a phone in fullscreen */
  #studyArea:fullscreen .study-hint,#studyArea.fs-mode .study-hint{display:none;}
}

/* ==========================================================================
   Fullscreen Versus

   The lobby is part of it on purpose. A room is not an antechamber you pass
   through on the way to the game: it is where the players are, where the
   chat is, where the emotes land and where everyone confirms they are
   ready, and all of that is worth the screen. So the toggle takes
   #multiArea whole and stays put through the lobby, the countdown, the
   game and the standings, exactly the way the Quiz toggle survives a run
   ending. Because #multiArea only ever has its children replaced, nothing
   in that journey drops the browser out of fullscreen.
   ========================================================================== */
/* The toggle rides the top-right corner of the area, and so do the tab's
   own top-right buttons (Messages on the browser, Leave lobby in a room):
   the heading bar keeps a lane clear for it, in fullscreen and out. */
#multiArea{position:relative;}
#multiArea .hist-head{padding-right:38px;}
#multiArea.fs-mode{position:fixed;inset:0;z-index:70;}
#multiArea:fullscreen,#multiArea.fs-mode{
  overflow:auto;box-sizing:border-box;
  display:flex;flex-direction:column;
  padding:clamp(10px,2vh,24px) clamp(12px,2.2vw,30px);
  background:
    linear-gradient(180deg, rgba(10,29,38,.93), rgba(12,38,49,.88) 42%, rgba(9,26,34,.94)),
    #0F3B4C url("assets/hero.webp") center 38%/cover no-repeat;
  background-attachment:fixed;
}
/* The browser screen is a stack of blocks (heading, lede, actions, plates)
   that are all direct children here, so growth is granted by name: only the
   room and the live game are asked to fill the screen. */
#multiArea:fullscreen > :not(.fs-btn),#multiArea.fs-mode > :not(.fs-btn){
  width:min(1520px,100%);margin-left:auto;margin-right:auto;flex:none;
}
#multiArea:fullscreen > .mp-lobby,#multiArea.fs-mode > .mp-lobby,
#multiArea:fullscreen > .mp-game,#multiArea.fs-mode > .mp-game{
  flex:1 1 auto;min-height:0;
}
#multiArea:fullscreen > .fs-btn,#multiArea.fs-mode > .fs-btn{
  position:fixed;top:12px;right:12px;opacity:.85;
}
#multiArea:fullscreen > .mp-after,#multiArea.fs-mode > .mp-after{
  flex:1 1 auto;min-height:0;align-items:stretch;
}
/* The standings column scrolls on its own; the chat beside it fills */
#multiArea:fullscreen > .mp-after > .mp-result,#multiArea.fs-mode > .mp-after > .mp-result{
  overflow:auto;min-height:0;
}
#multiArea:fullscreen > .mp-after > .mp-chat,#multiArea.fs-mode > .mp-after > .mp-chat{
  display:flex;flex-direction:column;min-height:0;
}
#multiArea:fullscreen > .mp-after > .mp-chat .mp-chat-log,
#multiArea.fs-mode > .mp-after > .mp-chat .mp-chat-log{
  flex:1 1 auto;height:auto;min-height:120px;max-height:none;
}
/* A player with no room left to talk to gets the reading-width standings */
#multiArea:fullscreen > .mp-after.alone,#multiArea.fs-mode > .mp-after.alone{
  flex:none;margin:auto;width:min(720px,100%);
}
/* The gate is a reading screen: it centres rather than stretching. */
#multiArea:fullscreen > .empty,#multiArea.fs-mode > .empty{
  flex:none;margin:auto;width:min(720px,100%);
}

/* THE LOBBY. The room takes the height it is given: seats and settings on
   one side, chat down the other, and the chat log (the thing that actually
   grows) spends every pixel the rest leaves over instead of scrolling in a
   200px window with a screen of empty space beneath it. */
#multiArea:fullscreen .mp-lobby,#multiArea.fs-mode .mp-lobby{
  display:flex;flex-direction:column;height:100%;min-height:0;
}
#multiArea:fullscreen .mp-lobby > .mp-cols,#multiArea.fs-mode .mp-lobby > .mp-cols{
  flex:1 1 auto;min-height:0;align-items:stretch;
}
#multiArea:fullscreen .mp-cols > .mp-side,#multiArea.fs-mode .mp-cols > .mp-side{
  display:flex;flex-direction:column;min-height:0;
}
#multiArea:fullscreen .mp-cols > .mp-side > .mp-plate,#multiArea.fs-mode .mp-cols > .mp-side > .mp-plate{
  flex:none;
}
#multiArea:fullscreen .mp-cols .mp-plate-body,#multiArea.fs-mode .mp-cols .mp-plate-body{
  overflow:auto;
}
/* The seat plate and the chat plate are the two that grow */
#multiArea:fullscreen .mp-cols > .mp-side:first-child > .mp-plate:first-child,
#multiArea.fs-mode .mp-cols > .mp-side:first-child > .mp-plate:first-child,
#multiArea:fullscreen .mp-cols .mp-plate.mp-chat,#multiArea.fs-mode .mp-cols .mp-plate.mp-chat{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
}
#multiArea:fullscreen .mp-cols .mp-chat .mp-chat-log,#multiArea.fs-mode .mp-cols .mp-chat .mp-chat-log{
  flex:1 1 auto;height:auto;min-height:120px;max-height:none;
}

/* THE GAME. Same shape as fullscreen Quiz: the live block on top, then the
   card takes the rest and hands the map whatever the prompt and the answer
   row leave over. */
#multiArea:fullscreen .mp-game,#multiArea.fs-mode .mp-game{
  display:flex;flex-direction:column;height:100%;min-height:0;
}
#multiArea:fullscreen .mp-live-top,#multiArea.fs-mode .mp-live-top{
  position:static;flex:none;background:transparent;padding:0 0 4px;
}
/* The clock is the top-right thing in the live bar and the toggle rides the
   top-right corner of the screen; keep them out of each other's way. */
#multiArea:fullscreen .mp-gbar,#multiArea.fs-mode .mp-gbar{padding-right:34px;}
#multiArea:fullscreen .mp-game > .card,#multiArea.fs-mode .mp-game > .card{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;box-sizing:border-box;
  padding:clamp(12px,2vh,24px) clamp(16px,2.4vw,40px);
}
#multiArea:fullscreen .mp-game > .card > .card-main,#multiArea.fs-mode .mp-game > .card > .card-main,
#multiArea:fullscreen #mpHead,#multiArea.fs-mode #mpHead{
  flex:1 1 auto;min-height:0;display:flex;flex-direction:column;
}
#multiArea:fullscreen #mpHead .card-map--main,#multiArea.fs-mode #mpHead .card-map--main,
#multiArea:fullscreen #mpHead .card-flag,#multiArea.fs-mode #mpHead .card-flag{
  flex:1 1 auto;min-height:120px;height:auto;width:100%;aspect-ratio:auto;margin:6px 0 10px;
}
#multiArea:fullscreen #mpHead .card-flag,#multiArea.fs-mode #mpHead .card-flag{
  display:flex;flex-direction:column;
}
#multiArea:fullscreen #mpHead .card-flag .fl-big,#multiArea.fs-mode #mpHead .card-flag .fl-big{
  flex:1 1 auto;min-height:0;width:auto;max-width:100%;margin:0 auto;
  aspect-ratio:auto;object-fit:contain;
}
#multiArea:fullscreen #mpHead .mp-count,#multiArea.fs-mode #mpHead .mp-count{
  flex:1 1 auto;min-height:0;
}
#multiArea:fullscreen .answer-block,#multiArea.fs-mode .answer-block{flex:none;}
/* Two columns of room: the answer box beside the map rather than under it,
   the same trade fullscreen Quiz makes on a wide screen. */
@media (min-width:900px){
  #multiArea:fullscreen .mp-cols,#multiArea.fs-mode .mp-cols{grid-template-columns:1fr 1.1fr;}
}
@media (max-width:900px){
  #multiArea:fullscreen .mp-lobby > .mp-cols,#multiArea.fs-mode .mp-lobby > .mp-cols{
    flex:none;min-height:0;
  }
  #multiArea:fullscreen .mp-lobby,#multiArea.fs-mode .mp-lobby{height:auto;}
}
/* While the phone keyboard is up the card pins itself to the visual
   viewport instead of the layout one, the same trade fullscreen Quiz
   makes (wireKeyboardFit drives --kb-vh/--kb-top for every fullscreen
   area, so only the rules that spend them are per-area). */
body.kb-compact #multiArea:fullscreen,body.kb-compact #multiArea.fs-mode{overflow:hidden;}
body.kb-compact #multiArea:fullscreen > :not(.fs-btn),
body.kb-compact #multiArea.fs-mode > :not(.fs-btn){
  flex:none;height:var(--kb-vh,100%);max-height:var(--kb-vh,100%);margin-top:var(--kb-top,0px);
}
body.kb-compact #multiArea:fullscreen #mpHead .card-map--main,
body.kb-compact #multiArea.fs-mode #mpHead .card-map--main,
body.kb-compact #multiArea:fullscreen #mpHead .card-flag,
body.kb-compact #multiArea.fs-mode #mpHead .card-flag{
  flex:1 1 auto;height:auto;min-height:80px;width:100%;margin:4px 0 8px;
}

/* The dark map shell: the working tabs float their plates on the engraved
   world. Home keeps its own hero; Options, History and Admin stay paper. */
body:has(#panel-study.active)::before,
body:has(#panel-quiz.active)::before,
body:has(#panel-test.active)::before,
body:has(#panel-ranks.active)::before{
  content:"";position:fixed;inset:0;z-index:-1;
  background:
    linear-gradient(180deg, rgba(10,29,38,.93), rgba(12,38,49,.88) 42%, rgba(9,26,34,.94)),
    #0F3B4C url("assets/hero.webp") center 38%/cover no-repeat;
  background-attachment:fixed;
}
body:has(#panel-study.active) .study-hint{color:rgba(255,255,255,.6);}
body:has(#panel-quiz.active) .practice-bar{
  background:var(--surface);border:1px solid var(--line-strong);border-radius:3px;
  padding:8px 12px;box-shadow:var(--shadow-sm);
}
body:has(#panel-ranks.active) .panel-lede,
body:has(#panel-ranks.active) .th-title{color:rgba(255,255,255,.82);}
body:has(#panel-ranks.active) .th-empty{color:rgba(255,255,255,.55);}

/* ==========================================================================
   Light / dark mode
   ========================================================================== */

/* The toggle rides the fixed bar next to the account chip; the bar is dark
   in both themes, so the button always speaks white. */
.theme-toggle{
  flex:none;width:30px;height:30px;border-radius:50%;padding:0;
  border:1px solid rgba(255,255,255,.35);background:rgba(13,34,44,.35);
  color:#fff;font-size:14px;line-height:1;cursor:pointer;
  transition:border-color .15s ease,color .15s ease;
}
.theme-toggle:hover{border-color:var(--amber);color:var(--amber-soft);}
@media (max-width:940px){.mast-top .theme-toggle{order:2;}}

/* The dark palette: the same engraved teal family, inverted. The masthead,
   the Home hero and the dark map shell behind the working tabs already live
   on the dark side and carry over unchanged; --brand sits mid-tone so it
   reads both as a fill under white text and as text on the dark paper. */
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0C1920;
  --surface:#132631;
  --surface-2:#1A3340;
  --ink:#E6EDF1;
  --muted:#9DB1BC;
  --faint:#69808E;
  --line:#23404D;
  --line-strong:#305261;
  --brand:#3D8CA4;
  --brand-2:#66ABC0;
  --brand-tint:#16323E;
  --good:#4FB183;
  --good-tint:#143024;
  --bad:#E08573;
  --bad-tint:#3A211C;
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px -12px rgba(0,0,0,.5);
  --shadow-sm:0 1px 2px rgba(0,0,0,.35);
  --plate-shadow:0 1px 2px rgba(0,0,0,.3),0 14px 40px -18px rgba(0,0,0,.55);
  --paper-map:linear-gradient(180deg,#122530,#0E1F28);
}

/* Spots the variables cannot reach: the map pane's engraved paper, the map
   tooltip (its light ink would go white on white), and the answer inputs. */
:root[data-theme="dark"] .study-map-pane{background:#122530;}
:root[data-theme="dark"] .study-tip{background:#0A161C;box-shadow:0 4px 14px rgba(0,0,0,.5);}
:root[data-theme="dark"] .answer-row input:focus{background:var(--surface);}
:root[data-theme="dark"] .answer-row input.answer-typo{background:#33270F;}
/* Same for the tint on a spoken answer the recognizer may still rewrite: the
   base sheet's cream would put pale ink on a pale field. Dimmer than the
   spelling-slip amber above it, because this one says "still listening",
   not "look at this". */
:root[data-theme="dark"] .answer-row input.voice-live{background:#2A2110;}
/* The listening microphone's cream disc is a headlight on the dark sheet;
   it only has to read as lit, not as the brightest thing on screen. */
:root[data-theme="dark"] .answer-row.voice-hear .voice-btn{background:rgba(191,138,44,.22);}

/* World Cup golds, dark: the base sheet's olive ink (#9A7A20 on translucent
   gold) goes muddy on the dark paper. Brighten the ink and thin the backing
   for the group-letter tags (study rows, flag-wall tiles, flag dialog), the
   wall chart's group headers and the gold/bronze result badges. */
:root[data-theme="dark"] .wc-g{color:#EBCB7C;background:rgba(255,214,110,.16);}
:root[data-theme="dark"] .wc-ghead{color:#D4AF5E;}
:root[data-theme="dark"] .wc-b.debut{color:#EBCB7C;background:rgba(255,214,110,.18);}
:root[data-theme="dark"] .wc-b.fin{color:#C9D3DB;}
:root[data-theme="dark"] .wc-b.pod{color:#DFA867;}

/* The toast pill: the base rule paints ink-on-white-era colors
   (background var(--ink), white text), which dark mode flips into a
   light pill with white text. Keep the inverted light pill (it pops on
   the night UI) but give it dark ink and a deeper drop. */
:root[data-theme="dark"] .toast{
  color:#10222C;
  box-shadow:0 12px 34px -8px rgba(0,0,0,.65);
}
/* The feedback coach mark is the toast's sibling (a floating note painted
   on var(--ink) with white text), so it takes the same treatment: keep the
   inverted light card, flip its ink dark. Its pointer inherits var(--ink)
   and follows on its own; only the text and the button need saying. */
:root[data-theme="dark"] .fb-coach{color:#10222C;box-shadow:0 16px 40px -10px rgba(0,0,0,.7);}
:root[data-theme="dark"] .fb-coach b{color:#10222C;}
:root[data-theme="dark"] .fb-coach .fb-coach-x{background:rgba(16,34,44,.1);color:#10222C;}
:root[data-theme="dark"] .fb-coach .fb-coach-x:hover{background:rgba(16,34,44,.2);}

/* The maps, dark: land lifts from deep water instead of sitting on white
   paper; strokes flip from white separators to deep-water channels. */
:root[data-theme="dark"] .m-c{fill:#2C4855;stroke:#0F1E26;}
:root[data-theme="dark"] .m-neutral{fill:#1D3441;stroke:#0F1E26;}
:root[data-theme="dark"] .m-xc{fill:#1D3441;}
:root[data-theme="dark"] .m-water{fill:#102330;stroke:#16303D;}
:root[data-theme="dark"] .m-isl{fill:#3D5B6B;stroke:#0F1E26;}
:root[data-theme="dark"] .m-off{fill:#16292F;stroke:#23404D;}
:root[data-theme="dark"] .m-dot{fill:#E6EDF1;stroke:#0F1E26;}
:root[data-theme="dark"] .m-inset-frame{fill:#10222C;stroke:#3D5B6B;}
:root[data-theme="dark"] .m-inset-src{stroke:#3D5B6B;}
/* The dashes live on m-terr-e (the arcs a country owns); m-terr is the
   closed outline underneath them, invisible until a state paints it. */
:root[data-theme="dark"] path.m-terr-e{stroke:#3D5B6B;}
/* The highlight and lens tints must be restated at dark-scope specificity:
   the land recolors above ([data-theme] + class) outrank the app's base
   path.m-hl / path.m-lang rules, so without these the question country,
   Atlas pin and language lens paint as plain land. */
:root[data-theme="dark"] path.m-hl{fill:var(--brand);}
:root[data-theme="dark"] circle.m-hl{fill:var(--brand);}
/* Quiz stains (right = green, wrong = red) need the same restatement, or
   answered countries paint as plain dark land. */
:root[data-theme="dark"] path.m-test-ok,
:root[data-theme="dark"] circle.m-test-ok{fill:#63B389;}
:root[data-theme="dark"] path.m-test-bad,
:root[data-theme="dark"] circle.m-test-bad{fill:#DC9090;}
:root[data-theme="dark"] path.m-terr.m-test-ok{stroke:#63B389;fill:rgba(99,179,137,.12);}
:root[data-theme="dark"] path.m-terr.m-test-bad{stroke:#DC9090;fill:rgba(220,144,144,.12);}
:root[data-theme="dark"] path.m-lang:not(.m-hl){fill:#3F7A90;}
:root[data-theme="dark"] circle.m-lang:not(.m-hl){fill:#5F9DB2;}
:root[data-theme="dark"] path.m-terr.m-lang:not(.m-hl){stroke:#5F9DB2;fill:rgba(95,157,178,.1);}
:root[data-theme="dark"] path.m-terr.m-hl{stroke:var(--brand-2);fill:rgba(102,171,192,.1);}
:root[data-theme="dark"] path.m-terr-e.m-off{stroke:#22383F;}
:root[data-theme="dark"] path.m-hover:not(.m-hl){fill:#3E5F70;}
:root[data-theme="dark"] circle.m-hover:not(.m-hl){fill:#7395A6;}
:root[data-theme="dark"] path.m-terr.m-hover:not(.m-hl){stroke:#7395A6;fill:rgba(115,149,166,.08);}
:root[data-theme="dark"] path.m-cthot:not(.m-hl):not(.m-hover):not(.m-off):not(.m-neutral){fill:#36566A;}
:root[data-theme="dark"] path.m-neutral.m-cthot{fill:#24404E;}
:root[data-theme="dark"] circle.m-cthot:not(.m-hl):not(.m-hover):not(.m-off){fill:#5F8296;}
:root[data-theme="dark"] path.m-terr.m-cthot:not(.m-hl):not(.m-hover):not(.m-off){stroke:#5F8296;}
:root[data-theme="dark"] .m-cont-label{fill:#5E7789;}
:root[data-theme="dark"] svg.m-zfar text.m-cont-label.m-cthot{fill:#8FA9BA;}
:root[data-theme="dark"] .africa-map{filter:none;}
