/* ============================================================
   10X CRM — Design tokens
   Visual direction: "Cyber Chrome" — Windows 2000 / WinAmp window
   chrome rendered in cyber-futurist neon, with pixel-art accents.

   Every colour, size, and duration in this project comes from a token
   defined here. No component file may hardcode a raw value. Changing a
   token here changes it everywhere, which is what makes the dark/light
   toggle (P0.3) a single class swap on <html>.
   ============================================================ */

:root {
  /* ---- Typography -------------------------------------------
     Three families, each with a real fallback so that the app stays
     legible if the webfonts fail to load (e.g. offline demo).
     --font-display is a pixel font: it is only ever used at 10-12px
     for short strings (logo, labels, badges). Long text uses --font-ui. */
  --font-display: "Press Start 2P", "Courier New", ui-monospace, monospace;
  --font-ui: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", "Cascadia Code", Consolas, ui-monospace, monospace;

  --fs-display-sm: 10px;   /* pixel font: badges, labels, buttons */
  --fs-display: 12px;      /* pixel font: logo, window titles */
  --fs-xs: 11px;
  --fs-sm: 13px;
  --fs-base: 15px;
  --fs-lg: 18px;
  --fs-xl: 24px;
  --fs-2xl: 32px;

  --lh-tight: 1.2;
  --lh-base: 1.55;

  /* ---- Spacing: strict 4px pixel grid ------------------------
     A pixel-art aesthetic falls apart on half-pixel values, so every
     gap and padding in the app snaps to this scale. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;

  /* ---- Radii --------------------------------------------------
     Hard edges used to be a global law here, and that was the
     mistake that flattened the whole design: chrome gloss needs
     soft, generous curves and neon needs blur, so a blanket "max
     4px, zero blur" rule made two of the three references
     impossible to draw and pixel-art won by default.

     Hard edges are now a property of the PIXEL layer only —
     icons, dividers, sprites. Chrome controls (buttons, chips,
     pills) use --r-3 and up. */
  --r-0: 0px;
  --r-1: 2px;
  --r-2: 4px;
  --r-3: 8px;      /* chrome panels */
  --r-4: 14px;     /* glossy cards */
  --r-pill: 999px; /* buttons, chips — the Y2K candy shape */

  /* ---- Motion -------------------------------------------------
     --t-snap uses steps() rather than a smooth curve. That makes
     movement advance frame-by-frame like an animated sprite instead
     of gliding, which is what sells the retro feel. */
  --t-snap: 90ms steps(3, end);
  --t-fast: 140ms cubic-bezier(0.2, 0.9, 0.3, 1);
  --t-med: 240ms cubic-bezier(0.2, 0.9, 0.3, 1);

  /* Ambient motion: things that move on their own, forever, with
     nobody touching them. This is what stops the app feeling dead
     between clicks. Deliberately slow — an idle loop that repeats
     faster than about 2s reads as a fault rather than atmosphere.
     All of it is switched off by prefers-reduced-motion. */
  --t-drift: 26s;     /* haze blobs wandering across the page */
  --t-sweep: 9s;      /* horizontal scan pass */
  --t-pulse: 2.4s;    /* status dots breathing */

  /* ---- Layout -------------------------------------------------- */
  --tap-min: 44px;          /* accessibility floor for any control */
  --shell-max: 1200px;

  /* The strip along the left edge that belongs to the assistant and nothing
     else. It is sized for the WIDER of the two bodies — RONIN's canvas is now
     137px (the light theme's survivor is narrower) — plus the 16px he sits in
     from the edge and a gutter so content never touches him. Used by base.css
     to keep the page out of his way — see the note there. */
  --ronin-strip: 170px;
  --card-max: 420px;        /* auth card width, per P1.1 */
}

/* ============================================================
   DARK THEME — the default (PRD P0.3 specifies dark as default)
   Deep near-black surfaces with neon accents.
   ============================================================ */
:root,
[data-theme="dark"] {
  --bg-void: #05060A;       /* page background */
  --bg-deep: #0A0D16;       /* inset wells, input backgrounds */
  --surface: #10141F;       /* window and card bodies */
  --surface-up: #171D2C;    /* hovered / raised surfaces */

  --bevel-light: #3A4560;   /* top-left highlight of a raised bevel */
  --bevel-dark: #04050A;    /* bottom-right shadow of a raised bevel */
  --border: #2A3347;

  --text: #E6ECFF;
  --text-dim: #8A97B8;
  --text-faint: #5A6480;

  /* Neon accent ramp */
  --cyan: #00F0FF;          /* primary action, focus, links */
  --magenta: #FF2E97;       /* destructive, errors */
  --lime: #B6FF3C;          /* success */
  --amber: #FFB627;         /* warning, in-progress */
  --violet: #A855F7;        /* brand, title-bar gradient partner */

  /* Text colour placed on top of a solid neon fill */
  --on-accent: #05060A;

  --grid-line: rgba(42, 51, 71, 0.4);
  --scanline-alpha: 0.05;
  --glow-strength: 14px;

  /* ---- LAYER 1: CHROME -------------------------------------
     A glossy surface is three things stacked: a bright top half,
     a hard mid-line where the "glass" breaks, and a darker bottom
     half. --gloss-face paints all three in one gradient, laid
     OVER a component's own background colour so every surface
     keeps its identity and only gains the sheen. */
  --gloss-face: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.14) 0%,
    rgba(255, 255, 255, 0.04) 45%,
    rgba(0, 0, 0, 0.10) 46%,
    rgba(0, 0, 0, 0.22) 100%
  );

  /* The specular strip: the hard white glare across the top edge
     of moulded plastic. Applied to a ::before, never the element,
     so it can be animated independently. */
  --gloss-spec: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.40),
    rgba(255, 255, 255, 0) 62%
  );

  --glass: rgba(16, 20, 31, 0.72);
  --glass-blur: blur(14px) saturate(150%);
  --chrome-edge: rgba(255, 255, 255, 0.16);

  /* The same glass, for surfaces that are NOT allowed a live blur.
     backdrop-filter is the most expensive property in this stylesheet,
     and a page can hold thirty client cards and six stat tiles. Those
     get this instead: a little more opacity to stand in for the frost,
     and no per-frame blur at all. Only the few large structural
     surfaces — windows, the taskbar, toasts — keep the real thing. */
  --glass-solid: rgba(16, 20, 31, 0.88);

  /* ---- LAYER 2: BLOOM ---------------------------------------
     Offset and blur only — the COLOUR is supplied where it is
     used, so one token serves every accent:
         box-shadow: var(--bloom-md) var(--accent); */
  --bloom-sm: 0 0 8px;
  --bloom-md: 0 0 20px;
  --bloom-lg: 0 0 44px;

  /* Iridescence: the oil-slick sheen on a CD. Deliberately loops
     back to violet so it can scroll forever without a seam. */
  --iri: linear-gradient(
    115deg,
    var(--violet), var(--cyan), var(--magenta), var(--lime), var(--violet)
  );

  /* Atmosphere: two coloured clouds drifting behind everything,
     which is what gives a flat page depth. */
  --haze-a: radial-gradient(closest-side, rgba(0, 240, 255, 0.16), transparent);
  --haze-b: radial-gradient(closest-side, rgba(255, 46, 151, 0.14), transparent);
  --vignette: radial-gradient(ellipse at center, transparent 42%, rgba(0, 0, 0, 0.62) 100%);

  /* ---- Terminal / Matrix vocabulary -------------------------- */
  --phosphor: #39FF14;

  /* ---- What the canvas atmosphere paints (js/atmosphere.js) ---
     One canvas, two atmospheres. Dark falls: --phosphor is the rain.
     The fog and apparition tokens below are the light theme's job and
     are never used here, but they are declared in both themes so the
     painter can read the same four names whichever theme is active and
     never has to branch on colour. */
  --fog-far: transparent;
  --fog-near: transparent;
  --apparition: transparent;

  /* Shadow cast by a lifted object. Pulled out of --lift so each theme
     can say how heavy its own gravity is. */
  --lift-shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
}

/* ============================================================
   LIGHT THEME — "Soft Club, Haunted"

   Not a lightened dark theme. Its own aesthetic, sharing the dark
   theme's skeleton and nothing else.

   Two references, held in tension:

     GEN X SOFT CLUB (1996-2002) — the cool, muted, low-saturation
     reaction against Y2K's glitter. Frosted glass, brushed aluminium,
     translucent plastics, subway-signage typography. Strictly cool
     tones: slate, surgical white, icy blue, pale green. It is the
     "future that never existed", and it is calm.

     EARLY-2000s SURVIVAL HORROR — Silent Hill's fogbank and Resident
     Evil 4's ochre rot. This is what stops the calm being bland: the
     whites go ashen, every accent is pulled towards decay rather than
     candy, the vignette closes in, and things move behind the fog.

   The result should feel like a clean clinical interface installed
   somewhere it should not be. Dark is neon and alive; light is pale
   and wrong. They share every measurement and every component.

   Accents are darkened until white text on a filled control AND
   accent-coloured text on --surface both clear 4.5:1. Verified, not
   assumed — see the contrast check in the verification notes.
   ============================================================ */
[data-theme="light"] {
  /* Ashen, with a faint green cast. A pure blue-white would read as a
     clean product; the green is what makes it read as damp. */
  --bg-void: #C8CDC6;
  --bg-deep: #D6DAD3;
  --surface: #E9ECE6;
  --surface-up: #F5F7F2;

  /* A soft press into paper rather than a moulded plastic edge. */
  --bevel-light: #FDFEFC;
  --bevel-dark: #A6ADA4;
  --border: #9AA396;

  --text: #14171A;
  --text-dim: #454B4E;
  --text-faint: #61676B;

  /* Every accent is a soft-club colour taken somewhere unpleasant. */
  --cyan: #1B6070;      /* clinical teal — the icy blue, drained */
  --magenta: #8E2334;   /* dried blood */
  --lime: #47632E;      /* moss */
  --amber: #7A5709;     /* nicotine ochre */
  --violet: #4B4568;    /* bruise slate */

  --on-accent: #FFFFFF;

  /* The blueprint grid becomes faint pencil ruling on damp paper. */
  --grid-line: rgba(120, 130, 118, 0.22);
  --scanline-alpha: 0.03;

  /* ---- LAYER 1: FROST ---------------------------------------
     Dark's gloss is moulded plastic: a bright top, a hard mid-line
     where the glass breaks, a darker bottom. Frost has no break in
     it. This is one soft wash from milky to shadowed, which is what
     a sheet of frosted glass actually looks like. */
  --gloss-face: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.78) 0%,
    rgba(255, 255, 255, 0.34) 42%,
    rgba(198, 206, 196, 0.10) 74%,
    rgba(138, 148, 136, 0.20) 100%
  );

  --gloss-spec: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.62),
    rgba(255, 255, 255, 0) 78%
  );

  --glass: rgba(240, 243, 237, 0.60);
  --glass-solid: rgba(238, 241, 235, 0.92);

  /* saturate() BELOW 1 is the whole trick. Every other frosted-glass
     effect on the web saturates upwards to look vivid and expensive.
     Draining the colour instead is the bleach-bypass look these two
     references share — soft club got it from photography, survival
     horror got it from bad video. */
  --glass-blur: blur(16px) saturate(0.7);
  --chrome-edge: rgba(255, 255, 255, 0.82);

  /* ---- LAYER 2: NO BLOOM ------------------------------------
     Switched off completely, not merely dialled down. Dark glows
     because it is full of light sources; this room has none. Every
     glow in the app resolves to nothing here, which is why the focus
     ring in base.css keeps a real 2px outline underneath it. */
  --bloom-sm: 0 0 0;
  --bloom-md: 0 0 0;
  --bloom-lg: 0 0 0;
  --glow-strength: 0px;

  /* Gravity is softer and greyer than dark's hard black. */
  --lift-shadow: 0 5px 16px rgba(70, 78, 68, 0.22);

  /* Iridescence becomes ink. A printed slate header, not a CD sheen —
     still a five-stop loop so it can occupy exactly the same token,
     but every stop is a shade of the same wet slate. */
  --iri: linear-gradient(
    115deg,
    #3B454B, #56636A, #2C353A, #47535A, #3B454B
  );

  /* ---- The fog ----------------------------------------------
     Two banks rather than two coloured clouds: cold damp, and the
     ochre rot that hangs underneath it. */
  --haze-a: radial-gradient(closest-side, rgba(146, 164, 166, 0.38), transparent);
  --haze-b: radial-gradient(closest-side, rgba(158, 138, 106, 0.30), transparent);

  /* Far heavier than dark's. On a pale page a closing vignette is the
     single strongest dread signal available, and it costs nothing. */
  --vignette: radial-gradient(ellipse at center, transparent 34%, rgba(58, 64, 56, 0.42) 100%);

  --phosphor: #33604A;   /* damp moss, where dark has phosphor green */

  /* ---- What the canvas paints -------------------------------
     Read once by js/atmosphere.js. --apparition is the silhouette ink;
     the two fogs sandwich it, so a figure rises out of --fog-far and
     is never quite resolved because --fog-near is painted over it. */
  --fog-far: rgba(190, 199, 189, 0.55);
  --fog-near: rgba(214, 220, 212, 0.42);
  --apparition: #5E6A62;
}

/* ============================================================
   SEMANTIC ALIASES
   Components reference these, never the raw colour names. That means
   "Contacted should be violet instead of amber" is a one-line change
   here, and every badge, chip, select and pipeline segment follows.
   ============================================================ */
:root {
  --status-lead: var(--cyan);
  --status-contacted: var(--amber);
  --status-won: var(--lime);
  --status-lost: var(--magenta);

  --accent: var(--cyan);
  --danger: var(--magenta);
  --success: var(--lime);
  --warning: var(--amber);

  /* ---- Bevels: the Win2K chrome effect ----------------------
     A raised control is light on the top-left and dark on the
     bottom-right. A pressed or inset control is the exact inverse.
     Swapping --bevel-out for --bevel-in is what makes a button feel
     physically depressed. */
  --bevel-out: inset 1px 1px 0 var(--bevel-light),
               inset -1px -1px 0 var(--bevel-dark);
  --bevel-in: inset -1px -1px 0 var(--bevel-light),
              inset 1px 1px 0 var(--bevel-dark);

  /* Offset shadows with ZERO blur — a blurred shadow would break the
     pixel-art illusion immediately. */
  --shadow-hard: 4px 4px 0 var(--bevel-dark);
  --shadow-hard-sm: 2px 2px 0 var(--bevel-dark);
  --shadow-hard-lg: 6px 6px 0 var(--bevel-dark);

  /* A lifted chrome object: shadow underneath, hard bevel on the
     face, bright hairline along the top edge. The shadow itself is a
     per-theme token — dark casts hard black, light casts a soft grey,
     and a shadow that suited one looked broken in the other. */
  --lift: var(--lift-shadow),
          inset 0 1px 0 var(--chrome-edge),
          var(--bevel-out);

  /* The analytics terminal's well. Shared by both themes on purpose —
     see the note in pages.css. It lives here rather than as a literal
     colour in that file because this project's own rule is that no
     component may hardcode a raw value, and it was the last one left. */
  --terminal-well: #040A04;

  /* Focus is a bloom now, not a flat ring. The 2px solid ring is
     kept underneath it so focus is still visible for anyone who
     cannot perceive the glow, and in forced-colours mode. */
  --focus-bloom: 0 0 0 2px var(--accent), var(--bloom-md) var(--accent);
}
