/* ==========================================================================
   Cocktails Your Way — Components
   Section by section, tracking Aaron's comp top to bottom.

   Percentages here are measured off the 1920pt artboard in
   DS-Moderation-Web-LandingPage-2026.ai, so `41.4%` means "41.4% across the
   artboard" and maps straight onto viewport width.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Brand bar
   Sizes come from the .ai file's own type, read out of the page content
   stream rather than measured off the render:

     "Cocktails" / "Way.com"   Neuzon (T1_0)            24pt
     "YOUR"                    PD Monolina Brush (T1_1)  36pt

   On a 1920pt artboard that is 1.25vw and 1.875vw, and 36/24 makes the script
   exactly 1.5x the rest — set in CAPS, butted hard against its neighbours
   (the comp runs 41.51 -> 48.14 -> 52.03 -> 58.49% with no spaces).

   THE BUG THIS FIXES. Both numbers were previously derived from cap heights
   measured off the JPG: 19.2pt and 26.6pt, giving a ratio of 1.385, which was
   then applied as `font-size: 1.4em`. But a cap-height ratio is not a
   font-size ratio — Neuzon and the brush have different cap-height-to-em
   proportions, so the script came out undersized against its own body while
   the whole lockup ran large. Measured ink before the fix: 19.72% of viewport
   against the comp's 16.88%, i.e. 16.9% too wide.

   Since we now serve the same two faces the comp was set in, quoting the .ai
   file's point sizes directly reproduces it — cap heights included — with no
   ratio to derive. Don't re-tune these off the render.
   -------------------------------------------------------------------------- */

.brandbar {
  background: var(--brown-deep);
  color: var(--cream);
  text-align: center;
  padding: .58rem 1rem;
  font-family: var(--font-header);
  font-size: clamp(.73rem, 1.25vw, 1.55rem);
  letter-spacing: 0;
  line-height: 1.5;
  position: relative; z-index: 60;
}
.brandbar a { text-decoration: none; color: inherit; }
.brandbar__you {
  font-family: var(--font-script);
  color: var(--tan);
  text-transform: uppercase;
  font-size: 1.5em;               /* 36pt against the body's 24pt */
  line-height: 0;                 /* keeps the taller script off the bar height */
  vertical-align: -.055em;
  letter-spacing: 0;
}

/* --------------------------------------------------------------------------
   Navigation
   Comp: links run 9.8%–75.3% at even intervals, CTA sits at 82%–94.8%.
   -------------------------------------------------------------------------- */

.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--cream);
  box-shadow: 0 10px 22px -14px rgb(0 0 0 / .55);
  transition: box-shadow .3s var(--ease-out);
}
.nav.is-scrolled { box-shadow: 0 14px 30px -12px rgb(0 0 0 / .6); }

.nav__inner {
  width: min(100% - var(--gutter) * 1.4, 1760px);
  margin-inline: auto;
  display: flex; align-items: center;
  gap: clamp(1rem, 2vw, 2.5rem);
  min-height: clamp(58px, 4.7vw, 78px);
}
.nav__links {
  display: flex; align-items: center;
  justify-content: space-evenly;
  list-style: none; margin: 0; padding: 0;
  flex: 1 1 auto;
}
.nav__link {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(.85rem, 1.06vw, 1.15rem);
  color: var(--brown);
  text-decoration: none;
  padding: .35rem 0 .5rem;
  position: relative;
  white-space: nowrap;
}
.nav__link::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 3px; background: var(--tan);
  transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease-out);
}
.nav__link:hover::after, .nav__link[aria-current="true"]::after { transform: scaleX(1); }

/* The comp's CTA carries a soft cast shadow, not the hard offset used on the
   in-page buttons. */
.nav__cta { flex: 0 0 auto; }
.nav__cta .btn {
  box-shadow: 5px 6px 13px rgb(31 12 4 / .32);
  padding: .78em 1.5em;
  transition: transform .22s var(--ease-out), background-color .22s var(--ease-out),
              color .22s var(--ease-out), box-shadow .22s var(--ease-out);
}
/* The lift alone was too quiet for the page's only persistent CTA, so hover
   flips the fill to orange as well. Both properties transition, and the
   `background` transition has to be declared on the base rule above — a
   transition only runs if the property is animatable on the element you are
   leaving as well as the one you are entering. */
.nav__cta .btn:hover, .nav__cta .btn:focus-visible {
  transform: translateY(-2px);
  background: var(--orange);
  color: var(--brown);
  box-shadow: 6px 9px 18px rgb(255 120 2 / .45);
}
.nav__cta .btn:active { transform: translateY(1px); box-shadow: 3px 4px 9px rgb(31 12 4 / .3); }

.nav__toggle {
  display: none;
  background: none; border: 0; cursor: pointer;
  padding: .5rem; margin-left: auto;
  color: var(--brown);
}
.nav__toggle svg { width: 28px; height: 28px; }

@media (max-width: 900px) {
  /* ------------------------------------------------------------------------
     Mobile header — ONE row, per Aaron's mobile comp.

     The comp does not stack a brand bar above a nav bar the way desktop does:
     it is a single brown-deep band with the domain lockup on the left and the
     hamburger on the right. Measured off the mobile artboard (1500px wide, so
     percentages of width map straight to vw):

       band height   22.27% of width
       lockup ink    11.07% - 47.93%
       hamburger     81.87% - 88.67%

     So the band is padded 11.1% either side and the two items sit at its ends.

     POSITION: FIXED, not sticky. Sticky was pinning with a visible strip of
     page showing above it on a real iPhone — a gap I could never reproduce in
     headless Chrome at any scroll offset. Fixed has no scrollport ambiguity to
     get wrong, and the cost (reserving the height in the flow) is one rule now
     that the header is a single short band.
     ------------------------------------------------------------------------ */
  .site-header {
    /* NOT pinned. On a one-page site the client would rather have the screen
       than a persistent bar, and dropping it also retires the strip-above-the-
       header artifact that neither sticky nor fixed ever fully shook off on
       iOS. Static means no reserved height and nothing to mis-measure. */
    position: relative;      /* in flow, and the dropdown anchors to it */
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 1rem;
    background: var(--brown-deep);
    min-height: 22.27vw;
    padding-inline: 11.1%;
  }

  .brandbar {
    flex: 1 1 auto;
    background: none;
    padding: 0;
    text-align: left;
    z-index: auto;
    /* The comp's own size is 2.73vw (a 36.86% lockup); the client asked for a
       little more presence, so this runs ~17% over the artboard on purpose. */
    font-size: clamp(.7rem, 3.2vw, 1.3rem);
  }

  /* The nav is now just the toggle; the dropdown hangs off .site-header, which
     is the positioned ancestor, so it can still span the full width. */
  .nav {
    position: static;
    flex: 0 0 auto;
    background: none !important;
    box-shadow: none;
  }
  .nav__inner { width: auto; margin: 0; min-height: 0; gap: 0; }
  .nav__toggle { display: block; padding: 0; margin: 0; color: var(--cream); }
  .nav__toggle svg { width: 6.8vw; height: 6.8vw; max-width: 34px; max-height: 34px; }
  .nav__links {
    position: absolute; inset: 100% 0 auto 0;
    flex-direction: column; align-items: flex-start;
    justify-content: flex-start;
    gap: 0;
    background: var(--cream);
    padding: 0 var(--gutter);
    max-height: 0; overflow: hidden;
    box-shadow: 0 18px 26px -18px rgb(0 0 0 / .6);
    transition: max-height .4s var(--ease-out), padding .4s var(--ease-out);
  }
  .nav.is-open .nav__links { max-height: 70vh; padding: .75rem var(--gutter) 1.5rem; }
  /* display: block matters. An <a> is inline, so `width: 100%` did nothing and
     the vertical padding did not grow the line box — which is why the items sat
     tight together AND why the scrollspy underline showed up as a stray bar
     floating through "The Facts": .nav__link::after is absolutely positioned
     against its containing block, and for an inline element that is the first
     line box, not the padded block. As a block it behaves. */
  .nav__link { display: block; padding: 1.05rem 0; width: 100%; }
  /* The underline is a desktop affordance: a full-width tan rule under one item
     in a stacked list reads as a divider, not as "you are here". Colour carries
     the current item instead. */
  .nav__link::after { display: none; }
  .nav__link[aria-current="true"] { color: var(--red); }
  .nav__cta { display: none; }
  /* In the dropdown the CTA is just the last item. It used to be hung off the
     nav with `position: absolute; bottom: -3.4rem`, which relied on .nav being
     the positioned ancestor — .nav is static now, so that would have escaped
     to .site-header and floated over the page. */
  .nav.is-open .nav__cta {
    display: block;
    position: static;
    margin-top: .5rem;
  }
  .nav.is-open .nav__cta .btn { display: inline-block; }
}

/* --------------------------------------------------------------------------
   Hero
   Comp: "ALL THE" spans 30.8%–63.7%, "FLAVOR" 38.4%–69.0% — the second line
   is stepped right, and the sub-head breaks after "MADE EXACTLY HOW".
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  z-index: 2;                     /* so the bottom shadow falls on the band below */
  /* 600px, per revision. The comp's hero is 720pt = 37.5% of the artboard,
     which is 540px at a 1440 viewport; 600 gives it a little more air without
     drifting from the comp's proportions. */
  min-height: clamp(480px, 42vw, 600px);
  /* Display stays at the root 13vw, which is the comp's own proportion: its
     ALL THE cap is 9.40% of the artboard width, and 13vw lands 9.31%. With the
     tighter padding the whole lockup is ~456px, so it fits 600px comfortably.
     NOTE if this needs to come down: --header is declared on :root as
     calc(--display * .2) and custom properties resolve var() at the element
     that DECLARES them, so a --display override here will NOT reach --header.
     Redeclare both together or the eyebrow and sub keep the old scale. */
  display: grid; place-items: center;
  background: var(--offwhite);
  overflow: hidden;
  text-align: center;
  padding: clamp(2.25rem, 4.4vw, 4rem) var(--gutter) clamp(3rem, 5.2vw, 4.6rem);
  box-shadow: 0 16px 26px -14px rgb(31 12 4 / .42);
}
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media video, .hero__media img {
  width: 100%; height: 100%; object-fit: cover;
}
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: var(--hero-scrim, linear-gradient(180deg,
              rgb(255 255 255 / .55), rgb(255 255 255 / .35) 45%, rgb(246 246 246 / .8)));
}
/* Full width so the stepped lines have room; the hero clips its overflow. */
.hero__content { position: relative; z-index: 3; width: 100%; }

.hero__eyebrow { color: var(--maroon); margin: 0 0 .06em; }

/* The hero headline alone runs on Veneer Three. The kit carries all three cuts
   — veneer, veneer-two, veneer-three — which are the same letterforms with
   progressively heavier erosion, meant to be alternated the way a real
   letterpress impression never repeats. Measured ink coverage of "ALL THE" at
   the comp's cap height: veneer .452, veneer-two .408, veneer-three .341, and
   the comp itself .428. Three is therefore MORE distressed than Aaron's comp,
   which is a deliberate art call by Jeremy, not a match to the artboard.
   Everything else on the page stays on base veneer via --font-display. */
.hero__display {
  color: var(--tan);
  margin: 0;
  font-family: "veneer-three", var(--font-display);
}

/* The comp's lockup is not stacked on one axis — it drifts rightward line by
   line. Measured centres: COCKTAILS 44.6%, ALL THE 47.3%, FLAVOR 53.7%,
   MADE EXACTLY HOW 53.5%, YOU WANT IT 52.2%. These offsets reproduce that
   drift against a centred block. */
.hero__eyebrow                          { position: relative; left: -5.4vw; }
.hero__display .display-line            { position: relative; left: -2.7vw; }
.hero__display .display-line + .display-line { left: 3.7vw; }
.hero__sub .hero__sub-line              { position: relative; left: 3.5vw; }
/* Comp leaves 26.5pt between MADE EXACTLY HOW's baseline and WANT IT's cap —
   room the oversized script needs. line-height alone would also push the whole
   sub away from FLAVOR, so the space goes on the second line only. */
.hero__sub .hero__sub-line + .hero__sub-line { left: 2.2vw; margin-top: .32em; }

.hero__sub {
  color: var(--maroon);
  margin: .26em 0 0;
  font-family: var(--font-header);
  font-size: var(--header);
  line-height: .92;
  text-transform: uppercase;
}
.hero__sub-line { display: block; }
.hero__sub .t-script {
  color: var(--tan);
  /* Measured off the artboard: the comp's YOU is 81.6pt of ink against WANT
     IT's 31.2pt on the same line — 2.615x. PD Monolina Brush puts .75em of
     ink in caps, Neuzon .645em, so 2.615 * .645 / .75 = 2.25em.
     .t-script sets text-transform:none globally; the comp shows this one in
     caps, and lowercase renders both smaller and wider than the comp. */
  font-size: 2.25em;
  line-height: 0;
  text-transform: uppercase;
  /* At 2.25em the brush overhangs its line far more than the old 1.42em did,
     so it has to be dropped or it collides with the line above. Comp has the
     script rising 14.6pt over WANT IT's cap and falling 35.8pt below its
     baseline; -.286em reproduces that split. */
  vertical-align: -.286em;
  margin-right: .1em;
}

/* Floating stamps behind the hero type. Faint enough to read as texture.

   Three nested transforms, each owned by exactly one system so nothing fights
   over the same matrix:

     .hero__stamps-inner  GSAP  slow lateral sway of the whole field
     .hero__stamps-track  GSAP  the upward ticker (infinite, linear)
     .hero__stamp         CSS   per-stamp drift   |  its <svg> CSS rock

   The track holds two identical tiles stacked one hero-height apart. The
   ticker runs yPercent 0 -> -100, and because the track is inset:0 its own
   height IS one tile, so at the end of the cycle tile 2 sits exactly where
   tile 1 began — the repeat is invisible. Per-stamp motion is CSS with a
   negative animation-delay, which is an absolute phase, so cloned tiles stay
   locked together no matter when JS built them. */

.hero__stamps { position: absolute; inset: 0; z-index: 2; pointer-events: none; }

.hero__stamps-inner {
  position: absolute; inset: -6% -12%;
  will-change: transform;
}
.hero__stamps-track {
  position: absolute; inset: 0;
  will-change: transform;
}
.hero__stamps-tile {
  position: absolute; left: 0; right: 0;
  top: calc(var(--ti, 0) * 100%);
  height: 100%;
}

.hero__stamp {
  position: absolute;
  color: var(--tan);
  opacity: 0;
  transition: opacity calc(1.1s * var(--speed)) var(--ease-out);
  animation: cyw-stamp-drift var(--dur, 18s) ease-in-out var(--dly, 0s) infinite alternate;
}
/* Visibility is a class + transition, never the animation — a paused or
   suppressed animation must not be able to hide these. */
.hero__stamp.is-in { opacity: var(--o, .16); }

.hero__stamp > svg {
  display: block;
  width: 100%; height: auto;
  fill: currentColor;
  animation: cyw-stamp-rock var(--rock-dur, 16s) ease-in-out var(--rock-dly, 0s) infinite alternate;
}

@keyframes cyw-stamp-drift {
  from { transform: translate3d(calc(var(--dx, 12%) * -1), var(--dy, 8%), 0); }
  to   { transform: translate3d(var(--dx, 12%), calc(var(--dy, 8%) * -1), 0); }
}
@keyframes cyw-stamp-rock {
  from { transform: rotate(calc(var(--rot, 0deg) - var(--rock, 3deg))); }
  to   { transform: rotate(calc(var(--rot, 0deg) + var(--rock, 3deg))); }
}

/* Nothing to animate while the hero is scrolled away. */
.hero__stamps.is-idle .hero__stamp,
.hero__stamps.is-idle .hero__stamp > svg { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  .hero__stamp,
  .hero__stamp > svg { animation: none; }
  .hero__stamp > svg { transform: rotate(var(--rot, 0deg)); }
}


/* --------------------------------------------------------------------------
   Statement band — comp sets this two lines wide at desktop (14%–86%).
   -------------------------------------------------------------------------- */

.statement {
  background: var(--cream);
  text-align: center;
  padding-block: clamp(3.5rem, 7vw, 7rem);
}
.statement__text {
  font-size: clamp(1.05rem, 1.55vw, 1.7rem);
  line-height: 1.42;
  max-width: min(74vw, 1240px);
  margin-inline: auto;
  color: var(--brown);
}

/* --------------------------------------------------------------------------
   Split — "Cocktails give you choices"
   Comp staircases the three lines rightward: their left edges sit at 58.8%,
   63.8% and 69.0% of the artboard — 17.6%, 27.6% and 37.9% into the panel.
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: clamp(420px, 46vw, 720px);
  align-items: stretch;
}
.split__media {
  position: relative;
  display: grid; place-items: center;
  padding: clamp(2rem, 4vw, 4rem);
  overflow: hidden;
}
.split__copy {
  display: grid; align-content: center;
  gap: clamp(1.5rem, 3vw, 3rem);
  background: var(--maroon);
  color: var(--cream);
  padding: clamp(2.5rem, 5vw, 5.5rem) clamp(1.5rem, 3vw, 3rem);
  text-align: left;
}
.split__copy .t-header  { color: var(--cream); }
.split__copy .t-display { color: var(--red); }
.split__copy .t-script  { color: var(--cream); }

.split__lockup { display: grid; gap: 0; justify-items: start; }
.split__lockup > * { display: block; }
.split__lockup-head { padding-left: 17.6%; }
/* "Give" runs on Veneer Three — the heaviest of the kit's three erosion cuts
   (veneer .452 ink coverage, veneer-two .408, veneer-three .341). Tried Two
   first; Jeremy's call is that Three's heavier break-up is the one that reads
   as the design. Same cut as the hero, so the two loudest words on the page
   share a voice. Base veneer stays the page default via --font-display. */
.split__lockup-display {
  padding-left: 27.6%;
  font-family: "veneer-three", var(--font-display);
}
.split__lockup-sub {
  padding-left: 37.9%;
  font-family: var(--font-header);
  font-size: var(--header);
  text-transform: uppercase;
  line-height: .9;
  margin-top: .06em;
}
/* Same brush as the hero, and the comp sets it in caps here too — .t-script
   declares text-transform:none globally, which silently cancels the uppercase
   this line inherits, so it has to be restated. Comp ink ratio here is 2.387
   against CHOICES (the hero's is 2.615), and it sits centred on the cap band
   rather than hanging low the way the hero's does. */
.split__lockup-sub .t-script {
  font-size: 2.36em;
  line-height: 0;
  text-transform: uppercase;
  vertical-align: -.216em;
  margin-right: .12em;
}
.split__body {
  max-width: 42ch;
  margin-inline: auto;
  text-align: center;
}
.split__body .strike { color: var(--red); }

/* Three drinks on a shared ground line; the beer is shouldered aside. */
/* The Choices panel is now a measured stage like Layered/Comparison/Enjoy:
   the comp's left panel is 936 x 850pt, so everything inside can be placed by
   artboard percentage — which is what lets Aaron's extracted shadows land
   exactly. It used to be an arbitrary 16/10 box, so no absolute coordinate
   from the .ai file could be used directly. */
.choices {
  position: relative;
  width: 100%; max-width: 820px;
  aspect-ratio: 936 / 850;
}
.choices__item,
.choices__beer {
  position: absolute;
  display: block;
  z-index: 2;            /* above .cyw-shadow, which sits at 1 */
}
.choices__item .drink,
.choices__beer .drink { height: 100%; }
.choices__item .drink__img,
.choices__beer img { height: 100%; width: auto; }

/* Heights scaled to the comp: measured against the artboard the espresso coupe
   group is 10.44% of the page width, and these were rendering 1.31x that.
   The --stamp-color overrides that used to sit here are gone — cyw_drink sets
   the shadow colour inline per drink from the block's own fields, so these
   only ever duplicated it and drifted out of step. */
/* Artboard -> panel: panel_x% = artboard_x% / 48.75 * 100,
                     panel_y% = (y_top - 1290) / 850 * 100          */
.choices__item--1 { left: 11.94%; top: 41.42%; height: 23.57%; }
.choices__item--2 { left: 41.44%; top: 38.38%; height: 28.74%; }
.choices__item--3 { left: 63.82%; top: 38.38%; height: 25.77%; }
.choices__beer    { left: 41.44%; top: 36.00%; height: 31.00%; z-index: 5; transform-origin: bottom center; }

/* Aaron's cast shadows, placed off the .ai file's own coordinates. */
.cyw-shadow--ch-espresso  { left: 10.58%; top: 37.41%; width: 22.55%; height: 29.88%; }
.cyw-shadow--ch-highball  { left: 43.53%; top: 38.80%; width:  9.60%; height: 25.85%; }
.cyw-shadow--ch-manhattan { left: 68.68%; top: 42.45%; width: 11.71%; height: 20.39%; }

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split__media { min-height: 52vw; }
}

/* --------------------------------------------------------------------------
   Layered headline
   Section is 960pt tall on a 1920pt board = 50vw. Everything below is placed
   at the percentages measured off the comp:
     MODERATE THE   top 14.8%,  right edge 43.2%
     ALCOHOL        top 27.4%,  right edge 43.2%   (right-aligned pair)
     glass          41.4%–54.5%
     NOT THE TASTE. top 44.5%,  left 57.1%         (runs behind the glass)
   -------------------------------------------------------------------------- */

.layered {
  position: relative;
  background: var(--olive);
  color: var(--cream);
  /* 150pt on the 1920pt artboard, read out of the .ai content stream — all
     three lines are Veneer Two at that size. Was 8.17vw, which is 4.6% large;
     since the two headlines are anchored by their INNER edges, the excess all
     came off the outside and pushed the section's ink left. */
  --display: clamp(2.4rem, 7.81vw, 7.81rem);
}
.layered__stage {
  position: relative;
  width: 100%;
  height: 50vw;
  max-height: 960px;
  /* Centre the whole composition on the page. Measured: the section's ink ran
     2.64%-91.46%, i.e. a 2.64% left margin against an 8.47% right one, and it
     read as sitting left. The comp is balanced (6.14 / 6.40) but it gets there
     with its own numbers — our type is not the comp's width to the pixel, and
     the 30px/60px nudges on the two headlines shifted the balance further.
     Rather than unpick either, the whole stage moves as one.

     `translate`, not `transform`: percentages resolve against the stage's own
     width (which is what we want), and it leaves `transform` free for the
     GSAP tweens on the headlines. */
  translate: 2.95% 0;
}

/* ---------------------------------------------------------------------------
   The 30px / 60px offsets below are Jeremy's, called on 2026-08-22, and they
   are written as PERCENTAGES OF THE STAGE rather than as literal px on
   purpose. Measured at the time: the stage was 1265px, so

       30px = 2.372% of stage        60px = 4.743% of stage

   Everything in this block scales with vw — the display type, the glass, and
   every position — so the overlap being corrected is itself proportional
   (1.50% of stage, whatever the viewport). A hard-coded 30px would fix it at
   1280 and fail above it: at 2560 the overlap grows to ~38px while a 30px
   nudge stays 30px, and the type would run behind the glass again. As a
   percentage it holds everywhere. Retune by changing the px figure above and
   redividing by the stage width.
   --------------------------------------------------------------------------- */

.layered__line { position: absolute; margin: 0; z-index: 3; }
.layered__line--a {
  /* The comp puts this line's ink right edge at 43.2% against a glass whose
     ink starts at 42.1% — it butts the glass and stops. In practice ours rested
     at 42.90% against a glass starting at 41.40%, i.e. 19px BEHIND it. Pulled
     back by 30px (57.1% + 2.372%), which lands the ink at 40.53% and leaves
     11px of daylight before the glass. This is also where the scroll tween
     comes to rest: it ends at xPercent 0, which is this position. */
  left: 0; right: 59.47%;
  top: 12.4%;
  text-align: right;
  color: var(--yellow);
}
.layered__line--b {
  /* Moved 60px left (57.1% - 4.743%) to travel with the glass's cast shadow,
     which moved the same distance — the two read as one group, so shifting the
     shadow without the line would open a gap under it. `right` moves with
     `left` so the box only translates rather than stretching. */
  left: 52.36%; right: 6.74%;
  top: 42.2%;
  text-align: left;
  color: var(--cream);
  z-index: 2;                       /* passes behind the glass */
}
.layered__line--b .display-line { white-space: nowrap; }

.layered__drink {
  position: absolute;
  left: 41.4%;
  top: 3.5%;
  height: 62%;
  z-index: 4;
  --stamp-color: var(--olive-deep);
}
.layered__drink .drink { height: 100%; }
.layered__drink .drink__img { height: 100%; width: auto; }

.layered__body {
  position: absolute;
  left: 14%; right: 14%;
  top: 80%;
  /* margin-inline MUST stay auto. .t-body caps the line length at --measure,
     which is narrower than this 14%–86% band, so the box is over-constrained:
     with margin:0 the browser drops `right` and the paragraph parks against
     the left edge — centred text sitting ~170px left of centre. */
  margin-block: 0;
  margin-inline: auto;
  color: var(--cream);
  text-align: center;
  z-index: 3;
}

/* --------------------------------------------------------------------------
   Comparison
   Section is 852pt tall = 44.35vw. The two halves are not symmetrical in the
   comp: on the left the figures straddle the bottle, on the right they run
   across the top with the glasses beneath.
     LEFT   10% at 13.0%/11.5%, ABV stacked under it, 12oz at 29.5%
            bottle 13.1%–36.4%,  label top 82.8%
     RIGHT  40% ABV from 49.9%, 1.5oz from 71.4%
            glasses 65.1%–83.4%, label top 82.2%
   -------------------------------------------------------------------------- */

.compare {
  background: var(--cream);
  /* 184.3pt on the artboard = 9.60vw (was 9.66 — within noise, corrected
     for the record while the sub and label ratios below were being fixed). */
  --display: clamp(2.2rem, 9.60vw, 9.60rem);
}
.compare__stage {
  position: relative;
  width: 100%;
  /* The comp's own section height, and the basis for everything that has to
     stay locked to the drinks. It CAPS at 852px (= 1921px viewport), and that
     cap is the whole problem this variable solves: above it the height stops
     growing while the width does not, so anything sized as a percentage of
     WIDTH keeps inflating while the drinks — which are sized by height — do
     not. The shadows did exactly that: at 2560 they rendered 1.33x too wide
     and the second one sat ~200px clear of its own glass. */
  --stage-h: min(44.35vw, 852px);
  height: var(--stage-h);
  color: var(--cmp-ink, var(--olive));
  /* Same treatment as Layered: ink ran 13.12%-83.54%, so a 13.12% left margin
     against 16.39% on the right. The comp balances this block by putting "TWO
     COCKTAILS" out at 49.84-86.93% — NOT centred under the glasses — but
     centring the labels on their figures was a deliberate call, so the block
     is nudged instead of moving the label back. */
  translate: 1.67% 0;
}

.compare__num,
.compare__sub,
.compare__label {
  position: absolute;
  margin: 0;
  font-family: var(--font-display);
  line-height: .8;
  text-transform: uppercase;
  white-space: nowrap;
  z-index: 3;
}
.compare__num { font-size: var(--display); }
/* .ai: numbers 184.3pt, the %/ABV/oz riders 107.5pt -> .5833, not .55. */
.compare__sub { font-size: calc(var(--display) * .5833); }
.compare__label {
  font-family: var(--font-header);
  /* .ai: Neuzon at 74.3pt against the numbers' 184.3pt -> .403. At .30 the
     labels rendered 34% small, so "TWO COCKTAILS" stopped ~3% short of the
     comp's right edge and left the whole block looking left-heavy. */
  font-size: calc(var(--display) * .403);
  line-height: .9;
}
.compare__num sup, .compare__num .unit {
  font-size: .44em; line-height: 1; vertical-align: .82em;
}
.compare__num .unit { margin-left: .12em; }

.compare__fig {
  position: absolute;
  display: flex; align-items: flex-end;
  width: max-content;
  gap: clamp(.2rem, .9vw, 1rem);
  z-index: 2;
}
.compare__fig .drink { height: 100%; }
.compare__fig .drink__img { height: 100%; width: auto; }

/* Re-measured off the artboard. The bottle was sitting at 13.1% — under the
   "10%" rather than between the two figures; the comp centres it in the gap,
   with 10%/ABV to its left and 12oz to its right. The glass pair was at 65.1%,
   pushed out under "1.5 OZ" alone; the comp centres the pair under both
   figures and leaves a 3.1% gap between the glasses so the first glass's own
   shadow is visible rather than hidden behind the second. */

/* Left half */
.compare__num--la  { left: 13.1%; top: 15.1%; }
.compare__sub--l   { left: 13.6%; top: 32.0%; }
.compare__num--lb  { left: 30.0%; top: 15.1%; }
.compare__fig--l   { left: 20.8%; top:  9.6%; height: 69.2%; }

/* Right half */
.compare__num--ra  { left: 50.3%; top: 15.1%; }
.compare__num--rb  { left: 71.5%; top: 15.1%; }
/* Our glass cut-out is proportionally narrower than the comp's (its garnish
   sits inside the frame rather than out to the side), so the pair is matched
   on pitch and left edges via the gap instead of by distorting the height. */
/* The gap is measured against --stage-h, not vw: the glasses themselves are
   sized by the stage height, so a vw gap keeps widening past the 852px cap and
   the pair drifts apart while the glasses stay put. .0992 of the stage height
   IS 4.4vw below the cap, so nothing moves at normal widths. */
.compare__fig--r   { left: 55.6%; top: 27.0%; height: 50%; gap: calc(var(--stage-h) * .0992); }

/* Both labels centre on the figure above them rather than starting at the
   comp's own left edge. The comp sets them at xMin 12.97% / 49.84% and its own
   type happens to centre near the drinks from there — but our Neuzon renders
   these words narrower than Aaron's artboard type, so matching the left edge
   left "One beer" sitting 2.84% (36px at 1280) left of the bottle's centre.
   Anchoring the centre instead is width-independent: reword the labels in ACF
   and they stay put.

   Measured against .compare__stage with the drink images loaded — the cut-outs
   are lazy and report zero width until they are, which is the trap here. The
   figures scale with vw, so these centres hold at every viewport:
     bottle    20.80%-29.63%  ->  centre 25.21%
     glass pair 55.60%-73.70% ->  centre 64.65%
   Using the `translate` property, not `transform`, so any later GSAP tween on
   these owns `transform` outright and the centring cannot be clobbered. */
.compare__label {
  translate: -50% 0;
  text-align: center;
}
.compare__label--l { left: 25.21%; top: 81.5%; }
.compare__label--r { left: 64.65%; top: 81.5%; }

/* ==========================================================================
   Cast shadows lifted from the .ai file
   Aaron's own artwork, extracted by _dev-tools/extract_shadows.py. Each is
   placed by artboard-derived percentages against its section's stage, never
   relative to the drink — the source BBox is already absolute.
   ========================================================================== */
.cyw-shadow { position: absolute; z-index: 1; pointer-events: none; }
.cyw-shadow svg,
.cyw-shadow img { display: block; width: 100%; height: 100%; }
.cyw-shadow svg { fill: currentColor; }

/* Layered — section 2128-3098pt (970pt tall); Fm8 at x 45.85-59.01%, y 2183.3-2800.8
   Moved 60px left of the .ai file's own BBox on Jeremy's call (2026-08-22):
   45.85% - 4.743% = 41.11%. See the note in the Layered block for why the
   offset is a percentage rather than literal px. "NOT THE TASTE." moved the
   same distance so the pair stays together. This is the one shadow that no
   longer sits at its extracted coordinate — re-running extract_shadows.py
   rewrites the SVG, not this placement, so the offset survives. */
.cyw-shadow--layered  { left: 41.11%; top:  5.70%; width: 13.16%; height: 63.66%; }

/* Comparison — section 3088-3950pt (862pt tall) */
/* Each shadow is pinned to the figure it falls from, not to the stage.
   Both halves of that matter above the 852px height cap (viewport > 1921px):

   SIZE — the width came from the stage WIDTH (9.33% / 8.49%) while the height
   came from the stage HEIGHT. Past the cap only the width kept growing, so the
   artwork stretched sideways (1.33x at 2560). Width now follows the height
   through `aspect-ratio`, using each shadow's own .ai BBox, so it can never
   distort again — and `preserveAspectRatio="none"` on the SVG is harmless once
   the box itself is the right shape.

   POSITION — the left edge was an absolute percentage of the stage width, so
   it drifted away from its glass past the cap (shadow 2 ended ~200px clear of
   glass 2). It is now its figure's own left plus an offset measured in stage
   HEIGHTS, so the pair moves as one. The offsets are the artboard's own left
   edges (22.00 / 58.22 / 69.48%) minus their figure's (20.8 / 55.6%),
   converted at 1% of width = 1/44.35 of the height — which reproduces the
   measured positions to 0.1px at every width below the cap. */
.cyw-shadow--cmp-beer {
  left: calc(20.8% + var(--stage-h) * .0270575);
  top: 14.10%;
  height: 65.41%;
  width: auto;
  aspect-ratio: 179.1 / 563.9;   /* Fm10 BBox, in artboard pt */
}
.cyw-shadow--cmp-glass1 {
  left: calc(55.6% + var(--stage-h) * .0590755);
  top: 27.08%;
  height: 46.21%;
  width: auto;
  aspect-ratio: 163.0 / 398.3;   /* Fm11 BBox */
}
.cyw-shadow--cmp-glass2 {
  left: calc(55.6% + var(--stage-h) * .3129651);
  top: 27.08%;
  height: 46.21%;
  width: auto;
  aspect-ratio: 163.0 / 398.3;   /* Fm12 BBox — same artwork as glass 1 */
}

/* Enjoy — section 3940-5065pt (1125pt tall); Fm3 at x 62.24-74.22%, y 4133.6-4415.9 */
/* Vertical values against --stage-h, not %, so trimming the stage box does not
   drag the shadow off the glass. See .enjoy__stage. */
.cyw-shadow--enjoy    { left: 62.24%; top: calc(var(--stage-h) * .1721); width: 11.98%; height: calc(var(--stage-h) * .2509); }

/* Extracted shadow art from the .ai file. Coordinates are the artboard's own:
   Fm10's BBox is x 422.4-601.5pt of 1920 (22.00%-31.33%) and y 3209.5-3773.4pt
   within the 3088-3950pt section (14.10% down, 65.41% tall). Absolute against
   the stage, not the drink, so no rounding is reintroduced. */
.compare__shadow {
  position: absolute;
  z-index: 1;
  pointer-events: none;
}
.compare__shadow svg { display: block; width: 100%; height: 100%; fill: currentColor; }
.compare__shadow--beer {
  left: 22.00%; top: 14.10%;
  width: 9.33%; height: 65.41%;
}

/* The equals is Aaron's own artwork, not two CSS bars and not a font glyph.
   In the .ai it is a flat amber raster with an alpha mask (196x205, drawn by
   form Fm9), so it is extracted as a transparent PNG the same way the Choices
   espresso shadow was. Veneer's "=" was tried and rejected: its glyph is 1.52
   wide-to-tall against the comp's 0.94, so a character comes out long and thin.
   Placement is the artboard's own: x 37.86-48.07% of 1920, y_top 3445-3650pt
   inside a section running 3088-3950pt. */
.compare__equals {
  position: absolute;
  left: 37.86%; top: 41.42%;
  width: 10.21%; height: 23.78%;
  z-index: 3;
  pointer-events: none;
}
.compare__equals img { display: block; width: 100%; height: 100%; }

.footer__links {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(.9rem, 2.4vw, 2.4rem);
  margin-top: clamp(1rem, 2.2vw, 1.6rem);
  font-family: var(--font-header);
  text-transform: uppercase;
  font-size: .72rem;
  letter-spacing: .13em;
}
.footer__links a { color: inherit; text-decoration: none; opacity: .9; }
.footer__links a:hover, .footer__links a:focus-visible { opacity: 1; text-decoration: underline; }

@media (max-width: 760px) {
  .footer__inner { grid-template-columns: 1fr; gap: clamp(1.5rem, 5vw, 2.25rem); }
  /* Four links in a wrapping row broke 3 + 1 at this width, which read as an
     orphan. Stacked they read as a list, which is what they are. */
  .footer__links { flex-direction: column; align-items: center; gap: .85rem; }
  .footer__meta { border-left: 0; border-top: 1px solid rgb(87 34 0 / .2); padding-left: 0; padding-top: clamp(1.5rem, 5vw, 2.25rem); }
}

/* --------------------------------------------------------------------------
   Enjoy
   Section is 1116pt tall = 58.14vw. Measured placements:
     CHOOSE WHAT'S IN YOUR  top 13.9%, left 19.7%
     GLASS AND              top 19.1%, left 41.6%
     ENJOY IT               top 25.6%, left 21.6%
     YOUR WAY.              top 43.7%, left 37.8%
     rocks glass            57%–74%, overlapping both display lines
     body                   top 69.7%
     "options and flavors"  top 87.4%
   -------------------------------------------------------------------------- */

.enjoy {
  position: relative;
  background: var(--brown);
  color: var(--cream);
}
.enjoy__stage {
  /* The comp's own section height. Every VERTICAL placement in this block is
     measured against this variable rather than against the box, so the box can
     be trimmed to its content without moving the lockup, the glass or the
     shadow — all of which are placed off the artboard and must not shift.
     Horizontal placements stay in % because the width is unchanged. */
  --stage-h: min(58.14vw, 1116px);
  position: relative;
  width: 100%;
  /* The stage used to be a flat 58.14vw, which left a tall band of empty brown
     between the body copy and the builder below it. It now ends a
     header's-worth of space after the copy: ::before reserves the lockup
     region, and this padding matches the 12.4% gap above the header. */
  padding-bottom: calc(var(--stage-h) * .124);
}
/* Reserves the lockup and glass region, which is otherwise all absolutely
   positioned and contributes no height. Ends where the body copy begins. */
.enjoy:not(.enjoy--closing) .enjoy__stage::before {
  content: '';
  display: block;
  height: calc(var(--stage-h) * .684);
}

.enjoy__line { position: absolute; margin: 0; z-index: 3; white-space: nowrap; }
.enjoy__line--h1 { left: 19.7%; top: calc(var(--stage-h) * .124); color: var(--cream); }
.enjoy__line--h2 { left: 41.6%; top: calc(var(--stage-h) * .176); color: var(--cream); }
/* "Enjoy it | your way." on Veneer Three, same call as the Choices "Give" —
   see the note there. Both display lines take it so the lockup stays one
   voice; splitting cuts across a single sentence would read as an accident. */
.enjoy__line--d1,
.enjoy__line--d2 { font-family: "veneer-three", var(--font-display); }
.enjoy__line--d1 { left: 21.6%; top: calc(var(--stage-h) * .224); }
.enjoy__line--d2 { left: 37.8%; top: calc(var(--stage-h) * .406); }

/* MEASURED off the comp, not inferred. These were previously derived from the
   shadow — "a cast shadow runs ~90% of the glass it falls from" — which is a
   guess, and it left the glass ~5% small and 1% high, so Fm3 stuck out twice
   as far to the right as it does on the artboard and read as a slab beside the
   glass rather than a shadow behind it.

   Measured on a vertical strip through the glass at x 64.5-70% (right of the
   cream header text, left of the shadow's edge) so nothing else is caught:
   the glass runs y 15.90%-45.23% of the section and its right edge is 72.42%.
   Width follows from the cut-out's own 1182x1337 aspect (0.8841), giving
   15.19% of the board and a left edge of 57.23%.

   Against that the shadow sits where the .ai puts it: starting 1.31% below the
   glass top and standing 1.80% proud of its right edge. */
.enjoy__drink {
  position: absolute;
  left: 57.23%;
  top: calc(var(--stage-h) * .159);
  height: calc(var(--stage-h) * .2933);
  z-index: 4;
}
.enjoy__drink .drink { height: 100%; }
.enjoy__drink .drink__img { height: 100%; width: auto; }

/* In normal flow, not absolute: it is what gives the stage its height, so the
   empty brown below it can end a fixed distance after the copy instead of
   running on to a fixed 58.14vw. The ::before spacer puts it at the same
   68.4% of the artboard it was placed at before, so it has not moved. */
.enjoy__body {
  position: relative;
  width: 72.4%;            /* the old left/right 13.8% inset */
  margin-block: 0;
  margin-inline: auto;
  color: var(--cream);
  text-align: center;
  z-index: 3;
}

/* The builder sits between the Enjoy copy and the "endless" line — brown,
   cream, brown — so that line is a second instance of the block, in closing
   mode. Nothing to place on a full-height stage, so the stage collapses and
   the line runs in normal flow. */
.enjoy--closing .enjoy__stage {
  height: auto;
  min-height: 0;
  display: grid;
  place-items: center;
  padding-block: clamp(2.25rem, 5vw, 4rem);
}
.enjoy--closing .enjoy__endless {
  position: static;
  left: auto; right: auto; top: auto;
  max-width: 90%;
}

/* Reads on from the body copy rather than sitting apart from it. */
.enjoy__cta {
  color: var(--orange);
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid color-mix(in srgb, var(--orange) 45%, transparent);
  transition: color .2s var(--ease-out), border-color .2s var(--ease-out);
}
.enjoy__cta:hover, .enjoy__cta:focus-visible {
  color: var(--cream);
  border-bottom-color: var(--cream);
}

.enjoy__endless {
  position: absolute;
  left: 6%; right: 6%;
  top: 86%;
  margin: 0;
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center;
  gap: .5em;
  font-family: var(--font-header);
  font-size: calc(var(--display) * 0.185);
  text-transform: uppercase;
  color: var(--orange);
  line-height: 1;
  z-index: 3;
}
/* Comp runs these much larger: measured against the line's own cap height the
   cherry is 3.47x and the sprig 2.34x (the old 1.4em box worked out at 2.15x,
   and a fixed-width box cropped the glyph narrower still because the SVG
   letterboxes itself inside it). Height drives the size and width follows the
   viewBox, so each keeps its own proportions. #410600 is the ink sampled off
   the comp. */
.enjoy__endless .stamp-inline {
  width: auto;
  height: 2.2em;
  color: #410600;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
}
.enjoy__endless .stamp-inline svg { width: auto; height: 100%; fill: currentColor; }

/* --------------------------------------------------------------------------
   Video
   -------------------------------------------------------------------------- */

.videoblock { background: var(--cream); }
.videoblock__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--brown-deep);
}
.videoblock__frame video, .videoblock__frame img, .videoblock__frame iframe {
  width: 100%; height: 100%; object-fit: cover; border: 0;
}
.videoblock__play {
  position: absolute; inset: 0; z-index: 3;
  display: grid; place-items: center;
  background: rgb(78 31 15 / .34);
  border: 0; cursor: pointer; color: var(--cream);
  transition: background-color .3s var(--ease-out);
}
.videoblock__play:hover { background: rgb(78 31 15 / .18); }
.videoblock__play span {
  display: grid; place-items: center;
  width: clamp(64px, 8vw, 108px); aspect-ratio: 1;
  border-radius: 50%;
  background: var(--orange); color: var(--brown);
  box-shadow: 6px 6px 0 var(--brown-shadow);
  transition: transform .25s var(--ease-out);
}
.videoblock__play:hover span { transform: scale(1.08); }
.videoblock__play svg { width: 38%; height: 38%; margin-left: 8%; }
.videoblock__caption {
  margin-top: 1.25rem; text-align: center;
  font-family: var(--font-header); text-transform: uppercase;
  color: var(--brown); font-size: clamp(.95rem, 1.4vw, 1.4rem);
}

/* --------------------------------------------------------------------------
   Savor
   Section is 720pt = 37.53vw. The comp runs the photograph at full strength —
   the type reads because it sits over the blown-out middle of the frame, not
   because the picture is washed out. Display lines step right.
   -------------------------------------------------------------------------- */

.savor {
  position: relative;
  overflow: hidden;
  --display: clamp(2.4rem, 8.4vw, 8.4rem);
}
.savor__stage {
  position: relative;
  width: 100%;
  height: 37.53vw;
  min-height: 420px;
  max-height: 780px;
}
/* The stage clips, so the plate can be over-scaled and drifted inside it. */
.savor__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.savor__media img, .savor__media video {
  width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 45%;
  will-change: transform;

  /* Ken Burns. A push in with a little lateral drift, alternating so it
     breathes back out rather than snapping to the start — a hard loop on a
     recognisable photograph reads as a glitch. transform-origin sits slightly
     above centre because the faces are in the upper half of the plate, so the
     push should converge on them.

     Both knobs come from the block: Savor -> Photo push sets --kb-dur, Push
     distance sets --kb-amt (a unitless percentage). Because it alternates, the
     round trip is 2x --kb-dur — which is why the original 28s read as almost
     static: it was a 56-second cycle. The fallbacks here are the block's own
     defaults, so the rule still behaves if a stale post has neither. */
  transform-origin: 50% 38%;
  animation: cyw-kenburns var(--kb-dur, 17s) ease-in-out infinite alternate;
}

/* The drift is derived from the push distance rather than set independently:
   over-scaling by --kb-amt is what creates the slack to move into, so the two
   have to stay in proportion or the image slides past its own edge. The
   ratios are the original 1.6% / 1.1% against an 11% push. */
@keyframes cyw-kenburns {
  from { transform: scale(1) translate3d(0, 0, 0); }
  to   { transform: scale(calc(1 + var(--kb-amt, 11) / 100))
                    translate3d(calc(var(--kb-amt, 11) * -0.145%),
                                calc(var(--kb-amt, 11) * -0.100%), 0); }
}

/* Hold it still once it is off screen, and for anyone who has asked for less
   motion — a long slow zoom is exactly the kind of thing that triggers it.
   "Off" in the block is the same stop, applied as a class. */
.savor.is-idle .savor__media img,
.savor.is-idle .savor__media video { animation-play-state: paused; }

.savor--still .savor__media img,
.savor--still .savor__media video { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .savor__media img, .savor__media video { animation: none; }
}
/* Just enough lift under the type to hold contrast if the crop shifts. */
.savor__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(96deg,
    rgb(255 252 230 / 0) 0%,
    rgb(255 252 230 / 0) 40%,
    rgb(255 252 230 / .12) 66%,
    rgb(255 252 230 / .20) 100%);
}
.savor__content { position: absolute; inset: 0; z-index: 3; }
.savor__eyebrow {
  position: absolute;
  left: 45%; right: 3%; top: 13%;
  margin: 0;
  color: var(--orange);
  text-align: left;
}
/* Comp: SAVOR starts at 41.8%, THE at 49.1%, MOMENT. at 49.5% — the last two
   step in together rather than continuing the staircase. */
.savor__display {
  position: absolute;
  left: 41.8%; right: 3%; top: 28.5%;
  margin: 0;
  color: var(--brown);
  text-align: left;
}
.savor__display .display-line { white-space: nowrap; }
.savor__display .display-line:nth-child(2) { padding-left: 13%; }
.savor__display .display-line:nth-child(3) { padding-left: 14%; }

/* --------------------------------------------------------------------------
   Signup
   -------------------------------------------------------------------------- */

.signup { background: var(--brown-deep); color: var(--cream); padding-block: clamp(1.5rem, 2.6vw, 2.5rem); }
.signup__inner {
  /* Header stacked over the form at every width (client, 2026-09-14) — the
     Spirits United form is four fields deep and no longer sits beside it. */
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(1rem, 1.8vw, 1.75rem);
  text-align: center;
}
.signup__label {
  font-family: var(--font-header);
  text-transform: uppercase;
  font-size: clamp(1rem, 1.5vw, 1.5rem);
  line-height: 1.1;
}
.signup__form { flex: 0 0 auto; width: 100%; max-width: 660px; }
.signup__note { margin: .75rem 0 0; font-size: .82rem; opacity: .78; }
.signup__note a { color: var(--tan); }

/* Gravity Forms markup. Its own CSS is disabled (inc/gravity.php), so this is
   everything. The wrappers between <form> and the fields are flattened with
   display: contents, which lets the email field, the submit button and the
   opt-in text be laid out as ONE row-wrapping flex line: field and button
   side by side, the opt-in language full width underneath — whatever order
   Gravity Forms prints them in. */
.signup__form .gform_wrapper form { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .75rem; }
.signup__form .gform-body,
.signup__form .gform_body,
.signup__form .gform_fields { display: contents; }
.signup__form .gfield { margin: 0; padding: 0; border: 0; list-style: none; }
.signup__form .cyw-gf-email  { order: 1; flex: 1 1 240px; min-width: 0; }
.signup__form .gform_footer  { order: 2; flex: 0 0 auto; align-self: stretch; margin: 0; padding: 0; display: flex; align-items: stretch; gap: .5rem; }
.signup__form .gform_footer .gform_ajax_spinner { align-self: center; }
.signup__form .cyw-gf-consent { order: 3; flex: 1 1 100%; font-size: .82rem; line-height: 1.45; opacity: .88; text-align: center; }
.signup__form .gform_validation_errors { order: 0; flex: 1 1 100%; }

.signup__form .gfield_label,
.signup__form .hidden_label .gfield_label,
.signup__form .gform_validation_container,
.signup__form .gfield_required,
.signup__form .screen-reader-text {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.signup__form input[type="email"] {
  width: 100%;
  background: var(--cream);
  border: 0; padding: .95em 1.1em;
  font-family: var(--font-body); font-size: 1rem;
  color: var(--brown);
}
.signup__form input[type="email"]::placeholder { color: color-mix(in srgb, var(--brown) 45%, transparent); }
.signup__form .gfield_error input[type="email"] { box-shadow: inset 0 0 0 2px var(--orange); }
/* Errors: short and in brand colour, not Gravity Forms' red box. */
.signup__form .gfield_validation_message,
.signup__form .validation_message { margin-top: .4rem; font-size: .82rem; color: var(--yellow); text-align: left; }
.signup__form .gform_validation_errors h2,
.signup__form .gform_submission_error { margin: 0; font-family: var(--font-body); font-size: .85rem; font-weight: 600; color: var(--yellow); text-align: left; }
.signup__form .gform_ajax_spinner { width: 18px; height: 18px; }
.signup__form .gform_confirmation_message {
  font-family: var(--font-header); text-transform: uppercase;
  font-size: clamp(1rem, 1.5vw, 1.5rem); line-height: 1.1;
}
.signup__form iframe[name^="gform_ajax_frame"] { display: none; }

/* Spirits United widget. Its markup arrives over the network as a <dl> of
   dt (label) / dd (input) pairs plus a statement and a submit, with a few
   inline widths and a <font size="1">. Labels are hidden visually because
   every input carries the same words as a placeholder; they stay for screen
   readers. The dd's become a two-column grid: names, then email and zip. */
.signup__form--su { max-width: 700px; }
.signup__form--su form { display: flex; flex-direction: column; align-items: center; gap: .75rem; margin: 0; }
.signup__form--su dl {
  display: grid; grid-template-columns: 1fr 1fr; gap: .75rem;
  width: 100%; margin: 0;
}
.signup__form--su dt {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* #wsd-root in the selector: the widget ships its own <style> with
   `.spkactionform dd { margin-bottom: 10px }`, injected later in the document,
   so an equal-specificity rule here loses to it. */
.signup__form--su #wsd-root dd { margin: 0; min-width: 0; }
.signup__form--su input.text {
  width: 100%;
  background: var(--cream);
  border: 0; border-radius: 0; padding: .95em 1.1em;
  font-family: var(--font-body); font-size: 1rem;
  color: var(--brown);
}
.signup__form--su input.text::placeholder { color: color-mix(in srgb, var(--brown) 45%, transparent); }
.signup__form--su dd.field-statement { grid-column: 1 / -1; order: 99; }
.signup__form--su .field-statement,
.signup__form--su .field-statement font {
  font-size: .82rem; line-height: 1.45; opacity: .88; text-align: center;
}
/* Their submit, dressed as .btn.btn--cream (main.css) — it arrives without
   our classes, so the rules are restated rather than borrowed. */
.signup__form--su input[type="submit"] {
  font-family: var(--font-header); text-transform: uppercase;
  font-size: clamp(.9rem, 1.1vw, 1.15rem); letter-spacing: .03em; line-height: 1;
  padding: .85em 1.5em; border: 0; border-radius: 0; cursor: pointer;
  background: var(--cream); color: var(--brown);
  box-shadow: 5px 5px 0 var(--brown-shadow);
  transition: transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.signup__form--su input[type="submit"]:hover,
.signup__form--su input[type="submit"]:focus-visible { transform: translate(-2px, -2px); box-shadow: 8px 8px 0 var(--brown-shadow); }
.signup__form--su input[type="submit"]:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--brown-shadow); }
.signup__form--su input[type="submit"]:disabled { opacity: .6; cursor: progress; transform: none; }
/* Until the widget has fetched its form, and the thank-you it swaps in after. */
.signup__loading { margin: 0; font-size: .9rem; opacity: .7; }
.signup__form--su #wsd-root > :not(form) {
  font-family: var(--font-header); text-transform: uppercase;
  font-size: clamp(1rem, 1.5vw, 1.5rem); line-height: 1.1;
}
.signup__form--su #wsd-root > .signup__loading { font-family: var(--font-body); text-transform: none; font-size: .9rem; }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

/* Laid out after Spirit Forward's footer: the council mark sits alone on the
   left, a hairline divides it from a centred legal block on the right. Their
   version carries a second logo in that left group; ours is DISCUS only, and
   the ground stays light rather than near-black. */
.footer {
  background: var(--cream);
  color: var(--brown);
  padding-block: clamp(2.5rem, 5vw, 4.5rem);
  /* 300px band, per revision. min-height rather than height so the footer can
     still grow — below 760px the two columns stack and the content is taller
     than this on its own. The grid is only here to centre .footer__inner in
     the extra space; without it the content sits at the top of the band. */
  min-height: 300px;
  display: grid;
  align-content: center;
}
.footer__inner {
  display: grid;
  grid-template-columns: minmax(150px, 24%) 1fr;
  align-items: center;
  gap: clamp(1.75rem, 5vw, 4rem);
}
.footer__brand { display: grid; place-items: center; }
.footer__logo { width: clamp(140px, 15vw, 215px); height: auto; display: block; }

.footer__meta {
  text-align: center;
  border-left: 1px solid rgb(87 34 0 / .2);
  padding-left: clamp(1.75rem, 5vw, 4rem);
}
.footer__meta p { margin: 0; font-size: .9rem; line-height: 1.75; }
.footer__disclaimer { opacity: .78; }

.footer__rule {
  display: block;
  width: 44px; height: 1px;
  background: currentColor; opacity: .38;
  margin: 0 auto clamp(.9rem, 2vw, 1.35rem);
}

.footer__links {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: clamp(.9rem, 2.4vw, 2.4rem);
  margin-top: clamp(1rem, 2.2vw, 1.6rem);
  font-family: var(--font-header);
  text-transform: uppercase;
  font-size: .72rem;
  letter-spacing: .13em;
}
.footer__links a { color: inherit; text-decoration: none; opacity: .9; }
.footer__links a:hover, .footer__links a:focus-visible { opacity: 1; text-decoration: underline; }

@media (max-width: 760px) {
  .footer__inner { grid-template-columns: 1fr; gap: clamp(1.5rem, 5vw, 2.25rem); }
  .footer__meta { border-left: 0; border-top: 1px solid rgb(87 34 0 / .2); padding-left: 0; padding-top: clamp(1.5rem, 5vw, 2.25rem); }
}

/* --------------------------------------------------------------------------
   Back to top
   -------------------------------------------------------------------------- */

.totop {
  position: fixed; right: clamp(1rem, 2.5vw, 2.25rem); bottom: clamp(1rem, 2.5vw, 2.25rem);
  z-index: 70;
  width: 54px; height: 54px;
  display: grid; place-items: center;
  background: var(--orange); color: var(--brown);
  border: 0; cursor: pointer;
  box-shadow: 5px 5px 0 var(--brown);
  opacity: 0; visibility: hidden; transform: translateY(14px);
  transition: opacity .32s var(--ease-out), transform .32s var(--ease-out), visibility .32s;
}
.totop.is-visible { opacity: 1; visibility: visible; transform: none; }
.totop:hover { transform: translate(-2px, -2px); box-shadow: 8px 8px 0 var(--brown); }
.totop svg { width: 24px; height: 24px; }

/* --------------------------------------------------------------------------
   Modal
   -------------------------------------------------------------------------- */

.modal[hidden] { display: none; }
.modal {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  padding: var(--gutter);
}
.modal__backdrop { position: absolute; inset: 0; background: rgb(31 12 4 / .78); border: 0; }
.modal__panel {
  position: relative; z-index: 2;
  background: var(--cream); color: var(--brown);
  width: min(100%, 680px);
  max-height: 84vh; overflow-y: auto;
  padding: clamp(1.75rem, 4vw, 3rem);
  box-shadow: 14px 14px 0 var(--brown-deep);
}
.modal__panel--video { width: min(100%, 1100px); padding: 0; background: #000; aspect-ratio: 16/9; max-height: none; }
.modal__panel--video iframe, .modal__panel--video video { width: 100%; height: 100%; border: 0; display: block; }
.modal__close {
  position: absolute; top: .5rem; right: .5rem; z-index: 3;
  width: 42px; height: 42px;
  background: var(--brown); color: var(--cream);
  border: 0; cursor: pointer; display: grid; place-items: center;
}
.modal__close svg { width: 20px; height: 20px; }
.modal__title { margin: 0 0 1rem; color: var(--maroon); }
.modal__body p { margin: 0 0 1rem; }

/* The Choices lockup and the layered lines are semantic headings; strip the
   user-agent margins so the visual result is unchanged. */
h2.split__lockup, h2.layered__line, p.layered__line { margin: 0; }

/* --------------------------------------------------------------------------
   Mobile refinements — Aaron's mobile comp is not the desktop narrowed:
   display type runs far larger, the header/display ratio opens up, and in the
   Choices split the copy panel comes first.
   -------------------------------------------------------------------------- */

@media (max-width: 760px) {
  :root {
    --display: clamp(3rem, 21vw, 7rem);
    --header:  calc(var(--display) * 0.28);
  }

  .split { grid-template-columns: 1fr; }
  .split__copy  { order: 1; text-align: center; }
  .split__media { order: 2; min-height: 54vw; }
  .split__lockup { justify-items: center; }
  .split__lockup-head,
  .split__lockup-display,
  .split__lockup-sub { padding-left: 0; }

  /* Sized off Aaron's mobile comp, not the desktop scale. Measured on "ALL THE"
     — a single unambiguous line — the comp runs it at 73.47% of viewport while
     ours was 53.33%, so the display was 27% small. The eyebrow and sub were the
     other way, ~9% wide, so --header comes down from .28 to .185 of display.

     Scoped to .hero, NOT :root. The root override at this breakpoint also feeds
     Choices, Enjoy and the mixer, and those measure close to the comp already —
     bumping root would blow them out. Both custom properties are redeclared
     together: --header is calc() off --display on :root, and that resolves ON
     :root, so overriding --display alone leaves --header at the page scale
     (the trap in CLAUDE.md §7.9).

     Height is the comp's own: its hero band is exactly 100% of the artboard
     width. svh not vh, because on iOS vh is the height with the toolbar hidden. */
  .hero {
    --display: clamp(3rem, 28.9vw, 9.6rem);
    --header:  calc(var(--display) * .185);
    min-height: clamp(336px, 100vw, 560px);
  }
  .hero__sub { line-height: 1.05; }
  .hero__eyebrow,
  .hero__display .display-line,
  .hero__display .display-line + .display-line,
  .hero__sub .hero__sub-line,
  .hero__sub .hero__sub-line + .hero__sub-line { left: 0; }

  .signup__inner { flex-direction: column; align-items: stretch; text-align: center; }
  /* The comp keeps the field and the button on ONE row at a real 44px touch
     height. `flex: 0 0 auto` because .signup__inner is a column here, so the
     desktop 380px basis would become a HEIGHT. `font-size: 16px` on the input
     is not cosmetic — iOS Safari zooms the page on a smaller focused field. */
  .signup__form { max-width: none; flex: 0 0 auto; }
  .signup__form .gform_wrapper form { align-items: center; gap: .6rem; }
  .signup__form .cyw-gf-email { flex: 1 1 0; }
  .signup__form input[type="email"] { font-size: 16px; padding: .7em .9em; }
  .signup__form .gform_footer .btn {
    font-size: .82rem;
    padding: .9em 1.05em;
    white-space: nowrap;
    box-shadow: 4px 4px 0 var(--brown-shadow);
  }
  .signup__form--su form { align-items: stretch; }
  .signup__form--su input.text { font-size: 16px; padding: .7em .9em; }
  .signup__form--su input[type="submit"] { font-size: .9rem; box-shadow: 4px 4px 0 var(--brown-shadow); }
  .signup__form--su .field-statement,
  .signup__form--su .field-statement font { text-align: center; }
  .signup__form .cyw-gf-consent,
  .signup__form .gform_validation_errors h2,
  .signup__form .validation_message { text-align: center; }
}

@media (max-width: 420px) {
  .footer__links { gap: 1rem; }
}

/* --------------------------------------------------------------------------
   Small screens: the absolutely-placed desktop stages return to normal flow.
   Aaron's mobile comp stacks these sections, so there is nothing to preserve
   from the artboard percentages below 860px.
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
  .layered__stage,
  .compare__stage,
  .enjoy__stage,
  .savor__stage {
    height: auto; max-height: none;
    display: grid; justify-items: center;
    gap: clamp(.5rem, 2vw, 1.25rem);
    padding: clamp(2.5rem, 7vw, 4rem) var(--gutter);
    text-align: center;
  }

  .layered__line, .layered__drink, .layered__body,
  .enjoy__line, .enjoy__drink, .enjoy__body, .enjoy__endless,
  .compare__num, .compare__sub, .compare__label, .compare__fig, .compare__equals,
  .savor__eyebrow, .savor__display {
    position: relative;
    left: auto; right: auto; top: auto; bottom: auto;
    /* .compare__label centres itself on its figure with translate at desktop.
       Back in normal flow it is centred by text-align, so the offset has to go
       or every label sits half its own width to the left. Anything else this
       reset covers has no translate, so clearing it here is free. */
    translate: none;
    text-align: center;
    white-space: normal;
  }

  .layered { --display: clamp(2.2rem, 13vw, 5rem); }
  .layered__line--a, .layered__line--b { text-align: center; }
  .layered__line--b .display-line { white-space: normal; }
  .layered__drink { height: clamp(200px, 52vw, 300px); order: 2; }
  .layered__line--a { order: 1; }
  .layered__line--b { order: 3; }
  .layered__body    { order: 4; margin-top: 1rem; }

  /* Sized off the comp's own mobile block, not carried over from desktop.
     Measured on the unambiguous groups — "40% ABV", "1.5 OZ", "ONE BEER",
     "TWO COCKTAILS" — the numbers ran ~1.7x small and the labels ~1.5x, so the
     label is a SMALLER fraction of the display here than the .403 the desktop
     artboard gives:  48.2 / 74.4% of viewport for the two labels against
     38.66 / 25.93% for the numbers beside them. */
  .compare { --display: clamp(2rem, 22.1vw, 8.5rem); }
  .compare__label { font-size: calc(var(--display) * .357); }
  /* The standalone "ABV" under the 10% is smaller here than the desktop .5833:
     the comp runs it 12.4% of viewport wide, and at the desktop ratio it came
     out 19% and ran over the bottle's label. */
  .compare__sub { font-size: calc(var(--display) * .38); }
  .compare__stage { grid-template-columns: 1fr; }
  .compare__fig { justify-content: center; height: clamp(160px, 46vw, 260px); }
  .compare__num, .compare__sub { display: inline-block; }
  .compare__equals { justify-items: center; }

  .enjoy__stage { padding-bottom: clamp(2rem, 6vw, 3rem); }
  /* The desktop stage reserves its lockup region with a ::before spacer. Here
     everything is stacked in a grid, so that spacer would just add an empty
     row — and the body is a grid item, so its desktop width has to go too. */
  .enjoy:not(.enjoy--closing) .enjoy__stage::before { content: none; }
  .enjoy__body { width: auto; }
  .enjoy__drink { height: clamp(160px, 44vw, 260px); }
  .enjoy__endless { font-size: clamp(1rem, 4.6vw, 1.6rem); gap: .4em; }
  .enjoy__line { white-space: normal; }

  .savor { --display: clamp(2.2rem, 15vw, 5rem); }
  /* The comp's savor band is 72.5% of the artboard width — 283px on a 390
     phone. Ours was `min-height: 60vh`, which is 506px at 844 and left a deep
     margin of photograph above and below the type. Height comes off the width
     now, and the shared stage padding is cut back for this block. */
  .savor__stage {
    min-height: 72.5vw;
    align-content: center;
    padding-block: clamp(.75rem, 3vw, 1.75rem);
  }
  /* The stage centres its rows, but .savor__content is `position: absolute;
     inset: 0` and is NOT in the reset above — so it stayed a full-bleed box
     with its two lines stacked from the top, and `align-content` on the stage
     never got a say. It has to do its own centring. It stays absolute on
     purpose: it sits over the photograph rather than beside it. */
  .savor__content {
    display: grid;
    align-content: center;
    justify-items: center;
    padding: var(--gutter);
  }
  .savor__display .display-line { white-space: normal; }
  .savor__display .display-line:nth-child(2),
  .savor__display .display-line:nth-child(3) { padding-left: 0; }
  .savor__scrim {
    background: linear-gradient(180deg,
      rgb(255 252 230 / .06) 0%, rgb(255 252 230 / .32) 46%, rgb(255 252 230 / .58) 100%);
  }

  /* ------------------------------------------------------------------------
     Cast shadows on mobile

     Aaron's extracted shadows are placed by artboard percentage against a
     fixed-aspect stage — `height: 63.66%` of a 50vw box. Here the stage is
     `height: auto`, so that percentage resolves against the whole stacked
     column and every shadow smears into a tall vertical bar behind the glass.
     That is the vertical stretch, and it hits Layered, Comparison and Enjoy
     alike (Choices is unaffected — it keeps its 936/850 aspect-ratio box, so
     its percentages still mean what they meant).

     The fix is to stop measuring them against the stage and measure them
     against the drink they fall from, which is also how the mobile comp draws
     them: a compact shape tucked behind the glass and offset right. The markup
     already puts each shadow immediately before its drink, so both can share
     one grid row. Sizes come from each shadow's own .ai BBox aspect ratio, so
     the artwork is never distorted — which matters, because cyw_shadow() emits
     preserveAspectRatio="none" and would happily stretch it.

     Every child of these stages gets an explicit grid-row: mixing explicit and
     auto placement (and `order`) in one grid is how items end up stacking in
     surprising places.
     ------------------------------------------------------------------------ */

  .cyw-shadow--layered,
  .cyw-shadow--enjoy,
  .cyw-shadow--cmp-beer,
  .cyw-shadow--cmp-glass1,
  .cyw-shadow--cmp-glass2 {
    position: static;
    width: auto;
    justify-self: center;
    align-self: center;
  }

  /* ---- Layered. Drink 200-300px; shadow BBox 252.7 x 617.5pt. */
  .layered            { --drink-h: clamp(200px, 52vw, 300px); }
  .layered__drink     { height: var(--drink-h); }
  .layered__line--a   { grid-row: 1; }
  .cyw-shadow--layered,
  .layered__drink     { grid-row: 2; grid-column: 1; }
  .layered__line--b   { grid-row: 3; }
  .layered__body      { grid-row: 4; }
  /* Offsets are derived, not eyeballed: each is the desktop distance between
     the shadow's .ai BBox centre and its drink's centre, expressed as a
     fraction of the drink's width, then converted to a percentage of the
     SHADOW's width — which is what `translate` resolves against. */
  .cyw-shadow--layered {
    height: calc(var(--drink-h) * 1.03);
    aspect-ratio: 252.7 / 617.5;
    translate: 12% 4.8%;
  }

  /* ---- Enjoy. Shadow BBox 230.0 x 282.3pt — much squatter than the others. */
  .enjoy              { --drink-h: clamp(160px, 44vw, 260px); }
  .enjoy__drink       { height: var(--drink-h); }
  .enjoy__line--h1    { grid-row: 1; }
  .enjoy__line--h2    { grid-row: 2; }
  .enjoy__line--d1    { grid-row: 3; }
  .enjoy__line--d2    { grid-row: 4; }
  .cyw-shadow--enjoy,
  .enjoy__drink       { grid-row: 5; grid-column: 1; }
  .enjoy__body        { grid-row: 6; }
  .enjoy__endless     { grid-row: 7; }
  .cyw-shadow--enjoy {
    height: calc(var(--drink-h) * .9);
    aspect-ratio: 230.0 / 282.3;
    translate: 39.9% 3%;
  }

  /* ---- Comparison. Two groups: the bottle, then the glass PAIR, which has
     one shadow per glass sharing a single figure. Each is nudged out to its
     own glass rather than centred on the pair. */
  /* The comp does NOT stack this block into one column. It keeps each figure
     and its own numbers as a GROUP: "10%" left and "12 OZ" right with the
     bottle rising between them, "ABV" tucked under the 10%; then the same for
     the pair, with "40% ABV" and "1.5 OZ" sitting above the glasses. Measured
     off the mobile artboard, as % of viewport width and of the section:

       10% / 12 OZ      y  2.54% - 19.04%   12 OZ ends at 79.67%
       10% starts       x 25.20%
       beer + shadow    x 42.07% - 63.53%
       ONE BEER         centred
       equals           x 42.07% - 57.80%
       40% ABV          x 11.47% - 50.13%   y 56.91% - 67.95%
       1.5 OZ           x 56.60% - 82.53%   same baseline
       glass shadows    x 17.40% - 88.33%

     So there are five rows, not ten, and two of them are overlays: every item
     in a group shares one grid cell and is placed with justify-self /
     align-self. The figure sits centred and the numbers ride the top of the
     same cell, which is what puts them beside the bottle rather than above it. */
  /* The bottle is TALLER than the glasses — 69.2% vs 50% of the section on
     desktop, and the comp's mobile shadows give the same story (beer shadow
     57.33% of viewport width against the glasses' 42.73%, so a 235px bottle
     beside 177px glasses at 390). One shared height flattened them. */
  .compare              { --fig-h: clamp(160px, 45.4vw, 260px);
                          --fig-h-l: calc(var(--fig-h) * 1.33); }
  .compare__fig--l      { height: var(--fig-h-l); }
  .compare__fig--r      { height: var(--fig-h); }

  /* Group 1 — the beer, all in one cell. */
  .compare__num--la,
  .compare__sub--l,
  .compare__num--lb,
  .cyw-shadow--cmp-beer,
  .compare__fig--l      { grid-row: 1; grid-column: 1; }
  /* Pulled in off the cell edges to the comp's own x positions: 10% starts at
     25.20% of viewport and 12 OZ ends at 79.67%, so they sit BESIDE the bottle
     rather than out at the gutters. The cell edge is one --gutter in, hence the
     subtraction. */
  .compare__num--la     { justify-self: start;  align-self: start;
                          translate: calc(25.2vw - var(--gutter)) 0; }
  .compare__sub--l      { justify-self: start;  align-self: start;
                          translate: calc(25.2vw - var(--gutter)) 24.4vw; }
  .compare__num--lb     { justify-self: end;    align-self: start;
                          translate: calc(var(--gutter) - 20.33vw) 0; }
  /* The numbers and the bottle start at the same height in the comp — its
     numbers sit at y 2.54% of the section and the bottle at 3.53% — so this
     group is top-aligned throughout and the numbers simply flank the bottle.
     The glass group below is different: there the numbers sit clear ABOVE the
     glasses, so that row reserves space and the figure drops to the bottom. */
  .compare__fig--l      { justify-self: center; align-self: start; }

  .compare__label--l    { grid-row: 2; }
  .compare__equals      { grid-row: 3; }

  /* Group 2 — the pair. The numbers ride above the glasses, so the figure is
     bottom-aligned and the row is padded by the numbers' own height. */
  .compare__num--ra,
  .compare__num--rb,
  .cyw-shadow--cmp-glass1,
  .cyw-shadow--cmp-glass2,
  .compare__fig--r      { grid-row: 4; grid-column: 1; }
  /* 40% ABV starts at 11.47%, 1.5 OZ ends at 82.53%. */
  .compare__num--ra     { justify-self: start;  align-self: start;
                          translate: calc(11.47vw - var(--gutter)) 0; }
  .compare__num--rb     { justify-self: end;    align-self: start;
                          translate: calc(var(--gutter) - 17.47vw) 0; }
  .compare__fig--r      { justify-self: center; align-self: end; }

  /* The shadows bottom-align with their figure now that the figure does, and
     their vertical offsets are re-derived from the desktop geometry on that
     basis: the beer's shadow sits 1.09% of its own height BELOW the bottle's
     foot, the glasses' 8.03% above theirs. */
  .cyw-shadow--cmp-beer   { align-self: start; }
  .cyw-shadow--cmp-glass1,
  .cyw-shadow--cmp-glass2 { align-self: end; }

  /* The comp runs the equals at 15.73% of viewport wide. */
  .compare__equals { width: 15.73vw; justify-self: center; }
  .compare__equals img { width: 100%; height: auto; }

  .compare__label--r    { grid-row: 5; }

  /* Both groups need room for the numbers above the figure. */
  /* Row 1 is just the bottle's height (numbers ride alongside it). Row 4 adds
     13.2vw so the numbers have somewhere to sit above the glasses, which is
     the 7% of section the comp leaves between them. */
  .compare__stage { grid-template-rows: var(--fig-h-l) auto auto calc(var(--fig-h) + 13.2vw) auto; }

  .cyw-shadow--cmp-beer {
    height: calc(var(--fig-h-l) * .95);
    aspect-ratio: 179.1 / 557.3;
    /* Top-aligned with the bottle now, so the offset is the artboard's own:
       the shadow starts 6.88% of its own height below the bottle's top. */
    translate: 16.1% 6.88%;
  }
  /* Tie the pair's gap to the figure height so the glasses, their shadows and
     the space between them all scale off one number. Left in vw it drifts out
     of step at the clamp's ends and the shadows slide off their glasses. */
  .compare__fig--r { gap: calc(var(--fig-h) * .312); }
  .cyw-shadow--cmp-glass1,
  .cyw-shadow--cmp-glass2 {
    height: calc(var(--fig-h) * .94);
    aspect-ratio: 163.0 / 398.3;
  }
  /* Both shadows are centred on the PAIR, so each has to back out to its own
     glass (half the pitch) before taking the same +0.5-glass-width offset the
     other shadows use. */
  .cyw-shadow--cmp-glass1 { translate: -40.2% -8.03%; }
  .cyw-shadow--cmp-glass2 { translate: 120.8% -8.03%; }
}

/* --------------------------------------------------------------------------
   Age gate — inc/age-gate.php, assets/js/age-gate.js
   Only ever visible under html.cyw-age-locked, which the head script sets
   before first paint, so the page never flashes before the gate.
   -------------------------------------------------------------------------- */

.agegate { display: none; }
html.cyw-age-locked,
html.cyw-age-locked body { overflow: hidden; }
html.cyw-age-locked .agegate {
  position: fixed; inset: 0; z-index: 10000;
  display: grid; place-items: center;
  padding: 16px;
  overflow-y: auto;
  /* The page shows through, knocked back — as on Destination Distillery. */
  background: color-mix(in srgb, var(--brown-deep) 40%, transparent);
  /* 5px, the plugin's --ag-blur on Destination Distillery. */
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
}

.agegate__panel {
  width: 100%; max-width: 34rem;
  padding: clamp(1.75rem, 5vw, 3rem) clamp(1.25rem, 5vw, 3rem);
  background: var(--brown-deep);
  color: var(--cream);
  text-align: center;
  box-shadow: 10px 10px 0 var(--brown-shadow);
}
.agegate__brand {
  margin: 0 0 1.1rem;
  font-family: var(--font-header);
  font-size: clamp(1rem, 2.4vw, 1.25rem);
  line-height: 1;
}
.agegate__brand-script {
  font-family: var(--font-script);
  color: var(--tan);
  text-transform: uppercase;
  font-size: 1.5em;
  line-height: 0;
  vertical-align: -.055em;
}
.agegate__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: clamp(2rem, 6vw, 3.25rem);
  line-height: .95;
  letter-spacing: .01em;
  color: var(--cream);
}
.agegate__sub { margin: .8rem 0 0; font-size: 1rem; opacity: .9; }

.agegate__form { margin-top: 1.4rem; display: grid; justify-items: center; gap: .9rem; }
.agegate__fields {
  display: flex; justify-content: center; gap: .6rem;
  margin: 0; padding: 0; border: 0; min-width: 0;
}
.agegate__input {
  width: 4.6rem;
  padding: .55em .3em;
  background: transparent;
  border: 2px solid var(--tan);
  border-radius: 0;
  color: var(--cream);
  font-family: var(--font-header);
  font-size: 1.35rem;              /* over 16px, so iOS does not zoom on focus */
  letter-spacing: .06em;
  text-align: center;
  -moz-appearance: textfield;
}
.agegate__field--year .agegate__input { width: 6.4rem; }
.agegate__input::placeholder { color: color-mix(in srgb, var(--tan) 70%, transparent); opacity: 1; }
.agegate__input:focus { outline: none; border-color: var(--orange); box-shadow: 0 0 0 3px color-mix(in srgb, var(--orange) 35%, transparent); }

.agegate__errors:empty { display: none; }
.agegate__error { margin: 0; font-size: .92rem; font-weight: 600; color: var(--yellow); }
.agegate__button { min-width: 9rem; }
.agegate__fine { margin: 1.4rem 0 0; font-size: .78rem; line-height: 1.45; opacity: .72; }

@media (max-width: 420px) {
  .agegate__fields { gap: .45rem; }
  .agegate__input { width: 3.9rem; font-size: 1.2rem; }
  .agegate__field--year .agegate__input { width: 5.4rem; }
}
