/* =====================================================================
   GAMIFY · SHELL — styles for the app shell (splash, road-map home,
   Uploads / Games / Score / Topics, settings).
   ---------------------------------------------------------------------
   skin.css stays the SINGLE SOURCE OF VISUAL TRUTH: everything here
   reads its CSS variables (palette, radius, font, shadows, keyframes).
   Reskinning the whole app — shell included — is still a one-file edit
   of skin.css :root. This file only lays out shell-specific surfaces.
   ===================================================================== */

html,body{height:100%}
body.shell{display:block;padding:0;overflow-x:hidden}

/* ---- sky backdrop clouds (decorative, behind everything) ---- */
.clouds{position:fixed;inset:0;pointer-events:none;z-index:0;overflow:hidden}
.cloud{position:absolute;background:rgba(255,255,255,.9);border-radius:999px;filter:blur(1px);
  animation:cloudDrift linear infinite}
.cloud::before,.cloud::after{content:"";position:absolute;background:inherit;border-radius:50%}
.cloud::before{width:55%;height:160%;left:12%;top:-70%}
.cloud::after{width:42%;height:120%;right:14%;top:-42%}
.cloud.dim{opacity:.55}
@keyframes cloudDrift{
  from{transform:translateX(-30vw)}
  to{transform:translateX(130vw)}
}
@media (prefers-reduced-motion: reduce){ .cloud{animation:none} }

/* ---- screen frame ---- */
.screen{position:relative;z-index:1;display:none;min-height:100%;
  flex-direction:column;align-items:center;padding:18px 16px 96px}
.screen.active{display:flex}
#screen-home.active{min-height:100vh}
#screen-home .car-wrap{width:min(96vw,420px)}
.screen-inner{width:min(96vw,640px)}

/* ---- top bar (home) ---- */
.topbar{position:relative;z-index:2;display:flex;justify-content:space-between;align-items:flex-start;
  width:min(96vw,640px);max-width:100%;margin:0 auto 4px}
.level-badge{display:flex;flex-direction:column;align-items:center;background:var(--pill-bg);
  border:2px solid var(--accent);border-radius:var(--radius);padding:6px 14px;
  box-shadow:0 4px 10px var(--shadow);min-width:74px}
.level-badge .lvl-word{font-size:.62rem;font-weight:800;letter-spacing:1.5px;color:var(--muted);text-transform:uppercase}
.level-badge .lvl-num{font-size:1.5rem;font-weight:900;color:var(--ink);line-height:1.1}
.level-badge.bump{animation:scorePop .4s ease}
/* "which class am I in" HUD chip — same pill language as .level-badge so it
   reads as part of the HUD rather than a bolted-on banner. */
.class-pill{display:flex;align-items:center;gap:5px;background:var(--pill-bg);
  border:2px solid var(--accent);border-radius:var(--radius-pill);padding:7px 13px;
  box-shadow:0 4px 10px var(--shadow);font-weight:800;font-size:.8rem;color:var(--ink);
  cursor:pointer;font-family:var(--font);max-width:38vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gear-btn{background:var(--pill-bg);border:1px solid var(--pill-edge);border-radius:var(--radius-pill);
  width:44px;height:44px;font-size:1.3rem;cursor:pointer;box-shadow:0 3px 8px var(--shadow);
  transition:transform .12s,box-shadow .2s}
.gear-btn:hover{transform:translateY(-2px) rotate(20deg);box-shadow:0 6px 14px var(--shadow)}
.gear-btn:active{transform:translateY(1px)}

/* ---- wordmark ---- */
.wordmark{font-size:2.6rem;font-weight:900;letter-spacing:2px;color:#fff;text-align:center;
  text-shadow:0 3px 0 rgba(21,50,74,.35),0 8px 18px var(--shadow)}
.wordmark .spark{color:var(--accent)}
.welcome-line{font-size:1rem;font-weight:800;letter-spacing:4px;color:var(--ink);opacity:.75;text-align:center;text-transform:uppercase}

/* ---- splash ---- */
#splash{position:fixed;inset:0;z-index:60;display:none;flex-direction:column;align-items:center;justify-content:center;
  background:radial-gradient(120% 120% at 50% 0%,var(--bg2),var(--bg1) 70%)}
#splash.show{display:flex}
#splash .wordmark{font-size:3.4rem;animation:starPop .6s ease}
#splash .btn{font-size:1.2rem;padding:15px 46px;margin-top:34px;animation:pop 1.6s ease infinite}
#splash::before,#splash::after{content:"";position:absolute;background:rgba(255,255,255,.9);
  border-radius:999px;filter:blur(2px);animation:cloudDrift linear infinite}
#splash::before{width:180px;height:56px;top:18%;animation-duration:70s;animation-delay:-12s}
#splash::after{width:120px;height:40px;top:64%;animation-duration:95s;animation-delay:-55s;opacity:.6}

/* ---- the carousel home (replaces the winding road, Design Pass Turn 7) ----
   Turn 7's decision 2 was "retire the road map; the carousel becomes the only
   home". This is that, with one change: the V1 carousel was one card per CLASS,
   and this is one card per GAME, because a game is what a student actually
   picks and it is what the road already showed.

   Ordered most recently played first, so the card facing you is the one you
   were last in. The road could never express that: its shape WAS its order, so
   a new game always appeared at the end of the path no matter what you played.
   Swipe, chevrons and dots all drive one index; nothing here reflows. */
.car-wrap{position:relative;z-index:1;width:min(96vw,420px);max-width:100%;margin:10px auto 0;
  flex:1;display:flex;flex-direction:column;min-height:0}
.car-stage{position:relative;overflow:hidden;border-radius:22px;touch-action:pan-y;
  flex:1;min-height:300px;box-shadow:0 14px 34px var(--shadow)}
.car-track{position:absolute;inset:0;display:flex;transition:transform .32s cubic-bezier(.22,.61,.36,1)}
.car-track.dragging{transition:none}
.car-cell{flex:0 0 100%;height:100%;box-sizing:border-box}

/* The card is the scene, edge to edge (Turn 7: "card is the scene"). The
   wallpaper fills it, the text sits over a scrim at the bottom so contrast
   never depends on which mechanic's colours are behind it. */
.car-card{position:relative;height:100%;border-radius:22px;overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;color:#fff}
.car-card .wall{position:absolute;inset:0;z-index:0}
.car-card .wall-svg{width:100%;height:100%;display:block}
.car-card .scrim{position:absolute;left:0;right:0;bottom:0;height:72%;z-index:1;
  background:linear-gradient(180deg,rgba(12,26,40,0) 0%,rgba(12,26,40,.48) 46%,rgba(12,26,40,.86) 100%)}
.car-card .c-body{position:relative;z-index:2;padding:18px 18px 20px;text-align:left}
.car-card .c-sub{font-size:.68rem;text-transform:uppercase;letter-spacing:1.4px;
  color:rgba(255,255,255,.88);font-weight:800}
.car-card .c-name{margin-top:4px;font-size:1.5rem;font-weight:900;line-height:1.15;color:#fff;
  text-shadow:0 2px 10px rgba(0,0,0,.35);
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.car-card .c-meta{display:flex;align-items:center;gap:8px;margin-top:10px}
.car-card .c-lv{font-size:.66rem;font-weight:900;letter-spacing:.5px;color:#12202e;
  background:#fff;border-radius:99px;padding:3px 10px}
.car-card .c-stars{font-size:.74rem;color:rgba(255,255,255,.95);font-weight:800}
.car-card .c-stars svg{vertical-align:-2px}
.car-card .c-bar{position:relative;height:5px;border-radius:99px;background:rgba(255,255,255,.28);
  margin-top:12px;overflow:hidden}
.car-card .c-bar i{position:absolute;inset:0 auto 0 0;width:calc(var(--pct)*1%);background:#fff;border-radius:99px}
.car-card .c-play{margin-top:14px;width:100%}
.car-card .c-resume{margin-top:8px;font-size:.72rem;color:rgba(255,255,255,.85);min-height:1em}
.car-card.done .c-lv{background:var(--good);color:#fff}
/* Challenge (2026-09-25): a secondary action under Play, so Play stays the
   biggest, brightest thing on the card. White-on-scrim like the rest of the
   card body, which reads the same in both themes (the scrim is fixed dark). */
.car-card .c-chal{margin-top:8px;width:100%;min-height:44px;border-radius:var(--radius);cursor:pointer;
  background:rgba(255,255,255,.14);border:1.5px solid rgba(255,255,255,.55);color:#fff;
  font-family:var(--font);font-weight:800;font-size:.875rem;display:flex;align-items:center;justify-content:center;gap:6px}
.car-card .c-chal:active{transform:translateY(1px)}
.car-card .c-chal:focus-visible{outline:3px solid #fff;outline-offset:2px}
@media (hover:hover) and (pointer:fine){
  .car-card .c-chal:hover{background:rgba(255,255,255,.24)}
}

/* Chevrons sit inset over the stage edge, never overhanging it: at -8px the
   right one poked 8px past a 390px screen and gave Home a horizontal scroll.
   A press on one is never a swipe (the swipe handler skips .car-chev). */
.car-chev{position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:44px;height:44px;border-radius:50%;border:1px solid var(--pill-edge);
  background:var(--pill-bg);box-shadow:0 3px 8px var(--shadow);cursor:pointer;
  display:flex;align-items:center;justify-content:center;color:var(--ink);padding:0}
.car-chev svg{display:block}
.car-chev.l{left:8px}
.car-chev.r{right:8px}
.car-dots{display:flex;justify-content:center;gap:6px;margin-top:10px;flex-wrap:wrap;flex:0 0 auto}
.car-dots i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.55);transition:width .2s,background .2s}
.car-dots i.on{width:18px;border-radius:99px;background:#fff}
.car-count{text-align:center;font-size:.7rem;color:rgba(255,255,255,.9);font-weight:700;margin-top:5px;flex:0 0 auto}

.car-empty{position:relative;z-index:1;text-align:center;background:var(--stage-bg);border:1px solid var(--stage-edge);
  border-radius:18px;padding:26px 20px;margin:12px auto 0;width:min(96vw,420px);max-width:100%;box-shadow:0 10px 26px var(--shadow)}
.car-empty p{color:var(--muted);margin:8px 0 14px}

/* The account button takes the level badge's slot in the top bar. The level is
   still shown, but the slot now leads somewhere: signing up when signed out,
   the account screen once signed in. */
.acct-btn{display:flex;align-items:center;gap:7px;border:1px solid var(--pill-edge);
  background:var(--pill-bg);border-radius:99px;padding:5px 11px 5px 6px;cursor:pointer;
  box-shadow:0 2px 6px var(--shadow);font:inherit;color:var(--ink)}
.acct-btn .a-ring{width:24px;height:24px;border-radius:50%;flex:0 0 auto;
  background:linear-gradient(180deg,var(--accent),var(--accent2));
  display:flex;align-items:center;justify-content:center;font-size:.7rem;font-weight:900;color:var(--btn-ink)}
.acct-btn .a-txt{font-size:.72rem;font-weight:800;line-height:1.1;text-align:left;white-space:nowrap}
.acct-btn .a-txt small{display:block;font-size:.6rem;font-weight:700;color:var(--muted)}
@media (prefers-reduced-motion:reduce){ .car-track{transition:none} }

/* ---- bottom nav ---- */
.bottom-nav{position:fixed;left:50%;bottom:12px;transform:translateX(-50%);z-index:40;
  display:flex;gap:6px;width:min(97vw,620px)}
.nav-tile{flex:1;min-width:0;border:0;border-radius:var(--radius);cursor:pointer;padding:10px 2px 8px;
  display:flex;flex-direction:column;align-items:center;gap:2px;font-family:var(--font);
  font-size:.66rem;font-weight:800;letter-spacing:.2px;box-shadow:0 5px 12px var(--shadow);
  transition:transform .12s,box-shadow .2s,filter .2s;border-bottom:4px solid rgba(0,0,0,.18)}
.nav-tile .nico{font-size:1.25rem;line-height:1.2}
.nav-tile:hover{transform:translateY(-3px);box-shadow:0 9px 18px var(--shadow)}
.nav-tile:active{transform:translateY(1px)}
.nav-tile.current{transform:translateY(-3px);box-shadow:0 9px 18px var(--shadow);filter:saturate(1.15)}
/* mockup colors: Uploads dark · Games green · Score orange · Topics light */
.nav-tile.nav-home{background:var(--pill-bg);color:var(--ink)}
.nav-tile.nav-uploads{background:linear-gradient(180deg,#2c4a63,#15324a);color:#fff}
.nav-tile.nav-games{background:linear-gradient(180deg,var(--good),var(--good-deep));color:#fff}
.nav-tile.nav-score{background:linear-gradient(180deg,var(--accent2),#e8862f);color:#fff}
.nav-tile.nav-topics{background:var(--choice);color:var(--ink)}
.nav-tile.nav-class{background:linear-gradient(180deg,var(--accent),var(--accent2));color:var(--btn-ink)}
/* dimmed, not disabled — tapping still works, it just redirects to Class,
   so a dim (not a hard block) is the honest affordance */
.nav-tile.locked{opacity:.45}

/* ---- shared shell cards ---- */
.shell-card{background:var(--stage-bg);border:1px solid var(--stage-edge);border-radius:var(--radius-lg);
  box-shadow:0 12px 30px var(--shadow);padding:18px;margin-bottom:16px}
.shell-card h2{font-size:1.15rem;margin-bottom:4px}
.shell-card .cap{font-size:.78rem;text-transform:uppercase;letter-spacing:1px;color:var(--label);font-weight:800;margin-bottom:8px}
.hint-note{font-size:.85rem;color:var(--muted)}
.screen-title{font-size:1.5rem;text-align:center;margin:6px 0 2px}
.screen-sub{display:block;font-size:.85rem;color:var(--muted);font-weight:500;text-align:center;margin:2px 0 14px}

/* ---- big choice tiles (Uploads: "what are you adding?") ---- */
.choice-tiles{display:flex;gap:12px;flex-wrap:wrap}
.big-tile{flex:1;min-width:220px;text-align:left;cursor:pointer;background:var(--choice);
  border:1px solid var(--choice-edge);border-radius:var(--radius);padding:16px;
  box-shadow:0 3px 8px var(--shadow);transition:transform .1s,border-color .2s,box-shadow .2s;font-family:var(--font);color:var(--ink)}
.big-tile:hover{border-color:var(--accent);transform:translateY(-2px);box-shadow:0 8px 16px var(--shadow)}
.big-tile:active{transform:translateY(1px)}
.big-tile .t-ico{font-size:1.6rem}
.big-tile .t-name{font-weight:800;font-size:1.02rem;margin-top:6px}
.big-tile .t-sub{font-size:.8rem;color:var(--muted);margin-top:3px;line-height:1.35}

/* ---- forms (uploads) ---- */
.shell-card label{font-size:.74rem;text-transform:uppercase;letter-spacing:1px;color:var(--muted);
  display:block;margin:10px 0 6px;font-weight:700}
.shell-card textarea{width:100%;min-height:90px;border-radius:12px;border:1px solid var(--choice-edge);
  background:var(--choice);color:var(--ink);padding:12px;font-size:15px;resize:vertical;font-family:var(--font)}
.shell-card textarea:focus{outline:2px solid var(--accent)}
.shell-card input[type=file]{color:var(--muted);font-size:.9rem;max-width:100%}
.shell-card select{border-radius:10px;border:1px solid var(--choice-edge);background:var(--choice);color:var(--ink);
  padding:10px 12px;font-size:.95rem;font-family:var(--font);width:100%}
.or-line{text-align:center;color:var(--muted);font-size:.85rem;margin:10px 0}
.btn.small{padding:9px 14px;font-size:.85rem;margin-top:8px}
.btn.full{width:100%}
.status-line{margin-top:12px;text-align:center;color:var(--muted);font-weight:700;font-size:.95rem;min-height:22px}
.err-box{margin-top:12px;background:rgba(255,106,106,.12);border:1px solid rgba(255,106,106,.5);
  border-radius:12px;padding:10px 14px;color:var(--bad-deep);font-size:.9rem;display:none;white-space:pre-wrap;
  overflow-wrap:anywhere;word-break:break-word;max-width:100%;box-sizing:border-box}
.file-note{margin:4px 0 8px;color:var(--muted);font-size:.85rem;font-weight:600;min-height:0}
.file-note:empty{display:none}
.err-box.show{display:block}
.saved-chip{display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:rgba(52,192,107,.12);border:1px solid rgba(52,192,107,.4);border-radius:12px;padding:10px 14px}
.saved-chip b{color:var(--good-deep)}
.saved-chip .sub{font-size:.8rem;color:var(--muted);word-break:break-word}
.linkish{background:none;border:0;color:var(--muted);cursor:pointer;font-size:.8rem;text-decoration:underline;font-family:var(--font)}

/* ---- game library tiles ---- */
.set-group{margin-bottom:18px}
.set-head{display:flex;align-items:baseline;justify-content:space-between;margin:0 4px 8px}
.set-head h3{font-size:1.02rem;color:var(--ink)}
.set-head .meta{font-size:.75rem;color:var(--muted);font-weight:600}
/* 2026-10-01: an upload plays as one shuffled mix; single games sit under a toggle */
.mix-btn{display:flex;align-items:center;justify-content:center;gap:8px;margin:0 0 8px;min-height:48px}
.set-each>summary{cursor:pointer;font-size:.85rem;font-weight:700;color:var(--muted);margin:4px 4px 8px;min-height:32px;display:flex;align-items:center}
.set-each[open]>summary{margin-bottom:10px}
.game-tile{display:flex;align-items:center;gap:12px;background:var(--choice);border:1px solid var(--choice-edge);
  border-radius:var(--radius);padding:12px 14px;margin-bottom:10px;box-shadow:0 3px 8px var(--shadow);
  transition:transform .1s,box-shadow .2s}
.game-tile:hover{transform:translateY(-1px);box-shadow:0 6px 14px var(--shadow)}
.game-tile .g-ico{font-size:1.5rem;flex:0 0 auto}
.game-tile .g-meta{flex:1;min-width:0}
.game-tile .g-name{font-weight:800;font-size:.95rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.game-tile .g-sub{font-size:.76rem;color:var(--muted);margin-top:2px}
.game-tile .g-purpose{font-size:.72rem;font-weight:800;color:var(--muted);margin-top:2px}
.game-tile .g-weak{font-size:.72rem;font-weight:800;color:var(--accent2,#e8842c);margin-top:3px}
.game-tile .g-stars{font-size:.8rem;color:var(--label);font-weight:800}
.game-tile{flex-wrap:wrap}
.game-tile .g-meta{cursor:pointer}
.level-strip{display:none;width:100%;padding-top:10px;margin-top:4px;border-top:1px dashed var(--edge);
  display:none;grid-template-columns:repeat(5,1fr);gap:6px}
.level-strip.open{display:grid}
.lv-chip{border:1px solid var(--choice-edge);border-radius:10px;background:var(--choice);cursor:pointer;
  padding:6px 2px;text-align:center;font-family:var(--font);transition:transform .1s,border-color .2s}
.lv-chip:hover{transform:translateY(-2px);border-color:var(--accent)}
.lv-chip .n{font-weight:900;font-size:.85rem;color:var(--ink)}
.lv-chip .s{font-size:.62rem;letter-spacing:1px;color:var(--label);font-weight:800}
.lv-chip.cleared{background:linear-gradient(180deg,rgba(52,192,107,.18),rgba(52,192,107,.08));border-color:rgba(52,192,107,.5)}
.lv-chip.now{border-color:var(--accent);box-shadow:0 0 0 3px rgba(255,206,58,.3)}
.lv-chip.unbuilt{opacity:.7}
.fav-btn{background:none;border:0;font-size:1.25rem;cursor:pointer;padding:4px;line-height:1;
  filter:grayscale(1);opacity:.45;transition:transform .12s,filter .2s,opacity .2s}
.fav-btn:hover{transform:scale(1.15)}
.fav-btn.on{filter:none;opacity:1;animation:starPop .4s ease}
/* Muted by default so removing a format never competes with Play; it only
   takes on the warning colour on hover. */
.del-btn{background:none;border:0;cursor:pointer;padding:4px;line-height:1;
  color:var(--muted);opacity:.65;transition:opacity .12s,color .12s,transform .12s}
.del-btn:hover{opacity:1;color:var(--bad,#c0392b);transform:scale(1.1)}
.del-btn svg{display:block}
/* Same quiet-by-default treatment as del-btn, but warms to the accent
   colour on hover instead of the danger colour -- this one grows a game,
   it doesn't threaten it. */
.grow-btn{background:none;border:0;cursor:pointer;padding:4px;line-height:1;
  color:var(--muted);opacity:.65;transition:opacity .12s,color .12s,transform .12s}
.grow-btn:hover{opacity:1;color:var(--accent);transform:scale(1.1)}
.grow-btn svg{display:block}
.play-btn{border:0;border-radius:10px;cursor:pointer;padding:10px 18px;font-weight:800;font-size:.9rem;
  background:linear-gradient(90deg,var(--accent),var(--accent2));color:var(--btn-ink);
  box-shadow:0 3px 8px var(--shadow);transition:transform .12s,box-shadow .2s;font-family:var(--font)}
.play-btn:hover{transform:translateY(-2px);box-shadow:0 6px 12px var(--shadow)}
.play-btn:active{transform:translateY(1px)}
.play-btn[disabled]{filter:grayscale(.6);opacity:.6;cursor:default;transform:none}
/* The tile's title column keeps real room (it used to shrink to one letter
   once Challenge joined the row); the action group wraps below it instead,
   staying right-aligned. */
.game-tile .g-meta{flex:1 1 150px}
.game-tile .g-acts{display:flex;align-items:center;gap:8px;margin-left:auto}
/* Challenge on a game tile: an outline pill beside Play, never louder than it. */
.chal-btn{border:1.5px solid var(--accent);border-radius:10px;cursor:pointer;padding:9px 12px;min-height:44px;
  background:transparent;color:var(--ink);font-weight:800;font-size:.875rem;font-family:var(--font);
  display:inline-flex;align-items:center;gap:5px;transition:transform .12s}
.chal-btn svg{color:var(--accent)}
.chal-btn:active{transform:translateY(1px)}
@media (hover:hover) and (pointer:fine){
  .chal-btn:hover{transform:translateY(-2px)}
}

/* ---- score screen ---- */
.xp-bar{height:18px;border-radius:999px;background:rgba(21,50,74,.14);overflow:hidden;margin:8px 0 4px}
.xp-bar .fill{height:100%;border-radius:999px;background:linear-gradient(90deg,var(--accent),var(--accent2));
  transition:width .6s cubic-bezier(.2,.7,.3,1.2);min-width:4px}
.xp-line{display:flex;justify-content:space-between;font-size:.78rem;color:var(--muted);font-weight:700}
.stat-row{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px}
.stat-chip{flex:1;min-width:110px;text-align:center;background:var(--pill-bg);border:1px solid var(--pill-edge);
  border-radius:var(--radius);padding:10px 6px;box-shadow:0 2px 6px var(--shadow)}
.stat-chip .v{font-size:1.35rem;font-weight:900}
.stat-chip .k{font-size:.66rem;text-transform:uppercase;letter-spacing:1px;color:var(--muted);font-weight:800}
.mastery-row{display:flex;align-items:center;gap:10px;padding:9px 4px;border-bottom:1px dashed var(--edge)}
.mastery-row:last-child{border-bottom:0}
.mastery-row .m-ico{font-size:1.2rem}
.mastery-row .m-meta{flex:1;min-width:0}
.mastery-row .m-name{font-weight:700;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mastery-row .m-bar{height:8px;border-radius:999px;background:rgba(21,50,74,.12);overflow:hidden;margin-top:4px}
.mastery-row .m-bar .fill{height:100%;background:linear-gradient(90deg,var(--good),var(--good-deep))}
.mastery-row .m-pct{font-size:.78rem;font-weight:800;color:var(--muted);min-width:74px;text-align:right}
.encourage{background:rgba(255,206,58,.18);border:1px solid rgba(255,206,58,.6);border-radius:var(--radius);
  padding:12px 14px;font-weight:700;font-size:.92rem;margin-bottom:14px}

/* ---- topics ---- */
.topic-tile{background:var(--choice);border:1px solid var(--choice-edge);border-radius:var(--radius);
  padding:14px;margin-bottom:12px;box-shadow:0 3px 8px var(--shadow)}
.topic-tile .t-head{display:flex;justify-content:space-between;align-items:baseline}
.topic-tile .t-name{font-weight:800;font-size:1rem}
.topic-tile .t-pct{font-size:.8rem;font-weight:800;color:var(--label)}
.topic-tile .t-sub{font-size:.78rem;color:var(--muted);margin:4px 0 8px}
.topic-tile .t-games{display:flex;gap:6px;flex-wrap:wrap}
.mini-chip{display:inline-flex;align-items:center;gap:5px;background:var(--pill-bg);border:1px solid var(--pill-edge);
  border-radius:999px;padding:4px 10px;font-size:.74rem;font-weight:700;cursor:pointer;
  transition:transform .12s,border-color .2s;font-family:var(--font);color:var(--ink)}
.mini-chip:hover{transform:translateY(-1px);border-color:var(--accent)}

/* ---- settings modal ---- */
.modal-veil{position:fixed;inset:0;z-index:50;background:rgba(21,50,74,.45);display:none;
  align-items:center;justify-content:center;padding:16px}
.modal-veil.show{display:flex}
.modal{background:var(--choice);color:var(--ink);border-radius:var(--radius-lg);box-shadow:0 20px 60px rgba(21,50,74,.4);
  width:min(94vw,420px);padding:22px;animation:pop .25s ease}
.modal h2{font-size:1.2rem;margin-bottom:14px}
.acct-input{width:100%;box-sizing:border-box;padding:11px 12px;border-radius:12px;border:1px solid var(--edge);
  background:var(--card,#fff);color:var(--ink);font:inherit;font-size:.92rem;margin-bottom:8px}
.acct-input:focus{outline:2px solid var(--accent,#4a3fc4);outline-offset:1px}
.full{width:100%}
/* skin.css gives .btn.ghost a 10px left margin so it sits nicely BESIDE another
   button (play.html's Replay / Home pair). A full-width ghost button is not
   beside anything, and that margin pushes it 10px off-centre from the primary
   button stacked above it. Scoped to .full so the inline pairs keep their gap. */
.btn.ghost.full{margin-left:0}
.setting-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 0;border-bottom:1px dashed var(--edge)}
.setting-row:last-of-type{border-bottom:0}
.setting-row .s-name{font-weight:700;font-size:.95rem}
.setting-row .s-sub{font-size:.76rem;color:var(--muted);margin-top:2px}
.toggle{position:relative;width:52px;height:28px;border-radius:999px;background:rgba(21,50,74,.2);
  border:0;cursor:pointer;transition:background .2s;flex:0 0 auto}
.toggle::after{content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:#fff;box-shadow:0 2px 5px rgba(0,0,0,.25);transition:left .2s}
.toggle.on{background:var(--good)}
.toggle.on::after{left:27px}
.danger-btn{background:rgba(255,106,106,.12);border:1px solid rgba(255,106,106,.5);color:var(--bad-deep);
  border-radius:10px;padding:8px 14px;font-weight:800;cursor:pointer;font-size:.85rem;font-family:var(--font)}
.about-line{font-size:.8rem;color:var(--muted);margin-top:14px;line-height:1.5}

/* ---- class filter + cap modal (home · master doc item 2) ---- */
.class-filter{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:10px auto 2px;max-width:560px}
.class-chip{border:0;border-radius:999px;padding:7px 14px;font-family:var(--font);font-weight:800;font-size:.8rem;
  background:var(--pill-bg);color:var(--ink);cursor:pointer;box-shadow:0 3px 8px var(--shadow);
  border:1px solid var(--pill-edge);
  transition:transform .12s,box-shadow .12s}
.class-chip:hover{transform:translateY(-2px);box-shadow:0 5px 12px rgba(21,50,74,.22)}
.class-chip:active{transform:translateY(0);box-shadow:0 2px 5px rgba(21,50,74,.18)}
/* Was background:var(--ink);color:#fff — which assumes --ink is dark. In
   night --ink flips to #eef0ff, so the selected chip became near-white text
   on a near-white fill at 1.13:1. The accent pair with --btn-ink on top is
   the same treatment .nav-tile.nav-class uses, and it holds in both skins. */
.class-chip.on{background:linear-gradient(180deg,var(--accent),var(--accent2));
  color:var(--btn-ink);border-color:transparent}
.class-chip.add{background:transparent;border:2px dashed rgba(21,50,74,.35);box-shadow:none;color:var(--muted)}
.cap-row{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px dashed var(--edge)}
.cap-row>div:first-child{flex:1}
.cap-row .s-name{font-weight:800;font-size:.92rem}
.cap-row .s-sub{font-size:.76rem;color:var(--muted);margin-top:2px}

/* ---- topics: due buckets + in-app banners (item 4) ---- */
.topic-banner{background:linear-gradient(90deg,rgba(255,206,58,.28),rgba(255,159,67,.28));
  border:1px solid rgba(255,159,67,.6);border-radius:12px;padding:10px 14px;margin:10px auto 4px;
  max-width:560px;font-weight:800;font-size:.85rem;color:var(--ink);text-align:center}
.topic-banner.tappable{cursor:pointer;transition:transform .12s,box-shadow .12s}
.topic-banner.tappable:hover{transform:translateY(-2px);box-shadow:0 5px 12px rgba(21,50,74,.2)}
.t-group{font-weight:900;font-size:.74rem;letter-spacing:.6px;color:var(--muted);
  margin:14px 0 2px;text-transform:uppercase}
.due-row{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px dashed var(--edge)}
.due-row:last-child{border-bottom:0}
.due-row .d-meta{flex:1;min-width:0}
.due-row .d-name{font-weight:800;font-size:.92rem}
.due-row .d-when{font-size:.76rem;color:var(--muted);margin-top:2px}
/* --bad-deep and #a06b00 are both gradient-end colours: fine as fills on a
   light card, 2.25:1 and 3.01:1 as TEXT on the night surface. The lighter
   end of each pair is the one meant to be read. */
.due-row.urgent .d-when{color:var(--bad);font-weight:800}
.due-row.upcoming .d-when{color:var(--accent);font-weight:800}
.due-row.covered{opacity:.72}

/* ---- syllabus schedule (uploads · master doc item 1) ---- */
.sched-chip{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  background:rgba(21,50,74,.06);border:1px dashed var(--edge);border-radius:12px;
  padding:10px 12px;margin-top:10px;font-size:.85rem;color:var(--ink)}
.sched-q{font-weight:800;font-size:.95rem;margin:12px 0 2px}
.sched-row{display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap}

/* ---- empty states ---- */
.empty-note{text-align:center;color:var(--muted);font-size:.92rem;padding:20px 8px}

/* ---- icons ----------------------------------------------------------------
   The old shell drew its icons as emoji, sized with `font-size` on the
   container. They come from GamifyIcons now, and an SVG ignores font-size —
   so every container that used to hold a glyph gets its box here instead, at
   the optical size the emoji was rendering at. No colour is defined below:
   the set inherits `currentColor`, which is the whole point of it. */
.gear-btn svg{margin:0 auto}
.wordmark .spark svg{display:inline-block;width:.62em;height:.62em;vertical-align:.02em}
.nav-tile .nico svg{display:block;margin:0 auto}
.big-tile .t-ico svg{display:block;margin:0 auto;width:26px;height:26px}
.game-tile .g-ico svg{display:block;width:24px;height:24px}
.mastery-row .m-ico svg{display:block;width:19px;height:19px}

/* The favourite star was a glyph that greyed out; it is a path now, so it
   needs a colour to grey. The filter and opacity rules above are unchanged. */
.fav-btn{color:var(--accent)}
.fav-btn svg{display:block}

/* An icon set inline in a line of text has no baseline of its own — a glyph
   got that free. One nudge, everywhere a count or a label carries one. */
.cap svg,.meta svg,.hint-note svg,.empty-note svg,.btn svg,.linkish svg,
.class-pill svg,.mini-chip svg,.saved-chip b svg,.stat-chip .v svg,
.nstars svg,.g-stars svg,.m-pct svg,.t-sub svg,.t-group svg,
.g-weak svg,.g-purpose svg,.d-name svg{display:inline-block;vertical-align:-.15em}

/* The three-star row on a level chip. skin.css styles `.stars .off` for the
   renderers; this is the same idea at chip scale, kept local so the shared
   sheet does not grow a rule only the old shell uses. */
.lv-chip .s{display:flex;justify-content:center;gap:2px}
.lv-chip .s svg{display:block;width:11px;height:11px}
.lv-chip .s .off{opacity:.28}

/* night theme: soften the clouds against the dark sky */
:root[data-theme="night"] .cloud{opacity:.10}
:root[data-theme="night"] .cloud.dim{opacity:.06}

/* o29 §2: account sync status beside the level on the account button */
.sync-state{font-weight:700}
.sync-state.saving{opacity:.75}
.sync-state.offline{color:var(--bad-deep)}

/* o29 §3: Undo toast after removing a game */
.undo-toast{position:fixed;left:50%;bottom:calc(20px + env(safe-area-inset-bottom));transform:translate(-50%,20px);
  max-width:calc(100% - 32px);box-sizing:border-box;display:flex;gap:14px;align-items:center;
  background:#1f2433;color:#fff;border-radius:14px;padding:12px 16px;font-weight:600;font-size:.92rem;
  box-shadow:0 8px 24px rgba(0,0,0,.25);opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;z-index:9999}
.undo-toast.show{opacity:1;pointer-events:auto;transform:translate(-50%,0)}
.undo-toast .linkish{color:#9fd3ff;font-weight:800;background:none;border:0;padding:0;cursor:pointer;font-size:.92rem}

/* ---- Upload redesign step 1 (2026-09-19): step screens, drop zone, real progress bar ---- */
.step-head{display:flex;align-items:center;gap:12px;margin-bottom:10px}
.step-head h2{margin:0}
.step-head .cap{margin-bottom:2px}
.step-back{flex:none;width:40px;height:40px;border-radius:50%;border:1px solid var(--choice-edge);
  background:var(--choice);color:var(--ink);cursor:pointer;display:grid;place-items:center;padding:0}
.step-back:hover{border-color:var(--accent)}
.step-back svg{display:block}
.step-why{margin:0 0 12px}
.step-alt{text-align:center;margin-top:10px}
.step-alt .linkish{font-size:.9rem}
.syl-line{display:flex;align-items:center;justify-content:space-between;gap:10px}
.syl-line b{color:var(--good-deep)}
.syl-line .sub{font-size:.8rem;color:var(--muted);word-break:break-word}
.syl-using{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
  font-size:.88rem;color:var(--muted);margin:0 0 12px}
.syl-using b{color:var(--ink)}
.intake{margin-bottom:12px}
.intake textarea{display:none}
.intake[data-mode=text] textarea{display:block}
.intake[data-mode=text] .dz{display:none}
.intake .swap{display:block;margin:10px auto 0;font-size:.88rem}
.dz{border:2px dashed var(--choice-edge);border-radius:16px;padding:22px 14px;text-align:center;
  background:var(--choice);cursor:pointer;transition:border-color .15s,background-color .15s}
.dz:hover,.dz:focus-visible,.dz.over{border-color:var(--accent);outline:none}
.dz.over{background:color-mix(in srgb,var(--accent) 10%,var(--choice))}
.dz .dz-ico{display:inline-block;color:var(--good-deep);margin-bottom:4px}
.dz .dz-ico svg{display:block;margin:0 auto}
.dz .btn.small{display:inline-block;margin-top:10px}
.dz .dz-full{display:none}
.dz.has .dz-empty{display:none}
.dz.has .dz-full{display:block}
.dz-name{font-weight:800;color:var(--ink);word-break:break-word;margin-bottom:4px}
.pbar{height:14px;border-radius:999px;background:var(--choice-edge);overflow:hidden;margin:18px 0 10px}
.pbar>i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--good),var(--good-deep));border-radius:inherit}
.pstage{text-align:center;font-weight:800;color:var(--ink);min-height:22px}
@media (prefers-reduced-motion: reduce){.dz{transition:none}}
.syl-line .linkish,.syl-using .linkish{white-space:nowrap}

/* ---- Upload redesign step 2 (2026-09-19): optional answer sheet ---- */
.ans-add{margin:4px 0 14px}
.ans-open{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:12px;
  border:1px dashed var(--choice-edge);border-radius:14px;background:none;color:var(--ink);
  font-family:var(--font);font-weight:700;font-size:.92rem;cursor:pointer}
.ans-open:hover{border-color:var(--good-deep)}
.ans-open svg{color:var(--good-deep)}
#ansBox{border:1px solid var(--choice-edge);border-radius:16px;padding:12px}
.ans-head{display:flex;align-items:baseline;gap:8px;margin-bottom:10px}
.ans-head .linkish{margin-left:auto}
.seg{display:flex;background:var(--choice-edge);border-radius:12px;padding:3px;gap:3px;margin-bottom:8px}
.seg button{flex:1;border:0;background:none;border-radius:10px;padding:9px 6px;font-family:var(--font);
  font-weight:700;font-size:.86rem;color:var(--muted);cursor:pointer}
.seg button.on{background:var(--choice);color:var(--ink);box-shadow:0 1px 4px var(--shadow)}
#ansBox .hint-note{margin:0 0 10px}
.build-note{margin-top:14px;padding:12px;border-radius:12px;background:var(--choice);border:1px solid var(--choice-edge);
  font-size:.9rem;line-height:1.4;color:var(--ink)}
#buildDone{margin-top:12px}

/* ---- Upload redesign step 3 (2026-09-19): check screen ---- */
.chk-topics{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.chk-chip{font-size:.78rem;font-weight:700;padding:4px 10px;border-radius:999px;background:var(--choice);
  border:1px solid var(--choice-edge);color:var(--ink)}
.chk-chip.cls{background:var(--good-deep);border-color:var(--good-deep);color:#fff}
.chk-how{margin:10px 0 12px}
.chk-group{margin-bottom:14px}
.chk-group-h{font-size:.74rem;text-transform:uppercase;letter-spacing:1px;color:var(--label);font-weight:800;margin:0 0 6px}
.chk-q{display:flex;gap:10px;align-items:flex-start;padding:10px;border-radius:12px;border:1px solid var(--choice-edge);
  background:var(--choice);margin-bottom:6px;transition:opacity .15s}
.chk-q.off{opacity:.5}
.chk-q.off .chk-text{text-decoration:line-through}
.chk-tick{flex:none;padding-top:2px;margin:0;cursor:pointer}
.chk-tick input{width:20px;height:20px;accent-color:var(--good-deep);cursor:pointer}
.chk-body{flex:1;min-width:0}
.chk-text{font-size:.92rem;line-height:1.35;color:var(--ink);word-break:break-word}
.chk-choices{font-size:.82rem;color:var(--muted);margin-top:4px;line-height:1.4}
.chk-meta{margin-top:6px}
.src{display:inline-block;font-size:.72rem;font-weight:800;padding:2px 8px;border-radius:999px;
  background:var(--choice-edge);color:var(--ink)}
.src-answer_key,.src-worksheet_key{background:rgba(46,160,90,.16);color:var(--good-deep)}
.src-answer_sheet{background:rgba(255,160,40,.18)}
.src-edited{background:rgba(80,120,255,.16)}
.src-none{background:transparent;border:1px dashed var(--choice-edge);color:var(--muted)}
.chk-actions{display:flex;gap:14px;margin-top:6px;flex-wrap:wrap}
.chk-actions .linkish{font-size:.84rem;padding:4px 0}
.gs-modal .chk-actions{gap:2px 16px}
.gs-modal .chk-actions .linkish{min-height:40px;padding:0 2px}
.gs-modal .chk-actions .linkish:disabled{text-decoration:none;opacity:.45;cursor:not-allowed}
.gs-size{margin:8px 2px 6px}
.gs-add{margin:4px 0 12px}
.gs-add .linkish{min-height:40px;padding:0 2px}
.gs-add .linkish:disabled{text-decoration:none;opacity:.45;cursor:not-allowed}
.gs-add-form{margin-top:6px}
.gs-add-form input,.gs-add-form select{display:block;width:100%;box-sizing:border-box;min-height:40px;margin-top:8px;border-radius:10px;border:1px solid var(--choice-edge);background:var(--stage-bg);color:var(--ink);padding:10px;font-size:.95rem;font-family:var(--font)}
.gs-add-form .gs-count{margin:2px 0 0}
.gs-add-form .btn.small{margin-top:10px}
.chk-reveal[data-open]{text-decoration:none;color:var(--ink);font-weight:800}
.chk-editor{margin-top:8px}
.chk-opt{display:block;width:100%;text-align:left;margin-top:6px;padding:10px 12px;border-radius:10px;
  border:1px solid var(--choice-edge);background:var(--stage-bg);color:var(--ink);font-family:var(--font);font-size:.88rem;cursor:pointer}
.chk-opt:hover,.chk-opt.on{border-color:var(--good-deep)}
.chk-opt.on{box-shadow:inset 0 0 0 1px var(--good-deep)}
.chk-type{display:flex;gap:8px;align-items:center}
.chk-type input{flex:1;min-width:0;border-radius:10px;border:1px solid var(--choice-edge);background:var(--stage-bg);
  color:var(--ink);padding:10px;font-size:.95rem;font-family:var(--font)}
.chk-type .btn.small{margin-top:0}
.chk-type{flex-wrap:wrap}
.chk-type input{min-height:40px}
.chk-type .gs-count{flex:0 0 100%;margin:0}
.chk-more-row{text-align:center;margin:6px 0 10px}
#chkMore{margin-bottom:10px}
.chk-count{text-align:center;margin:8px 0 4px}

/* ---- Upload redesign step 4 (2026-09-19): game settings sheet ---- */
.gs-modal{max-height:min(88vh,760px);overflow-y:auto;overscroll-behavior:contain;width:min(94vw,480px)}
.gs-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.gs-head h2{margin:0}
.gs-head .cap{margin-bottom:2px;font-size:.78rem;text-transform:uppercase;letter-spacing:1px;color:var(--label);font-weight:800}
.gs-modal .cap.gs-sec{font-size:.78rem;text-transform:uppercase;letter-spacing:1px;color:var(--label);font-weight:800;margin:16px 0 6px}
.gs-how{margin:0 0 10px}
.gs-secname{font-weight:800}
.gs-modal .chk-q{background:var(--stage-bg)}
.gs-src{margin-top:12px;border:1px solid var(--choice-edge);border-radius:12px;padding:10px 12px}
.gs-src summary{cursor:pointer;font-weight:800;font-size:.9rem}
.gs-srcq{font-size:.85rem;line-height:1.4;margin-top:8px}
.gs-srcq.off{opacity:.55}
.gs-srcq .src{margin-left:4px}
.gs-modal textarea{width:100%;min-height:80px;border-radius:12px;border:1px solid var(--choice-edge);padding:10px;font:inherit;box-sizing:border-box}

/* ---- Class cards and class settings (2026-10-01) ---- */
.car-card .c-gear{position:absolute;top:14px;left:14px;z-index:3;width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;color:#fff;background:rgba(0,0,0,.28);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);box-shadow:0 2px 8px rgba(0,0,0,.2)}
.car-card .c-gear:focus-visible{outline:3px solid #fff;outline-offset:2px}
.car-card .c-gear svg{width:20px;height:20px}
.set-head .cls-gear{margin-left:auto}
.cls-game{align-items:flex-start}
.cls-game .cls-ico{flex:0 0 auto;margin:2px 4px 0 0;display:inline-flex}
.cls-game.off .chk-text{opacity:.6}
.set-head:has(.cls-gear){align-items:center;gap:8px}
.set-head:has(.cls-gear) .meta{margin-left:auto}
.set-head .cls-gear{margin-left:0}

/* ---- readable text on the sky (2026-10-08) ----
   Text that sits straight on the sky backdrop, not on a card, used --muted and
   the amber label, which measured about 2 to 1 against the deeper end of the
   sky. It takes the main ink now, which each theme and skin sets to read on its
   own backdrop. The Games and Score tabs drew white on green and orange
   (2.4 and 2.0 to 1); they use dark ink like the light tabs do. */
:root{--on-sky:#081826}
:root[data-theme="night"]{--on-sky:var(--ink)}
.screen-sub,.empty-note,.empty-note b,
.screen-inner > .hint-note,#addChooser .hint-note,#addChooser .linkish,
#topicsBody > .hint-note,#topicsBody > .linkish{color:var(--on-sky)}
:root[data-theme="night"] .nav-tile.nav-games{color:#000}
:root[data-theme="night"] .sync-state.offline{color:#ffb3b3}
.stat-chip .k{color:var(--ink)}
.nav-tile.nav-games,.nav-tile.nav-score{color:#10202e}
.sync-state.offline{color:#9d2b32;font-weight:800}
.acct-btn .a-txt small{color:var(--ink)}

/* ---- tap targets: every button and link at least 44 px tall ----
   Links inside a sentence get their height from padding, which an inline
   element does not pass on to the line, so the text does not move. */
.btn,.acct-btn{min-height:44px}
p .linkish,.hint-note .linkish{padding:15px 4px}
.linkish.swap,.step-alt .linkish,.dz-clear,.chk-more-row .linkish{min-height:44px;padding:0 10px;display:inline-flex;align-items:center;justify-content:center}
