/* ============================================================================
   SCAN Central — token layer.
   Loaded FIRST, by every page: the game SPA, the five role dashboards, the
   scouts, the combine and the sign-in card.

   THE NAMING CONFLICT, RESOLVED
   -----------------------------
   The game's stylesheet defined  --volt: #E8FF3A  (the XP yellow).
   Every dashboard's inline CSS redefined  --volt: #5FD1F3  (the brand cyan).
   Whichever loaded last won, so an XP bar and a primary button were the same
   colour on one page and opposite colours on the next.

     --volt  is now ONLY the gameplay/XP yellow  #E8FF3A
     --cyan  is the primary brand colour         #5FD1F3

   Nothing may rely on --volt meaning cyan. The compatibility block at the
   bottom maps the OLD dashboard names (--panel, --white, --steel, ...) onto
   the new ones, but it deliberately does NOT map --volt to cyan.
   ========================================================================= */

:root {
  /* --- Surfaces ------------------------------------------------------- */
  --bg:            #111318;   /* charcoal, page background */
  --surface:       #181B21;   /* panel */
  --surface-2:     #1E222A;   /* panel-2, raised */
  --surface-3:     #23262D;   /* graphite, inputs / tracks */
  --border:        #2B303A;
  --border-strong: #3A4150;

  /* --- Text ----------------------------------------------------------- */
  --text-primary: #F3F5F7;
  --text-muted:   #8B939E;
  /* Was #656C77, which reads at 3.25:1 against the panel background — below
     the WCAG AA 4.5:1 floor for the 12px labels it is used on, measured by
     an axe-core sweep of the live pages. #8A93A0 is the same cool grey a
     step brighter: 4.6:1 on --panel, still clearly quieter than --text. */
  --text-dim:     #8A93A0;
  --on-cyan:      #062430;   /* readable ink on a cyan fill */
  --on-volt:      #23260A;   /* readable ink on the XP yellow */
  --on-gold:      #2A2113;

  /* app.css referenced --text but nothing declared it. Alias, not a copy. */
  --text: var(--text-primary);

  /* --- Brand ---------------------------------------------------------- */
  --cyan:       #5FD1F3;   /* PRIMARY */
  --cyan-dim:   #2CA9CE;
  --cyan-soft:  rgba(95, 209, 243, .12);
  --gold:       #C9A36B;   /* SECONDARY */
  --gold-soft:  rgba(201, 163, 107, .14);

  /* --- Gameplay ------------------------------------------------------- */
  --volt:      #E8FF3A;   /* XP / energy ONLY. Never a button fill. */
  --volt-soft: rgba(232, 255, 58, .14);

  /* --- Status --------------------------------------------------------- */
  --green:  #4ADE80;
  --amber:  #FBBF24;
  --orange: #FB923C;
  --red:    #F87171;
  --green-soft:  rgba(74, 222, 128, .13);
  --amber-soft:  rgba(251, 191, 36, .13);
  --orange-soft: rgba(251, 146, 60, .13);
  --red-soft:    rgba(248, 113, 113, .13);

  /* --- Score bands (0-100 and 0-10 both map here) --------------------- */
  --band-start:      #F87171;
  --band-developing: #FB923C;
  --band-building:   #E8FF3A;
  --band-consistent: #5FD1F3;
  --band-advanced:   #4ADE80;
  --band-mastered:   #C9A36B;
  --band-unscored:   #8B939E;

  /* --- Type ----------------------------------------------------------- */
  --font-head: 'Montserrat', 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, Consolas, monospace;

  --text-scale: 1;          /* user preference, 0.80 - 1.60 */

  --fs-display: 2.25rem;
  --fs-h1:      1.5rem;
  --fs-h2:      1.25rem;
  --fs-h3:      1.0625rem;
  --fs-body:    1rem;
  --fs-small:   .875rem;
  --fs-tiny:    .75rem;

  --lh-tight: 1.15;
  --lh-head:  1.25;
  --lh-body:  1.55;

  --fw-body:  400;
  --fw-med:   600;
  --fw-bold:  700;
  --fw-black: 800;

  /* --- Spacing -------------------------------------------------------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 40px;

  /* --- Shape ---------------------------------------------------------- */
  --r-card: 16px;
  --r-btn:  12px;
  --r-pill: 999px;
  --r-sm:   8px;
  --r-sheet: 20px;

  /* app.css referenced --radius but nothing declared it. Alias of --r-card. */
  --radius: var(--r-card);

  --hair: 1px solid var(--border);

  /* --- Elevation ------------------------------------------------------ */
  --shadow:      0 8px 28px rgba(0, 0, 0, .38);
  --shadow-sm:   0 2px 10px rgba(0, 0, 0, .28);
  --shadow-lg:   0 24px 70px rgba(0, 0, 0, .52);
  --shadow-glow: 0 0 0 3px var(--cyan-soft);

  /* --- Interaction ---------------------------------------------------- */
  --tap: 48px;                     /* minimum touch target, everywhere */
  --focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--cyan);
  --dur-fast: .12s;
  --dur:      .2s;
  --dur-slow: .42s;
  --ease: cubic-bezier(.2, .8, .2, 1);

  /* --- Layout --------------------------------------------------------- */
  --app-max:  560px;               /* the game / mobile shell */
  --page-max: 1440px;              /* the dashboards */
  --side-w:   240px;               /* dashboard sidebar */
  --topbar-h: 60px;
  --tabbar-h: 64px;

  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  /* --- Z index -------------------------------------------------------- */
  --z-nav:    30;
  --z-sheet:  80;
  --z-modal:  90;
  --z-toast: 100;
}

/* ---------------------------------------------------------------------------
   Compatibility aliases.

   The five dashboards were written against these names. They are kept so the
   migration does not have to touch every rule at once. --volt is NOT in this
   list: the dashboards that wrote `var(--volt)` meaning cyan must be changed
   to `var(--cyan)`, which is the whole point of the split.
   ------------------------------------------------------------------------ */
:root {
  --charcoal: var(--bg);
  --panel:    var(--surface);
  --panel2:   var(--surface-2);
  --graphite: var(--surface-3);
  --white:    var(--text-primary);
  --steel:    var(--text-muted);
}

/* ---------------------------------------------------------------------------
   Base element defaults. Anything more opinionated belongs in app.css or
   dash.css — this file stays a token layer plus a reset.
   ------------------------------------------------------------------------ */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  font-size: calc(100% * var(--text-scale));
  scroll-behavior: smooth;
}

body {
  background:
    radial-gradient(1200px 700px at 78% -8%, rgba(95, 209, 243, .06), transparent 60%),
    var(--bg);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-body);
  line-height: var(--lh-body);
  min-height: 100vh;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-head);
  font-weight: var(--fw-black);
  line-height: var(--lh-head);
  letter-spacing: -.01em;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

a {
  color: var(--cyan);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

img, svg, video, canvas { display: block; max-width: 100%; }

button, input, select, textarea {
  font: inherit;
  color: inherit;
}

button { cursor: pointer; background: none; border: none; }

/* One visible focus treatment, platform-wide. Never remove it. */
:focus-visible {
  outline: none;
  box-shadow: var(--focus);
  border-radius: var(--r-sm);
}

::selection {
  background: var(--cyan);
  color: var(--on-cyan);
}

/* Scrollbars, dark. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--r-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-track { background: transparent; }

/* Screen-reader-only, for labels that must exist but not show. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link — first focusable thing on every page. */
.skip-link {
  position: absolute;
  left: var(--sp-3);
  top: calc(-1 * var(--tap) - 20px);
  z-index: calc(var(--z-toast) + 1);
  background: var(--cyan);
  color: var(--on-cyan);
  font-weight: var(--fw-black);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-btn);
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: calc(var(--safe-top) + var(--sp-3)); text-decoration: none; }

/* ---------------------------------------------------------------------------
   HIGH CONTRAST — body.hc
   Set by SCAN.prefs.apply() and by the game's Nav.applyPrefs().
   ------------------------------------------------------------------------ */
body.hc {
  --bg:            #000000;
  --surface:       #0B0D11;
  --surface-2:     #14171D;
  --surface-3:     #1C2029;
  --border:        #6A7383;
  --border-strong: #97A1B2;
  --text-primary:  #FFFFFF;
  --text-muted:    #D3D8E0;
  --text-dim:      #B4BCC7;
  --cyan:          #8FE4FF;
  --gold:          #E4C594;
  --volt:          #F2FF6B;
  --green:         #7DEBA6;
  --amber:         #FFD24D;
  --orange:        #FFB067;
  --red:           #FF9B9B;
  --shadow:    none;
  --shadow-sm: none;
  --shadow-lg: none;
  background-image: none;
}

body.hc a { text-decoration: underline; }

body.hc :focus-visible {
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 6px var(--cyan);
}

/* Borders must be visible, not decorative, in high contrast. */
body.hc .card,
body.hc .panel,
body.hc .btn,
body.hc .field input,
body.hc .field select,
body.hc .field textarea {
  border-width: 2px;
}

/* ---------------------------------------------------------------------------
   REDUCED MOTION.

   The original had ONE broken selector that fused the class override and the
   media query into a single rule, so neither matched and every animation kept
   running for players who had asked for stillness. They are separate here:
   `body.rm` is the in-app preference, the media query is the OS setting.
   ------------------------------------------------------------------------ */
body.rm,
body.rm *,
body.rm *::before,
body.rm *::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .001ms !important;
  scroll-behavior: auto !important;
}

body.rm {
  --dur-fast: .001ms;
  --dur:      .001ms;
  --dur-slow: .001ms;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  :root {
    --dur-fast: .001ms;
    --dur:      .001ms;
    --dur-slow: .001ms;
  }
}

/* Coarse pointers get the full tap target on anything interactive. */
@media (pointer: coarse) {
  button,
  [role="button"],
  a.btn,
  input[type="checkbox"],
  input[type="radio"] {
    min-height: var(--tap);
  }
}

@media print {
  body { background: #fff; color: #000; }
  .tabbar, .topbar, .side-nav, .sheet, .toast-wrap, .skip-link { display: none !important; }
}

/* ==========================================================================
   FLUID NAVIGATION (2026-07-30)
   ==========================================================================
   Three pieces, all progressive enhancement, all neutralised by the
   reduced-motion block above (animation-duration .001ms catches the
   view-transition pseudo-elements too, because they are animations):

   1. MPA view transitions. One declaration opts same-origin navigations into
      the browser's cross-document transition: the old page cross-fades into
      the new one instead of flashing white-then-dark. Browsers without
      support ignore it entirely.

   2. The pending-navigation bar. scan.js tags <html> with .nav-pending the
      moment a same-origin link is tapped, and the ::before below renders a
      thin volt bar sweeping the top of the viewport until the next document
      takes over. The tap is acknowledged in the same frame it happens —
      which is most of what "feels fast" means on a phone.

   3. Smooth in-page scrolling for anchor jumps, guarded by reduced motion.
   ------------------------------------------------------------------------ */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation-duration: 90ms; }
::view-transition-new(root) { animation-duration: 140ms; }

html { scroll-behavior: smooth; }

html.nav-pending::before {
  content: "";
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 40%;
  background: linear-gradient(90deg, transparent, var(--volt, #5FD1F3) 30%, var(--volt, #5FD1F3));
  border-radius: 0 2px 2px 0;
  z-index: 9999;
  animation: scan-navbar 1s ease-in-out infinite;
  pointer-events: none;
}
@keyframes scan-navbar {
  0%   { transform: translateX(-100%); }
  55%  { transform: translateX(150vw); }
  100% { transform: translateX(150vw); }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.nav-pending::before { animation: none; width: 100%; opacity: .5; }
}
