/* Pawcast Design System — design tokens (generated from Figma V4IHAX481RwhC7CleZXwSl) */
/* Root = 20px (raised from 16px 2026-07-22, so 1rem=20px system-wide — every rem token below
   is expressed relative to THIS root; changing it rescales the whole system by design).
   Declared as a PERCENTAGE (125% of the browser default), not a hard px value, so it still
   respects a user's OS/browser font-size preference (a11y) — a hard `20px` would override it. */
html{ font-size: 125%; }
/* Add font fallbacks when loading: Fredoka + Rethink Sans via @font-face or Google Fonts. */
:root{
  color-scheme: light dark;

  /* ══ LAYER 1 · PRIMITIVES ══ the raw brand values, mirroring the Figma "Primitives" collection.
     This is the ONLY place a literal colour appears. Change a hex here and every semantic token
     that aliases it follows — in BOTH themes, across every component, with no other edit.
     Components must NEVER reference a primitive directly; they consume LAYER 2 below. */
  --fetch-orange: #ff6a3d;
  --fetch-strong: #e85526;
  --fetch-soft-light: #ffe7dd;
  --fetch-soft-dark: #3d2318;
  --park-green: #1fa463;
  --park-bright: #35c07e;
  --park-soft-light: #dbf3e7;
  --park-soft-dark: #16382c;
  --sunbeam-yellow: #ffc24b;
  --sun-soft-light: #fff0cf;
  --sun-soft-dark: #3a2f16;
  --forest-deep: #123c27;
  --forest-strong: #0c2a1b;
  --forest-light: #1a5638;
  --ink-900: #2a1f18;
  --ink-850: #241b14;
  --ink-950: #17110c;
  --ink-black: #000000;
  --taupe-700: #5c4b3e;
  --taupe-500: #8a7768;   /* the quietest legible step — role-2 links; see --color-link-muted */
  --taupe-300: #cdbbaa;
  --cream-paper: #fcf3e8;
  --cream-surface: #fffbf3;
  --cream-line: #eadcc6;
  --cream-pale: #f0e6d6;
  --line-dark: #40342a;
  --sky-blue: #5e9dff;
  --red-danger: #e5484d;
  --danger-soft-light: #fde8e8;
  --danger-soft-dark: #3d1c1c;
  --info-soft-light: #e4eeff;
  --info-soft-dark: #1b2740;
  --white: #ffffff;
  /* shadow washes — kept as primitives because rgba() can't be composed from a hex var */
  --shadow-ambient-light: rgba(42, 31, 24, 0.28);
  --shadow-ambient-dark: rgba(0, 0, 0, 0.6);

  /* ══ LAYER 2 · SEMANTIC ══ what components actually consume. Every one aliases a primitive;
     a raw hex down here is a bug. Light values; the dark blocks at the bottom re-alias. */
  --color-bg: var(--cream-paper);
  --color-surface: var(--cream-surface);
  --color-text: var(--ink-900);
  --color-text-muted: var(--taupe-700);
  --color-text-on-primary: var(--ink-black);
  --color-text-on-dark: var(--cream-paper);
  --color-primary: var(--fetch-orange);
  --color-primary-hover: var(--fetch-strong);
  --color-secondary: var(--forest-deep);
  --color-secondary-hover: var(--forest-strong);
  --color-accent: var(--sunbeam-yellow);
  --color-success: var(--park-green);
  --color-border: var(--ink-900);
  --color-border-subtle: var(--cream-line);
  --color-focus: var(--sky-blue);
  --color-danger: var(--red-danger);
  /* Soft tints — badge/pill/alert backgrounds. THEME-AWARE: light tints here, dark tints in the
     dark blocks below, so text/border can use the flipping --color-text / --color-border. */
  --color-fetch-soft: var(--fetch-soft-light);  /* ink 13.6:1 */
  --color-park-soft:  var(--park-soft-light);   /* ink 13.6:1 */
  --color-sun-soft:   var(--sun-soft-light);    /* ink 14.3:1 */
  --color-danger-soft: var(--danger-soft-light);/* ink 13.4:1 */
  --color-info-soft:   var(--info-soft-light);  /* ink 13.7:1 */
  /* the white a rising-disc hover reveals — a token so it is not a literal in component CSS */
  --color-disc-reveal: var(--white);
  /* Link colour for links that must read as links against body copy (in-content, breadcrumb).
     THEME-AWARE and deliberately in the green family: Forest is AAA on paper (10.9:1) but is
     dark-fixed, so dark mode flips to Park-bright (8.1:1 on the night page, 7.2:1 on dark surface).
     Nav + footer links stay --color-text; see the Link component. */
  /* THREE link roles (see MOTION.md):
     1 plain   — nav header, footer: inherits --color-text; the context already says "link"
     2 muted   — breadcrumb, legal: quieter than body
     3 link    — in main content: must out-shout body copy
     ⚠ Role 3 is Fetch by explicit brand decision and is BELOW the AAA bar: Fetch on Paper is
     2.59:1 (Fetch-strong only 3.25:1) — no orange can pass at body size on cream. It is carried as
     accepted debt, exactly like .eyebrow. Swap this ONE line to var(--forest-deep) for 10.9:1. */
  --color-link: var(--fetch-orange);
  /* Role-2 links (breadcrumb, legal, ©) are DELIBERATELY below AA — explicit brand call. The
     binding constraint is not the AA number, it is "quieter than the text in its own area": those
     areas are already muted, so a role-2 link matching --color-text-muted read as plain text, not
     a link. taupe-500 sits a real step under it in BOTH themes with one primitive —
     3.89:1 on Paper, 4.38:1 on the night page (muted itself is 7.56 / 10.06, body ink 14.63). */
  --color-link-muted: var(--taupe-500);

  /* — Spacing & shape (rem; >=12px are fluid clamp) —
   Fluid range 375px→2560px (raised from 375→1440 on 2026-07-23). min+mid kept
   identical to the old 375→1440 curve so every value at <=1440 is byte-identical;
   only the max cap was raised so tokens keep growing 1440→2560 instead of freezing.
   Pairs with full-bleed landing layout + content cap at 2560. */
  --space-4: 0.2rem;
  --space-8: 0.4rem;
  --space-12: clamp(0.4rem, 0.3296rem + 0.38vw, 0.8rem);
  --space-16: clamp(0.6rem, 0.5296rem + 0.38vw, 1rem);
  --space-20: clamp(0.8rem, 0.7296rem + 0.38vw, 1.2rem);
  --space-24: clamp(1rem, 0.9296rem + 0.38vw, 1.4rem);
  --space-32: clamp(1.2rem, 1.0592rem + 0.75vw, 2rem);
  --space-40: clamp(1.4rem, 1.1888rem + 1.13vw, 2.6rem);
  --space-48: clamp(1.6rem, 1.3184rem + 1.5vw, 3.2rem);
  --space-64: clamp(2rem, 1.5776rem + 2.25vw, 4.4rem);
  --space-80: clamp(2.4rem, 1.8368rem + 3vw, 5.6rem);
  --space-96: clamp(2.8rem, 2.096rem + 3.76vw, 7rem);
  /* Layout — the content cap and gutter, so a container is never a magic number.
     Landing = full-bleed bands with content capped here; app surfaces use --container-max-app. */
  --container-max: 2560px;
  --container-max-app: 1440px;
  --container-gutter: clamp(20px, 5vw, 120px);
  --radius-sm: 0.4rem;
  --radius-md: 0.6rem;
  --radius-lg: 1rem;
  --radius-xl: 1.6rem;
  --radius-pill: 9999px;
  --border-thin: 1px;
  --border-medium: 2px;
  --border-bold: 4px;

  /* — Typography (fluid clamp; families swappable) — */
  --font-family-display: "Fredoka", system-ui, sans-serif;
  --font-family-body: "Rethink Sans", system-ui, sans-serif;
  --font-size-display: clamp(2rem, 0.4507rem + 8.2629vw, 11rem);
  --line-height-display: clamp(2.2rem, 0.5803rem + 8.6385vw, 11.6rem);
  --font-size-h1: clamp(1.8rem, 0.7437rem + 5.6338vw, 8rem);
  --line-height-h1: clamp(2rem, 0.8732rem + 6.0094vw, 8.6rem);
  --font-size-h2: clamp(1.6rem, 0.8958rem + 3.7559vw, 5.6rem);
  --line-height-h2: clamp(1.8rem, 1.1135rem + 3.6613vw, 5.8rem);
  --font-size-h3: clamp(1.4rem, 0.907rem + 2.6291vw, 4.2rem);
  --line-height-h3: clamp(1.6rem, 1.107rem + 2.6291vw, 4.4rem);
  --font-size-h4: clamp(1.2rem, 0.9183rem + 1.5023vw, 2.8rem);
  --line-height-h4: clamp(1.6rem, 1.3597rem + 1.2815vw, 3rem);
  /* Letter-spacing (tracking) — negative on headings, tightening as size grows (matches Figma's
     existing text-style percent values; was never synced to code until 2026-07-22). Body/Lead/
     Strong/Small/Label carry no tracking. */
  --letter-spacing-display: -0.03em;
  --letter-spacing-h1: -0.02em;
  --letter-spacing-h2: -0.01em;
  --letter-spacing-h3: -0.005em;
  --letter-spacing-h4: 0em;
  --font-size-lead: clamp(1rem, 0.8944rem + 0.5634vw, 1.6rem);
  --line-height-lead: clamp(1.4rem, 1.2063rem + 1.0329vw, 2.6rem);
  /* Body/SemiBold — raised 2026-07-22: 20→24 fluid (was 16→20), SemiBold (see body{} rule).
     Now numerically == Lead; Body/Strong shares these same vars (stays Bold for emphasis). */
  --font-size-body: clamp(1rem, 0.8944rem + 0.5634vw, 1.6rem);
  --line-height-body: clamp(1.4rem, 1.2063rem + 1.0329vw, 2.6rem);
  /* — Fine print — THE ONLY sanctioned step below body (R1). Strict allow-list, see prompt.md.
     Reference: gethapply.com at 1280px — their body/nav/footer-nav is ONE size (14.2px) and only
     the legal row (Privacy / Terms / All Rights Reserved) steps down, to 12.4px = 0.875x body.
     Ours is body − 4px at EVERY viewport: same vw coefficient as body (0.5634) and the same cap
     point (~2505px), so the −4px offset holds all the way across. Ratios 0.80 / 0.85 / 0.875. */
  --font-size-fine: clamp(0.8rem, 0.6944rem + 0.5634vw, 1.4rem);    /* 16 → 22 → 28 */
  --line-height-fine: clamp(1.1rem, 0.9592rem + 0.7512vw, 1.9rem);  /* 22 → 30 → 38 */
  /* DEPRECATED by R1 (2026-07-28) — below the body floor, must not render on screen.
     Kept only so legacy CSS still parses while the migration runs; do NOT use in new work. */
  --font-size-small: 0.8rem;
  --line-height-small: 1.2rem;
  --font-size-label: 0.6rem;
  --line-height-label: 0.8rem;
  /* Component-scoped: Button "M" used to alias --font-size-body (16→20) for its size rung.
     Decoupled 2026-07-22 so Button sizing stays independent of the Body text-role change above
     (S/M/L must stay 3 distinct sizes: 16/20/24 — M colliding with L at 20→24 would break that). */
  --font-size-btn-m: clamp(0.8rem, 0.7296rem + 0.38vw, 1.2rem); /* deprecated alias of --font-size-control-s */
  /* — Component/control font scale — fluid, M = body (the reading size). Every SIZED component
     (Button, Text field…) maps its S/M/L rungs to these; single-size chips (Badge/Label) use S.
     4px-grid at the anchors; all grow with the viewport like the rest of the system. */
  /* R1: nothing below body, so S and M BOTH read at body. Only L goes above it. S vs M is a
     padding difference, not a type difference (R2). Kept as named aliases so component CSS
     that says --font-size-control-s keeps working and the intent stays readable. */
  --font-size-control-s: var(--font-size-body);                       /* 20 → 26 → 32  (= body) */
  --font-size-control-m: var(--font-size-body);                       /* 20 → 26 → 32  (= body) */
  --font-size-control-l: clamp(1.2rem, 1.0627rem + 0.7323vw, 2rem);   /* 24 → 32 → 40 */
  /* — Control HEIGHT ladder (2026-07-28) — the single source of truth for how tall a control is.
     Every interactive control (Button, Text field, Select, Icon Button) sets `height` from this
     ladder instead of hugging its own font+padding, so a Button, an input and a round Icon Button
     of the same rung are ALWAYS pixel-identical and line up in a row.
     Derived from the Figma Button (`121:110`): height = text line-box (Rethink Sans auto-LH 1.3)
     + 2× the rung's vertical padding, stroke INSIDE (so the 4px sticker border does not add
     height — pair these with `box-sizing:border-box`).
     Anchors 375 → 1440 → 2560. The ladder interlocks: S@1440 = M@375, S@2560 = L@375,
     M@2560 = L@1440. Desktop rungs 58/74/90 match Figma exactly. */
  --control-h-s: clamp(2.1rem, 1.8183rem + 1.5023vw, 3.7rem);   /* 42 → 58 → 74   (= M − 16) */
  --control-h-m: clamp(2.9rem, 2.6183rem + 1.5023vw, 4.5rem);   /* 58 → 74 → 90 */
  --control-h-l: clamp(3.6rem, 3.2831rem + 1.6901vw, 5.4rem);   /* 72 → 90 → 108 */
  /* Horizontal inset per rung — TWO scales, because the two control shapes need different insets.
     A Button HUGS its label, so it needs a generous side inset to read as a chunky pill/rect.
     A field is FULL-WIDTH, so the same inset just makes typed text look indented; it takes a
     SQUARE inset instead — literally the same token that sets the rung's vertical padding (and
     therefore its height). Both stay on the 4px spacing scale; neither invents a number. */
  --control-pad-x-s: var(--space-32);   /* Button / Icon-adjacent, hugging controls */
  --control-pad-x-m: var(--space-40);
  --control-pad-x-l: var(--space-48);
  --field-pad-x-s: var(--space-12);     /* Text field / Text area / Select — square inset */
  --field-pad-x-m: var(--space-20);
  --field-pad-x-l: var(--space-24);

  /* — Motion — */
  --duration-fast: 120ms;
  --duration-base: 220ms;
  --duration-slow: 360ms;
  --duration-page: 500ms;
  --ease-standard: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-emphasized: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  /* Scroll reveal is its own tempo — far slower than any control interaction. Matches the
     landing's tuned value; --duration-slow (360ms) was far too quick for a whole section. */
  /* The flip window's line-height. MUST contain the font's whole box, not just its ink, or
     overflow:hidden shears descenders (the "p" in "Watch a recap"). Measured for Rethink Sans
     ExtraBold: ink needs only 0.96 but the FONT BOX needs 1.308 — hence 1.35, with slack.
     Safe to raise: the control's height is a fixed token, so a taller label box never moves it. */
  --line-height-flip: 1.35;
  --duration-reveal: 1300ms;
  --reveal-distance: 2.5rem;
  --reveal-stagger: 80ms;

  /* — Elevation — hard ink offset + soft ambient (the Elevation/Card effect style) — */
  --elevation-card: 0 2px 0 0 var(--color-border), 0 6px 16px -6px var(--shadow-ambient-light);
}

/* Dark mode (color overrides only) — border flips to cream so outlines stay visible */
:root[data-theme="dark"]{
  --color-bg: var(--ink-950);
  --color-surface: var(--ink-850);
  --color-text: var(--cream-paper);
  --color-text-muted: var(--taupe-300);
  --color-text-on-primary: var(--ink-black);
  --color-text-on-dark: var(--cream-paper);
  --color-primary: var(--fetch-orange);
  --color-primary-hover: var(--fetch-strong);
  /* Secondary stays Forest-family in dark so cream text keeps AAA (Park green gave only 2.9:1). */
  --color-secondary: var(--forest-deep);    /* cream 11.3:1 */
  --color-secondary-hover: var(--forest-light); /* lighter forest for hover-in-dark; cream 7.9:1 */
  --color-accent: var(--sunbeam-yellow);
  --color-success: var(--park-bright);
  --color-border: var(--cream-pale);
  --color-border-subtle: var(--line-dark);
  --color-focus: var(--sky-blue);
  --color-danger: var(--red-danger);
  --color-link: var(--fetch-orange);
  --color-link-muted: var(--taupe-500);   /* dark: cream page 8.1:1, dark surface 7.2:1 */
  --color-fetch-soft: var(--fetch-soft-dark);   /* cream 13.1:1 */
  --color-park-soft:  var(--park-soft-dark);  /* cream 11.7:1 */
  --color-sun-soft:   var(--sun-soft-dark);   /* cream 12.0:1 */
  --color-danger-soft: var(--danger-soft-dark); /* cream 12.6:1 */
  --color-info-soft:   var(--info-soft-dark);   /* cream 12.3:1 */
  --elevation-card: 0 2px 0 0 var(--color-border), 0 10px 24px -10px var(--shadow-ambient-dark);
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --color-bg: var(--ink-950);
    --color-surface: var(--ink-850);
    --color-text: var(--cream-paper);
    --color-text-muted: var(--taupe-300);
    --color-text-on-primary: var(--ink-black);
    --color-text-on-dark: var(--cream-paper);
    --color-primary: var(--fetch-orange);
    --color-primary-hover: var(--fetch-strong);
    /* Secondary stays Forest-family in dark so cream text keeps AAA (Park green gave only 2.9:1). */
    --color-secondary: var(--forest-deep);        /* cream 11.3:1 */
    --color-secondary-hover: var(--forest-light); /* lighter forest for hover-in-dark; cream 7.9:1 */
    --color-accent: var(--sunbeam-yellow);
    --color-success: var(--park-bright);
    --color-border: var(--cream-pale);
    --color-border-subtle: var(--line-dark);
    --color-focus: var(--sky-blue);
    --color-danger: var(--red-danger);
    --color-link: var(--fetch-orange);
    --color-link-muted: var(--taupe-500);
    --color-fetch-soft: var(--fetch-soft-dark);   /* cream 13.1:1 */
    --color-park-soft:  var(--park-soft-dark);    /* cream 11.7:1 */
    --color-sun-soft:   var(--sun-soft-dark);     /* cream 12.0:1 */
    --color-danger-soft: var(--danger-soft-dark); /* cream 12.6:1 */
    --color-info-soft:   var(--info-soft-dark);   /* cream 12.3:1 */
    --elevation-card: 0 2px 0 0 var(--color-border), 0 10px 24px -10px var(--shadow-ambient-dark);
}
}
