/* =============================================================================
   LAYER 1 — PRIMITIVES
   -----------------------------------------------------------------------------
   Raw, theme-agnostic values: colour ramps, type scale, spacing, radii, motion.
   Nothing here is a decision about the product — a primitive says "this is the
   colour", never "this is what the colour is for". Only the semantic layer
   (semantic-light.css / semantic-dark.css) may reference these directly.

   Components must NEVER use a primitive. If a component needs `--azure-600`,
   the missing piece is a semantic or component token, not a shortcut.

   THE PALETTE — "Calm medical blue, done right".
   The brand ramp is a clean, slightly cyan-leaning medical blue (#0b5fa6),
   cooler and more contemporary than a corporate navy. It is paired with a
   COOL-neutral slate ramp (not a warm cream) so the blue reads crisp rather
   than muddy, and a single saturated teal/cyan signature accent for the
   "alive" moments (AI, progress, positive actions). Status hues stay on their
   own independent ramps so a cancelled appointment can never borrow the brand.
============================================================================= */

:root {
  /* ----------------------------------------------------------- brand azure ---
     600 is the source colour (#0b5fa6) and the one the product is recognised
     by — a confident medical blue with a touch of teal in the hue. It sits at
     600 rather than 500 because it is a fairly dark hue: the steps BELOW it are
     the soft surfaces and the lifted hover / dark-theme variants, and the two
     above it are the pressed and text-on-tint shades. White clears 6.6:1 on it,
     so it can carry white labels directly, and hover LIFTS to a lighter blue
     (500, white still 5.0:1) rather than darkening. */
  --azure-50:  #eef6fc;
  --azure-100: #d3e8f8;
  --azure-200: #a6d0f0;
  --azure-300: #6fb0e4;
  --azure-400: #3888d1;
  --azure-500: #1673bd;
  --azure-600: #0b5fa6;
  --azure-700: #094b82;
  --azure-800: #0a3a63;
  --azure-900: #0b2c49;

  /* --------------------------------------------------------- cool neutrals ---
     A clean, cool-neutral slate ramp. Paired with the medical blue it gives a
     crisp, contemporary reading: the neutrals stay quiet and clinical while the
     blue supplies the only saturated, cool-forward note. Nothing here is pure
     black or pure white except the two endpoints, which are spent deliberately. */
  --slate-0:   #ffffff;
  --slate-25:  #fbfcfe;
  --slate-50:  #f3f6fb;
  --slate-100: #e8edf4;
  --slate-200: #d6dfea;
  --slate-300: #b9c5d5;
  --slate-400: #92a0b3;
  --slate-500: #616d7c;
  --slate-600: #49535f;
  --slate-700: #353d47;
  --slate-800: #232931;
  --slate-900: #151a1f;
  --slate-950: #0d1013;

  /* ------------------------------------------------- signature teal (2nd) ---
     The saturated cyan-teal signature. Leans blue-green so it separates from
     the status green by hue, and carries the AI brand moments, progress and
     supporting positive actions. Used sparingly so it reads as a signature,
     not decoration. The 400 step is the "bright" variant for dots and marks. */
  --teal-50:  #e6faf9;
  --teal-100: #c4f1ef;
  --teal-200: #93e3e0;
  --teal-300: #57cdca;
  --teal-400: #24b1b0;
  --teal-500: #109099;
  --teal-600: #0c7a89;
  --teal-700: #0a6472;
  --teal-800: #094e5a;
  --teal-900: #083b44;

  /* ------------------------------------------------- status hues (not brand) ---
     Deliberately separate ramps. A cancelled appointment must never be able to
     change colour because the brand did, and the brand must never be able to
     borrow "danger red" for a primary action. Each ramp carries a mid value for
     filled marks, a dark value for text on light, and a pale value for washes. */

  /* success — Confirmed / Completed / Active */
  --green-50:  #e9f7f0;
  --green-100: #cdecdd;
  --green-300: #74c29a;
  --green-500: #359a67;
  --green-600: #287d52;
  --green-700: #216542;
  --green-800: #184c31;

  /* warning — Pending / Past due */
  --amber-50:  #fdf3e2;
  --amber-100: #fae4bf;
  --amber-300: #e2b25f;
  --amber-500: #cd8a2c;
  --amber-600: #a76e20;
  --amber-700: #85581a;
  --amber-800: #624013;

  /* danger — Cancelled / No-show / destructive actions */
  --red-50:  #fdeeee;
  --red-100: #fad8d6;
  --red-300: #e69893;
  --red-500: #d1574f;
  --red-600: #b1423c;
  --red-700: #8f342f;
  --red-800: #6b2723;

  /* info — neutral information, front-desk lane.
     A DESATURATED slate-blue, deliberately greyer and cooler than the brand.
     The brand owns the saturated blue now; a vivid info blue would sit only a
     few degrees of hue from it and status/brand would read as one family —
     exactly what the status ramps exist to prevent. Dropping the chroma keeps
     the "neutral information" reading while the brand keeps the vivid end. */
  --blue-50:  #eef3f7;
  --blue-100: #dae4ec;
  --blue-300: #9bb2c2;
  --blue-500: #547a91;
  --blue-600: #446677;
  --blue-700: #375260;
  --blue-800: #293d47;

  /* AI — a documented additional semantic series. The Inbox has three lanes
     (AI / front desk / doctor) that must be tellable apart at a glance, so the
     AI lane needs a fourth hue that is neither brand nor status. A cool
     PERIWINKLE (blue-violet): it harmonises with the medical-blue + teal system
     rather than reading as a warm purple against it, while staying far enough
     round the wheel from the brand blue and the info slate to remain its own
     lane. This is what carries AI-branded chat bubbles, lane chips and avatars. */
  --violet-50:  #eef1fc;
  --violet-100: #dfe3f7;
  --violet-300: #a9b0e4;
  --violet-500: #6a6bcf;
  --violet-600: #5556b4;
  --violet-700: #444593;
  --violet-800: #313168;

  /* ----------------------------------------------------------- typography ---
     The one piece of real personality is kept: Fraunces italic for display
     titles over a clean grotesk body, with a clean mono for times / phones /
     money / IDs. */
  --font-sans: 'Hanken Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-serif: 'Fraunces', serif;
  --font-mono: 'IBM Plex Mono', monospace;

  /* Fluid where a line has to survive 390px without wrapping badly.
     The whole ramp is set at ~90% of its former size — the app read a touch
     zoomed-in, so the global scale-down lives here in the tokens rather than in
     any component. */
  --fs-display: clamp(25px, 3.24vw, 40px);
  --fs-page: clamp(22px, 1.9vw, 28px);
  --fs-section: 18px;
  --fs-card-title: 15px;
  --fs-kpi: clamp(27px, 2.15vw, 34px);
  --fs-body-lg: 15px;
  --fs-body: 14.5px;
  --fs-secondary: 13.5px;
  --fs-label: 13.5px;
  --fs-input: 14.5px;
  --fs-table-head: 12px;
  --fs-btn: 13.5px;
  --fs-meta: 12px;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  --lh-tight: 1.15;
  --lh-snug: 1.3;
  --lh-normal: 1.5;
  --lh-relaxed: 1.62;

  /* --------------------------------------------------------------- space ---
     4 / 8 / 12 / 16 / 20 / 24 / 32 / 40. Nothing outside this scale should
     appear as a gap or a margin anywhere in the app. */
  /* Also scaled to ~90% for the global scale-down (card padding, section gaps
     and every token-driven margin ride on this ramp). */
  --sp-1: 4px; --sp-2: 7px; --sp-3: 11px; --sp-4: 14px;
  --sp-5: 18px; --sp-6: 22px; --sp-7: 29px; --sp-8: 36px;

  /* -------------------------------------------------------------- radius ---
     Modernised a touch over the old scale: controls sit at 8–10px, cards at
     16px (a hair more generous, cleaner), dialogs at 18–20px. The pill is
     reserved for filters, segmented controls, statuses and the search field —
     never a form action. */
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 18px;
  --radius-2xl: 20px;
  --radius-pill: 999px;

  /* --------------------------------------------------------------- motion --- */
  --t-fast: 130ms;
  --t: 160ms;
  --ease: cubic-bezier(.2, .6, .3, 1);

  /* ------------------------------------------------------- page geometry ---
     One system for every operational page: full viewport width with a
     comfortable side gutter, capped only where a very wide screen would
     otherwise stretch a reading line past comfort. */
  --page-pad-x: clamp(14px, 2.25vw, 36px);
  --page-pad-top: 25px;
  --page-pad-bottom: 36px;
  --page-max: 1680px;
  --section-gap: 29px;

  /* History sections cap at ~5 rows before scrolling internally. */
  --payment-history-max-h: 420px;
  --appt-history-max-h: 340px;
}
