/* ============ Wadicos - Base ============ *
 * Cascade-layer declaration · reset · @font-face ·
 * element defaults · reduced-motion override ·
 * container · skip-link · selection.
 * ======================================== */

@layer reset, tokens, base, components, utilities, overrides;

/* ============ @font-face ============ *
 * Self-hosted woff2, font-display swap.
 * ==================================== */

@font-face {
  font-family: "Cormorant Garamond";
  src: url("/assets/fonts/cormorant-garamond-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Cormorant Garamond";
  src: url("/assets/fonts/cormorant-garamond-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

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

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

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

/* ============ Fraunces (V1 primary display) ============ *
 * Self-hosted from Google Fonts (OFL 1.1; OFL.txt sits next to
 * the woff2 files at /assets/fonts/fraunces-OFL.txt).
 *
 * Fraunces ships as a variable font; Google's static-axes API
 * delivers one woff2 per (style × subset). We declare each woff2
 * as a separate @font-face with font-weight: 400 600 covering the
 * variable range so both 400 and 600 weights resolve to the same
 * file (smaller cache footprint, single network request per
 * style+subset). Latin + latin-ext only — vietnamese is skipped
 * (Wadicos catalogue has no Vietnamese characters in either FR
 * or EN copy).
 *
 * Glyph fallback chain (declared in tokens.css as --font-display):
 *   Fraunces → Cormorant Garamond → Georgia → Times New Roman → serif
 * so any glyph Fraunces lacks falls through to Cormorant (also
 * self-hosted), and any missing from both falls to the OS serif.
 * ====================================================== */

@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-upright-latin.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  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: "Fraunces";
  src: url("/assets/fonts/fraunces-upright-latin-ext.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-italic-latin.woff2") format("woff2");
  font-weight: 400 600;
  font-style: italic;
  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: "Fraunces";
  src: url("/assets/fonts/fraunces-italic-latin-ext.woff2") format("woff2");
  font-weight: 400 600;
  font-style: italic;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============ Fraunces metric-matched fallback ============ *
 * Solves the FOUT/CLS that hits every heading on cold load: until the
 * Fraunces woff2 arrives, headings paint in a local system serif. The
 * default metrics differ slightly from Fraunces, so the swap re-flows
 * the text and shifts the layout. This synthetic family points at the
 * OS-installed Georgia (or Times) with size-adjust + ascent/descent
 * overrides tuned to match Fraunces — no network roundtrip, no shift.
 *
 * It precedes "Cormorant Garamond" in --font-display so it wins the
 * substitution before our own self-hosted Cormorant kicks in.
 * Numbers calibrated against Fraunces 400 vs. Georgia 400; the
 * remaining shift on woff2 swap measures under 0.01 CLS. */
@font-face {
  font-family: "Fraunces Fallback";
  src: local("Georgia"), local("Times New Roman"), local("Times");
  font-weight: 400 600;
  font-style: normal;
  size-adjust: 103%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Fraunces Fallback";
  src: local("Georgia Italic"), local("Times New Roman Italic"), local("Times Italic");
  font-weight: 400 600;
  font-style: italic;
  size-adjust: 103%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* ============ Reset ============ *
 * Targeted - no * { } sweep.
 * =============================== */

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

  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

  body,
  h1, h2, h3, h4, h5, h6,
  p, figure, blockquote, dl, dd, ul, ol { margin: 0; }

  ul[class],
  ol[class] { padding: 0; list-style: none; }

  img,
  picture,
  svg,
  video,
  canvas {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
  }

  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
  }

  button {
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
  }

  a { color: inherit; text-decoration: none; }

  :focus:not(:focus-visible) { outline: 0; }

  /* The HTML `hidden` attribute is semantic - it must defeat any component
     display rule (e.g. `.pill { display: inline-flex }`). Without
     !important, layer-cascade order lets component rules win. */
  [hidden] { display: none !important; }
}

/* ============ Reduced motion ============ *
 * Global override - every transition/animation
 * collapses for users who prefer reduced motion.
 * ============================================= */

/* The four !important declarations below override every motion token
   set elsewhere - token values use --dur-*; this rule must win the
   cascade on every animated element so the user's OS-level preference
   is honored regardless of specificity. */
@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;
  }
}

/* ============ Base ============ */

@layer base {
  html {
    color-scheme: dark;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
  }

  /* Native smooth scroll — gated by reduced-motion so users who opt out
     get instant scroll on anchor jumps and programmatic scrollTo. No JS
     scroll engine (Lenis, locomotive, etc.) ships on this site; native
     scroll-behavior covers anchor jumps, JS scrollTo, and basic wheel
     smoothing without fighting sticky elements or view transitions. */
  @media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
  }

  /* Anchor offset — every element with an id gets a scroll-margin so
     the sticky header doesn't cover it when jumped to via a fragment
     URL or scrollIntoView. Offset roughly matches the sticky header
     height plus a breath of air. */
  [id] {
    scroll-margin-block-start: calc(var(--space-7) + 1rem);
  }

  /* Light theme: lets form controls, scrollbars, and other
     UA-rendered chrome adopt the light palette correctly.
     The data-theme attribute is set on <html> pre-paint by
     the inline boot snippet in each page <head>. */
  html[data-theme="light"] { color-scheme: light; }

  body {
    min-block-size: 100vh;
    background-color: var(--color-bg);
    color: var(--color-fg);
    font-family: var(--font-body);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    font-weight: 400;
    overflow-x: hidden;
    /* isolation: isolate establishes a stacking context so the
       negative z-index backdrop pseudo-elements (::before, ::after)
       remain trapped between the body background and its children,
       never bleeding behind the page or above content. */
    position: relative;
    isolation: isolate;
  }

  /* ============ Global backdrop ============ *
   * Single fixed-position pseudo-element pins the
   * burgundy-on-black (or warm-ivory on light) grunge
   * texture to the viewport. The flat colour layers
   * behind the WebP so dropout regions paint a clean
   * --color-bg ground. --bg-image is theme-scoped in
   * tokens.css ({dark,light}-bg.webp); the boot script
   * in each page <head> preloads the matching variant.
   *
   * Section-level backgrounds (.hero, .section--wine,
   * .section--ember, etc.) still paint above this on the
   * surfaces they cover.
   * =============================================== */

  body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background-color: var(--color-bg);
    background-image: var(--bg-image);
    background-size: cover;
    background-position: center center;
    background-repeat: no-repeat;
    pointer-events: none;
    transition: background-color var(--dur-base) var(--ease-out);
  }

  /* ============ Element headings (V1) ============ *
   * V1 splits the heading font defaults so the new Fraunces
   * family lands where it matters (page-hero h1, plus every
   * component class that explicitly opts in via
   * `font-family: var(--font-display)`) without inheriting
   * onto h2-h6 elements whose components rely on the element
   * default and have tight column widths. The §1.5 measurement
   * during V1 verification showed that Fraunces at the same
   * point size is ~7% wider than Cormorant — the same h2 at
   * the same clamp value wraps the subscribe-card lede column
   * at 768 in Fraunces where it fit in Cormorant.
   *
   * Resolution:
   *   h1               → var(--font-display) = Fraunces
   *   h2, h3, h4, h5, h6 → var(--font-bridge)  = Cormorant
   *
   * Component classes that need Fraunces on smaller headings
   * already declare `font-family: var(--font-display)`
   * explicitly (.section__heading, .brand-card__name,
   * .legal-page__section-heading, .feature-row__title, …) —
   * they win the cascade over this base default and keep
   * their Fraunces voice. Components that don't opt in (like
   * .subscribe-card__lede h2) inherit the base bridge family
   * and preserve §1.5 width.
   *
   * Weight + tracking stay at the pre-V1 defaults (400, per-level
   * tracking + leading from tokens). V2 component overrides
   * lift weight to 600 on hero/section openers.
   *
   * Tracking + leading per level give each scale step its own
   * voice:
   *   h1 → display tracking, display leading
   *   h2 → h2 tracking, h2 leading
   *   h3/h4/h5/h6 → tight tracking, tight leading */
  h1, h2, h3, h4, h5, h6 {
    font-weight: 400;
    color: var(--color-ink);
  }
  h1 { font-family: var(--font-display); }
  h2, h3, h4, h5, h6 { font-family: var(--font-bridge); }

  h1 {
    font-size: var(--fs-hero);
    line-height: var(--lh-display);
    letter-spacing: var(--tracking-display);
  }
  h2 {
    font-size: var(--fs-display);
    line-height: var(--lh-h2);
    letter-spacing: var(--tracking-h2);
  }
  h3 {
    font-size: var(--fs-h3);
    line-height: var(--lh-tight);
    letter-spacing: -0.01em;
  }
  h4 {
    font-size: var(--fs-h4);
    line-height: var(--lh-tight);
    letter-spacing: -0.005em;
  }
  h5, h6 {
    font-size: var(--fs-h4);
    line-height: var(--lh-tight);
    letter-spacing: 0;
  }

  /* Light-theme heading accent - re-pins --color-ink on
     heading elements only, so every rule that paints a
     heading with var(--color-ink) (including the dozens
     of .section__heading / .brand-hero__name / etc. class
     overrides scattered across the component files) picks
     up the burgundy accent via the cascade. Body text
     keeps the mocha --color-ink declared on [data-theme="light"]
     in tokens.css. Token reference (var(--color-red))
     rather than a raw hex keeps colour discipline - the
     burgundy value lives once in tokens.css. */
  [data-theme="light"] h1,
  [data-theme="light"] h2,
  [data-theme="light"] h3,
  [data-theme="light"] h4,
  [data-theme="light"] h5,
  [data-theme="light"] h6 {
    --color-ink: var(--color-red);
  }

  /* Headline 2-line rule — every heading must render in at most 2
     lines, in any language, at any viewport width, WITHOUT clipping
     and WITHOUT an ellipsis. We achieve this two ways:
       1. `text-wrap: balance` — modern browsers distribute words evenly
          between the available lines, producing cleaner 2-line breaks.
       2. The `--fs-hero` and `--fs-display` clamps in tokens.css scale
          font-size down on narrow viewports so the content fits 2 lines
          naturally.
     Source headings that would still overflow at the smallest scale
     are rewritten to be shorter (editorial discipline) — never clipped. */
  h1, h2, h3, h4, h5, h6 {
    text-wrap: balance;
  }

  p { color: var(--color-ink-soft); }

  strong, b { font-weight: 600; color: var(--color-ink); }
  em, i { font-style: italic; }

  a {
    color: var(--color-ink);
    transition: color var(--dur-fast) var(--ease-out);
  }

  @media (hover: hover) {
    a:hover {  color: var(--color-red);  }
  }

  ::selection {
    background-color: var(--color-red);
    color: var(--color-ink);
  }

  :focus-visible {
    outline: 2px solid var(--color-red);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
  }

  /* Inputs reset · base */
  input,
  textarea,
  select {
    border: 1px solid var(--color-line);
    background-color: var(--color-bg-elev);
    color: var(--color-ink);
    padding-block: var(--space-3);
    padding-inline: var(--space-4);
    border-radius: var(--radius-md);
    inline-size: 100%;
  }

  /* color-ink-muted on color-bg-elev clears WCAG 1.4.3 (≥ 4.5:1 for normal
     text). The previous color-ink-faint mapping was 2.43:1 — a fail. */
  input::placeholder,
  textarea::placeholder { color: var(--color-ink-muted); }

  /* Scrollbar · webkit (decorative) - track + thumb use
     theme-aware tokens so the chrome stays coherent when
     the page switches between dark and light. */
  ::-webkit-scrollbar { inline-size: 10px; block-size: 10px; }
  ::-webkit-scrollbar-track { background-color: var(--color-scroll-track); }
  ::-webkit-scrollbar-thumb {
    background-color: var(--color-scroll-thumb);
    border-radius: var(--radius-pill);
  }
  @media (hover: hover) {
    ::-webkit-scrollbar-thumb:hover {  background-color: var(--color-red-deep);  }
  }

  /* Skip link. color: var(--color-cta-ink) matches the
     .btn--red contrast pair - cream-on-burgundy in light,
     cream-on-vivid-red in dark. Using --color-ink here
     would render mocha-on-burgundy (~1.1:1) in light mode. */
  .skip-link {
    position: absolute;
    inset-block-start: var(--space-2);
    inset-inline-start: var(--space-2);
    z-index: var(--z-toast);
    padding-block: var(--space-3);
    padding-inline: var(--space-5);
    background-color: var(--color-red);
    color: var(--color-cta-ink);
    font-weight: 500;
    border-radius: var(--radius-md);
    transform: translateY(-200%);
    transition: transform var(--dur-fast) var(--ease-out);
  }

  .skip-link:focus,
  .skip-link:focus-visible {
    transform: translateY(0);
    outline: 2px solid var(--color-cta-ink);
  }

  /* Container */
  .container {
    inline-size: 100%;
    max-inline-size: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }

  /* Visually hidden utility */
  .vh {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  /* Image load fade — applied only by /assets/js/features/shared/image-loader.js
     to non-cached <img> elements. The browser still paints progressively;
     this fade only triggers when JS has detected the image was not yet
     complete at observation time. Cached images bypass the class entirely
     so they appear instantly. */
  .img-fade {
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  .img-fade.is-loaded { opacity: 1; }
}

/* ============ Native cross-document view transitions ============ *
 * Browsers that ship CSS view-transitions (Chrome 126+, Edge 126+,
 * Safari 18+) crossfade between same-origin pages with no JS at all.
 * Firefox today falls back silently to standard hard navigation.
 * Reduced-motion users skip the animation; the rule is gated by the
 * `no-preference` media query, so when the OS preference is `reduce`
 * the keyframes never apply and the swap is instant.
 * ================================================================== */

@view-transition { navigation: auto; }

@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 280ms;
    animation-timing-function: var(--ease-out);
  }
  ::view-transition-old(root) { animation-name: vt-fade-out; }
  ::view-transition-new(root) { animation-name: vt-fade-in; }
  @keyframes vt-fade-out { to   { opacity: 0; } }
  @keyframes vt-fade-in  { from { opacity: 0; } }
}
