/* ==========================================================================
   JF Filtr — design tokens
   Three layers: primitive -> semantic -> component.
   Only this file may contain raw colour values.

   Colour carries meaning here, it is not decoration:
     cool aqua  = filtered air, the clean side, every call to action
     warm ochre = contaminant, dust; appears in diagrams only, never on a control
     graphite   = housing, frame, the raw-air side of the filter
     air white  = the clean room behind the filter
   ========================================================================== */

:root {
  /* ---------- LAYER 1: primitives ------------------------------------ */

  /* Graphite — one cool-tinted grey family, no warm greys anywhere */
  --c-graphite-950: #090f12;
  --c-graphite-900: #0d1519;
  --c-graphite-850: #101a1f;
  --c-graphite-800: #131f24;
  --c-graphite-700: #1b2b31;
  --c-graphite-600: #253941;
  --c-graphite-500: #33505a;

  /* Air — the clean side */
  --c-air-050: #f4f8f9;
  --c-air-100: #e7eff1;
  --c-air-200: #d3e0e3;
  --c-air-300: #b6c8cd;

  /* Slate — mid tones for muted text. The 550/650 steps exist because the
     round hundreds straddle the AA contrast line on the light backgrounds:
     550 is the lightest grey that holds 4.5:1 on air-100, 650 the body tone. */
  --c-slate-300: #9db1b7;
  --c-slate-400: #7e939a;
  --c-slate-500: #5d737b;
  --c-slate-550: #52676f;
  --c-slate-600: #46595f;
  --c-slate-650: #3f5158;

  /* Aqua — filtered air. Saturation held under 80% so it sits with the greys */
  --c-aqua-200: #a8ede7;
  --c-aqua-300: #7fe3db;
  --c-aqua-400: #4cd3c6;
  --c-aqua-500: #22b3a8;
  --c-teal-600: #0f7a80;
  --c-teal-700: #0c6068;
  --c-teal-800: #084a52;
  --c-teal-900: #063840;

  /* Ochre / rust — contaminant. Diagrams only. */
  --c-ochre-300: #e4b878;
  --c-ochre-400: #d69b4f;
  --c-rust-600: #a55a2b;

  /* Status */
  --c-danger-400: #e8776d;
  --c-danger-500: #d9564b;
  --c-danger-700: #8c2a22;
  --c-ok-400: #5fcb9c;
  --c-ok-500: #3fb984;
  --c-ok-700: #1d6b4a;

  /* Spacing scale — 4px base, optical steps at the top */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;     --sp-7: 2.5rem;   --sp-8: 3rem;
  --sp-9: 4rem;     --sp-10: 5.5rem;  --sp-11: 7rem;    --sp-12: 9rem;

  /* Radii — tighter inside, softer on containers */
  --r-xs: 2px; --r-sm: 3px; --r-md: 6px; --r-lg: 10px; --r-xl: 16px;

  /* Type */
  --font-display: 'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Geist', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --fs-micro: 0.72rem;
  --fs-xs: 0.8rem;
  --fs-sm: 0.9rem;
  --fs-base: 1rem;
  --fs-md: 1.08rem;
  --fs-lg: 1.28rem;
  --fs-xl: clamp(1.5rem, 2.4vw, 1.9rem);
  --fs-2xl: clamp(1.9rem, 3.6vw, 2.8rem);
  --fs-3xl: clamp(2.4rem, 5vw, 3.6rem);
  --fs-hero: clamp(2.7rem, 6.6vw, 5.6rem);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-fast: 140ms;
  --dur-base: 240ms;
  --dur-slow: 420ms;

  /* Z scale — no magic 9999 anywhere. The grain film sits ABOVE raised
     content (sections have opaque backgrounds, so a film below them would
     never be seen) but below the nav and overlays. */
  --z-raised: 10;
  --z-grain: 40;
  --z-sticky: 50;
  --z-nav: 100;
  --z-overlay: 200;

  --wrap-max: 1240px;
  --measure: 65ch;

  /* ---------- LAYER 2: semantic (light = the clean side, the default) --
     The page lives behind the filter: airy, near-white, cool-tinted.
     Accent is teal-700 so it holds AA contrast on white. */

  --bg: var(--c-air-050);
  --bg-deep: var(--c-air-100);
  --bg-raised: #ffffff;
  --bg-inset: var(--c-air-100);

  /* Contrast: every step holds AA (4.5:1) for normal text even on air-100,
     the darkest light surface it can sit on. */
  --text-strong: var(--c-graphite-950);
  --text-body: var(--c-slate-650);
  --text-muted: var(--c-slate-600);
  --text-faint: var(--c-slate-550);

  --border-hairline: var(--c-air-200);
  --border-strong: var(--c-air-300);

  --accent: var(--c-teal-700);
  --accent-hover: var(--c-teal-800);
  --accent-quiet: var(--c-aqua-500);
  --accent-on: var(--c-air-050);

  --contaminant: var(--c-ochre-400);
  --contaminant-deep: var(--c-rust-600);

  --focus-ring: var(--c-teal-700);
  --danger: var(--c-danger-700);
  --ok: var(--c-ok-700);

  /* Shadows tinted with the background hue, never plain black */
  --shadow-sm: 0 1px 2px rgb(30 52 60 / 0.08);
  --shadow-md: 0 12px 30px -16px rgb(30 52 60 / 0.28);
  --shadow-lg: 0 30px 70px -30px rgb(30 52 60 / 0.32);

  /* ---------- LAYER 3: component ------------------------------------- */

  --btn-bg: var(--accent);
  --btn-fg: var(--accent-on);
  --btn-bg-hover: var(--accent-hover);
  --btn-bg-active: var(--c-teal-900);
  --btn-bg-disabled: var(--c-air-200);
  --btn-fg-disabled: var(--c-slate-400);

  --btn-ghost-fg: var(--text-body);
  --btn-ghost-border: var(--border-strong);
  --btn-ghost-fg-hover: var(--accent);

  --field-bg: #ffffff;
  --field-fg: var(--text-strong);
  --field-border: var(--border-strong);
  --field-border-focus: var(--accent);
  --field-placeholder: var(--c-slate-400);
  --field-invalid: var(--danger);

  --card-bg: #ffffff;
  --card-border: var(--c-air-200);
  --card-border-hover: var(--c-aqua-500);
  --card-glow: rgb(34 179 168 / 0.16);

  --nav-bg: rgb(244 248 249 / 0.85);
  --nav-border: transparent;

  --datasheet-line: var(--border-hairline);
  --datasheet-row-hover: var(--c-air-100);
}

/* ---------- Raw-air scope -------------------------------------------------
   The two story strips in front of the filter flip the semantic layer to
   graphite. Every component token above resolves through these, so nothing
   needs a second rule set. */

.raw {
  --bg: var(--c-graphite-900);
  --bg-deep: var(--c-graphite-950);
  --bg-raised: var(--c-graphite-800);
  --bg-inset: var(--c-graphite-850);

  /* Contrast: slate-400 is the faintest grey that still holds AA on the
     raised graphite cards; slate-500 fell to 3.4:1 there. */
  --text-strong: var(--c-air-050);
  --text-body: var(--c-air-300);
  --text-muted: var(--c-slate-300);
  --text-faint: var(--c-slate-400);

  --border-hairline: var(--c-graphite-700);
  --border-strong: var(--c-graphite-600);

  --accent: var(--c-aqua-400);
  --accent-hover: var(--c-aqua-300);
  --accent-quiet: var(--c-teal-700);
  --accent-on: var(--c-graphite-950);

  --focus-ring: var(--c-aqua-300);
  --danger: var(--c-danger-400);
  --ok: var(--c-ok-400);

  --shadow-sm: 0 1px 2px rgb(6 14 17 / 0.5);
  --shadow-md: 0 10px 28px -12px rgb(6 14 17 / 0.75);
  --shadow-lg: 0 28px 64px -24px rgb(6 14 17 / 0.85);

  --btn-bg-active: var(--c-aqua-500);
  --btn-bg-disabled: var(--c-graphite-600);
  --btn-fg-disabled: var(--c-slate-500);

  --field-bg: var(--c-graphite-850);
  --field-placeholder: var(--c-slate-500);

  --card-bg: var(--c-graphite-800);
  --card-border: var(--c-graphite-700);
  --card-border-hover: var(--c-teal-700);
  --card-glow: rgb(76 211 198 / 0.14);

  --datasheet-row-hover: var(--c-graphite-700);
}
