/* Self-hosted variable fonts. Files in /static/fonts/. */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/static/fonts/fraunces-vf.woff2') format('woff2');
  font-feature-settings: 'kern' 1, 'liga' 1;
}

@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/static/fonts/outfit-vf.woff2') format('woff2');
}

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

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

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-600.woff2') format('woff2');
}

/* ==============================================
   INTERACTION PATTERN SPLIT (slice B Drift (g), bible 4.2 / 7.4.3)

   Two patterns coexist by design, not by accident:

   1. .state-layer utility (globals.css). Canonical for primary
      interactive surfaces -- buttons, links, sidebar rail items.
      Animates a ::after opacity overlay on hover/active; no
      hue change. Applied wherever interaction reads as "this
      surface is reactive" without changing the surface's tint.

   2. --md-primary-hover token. Reserved for accent micro-surfaces
      where the hue shifts -- the saved-heart icon at save-heart.css:51
      is the only canonical use among production component CSS.
      Hover-token use on primary-button surfaces is a drift regression;
      migrate those to .state-layer. (--md-primary-action remains
      in use for accent text-color shifts on links; the state-layer
      overlay handles button :active.)
   ============================================== */

:root {
  color-scheme: light;

  /* ==============================================
     COLOR -- White + Fiery Tomato
     Surface is always cool zinc / white.
     Tomato is the single accent -- used sparingly.
     ============================================== */

  /* Foreground */
  --md-on-surface: #18181b;
  --md-on-surface-variant: #71717a;

  /* Borders */
  --md-border: #d4d4d8;
  --md-border-muted: #e4e4e7;
  --md-border-strong: #a1a1aa;

  /* Zinc scale */
  --md-zinc-50: #fafafa;
  --md-zinc-100: #f4f4f5;
  --md-zinc-200: #e4e4e7;
  --md-zinc-300: #d4d4d8;
  --md-zinc-400: #a1a1aa;
  --md-zinc-500: #71717a;
  --md-zinc-600: #52525b;
  --md-zinc-700: #3f3f46;
  --md-zinc-800: #27272a;
  --md-zinc-900: #18181b;
  --md-zinc-950: #09090b;

  /* Primary -- The Tomato.
     --md-primary-hover is reserved for save-heart's accent micro-surface
     only; see INTERACTION PATTERN SPLIT comment at the top of this file. */
  --md-primary: #c94418;
  --md-on-primary: #ffffff;
  --md-primary-hover: #b53d15;
  --md-primary-action: #9c3412;
  --md-primary-muted: #fccbb7;
  --md-primary-text: #9c4324; /* WCAG AA on #fafafa */

  /* Mascot stem */
  --md-stem: #268c32;

  /* Tag presets — bg + foreground pairs for recipe metadata.
     The "warm" pair was deleted in slice B Drift (b): its bg value (#fef2ec)
     collided with two other tokens at the same hex, and all three now
     resolve to --md-primary-container; the warm foreground (#9c3412) is
     captured by --md-on-primary-container. */
  --md-tag-green: #e0f0e6;
  --md-tag-green-foreground: #1c5c35;
  --md-tag-blue: #e0ecf8;
  --md-tag-blue-foreground: #1a4971;
  --md-tag-neutral: #f0f0f0;
  --md-tag-neutral-foreground: #3f3f46;

  /* Semantic */
  --md-success: #16a34a;
  --md-success-soft: #f0fdf4;
  --md-warning: #ca8a04;
  --md-warning-soft: #fefce8;
  --md-error: #dc2626;
  --md-error-soft: #fef2f2;

  /* MD3-E surface scale — 4 canonical tiers (bible 3.3).
   * MD3 names five tiers (lowest / low / _ / high / highest); shy-tomato
   * stays at 4 active tiers per slice B Decision 2. The lowest and highest
   * tiers are deliberately skipped: the four-step ramp gives enough surface
   * contrast at our viewport scale, and adding a fifth/sixth tier here
   * without a UI need is invention, not consolidation. */
  --md-surface: #fafafa;
  --md-surface-container-low: #ffffff;
  --md-surface-container: #f4f4f5;
  --md-surface-container-high: #e4e4e7;

  /* MD3-E primary container -- bible 3.3 consolidation target for the three
     pre-rename tokens that all held #fef2ec (background-focus, primary-soft,
     tag-warm). One canonical name, three former semantic intents now
     resolved at the callsite via the surrounding component. */
  --md-primary-container: #fef2ec;
  --md-on-primary-container: #6b2000;

  --md-outline: #a1a1aa;

  /* Overlay */
  --md-overlay: rgba(0, 0, 0, 0.5);
  --md-overlay-light: rgba(250, 250, 250, 0.95);

  /* Focus ring */
  --md-ring: var(--md-primary);
  /* 3px primary halo at 50% opacity, paired with a border-color change. */
  --focus-ring: 0 0 0 3px color-mix(in oklch, var(--md-primary) 50%, transparent);

  /* ==============================================
     TYPOGRAPHY
     ============================================== */

  --font-heading: 'Fraunces', Georgia, serif;
  --font-body: 'Outfit', system-ui, sans-serif;
  --font-sans: var(--font-body);
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* Scale */
  --text-xs: 0.75rem;    /* 12 */
  --text-sm: 0.875rem;   /* 14 */
  --text-base: 1rem;     /* 16 */
  --text-lg: 1.125rem;   /* 18 */
  --text-xl: 1.25rem;    /* 20 */
  --text-2xl: 1.5rem;    /* 24 */
  --text-3xl: 1.875rem;  /* 30 */
  --text-4xl: 2.5rem;    /* 40 */
  --text-5xl: 3.5rem;    /* 56 */

  /* Line height */
  --leading-tight: 1.1;
  --leading-snug: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;

  /* ==============================================
     SPACE
     ============================================== */

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 32px;
  /* --space-9 / --space-10 extend the 4px scale past 32px so fixed
     40/48px gaps no longer go raw. The clamps below stay for fluid
     page/section gutters; these two are the discrete large steps. */
  --space-9: 40px;
  --space-10: 48px;

  --space-page: clamp(1rem, 5vw, 3rem);
  --space-section: clamp(3rem, 8vw, 6rem);

  /* ==============================================
     LAYOUT — Chrome dimensions shared across the AppShell
     ============================================== */

  --sidebar-width: 112px;
  --tab-bar-height: 56px;

  /* Content-column width tiers. Every top-level surface centers its
     content on one of these three caps via the .page-shell utility
     (layout.css) — wide grid / editorial column / form. They replace
     the six ad-hoc per-surface width literals the spike catalogued. */
  --content-max: 1280px;     /* wide grid — Explore, author hub, plan */
  --content-narrow: 768px;   /* editorial — recipe detail */
  --content-form: 512px;     /* forms — auth, account, paywall, status */

  /* Canonical breakpoint set — a DOCUMENTED CANON, not live tokens.
     CSS custom properties cannot be referenced inside @media queries,
     so every production @media uses the raw literal that matches one
     of these values; the ~14 scattered breakpoints reconcile down to
     this set. The PR6 grep-guard enforces that @media literals match
     these declared values — the variables exist so the canon has one
     authoritative home and the guard has something to check against. */
  --bp-sm: 640px;
  --bp-md: 1024px;
  --bp-lg: 1280px;

  /* Control-height tiers. --control-h is the iOS 44px touch-target
     minimum (the canonical primary-action height); --control-h-sm is
     the smaller-control height. */
  --control-h: 44px;
  --control-h-sm: 36px;

  /* ==============================================
     RADIUS
     ============================================== */

  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius: 10px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 9999px;

  /* ==============================================
     SHADOW — Neutral, subtle
     ============================================== */

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
  --shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.03);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.08), 0 4px 8px rgba(0, 0, 0, 0.03);
  --shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.1), 0 32px 64px rgba(0, 0, 0, 0.08);

  /* ==============================================
     MOTION — M3 Motion Physics System (Expressive scheme)
     https://m3.material.io/styles/motion/
     ============================================== */

  /* Springs — paired curve + duration. Six tokens covering the
     {fast, default, slow} × {spatial, effects} matrix.

     Spatial: x/y, rotation, size, rounded corners → overshoots, bounces.
              Use for movement, transforms, and shape morphs.
     Effects: opacity, color → eases without overshoot.
              Use for fades and color transitions.

     Speed:   fast = small components (switch, button)
              default = mid-area (bottom sheet, navigation rail)
              slow = full-screen / large-area animations */
  --motion-spring-fast-spatial: cubic-bezier(0.42, 1.67, 0.21, 0.9);
  --motion-spring-fast-spatial-duration: 350ms;
  --motion-spring-default-spatial: cubic-bezier(0.38, 1.21, 0.22, 1);
  --motion-spring-default-spatial-duration: 500ms;
  --motion-spring-slow-spatial: cubic-bezier(0.39, 1.29, 0.35, 0.98);
  --motion-spring-slow-spatial-duration: 650ms;
  --motion-spring-fast-effects: cubic-bezier(0.31, 0.94, 0.34, 1);
  --motion-spring-fast-effects-duration: 150ms;
  --motion-spring-default-effects: cubic-bezier(0.34, 0.8, 0.34, 1);
  --motion-spring-default-effects-duration: 200ms;
  --motion-spring-slow-effects: cubic-bezier(0.34, 0.88, 0.34, 1);
  --motion-spring-slow-effects-duration: 300ms;

  /* Legacy emphasized easings — still used by M3 transition patterns
     (container transform, enter/exit, etc.) Pair these with the duration
     scale (--duration-*) below. */
  --motion-easing-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --motion-easing-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15);
  --motion-easing-standard: cubic-bezier(0.2, 0, 0, 1);
  --motion-easing-standard-decelerate: cubic-bezier(0, 0, 0, 1);
  --motion-easing-standard-accelerate: cubic-bezier(0.3, 0, 1, 1);

  /* Duration scale — for transitions paired with emphasized easings. */
  --duration-short-2: 100ms;
  --duration-short-3: 150ms;
  --duration-short-4: 200ms;
  --duration-medium-1: 250ms;
  --duration-medium-2: 300ms;
  --duration-medium-3: 350ms;
  --duration-medium-4: 400ms;
  --duration-long-2: 500ms;
  --duration-long-4: 600ms;

  /* Named animations -- each picks a canonical --motion-spring-* token
     per bible 7.x (slice B Drift (c)). The legacy --ease-md3-* and
     --duration-{instant,fast,default,slow,slower} aliases are retired;
     the M3 named --duration-{short,medium,long} scale above is kept
     for transition patterns paired with emphasized easings.

     - fade-in: opacity fade, 400ms -- slow-effects (no overshoot;
       chapter 7.4.3 reasoning: opacity always goes effects).
     - fade-up: opacity + translateY, 500ms -- default-spatial (mid-
       area position change reading as alive; chapter 7.2 default-
       spatial duration).
     - scale-in: opacity + scale, 300ms -- fast-spatial (small-area
       spring-y scale; chapter 7.2 small-area decision).
     - check-pop: scale bounce, 300ms -- fast-spatial (chapter 7.3.4
       names this explicitly as fast-spatial). */
  --animate-fade-in: fade-in 400ms var(--motion-spring-slow-effects);
  --animate-fade-up: fade-up 500ms var(--motion-spring-default-spatial);
  --animate-scale-in: scale-in 300ms var(--motion-spring-fast-spatial);
  --animate-check-pop: check-pop 300ms var(--motion-spring-fast-spatial);
  --animate-shimmer: shimmer 2s linear infinite;
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fade-up {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes scale-in {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes check-pop {
  0%   { transform: scale(0); opacity: 0; }
  50%  { transform: scale(1.2); }
  100% { transform: scale(1); opacity: 1; }
}

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* ==============================================
   DARK THEME
   Deep zinc surfaces + slightly brightened tomato.

   Surface-tier resolution (bible 3.3, slice B Drift (b)): the four MD3-E
   tiers (--md-surface, --md-surface-container-{low,_,high}) hold four
   pairwise-distinct hex values on dark. Pre-rename, two production
   surface tokens collapsed onto a single canonical name on dark; the
   new ramp picks #1f1f23 as the intermediate tier so all four are
   visually distinct. MD3 dark convention: higher container elevation
   reads as lighter (each step brightens against the base surface).
   ============================================== */

[data-theme='dark'] {
  color-scheme: dark;

  --md-on-surface: #fafafa;
  --md-on-surface-variant: #a1a1aa;

  --md-border: #3f3f46;
  --md-border-muted: #27272a;
  --md-border-strong: #52525b;

  /* Tomato brightens slightly on dark to preserve perceived saturation.
     Hover + active progress *darker* (same direction as light) so interaction
     intensity reads consistently across themes. */
  --md-primary: #e8552a;
  --md-on-primary: #ffffff;
  --md-primary-hover: #c94418;
  --md-primary-action: #9c3412;
  --md-primary-muted: #6b2a0f;
  --md-primary-text: #ff8862; /* WCAG AA on #0a0a0a */

  --md-stem: #4ade80;

  /* Tag presets -- dark variants: low-chroma fills on near-black.
     Warm pair retired in slice B Drift (b); see light-theme comment. */
  --md-tag-green: #0f2a1a;
  --md-tag-green-foreground: #86efac;
  --md-tag-blue: #0f1e30;
  --md-tag-blue-foreground: #93c5fd;
  --md-tag-neutral: #27272a;
  --md-tag-neutral-foreground: #d4d4d8;

  --md-success: #22c55e;
  --md-success-soft: #0f2a1a;
  --md-warning: #eab308;
  --md-warning-soft: #2a2208;
  --md-error: #f87171;
  --md-error-soft: #2a0f0f;

  /* MD3-E surface scale on dark -- four pairwise-distinct tiers (Drift (b)). */
  --md-surface: #0a0a0a;
  --md-surface-container-low: #18181b;
  --md-surface-container: #1f1f23;
  --md-surface-container-high: #27272a;

  --md-primary-container: #2a1308;
  --md-on-primary-container: #ffb088;

  --md-outline: #52525b;

  --md-overlay: rgba(0, 0, 0, 0.7);
  --md-overlay-light: rgba(10, 10, 10, 0.95);

  --md-ring: var(--md-primary);

  /* Shadows are muted on dark — rely on surface contrast instead */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
  --shadow: 0 2px 6px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.3);
  --shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.6), 0 32px 64px rgba(0, 0, 0, 0.4);
}
