/* ==========================================================================
   KANONKOP WINE ESTATE — Design System
   "Where the big guns roar"

   Colours come from the estate's own Brand Guide (16/03/2026). The four
   named brand colours are used verbatim:

     Cannon Black    #222221   Pantone Process Black
     Ash Grey        #776f65   Pantone 404C
     Ribbon Red      #9d2235   Pantone 201C
     Vintage Cream   #fffcdf   Pantone 7401C

   Everything else in this file is a documented tint or shade of those four
   (no invented hues), plus an antique gold for small-caps label text — the
   one job the four brand colours cannot do legibly.
   ========================================================================== */

/* ---- Tokens ------------------------------------------------------------ */
:root {
  /* --- brand colours, verbatim from the Brand Guide --- */
  --cannon-black:   #222221;
  --ash-grey:       #776f65;
  --ribbon-red:     #9d2235;
  --vintage-cream:  #fffcdf;

  /* --- creams: Vintage Cream and two steps down from it --- */
  --parchment:      #fffcdf;   /* page background — Vintage Cream itself */
  --parchment-soft: #fbf6d3;   /* card washes */
  --cream:          #f7f0c9;   /* feature bands */
  --cream-soft:     #fbf7d9;   /* cards sitting on a cream band */
  --cream-deep:     #efe4ad;   /* deeper cream — headings/accents on dark */
  --white:          #fffef2;

  /* --- reds: Ribbon Red and shades of it --- */
  --maroon:         #9d2235;   /* Ribbon Red — primary brand / CTAs / links */
  --maroon-deep:    #7c1a29;   /* pressed / hover */
  /* Estate maroon — the rebuild brief's settled two-red system (2026-08-19):
     Estate-tier pages/premium moments use this, Ribbon Red stays for Kadette
     and general brand touchpoints. Token only for now — applying it per page
     is a rebuild-phase task (docs/superpowers/specs/2026-08-19-website-rebuild-plan.md). */
  --maroon-estate:  #642238;
  --oxblood:        #4a1420;   /* deep Ribbon Red — footer */
  --oxblood-deep:   #330e17;   /* footer base bar */

  /* --- inks: Cannon Black and Ash Grey --- */
  --ink:            #222221;   /* Cannon Black */
  --ink-soft:       #4a443c;   /* Ash Grey darkened to clear AA on cream */
  --cellar:         #222221;   /* dark bands — Cannon Black */
  --cellar-soft:    #2e2c29;

  /* Gold, split by job: decoration vs. text.
     --gold is for rules, borders and marks (no contrast requirement).
     --gold-text is the small-caps label colour on light surfaces and clears
     4.5:1 on every cream in this file. --gold-soft is its dark-ground twin. */
  --gold:           #b79a63;
  --gold-text:      #6f5427;
  --gold-soft:      #dcc68f;
  --rule:           rgba(119, 111, 101, .34);
  --rule-soft:      rgba(119, 111, 101, .2);
  --rule-dark:      rgba(220, 198, 143, .22);

  /* legacy alias — older markup still says parchment-deep */
  --parchment-deep: var(--cream);

  --font-display: 'EB Garamond', Garamond, 'Times New Roman', serif;
  --font-text: 'Inter', -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* ---- Type scale ------------------------------------------------------
     One committed scale, used everywhere (client feedback 2026-08-07: "commit
     to a specific sizing … applying it to the full body of text
     consistently"). Before this the site carried 44 different font sizes;
     thirteen of them were "small", most under 12px.

     The two ends were wrong in opposite directions and are now met in the
     middle: the product description came DOWN from 20.8px, and the notes,
     hints and meta lines came UP from 11–12.5px.

       --fs-micro  12px   ONLY tracked all-caps labels — eyebrows, range tags,
                          table headings. Never running prose. This is the
                          floor: nothing on the site is smaller.
       --fs-sm     14px   Secondary reading text — notes, hints, meta, cart
                          lines, fine print.
       --fs-body   16px   Body copy. The anchor.
       --fs-lead   18px   Product descriptions and section intros.

     Headings keep some leeway, as asked, but come off one ladder rather than
     being invented per page. */
  --fs-micro: 0.75rem;
  --fs-sm:    0.875rem;
  --fs-body:  1rem;
  --fs-lead:  1.125rem;

  /* Display figures — prices, analysis values, cart totals. Set in the serif
     face, so they read as typographic features rather than body text. One
     size, so a price on a card, on a product page and in the cart all match. */
  --fs-figure: 1.35rem;

  --fs-h3: clamp(1.25rem, 2.1vw, 1.5rem);
  --fs-h2: clamp(1.7rem, 3.4vw, 2.4rem);
  --fs-h1: clamp(2rem, 4.4vw, 3rem);
  --fs-hero: clamp(2.6rem, 6.5vw, 4.75rem);

  /* ---- Text colour roles ----------------------------------------------
     The other half of the same request — consistent colour coding. Every
     piece of text is one of these five, and nothing picks a raw colour. */
  --text-heading: var(--ink);        /* every heading */
  --text-body:    var(--ink);        /* body copy */
  --text-muted:   var(--ink-soft);   /* secondary copy, notes, meta */
  --text-label:   var(--gold-text);  /* small-caps labels and eyebrows */
  --text-accent:  var(--maroon);     /* links, prices, calls to action */

  --w-content: 1200px;
  --w-narrow: 760px;
  --space-1: .5rem; --space-2: 1rem; --space-3: 1.5rem; --space-4: 2.5rem;
  --space-5: 4rem;  --space-6: 6rem; --space-7: 9rem;

  --shadow-soft: 0 18px 44px -26px rgba(33, 28, 24, .28);

  /* Pack-shot shadow (client feedback 2026-08-07): the estate's current store
     throws the shadow to the RIGHT and BELOW the photo — that offset is what
     gives the bottle dimension and stops the card reading as AI-flat. Two
     layers: a wide soft one for depth, a tight one for the contact edge.
     This is not the old fake ellipse under the bottle (removed in round 2);
     it belongs to the photo panel, and the panel has no frame. */
  --shadow-lift:       10px 13px 28px -14px rgba(34, 34, 33, .34), 3px 4px 9px -5px rgba(34, 34, 33, .16);
  --shadow-lift-hover: 14px 19px 38px -16px rgba(34, 34, 33, .40), 4px 6px 13px -6px rgba(34, 34, 33, .19);

  --ease-lux: cubic-bezier(.22, .8, .36, 1);
}

/* phones get a tighter vertical rhythm — 6rem/9rem bands read as dead space
   on a 390px screen */
@media (max-width: 760px) {
  :root {
    --space-4: 2rem; --space-5: 2.75rem; --space-6: 3.75rem; --space-7: 4.5rem;
  }
}

/* ---- Reset / base ------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  /* stop iOS Safari inflating type in landscape */
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
}
/* Nothing may push the page wider than the viewport — a single overflowing
   child is what makes mobile Safari shrink the whole page to fit ("zoomed
   out"). `clip` is deliberate: unlike `hidden` it does not create a scroll
   container, so position:sticky keeps working. */
html, body { overflow-x: clip; max-width: 100%; }
body {
  font-family: var(--font-text);
  font-size: var(--fs-body); line-height: 1.7;
  color: var(--text-body);
  background: var(--parchment);
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
  /* iOS paints a translucent link-coloured box over a tapped <a>; on the
     product cards (whose whole bottle shot is a link) that reads as a red
     filter over the bottle. */
  -webkit-tap-highlight-color: transparent;
}
img { max-width: 100%; display: block; }

/* Links in running text are underlined so a reader can see they are links
   (client feedback 2026-08-07). Navigation, buttons, cards and icon rows opt
   out below — a menu of underlined items reads as noise, not as links. */
a { color: var(--maroon); text-decoration: underline; text-underline-offset: .18em;
    text-decoration-thickness: from-font; transition: color .25s var(--ease-lux); }
a:hover { color: var(--maroon-deep); }
a.btn, a.chip, a.doc-link, a.wine-card, a.photo-tile, a.gal-item, a.journal-card,
a.brand, a.nav-shop-link, a.icon-btn, a.age-badge, .nav-links a, .social-row a,
.footer-main ul a, .site-footer .brand, a.video-link, a.portrait-card {
  text-decoration: none;
}
/* …but the footer's directory links still underline on hover, so they read
   as links when a reader goes looking */
.footer-main ul a:hover { text-decoration: underline; text-underline-offset: .18em; }
ul { list-style: none; }
button { font: inherit; cursor: pointer; background: none; border: none; }

/* a translucent wash, so a dragged selection tints text instead of flooding
   images with solid maroon */
::selection { background: rgba(157, 34, 53, .2); }

/* pack shots are artwork, not content to select or long-press */
.wine-card img, .bottle-stage img, .brand img, .footer-brand img, .cannon-divider img {
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}

/* ---- Typography -------------------------------------------------------- */
h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  color: inherit;
}
h1 { font-size: var(--fs-h1); letter-spacing: -.01em; }
h2 { font-size: var(--fs-h2); letter-spacing: -.005em; }
h3 { font-size: var(--fs-h3); }
/* the hero is the one place a page may shout */
.hero h1 { font-size: var(--fs-hero); }
.italic { font-style: italic; }

.eyebrow {
  font-family: var(--font-text);
  font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--text-label);
  display: inline-flex; align-items: center; gap: .9em;
  margin-bottom: var(--space-2);
}
/* the flanking rules follow the text colour, so they stay visible on cream,
   on maroon and on the dark bands without extra overrides */
.eyebrow::before { content: ""; width: 2.2em; height: 1px; background: currentColor; opacity: .65; }
.eyebrow.centered::after { content: ""; width: 2.2em; height: 1px; background: currentColor; opacity: .65; }

.dark .eyebrow, .dark-soft .eyebrow, .maroon-bg .eyebrow, .hero .eyebrow { color: var(--gold-soft); }

/* The product description. Was clamp(…, 1.3rem) — 20.8px — which the client
   read as "a tad too big". Now a fixed 18px, one step above body, so a
   description and the copy under it belong to the same system. */
.lead { font-size: var(--fs-lead); line-height: 1.7; color: var(--text-muted); }
.dark .lead { color: var(--cream-deep); }

.measure { max-width: 34em; }

/* ---- Layout ------------------------------------------------------------ */
.container { width: min(var(--w-content), 92vw); margin-inline: auto; }
.container-narrow { width: min(var(--w-narrow), 92vw); margin-inline: auto; }
.section { padding-block: var(--space-6); }
.section-lg { padding-block: var(--space-7); }
.dark { background: var(--cellar); color: var(--parchment); }
.dark-soft { background: var(--cellar-soft); color: var(--parchment); }
.maroon-bg { background: var(--maroon); color: var(--parchment); }
.cream-bg, .parchment-deep-bg { background: var(--cream); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); align-items: center; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); }
/* grid and flex children default to min-width:auto, which lets one wide
   child (a long spec value, a row of vintage chips) stretch its track past
   the viewport. This single rule is what keeps the page from zooming out. */
.grid-2 > *, .grid-3 > *, .grid-4 > *, .stats-grid > *, .footer-main > *,
.wine-detail > *, .chip-row > *, .buy-row > * { min-width: 0; }
@media (max-width: 900px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .grid-4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) { .grid-4 { grid-template-columns: 1fr; } }

.hairline { border: none; border-top: 1px solid var(--rule); margin-block: var(--space-4); }

/* anything that legitimately wants to be wider than a phone scrolls inside
   its own box rather than widening the page */
.scroll-x { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }

/* Cannon divider mark */
.cannon-divider { display: flex; align-items: center; justify-content: center; gap: 1.2rem; margin-block: var(--space-4); }
.cannon-divider::before, .cannon-divider::after { content: ""; height: 1px; width: min(120px, 20vw); background: var(--gold); opacity: .55; }
.cannon-divider img { width: 54px; opacity: .85; }
.dark .cannon-divider img { filter: invert(.9) sepia(.3); }

/* ---- Buttons ----------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .7em;
  /* up from 12.5px, with the tracking eased a touch so the button does not
     get wider as the type gets more legible */
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: 1em 2.1em;
  border: 1px solid currentColor;
  color: var(--maroon);
  transition: all .35s var(--ease-lux);
  position: relative; overflow: hidden;
  text-align: center;
}
.btn::after { content: "→"; letter-spacing: 0; transition: transform .35s var(--ease-lux); }
.btn:hover::after { transform: translateX(.35em); }
.btn-solid { background: var(--maroon); border-color: var(--maroon); color: var(--parchment); }
.btn-solid:hover { background: var(--maroon-deep); border-color: var(--maroon-deep); color: var(--parchment); }
.btn-light { color: var(--parchment); }
.btn-light:hover { background: var(--parchment); color: var(--ink); }
.btn-gold { color: var(--gold-soft); }
.btn-gold:hover { background: var(--gold-soft); border-color: var(--gold-soft); color: var(--cellar); }

/* ---- Header / nav ------------------------------------------------------ */
/* The header is fixed, so every page has to be pushed down past it. That
   clearance used to be a hardcoded padding-top written inline on twelve
   separate pages, which meant the header height and the space reserved for it
   were two unrelated numbers that had to be kept in step by hand — and the
   first time the logo grew, they weren't.
   Now there is one source: --logo-h. Everything else is derived, so changing
   the logo size moves the clearance and the sticky offsets with it. */
:root {
  --logo-h: 112px;                    /* client, 2026-08-12: closer to kanonkop.co.za */
  --logo-h-scrolled: 76px;
  --logo-h-footer: 120px;             /* the footer has room and never shrinks */
  --header-pad: 1.1rem;
  --header-pad-scrolled: .4rem;
  --header-h: calc(var(--logo-h) + var(--header-pad) * 2);
  --header-h-scrolled: calc(var(--logo-h-scrolled) + var(--header-pad-scrolled) * 2);
  /* what a non-hero page reserves at the top: the bar, plus breathing room */
  --page-top: calc(var(--header-h) + 2.4rem);
}
/* There was no tablet rule at all before — desktop values ran all the way
   down to 620px. A 185px-wide lockup does not fit a portrait tablet header
   beside the menu and the two icons, so this range now has its own size. */
@media (max-width: 1000px) {
  :root { --logo-h: 92px; --logo-h-scrolled: 68px; --logo-h-footer: 96px; }
}
/* Phones: the three-zone header is genuinely tight here. .nav-wrap's centre
   column is `auto`, so it will not shrink — an oversized logo crushes the
   burger and the cart icon instead of wrapping, and html{overflow-x:clip}
   hides the damage rather than showing a scrollbar. Hence a conservative
   figure, checked at 360px. */
@media (max-width: 620px) {
  :root { --logo-h: 62px; --logo-h-scrolled: 52px; --logo-h-footer: 76px; }
}

.page-top { padding-top: var(--page-top); }

.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  transition: background .4s var(--ease-lux), box-shadow .4s, padding .4s;
  padding-block: var(--header-pad);
}
.site-header.scrolled {
  background: rgba(255, 252, 223, .96);
  backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--rule);
  padding-block: var(--header-pad-scrolled);
}
/* menu open: the drawer unfolds as part of this same bar (see .nav-drawer
   below), so the header goes solid/opaque instead of transparent — client
   feedback 2026-08-07 wanted the current live site's nav feel, not a
   full-screen takeover */
body.nav-open .site-header {
  z-index: 130; background: var(--parchment); box-shadow: 0 1px 0 var(--rule); backdrop-filter: none;
}
body.nav-open .site-header .brand img { filter: none; }
body.nav-open .site-header .nav-shop-link { color: var(--ink); }
body.nav-open .site-header .icon-btn { color: var(--ink); }
/* three-zone header: menu + shop left · brand centre · login + cart right.
   Full width with its own edge padding (not .container) so the icons sit in
   the corners like the current live site, instead of inset under a centred
   max-width column — client feedback 2026-08-07. */
.nav-wrap {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-2);
  width: 100%; padding-inline: clamp(1rem, 3vw, 2.25rem);
}
.nav-left { display: flex; align-items: center; gap: .4rem; justify-self: start; min-width: 0; }
.nav-right { display: flex; align-items: center; gap: .5rem; justify-self: end; min-width: 0; }

/* The estate's original logo lockup, used as artwork — cannon over the
   wordmark. Never rebuild it from type.

   Header and footer are sized separately. They shared one selector before,
   which meant the footer silently inherited the header's mobile shrink even
   though the footer has neither a scroll state nor a space problem. */
.brand { display: flex; align-items: center; gap: .9rem; justify-self: center; }
.brand img { width: auto; transition: height .4s var(--ease-lux), filter .4s; }
.site-header .brand img { height: var(--logo-h); }
.site-header.scrolled .brand img { height: var(--logo-h-scrolled); }
.footer-brand .brand img { height: var(--logo-h-footer); }

.nav-shop-link {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink); padding: .8em .6em; border-bottom: 1px solid transparent;
}
.nav-shop-link:hover, .nav-shop-link.active { border-bottom-color: var(--gold); color: var(--maroon); }

.icon-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; color: var(--ink);
  transition: color .3s var(--ease-lux);
}
.icon-btn:hover { color: var(--maroon); }
/* profile link: icon + "Log in" / "Hello, Name" (client feedback 2026-08-07) */
.profile-btn { width: auto; gap: .5em; padding-inline: .3em; }
.profile-label {
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: .08em; white-space: nowrap;
}
.profile-btn.signed-in .profile-label { color: var(--maroon); }
/* a signed-in Wine Club member gets a small mark, so it is obvious at a
   glance why prices are showing the member rate */
.profile-btn.club-member .profile-label::after {
  content: "•"; margin-left: .4em; color: var(--maroon);
}
@media (max-width: 560px) { .profile-label { display: none; } }
.icon-btn .cart-count {
  position: absolute; top: 2px; right: 0;
  min-width: 17px; height: 17px; padding-inline: 4px; border-radius: 9px;
  background: var(--maroon); color: var(--parchment);
  font-size: var(--fs-micro); font-weight: 600; line-height: 17px; text-align: center;
}

/* over-hero (transparent) state */
/* the lockup is black artwork; over a photographic hero it inverts to white */
.site-header.on-hero:not(.scrolled) .brand img { filter: invert(1) brightness(1.6); }
.site-header.on-hero:not(.scrolled) .nav-shop-link { color: var(--parchment); }
.site-header.on-hero:not(.scrolled) .icon-btn { color: var(--parchment); }

/* burger — always visible, opens full-screen menu */
.burger { z-index: 120; width: 44px; height: 44px; position: relative; }
.burger span {
  position: absolute; left: 10px; right: 10px; height: 2px; background: var(--ink);
  transition: all .35s var(--ease-lux);
}
.burger span:nth-child(1) { top: 15px; } .burger span:nth-child(2) { top: 22px; } .burger span:nth-child(3) { top: 29px; }
.site-header.on-hero:not(.scrolled) .burger span { background: var(--parchment); }
body.nav-open .burger span { background: var(--ink) !important; }
body.nav-open .burger span:nth-child(1) { top: 22px; transform: rotate(45deg); }
body.nav-open .burger span:nth-child(2) { opacity: 0; }
body.nav-open .burger span:nth-child(3) { top: 22px; transform: rotate(-45deg); }

/* Nav drawer — a horizontal tab bar that unfolds beneath the header when the
   menu button is pressed, and folds back up on the next press (client
   feedback 2026-08-07: match the current live site's nav instead of a
   full-screen takeover). It's a child of .site-header so it opens as part
   of the same fixed bar rather than covering the page. */
.nav-drawer {
  max-height: 0; overflow: hidden;
  transition: max-height .45s var(--ease-lux);
}
body.nav-open .nav-drawer { max-height: 80vh; overflow-y: auto; }
.nav-links {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: .3rem 1.6rem;
  width: 100%; padding: 1.1rem clamp(1rem, 3vw, 2.25rem) 1.4rem;
  border-top: 1px solid var(--rule);
}
.nav-links > li { position: relative; }
.nav-links a, .nav-parent {
  display: inline-flex; align-items: center; gap: .45em;
  font-family: var(--font-text);
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink); padding: .55em .15em; border-bottom: 1px solid transparent;
  text-decoration: none;
}
.nav-links a:hover, .nav-links a.active,
.nav-parent:hover, .sub-open > .nav-parent { color: var(--maroon); border-bottom-color: var(--maroon); }
.nav-caret {
  width: .42em; height: .42em; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-.1em, -.1em); transition: transform .3s var(--ease-lux);
}
.sub-open > .nav-parent .nav-caret { transform: rotate(-135deg) translate(-.15em, -.15em); }

/* Submenus. Desktop floats a panel under the parent; the phone expands the
   list in place so nothing is hidden off-screen. Both are driven by the same
   .sub-open class, plus hover/focus-within on desktop only. */
.nav-sub {
  display: flex; flex-direction: column;
  max-height: 0; overflow: hidden;
  transition: max-height .35s var(--ease-lux);
}
.sub-open > .nav-sub { max-height: 26rem; }
.nav-sub a {
  font-size: var(--fs-sm); font-weight: 500; letter-spacing: .14em;
  color: var(--ink-soft); padding: .5em .15em; white-space: nowrap;
}
.nav-sub a:hover { color: var(--maroon); }

@media (min-width: 900px) {
  /* The drawer clips its own content while it slides (and scrolls on a
     phone). On desktop the submenu is an absolutely-positioned panel that
     has to hang BELOW the bar, so once the drawer is open it must stop
     clipping — otherwise the dropdown is sliced off at the drawer's edge. */
  body.nav-open .nav-drawer { overflow: visible; }
  .nav-sub {
    position: absolute; left: 50%; top: 100%; z-index: 5;
    transform: translateX(-50%);
    min-width: 13rem; padding: .5rem 1rem;
    background: var(--parchment); border: 1px solid var(--rule);
    box-shadow: var(--shadow-soft);
    max-height: 0; opacity: 0; visibility: hidden;
    transition: opacity .25s var(--ease-lux), visibility .25s;
  }
  .nav-links > li:hover > .nav-sub,
  .nav-links > li:focus-within > .nav-sub,
  .sub-open > .nav-sub { max-height: none; opacity: 1; visibility: visible; }
  .nav-sub a { padding: .6em .2em; }
}
@media (max-width: 899px) {
  /* a phone reads this as a list, not a bar — one item per line */
  .nav-links { flex-direction: column; align-items: stretch; gap: 0; text-align: left; }
  .nav-links > li { border-bottom: 1px solid var(--rule-soft); }
  .nav-links > li:last-child { border-bottom: none; }
  .nav-links a, .nav-parent { width: 100%; padding: .95em .2em; border-bottom: none; justify-content: space-between; }
  .nav-sub { padding-left: 1rem; }
  .nav-sub a { white-space: normal; }
}

/* ---- Hero -------------------------------------------------------------- */
.hero {
  position: relative; min-height: 100svh;
  display: flex; align-items: flex-end;
  color: var(--parchment); overflow: hidden;
  isolation: isolate;
}
.hero-media { position: absolute; inset: 0; z-index: -2; }
.hero-media img { width: 100%; height: 100%; object-fit: cover; animation: kenburns 22s var(--ease-lux) both; }
@keyframes kenburns { from { transform: scale(1.12); } to { transform: scale(1); } }
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top, rgba(34, 34, 33,.9) 0%, rgba(34, 34, 33,.26) 45%, rgba(34, 34, 33,.36) 100%);
}
.hero-inner { width: min(var(--w-content), 92vw); margin-inline: auto; padding-block: clamp(4rem, 10vh, 7rem); }
.hero h1 { max-width: 11em; }
.hero .lead { color: rgba(255, 252, 223, .86); max-width: 36em; margin-top: var(--space-3); }
.hero-actions { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: var(--space-4); }

.scroll-cue {
  position: absolute; left: 50%; bottom: 2rem; transform: translateX(-50%);
  width: 1px; height: 70px; background: rgba(255, 252, 223,.35); overflow: hidden;
}
.scroll-cue::after {
  content: ""; position: absolute; top: -40%; left: 0; width: 100%; height: 40%;
  background: var(--gold-soft); animation: cue 2.2s ease-in-out infinite;
}
@keyframes cue { to { top: 120%; } }

/* Page hero (interior pages) */
.page-hero { min-height: 62svh; }
.page-hero h1 { font-size: clamp(2.3rem, 5.5vw, 4.2rem); }

/* ---- Cards ------------------------------------------------------------- */
.card {
  background: var(--white);
  border: 1px solid var(--rule-soft);
  transition: transform .45s var(--ease-lux), box-shadow .45s var(--ease-lux);
}
.card:hover { transform: translateY(-6px); box-shadow: var(--shadow-soft); }
.card-body { padding: var(--space-3); }
.cream-bg .card, .parchment-deep-bg .card { background: var(--cream-soft); border-color: var(--rule); }

/* Wine card — NO frame around the pack shot (client feedback 2026-08-07:
   "haal die raampies om al die produk fotos weg en sit eerder die skadu regs
   en onder die fotos"). The photo sits on its own unframed panel carrying
   --shadow-lift; the text block below it is bare paper. */
.wine-card {
  background: none; border: none;
  text-align: center; position: relative;
  transition: transform .4s var(--ease-lux);
  display: flex; flex-direction: column;
}
.wine-card:hover { transform: translateY(-4px); }
.wine-card .bottle {
  height: 320px; display: flex; align-items: center; justify-content: center;
  padding: var(--space-3); position: relative;
  background: var(--white);
  border-radius: 12px;
  box-shadow: var(--shadow-lift);
  transition: box-shadow .45s var(--ease-lux);
  /* client 2026-08-12: pack shots must stay inside their frame on every
     card, mobile and desktop — never allowed to paint past this box. */
  overflow: hidden;
}
.wine-card:hover .bottle { box-shadow: var(--shadow-lift-hover); }
.wine-card .bottle img {
  max-height: 100%; max-width: 100%; width: auto; object-fit: contain;
  transition: transform .6s var(--ease-lux);
}
.wine-card:hover .bottle img { transform: scale(1.035) translateY(-3px); }
.wine-card .info { padding: var(--space-3) .2rem 0; display: flex; flex-direction: column; gap: .4rem; flex: 1; }
.wine-card .range-tag { font-size: var(--fs-micro); letter-spacing: .28em; text-transform: uppercase; color: var(--text-label); }
/* one size for every product card — the shop, the catalogue, the home strip
   and "products like this" each used to set their own inline */
.wine-card h3 { font-size: var(--fs-h3); }
/* reserve room for two lines so the price sits at the same height whether a
   title wraps ("Kanonkop Cabernet Sauvignon 2020") or not ("...Pinotage 2023") */
.wine-card .info h3 { min-height: 2.3em; }
.wine-card .meta { font-size: var(--fs-sm); color: var(--ink-soft); margin-top: auto; padding-top: .6rem; }
.wine-card .meta span + span::before { content: "·"; margin-inline: .6em; color: var(--gold); }

/* The buy row pins to the bottom of the card so every Add to Cart lines up,
   whatever length the title wraps to. It used to be the "we recommend
   multiples of six" line carrying margin-top:auto; that line is gone, so the
   job moves here. */
.wine-card .buy-row { margin-top: auto; padding-top: .8rem; justify-content: center; }

/* Portrait (legends) card */
.portrait-card { position: relative; overflow: hidden; background: var(--cellar); }
.portrait-card img {
  width: 100%; aspect-ratio: 3 / 3.6; object-fit: cover;
  filter: grayscale(1) contrast(1.05); opacity: .9;
  transition: all .6s var(--ease-lux);
}
.portrait-card:hover img { filter: grayscale(0); opacity: 1; transform: scale(1.03); }
.portrait-card figcaption {
  position: absolute; inset: auto 0 0 0; padding: 1.2rem 1.4rem;
  background: linear-gradient(to top, rgba(34, 34, 33,.93), transparent);
  color: var(--parchment);
}
.portrait-card figcaption .role { display: block; font-size: var(--fs-micro); letter-spacing: .26em; text-transform: uppercase; color: var(--gold-soft); margin-top: .3em; }
.portrait-card figcaption h3 { font-size: var(--fs-h3); }

/* Photo tile */
.photo-tile { position: relative; overflow: hidden; display: block; }
.photo-tile img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4/3; transition: transform .7s var(--ease-lux); }
.photo-tile:hover img { transform: scale(1.05); }
.photo-tile .tile-label {
  position: absolute; inset: auto 0 0 0; padding: 1.1rem 1.3rem;
  background: linear-gradient(to top, rgba(34, 34, 33,.86), transparent);
  color: var(--parchment); font-family: var(--font-display); font-size: var(--fs-h3);
}

/* ---- Stats band -------------------------------------------------------- */
.stats-band { text-align: center; }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
@media (max-width: 800px) { .stats-grid { grid-template-columns: 1fr 1fr; } }
.stat .num {
  font-family: var(--font-display); font-size: clamp(2.4rem, 5vw, 4rem);
  color: var(--gold-soft); line-height: 1;
}
.stat .num sup { font-size: .45em; color: var(--gold); }
.stat .label { font-size: var(--fs-micro); letter-spacing: .24em; text-transform: uppercase; color: rgba(255, 252, 223,.7); margin-top: .8em; }

/* ---- Timeline ---------------------------------------------------------- */
.timeline { position: relative; padding-left: 2.4rem; }
.timeline::before { content: ""; position: absolute; left: 8px; top: 6px; bottom: 6px; width: 1px; background: var(--gold); opacity: .5; }
.timeline-item { position: relative; padding-bottom: var(--space-4); }
.timeline-item::before {
  content: ""; position: absolute; left: -2.4rem; top: 8px; width: 17px; height: 17px;
  border: 1px solid var(--gold); border-radius: 50%; background: var(--parchment);
  transform: translateX(.5px);
}
.timeline-item .year { font-family: var(--font-display); font-size: var(--fs-sm); color: var(--maroon); line-height: 1.1; }
.timeline-item h3 { font-size: var(--fs-h3); margin-block: .3em .2em; }
.timeline-item p { color: var(--ink-soft); max-width: 46em; }

/* Vintage ribbon (kept for any horizontal year rail; always scrolls inside
   its own box so it can never widen the page) */
.vintage-ribbon {
  display: flex; gap: .7rem; overflow-x: auto; max-width: 100%; min-width: 0;
  padding-block: var(--space-2);
  scroll-snap-type: x proximity; scrollbar-width: thin;
}
.vintage-ribbon span {
  flex: 0 0 auto; scroll-snap-align: start;
  font-family: var(--font-display); font-size: var(--fs-body);
  border: 1px solid var(--rule); padding: .45em 1.1em;
  color: var(--ink-soft); background: var(--white);
}
.vintage-ribbon span:first-child { background: var(--maroon); color: var(--parchment); border-color: var(--maroon); }

/* ---- Split editorial ---------------------------------------------------- */
.split-media img { width: 100%; height: 100%; min-height: 420px; object-fit: cover; }
.split-media { position: relative; }
.split-media::after {
  content: ""; position: absolute; inset: 14px; border: 1px solid rgba(255, 252, 223,.5); pointer-events: none;
}
@media (max-width: 760px) { .split-media img { min-height: 300px; } }

/* ---- Process steps ------------------------------------------------------ */
.step { display: grid; grid-template-columns: 90px 1fr; gap: var(--space-3); padding-block: var(--space-3); border-bottom: 1px solid var(--rule-soft); }
.step > * { min-width: 0; }
.step:last-child { border-bottom: none; }
.step .n { font-family: var(--font-display); font-size: 2.6rem; color: var(--gold); line-height: 1; }
.step h3 { font-size: var(--fs-h3); margin-bottom: .3em; }
.step p { color: var(--ink-soft); max-width: 52em; }
@media (max-width: 560px) { .step { grid-template-columns: 56px 1fr; gap: var(--space-2); } .step .n { font-size: 2rem; } }

/* ---- Cultivar bars ------------------------------------------------------ */
.cultivar { margin-bottom: var(--space-2); }
.cultivar .row { display: flex; justify-content: space-between; gap: 1em; font-size: var(--fs-sm); letter-spacing: .1em; text-transform: uppercase; margin-bottom: .45em; }
.cultivar .track { height: 6px; background: var(--rule-soft); }
.cultivar .fill { height: 100%; background: var(--maroon); width: 0; transition: width 1.4s var(--ease-lux); }
.revealed .cultivar .fill { width: var(--w); }

/* ---- Pricing / club cards ----------------------------------------------- */
.tier-card {
  background: var(--white); border: 1px solid var(--rule);
  padding: var(--space-4) var(--space-3); text-align: center;
  display: flex; flex-direction: column; gap: var(--space-2);
  transition: all .45s var(--ease-lux);
}
.tier-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-soft); border-color: var(--gold); }
.tier-card .tier-name { font-size: var(--fs-micro); letter-spacing: .28em; text-transform: uppercase; color: var(--gold-text); }
.tier-card ul { display: flex; flex-direction: column; gap: .55em; font-size: var(--fs-body); color: var(--text-muted); flex: 1; }
.cream-bg .tier-card, .parchment-deep-bg .tier-card { background: var(--cream-soft); }

/* ---- Tables ------------------------------------------------------------- */
.lux-table { width: 100%; border-collapse: collapse; font-size: var(--fs-body); }
.lux-table th {
  font-size: var(--fs-micro); letter-spacing: .24em; text-transform: uppercase; color: var(--gold-text);
  text-align: left; padding: .9em 1em; border-bottom: 1px solid var(--gold);
}
.lux-table td { padding: .9em 1em; border-bottom: 1px solid var(--rule-soft); vertical-align: top; }
.lux-table td:last-child { font-family: var(--font-display); font-size: var(--fs-figure); white-space: nowrap; }

/* The always-open "Wine details" spec table from round 2 is gone: the client
   read it as product overload ("kan ons die tabel eerder uithaal, dit lyk nie
   nice nie"). Winemaker / origin / soil / vine age now live in the vintage's
   fact-sheet PDF only. */

/* analysis strip — ALC · RS · pH · TA, sits UNDER the prose in Product
   Information (client: "die wyn analises onder die paragrawe en nie bo nie") */
.analysis-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  gap: 1rem 1.2rem; min-width: 0;
  padding: var(--space-3) 0;
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
}
/* Client 2026-08-13: "align these columns so the red titles are the same
   height, and the black numbers are at the same height." Labels wrap to a
   different number of lines per column ("Residual Sugar" vs "pH"), which
   pushed each column's value down by a different amount. Reserving a fixed
   two-line box for every label — bottom-aligned, so a one-line label sits on
   the same line as the last line of a wrapped one — makes every value start
   at an identical offset regardless of how its own label wraps. */
.analysis-row > div { display: flex; flex-direction: column; }
.analysis-row .k {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .18em; text-transform: uppercase; color: var(--gold-text);
  line-height: 1.3; min-height: 2.6em;
  display: flex; align-items: flex-end;
}
.analysis-row .v { font-family: var(--font-display); font-size: var(--fs-figure); margin-top: .15em; color: var(--ink); }

/* ---- Accordion ----------------------------------------------------------- */
details.acc { border-bottom: 1px solid var(--rule); }
details.acc summary {
  font-family: var(--font-display); font-size: var(--fs-lead); padding: 1.1em .2em;
  cursor: pointer; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 1em;
}
details.acc summary::-webkit-details-marker { display: none; }
details.acc summary::after { content: "+"; font-size: 1.4em; color: var(--gold); transition: transform .3s; flex: 0 0 auto; }
details.acc[open] summary::after { transform: rotate(45deg); }
details.acc .acc-body { padding: 0 .2em 1.6em; color: var(--ink-soft); overflow-wrap: anywhere; }

/* ---- Forms --------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: .45em; margin-bottom: var(--space-2); min-width: 0; }
.field label { font-size: var(--fs-micro); letter-spacing: .22em; text-transform: uppercase; color: var(--gold-text); }
.field input, .field textarea, .field select {
  font: inherit; padding: .85em 1em; color: var(--ink); max-width: 100%;
  background: var(--white); border: 1px solid var(--rule);
  border-radius: 0; transition: border-color .3s;
}
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--maroon); }
/* the one field on "My details" that stays fixed (the account's email) reads
   as locked, now that its neighbours are genuinely editable */
.field input:disabled { background: var(--parchment-soft); color: var(--text-muted); cursor: not-allowed; }

/* Newsletter sign-up — one field, on the footer's cream. The full GHL hosted
   form lived here briefly and was pulled: six fields is too much friction for
   a footer, and the welcome email flow gathers the rest. */
.newsletter-inline { display: flex; flex-wrap: wrap; gap: .6rem; max-width: 460px; }
.newsletter-inline input {
  flex: 1 1 12rem; min-width: 0; font: inherit; padding: .85em 1em;
  background: var(--white); border: 1px solid var(--rule); color: var(--ink);
  border-radius: 0;
}
.newsletter-inline input::placeholder { color: var(--ash-grey); }
.newsletter-inline input:focus { outline: none; border-color: var(--maroon); }
.newsletter-msg { flex: 1 0 100%; font-size: var(--fs-sm); margin-top: .2rem; }
.newsletter-msg.error { color: var(--maroon); }
.newsletter-msg.ok { color: var(--maroon); font-family: var(--font-display); font-size: var(--fs-sm); }

/* ---- Footer -------------------------------------------------------------- */
/* Vintage Cream footer, matching the rest of the page (client feedback
   2026-08-07: the dark oxblood footer read as a black box; the same cream
   used everywhere else is correct). A pure directory — hours, contact,
   quick links — no marketing copy, per the same feedback. */
/* Vintage Cream proper — the same lighter yellow as the catalogue, not the
   browner --cream band (client feedback 2026-08-07: "the darker browner
   colour looks less aesthetic online"). */
.site-footer {
  background: var(--parchment); color: var(--text-muted);
  font-size: var(--fs-body);
  border-top: 1px solid var(--rule);
}
.footer-main { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.4fr; gap: var(--space-4); padding-block: var(--space-6) var(--space-4); }
@media (max-width: 900px) { .footer-main { grid-template-columns: 1fr 1fr; } }
/* Client 2026-08-13: centre the footer nav and details on mobile, where it
   was left-aligned like the desktop columns. */
@media (max-width: 560px) {
  .footer-main { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .footer-brand .brand { justify-self: center; }
  .footer-bottom { justify-content: center; text-align: center; }
}
.site-footer h4 { font-size: var(--fs-micro); letter-spacing: .28em; text-transform: uppercase; color: var(--gold-text); margin-bottom: 1.2em; font-family: var(--font-text); }
.site-footer a { color: var(--ink-soft); }
.site-footer a:hover { color: var(--maroon); }
.site-footer li { margin-bottom: .55em; }
.footer-brand .brand { justify-self: start; }
.footer-bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: .6rem 1.4rem;
  padding-block: var(--space-3);
  font-size: var(--fs-sm); letter-spacing: .05em; color: var(--ink-soft);
}
.footer-base { background: var(--parchment-soft); border-top: 1px solid var(--rule-soft); }
.footer-base a { color: var(--ink-soft); }
.social-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1.15rem; }
.social-row a { display: inline-flex; color: var(--ink-soft); transition: color .25s var(--ease-lux); text-decoration: none; }
.social-row a:hover { color: var(--maroon); }
/* the Aware.org pledge mark, at a size that can actually be read */
.age-badge { display: inline-flex; align-items: center; text-decoration: none; }
.age-badge img { height: auto; width: 190px; max-width: 45vw; }
@media (max-width: 560px) { .age-badge img { width: 170px; } }
.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;
}

/* ---- Info boxes (shop ordering/delivery/payment) -------------------------
   Grey boxes, light text — matches the newsletter sign-up module on the
   live site (client feedback 2026-08-07), instead of plain running text. */
.info-box-row { gap: var(--space-3); }
.info-box { background: var(--ash-grey); color: var(--parchment); padding: var(--space-3); }
.info-box .eyebrow { color: var(--gold-soft); }
.info-box p:not(.eyebrow) { color: rgba(255, 252, 223,.92); font-size: var(--fs-body); }
/* underlined so the links inside are obviously links (client feedback) */
.info-box a { color: var(--gold-soft); text-decoration: underline; text-underline-offset: .18em; }
.info-box a:hover { color: var(--parchment); }

/* ---- Reveal animations --------------------------------------------------- */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .9s var(--ease-lux), transform .9s var(--ease-lux); }
.reveal.revealed { opacity: 1; transform: none; }
.reveal-stagger > * { opacity: 0; transform: translateY(28px); transition: opacity .8s var(--ease-lux), transform .8s var(--ease-lux); }
.reveal-stagger.revealed > * { opacity: 1; transform: none; }
.reveal-stagger.revealed > *:nth-child(2) { transition-delay: .12s; }
.reveal-stagger.revealed > *:nth-child(3) { transition-delay: .24s; }
.reveal-stagger.revealed > *:nth-child(4) { transition-delay: .36s; }
.reveal-stagger.revealed > *:nth-child(5) { transition-delay: .48s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .reveal, .reveal-stagger > * { opacity: 1; transform: none; }
}

/* ---- Cart ---------------------------------------------------------------- */
.cart-fab {
  position: fixed; right: 1.6rem; bottom: 1.6rem; z-index: 140;
  width: 60px; height: 60px; border-radius: 50%;
  background: var(--maroon); color: var(--parchment);
  box-shadow: 0 12px 30px -8px rgba(33,28,24,.45);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.45rem; transition: transform .3s var(--ease-lux), background .3s;
}
.cart-fab:hover { transform: translateY(-3px); background: var(--maroon-deep); }
.cart-count {
  position: absolute; top: -4px; right: -4px;
  min-width: 22px; height: 22px; padding-inline: 5px; border-radius: 11px;
  background: var(--gold); color: var(--cellar);
  font-size: var(--fs-micro); font-weight: 600; line-height: 22px; text-align: center;
}
.cart-overlay {
  position: fixed; inset: 0; z-index: 150; background: rgba(34, 34, 33,.55);
  opacity: 0; visibility: hidden; transition: all .35s var(--ease-lux);
}
/* per-order quantity cap notice — sits above the cart drawer so it is seen
   even when "Add to cart" opens the drawer in the same click */
.cap-toast {
  position: fixed; top: 1.2rem; left: 50%; z-index: 200;
  max-width: min(420px, 92vw);
  background: var(--maroon); color: var(--parchment);
  padding: .9em 1.2em; border-radius: 4px;
  font-size: var(--fs-sm); line-height: 1.4;
  box-shadow: 0 12px 30px -10px rgba(34, 34, 33,.45);
  transform: translate(-50%, -140%); opacity: 0; pointer-events: none;
  transition: transform .35s var(--ease-lux), opacity .35s var(--ease-lux);
}
.cap-toast.show { transform: translate(-50%, 0); opacity: 1; }
.cart-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 160;
  width: min(420px, 94vw); background: var(--parchment);
  border-left: 1px solid var(--rule);
  display: flex; flex-direction: column;
  transform: translateX(102%); transition: transform .45s var(--ease-lux);
  box-shadow: -30px 0 60px -30px rgba(34, 34, 33,.5);
}
body.cart-open .cart-overlay { opacity: 1; visibility: visible; }
body.cart-open .cart-drawer { transform: none; }
body.cart-open { overflow: hidden; }
.cart-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 1.3rem 1.5rem; border-bottom: 1px solid var(--rule);
}
.cart-head h3 { font-size: var(--fs-h3); }
.cart-x { font-size: 1.7rem; line-height: 1; color: var(--ink-soft); padding: .2em .4em; }
.cart-x:hover { color: var(--maroon); }
.cart-body { flex: 1; overflow-y: auto; padding: 1rem 1.5rem; }
.cart-empty { padding: 2.5rem 1.5rem; text-align: center; color: var(--ink-soft); }
.cart-row {
  display: grid; grid-template-columns: 1fr auto; gap: .4rem .8rem;
  padding-block: 1rem; border-bottom: 1px solid var(--rule-soft);
}
.cart-row > * { min-width: 0; }
.cart-row-info { grid-column: 1 / -1; display: flex; flex-direction: column; }
.cart-row-info strong { font-family: var(--font-display); font-size: var(--fs-body); font-weight: 600; }
.cart-row-unit { font-size: var(--fs-sm); color: var(--ink-soft); }
/* the drawer reuses .qty-field so a bottle count can be typed or stepped by
   one here too — the old ±6 buttons were the client's "Ek kan nie die
   quantity minder as 6 maak" complaint */
.cart-qty { display: flex; align-items: center; gap: .7rem; }
/* the drawer is tighter than a product page, so its stepper sits one step down */
.cart-qty .qty-field button { width: 2.2em; font-size: var(--fs-sm); }
.cart-qty .qty-field input { width: 2.9em; font-size: var(--fs-sm); }
.cart-row-remove { font-size: var(--fs-sm); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-soft); text-decoration: underline; }
.cart-row-remove:hover { color: var(--maroon); }
.cart-row-total { font-family: var(--font-display); font-size: var(--fs-body); color: var(--maroon); align-self: center; }
.cart-row-total .was { display: block; font-size: var(--fs-sm); color: var(--ash-grey); text-decoration: line-through; }
.cart-foot { padding: 1.2rem 1.5rem 1.5rem; border-top: 1px solid var(--rule); }
.cart-sub { display: flex; justify-content: space-between; align-items: baseline; gap: 1em; margin-bottom: .6rem; }
/* the PayFast handoff copy sat flush against the submit button below it
   (client feedback 2026-08-13) — give it room to breathe */
#pay-copy { margin-bottom: var(--space-2); }
.cart-sub strong { font-family: var(--font-display); font-size: var(--fs-figure); color: var(--maroon); }
.cart-line { display: flex; justify-content: space-between; gap: 1em; font-size: var(--fs-sm); color: var(--ink-soft); margin-bottom: .35rem; }
.cart-line.club { color: var(--maroon); }
.cart-form .field input, .cart-form .field textarea, .cart-form .field select { background: var(--white); }
/* City + postal code share a line; everything else is full width */
.field-row { display: grid; grid-template-columns: 1.6fr 1fr; gap: 0 var(--space-2); }
.field-row > * { min-width: 0; }
/* Date-of-birth: day/month narrower, year wider for 4 digits */
.field-row.dob-row { grid-template-columns: 1fr 1fr 1.3fr; }
.check-field {
  display: flex; align-items: flex-start; gap: .7em;
  font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.5;
  margin-bottom: var(--space-2); cursor: pointer;
}
.check-field input { width: 1.05em; height: 1.05em; margin-top: .28em; accent-color: var(--maroon); flex: 0 0 auto; }
.add-to-cart { margin-top: .4rem; }

/* Wine Club qualification prompt in the checkout. Deliberately the loudest
   thing in the drawer other than the pay button — it only ever appears on an
   order that has already qualified, so it is good news, not an upsell. */
.club-prompt {
  background: rgba(157, 34, 53, .07);
  border: 1px solid var(--maroon);
  padding: var(--space-2);
  margin-block: var(--space-2);
  font-size: var(--fs-sm); color: var(--text-muted);
}
.club-prompt-head {
  font-family: var(--font-display); font-size: var(--fs-lead);
  color: var(--text-accent); margin-bottom: .3em;
}
.club-prompt p + p { margin-top: .5em; }
.club-prompt-q { font-weight: 600; color: var(--text-body); }
.club-prompt-choice { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; margin-top: .6rem; }
.club-prompt-choice label {
  display: inline-flex; align-items: center; gap: .5em;
  cursor: pointer; color: var(--text-body);
  font-size: 1em; letter-spacing: normal; text-transform: none;
}
.club-prompt-choice input { width: 1.05em; height: 1.05em; accent-color: var(--maroon); }

/* The invitation panel at the top of the cart drawer — the estate's club
   journey promises a notification THE MOMENT the basket crosses the
   threshold, not just a radio at checkout. Same family as .club-prompt but
   pinned above the items, framed as an invitation. */
.club-invite {
  background: rgba(157, 34, 53, .07);
  border: 1px solid var(--maroon);
  border-left-width: 4px;
  padding: var(--space-2);
  margin: 1rem 1.5rem 0; /* matches .cart-body's side padding */
  font-size: var(--fs-sm); color: var(--text-muted);
}
.club-invite-eyebrow {
  font-size: var(--fs-micro); letter-spacing: .28em; text-transform: uppercase;
  color: var(--maroon); font-weight: 600; margin-bottom: .35em;
}
.club-invite .club-prompt-head { font-family: var(--font-display); font-size: var(--fs-lead); color: var(--text-accent); margin-bottom: .3em; }
.club-invite p + p { margin-top: .5em; }
.club-invite-consent {
  display: inline-flex; align-items: center; gap: .55em; margin-top: .7em;
  cursor: pointer; color: var(--text-body); font-weight: 600;
}
.club-invite-consent input { width: 1.1em; height: 1.1em; accent-color: var(--maroon); }

/* the header badge announces the crossing when the drawer is closed */
@keyframes club-pulse {
  0%, 100% { transform: scale(1); }
  25% { transform: scale(1.6); }
  55% { transform: scale(1); }
  75% { transform: scale(1.35); }
}
.cart-count.pulse { animation: club-pulse 1.2s var(--ease-lux, ease) 2; }
@media (prefers-reduced-motion: reduce) {
  .cart-count.pulse { animation: none; }
}

/* PayFast handoff / order outcome */
.pay-note { display: flex; align-items: center; gap: .6em; font-size: var(--fs-sm); color: var(--ink-soft); margin-block: .7rem; }
.pay-note strong { color: var(--ink); }

/* checkout progress */
.cart-steps {
  display: flex; justify-content: center; flex-wrap: wrap; gap: .5rem 1.4rem;
  list-style: none; padding: .9rem 1.2rem; margin: 0;
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft);
}
.cart-steps li { display: flex; align-items: center; gap: .5em; }
.cart-steps li span {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid var(--rule); font-size: var(--fs-micro); letter-spacing: 0;
}
.cart-steps li.current { color: var(--maroon); font-weight: 600; }
.cart-steps li.current span { background: var(--maroon); border-color: var(--maroon); color: var(--parchment); }
.cart-steps li.done { color: var(--gold-text); }
.cart-steps li.done span { background: var(--gold); border-color: var(--gold); color: var(--cellar); }

/* persistent cart messages */
.cart-msgs {
  font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.55;
  padding: .7em .9em; margin-block: .6rem;
  background: rgba(183, 154, 99,.14); border-left: 2px solid var(--gold);
}
.cart-msgs strong { color: var(--maroon); }

/* ---- Shop -------------------------------------------------------------- */
.chip-row { display: flex; flex-wrap: wrap; gap: .6rem; }
.chip {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: .65em 1.3em; border: 1px solid var(--rule); color: var(--ink-soft);
  transition: all .3s var(--ease-lux);
}
.chip:hover, .chip.active { background: var(--maroon); border-color: var(--maroon); color: var(--parchment); }
.price { font-family: var(--font-display); font-size: var(--fs-figure); color: var(--maroon); }
.price .note { font-size: var(--fs-micro); font-family: var(--font-text); letter-spacing: .08em; color: var(--ink-soft); display: block; }

/* shop category selector — dropdown on mobile, tabs on desktop */
.cat-select { display: none; }
@media (max-width: 700px) {
  #shop-filter.chip-row { display: none; }
  .cat-select {
    display: block; width: 100%; max-width: 100%; font: inherit; padding: .9em 1em;
    background: var(--white); border: 1px solid var(--rule); color: var(--ink);
    font-size: var(--fs-sm); letter-spacing: .12em; text-transform: uppercase; border-radius: 0;
  }
}

/* hidden attribute must always win, even over display:grid/flex rules */
[hidden] { display: none !important; }

/* ---- Wine detail -------------------------------------------------------- */
/* The bottle keeps its sticky anchor (client: "Ek like dat die foto geanker
   is soos jy scroll") but loses its frame and shows noticeably larger — the
   column is wider and the panel carries the same offset shadow as the cards. */
.wine-detail { display: grid; grid-template-columns: minmax(300px, 6fr) 7fr; gap: var(--space-5); align-items: start; }
@media (max-width: 900px) { .wine-detail { grid-template-columns: 1fr; gap: var(--space-4); } }
.wine-detail .bottle-stage {
  /* clears the SCROLLED header — by the time this is pinned the page has
     scrolled, so the shrunken bar is the one to clear. Derived, not a magic
     number: at 110px it used to tuck the bottle behind the header the moment
     the logo grew. */
  position: sticky; top: calc(var(--header-h-scrolled) + 1rem);
  background: var(--white);
  border: none; border-radius: 14px;
  box-shadow: var(--shadow-lift);
  display: flex; align-items: center; justify-content: center;
  min-height: 620px; padding: var(--space-4) var(--space-3);
  /* belt-and-braces (client 2026-08-12: "the packshot goes big before it
     snaps in the frame"): the image must never be able to paint outside
     this box for even a moment, on any viewport, regardless of how long
     the pack shot itself takes to load. */
  overflow: hidden;
}
.wine-detail .bottle-stage img { max-height: 600px; max-width: 100%; width: auto; object-fit: contain; }

/* Mobile: the pack shots are tall and narrow (roughly 0.27:1), so the old 4/5
   box let the bottle run past the stage and fill the screen — the client's
   "on mobile the packshot isn't doing what it is supposed to". Cap the stage
   by viewport height and keep the bottle inside it, so the title and price are
   still on screen instead of below a giant bottle.
   This block must stay AFTER the rule above: same specificity, so source
   order is what stops the 600px desktop cap from winning on a phone. */
@media (max-width: 900px) {
  .wine-detail .bottle-stage {
    position: static; min-height: 0; aspect-ratio: auto;
    height: min(58vh, 420px); padding: var(--space-3);
  }
  /* The cap is spelled out in the same units as the stage, NOT max-height:
     100% — iPhone Safari resolves a percentage max-height against this
     min()-sized flex parent unreliably, let the image blow up to natural
     size and cropped it to the frame (Wiam's mobile screenshots,
     2026-08-17). Chrome was always fine; this form is right in both. */
  .wine-detail .bottle-stage img {
    max-height: calc(min(58vh, 420px) - 2 * var(--space-3));
    max-width: 100%; width: auto; object-fit: contain;
  }
}

/* title carries the brand and the vintage, big enough not to be hunted for
   (client: "Kanonkop Pinotage 2023 … groot genoeg dat mense nie na dit soek
   nie") */
/* the product title is a page title — same rung as every other h1, rather
   than its own invented clamp */
.wine-title { font-size: var(--fs-h1); line-height: 1.1; }
.wine-title .vintage { white-space: nowrap; }

/* the bottle format, one line under the title — same treatment on every
   single-bottle, magnum and large-format page (not the gift/mixed-case
   pages, which have no one size to state) */
.wine-subheading {
  font-family: var(--font-text);
  font-size: var(--fs-sm); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-label);
  margin-top: .4rem;
}

/* ---- Buy box (price · quantity · add) ----------------------------------- */
.buy-row { display: flex; flex-wrap: wrap; align-items: stretch; gap: .7rem; }
.buy-row .btn { flex: 1 1 14rem; }

/* quantity is free-form: any number of bottles, stepping by one. The estate
   recommends six, it never forces six (client: "Ons raai slegs mense aan om
   in veelvoude van 6 te koop, maar ons forseer hul nooit"). */
.qty-field {
  display: inline-flex; align-items: stretch; flex: 0 0 auto;
  border: 1px solid var(--rule); background: var(--white);
}
.qty-field button {
  width: 2.7em; color: var(--maroon); font-size: var(--fs-body); line-height: 1;
  transition: all .25s var(--ease-lux);
}
.qty-field button:hover { background: var(--maroon); color: var(--parchment); }
.qty-field button:disabled { color: var(--rule); cursor: not-allowed; background: none; }
.qty-field input {
  width: 3.2em; text-align: center; font: inherit;
  font-family: var(--font-display); font-size: var(--fs-body);
  color: var(--ink); background: none; border: none;
  border-inline: 1px solid var(--rule-soft);
  -moz-appearance: textfield; appearance: textfield;
}
.qty-field input::-webkit-outer-spin-button,
.qty-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-field input:focus { outline: none; background: var(--parchment-soft); }
.qty-note { font-size: var(--fs-sm); color: var(--ink-soft); margin-top: .5rem; }

/* Wine Club pricing — original struck through and greyed, member price beside
   it in Ribbon Red (client feedback 2026-08-07) */
.price .was {
  color: var(--ash-grey); text-decoration: line-through;
  font-size: .78em; margin-right: .45em; opacity: .8;
}
.price .member { color: var(--maroon); }
.member-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem;
  font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.55;
  padding: .7em .9em;
  background: rgba(157, 34, 53, .07); border-left: 2px solid var(--maroon);
}
.member-bar strong { color: var(--maroon); }
.member-bar button { font-size: var(--fs-sm); letter-spacing: .14em; text-transform: uppercase; color: var(--maroon); text-decoration: underline; }

.spec-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--space-3); margin-block: var(--space-4); min-width: 0; }
.spec-grid > * { min-width: 0; }
.spec .k { font-size: var(--fs-micro); letter-spacing: .24em; text-transform: uppercase; color: var(--gold-text); }
.spec .v { font-family: var(--font-display); font-size: var(--fs-figure); margin-top: .25em; }

/* ---- Vintage selector (wine detail) -------------------------------------
   A composed <select>, never a horizontal chip ribbon: the ribbon's flex row
   was what forced the page wider than the phone and made Safari zoom out.
   The "current release / library vintage" flag beside it is gone — the
   client reads it in the option label instead ("2020 — current release"). */
.wine-section { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--rule); }
.wine-section > .eyebrow { margin-bottom: var(--space-2); }

.vintage-field { display: flex; flex-direction: column; gap: .5em; min-width: 0; max-width: 20rem; }
.vintage-field > label {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .22em;
  text-transform: uppercase; color: var(--gold-text);
}
.vintage-select {
  font: inherit; font-family: var(--font-display); font-size: var(--fs-lead);
  width: 100%; max-width: 100%;
  padding: .62em 2.6em .62em 1em; color: var(--ink);
  background-color: var(--white);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%236f5427' stroke-width='1.4' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1em center; background-size: 11px auto;
  border: 1px solid var(--gold); border-radius: 0;
  appearance: none; -webkit-appearance: none;
  transition: border-color .3s;
}
.vintage-select:focus-visible { outline: none; border-color: var(--maroon); box-shadow: 0 0 0 2px rgba(157, 34, 53,.18); }

.vintage-panel { margin-top: var(--space-3); }
/* every stacked prose block breathes — Product Information stacks winemaking
   above the tasting note, and they must not run together */
.prose-block + .prose-block { margin-top: var(--space-3); }
.prose-block h4 {
  font-family: var(--font-text); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase; color: var(--gold-text);
  margin-bottom: .5em;
}
.prose-block p { color: var(--ink-soft); }
.doc-row { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: var(--space-3); }
.doc-link {
  display: inline-flex; align-items: center; gap: .6em;
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: .8em 1.2em; border: 1px solid var(--rule); color: var(--maroon);
  transition: all .3s var(--ease-lux);
}
.doc-link:hover { background: var(--maroon); border-color: var(--maroon); color: var(--parchment); }
.doc-link::before { content: "↓"; }
.doc-link.ext::before { content: "↗"; }
.doc-link.pending { border-style: dashed; color: var(--ink-soft); pointer-events: none; }
.doc-link.pending::before { content: "·"; }

/* awards & ratings for the selected vintage — a list when the estate supplies
   per-vintage award data, the PDF on its own until then */
.award-list { display: flex; flex-direction: column; gap: .5em; color: var(--ink-soft); }
.award-list li { display: flex; justify-content: space-between; gap: 1em; align-items: baseline; }
.award-list li > span:last-child { font-family: var(--font-display); color: var(--maroon); white-space: nowrap; }

/* gift-page "What's included" list — box/case first, then each bottle it holds */
.includes-list { display: flex; flex-direction: column; gap: .5em; color: var(--ink-soft); }
.includes-list li { position: relative; padding-left: 1.2em; }
.includes-list li::before { content: "•"; position: absolute; left: 0; color: var(--maroon); }

/* ---- Log in ------------------------------------------------------------- */
/* A narrow centred panel, the shape the estate's current Commerce7 login
   uses, so the journey feels the same during the transition. */
.auth-panel {
  width: min(28rem, 92vw); margin-inline: auto; text-align: center;
  background: var(--white); border: 1px solid var(--rule);
  padding: var(--space-4) var(--space-3);
}
.auth-panel h1 { font-size: clamp(1.9rem, 3.6vw, 2.5rem); }
.auth-panel form { text-align: left; }
.auth-panel .field { margin-bottom: var(--space-2); }
.auth-panel .hairline { margin-block: var(--space-3); }

/* ---- GoHighLevel embedded forms (log in / create account / reset) --------
   The form is a cross-origin iframe, so nothing inside it can be styled from
   this file — the fonts, colours, field shapes and button all live in GHL's
   own form builder, and have to be set to match there. See
   docs/GHL-FORMS-SETUP.md for the exact values.

   What this owns is the frame around it: the panel it sits in, its width, and
   keeping the iframe transparent so the panel's own background shows through
   rather than a white rectangle floating on cream.

   TWO RULES, both learned the hard way:

   · NEVER put loading="lazy" on one of these iframes. form_embed.js sizes the
     frame through a postMessage handshake; a lazy iframe below the fold never
     loads, never handshakes, and the script then parks it at
     opacity:0 / left:-9999px. The form disappears with no error in the
     console and no failed request — it simply is not there.

   · The panel must not impose a fixed height. GHL posts the real content
     height back and the script writes it onto the element; a height here
     fights that and either clips the submit button or leaves a gap. */
.auth-panel--form { width: min(34rem, 94vw); }
.ghl-form {
  /* min-height is a holding position for the moment before the handshake
     lands, not a final size — form_embed.js overwrites it inline. */
  min-height: 420px;
}
.ghl-form iframe {
  display: block; width: 100%; border: none; background: transparent;
}
/* while the cross-origin form is still coming down the wire */
.ghl-form-loading { font-size: var(--fs-sm); color: var(--ink-soft); }
/* Google renders its own button into [data-google-signin] and owns its
   appearance — brand rules forbid restyling it. Only the surrounding space
   is ours. */
.auth-google { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.auth-google > div { display: flex; justify-content: center; width: 100%; }
.auth-or {
  display: flex; align-items: center; gap: .9rem; width: 100%;
  font-size: var(--fs-micro); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-soft);
}
.auth-or::before, .auth-or::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

.field-hint { font-size: var(--fs-sm); color: var(--ink-soft); margin-top: .35em; }
.text-right { text-align: right; }

/* a button that has to read as a link inside running text */
.linkish {
  color: var(--maroon); text-decoration: underline; text-underline-offset: .18em;
  font: inherit; padding: 0;
}
.linkish:hover { color: var(--maroon-deep); }

/* ---- Wine Club benefits list (/club/) ----------------------------------- */
.club-benefits { display: flex; flex-direction: column; gap: .9rem; color: var(--ink-soft); }
.club-benefits li { padding-left: 1.5em; position: relative; }
.club-benefits li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: .5em; height: .5em; background: var(--maroon);
}
.club-benefits strong { color: var(--ink); }

/* ---- Commerce7 styling (retained, currently unused) ----------------------
   The estate's Commerce7 subscription flow was hosted at /club/ until the
   client confirmed on 2026-08-07 that they are not running subscription
   memberships yet — see TODO.md §2a. These rules are kept because they are
   the expensive part to rediscover (Commerce7's own class names, its blue
   default button, the Divi markup buried in its stored copy). If a
   subscription club is ever switched on, restore the embed and this dresses
   it to match. They match nothing on the site as it stands.
   ---- original notes ------------------------------------------------------
   The Wine Club signup — benefits, Delivery, Review, card authorisation — is
   Commerce7's own app, rendered into #c7-content. It is a subscription engine
   (card on file, recurring shipments, cancel any time), not something to
   rebuild, so it is hosted and dressed to match instead.

   Only presentation is touched here; no Commerce7 markup or behaviour is
   overridden. Selectors are theirs (.c7-btn, .c7-h1 …) and could change on
   their release schedule — if this block ever stops applying, that is why.
   Note the later steps of the flow sit behind a login, so Delivery and Review
   should be walked through once by eye after any Commerce7 update. */
#c7-content { color: var(--ink); }

/* our reset strips list markers site-wide; the benefits list needs them back */
#c7-content ul { list-style: disc; padding-left: 1.35em; }
#c7-content li { margin-bottom: .5em; color: var(--ink-soft); }

#c7-content h1, #c7-content h2, #c7-content h3,
#c7-content .c7-h1, #c7-content .c7-h2 {
  font-family: var(--font-display); font-weight: 600; line-height: 1.12; color: var(--ink);
}
#c7-content .c7-h2, #c7-content h2 { font-size: clamp(1.4rem, 2.6vw, 2rem); margin-bottom: .6em; }
/* Commerce7 opens with its own "Wine Club" title; the page already carries a
   heading that explains why the visitor is here, so the duplicate goes */
#c7-content > .c7-club > h1:first-child,
#c7-content > section > h1.c7-h1:first-child { display: none; }

/* Commerce7's primary button is a blue default — make it the estate's */
#c7-content .c7-btn--primary,
#c7-content .c7-btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-text);
  /* up from 12.5px, with the tracking eased a touch so the button does not
     get wider as the type gets more legible */
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: 1em 2.1em;
  background: var(--maroon); border: 1px solid var(--maroon); color: var(--parchment);
  border-radius: 0;
  transition: all .35s var(--ease-lux);
}
#c7-content .c7-btn--primary:hover, #c7-content .c7-btn:hover {
  background: var(--maroon-deep); border-color: var(--maroon-deep); color: var(--parchment);
}

/* form controls in the Delivery / Review steps */
#c7-content input, #c7-content select, #c7-content textarea {
  font: inherit; padding: .85em 1em; color: var(--ink); max-width: 100%;
  background: var(--white); border: 1px solid var(--rule); border-radius: 0;
}
#c7-content input:focus, #c7-content select:focus, #c7-content textarea:focus {
  outline: none; border-color: var(--maroon);
}
#c7-content label { font-size: var(--fs-micro); letter-spacing: .18em; text-transform: uppercase; color: var(--gold-text); }
#c7-content a:not(.c7-btn) { color: var(--maroon); }

/* Commerce7 stores the club copy as Divi markup exported from WordPress —
   neutralise the theme cruft that rides along with it */
#c7-content [class^="et_pb_"], #c7-content [class*=" et_pb_"] {
  background: none; padding: 0; margin-inline: 0; width: auto; max-width: none;
}

/* nothing in a third-party widget may widen the page on a phone */
.c7-host { max-width: 100%; min-width: 0; overflow-x: auto; }

/* ---- Gallery ------------------------------------------------------------- */
.gal-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: .9rem;
}
.gal-item { display: block; overflow: hidden; background: var(--cellar); aspect-ratio: 3 / 2; }
.gal-item img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .7s var(--ease-lux), opacity .5s;
}
.gal-item:hover img { transform: scale(1.045); opacity: .92; }

.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(34, 34, 33,.95);
  display: flex; align-items: center; justify-content: center;
}
.lightbox img { max-width: min(92vw, 1400px); max-height: 88vh; object-fit: contain; }
.lb-x, .lb-prev, .lb-next {
  position: absolute; color: var(--parchment); z-index: 201;
  font-size: 2.4rem; line-height: 1; padding: .3em .5em;
  transition: color .3s;
}
.lb-x:hover, .lb-prev:hover, .lb-next:hover { color: var(--gold-soft); }
.lb-x { top: 1rem; right: 1.4rem; }
.lb-prev { left: .6rem; top: 50%; transform: translateY(-50%); font-size: 3.2rem; }
.lb-next { right: .6rem; top: 50%; transform: translateY(-50%); font-size: 3.2rem; }

.video-frame {
  position: relative; aspect-ratio: 16 / 9; background: var(--cellar);
  border: 1px solid var(--rule);
}
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.video-link { display: block; }
.video-link img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: opacity .4s; }
.video-link:hover img { opacity: .85; }
.play-badge {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 64px; height: 64px; border-radius: 50%;
  background: rgba(157, 34, 53,.92);
  transition: transform .3s var(--ease-lux);
}
.play-badge::after {
  content: ''; position: absolute; top: 50%; left: 54%; transform: translate(-50%, -50%);
  border-style: solid; border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent var(--parchment);
}
.video-link:hover .play-badge { transform: translate(-50%, -50%) scale(1.08); }

/* ---- Text utilities ------------------------------------------------------
   These exist so no page has to invent a size inline. Every font-size that
   used to live in a style="" attribute now comes from here or from the
   element's own rule. */
.muted     { color: var(--text-muted); }
.text-sm   { font-size: var(--fs-sm); }
.text-body { font-size: var(--fs-body); }
.text-lead { font-size: var(--fs-lead); }
/* a serif line used as a small statement — order confirmations, empty states */
.statement { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--text-heading); }
/* the "← All wines" / "← All galleries" links above a detail page */
.back-link {
  font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
}
/* the big figures on the Wine Club benefit cards */
.benefit-figure { font-size: clamp(2.2rem, 4vw, 2.6rem); color: var(--text-accent); line-height: 1; }

/* ---- Utility ------------------------------------------------------------- */
.text-center { text-align: center; }
.mt-1 { margin-top: var(--space-1); } .mt-2 { margin-top: var(--space-2); } .mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); } .mt-5 { margin-top: var(--space-5); }
.mb-2 { margin-bottom: var(--space-2); } .mb-3 { margin-bottom: var(--space-3); } .mb-4 { margin-bottom: var(--space-4); }
.gold { color: var(--gold-text); }
.maroon { color: var(--maroon); }
.small-note { font-size: var(--fs-sm); color: var(--ink-soft); font-style: italic; }
.dark .small-note { color: rgba(255, 252, 223,.6); }
.no-wrap { white-space: nowrap; }

/* "For You" notification dot on the header profile icon (rebuild brief, 2026-08-19) -
   set by js/main.js when new For-You content is waiting, cleared by a visit */
.profile-btn.has-foryou { position: relative; }
.profile-btn.has-foryou::after {
  content: ""; position: absolute; top: 2px; right: 2px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--maroon); box-shadow: 0 0 0 2px var(--parchment);
}
