/* ==========================================================================
   HaSheesh — shared stylesheet

   The look is a dispensary menu / spec sheet, not a landing page: printed
   white, black ink, gold foil from the packaging, hairline rules, square
   corners, tabular data. See DESIGN.md before adding anything.

   Non-negotiables carried over: body text >= 17px, tap targets >= 48px,
   contrast >= 4.5:1, visible focus, native scrolling, no third-party assets.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Fonts — self-hosted. Figtree carries the page, Cormorant Garamond italic
   carries the gold accent word in a display line, and IBM Plex Mono carries
   every label, code and number.

   Archivo was here before and was the reason the type read as generic: it is a
   neutral workhorse grotesque, so at display size it looked like a system font
   set large. Bricolage has an optical-size axis, which is the part that matters
   — the same family draws tight, high-contrast, narrow-aperture letterforms for
   a 96px headline and opens the apertures back up for 17px body copy. The
   browser drives that axis itself from the used font-size via the default
   `font-optical-sizing: auto`, so nothing here has to name opsz per rule.

   Subset to latin + the punctuation the site actually sets, and the width axis
   pinned to 100 and dropped: 128.5KB -> 54KB, which is +19KB over Archivo for
   one family doing both jobs.
   -------------------------------------------------------------------------- */
@font-face {
    font-family: 'Figtree';
    font-style: normal;
    font-weight: 300 900;
    font-display: swap;
    src: url('fonts/figtree-latin.woff2') format('woff2');
    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;
}

/* The gold accent word in a display line ("One *standard.*"). One weight, one
   style, subset to the characters actually set in it: 24KB -> 10KB. */
@font-face {
    font-family: 'Cormorant';
    font-style: italic; font-weight: 500; font-display: swap;
    src: url('fonts/cormorant-italic.woff2') format('woff2');
}
@font-face {
    font-family: 'Plex Mono';
    font-style: normal; font-weight: 400; font-display: swap;
    src: url('fonts/plexmono-400.woff2') format('woff2');
}
@font-face {
    font-family: 'Plex Mono';
    font-style: normal; font-weight: 500; font-display: swap;
    src: url('fonts/plexmono-500.woff2') format('woff2');
}
@font-face {
    font-family: 'Plex Mono';
    font-style: normal; font-weight: 600; font-display: swap;
    src: url('fonts/plexmono-600.woff2') format('woff2');
}

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
    --paper:   #FFFFFF;   /* printed white, deliberately not cream */
    --paper-2: #F4F3F0;
    --paper-3: #E8E6E1;
    /* The product photography sits on a cool grey seamless. Panels behind a
       photo use this so the plate looks like an extension of the shot. */
    --plate:   #EDEEF0;
    --ink:     #101010;
    --ink-2:   #1C1C1A;

    --text:    #101010;
    --text-2:  #4A4A46;   /* 8.9:1 on white */
    --on-ink:     #FFFFFF;
    --on-ink-2:   #A8A49C;

    --gold:     #B8862B;  /* foil. Fills and rules — 3.2:1, never body text */
    --gold-ink: #7A5A15;  /* 6.4:1 on white. This is the one for gold *text* */
    --on-gold:  #1A1206;  /* 5.7:1 on --gold. Text sat on a gold fill */
    /* The foil wash that replaced the solid black feature bands. Deep enough to
       read as gold rather than as off-white paper. */
    --paper-gold: #F5EAD0;
    --gold-soft:  #E3D2AC;  /* decorative gold hairline */

    --rule:      #D8D5CE;
    --rule-firm: #101010;
    --rule-on-ink: rgba(255,255,255,0.22);

    --indica: #5B4A86;
    --sativa: #9A6B14;
    --hybrid: #2E6048;

    --ok:  #1F6136;
    --err: #93291B;

    /* Warm off-white from the reference build. Used as the page ground and for
       the panels behind product shots, replacing the cool grey plate there. */
    --bone: #FAF9F6;
    --hair: rgba(16, 16, 16, 0.12);   /* the 1px grid lines between fact cells */
    --serif: 'Cormorant', Georgia, 'Times New Roman', serif;

    --font: 'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --mono: 'Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

    /* Type scale. The old one topped out at 37px for a section heading, which is
       most of why the page read as a spec sheet from 2015 — there was no
       typographic drama anywhere. Display sizes now carry the page. */
    --fs-hero:  clamp(2.75rem, 8.4vw, 7.5rem);
    --fs-h2:    clamp(2rem, 5.4vw, 4.25rem);
    --fs-h3:    clamp(1.375rem, 2.3vw, 1.875rem);
    --fs-lede:  clamp(1.125rem, 1.55vw, 1.4375rem);
    --fs-meta:  0.8125rem;    /* mono labels. 13px is the floor, not 12 */
    --lh-tight: 0.94;

    /* Depth. There were zero shadows in the whole build; flat hairline boxes are
       the other half of why it looked dated. These are for lift on hover and for
       floating chrome, never for decoration at rest. */
    --lift:  0 22px 50px -22px rgba(16, 16, 16, 0.26);
    --lift-2: 0 34px 80px -30px rgba(16, 16, 16, 0.34);

    --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
    /* A long, soft curve for entrances — the thing that makes motion read as
       expensive rather than snappy. */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --t-fast: 160ms;
    --t-mid: 320ms;
    --t-slow: 560ms;
    --t-reveal: 900ms;

    /* Radius. The build had none by policy — the packaging is square, so the
       site was too. The owner asked for the sharp corners off everything: the
       boxes, the pictures, the buttons. One scale, applied in section 24, so
       the softening is a single decision rather than 30 scattered ones. */
    --r-xs:   4px;    /* swatches and markers */
    --r-sm:   10px;   /* chips, thumbs, inline tags, messages */
    --r-md:   14px;   /* buttons, inputs, selects */
    --r-lg:   20px;   /* cards, photo plates, fact grids, panels */
    --r-xl:   26px;   /* dialogs and floating chrome */
    --r-pill: 999px;

    --tap: 48px;
    --page: 1280px;
    --page-wide: 1600px;
    --gutter: clamp(18px, 4.4vw, 68px);
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: 96px;
}

body {
    background: var(--paper);
    color: var(--text);
    font-family: var(--font);
    font-size: 1.0625rem;
    line-height: 1.55;
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}
body.is-locked { overflow: hidden; }

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

/* A class that sets `display` outbids the UA rule for [hidden], which silently
   turns the attribute into a no-op. Several blocks here are hidden until their
   JSON arrives, so make the attribute win. */
[hidden] { display: none !important; }

button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; }

h1, h2, h3, h4 {
    font-weight: 800;
    line-height: var(--lh-tight);
    /* Tight tracking is what stops a heavy grotesque at display size from
       looking like a default browser heading. */
    letter-spacing: -0.035em;
    text-wrap: balance;
}

/* --------------------------------------------------------------------------
   2b. Motion primitives
   Everything here is transform and opacity only, so it stays on the compositor.
   Each is opt-in per element, and the whole set is switched off further down for
   prefers-reduced-motion.
   -------------------------------------------------------------------------- */

/* A line of type rising out of its own clipped box. The JS wraps each visual
   line in .rise > span so the mask follows the real line breaks. */
.rise { display: block; overflow: hidden; }
.rise > span {
    display: block;
    transform: translateY(105%);
    transition: transform var(--t-reveal) var(--ease-out);
    transition-delay: var(--d, 0ms);
}
.is-in > .rise > span, .rise.is-in > span { transform: none; }

/* Staggered group: children come up in sequence. The index is set inline by the
   JS so the delay survives filtering and re-rendering. */
.stagger > * {
    opacity: 0; transform: translateY(26px);
    transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
    transition-delay: calc(var(--i, 0) * 70ms);
}
.stagger.is-in > * { opacity: 1; transform: none; }

/* Scroll-linked parallax and scroll-linked zoom, in one transform. Keeping them
   in a single declaration is not tidiness — two rules both setting `transform`
   would overwrite each other, and an element that wants to drift and breathe at
   once has to compose both in the same function list. The JS writes --py and
   --pz; the element itself never gets a layout-affecting property. */
.para {
    will-change: transform;
    transform: translate3d(0, var(--py, 0px), 0) scale(var(--pz, 1));
}

/* --- Image reveals -------------------------------------------------------
   The page had exactly one image entrance and everything else was text moving,
   which is what made the motion read as a template. These are the image-led
   ones. */

/* A photograph uncovering itself directionally while it relaxes out of a zoom.
   Note WHICH element is clipped: the clip is on the child, never on .mask
   itself. This is the trap that cost two debugging rounds — a clipped element
   reports intersectionRatio 0 (measured: 0 clipped, 1 unclipped), so an observer
   watching it can never see it arrive and it stays hidden for good. The earlier
   fix was a cover panel that scaled away, which worked but had to be told what
   colour the section behind it was. Clipping the child instead keeps .mask's
   layout box intact and observable, and needs to know nothing about its ground. */
.mask { overflow: hidden; }
.mask > img, .mask > picture > img {
    clip-path: inset(0 0 100% 0);
    transform: scale(1.09);
    transition: clip-path 1150ms var(--ease-out), transform 1500ms var(--ease-out);
    transition-delay: var(--d, 0ms);
}
.mask.is-in > img, .mask.is-in > picture > img {
    clip-path: inset(0 0 0 0); transform: none;
}
.mask--left > img { clip-path: inset(0 100% 0 0); }
.mask--right > img { clip-path: inset(0 0 0 100%); }

/* Scale-settle with no cover panel, for photography that sits on a coloured
   ground where a paper cover panel would flash the wrong colour. */
.zoom { overflow: hidden; }
.zoom > img {
    opacity: 0; transform: scale(1.14);
    transition: opacity 900ms var(--ease-out), transform 1600ms var(--ease-out);
    transition-delay: var(--d, 0ms);
}
.zoom.is-in > img { opacity: 1; transform: none; }

/* Pointer tilt on a media card. Deliberately small — 5 degrees is the most that
   still reads as the object responding rather than a novelty. Pointer devices
   only; the JS never binds on touch. */
.tilt { perspective: 1000px; }
.tilt > * {
    transform: rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
    transition: transform 400ms var(--ease-out);
}

/* Media that answers a hover. Applies whether the hover lands on the frame or
   on an ancestor link, which is the usual case for a card. */
.mhov { overflow: hidden; }
.mhov img { transition: transform 750ms var(--ease-out); }
.mhov:hover img, a:hover .mhov img, a:focus-visible .mhov img { transform: scale(1.05); }

/* Word cascade, for short display lines where a whole-line rise is too blunt.
   The JS wraps each word; the inner element carries the movement so the wrapper
   can clip it. */
.word { display: inline-block; overflow: hidden; vertical-align: top; }
.word > i {
    display: inline-block; font-style: normal;
    transform: translateY(112%);
    transition: transform var(--t-reveal) var(--ease-out);
    transition-delay: calc(var(--w, 0) * 46ms);
}
.is-in .word > i, .word.is-in > i { transform: none; }

/* A single element fading up, for prose and odd blocks */
.up {
    opacity: 0; transform: translateY(22px);
    transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
    transition-delay: var(--d, 0ms);
}
.up.is-in { opacity: 1; transform: none; }

/* Reading progress, pinned to the very top of the viewport */
.progress {
    position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 200;
    background: transparent; pointer-events: none;
}
.progress i {
    display: block; height: 100%; width: 0;
    background: var(--gold); transform-origin: 0 50%;
}

/* Desktop cursor: a small ring that lags the pointer and swells over targets.
   Pointer-events none throughout, and never shown on touch. */
.cursor {
    position: fixed; top: 0; left: 0; z-index: 300;
    width: 34px; height: 34px; margin: -17px 0 0 -17px;
    border: 1.5px solid var(--gold); border-radius: 50%;
    pointer-events: none; opacity: 0;
    transform: translate3d(var(--cx, -100px), var(--cy, -100px), 0) scale(var(--cs, 1));
    transition: opacity var(--t-mid) var(--ease), scale var(--t-mid) var(--ease);
}
.cursor.is-on { opacity: 1; }
.cursor.is-hot { --cs: 1.85; background: rgba(184, 134, 43, 0.12); }
@media (hover: none), (pointer: coarse) { .cursor { display: none; } }

::selection { background: var(--gold); color: #000; }

:focus-visible {
    outline: 3px solid var(--gold-ink);
    outline-offset: 2px;
}

.skip-link {
    position: absolute; left: 8px; top: -100px; z-index: 999;
    background: var(--ink); color: var(--on-ink);
    padding: 14px 20px; font-family: var(--mono); font-weight: 600;
    text-decoration: none; transition: top var(--t-fast) var(--ease);
}
.skip-link:focus { top: 8px; }

.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;
}

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.feature > *, .form__row > *, .lab > * { min-width: 0; }

.wrap {
    width: 100%; max-width: var(--page);
    margin-inline: auto; padding-inline: var(--gutter);
}

.wrap--wide { max-width: var(--page-wide); }
/* Air. The old rhythm was 40-72px between sections, which crowds display type
   and is a large part of why the page felt like a document rather than a site. */
/* 11vw resolved to 158px top AND bottom on a laptop, so two consecutive sections
   put ~317px of contiguous nothing between their content. Generous space is not
   the problem — empty space with nothing to look at is. Measured on screen, the
   viewports covering these gaps carried under 6% ink. */
.section { padding-block: clamp(64px, 7.4vw, 124px); }
.section--tight { padding-block: clamp(44px, 5vw, 76px); }
.section--gold { background: var(--paper-gold); }
.section--band { background: var(--paper-2); }
/* The cool grey the product photography was actually shot on. A band in this
   colour reads as an extension of the shot rather than a panel the shot has been
   placed on, which is what the token exists for.

   The ground under a .blendshot has to stay light. Those photos carry no alpha —
   their white seamless disappears by multiplying against the band — and on a dark
   ground multiply would render the whole picture near-black. A cutout is not an
   available escape either: the packs are white boxes and 20% of the frame is
   near-white, so a luminance key eats the product along with the background. */
.section--plate { background: var(--plate); }

/* --------------------------------------------------------------------------
   3b. Editorial section heads
   Replaced the old marker-square-plus-rule device entirely. A section is
   announced by its own size now, not by a device bolted above it.
   -------------------------------------------------------------------------- */
.head { display: grid; gap: clamp(18px, 2.6vw, 34px); margin-bottom: clamp(34px, 5vw, 66px); }
.head--split {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    align-items: end; gap: clamp(24px, 5vw, 72px);
}
.head h2, .head h1 { font-size: var(--fs-h2); }
.head__meta {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.18em; text-transform: uppercase; color: var(--gold-ink);
    display: flex; align-items: center; gap: 12px;
}
.head__meta::before {
    content: ""; width: 28px; height: 1px; background: var(--gold); flex: none;
}
.head__aside { color: var(--text-2); font-size: var(--fs-lede); max-width: 46ch; }
@media (max-width: 860px) {
    .head--split { grid-template-columns: 1fr; align-items: start; }
}



.lede {
    font-size: clamp(1.0625rem, 1.5vw, 1.1875rem);
    color: var(--text-2); max-width: 66ch;
    padding: 18px 0 0;
}

/* A product shot dropped onto a coloured band leaves a visible rectangle, because
   the seamless it was shot on is never the same colour as the band. These files
   have their seamless lifted to pure white (see tools/crop-photos.js), and
   multiply maps white onto whatever is behind it — so the backdrop becomes the
   band exactly and only the product is left. The mask feathers the frame edge in
   case of any lens vignette the lift did not flatten.

   Keep this out of a .reveal: animating opacity creates a stacking context, and
   the blend would isolate against that instead of the band. */
.blendshot {
    display: block; width: 100%; height: auto;
    mix-blend-mode: multiply;
    -webkit-mask-image: radial-gradient(120% 110% at 50% 48%, #000 58%, transparent 100%);
            mask-image: radial-gradient(120% 110% at 50% 48%, #000 58%, transparent 100%);
}
@supports not (mix-blend-mode: multiply) {
    .blendshot { mix-blend-mode: normal; }
}

/* --------------------------------------------------------------------------
   4. Buttons — square, mono, no capsules
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 10px;
    min-height: var(--tap); padding: 12px 26px;
    font-family: var(--mono); font-size: 0.9375rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.06em;
    text-decoration: none; text-align: center;
    position: relative; overflow: hidden; isolation: isolate;
    border: 1px solid var(--gold); background: var(--gold); color: var(--on-gold);
    transition: color var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease);
}
/* The fill sweeps in from the bottom rather than the colour snapping over. */
.btn::after {
    content: ""; position: absolute; inset: 0; z-index: -1;
    background: var(--ink); transform: translateY(101%);
    transition: transform var(--t-mid) var(--ease-out);
}
.btn:hover { color: var(--on-ink); border-color: var(--ink); }
.btn:hover::after { transform: none; }

/* Paper, not transparent. A ghost button now sits over photography in the hero,
   and box artwork showing through the label made it the least readable thing on
   the page. */
.btn--ghost { background: var(--paper); color: var(--ink); border-color: var(--ink); }
.btn--ghost:hover { color: var(--on-ink); }

.btn--lg { min-height: 62px; padding: 16px 38px; font-size: 1rem; }


.btn-row { display: flex; flex-wrap: wrap; gap: 10px; }

.link {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: var(--mono); font-size: 0.9375rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--gold-ink); text-decoration: none;
    padding: 14px 0; position: relative;
    transition: gap var(--t-fast) var(--ease);
}
.link::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 8px; height: 1px;
    background: currentColor; transform: scaleX(1); transform-origin: 100% 50%;
    transition: transform var(--t-mid) var(--ease-out);
}
.link:hover { gap: 15px; }
.link:hover::after { transform: scaleX(0); }

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */
.header {
    position: sticky; top: 0; z-index: 100;
    background: var(--paper);
    /* Nothing under the nav at rest — it sits on the page. A hairline and a
       whisper of blur appear only once you have scrolled past the hero, which is
       what keeps the top of the page feeling open. */
    border-bottom: 1px solid transparent;
    transition: border-color var(--t-mid) var(--ease), background-color var(--t-mid) var(--ease);
}
.header.is-stuck {
    border-bottom-color: var(--rule);
    /* Solid, not translucent-and-blurred. A backdrop-filter here was the single
       most expensive thing on the page: it recomposites the strip on every frame
       of every scroll, and measured 9.2% dropped frames against 3.0% without it.
       Behind a white bar the blur is invisible anyway. */
    background: var(--paper);
    box-shadow: 0 1px 0 var(--rule);
}
/* The bar ignores the page's max-width so the mark sits near the viewport edge
   and the nav sits at the other, rather than both floating inside a 1280px
   column with dead space beyond them. */
.header__bar {
    display: flex; align-items: center; gap: clamp(16px, 3vw, 40px);
    max-width: none; min-height: 84px; padding-block: 8px;
}
.header__logo { display: flex; align-items: center; flex: none; text-decoration: none; min-height: var(--tap); }
.header__logo img { height: 42px; width: auto; }
.header__nav-wrap { margin-left: auto; }

.header__nav-wrap { display: flex; align-items: center; gap: clamp(18px, 3vw, 40px); margin-left: auto; }
.nav { display: flex; align-items: center; gap: clamp(2px, 0.6vw, 10px); }
.nav a {
    display: flex; align-items: center; min-height: var(--tap); padding: 0 14px;
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.11em;
    text-decoration: none; color: var(--text); white-space: nowrap;
    position: relative;
    transition: color var(--t-fast) var(--ease);
}
.nav a::after {
    content: ""; position: absolute; left: 14px; right: 14px; bottom: 12px; height: 1px;
    background: currentColor; transform: scaleX(0); transform-origin: 0 50%;
    transition: transform var(--t-mid) var(--ease-out);
}
.nav a:hover { color: var(--gold-ink); }
.nav a:hover::after { transform: scaleX(1); }
.nav a[aria-current="page"] { font-weight: 600; }
.nav a[aria-current="page"]::after { transform: scaleX(1); background: var(--gold); }


.header__toggle {
    display: none; align-items: center; gap: 9px; margin-left: auto;
    min-height: var(--tap); padding: 0 16px;
    border: 2px solid var(--ink); font-family: var(--mono);
    font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
    font-size: 0.9375rem;
}
.header__toggle svg { width: 18px; height: 18px; }
.header__toggle .icon-close { display: none; }
.header__toggle[aria-expanded="true"] .icon-close { display: block; }
.header__toggle[aria-expanded="true"] .icon-open { display: none; }

@media (max-width: 1060px) {
    /* The drawer is a positioned child of the header, so it would otherwise
       paint over the static toggle and swallow the tap that closes it. */
    .header__toggle { display: inline-flex; position: relative; z-index: 2; }
    .header__nav-wrap {
        /* --nav-top is the header's real bottom edge, set when the drawer opens.
           A fixed value cannot work: the header's own height changes with the
           viewport. Pinning bottom to 0 makes the drawer scroll itself, which
           matters in landscape where the body is scroll-locked and cannot help. */
        position: fixed; top: var(--nav-top, 76px); left: 0; right: 0; bottom: 0;
        z-index: 1;
        flex-direction: column; align-items: stretch; gap: 0; margin-left: 0;
        background: var(--paper); border-top: 2px solid var(--ink);
        padding: 0 var(--gutter) 32px; overflow-y: auto; display: none;
    }
    .header__nav-wrap.is-open { display: flex; }
    .nav { flex-direction: column; align-items: stretch; gap: 0; }
    .nav a {
        min-height: 58px; padding: 0 4px; font-size: 1.0625rem;
        border-bottom: 1px solid var(--rule);
    }
    .nav a[aria-current="page"] { border-bottom-color: var(--ink); }
}

/* --------------------------------------------------------------------------
   6a. Hero
   The range photo is the hero's ground, not a banner underneath it: the type
   sits over the boxes, and a two-axis scrim dissolves the photo back into the
   paper on the top and left so the headline still has a near-white ground to
   read against. Measured: 15.9:1 behind the h1, 8.6:1 behind the lede.
   -------------------------------------------------------------------------- */
/* Deliberately short of a full viewport. At 100svh the leftover after the copy
   got split evenly by align-content, which put 204px of empty paper between the
   header and the first line on a 1512x850 laptop and pushed the gold ticker 85px
   below the fold — measured, and the owner photographed the result. Sizing the
   hero to a little under the fold spends that air on showing the ticker instead. */
.hero {
    position: relative; isolation: isolate; overflow: hidden;
    min-height: min(78svh, 720px);
    display: grid; align-content: center;
    padding: clamp(34px, 3.6vw, 56px) 0 clamp(56px, 6vw, 88px);
}
/* overflow:hidden is load-bearing. The parallax translates the image by up to a
   couple of dozen pixels, and at rest it already sits 10px off — without a clip
   the image escapes the top of the scrim and lays a hard 8px strip of the
   photo's grey seamless across the full width of the page. */
.hero__bg {
    position: absolute; z-index: -1; left: 0; right: 0; bottom: 0;
    height: clamp(330px, 68%, 620px); overflow: hidden;
}
/* Taller than its frame and pulled up, so parallax in either direction always
   has image to spare and can never expose an edge. */
.hero__bgimg {
    position: absolute; inset: -7% 0; width: 100%; height: 114%;
    object-fit: cover; object-position: 50% 36%;
}
/* One soft ellipse of paper anchored where the copy sits, plus a short fade that
   dissolves the top edge. Two full-width linear scrims were the first attempt
   and they multiply: every pixel got hit by both, which washed the boxes out to
   250-255 and left no photograph to look at. */
.hero__bg::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background:
        linear-gradient(to bottom, var(--paper) 0%, rgba(255, 255, 255, 0.62) 9%,
            rgba(255, 255, 255, 0) 34%),
        radial-gradient(125% 155% at 0% 16%, var(--paper) 0%, rgba(255, 255, 255, 0.88) 30%,
            rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0) 72%);
}
.hero__inner { display: grid; justify-items: start; position: relative; }
.hero__meta {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.2em; text-transform: uppercase; color: var(--gold-ink);
    display: flex; align-items: center; gap: 14px; margin-bottom: clamp(22px, 3vw, 40px);
}
.hero__meta::before { content: ""; width: 40px; height: 1px; background: var(--gold); }
.hero__title {
    font-size: var(--fs-hero); font-weight: 800;
    letter-spacing: -0.045em; line-height: 0.9;
    margin-bottom: clamp(22px, 3vw, 38px); max-width: 15ch;
}
/* 38ch, not 44ch: the last line of a wider measure ran out of the scrim's
   protected zone and into the box artwork. */
.hero__lede {
    font-size: var(--fs-lede); color: var(--text-2);
    max-width: 38ch; margin-bottom: clamp(28px, 3.6vw, 46px);
}

/* A quiet cue that there is more, on the one screen where nothing else says so. */
.hero__scroll {
    position: absolute; left: 50%; bottom: clamp(18px, 2.6vw, 30px);
    transform: translateX(-50%);
    /* 13px is the site's floor and it applies to decorative labels too. */
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.24em; text-transform: uppercase; color: var(--text-2);
}
.hero__scroll span { display: block; animation: nudge 2.4s var(--ease-out) infinite; }
.hero__scroll::after {
    content: ""; display: block; width: 1px; height: 34px; margin: 10px auto 0;
    background: linear-gradient(to bottom, var(--gold), rgba(184, 134, 43, 0));
}
@keyframes nudge {
    0%, 100% { transform: translateY(0); opacity: 1; }
    50%      { transform: translateY(4px); opacity: 0.55; }
}

@media (max-width: 900px) {
    .hero { min-height: auto; padding-bottom: clamp(290px, 60vw, 400px); }
    .hero__bg { height: clamp(250px, 54vw, 370px); }
    /* Narrow screens cannot afford a scrim that reaches sideways — there is no
       width to put the type beside the photo — so the type sits above it and
       only a vertical fade runs. */
    .hero__bg::after {
        background: linear-gradient(to bottom, var(--paper) 0%,
            rgba(255, 255, 255, 0.5) 22%, rgba(255, 255, 255, 0) 54%);
    }
    .hero__bgimg { object-position: 50% 42%; }
    /* The cue exists because a full-height hero shows nothing else. Here the
       photo is already cut off by the fold, which says the same thing, and the
       label would sit over box artwork with no ground to read against. */
    .hero__scroll { display: none; }
}

/* --------------------------------------------------------------------------
   6b. Marquee — replaces the old utility strip
   An infinite ticker of the compliance facts. Two copies of the same list
   translate by exactly -50%, so the loop has no seam.
   -------------------------------------------------------------------------- */
/* Gold, not ink. It used to be the top of one continuous black block with the
   figures band below it; as a foil stripe between the white hero and that black
   band it does more work, and the colour change is what draws the edge. */
.marquee {
    position: relative; overflow: hidden;
    background: var(--gold); color: var(--on-gold);
    padding-block: clamp(14px, 1.6vw, 20px);
    border-block: 1px solid var(--gold);
}
.marquee__track {
    display: flex; width: max-content;
    animation: marquee 34s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group { display: flex; flex: none; }
.marquee__group span {
    display: inline-flex; align-items: center; gap: clamp(22px, 3vw, 44px);
    padding-inline: clamp(11px, 1.5vw, 22px);
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 500;
    letter-spacing: 0.14em; text-transform: uppercase; white-space: nowrap;
}
/* The separator was gold on ink; on gold it needs to go the other way. */
.marquee__group span::after {
    content: ""; width: 5px; height: 5px; background: var(--on-gold);
    opacity: 0.55; border-radius: 50%; flex: none;
}
@keyframes marquee { to { transform: translate3d(-50%, 0, 0); } }

/* --------------------------------------------------------------------------
   6c. Showcase rows — big alternating image/prose blocks
   -------------------------------------------------------------------------- */
.show { display: grid; gap: clamp(28px, 5vw, 86px); align-items: center; }
.show + .show { margin-top: clamp(80px, 11vw, 170px); }
.show > * { min-width: 0; }
@media (min-width: 900px) {
    .show { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .show--flip > .show__media { order: 2; }
}
.show__media { position: relative; background: var(--plate); overflow: hidden; }
.show__media img { width: 100%; }
/* Carries the row now that it has no heading of its own: the section title
   above governs both blocks, so this is the lead sentence, not a subhead. */
.show__lead {
    font-size: clamp(1.375rem, 2.6vw, 2rem); font-weight: 800;
    letter-spacing: -0.03em; line-height: 1.15; color: var(--text);
    margin-bottom: clamp(14px, 1.8vw, 20px);
}
.show__num {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.2em; color: var(--gold-ink); margin-bottom: 18px; display: block;
}
/* The same cap .split already applies to its plates, for the same reason. The
   spine and master-box shots are 0.62-0.67 aspect, so at half the page width
   they rendered ~970px tall; the prose beside them is half that, and `align-items:
   center` then floated the text in the middle of a mostly-empty band. Measured
   4.8% ink on the viewport covering the closing band.

   `width: auto` matters here: with `width: 100%` the img box stays full-width and
   `object-fit: contain` letterboxes the picture inside it, showing bands of the
   grey plate down both sides. Sizing by height instead lets the box track the
   picture. */
.show__media img, .show .zoom img {
    width: auto; max-width: 100%; max-height: 640px; height: auto;
}
.show__media, .show .zoom { display: grid; place-items: center; }

.show h2, .show h3 { font-size: var(--fs-h2); margin-bottom: clamp(16px, 2vw, 24px); }
.show p { color: var(--text-2); font-size: var(--fs-lede); max-width: 48ch; }
.show p + p { margin-top: clamp(12px, 1.6vw, 20px); }

.show p + p { margin-top: 14px; }
.show .btn-row, .show .link { margin-top: clamp(20px, 2.6vw, 32px); }

/* --------------------------------------------------------------------------
   6d. Figures — the numbers, set large, counting up on arrival
   -------------------------------------------------------------------------- */
/* Explicit tracks, not auto-fit. There are three figures now, and auto-fit at a
   140px minimum paired the first two on a phone and left the third alone on a
   second row — which is what the owner photographed. One per row below 620px,
   three across above it, so the band is never one short of a full row.

   (The 140px minimum was itself a fix, from back when there were four figures:
   at 190px a 354px phone fitted one column and the band ran a screen and a half
   long. With an odd count that fix became the problem.) */
.figs {
    display: grid; grid-template-columns: minmax(0, 1fr);
    gap: clamp(22px, 4vw, 60px);
}
@media (min-width: 620px) {
    .figs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.fig__n {
    display: block; font-size: clamp(2.5rem, 5.6vw, 4.5rem); font-weight: 800;
    letter-spacing: -0.045em; line-height: 1; margin-bottom: 12px;
    font-variant-numeric: tabular-nums;
}
.fig__l {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-2);
}
.fig { padding-top: 22px; border-top: 1px solid var(--rule); }

/* The figures used to float on white with 201px of padding around a 127px row,
   which is what made them read as an accident rather than a statement. They now
   continue the marquee's ink block, so the two together make one deliberate dark
   band across the page instead of two thin things separated by nothing. */
/* Solid foil, not the --paper-gold wash .section--gold carries. The figures
   band sits directly under the ticker and the owner asked for both in gold, so
   the two read as one field again — which is how they read when both were ink.
   Rules and labels darken rather than lighten here: on gold, a white hairline
   disappears and a dark one reads as struck. */
.section--foil {
    background: var(--gold); color: var(--on-gold);
    padding-block: clamp(38px, 4.4vw, 68px);
}
.section--foil .fig { border-top-color: rgba(26, 18, 6, 0.32); }
/* 0.9, not 0.78: at 13px these labels need 4.5:1 and 0.78 measured 4.14. The
   live audit caught it. */
.section--foil .fig__l { color: rgba(26, 18, 6, 0.9); }

/* --------------------------------------------------------------------------
   8. Exploded pen scrubber
   -------------------------------------------------------------------------- */
.explode { background: var(--paper); color: var(--text); }
.explode__track { position: relative; }
.explode__sticky {
    position: sticky; top: 0; height: 100vh;
    display: grid;
    grid-template-columns: 1fr minmax(0, 380px) 1fr;
    /* A definite row is what stops the tall canvas from growing the grid and
       spilling out of the viewport. */
    grid-template-rows: minmax(0, 1fr);
    align-items: center; gap: 20px;
    padding: 70px var(--gutter) 34px;
}
.explode__stage {
    grid-column: 2; grid-row: 1; align-self: stretch;
    position: relative; min-height: 0; display: grid; place-items: center;
}
/* Frames are swapped by changing src. object-fit keeps the pen whole at any
   stage size, and a fixed intrinsic ratio means no frame can cause a reflow. */
.explode__frame {
    display: block; width: 100%; height: 100%; min-height: 0;
    object-fit: contain;
}

.explode__intro { grid-column: 1; align-self: center; max-width: 340px; justify-self: end; }
.explode__intro h2 {
    font-size: clamp(2rem, 4.6vw, 3.5rem); font-weight: 800;
    letter-spacing: -0.035em; margin-bottom: 18px;
}
.explode__intro p { color: var(--text-2); font-size: 1.0625rem; max-width: 32ch; }

.explode__notes { grid-column: 3; align-self: center; display: grid; gap: 20px; max-width: 330px; }

/* All four are present from the first frame, as a legend of the parts that
   lights up as each one separates. They used to start at opacity 0 and appear
   one at a time from 42% of the scrub onward, which left the right third of a
   full-screen section empty for most of it — measured 0.6% ink.

   The inactive state is a colour change, not opacity. Fading text to ~0.3 would
   have taken it to roughly 2:1 against the paper; --text-2 is 8.9:1 in both
   states and the active one is carried by the gold rule and the ink body copy. */
.explode__note {
    border-left: 2px solid var(--rule);
    padding-left: 16px;
    transition: border-color var(--t-mid) var(--ease-out),
                transform var(--t-mid) var(--ease-out);
}
.explode__note h3 {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.16em; color: var(--text-2);
    margin-bottom: 8px;
    transition: color var(--t-mid) var(--ease-out);
}
.explode__note p {
    font-size: 1rem; color: var(--text-2);
    transition: color var(--t-mid) var(--ease-out);
}
.explode__note.is-on { border-left-color: var(--gold); transform: translateX(4px); }
.explode__note.is-on h3 { color: var(--gold-ink); }
.explode__note.is-on p { color: var(--text); }

.explode__progress {
    grid-column: 2; position: absolute; left: 50%; bottom: 18px;
    transform: translateX(-50%); width: min(280px, 60vw); height: 2px;
    background: var(--gold-soft);
}
.explode__progress i { display: block; height: 100%; width: 0; background: var(--gold); }

.explode__hint {
    position: absolute; left: 50%; bottom: 30px; transform: translateX(-50%);
    font-family: var(--mono); font-size: 0.8125rem; letter-spacing: 0.12em;
    text-transform: uppercase; color: var(--text-2); white-space: nowrap;
    transition: opacity var(--t-mid) var(--ease);
}

@media (max-width: 1000px) {
    .explode__sticky {
        grid-template-columns: 1fr;
        grid-template-rows: auto minmax(0, 1fr) auto;
        gap: 12px; padding-top: 88px;
    }
    .explode__stage { grid-row: 2; }
    .explode__intro, .explode__stage, .explode__notes, .explode__progress {
        grid-column: 1; justify-self: stretch; max-width: none;
    }
    .explode__intro { align-self: start; }
    .explode__intro h2 { font-size: 1.5rem; margin-bottom: 6px; }
    .explode__intro p { font-size: 0.9375rem; }
    .explode__notes {
        grid-row: 3; grid-template-columns: 1fr 1fr; gap: 12px; align-self: end;
    }
    .explode__note { padding-left: 10px; }
    .explode__note p { font-size: 0.875rem; }
    .explode__progress { position: static; width: 100%; transform: none; margin-top: 6px; }
}

/* Short viewports: the sticky stage is 100vh, so anything stacked above or
   below the pen is taken straight out of the pen's height. Measured at
   320x568 the four descriptions took 268px and left the stage 33px — the pen
   was effectively invisible. Keep the gold labels, drop the prose; the same
   detail is spelled out in the hardware rows below. */
@media (max-width: 1000px) and (max-height: 780px) {
    .explode__sticky { padding-top: 80px; padding-bottom: 18px; gap: 10px; }
    .explode__intro p { display: none; }
    .explode__note p { display: none; }
    .explode__notes { grid-template-columns: 1fr 1fr; gap: 8px 14px; }
    .explode__note { padding-left: 8px; }
}

/* Landscape phones — wide but short. Stacking cannot work at 360px of height,
   so put the text back beside the pen the way the desktop layout does. */
@media (max-width: 1000px) and (max-height: 620px) and (min-width: 560px) {
    .explode__sticky {
        grid-template-columns: 1fr minmax(0, 190px) 1fr;
        grid-template-rows: minmax(0, 1fr);
        padding: 64px var(--gutter) 16px; gap: 18px;
    }
    .explode__intro {
        grid-column: 1; grid-row: 1;
        align-self: center; justify-self: end; max-width: 260px;
    }
    .explode__intro h2 { font-size: 1.25rem; }
    .explode__stage { grid-column: 2; grid-row: 1; align-self: stretch; }
    .explode__notes {
        grid-column: 3; grid-row: 1; align-self: center;
        grid-template-columns: 1fr; max-width: 260px; gap: 8px;
    }
    .explode__progress {
        grid-column: 2; grid-row: 1;
        position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%);
        width: min(200px, 34vw); margin-top: 0;
    }
}

/* --------------------------------------------------------------------------
   9. Data rows (spec lists)
   -------------------------------------------------------------------------- */
.rows { width: 100%; border-collapse: collapse; }
.rows tr { border-bottom: 1px solid var(--rule); }
.rows tr:first-child { border-top: 1px solid var(--rule); }
.rows th {
    text-align: left; font-family: var(--mono); font-size: 0.875rem;
    font-weight: 400; color: var(--text-2); padding: 13px 0; width: 52%;
}
.rows td {
    text-align: right; font-weight: 700; font-size: 1rem;
    padding: 13px 0; font-variant-numeric: tabular-nums;
}

.feature {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: clamp(24px, 4vw, 56px); align-items: start;
    padding-block: clamp(26px, 3.5vw, 44px);
    border-bottom: 1px solid var(--rule);
}
.feature:last-child { border-bottom: 0; }
.feature h3 {
    font-size: clamp(1.3rem, 2.2vw, 1.7rem); font-weight: 800;
    text-transform: uppercase; margin-bottom: 12px;
}
.feature p { color: var(--text-2); }
.feature p + p { margin-top: 12px; }
@media (max-width: 820px) { .feature { grid-template-columns: 1fr; } }

/* Blend bars, squared off */
.blend { display: grid; gap: 14px; }
.blend__top {
    display: flex; justify-content: space-between; align-items: baseline;
    font-family: var(--mono); font-size: 0.9375rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 5px;
}
.blend__pct { color: var(--gold-ink); font-variant-numeric: tabular-nums; }
.blend__track { height: 14px; background: var(--paper-3); }
.blend__fill { height: 100%; background: var(--gold); width: 0; transition: width 650ms var(--ease); }

/* --------------------------------------------------------------------------
   10. FAQ
   -------------------------------------------------------------------------- */
.faq { max-width: 900px; }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
    display: flex; align-items: center; justify-content: space-between; gap: 20px;
    min-height: 66px; padding: 16px 0; cursor: pointer; list-style: none;
    font-size: 1.0625rem; font-weight: 700;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--gold-ink); }
.faq summary::after {
    content: "+"; font-family: var(--mono); font-size: 1.5rem; font-weight: 400;
    line-height: 1; flex: none; transition: transform var(--t-mid) var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq__answer { padding-bottom: 22px; color: var(--text-2); max-width: 70ch; }
.faq details[open] .faq__answer { animation: reveal var(--t-mid) var(--ease); }
@keyframes reveal { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   11. Forms
   -------------------------------------------------------------------------- */
.form { display: grid; gap: 16px; max-width: 760px; }
.form__row { display: grid; gap: 16px; grid-template-columns: 1fr 1fr; }
.field { display: grid; gap: 6px; }
.field label {
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-2);
}
.input {
    width: 100%; min-height: var(--tap); padding: 12px 14px;
    background: var(--paper); border: 1px solid var(--rule-firm);
    font-size: 1.0625rem;
    transition: box-shadow var(--t-fast) var(--ease);
}
.input:focus { box-shadow: inset 0 0 0 2px var(--ink); outline-offset: 1px; }
textarea.input { min-height: 130px; resize: vertical; line-height: 1.55; }
select.input {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23101010' stroke-width='1.6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 14px center; padding-right: 40px;
}
.form__note { font-size: 0.9375rem; color: var(--text-2); padding-top: 8px; }
.form__msg { display: none; padding: 13px 16px; font-weight: 600; border-left: 4px solid; }
.form__msg.is-visible { display: block; }
.form__msg.is-ok  { background: #E6EFE8; color: var(--ok);  border-color: var(--ok); }
.form__msg.is-err { background: #F5E3E0; color: var(--err); border-color: var(--err); }
@media (max-width: 700px) { .form__row { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------------------
   12. Dialogs
   -------------------------------------------------------------------------- */
dialog {
    border: 2px solid var(--ink); padding: 0; margin: auto;
    color: var(--text); background: var(--paper);
    max-width: min(960px, calc(100vw - 24px));
    max-height: min(92vh, 920px); width: 100%;
}
dialog::backdrop { background: rgba(16,16,16,0.72); }
dialog[open] { animation: dlg-in var(--t-slow) var(--ease); }
@keyframes dlg-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }


/* --------------------------------------------------------------------------
   7. Filters and strain marks
   -------------------------------------------------------------------------- */
.filters {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding: 14px 0; border-bottom: 1px solid var(--rule);
}
.filters__label {
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-2);
    margin-right: 4px;
}
.chip {
    min-height: 44px; padding: 0 16px;
    font-family: var(--mono); font-size: 0.875rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    border: 1px solid var(--rule); color: var(--text);
    transition: background-color var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease);
}
.chip:hover { background: var(--paper-gold); border-color: var(--gold-soft); }
.chip[aria-pressed="true"] { background: var(--gold); color: var(--on-gold); border-color: var(--gold); }

/* Strain type: a square swatch and a mono code, never a pastel capsule. */
.strain { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.strain::before {
    content: ""; width: 11px; height: 11px; flex: none; background: var(--hybrid);
}
.strain--indica::before { background: var(--indica); }
.strain--sativa::before { background: var(--sativa); }

/* --------------------------------------------------------------------------
   12b. Product page — one page per flavour, not a dialog
   -------------------------------------------------------------------------- */
.prod {
    display: grid; grid-template-columns: 1.02fr 0.98fr;
    gap: clamp(24px, 4vw, 60px); align-items: start;
}
.prod > * { min-width: 0; }
.prod__body { display: grid; gap: 22px; align-content: start; }
/* The flavor's own name, at the display scale the rest of the site now uses.
   Uppercasing it cost the typeface its descenders and its optical size, which is
   most of what makes this face worth having. */
.prod__name {
    font-size: clamp(2.25rem, 5vw, 3.75rem); font-weight: 800;
    letter-spacing: -0.04em; line-height: 0.96;
}
.prod__desc { color: var(--text-2); font-size: var(--fs-lede); max-width: 46ch; }
.prod__grouptitle {
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-2);
    padding-bottom: 7px; border-bottom: 2px solid var(--ink); margin-bottom: 12px;
}
.prod__terps { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; }
.prod__terps li {
    font-family: var(--mono); font-size: 0.8125rem; padding: 6px 11px;
    border: 1px solid var(--rule-firm);
}

/* Gallery: front of the pack, the box on its own, and the back panel. All the
   frames are stacked and cross-faded on opacity, so switching one costs the
   compositor nothing — same reason the pen scrubber uses an <img>. */
.gal { display: grid; gap: 12px; }
.gal__stage {
    display: grid; background: var(--plate); border: 1px solid var(--rule);
    aspect-ratio: 4 / 5; overflow: hidden;
}
.gal__stage img {
    grid-area: 1 / 1; width: 100%; height: 100%; object-fit: contain;
    opacity: 0; transition: opacity var(--t-mid) var(--ease);
}
.gal__stage img.is-on { opacity: 1; }
.gal__thumbs { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.gal__thumb {
    display: grid; width: 100%; aspect-ratio: 1;
    background: var(--plate); border: 2px solid var(--rule); padding: 6px;
    transition: border-color var(--t-fast) var(--ease);
}
.gal__thumb img { width: 100%; height: 100%; object-fit: contain; }
.gal__thumb:hover { border-color: var(--gold-soft); }
.gal__thumb[aria-selected="true"] { border-color: var(--gold); }
.gal__cap {
    font-family: var(--mono); font-size: 0.8125rem; letter-spacing: 0.06em;
    text-transform: uppercase; color: var(--text-2);
}

/* Previous / next flavour, so the six pages read as one set */
.prodnav {
    display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
    background: var(--rule); border: 1px solid var(--rule);
}
.prodnav a {
    display: grid; gap: 4px; padding: 16px clamp(14px, 2vw, 22px);
    background: var(--paper); text-decoration: none; min-height: var(--tap);
    transition: background-color var(--t-fast) var(--ease);
}
.prodnav a:hover { background: var(--paper-gold); }
.prodnav a:last-child { text-align: right; }
.prodnav span {
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 600;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-2);
}
.prodnav strong { font-size: 1.0625rem; font-weight: 700; }

@media (max-width: 860px) {
    .prod { grid-template-columns: 1fr; }
    .gal__stage { aspect-ratio: 1 / 1; }
}
@media (max-width: 420px) {
    .prodnav { grid-template-columns: 1fr; }
    .prodnav a:last-child { text-align: left; }
}

/* An explicit width, not just a max-width. A dialog defaults to `fit-content`,
   and setting only `max-width: 460px` replaces the UA's viewport-relative cap
   (`calc(100% - 6px - 2em)`) with a fixed one — so the box grew to its
   max-content width, 369px, and overflowed every screen narrower than that. */
.agegate { width: calc(100% - 24px); max-width: 460px; }
.agegate__inner { padding: clamp(26px, 4vw, 40px); display: grid; gap: 14px; }
.agegate img { height: 30px; width: auto; margin-bottom: 4px; }
.agegate h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); font-weight: 800; letter-spacing: -0.03em; }
.agegate p { color: var(--text-2); }
.agegate__actions { display: grid; gap: 8px; margin-top: 6px; }
.agegate__actions .btn { width: 100%; }
.agegate__fine { font-family: var(--mono); font-size: 0.8125rem; color: var(--text-2); }

/* --------------------------------------------------------------------------
   13. Lab results
   -------------------------------------------------------------------------- */
.lab { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: clamp(20px, 3vw, 40px); align-items: start; }
.lab__list { list-style: none; display: grid; position: sticky; top: 90px; border-top: 1px solid var(--rule); }
.lab__btn {
    display: grid; gap: 2px; width: 100%; min-height: 62px; padding: 11px 12px;
    text-align: left; border-bottom: 1px solid var(--rule); background: var(--paper);
    transition: background-color var(--t-fast) var(--ease);
}
.lab__btn:hover { background: var(--paper-2); }
.lab__btn[aria-selected="true"] { background: var(--gold); color: var(--on-gold); }
.lab__btn strong { font-size: 1rem; font-weight: 700; }
.lab__btn span { font-family: var(--mono); font-size: 0.8125rem; color: var(--text-2); }
.lab__btn[aria-selected="true"] span { color: var(--on-gold); }

.lab__panel { border: 2px solid var(--ink); }
.lab__head {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 14px; padding: 16px 20px; border-bottom: 2px solid var(--ink); background: var(--paper-2);
}
.lab__headtitle { font-size: 1.25rem; font-weight: 800; text-transform: uppercase; }
/* Provenance strip: which laboratory, which batch, which date. It replaced the
   note that used to explain a certificate shared between flavors, now that each
   flavor has its own. Cells divide on the gap, same trick as .facts. */
.lab__facts {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1px; background: var(--rule); border-bottom: 1px solid var(--rule);
}
.lab__facts > div { background: var(--paper); padding: 12px 20px; }
.lab__facts dt {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 500;
    letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-2);
}
.lab__facts dd {
    margin-top: 4px; font-family: var(--mono); font-size: 0.9375rem;
    font-weight: 600; overflow-wrap: anywhere;
}
.lab__doc { padding: clamp(12px, 2vw, 24px); background: var(--paper-3); }
.lab__doc img { width: 100%; border: 1px solid var(--rule-firm); background: #fff; border-radius: var(--r-sm); }
.lab__doc p { color: var(--text-2); }
.lab__files { list-style: none; display: grid; gap: 2px; margin-top: 16px; }
.lab__files a {
    display: block; padding: 13px 16px; min-height: var(--tap);
    background: var(--paper); border-radius: var(--r-sm);
    font-family: var(--mono); font-size: 0.9375rem; text-decoration: none;
}
.lab__files a:hover { background: var(--paper-gold); }
.lab__empty { padding: 40px 20px; text-align: center; color: var(--text-2); }
@media (max-width: 900px) {
    .lab { grid-template-columns: 1fr; }
    .lab__list {
        position: static; grid-auto-flow: column; grid-auto-columns: minmax(170px, 1fr);
        overflow-x: auto; border: 1px solid var(--rule);
    }
    .lab__btn { border-bottom: 0; border-right: 1px solid var(--rule); }
}

/* --------------------------------------------------------------------------
   15. Page head / prose
   -------------------------------------------------------------------------- */
.pagehead { padding-block: clamp(44px, 7vw, 104px) clamp(30px, 4.5vw, 60px); }
.crumbs {
    display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: clamp(18px, 2.4vw, 30px);
    font-family: var(--mono); font-size: var(--fs-meta); text-transform: uppercase;
    letter-spacing: 0.14em; color: var(--text-2);
}
.crumbs a { color: var(--gold-ink); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.pagehead h1 {
    font-size: clamp(2.5rem, 7vw, 5.5rem); font-weight: 800;
    letter-spacing: -0.04em; margin-bottom: clamp(16px, 2vw, 24px);
}
.pagehead p { color: var(--text-2); max-width: 56ch; font-size: var(--fs-lede); }

/* --- Editorial masthead --------------------------------------------------
   Every inner page opened on a heading and a paragraph over empty white, which
   is why they read as plain next to the home page: nothing to look at above the
   fold and no sense of a brand. .phead gives each one a real masthead with a
   photograph carrying its own weight, on a ground that changes page to page so
   they stop feeling like one template repeated.

   .pagehead stays for the legal pages, where plain is the correct answer. */
.phead { position: relative; overflow: hidden; padding-block: clamp(30px, 4vw, 52px) 0; }
.phead__grid {
    display: grid; gap: clamp(26px, 4vw, 60px); align-items: center;
    padding-bottom: clamp(40px, 6vw, 84px);
}
.phead__body { min-width: 0; }
.phead h1 {
    font-size: clamp(2.75rem, 7.4vw, 6.25rem); font-weight: 800;
    letter-spacing: -0.045em; line-height: 0.92;
    margin-bottom: clamp(16px, 2vw, 26px);
}
.phead__lede {
    color: var(--text-2); max-width: 46ch; font-size: var(--fs-lede);
}
/* An inline link inside the lede, not a standalone call to action. .link is
   mono, uppercase and letter-spaced, which reads as a button dropped into the
   middle of a sentence. */
.phead__lede a {
    color: var(--gold-ink); font-weight: 700;
    text-decoration: underline; text-decoration-thickness: 2px;
    text-underline-offset: 3px;
    /* Padding on an inline element grows the hit area without touching the line
       box, so the thumb target is taller than the 22px of type. A link inside a
       sentence is exempt from the 48px floor (WCAG 2.5.8 excludes targets in
       running text) — but bigger is still better on a phone. */
    padding: 9px 0;
}
.phead--ink .phead__lede a { color: var(--gold-soft); }
.phead__media {
    position: relative; min-width: 0;
    display: grid; place-items: center;
}
.phead__media img { width: 100%; height: auto; display: block; }
/* The pen renders carry their own alpha, so they need no plate behind them and
   read as an object on the page rather than a picture in a box. */
.phead__media--pen img { max-height: clamp(300px, 42vw, 560px); width: auto; }
.phead__stats {
    display: flex; flex-wrap: wrap; gap: clamp(20px, 3.4vw, 52px);
    margin-top: clamp(24px, 3vw, 38px);
    padding-top: clamp(20px, 2.6vw, 30px); border-top: 1px solid var(--rule);
}
.phead__stat { display: grid; gap: 4px; }
.phead__stat b {
    font-size: clamp(1.5rem, 2.6vw, 2.125rem); font-weight: 800;
    letter-spacing: -0.03em; line-height: 1;
}
.phead__stat span {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.14em; color: var(--text-2);
}
@media (min-width: 900px) {
    .phead__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); }
    .phead--wide .phead__grid { grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr); }
}
/* Grounds. Each page picks one so the set reads as a family, not a template. */
.phead--band { background: var(--paper-2); }
.phead--ink { background: var(--ink); color: var(--on-ink); }
.phead--ink .crumbs { color: var(--on-ink-2); }
.phead--ink .crumbs a { color: var(--gold-soft); }
.phead--ink .phead__lede { color: var(--on-ink-2); }
.phead--ink .phead__stats { border-top-color: rgba(255, 255, 255, 0.18); }
.phead--ink .phead__stat span { color: var(--on-ink-2); }

.prose { max-width: 76ch; }
.prose h2 {
    font-size: clamp(1.2rem, 2.2vw, 1.5rem); font-weight: 800; text-transform: uppercase;
    margin-top: 36px; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 2px solid var(--ink);
}
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: 1.0625rem; margin-top: 22px; margin-bottom: 6px; }
.prose p, .prose li { color: var(--text-2); }
.prose p { margin-bottom: 14px; }
.prose ul, .prose ol { margin: 0 0 16px 20px; display: grid; gap: 6px; }
.prose a { color: var(--gold-ink); font-weight: 600; }
.prose__meta {
    font-family: var(--mono); font-size: 0.875rem; color: var(--text-2);
    padding: 12px 16px; border: 1px solid var(--rule-firm); margin-bottom: 30px;
}

/* --------------------------------------------------------------------------
   16. Footer
   -------------------------------------------------------------------------- */
/* Ink and centred. It was four left-aligned columns on paper; the owner sent a
   reference and asked for the bottom of the page to look more put together,
   which in that reference means one centred stack, a subscribe field, and a
   quiet line of legal underneath. The dark ground bookends the page against the
   gold band under the hero. */
.footer {
    background: var(--ink); color: var(--on-ink);
    padding-block: clamp(52px, 7vw, 88px) clamp(28px, 3.4vw, 40px);
}
.footer__inner {
    display: grid; justify-items: center; text-align: center;
    gap: clamp(22px, 3vw, 32px);
}
.footer__mark { height: 37px; width: auto; }
.footer__tag {
    font-weight: 700; font-size: 1.0625rem; color: var(--gold);
    margin-top: -12px;
}

/* The link stack. Rows on a phone, a wrapped line from 560px up: six items in a
   single column is a lot of scrolling for something nobody came here to read. */
.footer__nav {
    display: flex; flex-direction: column; align-items: center;
    gap: 2px; width: 100%; max-width: 420px;
}
@media (min-width: 560px) {
    .footer__nav {
        flex-flow: row wrap; justify-content: center;
        column-gap: clamp(14px, 2.2vw, 30px); row-gap: 0;
        /* Narrow enough to break three and three. At 720px it fitted five and
           orphaned the sixth; at 560 it fitted four and left two adrift under
           them. Measured: a row of three is 392px, a row of four is 511px. */
        max-width: 440px;
    }
}
.footer__nav a {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: var(--tap); padding: 8px 12px;
    font-size: 1.0625rem; font-weight: 600; color: var(--on-ink);
    text-decoration: none; border-radius: var(--r-sm);
    transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.footer__nav a:hover { color: var(--gold); background: rgba(255, 255, 255, 0.07); }

/* --- subscribe ------------------------------------------------------------ */
.footer__sub { width: 100%; max-width: 470px; display: grid; justify-items: center; }
.footer__subtitle {
    font-family: var(--mono); font-size: var(--fs-meta); line-height: 1.6;
    letter-spacing: 0.08em; color: var(--on-ink-2); margin-bottom: 14px;
    /* Wider than the field it labels, so the sentence breaks evenly instead of
       dropping one word onto a second line. */
    width: max-content; max-width: min(100vw - 2 * var(--gutter), 52ch);
    text-wrap: balance;
}
/* Field and button share one pill. Below 420px they stack, because a 48px tap
   target either side of a usable input does not fit on a 320px screen. */
.footer__field {
    display: grid; gap: 8px; width: 100%;
}
@media (min-width: 420px) {
    .footer__field {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0; padding: 5px; border-radius: var(--r-pill);
        background: rgba(255, 255, 255, 0.08);
        border: 1px solid rgba(255, 255, 255, 0.2);
        transition: border-color var(--t-fast) var(--ease);
    }
    .footer__field:focus-within { border-color: var(--gold); }
    .footer__input { background: transparent; border: 0; padding-inline: 18px; }
    .footer__input:focus { box-shadow: none; }
}
.footer__input {
    width: 100%; min-height: 48px; padding: 12px 16px;
    font-size: 1.0625rem; color: var(--on-ink);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.2); border-radius: var(--r-pill);
}
.footer__input::placeholder { color: rgba(255, 255, 255, 0.5); }
.footer__go {
    min-height: 48px; padding: 12px 26px; cursor: pointer;
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.14em; text-transform: uppercase;
    background: var(--gold); color: var(--on-gold);
    border: 1px solid var(--gold); border-radius: var(--r-pill);
    transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.footer__go:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }
.footer__go[disabled] { opacity: 0.6; cursor: default; }
.footer__sub .form__msg { margin-top: 12px; width: 100%; }

/* --- the quiet end -------------------------------------------------------- */
.footer__legal {
    font-size: var(--fs-meta); line-height: 1.7; color: var(--on-ink-2);
    max-width: 92ch; padding-top: clamp(14px, 2vw, 22px);
    border-top: 1px solid rgba(255, 255, 255, 0.14); width: 100%;
}
.footer__fine {
    display: flex; flex-wrap: wrap; justify-content: center;
    align-items: center; gap: 6px clamp(14px, 2.4vw, 26px);
    font-family: var(--mono); font-size: var(--fs-meta); color: var(--on-ink-2);
}
.footer__fine a {
    display: inline-flex; align-items: center; min-height: 44px;
    color: var(--on-ink-2); text-decoration: none;
}
.footer__fine a:hover { color: var(--on-ink); text-decoration: underline; }

/* --------------------------------------------------------------------------
   17. Reveal — the only scroll-linked motion outside the pen scrubber
   -------------------------------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(10px); transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease); }
.reveal.is-in { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }

.no-js #productGrid, .no-js #productFilters, .no-js #productCount,
.no-js #labList, .no-js #labPanel,
.no-js .header__toggle, .no-js .explode__track { display: none; }

/* Without scripts the reveal classes never get .is-in, so every one of them has
   to fall back to its finished state. Missing this hid the entire page below the
   headline — and a text-length check cannot catch it, because innerText still
   returns text that is sitting at opacity 0. */
.no-js .up, .no-js .stagger > * { opacity: 1; transform: none; }
.no-js .rise > span { transform: none; }
.no-js .para { transform: none; }
.no-js .progress { display: none; }
/* Without JS nothing ever gets .is-in, so every primitive has to resolve to its
   finished state here. A missing line in this block does not degrade the motion,
   it renders the section blank — that has happened twice. */
.no-js .mask > img, .no-js .mask > picture > img { clip-path: none; transform: none; }
.no-js .zoom > img { opacity: 1; transform: none; }
.no-js .word > i { transform: none; }
.no-js .dsp__in { transform: none; }
.no-js .header__nav-wrap { display: flex; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .reveal { opacity: 1; transform: none; }
    /* Every entrance primitive lands in its finished state */
    .up, .stagger > * { opacity: 1 !important; transform: none !important; }
    .rise > span { transform: none !important; }
    .para { transform: none !important; }
    .mask > img, .mask > picture > img { clip-path: none !important; transform: none !important; }
    .zoom > img { opacity: 1 !important; transform: none !important; }
    .tilt > * { transform: none !important; }
    .mhov:hover img { transform: none !important; }
    .word > i { transform: none !important; }
    .dsp__in { transform: none !important; }
    .hero__scroll span { animation: none !important; }
    .marquee__track { animation: none !important; }
    .cursor { display: none !important; }
    .explode__note { opacity: 1; transform: none; }
    .explode__sticky { position: static; height: auto; }
    .explode__track { height: auto !important; }
}

@media print {
    .header, .footer, .skip-link, dialog, .explode { display: none !important; }
    body { background: #fff; }
}


/* --------------------------------------------------------------------------
   19. Photo plates and banners
   -------------------------------------------------------------------------- */
.plate {
    background: var(--plate);
    border: 1px solid var(--rule);
    display: grid; place-items: center;
    overflow: hidden;
}
.plate img { width: 100%; height: 100%; object-fit: cover; }
.plate--fit img { object-fit: contain; }


/* --------------------------------------------------------------------------
   20. Product cards (products.html)
   -------------------------------------------------------------------------- */
.pgrid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
    gap: clamp(14px, 2vw, 22px); list-style: none;
}
.pgrid > * { min-width: 0; }

.pcard {
    display: flex; flex-direction: column; width: 100%; height: 100%;
    background: var(--paper);
    text-align: left; text-decoration: none; color: inherit;
    transition: transform var(--t-mid) var(--ease-out), box-shadow var(--t-mid) var(--ease-out);
}
.pcard:hover { transform: translateY(-6px); box-shadow: var(--lift); }
.pcard__media {
    background: var(--plate); aspect-ratio: 82 / 100; overflow: hidden;
}
.pcard__media img {
    /* contain, not cover: the shots differ slightly in aspect and cover was
       clipping the pen. The plate is the same grey as the photo backdrop, so
       the letterboxing is invisible. */
    width: 100%; height: 100%; object-fit: contain;
    transition: transform var(--t-slow) var(--ease);
}
.pcard:hover .pcard__media img { transform: scale(1.06); }
.pcard__body { padding: 16px 18px 20px; display: grid; gap: 8px; flex: 1; align-content: start; }
.pcard__name { font-size: 1.375rem; font-weight: 700; letter-spacing: -0.025em; }
.pcard__terps { font-family: var(--mono); font-size: 0.8125rem; color: var(--text-2); }
.pcard__nums {
    display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 2px;
    font-family: var(--mono); font-size: 0.8125rem; font-variant-numeric: tabular-nums;
}
.pcard__nums b { font-weight: 600; }
.pcard__cue {
    margin-top: auto; padding-top: 14px;
    font-family: var(--mono); font-size: 0.8125rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.06em; color: var(--gold-ink);
}

/* --------------------------------------------------------------------------
   21. Signpost cards — where the homepage sends you instead of scrolling
   -------------------------------------------------------------------------- */
/* A stack of oversized index rows rather than a 4-up grid of boxed cards. The
   whole row is the target, the heading slides on hover, and the rule under each
   is the only line involved. */
.signposts { list-style: none; border-top: 1px solid var(--rule); }
/* Explicit placement, because auto-placement put the numeral and the heading on
   row one and the description on row two: the tall numeral then stretched row
   one and opened a gap between each heading and its own description. The numeral
   and the call to action span both rows and centre across them instead. */
.signpost {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start; column-gap: clamp(16px, 3vw, 48px); row-gap: 8px;
    padding: clamp(22px, 3.2vw, 40px) 0;
    border-bottom: 1px solid var(--rule);
    text-decoration: none; position: relative; isolation: isolate;
}
.signpost__n, .signpost__go { grid-row: 1 / span 2; align-self: center; }
/* A gold wash sweeps up behind the row on hover */
.signpost::before {
    content: ""; position: absolute; inset: 0 calc(var(--gutter) * -0.5); z-index: -1;
    background: var(--paper-gold); transform: scaleY(0); transform-origin: 50% 100%;
    transition: transform var(--t-mid) var(--ease-out);
}
.signpost:hover::before { transform: scaleY(1); }
/* A display numeral, not a 13px mono label. It fills the left column, which is
   what stops the row from reading as four lines of text in a lot of white. */
.signpost__n {
    font-size: clamp(1.75rem, 4vw, 3.25rem); font-weight: 800;
    letter-spacing: -0.04em; line-height: 1;
    /* --gold, not --gold-soft. The hairline token is 1.49:1 on white and is for
       rules, not glyphs; the live contrast audit caught it. --gold is 3.2:1,
       which clears the 3:1 that applies to text at this size. */
    color: var(--gold); flex: none;
    transition: color var(--t-mid) var(--ease-out);
}
.signpost:hover .signpost__n { color: var(--gold-ink); }
.signpost h3 {
    font-size: clamp(1.5rem, 3.4vw, 2.5rem); font-weight: 800;
    letter-spacing: -0.035em;
    transition: transform var(--t-mid) var(--ease-out);
}
.signpost:hover h3 { transform: translateX(10px); }
.signpost p {
    font-size: 1.0625rem; color: var(--text-2); max-width: 52ch;
    grid-column: 2; grid-row: 2;
}
.signpost__go {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.12em; white-space: nowrap;
    color: var(--gold-ink); justify-self: end;
    transition: transform var(--t-mid) var(--ease-out);
}
.signpost:hover .signpost__go { transform: translateX(8px); }
@media (max-width: 720px) {
    /* Three rows here, and the row placement above has to be undone explicitly.
       Left as-is, .signpost__go stayed pinned to rows 1-2 of the text column,
       where its `white-space: nowrap` set that column's minimum width and pushed
       the whole page wider than a 320px screen. */
    .signpost { grid-template-columns: auto minmax(0, 1fr); }
    .signpost__n { grid-row: 1 / span 3; }
    .signpost__go {
        grid-column: 2; grid-row: 3;
        justify-self: start; align-self: start; margin-top: 10px;
    }
}

/* --------------------------------------------------------------------------
   22. Split — photo beside prose, used on the content pages
   -------------------------------------------------------------------------- */
.split {
    display: grid; grid-template-columns: 0.85fr 1.15fr;
    gap: clamp(20px, 4vw, 52px); align-items: start;
}
.split > * { min-width: 0; }
/* Detail shots are 1000-1650px tall. Left unbounded inside a split they run
   far past the prose beside them, so cap every plate in a split. */
.split .plate { align-self: start; }
.split .plate img { max-height: 520px; width: auto; object-fit: contain; }
.split h3 { font-size: clamp(1.25rem, 2.2vw, 1.6rem); font-weight: 800; text-transform: uppercase; margin-bottom: 12px; }
.split p { color: var(--text-2); }
.split p + p { margin-top: 12px; }
@media (max-width: 860px) {
    .split { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   22b. Closing band — the last thing above the footer
   -------------------------------------------------------------------------- */

/* Numbered steps, for "how to use" */
.steps { list-style: none; counter-reset: s; display: grid; gap: 0; border-top: 1px solid var(--rule); }
.steps li {
    counter-increment: s; display: grid;
    /* The counter spans both rows so the title and the detail stack in one
       column. Without the explicit placement the third child wraps back under
       the number and the text right-aligns. */
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto;
    gap: 4px 16px;
    padding: 16px 0; border-bottom: 1px solid var(--rule);
}
.steps li::before {
    content: counter(s, decimal-leading-zero);
    grid-column: 1; grid-row: 1 / span 2;
    font-family: var(--mono); font-weight: 600; color: var(--gold-ink); font-size: 0.9375rem;
    line-height: 1.45;
}
.steps strong { grid-column: 2; grid-row: 1; font-size: 1.0625rem; text-align: left; }
.steps span { grid-column: 2; grid-row: 2; color: var(--text-2); font-size: 1rem; text-align: left; }

/* --------------------------------------------------------------------------
   23. Editorial layer — the reference build's language

   The owner prototyped the direction he wants in an AI site builder and sent
   video of it. This section is that language translated into the static
   architecture here: a warm off-white ground, gold hairline eyebrows, display
   lines that mix an outlined word with a solid one or hand the whole line to a
   gold serif italic, bordered fact grids, and line-icon topic blocks.
   -------------------------------------------------------------------------- */

.ed { background: var(--bone); }

/* --- eyebrow -------------------------------------------------------------
   13px, not the 10-11px of the reference build. 13 is this site's floor for
   label text, and at 0.3em tracking the difference in presence is negligible
   while the difference in legibility is not. */
.eyebrow {
    font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.3em; text-transform: uppercase;
    color: var(--gold-ink); margin-bottom: clamp(14px, 2vw, 22px);
}

/* --- the display line ----------------------------------------------------
   "THC-A, / explained." — first word outlined, rest solid. The Collection
   masthead takes the .dsp--ser variant below instead, which hands the whole
   line to the serif. */
.dsp {
    font-size: clamp(2.75rem, 7vw, 5.75rem);
    font-weight: 800; letter-spacing: -0.03em; line-height: 0.98;
}
.dsp b { font-weight: 800; }
/* The outline has to be opt-in behind @supports. text-stroke with a
   transparent fill is the whole effect, and where it is unsupported that pair
   renders the word invisible rather than merely unstyled. */
.dsp__out { font-weight: 800; }
@supports (-webkit-text-stroke: 1px currentColor) {
    .dsp__out {
        -webkit-text-stroke: clamp(1px, 0.16vw, 2px) var(--ink);
        color: transparent;
    }
}
/* Each line reveals from its own clip. Deliberately NOT data-rise: that splitter
   reads textContent and rebuilds the element, which would throw away the
   outline and serif spans this headline is made of. The lines are already
   explicit in the markup, so nothing needs measuring and nothing gets rewritten.
   The padding/margin pair keeps descenders and the stroke out of the clip. */
.dsp__line {
    display: block; overflow: hidden;
    padding-bottom: 0.14em; margin-bottom: -0.14em;
}
.dsp__line + .dsp__line { padding-left: clamp(0px, 4vw, 84px); }
.dsp__in {
    display: block;
    transform: translateY(106%);
    transition: transform var(--t-reveal) var(--ease-out);
    transition-delay: calc(var(--i, 0) * 90ms);
}
.dsp.is-in .dsp__in { transform: none; }

.ed__lede {
    margin-top: clamp(20px, 2.6vw, 30px);
    max-width: 46ch; font-size: var(--fs-lede); color: var(--text-2);
}

/* --- serif display variant -----------------------------------------------
   Cormorant italic carrying a whole headline instead of one accent word. It is
   a high-contrast face with a small x-height, so it needs more optical size
   and more room under the baseline than the Figtree display line does. */
.dsp--ser {
    font-family: var(--serif); font-style: italic; font-weight: 500;
    font-size: clamp(3rem, 8.4vw, 6.75rem);
    letter-spacing: -0.005em; line-height: 1;
}
.dsp--ser em { font-style: italic; color: var(--gold-ink); }
/* Descenders on an italic serif sit deeper than the sans ones this clip was
   sized for; without the extra room the reveal shears the tails off. */
.dsp--ser .dsp__line { padding-bottom: 0.22em; margin-bottom: -0.22em; }
.dsp--ser .dsp__line + .dsp__line { padding-left: clamp(0px, 3vw, 62px); }

/* --- masthead: heading one side, summary the other ------------------------
   Below 900px the aside stacks under the heading and the leading paragraph
   loses its top margin, so the pair reads as one block rather than two. */
.mast { display: grid; gap: clamp(24px, 4vw, 44px); }
@media (min-width: 900px) {
    .mast {
        grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
        column-gap: clamp(44px, 6vw, 104px);
        align-items: start;
    }
    /* Drop the summary past the eyebrow so its first line starts level with the
       headline rather than with the label above it. Bottom-aligning the two
       columns instead reads well only while they happen to be the same height,
       and the summary grows a line every time the column narrows. */
    .mast__aside { padding-top: clamp(28px, 3.4vw, 46px); }
}
.mast__aside > .ed__lede:first-child { margin-top: 0; }

/* --- fact strip ----------------------------------------------------------
   A hairline grid whose lines are the gaps, so there are no double borders
   where cells meet. */
.facts {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px; background: var(--hair);
    border: 1px solid var(--hair);
    /* The cells paint their own background right up to the frame, so without a
       clip their square corners sit proud of the rounded border. */
    overflow: hidden;
    margin-top: clamp(34px, 5vw, 62px);
}
@media (min-width: 800px) { .facts { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.facts > div { background: var(--paper); padding: clamp(18px, 2.6vw, 30px); }
.ed .facts > div { background: var(--bone); }
.facts dt {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 500;
    letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-2);
}
.facts dd { margin-top: 8px; font-size: clamp(1.0625rem, 1.6vw, 1.3125rem); font-weight: 700; letter-spacing: -0.02em; }

/* --- icon topics ---------------------------------------------------------- */
.topics {
    display: grid; gap: clamp(38px, 5vw, 64px);
    margin-top: clamp(46px, 7vw, 96px);
}
@media (min-width: 820px) { .topics { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(48px, 6vw, 96px); } }
.topic__icon { width: 28px; height: 28px; color: var(--gold-ink); display: block; }
.topic h3 {
    margin-top: 18px; font-size: clamp(1.5rem, 3vw, 2.125rem);
    font-weight: 800; letter-spacing: -0.03em;
}
.topic p { margin-top: 14px; font-size: 1.0625rem; line-height: 1.7; color: var(--text-2); }

/* --- gold buttons --------------------------------------------------------- */
.gbtn {
    display: inline-flex; align-items: center; justify-content: center; gap: 12px;
    min-height: 54px; padding: 14px 32px;
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.22em; text-transform: uppercase; text-decoration: none;
    background: var(--gold); color: var(--on-gold);
    border: 1px solid var(--gold);
    transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.gbtn:hover { background: var(--on-gold); border-color: var(--on-gold); color: var(--paper); }
.gbtn svg { width: 16px; height: 16px; flex: none; }
.gbtn--out { background: transparent; color: var(--gold-ink); border-color: var(--gold); }
.gbtn--out:hover { background: var(--gold); color: var(--on-gold); border-color: var(--gold); }

/* --- product panel -------------------------------------------------------- */
.panel {
    background: var(--bone); border: 1px solid var(--hair);
    display: grid; place-items: center; overflow: hidden;
    padding: clamp(18px, 3vw, 40px);
}
.panel img { width: auto; max-width: 100%; max-height: 55vh; height: auto; display: block; }

/* --- two-column feature row ---------------------------------------------- */
.duo {
    display: grid; gap: clamp(30px, 5vw, 64px); align-items: center;
    margin-top: clamp(52px, 8vw, 112px);
}
@media (min-width: 960px) { .duo { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.duo h2 { font-size: clamp(1.75rem, 3.4vw, 2.5rem); font-weight: 800; letter-spacing: -0.03em; margin-top: 4px; }
.duo p { margin-top: 18px; font-size: 1.0625rem; line-height: 1.7; color: var(--text-2); max-width: 46ch; }
.duo .btn-row { margin-top: clamp(26px, 3.4vw, 36px); }

/* --- strain finder -------------------------------------------------------- */
.finder { max-width: 900px; margin-inline: auto; text-align: center; }
.finder__head p { color: var(--text-2); font-size: var(--fs-lede); max-width: 52ch; margin-inline: auto; }
.finder__title { font-size: clamp(1.875rem, 4.4vw, 3rem); font-weight: 800; letter-spacing: -0.03em; margin-bottom: 16px; }

.finder__bars {
    display: flex; gap: 10px; justify-content: center; list-style: none;
    margin: clamp(28px, 4vw, 44px) auto clamp(26px, 3.4vw, 40px); max-width: 420px;
}
.finder__bars li {
    flex: 1; height: 2px; background: var(--rule);
    transition: background-color var(--t-mid) var(--ease);
}
.finder__bars li.is-on { background: var(--gold); }

.finder__step { border: 0; padding: 0; margin: 0; }
.finder__step legend { display: block; width: 100%; padding: 0; }
.finder__num {
    display: block; font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.24em; text-transform: uppercase; color: var(--text-2); margin-bottom: 10px;
}
.finder__q {
    display: block; font-size: clamp(1.375rem, 3vw, 2rem);
    font-weight: 800; letter-spacing: -0.03em; margin-bottom: clamp(22px, 3vw, 34px);
}
.finder__opts { display: grid; gap: 12px; }
@media (min-width: 760px) { .finder__opts { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* The radio covers the whole card at zero opacity rather than sitting in a
   corner at 1x1. It stays the real control — focusable, announced, checkable —
   and it is also the full 88px tap target, instead of depending on the label to
   forward the click to something a thumb could never hit. */
.fopt {
    position: relative; display: block; text-align: left; cursor: pointer;
    background: var(--paper); border: 1px solid var(--hair);
    padding: clamp(16px, 2.2vw, 22px); min-height: 88px;
    transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.fopt input {
    position: absolute; inset: 0; width: 100%; height: 100%;
    margin: 0; opacity: 0; cursor: pointer; appearance: none;
}
.fopt b { display: block; font-size: 1.125rem; font-weight: 700; letter-spacing: -0.02em; }
.fopt span {
    display: block; margin-top: 6px;
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 500;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-2);
}
.fopt:hover { border-color: var(--gold); }
.fopt:has(input:focus-visible) { outline: 3px solid var(--gold-ink); outline-offset: 2px; }
.fopt:has(input:checked) { border-color: var(--gold); background: var(--paper-gold); }

.finder__result { margin-top: clamp(28px, 4vw, 44px); }
.finder__result h3 { font-size: clamp(1.875rem, 4.4vw, 3rem); font-weight: 800; letter-spacing: -0.03em; }
.finder__result p { color: var(--text-2); font-size: var(--fs-lede); max-width: 48ch; margin: 14px auto 0; }
.finder__result .btn-row { justify-content: center; margin-top: clamp(24px, 3vw, 32px); }

.no-js #strainFinder { display: none; }

/* --- product masthead ----------------------------------------------------- */
.pmast {
    display: grid; gap: clamp(30px, 5vw, 64px); align-items: center;
    padding-bottom: clamp(40px, 6vw, 76px);
}
@media (min-width: 960px) { .pmast { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); } }
.pmast__name { font-size: clamp(2.5rem, 6.4vw, 5rem); }
/* The tagline is the second line of the display pair, so it sits at display size
   but a step down from the name it belongs to. */
.pmast__tag { display: block; font-size: 0.5em; letter-spacing: -0.02em; }
/* Three across only once there is room for it. Forcing three columns at every
   width put "2000 MG | 0.071 OZ" into a ~110px cell on a 360px screen, which it
   cannot wrap into, and the whole document overflowed by 7px. */
.pmast__facts { margin-top: clamp(26px, 3.4vw, 38px); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 560px) { .pmast__facts { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.pmast__facts dd { font-size: clamp(0.9375rem, 1.4vw, 1.125rem); }
/* Each flavor carries its own strain colour on the primary action. */
.pmast__cta { background: var(--accent, var(--gold)); border-color: var(--accent, var(--gold)); color: #FFF; }
.pmast__cta:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.pmast__media img { max-height: 60vh; }

/* --- Master Case block ---------------------------------------------------- */
.mclist__title {
    margin-top: clamp(24px, 3vw, 32px);
    font-size: clamp(1.125rem, 1.8vw, 1.375rem); font-weight: 800;
    letter-spacing: -0.02em;
}
.mclist {
    margin-top: 14px; list-style: none;
    display: grid; gap: 10px; max-width: 46ch;
}
.mclist li {
    position: relative; padding-left: 22px;
    font-size: 1.0625rem; line-height: 1.6; color: var(--text-2);
}
.mclist li::before {
    content: ""; position: absolute; left: 0; top: 0.62em;
    width: 7px; height: 7px; background: var(--gold);
}
.mclist li strong { color: var(--text); font-weight: 700; }
/* The closing line, promoted so it lands as a claim rather than another
   paragraph. */
.mclist__sign {
    margin-top: clamp(22px, 2.8vw, 30px) !important;
    font-size: clamp(1.125rem, 1.9vw, 1.4375rem) !important;
    font-weight: 700; letter-spacing: -0.02em; line-height: 1.35;
    color: var(--gold-ink) !important; max-width: 34ch;
}
/* The stack is tall (0.71 aspect). Cap it so the row stays balanced against a
   text column this long. */
.mclist__media img { max-height: clamp(420px, 62vh, 680px); width: auto; max-width: 100%; }
.mclist__media { display: grid; place-items: center; }


/* ==========================================================================
   24. Radius

   Everything that softens the corners, in one place. The original build was
   zero-radius by policy; the owner circled the button and card corners and
   asked for the sharp edges off "everything the boxes the pictures etc", so
   the policy is now a scale rather than a zero.

   What is deliberately NOT rounded: full-bleed bands (the ticker, the ink and
   gold section grounds, the hero backdrop) and rule-based lists (tables, the
   FAQ, breadcrumbs). Those have no box to round — a radius on a band that runs
   to both edges of the window only shows as two odd notches.
   ========================================================================== */

/* --- controls ------------------------------------------------------------- */
.btn, .gbtn, .header__toggle { border-radius: var(--r-md); }
.input, textarea.input, select.input { border-radius: var(--r-md); }
.chip, .prod__terps li, .form__msg { border-radius: var(--r-sm); }
/* Already only 14px tall, so a pill is the honest shape. */
.blend__track, .blend__fill { border-radius: var(--r-pill); }

/* .btn paints its hover sweep in an ::after pinned to inset:0. The parent
   clips it (overflow is already hidden for that sweep), but Safari has
   historically leaked a square corner through a transformed child, so round
   the child to match. */
.btn::after { border-radius: inherit; }

/* --- cards and photo boxes ------------------------------------------------ */
.pcard { border-radius: var(--r-lg); overflow: hidden; }
.plate, .panel, .facts, .gal__stage, .fopt,
.show__media, .show .zoom, .pcard__media { border-radius: var(--r-lg); }
.gal__thumb { border-radius: var(--r-sm); }

/* Where the picture is letterboxed inside its box — object-fit: contain, or a
   panel with padding — the parent's clip never reaches the photo's own corners,
   so the picture keeps its square edges inside a rounded frame. Round the image
   itself in those cases. Boxes whose picture fills them edge to edge are
   already handled by the clip above. */
.panel img, .plate img, .gal__stage img { border-radius: var(--r-lg); }
.gal__thumb img { border-radius: var(--r-xs); }

/* The generic image wrappers. .mask and .zoom are what every photograph on the
   site is wrapped in, so this is the rule that actually takes the corners off
   the pictures. Both already clip their child. */
.mask, .zoom { border-radius: var(--r-lg); }

/* --- floating chrome ------------------------------------------------------ */
.agegate, .vip, .nudge { border-radius: var(--r-xl); }

/* --- markers -------------------------------------------------------------- */
/* Not fully round: at 11px and 7px a circle reads as a bullet, and these are
   meant to read as foil marks. Just enough to take the point off. */
.strain::before, .mclist li::before { border-radius: var(--r-xs); }

/* The gold wash behind a signpost row on hover. The row itself keeps its
   hairline rule — it is a list, not a card — but the wash is a shape, and a
   square one sliding up behind rounded everything-else looks like a mistake. */
.signpost::before { border-radius: var(--r-lg); }


/* ==========================================================================
   25. Overlays that ask for something

   Two of them, deliberately different weights.

   The VIP popup (home) is a real modal, because the owner's reference is one
   and because segmenting a visitor is a question, not a suggestion. It is ink
   rather than paper: the reference he sent is a dark overlay with outlined
   pill options, and the figures band already establishes ink as a ground here.

   The strain nudge (collection) is a corner card that never blocks anything.
   It appears while a visitor is halfway through looking at flavors, and a
   modal at that moment would interrupt exactly the thing it is offering to
   help with.
   ========================================================================== */

/* --- VIP popup ------------------------------------------------------------ */
.vip {
    width: calc(100% - 24px); max-width: 470px;
    background: var(--ink); color: var(--on-ink);
    border: 1px solid rgba(255, 255, 255, 0.16);
    box-shadow: var(--lift-2);
    position: relative; overflow: hidden;
}
.vip::backdrop { background: rgba(16, 16, 16, 0.74); }
/* A gold wash out of the top corner, so the black is not a flat rectangle. */
.vip__wash {
    position: absolute; inset: 0; pointer-events: none;
    background: radial-gradient(125% 95% at 14% -12%,
        rgba(184, 134, 43, 0.42), rgba(184, 134, 43, 0) 64%);
}
.vip__inner { position: relative; padding: clamp(30px, 4.6vw, 44px); }
.vip__step[hidden] { display: none; }

.vip__x {
    position: absolute; top: 8px; right: 8px; z-index: 2;
    width: var(--tap); height: var(--tap);
    display: grid; place-items: center;
    color: var(--on-ink-2); background: transparent; border: 0;
    border-radius: var(--r-pill); cursor: pointer;
    transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.vip__x:hover { color: var(--on-ink); background: rgba(255, 255, 255, 0.1); }
.vip__x svg { width: 18px; height: 18px; }

.vip__eyebrow {
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.26em; text-transform: uppercase; color: var(--gold);
    margin-bottom: 12px;
}
.vip__title {
    font-size: clamp(1.75rem, 4.6vw, 2.375rem); font-weight: 800;
    letter-spacing: -0.035em; line-height: 1.02;
}
.vip__sub { margin-top: 12px; color: var(--on-ink-2); font-size: 1.0625rem; }

/* Pills, following the reference: outlined at rest, gold foil on hover. */
.vip__choices { display: grid; gap: 10px; margin-top: clamp(22px, 3vw, 28px); }
.vip__choice {
    min-height: 56px; padding: 14px 22px; width: 100%; cursor: pointer;
    font-family: var(--mono); font-size: 0.9375rem; font-weight: 600;
    letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--on-ink); background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.44); border-radius: var(--r-pill);
    transition: background-color var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease);
}
.vip__choice:hover { background: var(--gold); border-color: var(--gold); color: var(--on-gold); }

.vip__no, .vip__back {
    background: transparent; border: 0; cursor: pointer; color: var(--on-ink-2);
    font-size: 1rem; text-decoration: underline; text-underline-offset: 3px;
}
.vip__no { display: block; margin: 18px auto 0; padding: 10px 14px; min-height: 44px; }
.vip__no:hover, .vip__back:hover { color: var(--on-ink); }

.vip__field { margin-top: clamp(20px, 2.8vw, 26px); }
.vip__input {
    background: rgba(255, 255, 255, 0.07);
    border-color: rgba(255, 255, 255, 0.38); color: var(--on-ink);
}
.vip__input::placeholder { color: rgba(255, 255, 255, 0.5); }
.vip__input:focus { box-shadow: inset 0 0 0 2px var(--gold); }
.vip__submit {
    margin-top: 10px; width: 100%; min-height: 56px; padding: 14px 22px; cursor: pointer;
    font-family: var(--mono); font-size: 0.9375rem; font-weight: 600;
    letter-spacing: 0.14em; text-transform: uppercase;
    background: var(--gold); color: var(--on-gold);
    border: 1px solid var(--gold); border-radius: var(--r-pill);
    transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.vip__submit:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }
.vip__submit[disabled] { opacity: 0.6; cursor: default; }
.vip__fine {
    margin-top: 14px; font-family: var(--mono); font-size: var(--fs-meta);
    line-height: 1.6; color: var(--on-ink-2);
}
.vip .form__msg { margin-top: 14px; }

/* --- strain nudge --------------------------------------------------------- */
.nudge {
    position: fixed; z-index: 120;
    left: 16px; right: 16px; bottom: 16px;
    display: grid; gap: 6px;
    padding: 18px 56px 18px 20px;
    background: var(--ink); color: var(--on-ink);
    box-shadow: var(--lift-2);
    /* Off-screen and inert until initFinderNudge reveals it, so it can never
       cover the grid before a visitor has scrolled into it. */
    transform: translateY(calc(100% + 24px));
    transition: transform var(--t-slow) var(--ease-out), opacity var(--t-mid) var(--ease);
}
@media (min-width: 620px) {
    .nudge { left: auto; right: 22px; bottom: 22px; width: min(360px, calc(100vw - 44px)); }
}
.nudge.is-in { transform: none; }
.nudge[hidden] { display: none; }
.nudge__title { font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.02em; }
.nudge__sub { font-size: 0.9375rem; line-height: 1.55; color: var(--on-ink-2); }
.nudge__go {
    justify-self: start; margin-top: 8px;
    display: inline-flex; align-items: center; gap: 10px;
    min-height: 44px; padding: 10px 20px;
    font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
    letter-spacing: 0.16em; text-transform: uppercase; text-decoration: none;
    background: var(--gold); color: var(--on-gold);
    border-radius: var(--r-pill);
    transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.nudge__go:hover { background: var(--paper); color: var(--ink); }
.nudge__go svg { width: 14px; height: 14px; flex: none; }
.nudge__x {
    position: absolute; top: 6px; right: 6px;
    width: 44px; height: 44px; display: grid; place-items: center;
    background: transparent; border: 0; cursor: pointer; color: var(--on-ink-2);
    border-radius: var(--r-pill);
    transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.nudge__x:hover { color: var(--on-ink); background: rgba(255, 255, 255, 0.1); }
.nudge__x svg { width: 16px; height: 16px; }

@media (prefers-reduced-motion: reduce) {
    .nudge { transition: none; }
}
