/* SendWide design tokens — the single source of truth.
 *
 * Rationale and evidence: docs/design/anti-slop.md
 *
 * Three rules govern this file, and they are the point of it:
 *
 *  1. CLOSED SETS. Every scale below is finite and complete. If a value you want is
 *     not here, the answer is to use the nearest one, not to add a sibling. Drift
 *     into "just one more grey" is what makes an interface read as undesigned.
 *  2. SEMANTIC NAMES. --accent, --danger, --surface. Never --teal-2. A semantic name
 *     gets used correctly by someone who has not read this file; a hue name gets
 *     used at random.
 *  3. COLOUR IS AUTHORED IN OKLCH, SHIPPED AS HEX. The ramps were built by holding
 *     hue and stepping lightness evenly in OKLCH so the steps are perceptually even
 *     (sRGB hex steps are not). The oklch() source is recorded in the comment beside
 *     each value so the next person extends the ramp rather than eyeballing it.
 *
 * Deliberately NOT here: no gradient tokens, no coloured glow, no third elevation.
 * Those are the tells, and a token for one is an invitation to use it.
 */

:root {
  /* ---- Surfaces. Warm-shifted near-blacks, not Tailwind's cool slate. ---------- */
  --bg:            #0b0d0f;  /* house near-black, shared with SellWide + StockCraft */
  --surface:       #101316;  /* panels, cards                                       */
  --surface-2:     #14181c;  /* nested / hovered panel                              */
  --line:          #1e242a;  /* hairline                                            */
  --line-strong:   #2b333b;  /* emphasised divider                                  */

  /* ---- Text. Warm neutral ramp, hue 95 at very low chroma. ---------------------
   * Ratios are quoted against --surface, NOT --bg, because --surface is the harder
   * case and text sits on both. Measured, not estimated. */
  --ink:           #f1f0ec;  /* oklch(.955 .006 95)  16.4:1 on --surface           */
  --muted:         #a09e99;  /* oklch(.700 .008 95)   7.0:1 — body-safe            */
  --dim:           #82807b;  /* oklch(.600 .008 95)   4.7:1 — meets AA for text    */
  --faint:         #64635e;  /* oklch(.500 .008 95)   3.1:1 — LARGE/decorative ONLY */

  /* ---- Accent. Hue 172, and deliberately NOT a Tailwind swatch. ----------------
   * #2dd4bf (the previous value) is exactly Tailwind teal-400. --accent sits 36
   * units of RGB distance away, which is a different colour rather than a nudge.
   * SellWide is amber #ffab1f, StockCraft orange: teal is SendWide's family slot. */
  --accent:        #4fd9b4;  /* oklch(.80 .13  172)  11.1:1 on --bg                 */
  --accent-mid:    #37af90;  /* oklch(.68 .115 172)   7.1:1                         */
  --accent-dim:    #287f69;  /* oklch(.54 .09  172)   4.0:1 — borders, large text   */
  --accent-deep:   #124135;  /* oklch(.34 .055 172)  fills behind --accent text     */
  --on-accent:     #04120e;  /* text ON an --accent fill                            */

  /* ---- Status. Only three, because we only have three states worth colouring. -- */
  --ok:            #46c47d;
  --warn:          #d9a24f;
  --danger:        #e06a5c;

  /* ---- Type. Roles first, sizes second. --------------------------------------- */
  --font-sans:  "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --font-mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Bricolage is variable on BOTH opsz and wght. Headings set opsz high so the
   * display cut is used; body leaves it at text size. That is the same technique
   * Linear uses via Inter Display vs Inter, from one file instead of two.        */
  --step--1:  clamp(12.5px, 0.78rem, 13px);   /* mono labels, meta               */
  --step-0:   16px;                            /* body — the floor, never smaller */
  --step-1:   18.5px;                          /* lede                            */
  --step-2:   23px;                            /* h3                              */
  --step-3:   clamp(28px, 3.2vw, 36px);        /* h2                              */
  --step-4:   clamp(44px, 5.6vw, 76px);        /* h1                              */

  --lh-tight:  0.98;   /* display only — large type needs proportionally less     */
  --lh-snug:   1.28;
  --lh-body:   1.62;

  --tracking-display: -0.035em;   /* tightens as size grows, per Stripe's approach */
  --tracking-label:    0.14em;    /* mono uppercase labels                         */

  /* ---- Spacing. One 4px-based closed set. Tight WITHIN a group, generous
   * BETWEEN groups — uniform spacing everywhere is itself a tell.               */
  --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;

  /* ---- Radius. Near-square on purpose. `rounded-xl` on everything is tell #5,
   * and shadcn's untouched default is 0.625rem/10px — so we are nowhere near it. */
  --r-sharp: 0;
  --r-1:     3px;    /* buttons, inputs, panels — the workhorse */
  --r-2:     6px;    /* the logo tile only                     */
  --r-pill:  999px;  /* status dots and genuine pills ONLY     */

  /* ---- Elevation. EXACTLY TWO, and neither is coloured. ----------------------- */
  --elev-1: 0 1px 2px rgb(0 0 0 / 0.30);
  --elev-2: 0 8px 24px -8px rgb(0 0 0 / 0.55);

  /* ---- Motion. Authored easing, never the browser defaults — their
   * accelerations are too weak to read as intentional. Prefer ease-out so the
   * motion commits immediately; in-out is for moving something already on screen. */
  --dur-fast: 110ms;   /* under ~100ms reads as simultaneous: skip the animation  */
  --dur-base: 200ms;
  --dur-slow: 320ms;   /* past ~1s you need a loader, not a transition            */
  --ease-out:    cubic-bezier(.23, 1, .32, 1);
  --ease-in-out: cubic-bezier(.76, 0, .24, 1);

  /* ---- Layout ---------------------------------------------------------------- */
  --maxw:      1080px;
  --maxw-wide: 1180px;
  --measure:   58ch;   /* body copy never runs wider than this */
}

/* Self-hosted — see assets/fonts/NOTICE.txt for why, and for the OFL notices. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("assets/fonts/bricolage-grotesque-400-800.woff2") format("woff2-variations");
  font-weight: 400 800;
  font-stretch: 75% 100%;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("assets/fonts/ibm-plex-mono-500.woff2") format("woff2");
  font-weight: 500; font-display: swap;
}

/* ---- Primitives every page shares ------------------------------------------- */

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Numerals that sit in a column must not reflow as the value changes. Applies to
 * money, counts and rates — the reason Stripe sets tnum on every numeric cell. */
.tnum, td.num, .metric, .price-amt { font-variant-numeric: tabular-nums; }

/* Kill orphans and ragged headings without hand-inserted <br>. */
h1, h2, h3 { text-wrap: balance; }
p, li      { text-wrap: pretty;  }

h1 {
  font-size: var(--step-4);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-display);
  font-weight: 800;
  font-variation-settings: "opsz" 96;   /* display cut */
  margin: 0 0 var(--sp-5);
}
h2 {
  font-size: var(--step-3);
  line-height: var(--lh-snug);
  letter-spacing: -0.02em;
  font-weight: 700;
  font-variation-settings: "opsz" 48;
  margin: 0 0 var(--sp-4);
}
h3 {
  font-size: var(--step-2);
  line-height: var(--lh-snug);
  font-weight: 600;
  margin: 0 0 var(--sp-3);
}

.mono, code, kbd {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}
.label {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--dim);
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-mid); }

/* A designed focus ring, on brand. Generated output ships the browser default or
 * suppresses it; a considered :focus-visible is a real authorship signal. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

/* Honour the user's stated preference. Non-negotiable, not a nicety. */
@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;
  }
}
