/* ============================================================================
   BeautyPages — Design Token Contract
   ----------------------------------------------------------------------------
   Every layout styles itself ONLY with the tokens declared here. A theme sets
   the ~14 INPUT tokens; everything else derives from them in CSS. That is the
   whole trick: swap one input and the tints, hovers, borders, shadows and
   contrast follow automatically, so any palette reads as designed rather than
   recoloured.

   Rule for layout authors: never write a literal colour, radius or font
   family in a layout. If you need a value that isn't here, add it here as a
   derivation so all 12 themes inherit it.
   ============================================================================ */

:root {
  /* ---- INPUTS: a theme overrides these and nothing else ------------------ */
  --bg: #F7F4EE;          /* page background                                  */
  --surface: #FFFFFF;     /* cards, sheets, anything lifted off the page      */
  --ink: #17211B;         /* primary text                                     */
  --brand: #1E3A2B;       /* primary brand colour                             */
  --brand-ink: #FFFFFF;   /* text/icons that sit ON --brand (contrast-picked) */
  --accent: #C96F2E;      /* highlight + calls to action                      */
  --accent-ink: #FFFFFF;  /* text/icons that sit ON --accent                  */

  --font-display: Georgia, "Times New Roman", serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;

  --radius: 18px;         /* vibe dial: 0 = editorial, 26px = soft/friendly   */
  /* Button shape is its own dial. A pill reads friendly and modern; a square
     button reads editorial and expensive. Themes that set --radius: 0 must be
     able to square their buttons too, or the page fights itself. */
  --radius-btn: 999px;
  --tracking-eyebrow: .18em;
  --case-eyebrow: uppercase;
  --weight-display: 600;

  /* ---- DERIVED: never set these in a theme ------------------------------ */

  /* Surfaces tinted by the brand — cards, badges, quiet section bands. */
  --brand-tint: color-mix(in oklab, var(--brand) 8%, var(--surface));
  --brand-tint-2: color-mix(in oklab, var(--brand) 18%, var(--surface));
  --brand-band: color-mix(in oklab, var(--brand) 6%, var(--bg));
  /* Interaction states. Mixing toward --ink (not black) keeps dark themes
     from collapsing to mud and light themes from going flat. */
  --brand-hover: color-mix(in oklab, var(--brand) 82%, var(--ink));
  --brand-soft: color-mix(in oklab, var(--brand) 45%, var(--bg));
  --accent-tint: color-mix(in oklab, var(--accent) 12%, var(--surface));
  --accent-hover: color-mix(in oklab, var(--accent) 82%, var(--ink));
  --accent-soft: color-mix(in oklab, var(--accent) 40%, var(--bg));

  /* Coloured TEXT. A mid-tone accent that works as a button fill is rarely
     legible as body text on --surface, so text gets its own darkened-toward-ink
     variants. Rule: --brand/--accent for fills, --brand-text/--accent-text for
     any coloured type or icon sitting directly on --bg/--surface. */
  --brand-text: color-mix(in oklab, var(--brand) 76%, var(--ink));
  --accent-text: color-mix(in oklab, var(--accent) 72%, var(--ink));

  /* Text hierarchy, derived so it stays legible on any background. */
  --ink-soft: color-mix(in oklab, var(--ink) 72%, var(--bg));
  --ink-muted: color-mix(in oklab, var(--ink) 52%, var(--bg));
  --ink-faint: color-mix(in oklab, var(--ink) 34%, var(--bg));

  /* Rules and dividers. */
  --line: color-mix(in oklab, var(--ink) 12%, var(--bg));
  --line-strong: color-mix(in oklab, var(--ink) 24%, var(--bg));
  --line-brand: color-mix(in oklab, var(--brand) 26%, var(--bg));

  /* Shadows tinted with the ink so they read as the same light source. */
  --shadow-tint: color-mix(in oklab, var(--ink) 12%, transparent);
  --shadow-tint-2: color-mix(in oklab, var(--ink) 8%, transparent);
  --shadow-sm: 0 1px 2px var(--shadow-tint-2), 0 4px 12px var(--shadow-tint-2);
  --shadow-md: 0 2px 6px var(--shadow-tint-2), 0 16px 40px var(--shadow-tint);
  --shadow-lg: 0 4px 12px var(--shadow-tint-2), 0 32px 70px var(--shadow-tint);

  /* Radius scale — one dial drives the whole family. */
  --radius-xs: calc(var(--radius) * .28);
  --radius-sm: calc(var(--radius) * .55);
  --radius-lg: calc(var(--radius) * 1.55);
  --radius-pill: 999px;

  /* Fluid type scale. Layouts use these, never raw rem values. */
  --step--2: clamp(.69rem, .67rem + .1vw, .75rem);
  --step--1: clamp(.83rem, .8rem + .15vw, .91rem);
  --step-0: clamp(1rem, .96rem + .2vw, 1.09rem);
  --step-1: clamp(1.2rem, 1.13rem + .35vw, 1.42rem);
  --step-2: clamp(1.44rem, 1.32rem + .6vw, 1.85rem);
  --step-3: clamp(1.73rem, 1.53rem + .98vw, 2.4rem);
  --step-4: clamp(2.07rem, 1.75rem + 1.6vw, 3.13rem);
  --step-5: clamp(2.49rem, 1.98rem + 2.55vw, 4.07rem);

  /* Space scale. */
  --space-1: .25rem;
  --space-2: .5rem;
  --space-3: .75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;
  --space-9: 7rem;

  --container: 1180px;
  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* Coarse fallback for browsers without color-mix() (iOS Safari < 16.2).
   Values are flat neutrals: the page stays legible and on-brand-ish rather
   than rendering with empty custom properties. */
@supports not (color: color-mix(in oklab, #000, #fff)) {
  :root {
    --brand-tint: rgba(128, 128, 128, .06);
    --brand-tint-2: rgba(128, 128, 128, .14);
    --brand-band: rgba(128, 128, 128, .05);
    --brand-hover: var(--brand);
    --brand-soft: var(--brand);
    --accent-tint: rgba(128, 128, 128, .1);
    --accent-hover: var(--accent);
    --accent-soft: var(--accent);
    --ink-soft: rgba(90, 90, 90, .92);
    --ink-muted: rgba(110, 110, 110, .8);
    --ink-faint: rgba(130, 130, 130, .6);
    --line: rgba(128, 128, 128, .22);
    --line-strong: rgba(128, 128, 128, .4);
    --line-brand: rgba(128, 128, 128, .35);
    --brand-text: var(--brand);
    --accent-text: var(--accent);
    --shadow-tint: rgba(0, 0, 0, .12);
    --shadow-tint-2: rgba(0, 0, 0, .07);
  }
}

/* ============================================================================
   Baseline. Reset plus the accessibility floor every layout inherits, so no
   layout has to remember it.
   ============================================================================ */

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

/* The UA rule for [hidden] is a bare type selector, so ANY class that sets
   `display` silently defeats it — which is how a layout ends up showing an
   empty reviews block, or worse, a placeholder rating that no API returned.
   Hiding must win over layout. */
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; }
input, select, textarea { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: 1.12;
  text-wrap: balance;
}

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

/* Keyboard focus is always visible, and always contrasts with the surface
   it lands on. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}

.container { width: min(var(--container), 92%); margin-inline: auto; }

/* Eyebrow / kicker labels. The case + tracking are theme dials, so an
   editorial theme gets WIDE CAPS and a soft theme gets sentence case. */
.eyebrow {
  font-size: var(--step--2);
  text-transform: var(--case-eyebrow);
  letter-spacing: var(--tracking-eyebrow);
  color: var(--ink-muted);
  font-weight: 600;
}

/* Scroll reveal. Opt-in via .reveal; theme.js adds .in. */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s ease, transform .7s var(--ease);
}
.reveal.in { opacity: 1; transform: none; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}
