/* ---------------------------------------------------------------------------
   Slip Tracker website tokens.

   Every colour, size, radius, and duration below is read out of the iOS app's
   own token modules in apps/budget-tracker/app/theme/v2/. The mapping, and the
   two deliberate web-only divergences, are recorded in
   docs/landing/design-tokens.md. Do not invent a value here.

   The governing rule from theme/v2/palette.ts: colour is DATA. A hue appears
   if and only if it names a category or a state. There is no decorative colour.
   --------------------------------------------------------------------------- */

/* Faces are the same TTFs the app loads, subset to woff2 and served from this
   origin. Never a font CDN: a product whose claim is that records stay on the
   device must not make its own marketing page disclose the visitor's IP. */

@font-face {
  font-family: "Hanken Grotesk";
  src: url("../assets/fonts/hanken-grotesk-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../assets/fonts/hanken-grotesk-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("../assets/fonts/hanken-grotesk-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans Thai";
  src: url("../assets/fonts/plex-sans-thai-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans Thai";
  src: url("../assets/fonts/plex-sans-thai-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans Thai";
  src: url("../assets/fonts/plex-sans-thai-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../assets/fonts/plex-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light dark;

  /* -- colour, light (lightPrimitivesV2) ---------------------------------- */
  --canvas: #f9f6f2;
  --paper: #ffffff;
  --inset: #f3f0e9;
  --ink: #211e18;
  --text-secondary: #67635c;
  /* Footnote tone. ~3.1:1 on --paper, below AA on --canvas, so it is a
     card-surface tone ONLY. Never place it on the page background. */
  --text-muted: #95928b;
  --hairline: #e7e2da;
  --accent: #2d63b7;
  --accent-pressed: #184ea1;
  --accent-tint: #e7f1ff;
  --on-accent: #fcfaf6;
  --link: #2d63b7;
  /* Hover must never REDUCE contrast. In light that means going darker; in
     dark it means going lighter. One token, two directions. */
  --link-hover: #184ea1;
  /* Privacy is deliberately chromaless. Keeping it hueless is what stops a
     factual on-device mark from looking tappable. */
  --privacy-mark: #6d6861;
  --privacy-ink: #56524b;
  --privacy-tint: #e9e6e0;

  /* Category identity. These are the ONLY hues on the site besides the accent,
     and they appear only where a real app category is named in a figure. That
     is the whole rule: a hue names a category or a state, or it is absent. */
  --cat-food: #bf696a;
  --cat-grocery: #69954f;
  --cat-transport: #009a9b;
  --cat-bills: #c18434;
  --cat-neutral: #8d8579;
  --on-category: #fcfaf6;

  /* -- type --------------------------------------------------------------- */
  /* Hanken Grotesk has NO Thai coverage, so IBM Plex Sans Thai follows it in
     the display stack. Per-glyph fallback then sets a Latin heading in Hanken
     and a Thai heading in Plex Thai with no :lang() switching. */
  --font-display: "Hanken Grotesk", "IBM Plex Sans Thai", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-ui: "IBM Plex Sans Thai", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --fs-hero: clamp(2.125rem, 1.55rem + 2.6vw, 3.25rem);
  --fs-section: clamp(1.5rem, 1.25rem + 1.1vw, 2rem);
  --fs-subsection: 1.3125rem;
  --fs-card-title: 1.0625rem;
  --fs-body-lg: 1.1875rem;
  --fs-body: 1.0625rem;
  --fs-legal: 1.125rem;
  --fs-sub: 0.9375rem;
  --fs-caption: 0.875rem;
  --fs-eyebrow: 0.8125rem;
  --fs-mono: 0.9375rem;

  --lh-tight: 1.15;
  --lh-heading: 1.25;
  --lh-body: 1.65;
  --lh-legal: 1.75;

  /* -- spacing (rhythmV2: a relationship, never a magnitude) --------------- */
  --space-tight: 4px;
  --space-related: 8px;
  --space-label: 12px;
  --space-group: 16px;
  --space-section: 24px;
  --space-page: 32px;
  --gutter: 20px;

  /* web only: a desktop page has vertical distances a phone screen does not */
  --space-block: clamp(32px, 4.4vw, 68px);
  --space-block-sm: clamp(24px, 2.8vw, 40px);
  --measure: 68ch;
  --measure-narrow: 62ch;
  --container: 74rem;

  /* -- surfaces for the dark chapters -------------------------------------
     `premiumSurface` and its text pair, straight out of the app's palette. The
     app uses this dark surface to mark what Premium unlocks; the site uses it to
     break the page into chapters so the scroll is not one flat run. */
  --dark: #182230;
  --dark-raised: #232c3e;
  --dark-hairline: #33405a;
  --on-dark: #eaeef6;
  --on-dark-secondary: #a8b4c8;
  --brass: #c89e3a;

  /* -- elevation -----------------------------------------------------------
     The app sanctions exactly ONE shadow (level1, y6 blur18 alpha .10) and it
     belongs to popovers. The device frame is a web-only object that has to read
     as a physical thing sitting on the page, so it gets a real cast shadow.
     That is a deliberate exception under the owner's 2026-08-22 ruling, and it
     is the ONLY place on this site a shadow larger than level1 appears. */
  --elev-1: 0 6px 18px rgba(21, 17, 11, 0.1);
  --elev-device: 0 2px 6px rgba(21, 17, 11, 0.06), 0 18px 40px rgba(21, 17, 11, 0.14),
    0 60px 90px rgba(21, 17, 11, 0.1);
  --elev-float: 0 2px 6px rgba(21, 17, 11, 0.05), 0 14px 30px rgba(21, 17, 11, 0.12);

  /* -- shape (shapeV2) ---------------------------------------------------- */
  --radius-chip: 6px;
  --radius-tile: 8px;
  --radius-card: 10px;
  --radius-card-lg: 14px;
  --radius-viz: 3px;
  --stroke-hairline: 1px;
  --tap-min: 44px;
  --cta-h: 52px;
  /* The phone. Matches the corner radius of the hardware it stands in for. */
  --device-radius: 44px;
  --device-bezel: 9px;

  /* -- motion (motionV2) -------------------------------------------------- */
  --dur-quick: 150ms;
  --dur-standard: 220ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --press-scale: 0.98;
}

@media (min-width: 40rem) {
  :root {
    --gutter: 24px;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    /* darkPrimitivesV2 */
    --canvas: #12100d;
    --paper: #2b2823;
    --inset: #3b3731;
    --ink: #edebe7;
    --text-secondary: #adaaa5;
    --text-muted: #898681;
    /* Divergence, recorded in design-tokens.md: the app's dark hairline is
       #070604 because a native card stack needs its rule BELOW the surface
       (R25). A flat web page needs a rule that is actually visible, so this
       steps up to the `inset` value instead. */
    --hairline: #3b3731;
    --accent: #3f6cad;
    --accent-pressed: #2e5794;
    --accent-tint: #1c2e49;
    --on-accent: #fcfaf6;
    --link: #8fb9f7;
    --link-hover: #b8d3fb;
    --privacy-mark: #9c9890;
    --privacy-ink: #c2bdb5;
    --privacy-tint: #302d28;

    --cat-food: #bc5659;
    --cat-grocery: #4c8d3d;
    --cat-transport: #058b96;
    --cat-bills: #b66022;
    --cat-neutral: #7e7a73;
    --on-category: #fcfaf6;

    /* The dark chapter has to stay darker than the dark canvas, or the two
       merge and the chapter break disappears. */
    --dark: #0b0f16;
    --dark-raised: #161d29;
    --dark-hairline: #2a3546;

    --elev-1: 0 6px 18px rgba(0, 0, 0, 0.5);
    --elev-device: 0 2px 6px rgba(0, 0, 0, 0.4), 0 18px 40px rgba(0, 0, 0, 0.55),
      0 60px 90px rgba(0, 0, 0, 0.4);
    --elev-float: 0 2px 6px rgba(0, 0, 0, 0.4), 0 14px 30px rgba(0, 0, 0, 0.5);
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-quick: 0.01ms;
    --dur-standard: 0.01ms;
    --press-scale: 1;
  }
}
