/*
 * Single source of truth for the site's palette and type scale. Swapping
 * the whole look later is a change to this file only — nothing else should
 * hardcode a color or font size.
 */

/* Self-hosted rather than linked from Google Fonts: the production CSP is
   `font-src 'self'` (src/lib/security-headers.ts), so a CDN link would work
   in dev and silently fall back to the system stack in production. Both
   faces are SIL Open Font License, latin subset only, variable — two files,
   ~115 KB total, which buys the whole weight range without a request per
   weight. `swap` so text is never invisible while they load (objective #1
   in CLAUDE.md is page speed). */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/fraunces-latin-var.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/inter-latin-var.woff2") format("woff2");
}

:root {
  /* Palette — pastel neutral base, "fresh/healthy" greens for accent.
     Deliberately a saturated, crisp green rather than a muted/earthy one —
     that saturation is what reads as fresh produce/health to people (the
     same cue grocery and salad packaging leans on), where the previous
     sage/terracotta read more "artisanal" than "healthy". */
  --color-bg: #f7f5f0;
  --color-bg-raised: #ffffff;
  --color-text: #2b2b26;
  --color-text-muted: #6b6b62;
  --color-border: #e4e0d6;
  --color-accent: #1f7a43;
  --color-accent-strong: #175c34;
  --color-accent-contrast: #ffffff;
  /* Crisp "sprout" green — secondary highlight. Used for the
     100%-plastic-free product badge below (the McDonald's-sticker-style
     positive signal this was earmarked for). */
  --color-accent-2: #8fbf6b;

  /* Mission bar — the light-green strip above the header. A desaturated
     tint of --color-accent-2 so it reads as a quiet band behind small
     text, not a second accent competing with the buttons. */
  --color-mission-bg: #e8f2df;
  --color-mission-text: #2f5233;

  /* Product claim badges (src/components/ProductBadges.astro) — bottom-left
     chips on product cards/detail pages. Deliberately not reusing the
     category tints above; these signal a claim about the product, not its
     taxonomy, so they need their own fixed identity even where a hue is
     close to a category tint. */
  --color-badge-plastic-free: var(--color-accent-2);
  --color-badge-plastic-reduced: #c9a86a;
  --color-badge-silicone: #7c98a8;
  --color-badge-unverified: #9a958a;
  /* Dark ink, not white. All four fills above are mid-tone by design (they
     have to sit legibly on the category-tinted image panel), and white text
     on them measures 2.1–2.9:1 — below the 4.5:1 floor, and worse at the
     11px these labels are set in. The same ink on the same fills measures
     5.7–7.4:1. Any new badge colour added here needs to stay light enough
     for this to hold. */
  --color-badge-contrast: #22221e;

  /* Rating stars (src/components/Stars.astro). The filled tile is the
     accent green the rest of the site already uses for "good"; this is
     only the unfilled one. Warm grey rather than a tint of the accent, so
     an unfilled tile never reads as a faintly-good one — the gap between
     3 stars and 5 has to be obvious at card size. */
  --color-star-empty: #d5d1c6;

  /* Category tints — a small, fixed taxonomy, so explicit tokens rather
     than a hashed/generated color are clearer and stay stable. */
  --color-category-kitchen: #d9c7a3;
  --color-category-bathroom: #b9cfd6;
  --color-category-cleaning: #cdd9bd;
  --color-category-baby-kids: #e3c7c1;
  --color-category-default: #d8d4c8;

  /* Type — two faces, and every heading in the site resolves to
     --font-display (see the h1–h4 rule below), so re-branding the site is a
     one-line change here.

     Fraunces for display: a warm, slightly organic serif. The editorial
     voice is the product ("every pick comes with an honest writeup, not
     just a buy button"), and a serif is what signals *written by someone*
     — the entire affiliate-site category defaults to a geometric sans, so
     this is also the cheapest way to not look like one.

     Inter for body/UI: neutral, tall x-height, holds up at 13–14px where
     most of this site's text actually lives (prices, badges, offer rows). */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* One scale, no gaps. The previous scale ran 14 / 16 / 18 and then jumped
     straight to 36, so every heading below a section title collapsed into
     body text and the page read flat — the sizes between are what carry
     card titles, lead paragraphs and subheads. --font-size-md was already
     referenced by the admin product editor but had never been defined
     here, so it was resolving to nothing. */
  --font-size-xs: 0.8125rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-md: 1.125rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: clamp(1.75rem, 1.4rem + 1.5vw, 2.25rem);
  --font-size-2xl: clamp(2.25rem, 1.7rem + 2.4vw, 3.25rem);

  /* Display type needs tighter tracking and leading than body type at the
     same nominal size — these are the two adjustments that separate set
     type from default type. */
  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-body: 1.6;
  --tracking-tight: -0.02em;
  --tracking-wide: 0.06em;

  /* Spacing scale */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2.5rem;
  --space-6: 4rem;

  --radius-sm: 0.375rem;
  --radius: 0.5rem;
  --radius-lg: 0.875rem;
  --radius-pill: 999px;

  /* Elevation. Tinted with the warm text colour rather than pure black so
     shadows sit on the cream background without going grey//dirty. */
  --shadow-sm: 0 1px 2px rgb(43 43 38 / 6%);
  --shadow-md: 0 2px 4px rgb(43 43 38 / 5%), 0 8px 20px rgb(43 43 38 / 7%);
  --shadow-lg: 0 4px 8px rgb(43 43 38 / 6%), 0 18px 40px rgb(43 43 38 / 10%);

  /* Shared geometry for every input/button that can sit next to another
     one. Anything in a row together sets `height: var(--control-height)`
     rather than its own padding, so pairs line up exactly instead of
     nearly. */
  --control-height: 3rem;
  --control-height-sm: 2.5rem;

  --content-max-width: 72rem;
}

* {
  box-sizing: border-box;
}

html {
  /* Stop mobile browsers auto-inflating text after a reflow or an
     orientation change. Without it, Safari and Chrome on Android re-run
     their own text-inflation heuristic as blocks resize, so type can
     change size after the page has already painted — which looks like the
     text moving on its own, and is independent of any animation. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Inter's default figures are proportional; tabular figures keep prices
     and review counts from jittering as digits change. */
  font-variant-numeric: tabular-nums;
}

/* Every heading on the site, in one place. Individual components still set
   their own size — this is only about which face they're set in and how
   it's tracked, so a component never has to remember to opt in. */
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  /* Fraunces' optical-size axis: larger sizes want tighter, more contrasted
     letterforms. Set per-heading below rather than globally so small
     headings don't get display-weight thins. */
  font-optical-sizing: auto;
  text-wrap: balance;
}

h1 {
  font-variation-settings: "SOFT" 20, "WONK" 0;
}

/* Body copy reads better ragged than balanced — balance is for short
   headings, where it stops a one-word last line. */
p {
  text-wrap: pretty;
}

a {
  color: inherit;
}

/* A single visible focus treatment sitewide. Without this the browser
   default is inconsistent across the custom-styled buttons, links and
   chips, and several of them showed no ring at all. */
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

::selection {
  background: var(--color-mission-bg);
  color: var(--color-mission-text);
}

img {
  max-width: 100%;
  display: block;
}

/* Respect a user's reduced-motion setting for the hover lifts and drawer
   transitions added elsewhere. */
@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;
  }
}

/* Visually hidden, still announced. Global rather than scoped to one
   component: it is a utility, and a second copy inside a component's
   scoped <style> silently does nothing for any other component's markup —
   which is exactly the bug it caused when the homepage hero's screen-
   reader-only line rendered as visible duplicate text. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
