/* ─── Tokens ──────────────────────────────────────────────────────── */
:root {
  --white: #ffffff;
  --ink: #14101a;
  --ink-60: rgba(20, 16, 26, 0.6);
  --ink-30: rgba(20, 16, 26, 0.3);
  --ink-12: rgba(20, 16, 26, 0.12);

  --lilac: #c9b6f2;
  --lilac-deep: #8f6fe0;
  --lilac-soft: #f3eeff;

  --pink: #f7b8d6;
  --pink-deep: #e8639f;
  --pink-soft: #fff0f7;

  --mint: #bfe8de;
  --butter: #fce7a2;
  /* Two more, added when the theme rail went from four chips to six. A theme
     chip's colour is semantic — it is how you tell Marvel from Minecraft at a
     glance — so two of six sharing a pastel is a worse answer than two more
     tokens. `--coral` is the red the Marvel stage already paints with
     (#d81f26) pulled up into this palette's pastel range; `--azure` is the
     plain one, which is what "Everyday" means. */
  --coral: #f9b3a8;
  --azure: #bcd9f2;
  --grey: #8b8496;

  /* The watercolour sky the interlude bands sit on — a chapter break in the
     middle of the white page, so the product sections stop reading as one
     continuous wall. Deeper than the pastels above, because these are a
     *ground*: a tint that reads as a highlight on white reads as nothing at
     all when the whole band is made of it. */
  --sky-base: #f6effb;
  --sky-blush: rgba(255, 202, 226, 0.92);
  --sky-cream: rgba(255, 238, 199, 0.72);
  --sky-blue: rgba(186, 219, 246, 0.9);
  --sky-lilac: rgba(216, 197, 248, 0.92);

  --rail: 68px;
  --gutter: clamp(20px, 4vw, 72px);
  --radius: 22px;

  /*
   * The vertical breathing room a full section gets, in one place.
   *
   * Three sections had each written their own `clamp(5rem, 12vh, 9rem)`, which
   * is fine until the answer to "the page feels crowded" is to change it — then
   * it is three edits and a fourth section that quietly drifts out of step.
   * Raised from that original figure as part of the same pass that added the
   * interlude bands: more air around the product grids is half of what makes
   * them stop reading as one continuous wall.
   */
  --air: clamp(6.5rem, 16vh, 12rem);

  /* Loaded from Google Fonts in inc/enqueue.php. Each keeps a real fallback
     stack: the display face sets the largest element on every page, so a
     failed font request must not collapse the headline to a serif. */
  --font-display: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-script: 'Pacifico', 'Brush Script MT', cursive;
}

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

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

body {
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; }
button, input, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

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

/* ─── ScrollSmoother structure ────────────────────────────────────── */
#smooth-wrapper { overflow: hidden; }
#smooth-content { will-change: transform; }

/*
 * Where ScrollSmoother steps aside, nothing ever transforms this element, and
 * the hint becomes a promise the page cannot cash in: it promotes the *entire*
 * document to its own composited layer, to be rastered and held in memory, for
 * a transform that never comes.
 *
 * It also has a second effect that is easy to miss: `will-change: transform`
 * establishes a containing block for `position: fixed` descendants exactly as
 * a real transform does. That is the trap ProductPage and ThemeCycler both
 * force `pinType: 'transform'` to avoid, and dropping the hint here is what
 * lets plain fixed positioning behave normally on a phone.
 *
 * ── Keep in step with SmoothScroll.tsx ──
 * These two queries are the definition of "no smoother", and the component
 * tests the same pair before deciding whether to create one. Change one, change
 * the other. Deliberately a media query rather than a class the component
 * sets: the smoother is skipped from the very first frame, and an attribute
 * written before hydration is a mismatch against the server-rendered markup.
 */
@media (pointer: coarse), (prefers-reduced-motion: reduce) {
  #smooth-content { will-change: auto; }
}

/* ─── Type scale ──────────────────────────────────────────────────── */
.display {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.035em;
  line-height: 0.86;
  font-size: clamp(2.6rem, 7.4vw, 8.2rem);
}

.display-md {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 0.92;
  font-size: clamp(2.2rem, 6vw, 5.2rem);
}

.eyebrow {
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--grey);
}

.lede {
  font-size: clamp(1rem, 1.3vw, 1.2rem);
  color: var(--ink-60);
  max-width: 46ch;
}

/* Utility for SplitText line masking */
.line-mask { overflow: hidden; display: block; }

/* ── Small-screen type step ───────────────────────────────────────────
   `.display`'s floor of 2.6rem stops shrinking at about 562px wide, but the
   hero sets each headline line as `word · image tile · word` on a
   `flex-wrap: nowrap` row. Below that width the row is wider than the screen,
   and because `body` carries `overflow-x: hidden` the excess is silently
   clipped rather than scrolled — measured at 320px, "MAGIC __ IN" lost its
   last word entirely. Dropping the floor is what actually keeps the lines
   whole; the tiles are sized in `em`, so they follow it down.
   The cap is chosen to meet the default clamp at 600px so there is no jump
   across the boundary. */
@media (max-width: 599px) {
  .display { font-size: clamp(1.75rem, 9vw, 2.8rem); }
  .display-md { font-size: clamp(1.6rem, 7.6vw, 2.4rem); }
}

/* ─── Layout ──────────────────────────────────────────────────────── */
.section {
  position: relative;
  padding-inline: var(--gutter);
  padding-right: calc(var(--gutter) + var(--rail));
}

@media (max-width: 899px) {
  .section { padding-right: var(--gutter); }
  :root { --rail: 0px; }
}

/* ── Focus ───────────────────────────────────────────────────────────
   Only the nav and the chips styled a focus ring; every other link and
   button fell back to the UA default, which is invisible against the ink
   pills. One consistent ring, keyboard-only. */
:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--lilac-deep);
  outline-offset: 3px;
  border-radius: 6px;
}

.wash-lilac { background: var(--lilac-soft); }
.wash-pink { background: var(--pink-soft); }

/* Tint helpers used by product cards / chips */
.t-lilac { --tint: var(--lilac); --tint-soft: var(--lilac-soft); --tint-deep: var(--lilac-deep); }
.t-pink  { --tint: var(--pink);  --tint-soft: var(--pink-soft);  --tint-deep: var(--pink-deep); }
.t-mint  { --tint: var(--mint);  --tint-soft: #ecfaf6;           --tint-deep: #4fa895; }
.t-butter{ --tint: var(--butter);--tint-soft: #fffaea;           --tint-deep: #c9a02c; }
.t-coral { --tint: var(--coral); --tint-soft: #fff1ee;           --tint-deep: #d8543f; }
.t-azure { --tint: var(--azure); --tint-soft: #eef6fd;           --tint-deep: #3f7fae; }

/* ─── Reduced motion ──────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}


/* ─── WordPress ───────────────────────────────────────────────────────
   The handful of things the platform expects a theme to style, plus the
   two rules the storefront's own structure needs. */

.us-main { display: block; }

/*
 * Visually hidden, but still read out and still focusable.
 *
 * `clip-path` rather than the old `clip`: a zero-size box with `overflow:
 * hidden` stops some screen readers announcing the content at all.
 */
.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link:focus {
  position: fixed;
  z-index: 200;
  top: 12px;
  left: 12px;
  width: auto;
  height: auto;
  margin: 0;
  padding: 10px 18px;
  clip-path: none;
  background: var(--ink);
  color: var(--white);
  border-radius: 999px;
  font-weight: 600;
}

/* WordPress' own alignment and caption classes, for post content. */
.alignleft { float: left; margin: 0 var(--gutter) 1rem 0; }
.alignright { float: right; margin: 0 0 1rem var(--gutter); }
.aligncenter { display: block; margin-inline: auto; }
.wp-caption-text { font-size: 0.85rem; color: var(--ink-60); margin-top: 0.5rem; }

/*
 * ── The cast's mobile switch ─────────────────────────────────────────
 *
 * Seven of the placements stay below 900px and the rest come off. The
 * decision is set per character with `mobile="off"` on the call *and* a
 * matching rule in the section's stylesheet, so it is visible from either
 * file; this is the shared half.
 *
 * The ones that go are the ones whose placement *is* the space around them.
 * A peering dinosaur needs 143px of clear height above the filmstrip and a
 * phone gives him 90; a character reaching into the wordmark needs a band
 * much taller than she is, and on a phone that band is 74px, so she was
 * standing on the logo rather than reaching into it.
 */
@media (max-width: 899px) {
  .us-cast[data-mobile='off'] { display: none; }
}
