/* ============================================================================
   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 */
  /* THREE EDGES, THREE JOBS (build 227, item 4).
     --border was #2B303A: 1.30:1 against --surface. That is fine for the
     decorative line around a card, and a failure of WCAG 1.4.11 the moment it
     is the only thing telling a person where a text field is. On the sign-in
     card an empty email box was a #23262D rectangle on a #181B21 card behind a
     1.30:1 hairline — three shades of the same dark, and on a phone in daylight
     no box at all.
       --border         decorative. The line around a card. Lifted one step to
                        #343B47 (1.53:1) so a card edge registers.
       --border-strong  emphasis: a scrollbar thumb, a hovered edge.
       --border-control THE EDGE THAT IDENTIFIES A CONTROL. #6B7486 clears 3:1
                        against every surface the platform paints — bg 3.95,
                        surface 3.67, surface-2 3.39, surface-3 3.22 — including
                        surface-3, which is the field's own fill, so the edge is
                        visible from both sides. Inputs, selects, textareas and
                        any button with no fill of its own wear this. */
  --border:         #343B47;
  --border-strong:  #4A5262;
  --border-control: #6B7486;

  /* --- 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;
  /* THE FLOOR (design review, item 11). 11px is the smallest type the platform
     prints — the QA review set it for menu captions, badges and drill tags in
     build 226 — and it needed a name, because the page stylesheets were
     reaching under it with 10px and 10.5px literals. Nothing goes below this
     and nothing invents a half-pixel step above it. */
  --fs-micro:   .6875rem;
  /* THE BIG NUMBER (design review, item 11). A SCAN Index in a ring, a
     parent's headline score, a moment's figure — the one piece of type on a
     page that is a MEASUREMENT rather than a sentence. It was 2.5rem on the
     player, 3.25rem on the parent and 1.75rem on a moment card: three sizes
     for one job, none of them named. Two steps, named, and nothing above
     --fs-display is anything else. */
  --fs-hero:    2.75rem;   /* the headline measurement */
  --fs-metric:  1.75rem;   /* the same thing on a card */

  --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);
  /* The control hairline. Anything a person types into, picks from or presses
     that has no fill of its own is drawn with this, never with --hair. */
  --hair-control: 1px solid var(--border-control);

  /* --- 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; }

/* ── THE BROWSER'S OWN CONTROLS, IN THE PLATFORM'S CLOTHES ────────────────
   (design review, item 10.)

   color-scheme is what tells a browser to paint the parts of a control it
   owns and CSS cannot reach: the list a <select> pops open, the calendar a
   date input drops down, the scrollbars, the spin buttons. Without it those
   arrive in the browser's LIGHT theme — three white boxes in a dark card on
   the Session plan, which is where the review found them.

   The declaration below is the whole fix for the parts CSS cannot style. The
   rule after it dresses the part CSS can: appearance:none plus a drawn
   chevron keeps the NATIVE element — its keyboard behaviour, its screen
   reader announcement, its mobile picker — and changes only the box. A custom
   listbox widget would have thrown all three away for the same look. */
:root { color-scheme: dark; }

select {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--surface-3);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 9.5 12 15.5 18 9.5' fill='none' stroke='%238B939E' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 18px 18px;
  border: var(--hair-control);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  padding: 10px var(--sp-8) 10px var(--sp-3);
  min-height: var(--tap);
}
/* A select with no room for the chevron (an inline one in a table cell) says
   so by carrying .bare, rather than by being overridden in six stylesheets. */
select.bare { background-image: none; padding-right: var(--sp-3); }

input[type="date"],
input[type="datetime-local"],
input[type="time"],
input[type="month"] {
  background: var(--surface-3);
  border: var(--hair-control);
  border-radius: var(--r-sm);
  color: var(--text-primary);
  padding: 10px var(--sp-3);
  min-height: var(--tap);
}
/* The little calendar glyph is drawn by the browser in its own colour; this
   is the one hook it gives us. */
::-webkit-calendar-picker-indicator { filter: invert(0.7); cursor: pointer; }

/* 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;
  --border-control: #B6BECC;
  --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;
  }
}

/* A BOX YOU CAN ACTUALLY HIT (build 226, QA #31). A browser draws a
   checkbox at 13x13, which is smaller than the letters beside it and far
   smaller than a fingertip. Twenty is the platform's floor; the coarse
   pointer rule below still gives it a 44px row to sit in. Anything that
   builds its own control (appearance:none, or an inline width) keeps
   whatever it set — this only raises the ones nobody styled. */
input[type="checkbox"],
input[type="radio"] {
  width: 20px;
  height: 20px;
  /* Never the thing that shrinks: inside a flex label ("[x] Scout individual
     players in this club") a box with a width and no flex basis gets squeezed
     back to thirteen pixels by the sentence beside it. */
  flex: 0 0 auto;
  accent-color: var(--cyan);
}

/* 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(--cyan) 30%, var(--cyan));
  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; }
}
