/* 3w — design tokens
   Single source of truth. Nothing downstream hard-codes a colour, size,
   or duration — every value a component needs lives here.

   Breakpoint reference (CSS custom properties can't drive @media
   conditions, so this is a convention, not enforced by the cascade):
     mobile   <600px
     tablet   600–1024px
     desktop  >1024px
     wide     >1600px
*/

:root {
  /* ── Colour — light (default) ──────────────────────────────────── */
  /* Tells the browser to render its OWN chrome to match: scrollbars,
     the native select menu on the contact form, text carets, autofill
     highlighting and default focus rings. Without it those stay light
     no matter how dark the page gets. Declared in all three blocks for
     the same reason every other token is. */
  color-scheme: light;

  --ink-900: #0B0B0C;   /* primary text, near-black, never pure #000 */
  --ink-700: #2A2A2E;
  --ink-500: #65656C;   /* secondary text — 4.5:1+ on both paper surfaces */
  --ink-300: #B8B6B1;   /* hairlines only — 1.9:1, never text */
  --paper:   #F7F5F1;   /* warm off-white canvas — not #FFF */
  --paper-2: #EFECE6;   /* alternating band */
  --white:   #FFFFFF;   /* cards / raised surfaces only */

  --signal:       #1B34F0;
  --signal-hover: #132AC7;
  --signal-tint:  #E7EAFE;

  --positive: #0E7A4F;

  --canvas: var(--paper);
  --text: var(--ink-900);
  --text-secondary: var(--ink-500);
  --surface: var(--white);
  --hairline-color: var(--ink-300);

  /* Foreground colours for content sitting directly on a solid
     --signal background (.bg-alt). NOT an alias to --paper/--ink-900:
     those tokens flip meaning between themes (paper is light-mode's
     canvas, near-black in dark mode), but which foreground reads best
     on --signal depends on how BRIGHT --signal itself is in the
     current theme, which doesn't track the same flip. Light mode's
     --signal is a dark blue (needs light text); dark mode's --signal
     is deliberately lifted much brighter for its own AA pass (needs
     dark text instead) — computed and verified per theme below, not
     assumed. */
  --on-signal: #F7F5F1;
  --on-signal-secondary: rgba(255, 255, 255, 0.75);
  --on-signal-hairline: rgba(255, 255, 255, 0.3);
  /* Error text on the signal band. The global form-error red lands at
     1.38:1 there, and the band's blue flips between themes, so this
     needs its own value per theme: 5.81:1 here, 4.73:1 in dark. */
  --on-signal-error: #FFD9DE;

  /* ── Typography ───────────────────────────────────────────────── */
  --font-display: 'Inter Tight', system-ui, sans-serif;
  --font-body: 'Inter Tight', system-ui, sans-serif;
  --font-mono: 'Geist Mono', 'JetBrains Mono', monospace;
  --font-serif: 'Instrument Serif', serif;

  /* Fluid scale, clamp() computed for a 360→1600px viewport. */
  --step--1: clamp(0.83rem, 0.80rem + 0.15vw, 0.94rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.15rem);
  --step-1:  clamp(1.25rem, 1.15rem + 0.50vw, 1.55rem);
  --step-2:  clamp(1.56rem, 1.35rem + 1.05vw, 2.30rem);
  --step-3:  clamp(1.95rem, 1.55rem + 2.00vw, 3.45rem);
  --step-4:  clamp(2.44rem, 1.70rem + 3.70vw, 5.20rem);
  --step-5:  clamp(3.05rem, 1.60rem + 7.25vw, 9.00rem);

  /* ── Space — 4px base ─────────────────────────────────────────── */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-5: 24px;  --sp-6: 32px;  --sp-7: 48px;  --sp-8: 64px;
  --sp-9: 96px;  --sp-10: 128px; --sp-11: 192px; --sp-12: 256px;

  /* ── Radius ───────────────────────────────────────────────────── */
  --radius-sm: 2px;
  --radius-md: 4px;
  --hairline: 1px solid var(--hairline-color);

  /* ── Grid ─────────────────────────────────────────────────────── */
  --grid-columns: 4;       /* mobile default; overridden per breakpoint below */
  --grid-gutter: var(--sp-5);
  --content-max: 1440px;
  --measure-max: 1200px;
  --page-pad: var(--sp-5);

  /* ── Motion ───────────────────────────────────────────────────── */
  --dur-fast: 140ms;
  --dur-base: 260ms;
  --dur-slow: 520ms;
  --dur-scroll: 800ms;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (min-width: 600px) {
  :root { --grid-columns: 6; }
}
@media (min-width: 1024px) {
  :root { --grid-columns: 12; --page-pad: var(--sp-8); }
}

/* ── Colour — dark, re-tuned (not inverted) ──────────────────────── */
/* System preference: applies when the OS is dark and no manual choice
   has been made. Guarded by :not([data-theme="light"]) so a manual
   light selection can still win over a dark system preference. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ink-900: #EDEBE7;      /* now the near-white text tone */
    --ink-700: #C7C4BE;
    --ink-500: #97948F;      /* re-tuned independently — a straight invert
                                 of --ink-500 fails 4.5:1 on the dark canvas */
    --ink-300: #38373A;      /* hairlines: darker, not lighter */
    --paper:   #08080A;
    --paper-2: #131315;
    --white:   #1B1B1E;      /* raised surfaces lift off canvas, not to white */

    --signal:       #5C72FF; /* lifted for AA on the dark canvas */
    --signal-hover: #7C8FFF;
    --signal-tint:  #1B2050;

    --positive: #35B37E;

    --canvas: var(--paper);
    --text: var(--ink-900);
    --text-secondary: var(--ink-500);
    --surface: var(--white);
    --hairline-color: var(--ink-300);

    /* Dark mode's --signal is much brighter than light mode's, so it
       needs dark foreground, not light — computed against #5C72FF
       specifically, not inherited from the light-mode values above. */
    --on-signal: #0B0B0C;
    /* 0.85 measured 4.31:1 against the dark-mode band (#5C72FF) — under
       the 4.5 AA floor for body copy, and that band carries the whole
       services list. The band inverts in dark mode (light blue,
       near-black text), so its ceiling is 4.97:1 at full strength; 0.95
       reaches 4.79:1 and keeps the text visibly secondary. */
    --on-signal-secondary: rgba(11, 11, 12, 0.95);
    --on-signal-hairline: rgba(11, 11, 12, 0.35);
    --on-signal-error: #2E000C;
  }
}

/* Manual toggle: wins in both directions regardless of system preference. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --ink-900: #EDEBE7;
  --ink-700: #C7C4BE;
  --ink-500: #97948F;
  --ink-300: #38373A;
  --paper:   #08080A;
  --paper-2: #131315;
  --white:   #1B1B1E;

  --signal:       #5C72FF;
  --signal-hover: #7C8FFF;
  --signal-tint:  #1B2050;

  --positive: #35B37E;

  --canvas: var(--paper);
  --text: var(--ink-900);
  --text-secondary: var(--ink-500);
  --surface: var(--white);
  --hairline-color: var(--ink-300);

  --on-signal: #0B0B0C;
  /* 0.85 measured 4.31:1 against the dark-mode band (#5C72FF) — under
     the 4.5 AA floor for body copy, and that band carries the whole
     services list. The band inverts in dark mode (light blue, near-black
     text), so its ceiling is 4.97:1 at full strength; 0.95 reaches
     4.79:1 and keeps the text visibly secondary. */
  --on-signal-secondary: rgba(11, 11, 12, 0.95);
  --on-signal-hairline: rgba(11, 11, 12, 0.35);
  --on-signal-error: #2E000C;
}
