/* =============================================================================
   ExamClash — A4A brand styles
   Palette is the A4A brand sheet, nothing else:
     deep pink #C2185B · teal #0097A7 · gold #F9A825
     black #212121 · warm sand #F4E9D6 · white #FFFFFF
   Type is Montserrat, self-hosted (subset to 48KB) so the app loads on a weak
   connection and works offline once installed.
   ========================================================================== */

@font-face {
  font-family: 'Montserrat';
  src: url('fonts/montserrat-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

:root {
  --pink:      #C2185B;
  --pink-dark: #8E1548;
  --pink-tint: rgba(194, 24, 91, 0.08);
  --teal:      #0097A7;
  --teal-dark: #00707C;
  --teal-tint: rgba(0, 151, 167, 0.10);
  --gold:      #F9A825;
  --ink:       #212121;
  --ink-soft:  #4A4A4A;
  --muted:     #857C6E;
  --sand:      #F4E9D6;
  --sand-dim:  #E4D7C0;
  --white:     #FFFFFF;

  --ok:   #0097A7;
  --bad:  #C2185B;

  --radius:    18px;
  --radius-sm: 12px;
  --pad:       18px;
  --shadow:    0 12px 28px -18px rgba(33, 33, 33, 0.55);
}

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

html, body {
  margin: 0;
  height: 100%;
}

/* Mobile browsers report 100vh as the height with the address bar hidden, so a
   full-height layout sits taller than the visible area and the bottom nav ends
   up under the chrome. dvh tracks the real viewport; the vh line stays as the
   fallback for anything that does not know dvh. */
@supports (height: 100dvh) {
  html, body { height: 100dvh; }
}

body {
  font-family: 'Montserrat', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: var(--sand);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.45;
  overscroll-behavior-y: contain;
}

#app {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100%;
  background: var(--sand);
  display: flex;
  flex-direction: column;
  position: relative;
}

.screen { display: none; flex: 1; flex-direction: column; padding-bottom: 84px; }
.screen.active { display: flex; }
.screen.no-nav { padding-bottom: 0; }
.hidden { display: none !important; }

/* ---------------------------------------------------------------- top bar */
.topbar {
  background: var(--ink);
  color: var(--white);
  /* index.html sets viewport-fit=cover, which extends the page under the status
     bar on a notched phone. Installed to a home screen the app has no browser
     chrome to hide behind, so without this the logo sits under the clock.

     Horizontal padding is tighter than --pad on purpose. This bar carries the
     A4A lockup (89px on its own), the wordmark and two live counters, and at
     375px the whole row came to 376px, so the wordmark truncated on one of the
     commonest phone widths there is. */
  padding: calc(14px + env(safe-area-inset-top)) 14px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  position: sticky;
  top: 0;
  z-index: 20;
}
.topbar .brand { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1 1 auto; }
/* The mark is square, so it costs 22px where the A4A lockup cost 89. That is
   most of the reason the wordmark no longer has to truncate at 375px. */
.topbar .brand .mark { display: block; flex-shrink: 0; }
/* The wordmark has to be the thing that gives way. Without the overflow rules
   it kept its full width on a 320px phone and the streak and XP pills sat on
   top of it. */
.topbar .brand .name {
  font-weight: 800; font-size: 16px; letter-spacing: -0.2px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
/* 500 against 900, tracking pulled in until the two halves touch: the clash is
   inside the word rather than decorating it. Both weights come out of the one
   variable font already loaded, so this costs no extra download.

   A class rather than :has(), because .name is also the screen title on the
   quiz and leaderboard bars and this has to hold on whatever Chrome shipped on
   a four-year-old Android. */
.topbar .brand .name.wordmark { letter-spacing: -0.03em; }
.topbar .brand .name.wordmark span { font-weight: 500; }
.topbar .brand .name.wordmark b    { font-weight: 900; }
.topbar .back {
  background: rgba(255,255,255,0.12); border: 0; color: var(--white);
  width: 44px; height: 44px; border-radius: 12px; font-size: 19px; cursor: pointer;
  flex-shrink: 0;
}

.pills { display: flex; gap: 6px; flex-shrink: 0; }
.pill {
  background: rgba(255,255,255,0.12); border-radius: 999px;
  padding: 5px 11px; font-size: 13px; font-weight: 700;
  display: flex; align-items: center; gap: 5px; white-space: nowrap;
}
/* The word beside a figure in a pill — "left" on the paper clock. Small enough
   that the figure still reads first. */
.pill .unit {
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.04em;
  opacity: 0.72; text-transform: uppercase;
}
/* Under a minute. The warning is the mark and the word as much as the colour:
   about one boy in twelve cannot use the colour. */
.pill.low { background: var(--pink); color: var(--white); }
.pill.low::before { content: '⚠'; }

/* ------------------------------------------------------------------- type */
h1, h2, h3 { margin: 0; letter-spacing: -0.4px; }
.hero { padding: 20px var(--pad) 6px; }
.eyebrow {
  font-size: 11px; font-weight: 800; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--pink);
}
.hero h1 { font-size: 23px; font-weight: 800; margin: 5px 0 3px; }
/* Streak and XP, in words. Below the greeting rather than in the top bar,
   because the words are the point and the top bar has no room for them. */
.statline { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.stat {
  background: var(--white); border-radius: 999px; padding: 6px 12px;
  font-size: 11.5px; font-weight: 600; color: var(--muted);
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.stat b { color: var(--ink); font-weight: 800; font-size: 13.5px; }
.stat .ico { font-size: 13px; }
.hero p  { margin: 0; color: var(--muted); font-size: 13.5px; }

.section-label {
  padding: 0 var(--pad); margin: 20px 0 10px;
  font-size: 11px; font-weight: 800; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
}

/* ------------------------------------------------------------------ cards */
.card {
  background: var(--white); border-radius: var(--radius);
  border: 1px solid rgba(33,33,33,0.07); padding: 16px;
}

.daily-card {
  margin: 6px var(--pad) 0;
  border-radius: var(--radius);
  padding: 18px;
  background: linear-gradient(135deg, var(--pink), var(--pink-dark));
  color: var(--white);
  box-shadow: var(--shadow);
}
.daily-card .label { font-size: 11px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.85; }
.daily-card h2 { font-size: 19px; font-weight: 800; margin: 4px 0 4px; }
.daily-card p  { margin: 0 0 14px; font-size: 13px; opacity: 0.92; }
.daily-card.done { background: linear-gradient(135deg, var(--teal), var(--teal-dark)); }

/* The misses card: a study tool, so it reads calmer than the daily. Teal to set
   it apart from the pink challenge above it and the white subject cards below. */
.review-card {
  display: flex; align-items: center; gap: 12px; width: calc(100% - 2 * var(--pad));
  margin: 12px var(--pad) 0; padding: 14px 16px; text-align: left;
  font-family: inherit; cursor: pointer;
  background: var(--teal-tint); border: 1px solid rgba(0,151,167,0.28);
  border-radius: var(--radius); color: var(--ink);
}
.review-ico {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; font-size: 19px; font-weight: 800;
  background: var(--teal); color: var(--white);
}
.review-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.review-title { font-size: 15px; font-weight: 800; }
.review-sub { font-size: 12px; color: var(--ink-soft); }
.review-count {
  flex: none; min-width: 26px; height: 26px; padding: 0 8px; border-radius: 13px;
  display: grid; place-items: center; font-size: 14px; font-weight: 800;
  background: var(--teal); color: var(--white);
}

/* The "you missed this N days ago" line above a review question. */
.miss-tag {
  margin: 4px 0 10px; padding: 8px 12px; border-radius: var(--radius-sm);
  background: var(--teal-tint); border-left: 3px solid var(--teal);
  color: var(--teal-dark); font-size: 13px; font-weight: 700;
}

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 0 var(--pad); }
.subject-card {
  background: var(--white); border: 1px solid rgba(33,33,33,0.07);
  border-radius: var(--radius); padding: 14px; text-align: left;
  cursor: pointer; font-family: inherit; display: flex; flex-direction: column; gap: 6px;
}
.subject-card:active { transform: scale(0.97); }
.subject-card .emoji { font-size: 20px; }
.subject-card .name  { font-weight: 700; font-size: 13.5px; line-height: 1.25; }
.subject-card .meta  { font-size: 11px; color: var(--muted); }
.subject-card .bar   { height: 4px; border-radius: 4px; background: var(--sand-dim); overflow: hidden; margin-top: 2px; }
.subject-card .bar > i { display: block; height: 100%; border-radius: 4px; }

/* The topic picker. One full-width row per topic: names like "Probability,
   permutations and combinations" need the width a two-column grid would take
   away, and a long list scans faster as a column. */
.topic-list { display: flex; flex-direction: column; gap: 8px; padding: 14px var(--pad) 34px; }
.topic-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: var(--white); border: 1px solid rgba(33,33,33,0.07);
  border-radius: var(--radius-sm); padding: 14px 16px; min-height: 52px;
  font-family: inherit; font-size: 14.5px; font-weight: 600; color: var(--ink);
  text-align: left; cursor: pointer;
}
.topic-row:active { transform: scale(0.99); }
.topic-row::after { content: '›'; margin-left: auto; font-size: 20px; color: var(--muted); }
.topic-row.all {
  background: var(--teal-tint); border-color: rgba(0,151,167,0.28); font-weight: 800;
}
.topic-row.all .sub { display: block; font-size: 12px; font-weight: 600; color: var(--ink-soft); margin-top: 2px; }
.topic-list .note { color: var(--muted); font-size: 13px; padding: 6px 2px; }

/* Access and payment (0038). The Home card reuses .review-card's teal shape;
   the paywall reuses the pink .daily-card for the price, so paying looks like
   part of the app rather than a form bolted on. */
.access-card { margin-top: 12px; }
.paywall-card { margin-top: 14px; }
.paywall-card h2 { font-size: 30px; }
.paywall-list { margin: 0 0 16px; padding-left: 18px; font-size: 13.5px; line-height: 1.55; }
.paywall-small { margin: 10px 0 0; font-size: 12px; opacity: 0.9; text-align: center; }
.paywall-more { padding: 6px var(--pad) 34px; display: flex; flex-direction: column; gap: 10px; }
.paywall-more .form { padding: 0; }
.access-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--white); border: 1px solid rgba(33,33,33,0.07);
  border-radius: var(--radius-sm); padding: 12px 14px;
}
.access-row > div { flex: 1; min-width: 0; }
.access-state { font-weight: 800; font-size: 15px; }
.access-row .hint { margin-top: 2px; }
/* Two classes so this beats .btn's width: 100%, which comes later. */
.access-row .access-btn { width: auto; min-height: 40px; padding: 8px 18px; flex: none; }
label .optional { font-weight: 500; color: var(--muted); }

/* --------------------------------------------------------------- buttons */
.btn {
  font-family: inherit; font-weight: 700; font-size: 15px;
  border: 0; border-radius: var(--radius-sm); padding: 14px 16px;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  gap: 7px; width: 100%; min-height: 48px;
}
.btn:disabled { opacity: 0.55; cursor: default; }
.btn:active:not(:disabled) { transform: scale(0.985); }
/* Nothing else on a phone confirms a tap landed, since the tap highlight is
   turned off at the top of this file. */
.tab:active, .nav button:active { transform: scale(0.97); }
.btn-primary   { background: var(--pink); color: var(--white); }
.btn-secondary { background: var(--sand-dim); color: var(--ink); }
.btn-teal      { background: var(--teal); color: var(--white); }
.btn-light     { background: var(--white); color: var(--pink); }
.btn-ghost     { background: transparent; color: var(--muted); font-weight: 600; }
.btnrow { display: flex; gap: 10px; padding: 0 var(--pad); }

/* ----------------------------------------------------------------- forms */
.form { padding: 0 var(--pad); }
.field { margin-bottom: 14px; }
.field label {
  display: block; font-size: 11px; font-weight: 800; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-soft); margin-bottom: 6px;
}
.field input, .field select {
  width: 100%; padding: 13px 12px; border-radius: var(--radius-sm);
  border: 1.5px solid var(--sand-dim); background: var(--white);
  font-family: inherit; color: var(--ink);
  /* Never drop below 16px. iOS Safari zooms the whole page in when a focused
     input has smaller text, and it does not zoom back out, which leaves a
     student scrolling sideways through the rest of the form. */
  font-size: 16px;
  min-height: 48px;
  appearance: none; -webkit-appearance: none;
}
.field select {
  /* appearance:none takes the arrow with it, so draw one back. */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) calc(50% + 2px), calc(100% - 14px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
}
.field input:focus, .field select:focus { outline: 0; border-color: var(--pink); }
.field .hint { font-size: 11.5px; color: var(--muted); margin-top: 5px; }
.field.invalid input, .field.invalid select { border-color: var(--pink); }

/* ------------------------------------------------------------------ quiz */
.progress { height: 5px; background: var(--sand-dim); }
.progress > i { display: block; height: 100%; background: var(--teal); transition: width 1s linear; }

.qmeta {
  display: flex; justify-content: space-between; align-items: center;
  /* The subject now flexes to fill, so space-between has no slack left to
     distribute and the three items butt together without an explicit gap. */
  gap: 10px;
  padding: 14px var(--pad) 0; font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
/* Three items share this row, and at 320px they do not all fit. The subject is
   the one that gives way, because it is the only one still readable when cut:
   "LITERATURE-IN-ENG…" still says literature, while "WAEC 2…" is a year the
   student cannot read and "QUESTION 1 OF…" loses the count. So the counter and
   the source tag hold their width and the subject ellipses between them. */
.qmeta > span:first-child {
  white-space: nowrap; flex-shrink: 0;
  /* No tracking on the counter. It is the least informative of the three and
     the tracking cost ~20px, which is the difference between "English
     Language" fitting on a 375px phone and clipping. */
  letter-spacing: 0;
}
.qsubject {
  color: var(--teal-dark);
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-align: center;
}
.qsource { color: var(--muted); white-space: nowrap; flex-shrink: 0; }
.qstem { padding: 10px var(--pad) 16px; font-size: 18px; font-weight: 700; line-height: 1.35; }
/* The word the question says is underlined. At 18px bold the browser default
   sits on the descenders, so it is pushed clear and thickened to survive a
   cheap screen. */
.qstem u, .mark-stem u {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.qstem img { max-width: 100%; border-radius: var(--radius-sm); margin-top: 10px; }

.options { padding: 0 var(--pad); display: flex; flex-direction: column; gap: 10px; }
.option {
  font-family: inherit; font-size: 14.5px; text-align: left; width: 100%;
  padding: 14px; border-radius: var(--radius-sm);
  border: 2px solid var(--sand-dim); background: var(--white); color: var(--ink);
  cursor: pointer; display: flex; gap: 10px; align-items: flex-start;
}
.option .key {
  font-weight: 800; color: var(--muted); flex-shrink: 0; width: 18px;
}
.option:active { transform: scale(0.99); }
.option.correct { border-color: var(--ok);  background: var(--teal-tint); }
.option.correct .key { color: var(--ok); }
.option.wrong   { border-color: var(--bad); background: var(--pink-tint); }
.option.wrong .key { color: var(--bad); }
/* Never signal right/wrong by colour alone — roughly 1 in 12 boys is
   colour-blind, and this is an app for teenagers. */
.option.correct::after { content: '✓'; margin-left: auto; font-weight: 800; color: var(--ok); }
.option.wrong::after   { content: '✗'; margin-left: auto; font-weight: 800; color: var(--bad); }
.option:disabled { cursor: default; }

/* --------------------------------------------------- timed paper: palette */
/* The row of question numbers under the clock. Answered carries a dot and
   flagged carries a mark, so the three states are never colour alone. */
/* Ten across a 375px phone without scrolling, and it wraps rather than
   scrolls when a mock paper brings fifty. */
.palette {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 12px var(--pad) 2px;
}
.pchip {
  font-family: inherit; font-size: 12.5px; font-weight: 700; flex: 0 0 auto;
  width: 28px; height: 28px; border-radius: 9px; position: relative; padding: 0;
  border: 2px solid var(--sand-dim); background: var(--white); color: var(--muted);
  cursor: pointer;
}
/* Answered is a filled chip, not a tinted one: fill against outline survives
   being seen in one colour, and a dot under the numeral read as punctuation. */
.pchip.done { background: var(--teal); border-color: var(--teal); color: var(--white); }
.pchip.flagged::before {
  content: '⚑'; position: absolute; top: -5px; right: -4px; font-size: 11px;
  color: var(--gold); text-shadow: 0 0 2px var(--sand);
}
/* Where you are. Ring rather than fill, so it reads on top of either state. */
.pchip.here { border-color: var(--pink); box-shadow: 0 0 0 2px var(--pink-tint); }
.pchip.here:not(.done) { color: var(--pink); background: var(--pink-tint); }

/* An answer chosen but not yet marked — the paper is still running, so this is
   the only state a timed option ever shows. */
.option.chosen { border-color: var(--pink); background: var(--pink-tint); }
.option.chosen .key { color: var(--pink); }
.option.chosen::after { content: '●'; margin-left: auto; font-weight: 800; color: var(--pink); }

/* Back and Flag take only what they need; Next takes the rest. `.btn` is
   width:100% for the full-width buttons everywhere else, which has to be undone
   here or the first one eats the row. */
.quiz-actions {
  display: flex; gap: 8px; padding: 16px var(--pad) 30px; align-items: center;
}
.quiz-actions .btn { width: auto; padding: 14px 14px; }
.quiz-actions #btn-next { flex: 1; }
.quiz-actions #btn-flag.on { background: var(--gold); color: var(--ink); }

/* What a filled chip means, spelled out on the one screen that needs it. */
.legend {
  display: flex; flex-wrap: wrap; gap: 14px; padding: 12px var(--pad) 0;
  font-size: 11.5px; color: var(--muted); font-weight: 600;
}
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i.pchip { width: 15px; height: 15px; border-width: 2px; }
.legend i.flagkey { color: var(--gold); font-style: normal; font-size: 13px; }

/* ---------------------------------------------------- the marked paper */
.mark-card {
  margin: 12px var(--pad) 0; padding: 14px; border-radius: var(--radius);
  background: var(--white); box-shadow: var(--shadow);
}
.mark-head {
  display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
.mark-no {
  width: 22px; height: 22px; border-radius: 7px; background: var(--sand);
  color: var(--ink); display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto; letter-spacing: 0;
}
.mark-subject { color: var(--teal-dark); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mark-verdict { margin-left: auto; flex: 0 0 auto; }
.mark-verdict.ok  { color: var(--ok); }
.mark-verdict.bad { color: var(--bad); }
.mark-stem { font-size: 14.5px; font-weight: 600; margin: 10px 0 12px; }
.mark-options { display: flex; flex-direction: column; gap: 7px; }
.mark-opt {
  font-size: 13.5px; padding: 9px 11px; border-radius: var(--radius-sm);
  border: 2px solid var(--sand-dim); display: flex; gap: 9px; align-items: flex-start;
}
.mark-opt .key { font-weight: 800; color: var(--muted); flex-shrink: 0; width: 16px; }
.mark-opt.correct { border-color: var(--ok); background: var(--teal-tint); }
.mark-opt.correct .key { color: var(--ok); }
.mark-opt.correct::after { content: '✓'; margin-left: auto; font-weight: 800; color: var(--ok); }
.mark-opt.wrong { border-color: var(--bad); background: var(--pink-tint); }
.mark-opt.wrong .key { color: var(--bad); }
.mark-opt.wrong::after { content: '✗'; margin-left: auto; font-weight: 800; color: var(--bad); }
.mark-card .explain { margin: 12px 0 0; }

.explain {
  margin: 14px var(--pad) 0; padding: 13px 14px; border-radius: var(--radius-sm);
  background: var(--white); border-left: 4px solid var(--gold);
  font-size: 13.5px; color: var(--ink-soft);
}
.explain b { color: var(--ink); }

/* ---------------------------------------------------------------- result */
.result-hero { background: var(--ink); color: var(--white); padding: 30px var(--pad) 34px; text-align: center; }
.result-hero .badge {
  width: 58px; height: 58px; border-radius: 18px; margin: 0 auto 12px;
  background: linear-gradient(135deg, var(--gold), var(--pink));
  display: flex; align-items: center; justify-content: center; font-size: 26px;
}
.result-hero h2 { font-size: 21px; font-weight: 800; }
.result-hero p  { margin: 5px 0 0; font-size: 13px; color: rgba(255,255,255,0.72); }

.score-card { margin: -22px var(--pad) 0; position: relative; z-index: 2; box-shadow: var(--shadow); }
.score-row  { display: flex; justify-content: space-around; text-align: center; }
.score-num  { font-size: 25px; font-weight: 800; }
.score-lbl  { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 2px; }

/* ----------------------------------------------------------- leaderboard */
.tabs { display: flex; gap: 8px; padding: 0 var(--pad) 4px; overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex-shrink: 0; font-family: inherit; font-size: 13px; font-weight: 700;
  padding: 11px 16px; border-radius: 999px; cursor: pointer;
  background: var(--white); border: 1px solid var(--sand-dim); color: var(--ink-soft);
  min-height: 44px;   /* a thumb, not a mouse pointer */
}
.tab.active { background: var(--ink); border-color: var(--ink); color: var(--white); }

/* Students|Schools and National|State toggles on the subjects board. */
.board-controls { display: flex; gap: 10px; padding: 8px var(--pad) 2px; flex-wrap: wrap; }
.seg { display: inline-flex; border: 1px solid var(--sand-dim); border-radius: 999px; overflow: hidden; }
.seg-btn {
  font-family: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
  padding: 9px 14px; min-height: 40px; border: 0; background: var(--white); color: var(--ink-soft);
}
.seg-btn.on { background: var(--pink); color: var(--white); }
.seg-btn + .seg-btn { border-left: 1px solid var(--sand-dim); }

/* Tap-to-reveal "how is this scored?" note under the board tabs. */
.board-info-toggle {
  display: block; margin: 6px var(--pad) 0; padding: 4px 0;
  background: none; border: 0; font-family: inherit; font-size: 12px; font-weight: 700;
  color: var(--pink); cursor: pointer; min-height: 32px; text-align: left;
}
.board-hint {
  margin: 2px var(--pad) 6px; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--sand); color: var(--ink-soft); font-size: 12.5px; line-height: 1.5;
}

.lb-list { padding: 4px var(--pad) 0; }
/* The break between the top ten and the viewer's own pinned row. */
.lb-gap { text-align: center; color: var(--muted); letter-spacing: 3px; padding: 2px 0; }
.lb-you { font-size: 11px; font-weight: 800; color: var(--pink); }
.lb-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 0;
  border-bottom: 1px solid rgba(33,33,33,0.07);
}
.lb-row.me { background: var(--pink-tint); border-radius: var(--radius-sm); padding: 12px 10px; border-bottom: 0; }
.lb-rank { font-weight: 800; font-size: 14px; color: var(--muted); width: 24px; flex-shrink: 0; }
.lb-rank.top { color: var(--gold); }
.lb-av {
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--white); font-weight: 800; font-size: 13px; background: var(--teal);
}
.lb-main { min-width: 0; flex: 1; }
.lb-name { font-weight: 700; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lb-meta { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lb-score { font-weight: 800; font-size: 14px; flex-shrink: 0; }

.note {
  margin: 12px var(--pad); padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--white); border-left: 4px solid var(--teal);
  font-size: 12.5px; color: var(--ink-soft);
}
.empty { padding: 28px var(--pad); text-align: center; color: var(--muted); font-size: 13px; }

/* Shown on the onboarding form when the server-fed State and Career lists did
   not arrive. Sits above the fields it is explaining, and carries its own
   retry, because a reload would cost the student their typing. */
.notice {
  background: var(--sand-dim);
  border: 1px solid var(--pink);
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 14px;
}
.notice p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.4; }
/* btn-secondary is --sand-dim, which is the notice's own background, so the
   button read as plain text sitting in the box. Give it its own ground. */
.notice .btn {
  width: auto;
  padding: 9px 18px;
  font-size: 14px;
  background: var(--white);
  border: 1px solid var(--pink);
  color: var(--pink);
}

/* -------------------------------------------------------------- profile */
.profile-head { display: flex; align-items: center; gap: 14px; padding: 18px var(--pad); }
.profile-av {
  width: 56px; height: 56px; border-radius: 50%;
  background: linear-gradient(135deg, var(--pink), var(--gold));
  color: var(--white); font-weight: 800; font-size: 21px;
  display: flex; align-items: center; justify-content: center;
}
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 0 var(--pad); }
.stat-box { background: var(--white); border: 1px solid rgba(33,33,33,0.07); border-radius: var(--radius-sm); padding: 12px; text-align: center; }
.stat-num { font-size: 18px; font-weight: 800; }
.stat-lbl { font-size: 9.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 2px; }

.srow { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.srow .nm { flex: 1; font-size: 13.5px; font-weight: 600; }
.srow .vl { font-weight: 800; font-size: 13.5px; }

/* ------------------------------------------------------------------- nav */
.nav {
  position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 100%; max-width: 480px; display: flex;
  background: var(--white); border-top: 1px solid rgba(33,33,33,0.09);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 30;
}
.nav button {
  flex: 1; background: none; border: 0; font-family: inherit; cursor: pointer;
  padding: 9px 0 11px; color: var(--muted);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.nav button.active { color: var(--pink); }
.nav .ic { font-size: 17px; line-height: 1; }
.nav .tx { font-size: 10px; font-weight: 700; }

/* ---------------------------------------------------------------- toast */
.toast {
  position: fixed; bottom: 92px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--white); padding: 11px 18px;
  border-radius: 999px; font-size: 13px; font-weight: 600; z-index: 60;
  box-shadow: var(--shadow); max-width: 90%; text-align: center;
}

.footnote { padding: 18px var(--pad) 26px; font-size: 11px; color: var(--muted); text-align: center; line-height: 1.5; }
/* The sign-in message is empty until something needs saying, and its padding
   would otherwise push the switch below it half a screen down. */
#auth-msg:empty { padding: 0; }

/* Swap between "redeem an invite" and "sign back in". */
.auth-switch {
  margin: 14px 0 0; padding: 0 var(--pad);
  font-size: 12.5px; color: var(--muted); text-align: center;
}
.lp-signin .auth-switch { padding: 0; }
.linkish {
  font-family: inherit; font-size: inherit; font-weight: 800;
  background: none; border: 0; padding: 4px 2px; margin-left: 2px;
  color: var(--pink); text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}

/* -------------------------------------------------------------- landing page
   The sign-in screen is also the only page anyone outside the pilot will ever
   see, so it has to answer three different people: the student who wants to
   play, the parent deciding whether to allow it, and the principal deciding
   whether to hand out seats. Sign-in stays first; the pitch runs underneath.
   Everything here is scoped to lp- so the app screens are untouched. */

.lp-signin {
  margin: 16px var(--pad) 0; padding: 16px;
  background: var(--white); border-radius: var(--radius);
  border: 1px solid rgba(33,33,33,0.07); box-shadow: var(--shadow);
}
.lp-signin .form { padding: 0; }
.lp-signin .field:last-of-type { margin-bottom: 16px; }
.lp-signin .footnote { padding: 12px 0 0; }

/* Two by two on a phone rather than four squeezed columns: at 375px the price
   is the widest of the four and would have forced the others to wrap. */
.lp-stats {
  display: grid; grid-template-columns: 1fr 1fr; row-gap: 16px;
  margin: 24px var(--pad) 0; padding: 14px 0;
  border-top: 1px solid var(--sand-dim); border-bottom: 1px solid var(--sand-dim);
}
.lp-stats div { text-align: center; }
.lp-stats div:nth-child(even) { border-left: 1px solid var(--sand-dim); }
@media (min-width: 560px) {
  .lp-stats { grid-template-columns: repeat(4, 1fr); row-gap: 0; }
  .lp-stats div:nth-child(n+2) { border-left: 1px solid var(--sand-dim); }
}
.lp-stats b { display: block; font-size: 21px; font-weight: 800; color: var(--pink); }
.lp-stats span {
  display: block; margin-top: 2px; font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}

.lp-h { padding: 0 var(--pad); margin: 28px 0 12px; font-size: 18px; font-weight: 800; }

.lp-steps { list-style: none; margin: 0; padding: 0 var(--pad); }
.lp-steps li { display: flex; gap: 12px; margin-bottom: 16px; }
.lp-steps .n {
  flex-shrink: 0; width: 27px; height: 27px; border-radius: 50%;
  background: var(--pink); color: var(--white);
  font-size: 13px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.lp-steps h3 { font-size: 14.5px; font-weight: 800; }
.lp-steps p  { margin: 3px 0 0; font-size: 13px; color: var(--ink-soft); }

.lp-cards { padding: 0 var(--pad); }
.lp-aud {
  background: var(--white); border-radius: var(--radius);
  border: 1px solid rgba(33,33,33,0.07); border-top: 4px solid var(--pink);
  padding: 16px; margin-bottom: 12px;
}
/* One colour per audience, so a card keeps its identity in a screenshot with
   no heading around it. */
.lp-aud.parents    { border-top-color: var(--teal); }
.lp-aud.principals { border-top-color: var(--gold); }
.lp-tag {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--pink);
}
.lp-aud.parents .lp-tag    { color: var(--teal-dark); }
.lp-aud.principals .lp-tag { color: #9A6500; }
.lp-aud h3 { font-size: 15px; font-weight: 800; margin: 5px 0 0; }
.lp-aud p  { margin: 6px 0 0; font-size: 13px; color: var(--ink-soft); }

/* Install instructions. Two cards rather than one list, because the Android
   route and the iPhone route share no step and interleaving them is how a
   parent ends up hunting for a Share button that Chrome does not have. */
.lp-lede {
  padding: 0 var(--pad); margin: 0 0 12px;
  font-size: 13px; color: var(--ink-soft);
}
.lp-aud.android .lp-tag { color: var(--teal-dark); }
.lp-aud.android { border-top-color: var(--teal); }
.lp-how {
  margin: 10px 0 0; padding-left: 20px;
  font-size: 13px; color: var(--ink-soft);
}
.lp-how li { margin-bottom: 6px; }
.lp-how li::marker { font-weight: 800; color: var(--pink); }
.lp-aud.android .lp-how li::marker { color: var(--teal-dark); }
.lp-how b { font-weight: 800; color: var(--ink); }
/* The caveat under each route, and the one under both. Smaller than the steps
   so it reads as an aside rather than a fourth thing to do. */
.lp-note {
  margin: 10px 0 0; padding-top: 9px;
  border-top: 1px solid var(--sand-dim);
  font-size: 12px; color: var(--muted);
}
.lp-note b { font-weight: 800; color: var(--ink-soft); }
.lp-note-wide { margin: 0 var(--pad); padding-top: 0; border-top: 0; }

/* Deliberately quiet: one muted line, no card, no border, no icon. It is an
   admission, not an announcement. */
.soon-note {
  margin: 12px var(--pad) 0;
  font-size: 12px; line-height: 1.5; color: var(--muted);
}

/* A mock card is a practice card that means business: the bar takes the gold
   so a full paper reads as a different kind of thing at a glance. */
.mock-card .bar i { background: var(--gold); }
.mock-card .meta { color: var(--ink-soft); font-weight: 700; }

/* Board strip on the subject picker. Two lists, edited one at a time, so the
   student always knows which exam they are choosing for. */
.board-tabs { display: flex; gap: 8px; margin-bottom: 12px; }
.board-tab {
  flex: 1; padding: 9px 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--sand-dim); background: var(--white);
  font-family: inherit; font-size: 13px; font-weight: 800; color: var(--muted);
  cursor: pointer;
}
.board-tab.on { background: var(--pink); border-color: var(--pink); color: var(--white); }
/* The profile lists WAEC and JAMB on their own lines. */
#pf-subject-list { white-space: pre-line; }

.lp-facts { list-style: none; margin: 0; padding: 0 var(--pad); }
.lp-facts li {
  position: relative; padding-left: 18px; margin-bottom: 9px;
  font-size: 13px; color: var(--ink-soft);
}
.lp-facts li::before {
  content: ''; position: absolute; left: 0; top: 7px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--teal);
}

.lp-cta {
  margin: 26px var(--pad) 0; padding: 18px;
  background: var(--ink); color: var(--white); border-radius: var(--radius);
}
.lp-cta h3 { font-size: 16px; font-weight: 800; }
.lp-cta p  { margin: 6px 0 14px; font-size: 13px; color: rgba(255,255,255,0.75); }
/* .btn is a <button> everywhere else; this one is a mailto. */
.lp-cta .btn { display: block; text-decoration: none; text-align: center; }

/* A principal or a parent is the one likely to open this on a laptop, and the
   480px phone column reads as a broken page there. The app screens keep it:
   only the landing widens, and only past the point where two columns fit. */
@media (min-width: 900px) {
  body.landing #app { max-width: 940px; }
  .lp-top {
    display: grid; grid-template-columns: 1.15fr 0.85fr;
    gap: 30px; align-items: start; padding: 10px var(--pad) 0;
  }
  .lp-top .hero { padding: 14px 0 0; }
  .lp-top .hero h1 { font-size: 34px; }
  .lp-top .hero p  { font-size: 15px; margin-top: 6px; }
  .lp-signin { margin: 0; }
  .lp-h { font-size: 22px; margin-top: 34px; }
  .lp-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
  .lp-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
  /* Three audiences fit the three columns; the install routes are a pair, and
     in a three-column grid the second one would sit next to an empty cell. */
  .lp-cards.lp-pair { grid-template-columns: repeat(2, 1fr); }
  .lp-aud { margin-bottom: 0; }
  .lp-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
  .lp-cta { display: flex; align-items: center; gap: 24px; }
  .lp-cta div { flex: 1; }
  .lp-cta p { margin-bottom: 0; }
  .lp-cta .btn { width: 260px; flex-shrink: 0; }
}

/* Parent-brand attribution. A free app that asks a teenager for their school
   and state has to say who is behind it, and A4A's name is the answer. */
.by-a4a {
  margin: auto 0 0; padding: 22px var(--pad) 28px;
  font-size: 11.5px; line-height: 1.6; color: var(--muted); text-align: center;
}
.by-a4a a { color: var(--ink-soft); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }

.spinner {
  width: 22px; height: 22px; border-radius: 50%;
  border: 3px solid var(--sand-dim); border-top-color: var(--pink);
  animation: spin 0.8s linear infinite; margin: 30px auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------- board headings + invite */
/* The profession boards get a real headline, because "Top Future Doctors" is
   the thing that ends up in a screenshot or a newspaper, and a bare list of
   names does not carry that on its own. */
.board-head {
  margin: 4px var(--pad) 12px; padding: 14px 16px;
  border-radius: var(--radius); color: var(--white);
  background: linear-gradient(135deg, var(--pink), var(--pink-dark));
}
.board-head .kicker {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.14em;
  text-transform: uppercase; opacity: 0.85;
}
.board-head h2 { font-size: 19px; font-weight: 800; margin: 3px 0 0; }
.board-head p  { margin: 5px 0 0; font-size: 12px; opacity: 0.9; }

.invite-card {
  margin: 14px var(--pad) 0; padding: 16px;
  background: var(--white); border: 1px solid rgba(33,33,33,0.07);
  border-radius: var(--radius);
}
.invite-card h3 { font-size: 15px; font-weight: 800; }
.invite-card p  { margin: 4px 0 12px; font-size: 12.5px; color: var(--muted); }

/* --------------------------------------------------------- small handsets */
/* A 320px Android is still a real device in Nigeria and it is the width the
   two-column subject grid gets tightest at. */
@media (max-width: 360px) {
  :root { --pad: 14px; }
  body { font-size: 14.5px; }
  .hero h1 { font-size: 21px; }
  .topbar { gap: 8px; }
  .topbar .brand { gap: 7px; }
  .topbar .brand .mark { width: 19px; height: 19px; }
  .topbar .brand .name { font-size: 14.5px; }
  .pill { padding: 5px 9px; font-size: 12px; }
  .grid2 { gap: 10px; }
  .subject-card { padding: 12px; }
  .stat-grid { gap: 8px; }
  .lb-av { width: 28px; height: 28px; font-size: 12px; }
  /* Three items in the question meta row do not fit at this width once the
     counter carries uppercase letter-spacing, and the subject was clipping even
     at "Mathematics". Dropping the tracking on the counter buys back the ~20px
     that keeps every ordinary subject name whole. */
  .qmeta { gap: 8px; }
  .lb-row { gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---------------------------------------------------- subject picker ---
   A tap target per subject, not a bare checkbox: the whole row is the
   control, sized past 44px so it works on a 320px phone. The compulsory two
   are shown checked and disabled rather than hidden, because a student who
   cannot see English in the list assumes it was forgotten. */
.subj-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.subj-item {
  display: flex; align-items: center; gap: 12px;
  min-height: 52px; padding: 8px 14px;
  background: var(--white); border: 2px solid transparent; border-radius: 14px;
  cursor: pointer; text-align: left; width: 100%;
  font-family: inherit; font-size: 15px; color: var(--ink);
}
.subj-item .emoji { font-size: 20px; line-height: 1; }
.subj-item .name  { font-weight: 700; flex: 1; min-width: 0; }
.subj-item .tick {
  width: 22px; height: 22px; border-radius: 7px; flex: none;
  border: 2px solid var(--sand-dim); display: grid; place-items: center;
  font-size: 13px; color: transparent;
}
.subj-item.on             { border-color: var(--teal); }
.subj-item.on .tick       { background: var(--teal); border-color: var(--teal); color: var(--white); }
.subj-item.locked         { opacity: 0.75; cursor: default; }
.subj-item.locked .name::after {
  content: ' · compulsory'; font-weight: 600; color: var(--muted); font-size: 12px;
}
.subj-item:disabled:not(.on) { opacity: 0.45; cursor: default; }
