/* ==========================================================================
   Design tokens
   ==========================================================================
   Every component in the UI kit should consume these tokens rather than
   hardcoding colors/spacing/type — see docs/00-charter.md §4 (vanilla CSS,
   no framework) and docs/05-roadmap.md Phase 2.

   Breakpoints are listed here as documentation only — CSS custom properties
   cannot be used inside @media feature values in standard CSS, so each
   component's own @media rules must repeat these numbers literally. Keep
   them in sync with this list by hand.

   Breakpoints: sm 480px · md 768px · lg 1024px
   ========================================================================== */

:root {
  /* Tells the browser which palette native form controls (scrollbars,
     checkboxes, date pickers) should render in -- without this they stay
     light-themed even once the rest of the page switches. */
  color-scheme: light;

  /* Color — three background tiers, darkest to lightest:
     --color-page-bg (the page itself, <body> below) → --color-bg
     (Container, modals, form inputs — the "panel" tier sitting on the
     page) → --color-surface (Card/Alert/Badge/the nav/data-list — stacked
     on top of a container, meant to read as the brightest layer). Same
     order in both themes — see the --color-page-bg comment in
     :root[data-theme="dark"] below for why dark mode only needs to ADD a
     token here while light mode needed --color-bg/--color-surface
     themselves renumbered (in short: #fff was already the lightest
     possible sRGB value, leaving no headroom above it for
     --color-surface to be lighter still — dark mode has no such ceiling
     at its dark end). */
  --color-bg: #eef0f2;
  --color-surface: #fafbfc;
  --color-text: #1a1a1a;
  --color-text-muted: #5f6368;
  --color-border: #d9dadd;
  --color-primary: #2563eb;
  --color-primary-hover: #1d4ed8;
  --color-on-primary: #fff;

  /* Deliberately its own token, not --color-bg or --color-surface: editable
     form fields (TextField/Textarea/InputGroup's own input, plus the local
     .input/.select/.date-input rules duplicated across the *-form.module.css
     files) read as pure white, distinct from both the --color-bg "panel"
     tier they used to share with Container and the --color-surface tier —
     a deliberate deviation from the tier system above, not an omission. */
  --color-input-bg: #fff;

  /* Bottom stop of the page's own top-to-bottom gradient (body rule
     below) — the top stop is --color-bg itself, so the gradient starts
     exactly matching Container's tone (no visible seam where the two
     meet) and darkens away from it going down the page. Pushed
     meaningfully darker than the container/surface tiers above now that
     Container has its own opaque background (--color-bg,
     container.module.css): nothing renders text directly against this
     color anymore, so unlike --color-bg/--color-surface it isn't bound
     by --color-text's WCAG contrast floor — free to read as a distinct,
     clearly darker backdrop rather than a subtle tint. */
  --color-page-bg: #a6aebb;

  /* A fourth, "sunken" tier — darker than --color-bg, but unlike
     --color-page-bg it DOES need to stay bound by --color-text's WCAG
     floor: it's for a panel nested one level deeper than --color-bg that
     still renders text directly on it (e.g. a Mouvements de stock card's
     own "Supprimer la ligne" hover state,
     movement-lines-form.module.css's own `.remove:hover` — formerly the
     Assistant de stockage's SimpleList, removed 2026-08-28), not a
     non-text backdrop. #dcdfe3 keeps a ~13.3:1 contrast against
     --color-text (#1a1a1a), comfortably past the 4.5:1 AA floor — same
     contrast-script discipline as the rest of this file (see
     :root[data-theme="dark"]'s own docblock below). */
  --color-bg-inset: #dcdfe3;

  /* One step darker still than --color-bg-inset — for a single row/element
     that needs to stand out *within* an already-sunken panel. No current
     consumer as of 2026-08-28 (its one user, the removed Assistant de
     stockage's SimpleList "Total" row, was deleted alongside that
     component) — kept defined since it's a real step on this file's own
     tiering scale, not dead weight tied to one removed component. #c3c8ce
     keeps a ~10.6:1 contrast against --color-text, same contrast-script
     discipline as the rest of this file. */
  --color-bg-inset-strong: #c3c8ce;

  /* --color-danger, --color-success, and --color-warning were sized for
     ~4.5:1 contrast as TEXT color against --color-surface's ORIGINAL
     value, #f7f7f8 (WCAG AA, normal text) — the bar that matters since
     Alert/Badge render them as text-on-surface, not background fills
     (--color-danger was ~4.51:1, --color-warning ~4.69:1, both close to
     the floor). --color-surface is lighter now (#fafbfc, the tier
     redesign above) — lightening the background under a fixed-darkness
     text color only widens a contrast margin, never narrows it, so both
     ratios are comfortably higher than those original numbers, not
     lower. Still don't lighten --color-danger/--color-warning themselves
     without re-checking with a contrast script, not by eye (a real
     axe-core run caught the original --color-success #16a34a failing at
     ~3.08:1 — docs/04-retro-log.md Phase 6 — and --color-warning's
     original #d97706 was checked here while building Badge and found
     failing at ~2.98:1 before it ever had a real consumer,
     docs/04-retro-log.md Phase 9). */
  --color-danger: #dc2626;
  --color-success: #15803d;
  --color-warning: #b45309;
  --color-focus-ring: #2563eb;

  /* A border for a component nested inside an already-sunken panel
     (--color-bg-inset or --color-bg-inset-strong), where --color-border
     itself is too close in tone to read as a boundary (~1.1:1 against
     --color-bg-inset). Falls under the ~3:1 WCAG 1.4.11 "Non-text
     Contrast" floor other border tokens target (~1.4:1 against
     --color-bg-inset) — #b7bdc6 is a deliberate visual choice below
     that floor. */
  --color-border-strong: #b7bdc6;

  /* Light background for CustomerReferenceChip's own base chip look
     (customer-reference-chip.module.css's own .chip) — colored
     --color-primary text stays readable against 8% of it mixed into
     white (~4.6:1, past WCAG's 4.5:1 floor). See
     :root[data-theme="dark"] below: dark mode needs a different
     percentage and mix target. */
  --color-primary-tint: color-mix(in srgb, var(--color-primary) 8%, #ffffff);

  /* Independent of --color-success/--color-warning on purpose — those
     name a generic status vocabulary (form validation, Alert), while
     this pair names an actual business direction: inbound (réception)
     / outbound (expédition), shared by BusinessDocumentChip,
     StockMovementBadge, and QuantityBadge's own `@outbound`. Starting
     from the same hex values as --color-success/--color-warning today
     is coincidence, not a dependency — the two pairs can diverge later
     without cross-affecting each other. 6% into white clears the 4.5:1
     floor with margin (~4.6:1 both, same contrast-script discipline as
     the rest of this file). */
  --color-inbound: #15803d;
  --color-outbound: #b45309;
  --color-inbound-tint: color-mix(in srgb, var(--color-inbound) 6%, #ffffff);
  --color-outbound-tint: color-mix(in srgb, var(--color-outbound) 6%, #ffffff);

  /* Spacing (rem, not px — respects browser font-size/zoom) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;

  /* Type scale (rem, not px) */
  --font-family-base: system-ui, -apple-system, "Segoe UI", roboto, sans-serif;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-md: 1.125rem;
  --font-size-lg: 1.5rem;
  --font-size-xl: 2rem;
  --font-size-2xl: 2.5rem;

  /* Radius (used by Button/TextField/Modal/Toast in Phase 2) */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;

  /* Elevation shadow for a panel floating above the page (Container,
     container.module.css). Subtle here since the page background is
     already fairly light close to Container's own edges (the gradient,
     body rule below, starts at --color-bg — the same tone as Container
     itself). See :root[data-theme="dark"] below for why the alpha needs
     to be higher there rather than reusing this same value. */
  --shadow-container: 0 4px 16px rgb(0 0 0 / 8%);
}

/* Dark-mode token overrides (docs/00-charter.md §8, docs/04-retro-log.md
   Phase 6 for the contrast-verification pattern this follows). Keyed off
   `data-theme`, not a `prefers-color-scheme` media query -- ThemeService
   (app/services/theme.ts) sets the attribute for both the "follow the OS
   setting" and "explicit toggle" cases, so a single selector covers both
   instead of a media query fighting a manual override.

   Every value below was checked with a WCAG AA contrast script before
   picking it (same discipline as --color-success in :root above, which a
   real axe-core run caught failing at ~3.08:1) -- text/background pairs
   all land between 6.4:1 and 15.4:1, comfortably past the 4.5:1 floor.

   --color-on-primary is dark text here, not white: --color-primary and
   --color-danger both had to become light enough (~7-8.5:1) to work as
   plain text against --color-surface (used for nav/link text, not just
   button fills -- see header.module.css), which makes them too light for
   white button text to stay legible. Dark text on a light-accent button
   is the tradeoff that keeps both uses passing at once, rather than
   needing separate light/dark-mode-only tokens for text-role vs.
   button-fill-role accents. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --color-bg: #0f1115;
  --color-surface: #1a1d23;
  --color-text: #e8e8ea;
  --color-text-muted: #9aa0a8;
  --color-border: #2c2f36;

  /* Mirrors light mode's --color-bg-inset — darker than --color-bg
     (#0f1115) toward --color-page-bg (#030405), still checked against
     --color-text (#e8e8ea): ~16:1, comfortably past the 4.5:1 floor. */
  --color-bg-inset: #0a0c10;

  /* Mirrors light mode's --color-bg-inset-strong — darker still, toward
     --color-page-bg (#030405), checked against --color-text (#e8e8ea):
     ~18:1. */
  --color-bg-inset-strong: #060709;
  --color-primary: #7fb0fb;
  --color-primary-hover: #9dc4fc;
  --color-on-primary: #0f1115;
  --color-danger: #ff8a8a;
  --color-success: #5fd88a;
  --color-warning: #f5c451;
  --color-focus-ring: #7fb0fb;

  /* Mirrors light mode's --color-border-strong — recalculated for ~3:1
     against dark mode's own --color-bg-inset (#0a0c10), same WCAG 1.4.11
     floor. */
  --color-border-strong: #5c6065;

  /* Same role as light mode's own --color-primary-tint, mixed against
     --color-surface instead of white: dark mode's own --color-primary
     (#7fb0fb) is a light blue meant for light-on-dark text, so mixing
     it into white would pair light text with a near-white background.
     15% here checks at ~5.8:1 against --color-primary text. */
  --color-primary-tint: color-mix(in srgb, var(--color-primary) 15%, var(--color-surface));

  /* Same independent-tokens reasoning as :root's own --color-inbound/
     --color-outbound above — 20% into --color-surface checks at ~6:1
     (inbound) and ~6.5:1 (outbound) against their own text color. */
  --color-inbound: #5fd88a;
  --color-outbound: #f5c451;
  --color-inbound-tint: color-mix(in srgb, var(--color-inbound) 20%, var(--color-surface));
  --color-outbound-tint: color-mix(in srgb, var(--color-outbound) 20%, var(--color-surface));

  /* Pure white would be jarring against this theme's dark tiers, so unlike
     light mode this keeps form fields on --color-surface (#1a1d23) — the
     closest match to what most of these fields already rendered before
     --color-input-bg existed, and still reads as a distinct, brighter tier
     than the page around it. */
  --color-input-bg: var(--color-surface);

  /* --color-bg (#0f1115) and --color-surface (#1a1d23) already sit in the
     right order for the tier system above (bg darker than surface), so
     unlike light mode neither needs to change — this just adds a token
     darker than --color-bg for the gradient's bottom stop (body rule
     below uses --color-bg itself as the top stop, same as light mode).
     Pushed close to pure black — same reasoning as light mode's
     --color-page-bg: nothing renders text on it directly now that
     Container has its own opaque background, so it isn't bound by
     --color-text's contrast floor. */
  --color-page-bg: #030405;

  /* Same shadow, higher alpha: a black shadow this size barely
     registers against an already-dark page, so the alpha compensates to
     keep the elevation cue visible right at Container's own edges,
     where the page still matches --color-bg's own (lighter, by dark-mode
     standards) tone before the gradient darkens further down. */
  --shadow-container: 0 4px 16px rgb(0 0 0 / 40%);
}

/* ==========================================================================
   Minimal reset
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* leave at 100% — respects the user's browser font-size/zoom setting,
     which a px-based override would ignore */
  font-size: 100%;
}

/* Headings/paragraphs otherwise carry their own UA-default margin-block
   (~0.67em/1em) — inside a padded container that adds straight onto that
   container's own padding-block instead of collapsing into it (padding
   blocks margin collapse through it), so a leading `<h1>`/`<p>` visibly
   grows the top gap past the bottom one. `Stack` already spaces siblings
   with `gap`, not margins (its own docblock) — zeroing this out here
   makes that the ONLY source of vertical spacing between elements, so a
   container's own padding-block reads the same on both ends regardless
   of what its first/last child happens to be. */
h1,
h2,
h3,
h4,
h5,
h6,
p {
  margin: 0;
}

body {
  margin: 0;

  /* Starts at --color-bg (Container's own tone — no visible seam right
     where the two meet) and darkens toward --color-page-bg going down
     the page, rather than staying uniformly darker than Container
     everywhere. background-color is the fallback for the rare case
     gradients aren't supported; background-attachment: fixed pins the
     gradient to the viewport instead of the (possibly much taller)
     scrollable page, so the top-to-bottom transition stays visible on
     screen at any scroll position rather than stretching across the
     whole page height. */
  background-color: var(--color-page-bg);
  background-image: linear-gradient(
    to bottom,
    var(--color-bg),
    var(--color-page-bg)
  );
  background-attachment: fixed;
  color: var(--color-text);
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  line-height: 1.5;
}

/* A person asking for more contrast almost certainly doesn't want a
   background that shifts tone as they read down the page — fall back to
   the flat, fully-opaque --color-page-bg. */
@media (prefers-contrast: more) {
  body {
    background-image: none;
  }
}

img,
picture,
svg {
  display: block;
  max-inline-size: 100%;
}

/* :focus-visible, not bare :focus — keyboard users see a ring, mouse users
   don't get one after every click */
:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* First real print use case, added 2026-08-28 for the two blank-bon
   print-preview pages (`app/templates/contract/receipt-notes/print.gts`/
   `dispatch-notes/print.gts`) — global rather than scoped to those two
   pages specifically, since `AppHeader`/`Footer` are rendered once, in
   `app/templates/application.gts`, outside any per-route component's own
   DOM/CSS-Modules scope; hiding them here unconditionally on every route
   is a harmless, even correct, default in the meantime (nothing else in
   this app currently benefits from printing its own nav/footer chrome).
   Revisit if a future page ever wants the app chrome to survive
   printing. */
@media print {
  header,
  footer {
    display: none;
  }
}

/* Same first-print-use-case reasoning as the rule above — global, not
   scoped to the two print pages, for the same "nothing else in this app
   prints yet" reason. `@page` margins default to whatever the browser
   ships (Chrome/Firefox both default to roughly 1in/2.5cm on every
   side), which read as too much white space around a page-sized `.document`
   sized for on-screen preview — unlike the print dialog's own "Headers
   and footers" toggle (`.print-hint`, `receipt-notes.module.css`/
   `dispatch-notes.module.css`), `@page` margin IS a standard CSS Paged
   Media feature the page itself can set, no per-browser user setting
   involved. 1cm on request 2026-08-28 (down from the browser default). */
@page {
  margin: 1cm;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
