/*
Theme Name: Aroma Lab Coffee
Theme URI: https://aromalabcoffee.com
Author: Aroma Lab Coffee
Description: Block theme carrying the Aroma Lab Coffee design system. Tokens transcribed from Aroma Lab.fig — do not round these values. V1 is a content site; V2 adds WooCommerce and Square.
Requires at least: 6.4
Tested up to: 6.7
Requires PHP: 7.4
Version: 1.3.3
License: Proprietary
Text Domain: aroma-lab
*/

/* ─────────────────────────────────────────────────────────────────────
   AROMA LAB COFFEE — V1 site CSS
   Paste into WordPress.com → Appearance → Customise → Additional CSS
   (Premium plan or above). Pairs with the patterns in ./patterns/.
   Tokens transcribed from Aroma Lab.fig. Do not round these values.
   ───────────────────────────────────────────────────────────────────── */

@import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&display=swap");

:root{
  --al-black:#000000;--al-ink:#1A1A1A;--al-white:#FFFFFF;--al-grey:#D9D9D9;
  --al-amber:#FFAE00;--al-blue:#003CFF;
  --al-grey-900:#0D0D0D;--al-grey-800:#1A1A1A;--al-grey-700:#333333;--al-grey-600:#5C5C5C;
  --al-grey-500:#8A8A8A;--al-grey-400:#B3B3B3;--al-grey-300:#D9D9D9;--al-grey-200:#E8E8E8;--al-grey-100:#F2F2F2;
  --surface-page:var(--al-white);--surface-card:var(--al-white);--surface-inverse:var(--al-black);
  --surface-sunken:var(--al-grey-100);--surface-plate:var(--al-black);
  --text-primary:var(--al-black);--text-secondary:var(--al-grey-600);--text-muted:var(--al-grey-500);
  --text-on-inverse:var(--al-white);--text-on-amber:var(--al-black);
  --text-link:var(--al-black);--text-link-hover:var(--al-grey-600);
  --border-hairline:var(--al-black);--border-quiet:var(--al-grey-300);--border-inverse:var(--al-white);
  --accent-primary:var(--al-amber);--accent-secondary:var(--al-blue);
  --font-mono:"Geist Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --font-sd-display:Arial,Helvetica,sans-serif;
  --fs-82:82px;--fs-63:63px;--fs-31-6:31.625px;--fs-25-8:25.830324px;--fs-22:22px;
  --fs-16:16px;--fs-14:14px;--fs-12:12px;
  --tracking-wordmark:0.150em;--tracking-display:0.040em;--tracking-loose:0.300em;
  --lh-solid:100%;--lh-body:1.55;
  --space-7:7px;--space-10:10px;--space-14:14px;--space-18:18px;--space-34:34px;--space-46:46px;
  --gutter-page:46px;--gutter-card:18px;--max-measure:64ch;
  --radius-0:0px;
  --shadow-card:0px 4px 4px 0px rgba(0,0,0,0.25);
  --rule-hairline:1px solid var(--border-hairline);--rule-quiet:1px solid var(--border-quiet);
  --dur-fast:120ms;--dur-base:180ms;--ease-standard:cubic-bezier(0.2,0,0.2,1);--press-shift:1px;
}

/* ── Base ─────────────────────────────────────────────────────────── */
body{background:var(--surface-page);color:var(--text-primary);font-family:var(--font-mono);font-weight:400;font-size:var(--fs-14);line-height:var(--lh-body);-webkit-font-smoothing:antialiased}
/* Measure applies to prose only. Any p or li carrying a class is layout —
   capping it at 64ch silently shortens rows against a shared right edge. */
p,li{text-wrap:pretty}
p:not([class]),li:not([class]){max-width:var(--max-measure)}
a{color:var(--text-link);text-decoration:underline;text-underline-offset:3px;transition:color var(--dur-fast) var(--ease-standard)}
a:hover{color:var(--text-link-hover)}
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible{outline:1px solid var(--al-black);outline-offset:2px}
::selection{background:var(--al-black);color:var(--al-white)}
img{display:block;max-width:100%;height:auto}

/* Everything set in caps is solid-leaded, per the source lockups. */
h1,h2,h3,h4,.al-eyebrow,.al-nav a,.al-btn,.al-row__label{line-height:var(--lh-solid)}
h1,h2,h3,h4{font-family:var(--font-mono);font-weight:700;text-transform:uppercase;margin:0}
h1{font-size:clamp(38px,7vw,var(--fs-63));letter-spacing:var(--tracking-display);font-weight:400}
h2{font-size:clamp(22px,3.4vw,var(--fs-31-6));letter-spacing:var(--tracking-display)}
h3{font-size:var(--fs-16);letter-spacing:var(--tracking-wordmark)}
h4{font-size:var(--fs-12);letter-spacing:var(--tracking-wordmark)}

.al-eyebrow{font-size:9px;font-weight:700;letter-spacing:var(--tracking-loose);text-transform:uppercase;color:var(--text-muted);margin:0 0 var(--space-14)}
.al-muted{color:var(--text-muted)}
.al-wrap{max-width:1180px;margin:0 auto;padding:0 var(--gutter-page)}
@media(max-width:600px){:root{--gutter-page:18px}}

/* ── The dashed rule: the signature divider ───────────────────────── */
.al-rule,hr.wp-block-separator{border:0;height:1px;width:100%;max-width:none;margin:var(--space-18) 0;background-image:repeating-linear-gradient(to right,var(--al-black) 0 5px,transparent 5px 9px);background-repeat:repeat-x;opacity:1}
.al-rule--quiet{background-image:repeating-linear-gradient(to right,var(--border-quiet) 0 5px,transparent 5px 9px)}
.al-rule--inverse{background-image:repeating-linear-gradient(to right,var(--al-white) 0 5px,transparent 5px 9px)}

/* ── Header: black plate, flush-left lockup ───────────────────────── */
.al-header{position:sticky;top:0;z-index:50;background:var(--surface-plate);color:var(--text-on-inverse);min-height:82px;display:flex;align-items:center}
.al-header .al-wrap{display:flex;align-items:center;justify-content:space-between;gap:var(--space-34);width:100%}
.al-lockup{display:flex;align-items:center;gap:var(--space-14);text-decoration:none;color:var(--al-white)}
.al-lockup:hover{color:var(--al-white)}
/* The lockup is two white SVGs — mark then wordmark — so it needs no invert.
   (mark.svg elsewhere is fill="currentColor"; through an <img> the page's
   colour never crosses the SVG document boundary, so those marks are
   inverted rather than inherited. See .al-plate / .al-bean / .al-shelf.) */
.al-lockup figure{margin:0;line-height:0}
/* Specificity, not decoration: core ships .wp-block-image img{height:auto},
   which ties with a bare .al-lockup__brand img. The front end loads the
   theme last so ours wins, but the editor loads Gutenberg last and the SVG
   springs to its natural 55px. The extra class settles it in both. */
.al-lockup .al-lockup__brand img{width:auto;height:34px}
.al-lockup__type{font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;white-space:pre-line}
.al-nav{display:flex;gap:var(--space-18);flex-wrap:wrap}
.al-nav a{font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--al-grey-300);text-decoration:none}
.al-nav a:hover,.al-nav a[aria-current]{color:var(--al-white)}
/* A core navigation block, not a page list. The page list rendered every
   page, so Cart, Checkout, My Account and Shop all appeared by themselves
   the moment WooCommerce was installed. This lists only what the pattern
   names, and brings core's overlay menu with it — a real hamburger with a
   focus trap and Escape handling, rather than one we would have to write
   and then maintain. Only the colours and type are ours. */
.al-nav .wp-block-navigation__container{gap:var(--space-18);margin:0;padding:0}
.al-nav .wp-block-navigation-item{margin:0}
.al-nav .wp-block-navigation__responsive-container-open,
.al-nav .wp-block-navigation__responsive-container-close{color:var(--al-white)}
/* Overlay colours come from the block's own overlayBackgroundColor and
   overlayTextColor attributes, not from here — the block emits its own
   background rule and a stylesheet override loses to it, which is how
   the menu ended up white-on-white. Padding and type are still ours. */
.al-nav .wp-block-navigation__responsive-container.is-menu-open{padding:var(--space-46) var(--gutter-page)}
.al-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container{gap:var(--space-18)}
.al-nav .wp-block-navigation__responsive-container.is-menu-open a{font-size:var(--fs-22);color:var(--al-white)}

/* ── Buttons ──────────────────────────────────────────────────────── */
.al-btn,.wp-block-button__link{display:inline-flex;align-items:center;gap:var(--space-10);font-family:var(--font-mono);font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;text-decoration:none;padding:14px 18px;border-radius:var(--radius-0);border:var(--rule-hairline);background:var(--al-black);color:var(--al-white);cursor:pointer;transition:background var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.al-btn:hover,.wp-block-button__link:hover{background:var(--al-grey-700);border-color:var(--al-grey-700);color:var(--al-white)}
.al-btn:active,.wp-block-button__link:active{transform:translateY(var(--press-shift))}
.al-btn--secondary{background:transparent;color:var(--al-black)}
.al-btn--secondary:hover{background:var(--al-grey-100);border-color:var(--al-black);color:var(--al-black)}
.al-btn--ghost{background:transparent;border-color:transparent;color:var(--al-black)}
.al-btn--ghost:hover{background:var(--al-grey-100);border-color:transparent;color:var(--al-black)}
.al-btn--accent{background:var(--accent-primary);border-color:var(--accent-primary);color:var(--text-on-amber)}
.al-btn--accent:hover{background:#E69D00;border-color:#E69D00;color:var(--text-on-amber)}
.al-btn[aria-disabled="true"],.al-btn--soldout{opacity:.35;pointer-events:none}

/* ── Spec sheet ───────────────────────────────────────────────────── */
.al-spec{display:flex;flex-direction:column;gap:var(--space-7);margin:0}
.al-row{display:flex;gap:var(--space-18);align-items:baseline;flex-wrap:wrap}
.al-row__label{flex:0 0 150px;font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--text-secondary);margin:0}
.al-row__value{flex:1 1 0;min-width:0;font-size:var(--fs-14);letter-spacing:0.06em;text-transform:uppercase;color:var(--text-primary);margin:0;white-space:pre-line;max-width:none}
.al-row--notes .al-row__value::before{content:"\2192  ";color:var(--text-muted)}
/* Once the label sits above its value rather than beside it, a 7px gap
   between rows reads the same as the gap inside a row and the sheet
   collapses into one list. Separate the rows when they stack. */
@media(max-width:600px){.al-row__label{flex-basis:100%}.al-row{gap:var(--space-7)}.al-spec{gap:var(--space-18)}}

.al-cupping{display:flex;align-items:baseline;gap:var(--space-14);margin:0}
.al-cupping__n{font-size:var(--fs-31-6);font-weight:700;letter-spacing:var(--tracking-display)}
.al-cupping__l{font-size:9px;font-weight:700;letter-spacing:var(--tracking-loose);text-transform:uppercase;color:var(--text-muted)}

/* ── Cards, plates, index grid ────────────────────────────────────── */
.al-card{border:var(--rule-hairline);border-radius:var(--radius-0);padding:var(--gutter-card);background:var(--surface-card)}
.al-card--raised{border:0;box-shadow:var(--shadow-card)}
.al-plate{background:var(--surface-plate);color:var(--text-on-inverse);padding:var(--space-46);display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-34);flex-wrap:wrap}
.al-plate h1,.al-plate h2{color:var(--al-white)}
.al-plate img{width:46px;filter:invert(1)}

.al-index{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));gap:var(--space-46);list-style:none;padding:0;margin:0}
.al-bean{display:flex;flex-direction:column;gap:var(--space-14);text-decoration:none;color:inherit}
.al-bean:hover{color:inherit}
.al-bean__plate{aspect-ratio:4/3;background:var(--surface-plate);display:flex;align-items:center;justify-content:center}
.al-bean__plate img{width:64px;filter:invert(1)}
.al-bean__name{font-size:var(--fs-16);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase}
.al-bean__meta{display:flex;justify-content:space-between;gap:var(--space-14);font-size:var(--fs-12);letter-spacing:0.06em;color:var(--text-muted);text-transform:uppercase}
.al-bean__price{color:var(--text-primary)}

/* ── S.D — East Asian Kitchen. Sibling brand: its own #1A1A1A plate,
      never the Aroma Lab mark, never signed "by Aroma Lab". ───────── */
.al-sd{background:var(--al-ink);color:var(--al-white);padding:var(--space-46) 0}
.al-sd h2,.al-sd h3{color:var(--al-white)}
.al-sd .al-rule{background-image:repeating-linear-gradient(to right,var(--al-white) 0 5px,transparent 5px 9px)}
.al-sd__display{font-family:var(--font-sd-display);font-weight:700;font-size:clamp(46px,9vw,var(--fs-82));letter-spacing:var(--tracking-display);line-height:var(--lh-solid);margin:0}
.al-menu{display:flex;flex-direction:column;gap:0;list-style:none;padding:0;margin:0}
.al-menu__row{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-18);padding:var(--space-14) 0;border-bottom:1px solid rgba(255,255,255,.18)}
.al-menu__name{font-size:var(--fs-14);letter-spacing:0.06em;text-transform:uppercase}
.al-menu__note{display:block;font-size:var(--fs-12);letter-spacing:0.06em;color:var(--al-grey-400);text-transform:uppercase;padding-top:5px}
.al-menu__price{font-size:var(--fs-14);letter-spacing:0.06em;white-space:nowrap}

/* ── Sections ─────────────────────────────────────────────────────── */
.al-section{padding:var(--space-46) 0}
.al-section--tight{padding:var(--space-34) 0}
.al-stack{display:flex;flex-direction:column;gap:var(--space-18)}
.al-two{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr));gap:var(--space-46);align-items:start}
/* ── Stores. The one place V1 uses real photography — architecture and
      store shots are licensed treatments; coffee still gets the plate. ── */
.al-store{border:var(--rule-hairline);border-radius:var(--radius-0);background:var(--surface-card);display:flex;flex-direction:column}
.al-store__img{aspect-ratio:16/11;background-size:cover;background-position:center;background-repeat:no-repeat}
.al-store__body{padding:var(--gutter-card);display:flex;flex-direction:column;gap:var(--space-14)}
.al-store__head{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-14)}
.al-store__name{font-size:var(--fs-25-8);letter-spacing:var(--tracking-display);text-transform:uppercase}
.al-badge{font-size:9px;font-weight:700;letter-spacing:var(--tracking-loose);text-transform:uppercase;padding:5px 9px;border:var(--rule-hairline);white-space:nowrap}
/* Store rows sit in a narrow card: 110px label and 12px value, per
   StoresScreen. The global 150/14 wraps "UNIT 4, MARE STREET" mid-phrase. */
.al-store .al-row__label{flex-basis:110px}
.al-store .al-row__value{font-size:var(--fs-12)}

/* ── Footer ───────────────────────────────────────────────────────── */
.al-footer{background:var(--surface-plate);color:var(--al-grey-300);padding:var(--space-46) 0;font-size:var(--fs-12);letter-spacing:0.06em;text-transform:uppercase}
.al-footer a{color:var(--al-grey-300)}
.al-footer a:hover{color:var(--al-white)}

/* ── Home page bands ──────────────────────────────────────────────────
      Ported from ui_kits/aroma-lab-web/HomeScreen.jsx. The screen uses a
      33px radius on the stores photo; V1 locks radius to 0, so the plate
      edge stays square here and the shadow carries the lift instead. ── */
.al-hero{position:relative;background:var(--surface-plate);color:var(--text-on-inverse);overflow:hidden}
.al-hero__bg{position:absolute;inset:0;background-position:right center;background-size:cover;background-repeat:no-repeat;opacity:1}
.al-hero .al-wrap{position:relative;padding-top:72px;padding-bottom:92px}
.al-hero .al-eyebrow{color:var(--al-grey-300)}
.al-hero h1{font-size:clamp(42px,7.5vw,72px);font-weight:400;margin-top:var(--space-18)}
.al-hero p{color:var(--al-grey-300);margin-top:26px}
/* Hero standfirst. At 14px against a 72px heading the jump is 5x and the
   copy reads as a caption; the 48ch cap also held it to 369px inside the
   722px column, so widening that column did nothing. Scales with the
   viewport and stops at 18px. Excluding the eyebrow and the button row
   matters: .al-hero p outranks .al-eyebrow, so an unscoped font-size
   here would blow up the 9px label as well. */
.al-hero__copy p:not(.al-eyebrow):not(.al-hero__actions){font-size:clamp(var(--fs-14),0.6vw + 8px,18px);line-height:1.6;max-width:54ch}
.al-hero__actions{display:flex;gap:var(--space-10);margin-top:var(--space-34);flex-wrap:wrap}
.al-btn--inverse{background:var(--al-white);border-color:var(--al-white);color:var(--al-black)}
.al-btn--inverse:hover{background:var(--al-grey-300);border-color:var(--al-grey-300);color:var(--al-black)}
.al-hero .al-btn--ghost{color:var(--al-white);border-color:var(--al-grey-600)}
.al-hero .al-btn--ghost:hover{background:var(--al-grey-700);border-color:var(--al-grey-600);color:var(--al-white)}

.al-statbar{background:var(--surface-sunken);border-top:var(--rule-hairline);border-bottom:var(--rule-hairline)}
.al-statbar .al-wrap{display:grid;grid-template-columns:repeat(4,1fr)}
.al-stat{padding:26px 0}
.al-stat+.al-stat{border-left:var(--rule-quiet);padding-left:26px}
.al-stat__k{font-size:9px;font-weight:700;letter-spacing:var(--tracking-loose);text-transform:uppercase;color:var(--text-muted);margin:0}
.al-stat__v{font-size:20px;letter-spacing:var(--tracking-display);text-transform:uppercase;padding-top:9px;margin:0}
@media(max-width:900px){
  .al-statbar .al-wrap{grid-template-columns:repeat(2,1fr)}
  .al-stat:nth-child(odd){border-left:0;padding-left:0}
}

/* Label and rule share a baseline; the rule takes the remaining width. */
.al-seclabel{display:flex;align-items:baseline;gap:var(--space-18);padding-bottom:var(--space-14)}
.al-seclabel .al-rule{flex:1 1 0;margin:0}
.al-sectitle{font-size:clamp(30px,4.6vw,44px);font-weight:400;margin:0 0 var(--space-34)}

.al-shelf{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,340px),1fr));gap:26px}
.al-shelf__plate{min-height:220px;background:var(--surface-plate);display:flex;flex-direction:column;justify-content:flex-end;gap:var(--space-18);padding:var(--space-34)}
.al-shelf__plate img{width:34px;filter:invert(1)}
.al-shelf__lockup{font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--al-white);white-space:pre-line;margin:0}
.al-shelf__body{padding:var(--gutter-card);display:flex;flex-direction:column;gap:var(--space-14)}
.al-shelf__head{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-14)}
.al-shelf__origin{font-size:34px;letter-spacing:var(--tracking-display);text-transform:uppercase}
.al-shelf__notes{font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--text-secondary);margin:0;max-width:none}
.al-shelf__foot{display:flex;justify-content:space-between;align-items:center;gap:var(--space-14)}
.al-shelf__price{font-size:var(--fs-16);letter-spacing:var(--tracking-display)}
.al-shelf__unit{font-size:10px;color:var(--text-muted)}
.al-tags{display:flex;flex-wrap:wrap;gap:9px;padding-top:26px}
.al-tag{font-size:var(--fs-12);letter-spacing:0.06em;text-transform:uppercase;padding:7px 14px;border:var(--rule-quiet)}
.al-tag--on{background:var(--al-black);border-color:var(--al-black);color:var(--al-white)}

.al-kitchen{display:grid;grid-template-columns:320px 1fr;gap:var(--space-46);align-items:start}
.al-kitchen p{color:var(--al-grey-300);max-width:52ch;margin:0 0 26px}
@media(max-width:900px){.al-kitchen{grid-template-columns:1fr}}

.al-storesband{display:grid;grid-template-columns:1.2fr 1fr;gap:26px;align-items:stretch}
.al-storesband__img{min-height:340px;background-position:center;background-size:cover;background-repeat:no-repeat;box-shadow:var(--shadow-card)}
.al-storerow{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-18);padding:var(--space-18) 0}
.al-storerow__n{font-size:20px;letter-spacing:var(--tracking-display);text-transform:uppercase}
.al-storerow__d{font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:var(--text-muted);padding-top:5px;margin:0;max-width:none}
.al-storerow__m{font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-secondary);text-align:right;flex-shrink:0;margin:0;max-width:none}
@media(max-width:900px){.al-storesband{grid-template-columns:1fr}}

/* ── Sticky footer ────────────────────────────────────────────────────
      A short page must not float the footer up into the viewport. The
      block theme wraps everything in .wp-site-blocks, so that is the
      column: main takes the slack, the footer sits on the bottom edge.
      dvh keeps it honest on mobile where the address bar resizes vh. ── */
.wp-site-blocks{display:flex;flex-direction:column;min-height:100vh;min-height:100dvh}
.wp-site-blocks>main{flex:1 0 auto}
.wp-site-blocks>footer{flex:0 0 auto}

/* Shelf cards run plate-to-edge, so the card's own padding is dropped and
   the body supplies it. Rows sit in a narrow column, as on the store card. */
.al-card--flush{padding:0}
.al-shelf .al-row__label{flex-basis:110px}
.al-shelf .al-row__value{font-size:var(--fs-12)}

/* Shipped with the theme rather than the media library: an uploaded file
   lands under /uploads/<year>/<month>/, so a hard-coded /uploads/ path
   breaks the moment the image is uploaded properly. These URLs resolve
   relative to style.css, so they work on any domain and any install. */
.al-hero__bg{background-image:url("assets/backdrop.jpeg")}

/* A sticky box can only travel inside its own parent. The black plate is
   wrapped by the template part, whose height is exactly the plate's — so
   .al-header had nowhere to go and never stuck. Sticking the wrapper gives
   it the whole column to travel down. */
.wp-site-blocks>header{position:sticky;top:0;z-index:50}

/* Hero: lockup top-left, copy beneath, sharing one left edge. */
.al-hero__inner{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-34)}
.al-hero__copy{max-width:70%;min-width:0}
@media(max-width:900px){.al-hero__copy{max-width:100%}}
.al-hero__logo{flex:0 0 auto}
.al-hero__logo figure{margin:0;line-height:0}
.al-hero .al-hero__logo img{width:auto;height:clamp(96px,13vw,168px)}
@media(max-width:900px){.al-hero .al-hero__logo img{height:96px}}
/* Out of flow and pinned to the document top: the sentinel header.js watches
   to decide whether the plate has stuck. Taking no space is the point — the
   plate collapses by 42px, which would drag an in-flow sentinel with it. */
.wp-site-blocks{position:relative}
.al-header-sentinel{position:absolute;top:0;left:0;width:1px;height:60vh;visibility:hidden;pointer-events:none}

/* ── Home opens on the hero as a cover ────────────────────────────────
      The plate would otherwise eat 82px off the top of the first screen.
      On home it leaves the flow and sits off-screen, so the hero starts at
      the very top, then drops in once the reader has scrolled past the
      sentinel. The sentinel's height IS the threshold, so it is one value
      in the CSS rather than a magic number in the JS. Inner pages keep a
      normal plate; the plate is unchanged once it appears. */
body.home .wp-site-blocks>header{position:fixed;top:0;left:0;right:0;z-index:50;transform:translateY(-100%);transition:transform var(--dur-base) var(--ease-standard)}
body.home .wp-site-blocks>header.is-stuck{transform:none}
body.home .al-hero{min-height:100vh;min-height:100dvh}
/* On a tall phone a full-height hero reads as the whole page. Backing
   off lets the next section show below the fold as a scroll cue; the
   hero still fills a short screen, where its own content is taller. */
@media(max-width:900px){body.home .al-hero{min-height:85vh;min-height:85dvh}}
@media(prefers-reduced-motion:reduce){body.home .wp-site-blocks>header{transition:none}}

/* Dashed rules are off for now — but only the dashes. They also carry
   18px of vertical rhythm between blocks, and display:none took that with
   them, which is what pulled every eyebrow onto the text beneath it. The
   box and its margins stay; just the pattern goes. */
.al-rule,hr.wp-block-separator{background-image:none}

/* ── Origin spec card ─────────────────────────────────────────────────
      Ported from the printed card (spec cards/card.css): a black plate
      carrying the lockup and the origin, then a white sheet of stacked
      fields — label over value, not the side-by-side rows used elsewhere.
      Every dimension is expressed against --al-u, one pixel at the card's
      600px design width, so the whole card scales with its grid track
      instead of needing a breakpoint per size.
      Two deliberate departures from the print CSS: it offsets the lockup
      by -26/-48 to cancel padding baked into its own lockup.svg, and
      brand-horizontal.svg is cropped tight, so those offsets would hang
      it off the plate; and the card takes its height from content rather
      than a fixed 1050, since web copy varies and print copy does not. */
/* The card is 600px of paper. On screen that scale is simply too big, so
   --al-u is capped: it still tracks the card's width down at phone sizes,
   but stops growing once the card is wide. And the plate sizes to its own
   content now the lockup has gone — holding the paper's 600/470 would
   leave a large empty black field above the origin. */
.al-speccard{container-type:inline-size;--al-u:min(0.16667cqw,0.58px);display:flex;flex-direction:column;background:var(--al-white);border:1px solid var(--border-quiet);text-transform:uppercase}
.al-speccard__plate{background:var(--al-black);color:var(--al-white);min-height:calc(200*var(--al-u));display:flex;flex-direction:column;justify-content:flex-end;gap:calc(24*var(--al-u));padding:calc(42*var(--al-u));box-sizing:border-box}
.al-speccard__titles{display:flex;flex-direction:column;gap:calc(14*var(--al-u))}
.al-speccard__country{font-size:calc(86*var(--al-u));font-weight:400;line-height:.9;letter-spacing:var(--tracking-display);color:var(--al-white);margin:0}
/* Farm names run to one line or two depending on the estate. Reserving
   two keeps every plate the same depth, so the sheets below them start
   on one line across the row — otherwise a long name pushes its card's
   labels out of step with its neighbours. Set in em so it tracks the
   font size as the card scales. */
.al-speccard__farm{font-size:calc(24*var(--al-u));font-weight:400;line-height:1.25;min-height:2.5em;letter-spacing:var(--tracking-wordmark);color:var(--al-grey-400);margin:0;max-width:none}
/* Roughly double the print spacing: the card is no longer trying to fit
   a 600x1050 trim. Horizontal padding still tracks the plate so the
   labels stay on the same left edge as the origin above them. */
.al-speccard__sheet{flex:1;display:flex;flex-direction:column;gap:var(--space-18);padding:var(--space-34) calc(42*var(--al-u))}
.al-speccard__field{display:flex;flex-direction:column;gap:var(--space-7)}
.al-speccard__field--origin{margin-top:calc(10*var(--al-u))}
.al-speccard__label{font-size:calc(22*var(--al-u));font-weight:700;line-height:1;letter-spacing:var(--tracking-loose);color:var(--text-muted);margin:0}
.al-speccard__value{font-size:calc(28*var(--al-u));line-height:1.3;letter-spacing:0.06em;color:var(--text-primary);white-space:pre-line;margin:0;max-width:none}

/* ── WooCommerce ──────────────────────────────────────────────────────
      Woo owns this markup and most of it cannot be changed, so this is a
      translation layer: its class names, our tokens. It restyles surfaces
      only — type, colour, rules, the plate — and leaves Woo's structure
      and behaviour alone, so a plugin update cannot break layout here. */

/* The attributes table is the printed card's spec sheet in another form,
   so it is set the same way: quiet label, black value, no table chrome. */
.woocommerce-product-attributes{width:100%;border:0;border-collapse:collapse;margin:var(--space-18) 0}
.woocommerce-product-attributes-item{border:0}
.woocommerce-product-attributes-item th,
.woocommerce-product-attributes-item td{border:0;background:none}
.woocommerce-product-attributes-item__label{width:150px;padding:var(--space-7) var(--space-18) var(--space-7) 0;text-align:left;vertical-align:top;font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-loose);text-transform:uppercase;color:var(--text-muted)}
/* Woo sets table.shop_attributes td to italic and stripes alternate rows.
   Neither belongs in this system, and both need naming explicitly —
   inheriting from our own rules is not enough to undo them. */
.woocommerce-product-attributes-item__value{padding:var(--space-7) 0;font-size:var(--fs-14);font-style:normal;letter-spacing:0.06em;text-transform:uppercase;color:var(--text-primary)}
.woocommerce table.shop_attributes td,
.woocommerce table.shop_attributes th{font-style:normal;background:none}
.woocommerce table.shop_attributes tr:nth-child(even) td,
.woocommerce table.shop_attributes tr:nth-child(even) th{background:none}
.woocommerce table.shop_attributes td p{font-style:normal;padding:0}
.woocommerce-product-attributes-item__value p{margin:0;max-width:none}

/* Price: the display face, not Woo's default body size. */
.woocommerce-Price-amount,
.wc-block-components-product-price__value{font-family:var(--font-mono);font-size:var(--fs-25-8);letter-spacing:var(--tracking-display);color:var(--text-primary)}

/* Every Woo button becomes .al-btn. Includes .wp-element-button, which is
   what the block checkout renders. */
.woocommerce a.button,.woocommerce button.button,.woocommerce input.button,
.single_add_to_cart_button,.wc-block-components-product-button__button,
.wc-block-components-button:not(.is-link){display:inline-flex;align-items:center;gap:var(--space-10);font-family:var(--font-mono);font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;text-decoration:none;padding:14px 18px;border-radius:var(--radius-0);border:var(--rule-hairline);background:var(--al-black);color:var(--al-white);cursor:pointer;transition:background var(--dur-fast) var(--ease-standard)}
.woocommerce a.button:hover,.woocommerce button.button:hover,
.single_add_to_cart_button:hover,.wc-block-components-product-button__button:hover{background:var(--al-grey-700);border-color:var(--al-grey-700);color:var(--al-white)}

/* Quantity stepper: square, hairline, mono — Woo's default is rounded. */
.quantity input.qty,.wc-block-components-quantity-selector{font-family:var(--font-mono);font-size:var(--fs-14);border:var(--rule-hairline);border-radius:var(--radius-0);background:var(--surface-card)}
.wc-block-components-quantity-selector__button{font-family:var(--font-mono);border-radius:var(--radius-0)}

/* No origin photography exists and none is planned, so a missing image is
   the black plate carrying the mark — the same treatment the coffee cards
   use — rather than Woo's grey camera icon. */
.woocommerce-product-gallery__image--placeholder,
.wc-block-components-product-image{background:var(--al-black) url("assets/mark-white.svg") center/64px auto no-repeat}
img.woocommerce-placeholder,
.woocommerce-product-gallery__image--placeholder img{opacity:0}

/* Tabs and breadcrumb: mono, uppercase, hairline instead of Woo's pills. */
.woocommerce-tabs ul.tabs{display:flex;gap:var(--space-18);margin:0 0 var(--space-18);padding:0;list-style:none;border-bottom:var(--rule-quiet)}
.woocommerce-tabs ul.tabs::before,.woocommerce-tabs ul.tabs::after{display:none}
.woocommerce-tabs ul.tabs li{margin:0;padding:0;background:none;border:0;border-radius:0}
.woocommerce-tabs ul.tabs li a{padding:0 0 var(--space-7);font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--text-muted);text-decoration:none}
.woocommerce-tabs ul.tabs li.active a{color:var(--text-primary);box-shadow:inset 0 -1px 0 var(--al-black)}
/* The breadcrumb sat hard against the sticky plate — 0px gap at every
   width. The spacing goes on the block wrapper rather than the <nav>:
   Woo sets margin on the nav itself from two rules, one of them at four
   classes, so matching it there would mean an escalating specificity
   fight over a margin. The wrapper is uncontested. */
.woocommerce-page .wc-block-breadcrumbs{margin-top:var(--space-34);margin-bottom:var(--space-18)}
.woocommerce-page .wc-block-breadcrumbs .woocommerce-breadcrumb{margin:0}
.woocommerce-breadcrumb{font-size:var(--fs-12);letter-spacing:0.06em;text-transform:uppercase;color:var(--text-muted)}
.woocommerce-breadcrumb a{color:var(--text-muted)}
.woocommerce-breadcrumb a:hover{color:var(--text-primary)}

/* Product titles in listings and related products. */
.wc-block-components-product-name,
.woocommerce-loop-product__title{font-family:var(--font-mono);font-weight:700;font-size:var(--fs-16);letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--text-primary)}

/* ── WooCommerce page furniture ───────────────────────────────────────
      Shop and Cart render through Woo's own templates, not ours, and put
      their titles at .alignwide. theme.json sets root padding to 0 — our
      own pages get their gutter from .al-wrap instead — so an alignwide
      element runs to the window edge and the letterforms clip. These are
      the elements that sit outside .al-wrap and need the gutter directly. */

/* Woo prints a cartoon face above "your cart is empty" as a ::before on the
   title. The voice guideline strikes through exactly this register, so the
   icon goes and the line stands on its own. */
.wc-block-cart__empty-cart__title.with-empty-cart-icon::before{display:none}
/* The icon was carrying the space under the page title; without it the
   message butts against the heading, so the margin moves onto the text. */
.wc-block-cart__empty-cart__title{font-family:var(--font-mono);font-weight:700;font-size:var(--fs-16);letter-spacing:var(--tracking-wordmark);text-transform:uppercase;margin-top:var(--space-46)}

/* Woo puts the result count and the sort control in one space-between flex
   row. On a phone that leaves the count about 130px and "Showing all 6
   results" breaks over three lines. Sizing the children cannot fix it —
   the row has to become a column, so :has() targets that one toolbar. */
@media(max-width:600px){
  .wp-block-group.is-content-justification-space-between:has(.wc-block-product-results-count){flex-direction:column;align-items:stretch;gap:var(--space-14)}
  .woocommerce-result-count,
  .woocommerce-ordering{float:none;width:100%;margin:0}
  .woocommerce-ordering select{width:100%}
}
/* The sort control was the one raw browser select left on the site. */
.woocommerce-ordering select,
select.orderby{font-family:var(--font-mono);font-size:var(--fs-12);font-weight:700;letter-spacing:var(--tracking-wordmark);text-transform:uppercase;color:var(--text-primary);background:var(--surface-card);border:var(--rule-hairline);border-radius:var(--radius-0);padding:10px 14px}

/* Footer went from two columns to three — address, policy links, legal line.
   Same auto-fit behaviour as .al-two so it collapses on a phone. */
.al-three{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:var(--space-34)}
.al-footer__links p{margin:0}
.al-footer p{margin:0 0 var(--space-7)}
.al-footer p:last-child{margin-bottom:0}

/* ── Page content flow ────────────────────────────────────────────────
      Two things only bite on prose pages, and both come from rules that
      were written for the patterns.
      Headings sit at margin:0 so each pattern owns its own rhythm — fine
      in a composed layout, but in running copy it leaves every h3 jammed
      against the paragraph above it.
      And the 64ch measure is on p:not([class]), which never matches: the
      block editor puts wp-block-paragraph on every paragraph. So policy
      copy ran the full 1088px, about 140 characters a line.
      Hooked on .entry-content, which exists only in page content — never in
      the header or footer wraps — and scoped to direct children, so the hero,
      the spec cards (whose country is also an h3) and the header and
      footer wraps are all left alone. */
body.page-template-page-plain .entry-content > * + :is(h2,h3){margin-top:var(--space-34)}
body.page-template-page-plain .entry-content > :is(h2,h3) + :is(p,ul){margin-top:var(--space-7)}
body.page-template-page-plain .entry-content > :is(p,ul){max-width:var(--max-measure)}
body.page-template-page-plain .entry-content > ul{margin-bottom:var(--space-18);padding-left:1.4em}
body.page-template-page-plain .entry-content > ul li{margin-bottom:var(--space-7)}
