/* ═══════════════════════════════════════════════════════════════
   careiti-album.css — 將 app 由 "sunrise" 轉成首頁嘅 "album" 系統
   Loaded on every page carrying <body data-ct="app">, after that page's
   own <style> and before careiti-tablet.css.

   Why this file exists
   ────────────────────
   The product shipped with THREE visual systems, which is what "UI 不一致"
   actually means:

     1. sunrise light — cream #FAF8F3, teal→amber→coral gradients, 22px
        radii, emoji icons. Most pages.
     2. dark navy/purple — #050d1a ground, #7c3aed accents. Five pages
        (reaction, health-quiz, object-sort, orientation, n-back).
     3. album — the homepage, specified in MASTER.md.

   Album is the one that was designed. It wins. This file remaps every
   custom property those pages declare onto album values, so 29 pages
   convert without touching 29 files. Each page declares its palette in an
   inline `:root{}`; this sheet loads later at equal specificity, so it
   overrides by source order — the same mechanism careiti-tablet.css uses.

   The album contract (MASTER.md), restated because it is easy to break:
     · --teal-a #0D9488 is a SHAPE colour. Measured 3.33:1 on paper — it
       must never carry text. Text teal is --teal-ink #0B6E64 (5.44:1).
     · One red accent only (--stamp). No gradients on text. No pill
       shapes, no large rounded cards — prints are rectangles.
     · Hierarchy comes from position, weight, rule lines and whitespace,
       not from size. Display never exceeds 30px.

   Colours album did not define
   ────────────────────────────
   The app needs correct/incorrect semantics that MASTER.md has no token
   for. Rather than import #22c55e from the sunrise palette — which glows
   against warm paper and reads as a different product — one green was
   picked and MEASURED: #3D6B45 is 5.51:1 on --paper and 6.20:1 behind
   white text. Wrong answers reuse --stamp, the album's existing red.
   (Measured, not asserted. MASTER.md carries a scar from asserting a
   ratio that turned out to be 2.85:1.)
   ═══════════════════════════════════════════════════════════════ */

/* ── Album source of truth ──────────────────────────────────── */
body[data-ct="app"],
:root {
  --paper:      #F6F1E7;
  --paper-2:    #EFE7D8;
  --print:      #FFFDF8;
  --ink:        #221E1A;
  --ink-2:      #5B5147;
  --ink-3:      #6F6355;
  --rule:       #DFD3BE;
  --teal-a:     #0D9488;   /* shapes only — 3.33:1, never text */
  --teal-ink:   #0B6E64;   /* the teal text uses — 5.44:1 */
  --teal-deep:  #095A52;
  --tape:       #E8D9A8;
  --pen:        #2F4F8F;
  --stamp:      #B4472F;
  --grow:       #3D6B45;   /* correct — measured 5.51:1 on paper */
  /* The border a CONTROL uses. --rule is MASTER.md's hairline for print
     EDGES: at 1.31:1 on paper it is a decoration, and using it as the only
     thing outlining a button made 56 controls invisible — transparent fill
     plus an invisible border is an invisible control. WCAG 1.4.11 asks 3:1
     for UI components; measured 3.59:1 on paper, 3.98:1 on print. --rule
     keeps its decorative job; this one is for anything you can press. */
  --edge:       #8E7C5E;

  --r-print:    2px;
  --r-ui:       8px;
  --sh-print:   0 10px 26px rgba(58,42,20,.16), 0 2px 5px rgba(58,42,20,.10);
  --sh-lift:    0 20px 44px rgba(58,42,20,.22), 0 3px 8px rgba(58,42,20,.12);
  --f-album:    "DM Sans", "PingFang HK", "Hiragino Sans GB", system-ui, sans-serif;
  --f-hand:     "HanziPen TC", "Bradley Hand", "Xingkai TC", "PingFang HK", cursive;
}

/* ── Remap the sunrise palette ──────────────────────────────── */
body[data-ct="app"],
:root {
  --teal:        var(--teal-ink);   /* pages use --teal for text too */
  --teal-light:  var(--teal-a);
  --teal-dark:   var(--teal-deep);
  --c-teal:      var(--teal-ink);
  --c-teal-light:var(--teal-a);
  --c-teal-dark: var(--teal-deep);

  --cream:       var(--paper);
  --c-cream:     var(--paper);
  --paper-bg:    var(--paper);
  --c-paper:     var(--print);

  --stone-900:   var(--ink);
  --stone-700:   var(--ink-2);
  --stone-500:   var(--ink-3);
  --stone-300:   #CFC0A6;
  --stone-200:   var(--rule);
  --stone-100:   var(--paper-2);
  --c-ink:       var(--ink);
  --c-ink2:      var(--ink-2);
  --c-ink3:      var(--ink-3);
  --c-line:      var(--rule);
  --ink2:        var(--ink-2);
  --ink3:        var(--ink-3);
  --line:        var(--rule);

  /* The one accent. Amber, gold, coral and rose all collapse into it —
     album does not have a warm-decorative family, by design. */
  --amber:       var(--stamp);
  --c-amber:     var(--stamp);
  --gold:        var(--stamp);
  --c-gold:      var(--stamp);
  --coral:       var(--stamp);
  --c-coral:     var(--stamp);
  --rose:        var(--stamp);
  --c-rose:      var(--stamp);
  --accent:      var(--stamp);

  --green:       var(--grow);
  --good:        var(--grow);
  --c-good:      var(--grow);
  --red:         var(--stamp);
  --bad:         var(--stamp);
  --c-bad:       var(--stamp);

  /* Purple and blue become the biro — album's only other ink. */
  --purple:      var(--pen);
  --purple-dim:  rgba(47, 79, 143, .12);
  --purple-glow: rgba(47, 79, 143, .22);
  --blue:        var(--pen);

  --radius:      var(--r-print);
  --c-radius:    var(--r-print);
  --shadow:      var(--sh-print);
  --c-shadow:    var(--sh-print);
  --font:        var(--f-album);
  --c-font:      var(--f-album);
}

/* ── The five dark pages ────────────────────────────────────────
   reaction / health-quiz / object-sort / orientation / n-back shipped on a
   navy ground with purple accents. Left alone they stay a different
   product from everything the user just navigated through — this is the
   single largest source of the reported inconsistency. */
body[data-ct="app"] {
  --bg:        var(--paper);
  --surf:      var(--print);
  --surface:   var(--print);
  --surf2:     var(--paper-2);
  --surface2:  var(--paper-2);
  --card:      var(--print);
  --text:      var(--ink);
  --muted:     var(--ink-3);
  --dim:       var(--ink-3);
  --border:    var(--rule);
}

/* Those pages also hardcode the dark ground outside any variable. */
body[data-ct="app"] {
  background: var(--paper) !important;
  color: var(--ink);
  font-family: var(--f-album);
}

/* ── Prints, not cards ──────────────────────────────────────────
   Album cards are photographic prints: near-square corners, a warm white
   border, a real shadow. No 22px pills, no gradient fills. */
body[data-ct="app"] .card,
body[data-ct="app"] .c-card,
body[data-ct="app"] .q-card,
body[data-ct="app"] .result-card,
body[data-ct="app"] .level-card,
body[data-ct="app"] .lv-card,
body[data-ct="app"] .reward-card,
body[data-ct="app"] .sub-card,
body[data-ct="app"] .gcard,
body[data-ct="app"] .fcard,
body[data-ct="app"] .guild-card,
body[data-ct="app"] .camp-card,
body[data-ct="app"] .tier-card,
body[data-ct="app"] .session-card,
body[data-ct="app"] .feat-card {
  background: var(--print);
  border: 1px solid var(--rule);
  border-radius: var(--r-print);
  box-shadow: var(--sh-print);
  color: var(--ink);
}

/* ── Buttons ────────────────────────────────────────────────────
   One fill colour, and it is the teal that may carry white text. Gradients
   are removed rather than restyled: a gradient behind text has no single
   measurable contrast ratio, which is why the album system bans them. */
/* Everything below carries WHITE text somewhere in the app, so each one
   needs a dark fill or the label disappears. This list is not stylistic —
   it is the set of elements whose gradient this file removed. Neutralising
   a background without owning the foreground on top of it is what put 153
   pieces of white-on-white text into production. */
body[data-ct="app"] .btn-primary,
body[data-ct="app"] .c-btn,
body[data-ct="app"] .btn-teal,
body[data-ct="app"] .result-btn,
body[data-ct="app"] .next-btn,
body[data-ct="app"] .btn,
body[data-ct="app"] .cta,
body[data-ct="app"] .pop-label,
body[data-ct="app"] .hero-btn,
body[data-ct="app"] .hero-btn-sm,
body[data-ct="app"] .claim-btn,
body[data-ct="app"] .start-btn,
body[data-ct="app"] .nb-btn,
body[data-ct="app"] button.primary {
  background: var(--teal-ink);
  background-image: none;
  border: 1px solid var(--teal-deep);
  border-radius: var(--r-ui);
  color: #fff;
  box-shadow: none;
  font-family: var(--f-album);
  font-weight: 700;
  letter-spacing: .01em;
}
body[data-ct="app"] .btn-primary:active,
body[data-ct="app"] .c-btn:active,
body[data-ct="app"] .result-btn:active { background: var(--teal-deep); transform: scale(.985); }

body[data-ct="app"] .btn-secondary,
body[data-ct="app"] .btn-outline,
body[data-ct="app"] .c-btn-ghost,
body[data-ct="app"] .btn-sm {
  background: transparent;
  /* --edge, not --rule: a transparent control outlined with the decorative
     hairline is an invisible control (1.31:1 on paper). */
  border: 1px solid var(--edge);
  border-radius: var(--r-ui);
  color: var(--ink-2);
  box-shadow: none;
}

/* Answer and choice buttons are things you press, so they get the UI
   radius and a rule border — not a print border, which would read as
   content rather than control. */
body[data-ct="app"] .ans-btn,
body[data-ct="app"] .choice-btn {
  background: var(--print);
  border: 1.5px solid var(--rule);
  border-radius: var(--r-ui);
  color: var(--ink);
  box-shadow: none;
}
body[data-ct="app"] .ans-btn.correct,
body[data-ct="app"] .choice-btn.correct,
body[data-ct="app"] .ans-btn.reveal {
  background: rgba(61, 107, 69, .10);
  border-color: var(--grow);
  color: var(--ink);
}
body[data-ct="app"] .ans-btn.wrong,
body[data-ct="app"] .choice-btn.wrong {
  background: rgba(180, 71, 47, .09);
  border-color: var(--stamp);
  color: var(--ink);
}

/* ── Kill the gradients ─────────────────────────────────────────
   Several pages paint the hero, the score and the progress bar with a
   linear-gradient. Album has no gradient anywhere; a gradient under text
   also defeats any single contrast measurement. */
body[data-ct="app"] .hero,
body[data-ct="app"] .hero-band {
  background: var(--paper-2);
  background-image: none;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
body[data-ct="app"] .hero h1,
body[data-ct="app"] .hero h2 { color: var(--ink); }
body[data-ct="app"] .hero p,
body[data-ct="app"] .hero .sub { color: var(--ink-2); }

body[data-ct="app"] .score-big,
body[data-ct="app"] .big-score,
body[data-ct="app"] .result-score {
  background: none;
  -webkit-background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: var(--ink);
  font-weight: 800;
}

body[data-ct="app"] .timer-bar,
body[data-ct="app"] .progress-fill {
  background: var(--teal-a);
  background-image: none;
}
body[data-ct="app"] .timer-track,
body[data-ct="app"] .progress-dot { background: var(--rule); }
body[data-ct="app"] .progress-dot.done { background: var(--grow); }
body[data-ct="app"] .progress-dot.active { background: var(--teal-a); }

/* ── Bottom navigation ──────────────────────────────────────────
   Was a near-black bar under a warm paper page — the single most jarring
   seam in the app. It becomes paper with a rule line, and the labels get
   real contrast instead of 40% white. */
body[data-ct="app"] .bnav-dark,
body[data-ct="app"] .bnav,
body[data-ct="app"] .c-nav {
  background: var(--print);
  border-top: 1px solid var(--rule);
  box-shadow: 0 -6px 20px rgba(58, 42, 20, .07);
  backdrop-filter: none;
}
body[data-ct="app"] .bnav-dark .bnav-item,
body[data-ct="app"] .bnav a,
body[data-ct="app"] .c-nav a { color: var(--ink-3); }
body[data-ct="app"] .bnav-dark .bnav-item.active,
body[data-ct="app"] .bnav-dark .bnav-item.bnav-active,
body[data-ct="app"] .bnav a.active,
body[data-ct="app"] .c-nav a.active { color: var(--teal-ink); font-weight: 700; }

/* ── The games hub cards ────────────────────────────────────────
   These were the loudest thing in the product: eight saturated gradient
   tiles, white text on them, an 18px radius and a decorative white circle
   bleeding out of each corner. Against warm paper they read as a different
   application, and white-on-gradient has no single measurable contrast
   ratio — the same defect MASTER.md already banned once.

   Each gradient arrives as an INLINE style (the hub writes one per game
   from the catalogue, and the shortcut row hardcodes its own), so the
   background needs !important to be reachable at all. That is the narrow,
   justified use: competing with a per-element inline declaration, not with
   another stylesheet.

   The card becomes a print: warm white, one hairline rule, ink text, and
   the game's identity carried by a small teal tile behind its icon rather
   than by flooding the whole card. */
body[data-ct="app"] .gcard,
body[data-ct="app"] .fcard {
  background: var(--print) !important;
  background-image: none !important;
  border: 1px solid var(--rule);
  border-radius: var(--r-print);
  box-shadow: var(--sh-print);
  color: var(--ink);
}
body[data-ct="app"] .gcard::after { display: none; }   /* the corner circle */

body[data-ct="app"] .gcard .gi,
body[data-ct="app"] .fcard .fi {
  background: rgba(13, 148, 136, .12);
  border-radius: var(--r-ui);
  color: var(--teal-ink);
}
body[data-ct="app"] .gcard .gi svg,
body[data-ct="app"] .fcard .fi svg { color: var(--teal-ink); }

body[data-ct="app"] .gcard .gt,
body[data-ct="app"] .fcard .ft { color: var(--ink); font-weight: 700; }
body[data-ct="app"] .gcard .gd,
body[data-ct="app"] .fcard .fs { color: var(--ink-2); }

/* Tags were translucent white on the gradient; on paper they need a real
   edge and real ink. */
body[data-ct="app"] .gcard .gtag {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-ui);
  color: var(--ink-3);
  font-weight: 600;
}

/* Hover lifts the print and straightens it, per the album interaction
   spec — no colour change, no glow. */
@media (hover: hover) {
  body[data-ct="app"] .gcard:hover,
  body[data-ct="app"] .fcard:hover {
    box-shadow: var(--sh-lift);
    transform: translateY(-2px);
  }
}

/* The featured banner and the panel heroes carried the same gradients. */
body[data-ct="app"] .feat-hero,
body[data-ct="app"] .panel-hero,
body[data-ct="app"] .panel-hero.pvp,
body[data-ct="app"] .panel-hero.guild {
  background: var(--paper-2) !important;
  background-image: none !important;
  border: 1px solid var(--rule);
  border-radius: var(--r-print);
  box-shadow: var(--sh-print);
  color: var(--ink);
}
body[data-ct="app"] .feat-hero *,
body[data-ct="app"] .panel-hero * { color: inherit; }
body[data-ct="app"] .feat-hero .fh-sub,
body[data-ct="app"] .panel-hero p { color: var(--ink-2); }

/* The "evidence-backed" flag is a stamp — the album already has a component
   for exactly this, and it is the one place the red belongs. */
body[data-ct="app"] .feat-badge,
body[data-ct="app"] .badge-tag,
body[data-ct="app"] .sci-badge {
  background: transparent;
  border: 1px solid var(--stamp);
  border-radius: var(--r-print);
  color: var(--stamp);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* ── Cookie consent ─────────────────────────────────────────────
   An indigo #1e1b4b slab with periwinkle text, pinned to the bottom of
   every page in the product — the last remaining piece of a palette that
   no longer exists here, and the first thing a new visitor sees.
   Its own <style> is appended to <head> at runtime, so it sits after these
   link elements in document order; the extra class in this selector is what
   wins, not source position. */
body[data-ct="app"] #b4d-consent {
  background: var(--print);
  color: var(--ink);
  border-top: 1px solid var(--rule);
  box-shadow: 0 -8px 24px rgba(58, 42, 20, .10);
  font-family: var(--f-album);
}
body[data-ct="app"] #b4d-consent p { color: var(--ink-2); }
body[data-ct="app"] #b4d-consent p a { color: var(--teal-ink); }
body[data-ct="app"] #b4d-consent .b4d-btn-all {
  background: var(--teal-ink);
  border: 1px solid var(--teal-deep);
  border-radius: var(--r-ui);
  color: #fff;
}
body[data-ct="app"] #b4d-consent .b4d-btn-nec {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--r-ui);
  color: var(--ink-2);
}

/* ── Text orphaned by a flattened panel ─────────────────────────
   These carried white because they sat on a dark or gradient panel that
   this file turned to paper. Flattening a background without owning the
   text on it leaves the label invisible — the same mistake as the nav,
   found by the same audit. Enumerated rather than guessed: every entry
   below was reported at 1.02–1.13:1 by tools/contrast-audit.js. */
body[data-ct="app"] .streak-num,
body[data-ct="app"] .streak-label,
body[data-ct="app"] .streak-card,
body[data-ct="app"] .streak-card *,
body[data-ct="app"] .notif-title,
body[data-ct="app"] .notif-msg,
body[data-ct="app"] .notif-icon,
body[data-ct="app"] .notif-inner,
body[data-ct="app"] .pts-num,
body[data-ct="app"] .pts-lbl,
body[data-ct="app"] .lb-row,
body[data-ct="app"] .lb-row * { color: var(--ink); }

body[data-ct="app"] .streak-label,
body[data-ct="app"] .notif-msg,
body[data-ct="app"] .pts-lbl { color: var(--ink-2); }

/* Tabs and icon buttons are controls: the selected one gets the dark fill
   so its white label is legible, the rest read as ink on paper. */
body[data-ct="app"] .tab,
body[data-ct="app"] .icon-btn {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--r-ui);
  color: var(--ink-2);
}
body[data-ct="app"] .tab.active,
body[data-ct="app"] .icon-btn.on,
body[data-ct="app"] .icon-btn.active {
  background: var(--teal-ink);
  border-color: var(--teal-deep);
  color: #fff;
}

/* ── Focus ──────────────────────────────────────────────────────
   A ring is a shape, so the shape teal is correct here. */
body[data-ct="app"] :focus-visible {
  outline: 3px solid var(--teal-a);
  outline-offset: 2px;
}

/* ── Album motion ───────────────────────────────────────────────
   Prints settle; they do not bounce or glow. Anything that loops forever
   is removed — MASTER.md is explicit that nothing loops. */
body[data-ct="app"] .c-mascot .m-halo { animation: none; opacity: .5; }

@media (prefers-reduced-motion: reduce) {
  body[data-ct="app"] * { animation: none !important; }
}
