/* ==========================================================================
   Herbal Heat — design system
   Brand colours sampled from the label artwork (static/img/label.jpg).
   Mobile first: base rules target phones, media queries scale up.
   To rebrand later, only the :root block below needs to change.
   ========================================================================== */

:root {
    /* Brand */
    --color-orange: #eb7720;
    --color-orange-dark: #c85f13;
    --color-ink: #14100d;
    --color-cream: #fbf7f0;
    --color-white: #ffffff;
    --color-green: #4a8244;
    --color-muted: #6b6259;
    --color-border: #e4dcd0;
    /* Warm grey tile the product cards sit on, a step darker than the cream
       page so the cards read as objects without needing a shadow. */
    --color-tile: #f0ece4;
    --color-tile-hover: #e9e3d8;

    /* Type — system stack only, no webfont request */
    --font-display: "Arial Black", "Segoe UI", Impact, system-ui, sans-serif;
    --font-base: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;

    /* Spacing scale */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4.5rem;

    --radius-sm: 4px;
    --radius-md: 10px;
    --radius-lg: 20px;
    --radius-pill: 999px;

    --shadow-sm: 0 1px 3px rgba(20, 16, 13, 0.12);
    --shadow-md: 0 6px 18px rgba(20, 16, 13, 0.12);
    --shadow-lg: 0 14px 40px rgba(20, 16, 13, 0.18);

    --maxw: 1180px;
    --header-h: 64px;
}

/* --------------------------------------------------------------- base ---- */

* { box-sizing: border-box; }

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

/* The page fills the screen even when the content does not. A short page --
   a legal text of two lines, an empty search result -- would otherwise end
   above the fold and leave the cream body background showing under the
   footer. The column lays out header, content and footer top to bottom; the
   content is the part that stretches, so the footer is pushed to the bottom
   of the screen rather than sitting wherever the text happens to end.
   Preferred over a min-height on the content block: a fixed number is right
   at exactly one window size and wrong at every other. */
body {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* Phone browsers count their collapsing address bar as part of 100vh,
       which leaves a strip of background below the footer. dvh measures what
       is actually visible; the line above stays for browsers without it. */
    min-height: 100dvh;
    font-family: var(--font-base);
    font-size: 1rem;
    line-height: 1.6;
    color: var(--color-ink);
    background: var(--color-cream);
    overflow-x: hidden;
}

/* The one element that absorbs the leftover height. flex-grow only, so a page
   longer than the screen is unaffected and simply scrolls. */
#app {
    flex: 1 0 auto;
}

img {
    max-width: 100%;
    display: block;
}

a { color: inherit; }

h1, h2, h3 {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: -0.02em;
    line-height: 0.95;
    margin: 0 0 var(--space-4);
}

h1 { font-size: clamp(2.4rem, 9vw, 4.5rem); }
h2 { font-size: clamp(1.8rem, 5.5vw, 3rem); }
h3 { font-size: clamp(1.1rem, 3vw, 1.35rem); }

p { margin: 0 0 var(--space-4); }

:focus-visible {
    outline: 3px solid var(--color-orange);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
}

/* Kept in the page for screen readers, but never painted: it stays off-screen
   even while focused, by explicit request. A keyboard user can still land on
   it and activate it; they just get no visible indication that they have. */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ------------------------------------------------------------- header ---- */

.site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    min-height: var(--header-h);
    padding: var(--space-3) var(--space-4);
    background: var(--color-ink);
}

/* The logo art is black with transparency; invert it for the dark header. */
.site-header .logo img {
    height: 56px;
    width: auto;
    filter: invert(1);
}

/* Hidden visually but still focusable, so the menu is keyboard operable. */
.nav-toggle {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

.nav-toggle-label {
    display: none;
}

.nav-toggle:focus-visible ~ .nav-toggle-label {
    outline: 3px solid var(--color-orange);
    outline-offset: 2px;
}

.main-nav {
    display: flex;
    align-items: center;
    gap: var(--space-5);
}

.main-nav a {
    color: var(--color-white);
    text-decoration: none;
    font-weight: bold;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.main-nav a:hover {
    color: var(--color-orange);
}

/* CSS-only mobile disclosure: no JS, so the SPA swap cannot break it. */
@media (max-width: 47.99em) {
    .nav-toggle-label {
        display: block;
        width: 40px;
        height: 40px;
        padding: 10px 8px;
        cursor: pointer;
    }

    .nav-toggle-label span,
    .nav-toggle-label span::before,
    .nav-toggle-label span::after {
        display: block;
        height: 2px;
        background: var(--color-white);
        content: "";
    }

    .nav-toggle-label span { position: relative; }
    .nav-toggle-label span::before { position: absolute; top: -7px; width: 100%; }
    .nav-toggle-label span::after { position: absolute; top: 7px; width: 100%; }

    .main-nav {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background: var(--color-ink);
        border-top: 1px solid rgba(255, 255, 255, 0.15);
        max-height: 0;
        overflow: hidden;
    }

    .nav-toggle:checked ~ .main-nav {
        max-height: 20rem;
    }

    .main-nav a {
        padding: var(--space-4);
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    }
}

/* ------------------------------------------------------------ usp bar ---- */

/* The bar is the window; the list inside it is what moves. */
.usp-bar {
    overflow: hidden;
    padding: var(--space-3) 0;
    background: var(--color-cream);
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
    font-size: 0.8rem;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-ink);
}

/* One continuous right-to-left loop, the same trick as the USP marquee below:
   the track holds two copies of the list, so translating it by exactly half
   its width lands on the frame it started from and the restart is invisible. */
.usp-bar-track {
    display: flex;
    width: max-content;
    gap: var(--space-6);
    list-style: none;
    padding: 0;
    margin: 0;
    animation: usp-bar-scroll 60s linear infinite;
}

.usp-bar-track li {
    flex: none;
}

/* Let a reader stop it to actually read an item. */
.usp-bar:hover .usp-bar-track,
.usp-bar:focus-within .usp-bar-track {
    animation-play-state: paused;
}

@keyframes usp-bar-scroll {
    from { transform: translateX(0); }
    /* Half the track is one full copy of the list. */
    to { transform: translateX(calc(-50% - var(--space-6) / 2)); }
}

/* Continuous motion is a vestibular trigger, so it stops entirely when the
   visitor asks for that. The second copy only exists to make the loop
   seamless, so it is hidden here: it would otherwise show every item twice. */
/* ------------------------------------------------------------- recipes --- */

/* Same measure and centring as .product-grid, so the recipes page reads as the
   shop's sibling rather than a different site. */
.recipe-grid {
    display: grid;
    grid-template-columns: 1fr;
    justify-content: center;
    gap: var(--space-5);
}

/* From here the columns have a fixed measure, so the grid is narrower than
   its wrapper and has to centre itself: justify-content only places the
   columns inside the grid box, it does not centre that box. Below this width
   the single column should still fill the screen, so it is not set there. */
@media (min-width: 30em) {
    .recipe-grid {
        grid-template-columns: repeat(auto-fit, 20rem);
        width: fit-content;
        margin-left: auto;
        margin-right: auto;
        max-width: calc(2 * 20rem + var(--space-5));
    }
}

@media (min-width: 60em) {
    /* auto-fit like the two-column step above, not repeat(3, ...): a fixed
       count lays down three tracks whatever the number of recipes, so a single
       tile sat in the first of them while fit-content still measured all
       three -- off to the left, and each track narrow enough that a long title
       broke letter by letter. The cap holds the row to three. */
    .recipe-grid {
        grid-template-columns: repeat(auto-fit, 20rem);
        max-width: calc(3 * 20rem + 2 * var(--space-5));
    }
}

.recipe-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    color: inherit;
    text-decoration: none;
    background: var(--color-tile);
    border-radius: var(--radius-lg);
    transition: background-color 0.18s ease;
}

.recipe-card:hover {
    background: var(--color-tile-hover);
}

/* Unlike a bottle, a dish photo may be cropped -- so this one fills the frame
   edge to edge instead of sitting inside padding like .product-card-media. */
.recipe-card-media {
    height: 220px;
    background: var(--color-tile-hover);
}

.recipe-card-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.recipe-card-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-4) var(--space-5);
    text-align: center;
}

/* The editor writes the title, so it can be a good deal longer than "Mango
   Dragon Habanero". It wraps between words; breaking inside one is a last
   resort for a single word wider than the tile, which is the lesser evil
   against a title spilling out of the card. */
.recipe-card-body h3 {
    margin: 0;
    font-size: clamp(1rem, 2.4vw, 1.2rem);
    letter-spacing: 0.01em;
    overflow-wrap: break-word;
}

/* The title settings an editor picks per recipe (TitleSize, TitleTracking,
   TitleAlign in cms/models.py). Each choice is a class the template puts on
   the element, so adding a step means adding it in both places.

   Letter-spacing is here for a reason worth stating: typing spaces between
   the letters looks the same on screen but is a different text. A screen
   reader then spells the title out, it wraps at every letter, and a search
   for "zuurdesem" no longer finds it. This changes the spacing and leaves the
   word intact. */
.recipe-card-body h3.title--small { font-size: clamp(0.9rem, 2vw, 1rem); }
.recipe-card-body h3.title--medium { font-size: clamp(1rem, 2.4vw, 1.2rem); }
.recipe-card-body h3.title--large { font-size: clamp(1.15rem, 3vw, 1.5rem); }

.recipe-card-body h3.tracking--tight { letter-spacing: -0.02em; }
.recipe-card-body h3.tracking--normal { letter-spacing: 0.01em; }
.recipe-card-body h3.tracking--wide { letter-spacing: 0.12em; }

/* The site-wide h1,h2,h3 rule uppercases every heading; this is the opt-out
   for a title that reads better as the editor typed it. */
.recipe-card-body h3.title--as-typed { text-transform: none; }

/* The body is a flex column, so the text alignment and the cross-axis have to
   agree -- text-align alone would leave the items themselves centred. */
.recipe-card-body.align--left {
    text-align: left;
    align-items: flex-start;
}

.recipe-card-body.align--center {
    text-align: center;
    align-items: center;
}

.recipe-card-body p {
    margin: 0;
    font-size: 0.9rem;
    color: var(--color-muted);
}

/* A tile with no photo yet would collapse to just its title; keep the frame so
   the grid stays even while the owner is still adding images. */
.recipe-card-media:empty {
    min-height: 220px;
}

.recipe-product,
.recipe-back {
    margin-top: var(--space-5);
}

@media (prefers-reduced-motion: reduce) {
    .usp-bar { padding: var(--space-3) var(--space-4); }

    .usp-bar-track {
        animation: none;
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--space-2) var(--space-6);
        width: auto;
        text-align: center;
    }

    .usp-bar-track li[aria-hidden="true"] { display: none; }
}

/* ------------------------------------------------------------ buttons ---- */

.btn {
    display: inline-block;
    padding: var(--space-4) var(--space-6);
    border: 0;
    border-radius: var(--radius-pill);
    font-family: var(--font-display);
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    text-decoration: none;
    cursor: pointer;
    transition: transform 0.15s ease, background-color 0.15s ease;
}

.btn:hover { transform: translateY(-2px); }

.btn-primary {
    background: var(--color-orange);
    color: var(--color-ink);
}

.btn-primary:hover { background: var(--color-orange-dark); color: var(--color-white); }

.btn-ink {
    background: var(--color-ink);
    color: var(--color-white);
}

.btn-ink:hover { background: #000; }

.btn-lg {
    padding: var(--space-5) var(--space-7);
    font-size: 1.15rem;
}

/* ----------------------------------------------------------- sections ---- */

.block {
    padding: var(--space-7) var(--space-4);
}

.block > * {
    max-width: var(--maxw);
    margin-left: auto;
    margin-right: auto;
}

.section--orange { background: var(--color-orange); }
.section--ink { background: var(--color-ink); color: var(--color-white); }
.section--cream { background: var(--color-cream); }
.section--white { background: var(--color-white); min-height:9.5rem}

/* The story block, when an editor gives it a background photo. The photo is a
   real <img> rather than a CSS background: the URL is only known per request,
   and an inline style attribute carrying it is blocked by style-src 'self'. */
.block-story--image {
    position: relative;
}

/* The section paints an opaque colour of its own, so the photo cannot sit
   behind it on a negative z-index -- that would bury it. It stacks in front
   instead, as the first layer, with the scrim and text lifted above it. */
.block-story--image.section--cream { background: none; }

.block-story-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    object-position: center;
}

/* Text over a photo needs its own contrast: the scrim is what keeps it
   readable whatever the editor uploads, rather than trusting the image. */
.block-story--light {
    position: relative;
    color: var(--color-white);
}

.block-story--light::before {
    position: absolute;
    inset: 0;
    z-index: 1;
    background: rgba(0, 0, 0, 0.45);
    content: "";
}

/* The photo places itself; only the text needs lifting above photo and scrim.
   This applies with or without light text: once there is a photo in front of
   the section background, unlifted text would end up behind it. */
.block-story--image > div,
.block-story--light > div {
    position: relative;
    z-index: 2;
}

.section-intro {
    max-width: 60ch;
    color: var(--color-muted);
}

.section--ink .section-intro { color: rgba(255, 255, 255, 0.75); }

/* --------------------------------------------------------------- hero ---- */

.hero {
    position: relative;
    overflow: hidden;
    padding: var(--space-8) var(--space-4);
    background: var(--color-orange);
    color: var(--color-ink);
}

/* Text and bottle side by side, each in its own column. The bottle used to be
   positioned absolutely behind the text, which only held while the text was
   fixed: an editor writing a longer tagline pushed the button down onto the
   photo. A column cannot be overlapped, so the block now grows instead. */
/* One column on a phone; from 48em the two sit side by side and the pair is
   centred in the hero (see the media query below). */
.hero-inner {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
    align-items: center;
}

/* The editor decides the wording, so the text has to survive a word longer
   than its column rather than being clipped by the hero's overflow: hidden. */
.hero-text {
    overflow-wrap: anywhere;
}

/* The banner image gets its own steps rather than the .img--* caps used for
   page images: it shares the block with the text, so what reads as "groot"
   beside a heading is far smaller than a photo that owns the full width. */
/* The fallback for a banner rendered without a size class; every one the CMS
   renders carries one, since the field has a default. */
.hero-image {
    justify-self: center;
    max-width: 320px;
}

/* Stacked under the text on a phone, where the bottle has the whole width to
   itself: the steps are a share of that width rather than of the screen, and
   the cap keeps the largest one from towering over the heading above it. */
.hero-image.img--xsmall { max-width: min(30%, 140px); }
.hero-image.img--small { max-width: min(45%, 200px); }
.hero-image.img--medium { max-width: min(60%, 260px); }
.hero-image.img--large { max-width: min(75%, 320px); }
.hero-image.img--mega { max-width: 100%; }
.hero-image.img--full { max-width: 100%; }

.hero-image img {
    width: 100%;
    height: auto;
}

.hero .eyebrow {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 0.8rem;
    margin-bottom: var(--space-3);
}

/* Wide enough for a short product name on two or three lines. Not a hard cap
   in characters any more: the editor sets the title, and its column is what
   decides where it wraps.

   The negative indent lines the heading up with the eyebrow above it. Every
   glyph carries a little blank space on its left (its side bearing), and that
   space scales with the type size -- so at 4.5rem the heading visibly starts
   further right than the 0.8rem line above, even though both boxes begin at
   the same edge. In em it stays proportional, and so keeps holding as the
   clamped heading resizes. */
.hero h1 {
    max-width: 14ch;
    margin-left: -0.055em;
}

/* The tagline is the widest thing in the text column, so its measure is what
   sets that column's width. 44ch broke the sentence into three short lines
   against a half-empty column; 52ch is still a comfortable measure and gives
   the block a shape that matches the bottle beside it. */
.hero .tagline {
    max-width: 52ch;
    font-size: clamp(1rem, 2.6vw, 1.25rem);
    margin-bottom: var(--space-6);
}

/* On a phone the bottle sits centred under the text, and a button hard against
   the left edge read as unrelated to it. Centring only the button, rather than
   the whole text block, keeps the eyebrow, heading and tagline ranged left
   where they belong -- an uppercase display heading is what anchors that edge,
   and centring it too would loosen the whole hero.

   A margin rather than text-align on the parent, for the same reason: the
   button is inline-block, so auto margins move the box itself and leave
   everything around it untouched. display: table is what gives it a shrink-to-
   fit width that auto margins can act on without stretching the pill to the
   full column. */
@media (max-width: 47.99em) {
    .hero-text .btn {
        display: table;
        margin-left: auto;
        margin-right: auto;
    }
}

@media (min-width: 48em) {
    .hero { padding: var(--space-8) var(--space-6); }

    /* Columns sized to what is in them, not to a share of the screen.
       1.1fr/0.9fr split the full width whatever that width was, so on a wide
       monitor both columns grew while the heading (14ch) and the tagline
       (44ch) stayed the same size -- and all that growth turned into a gap
       down the middle. max-content gives the text the width it actually
       needs; the bottle column takes its own size from the cap below.

       The pair is then centred as a unit. The hero used to open hard left
       against its own padding edge, which was deliberate while the columns
       filled the width; now that they are only as wide as their contents,
       that left the whole block stranded on the left of a wide screen. */
    .hero-inner {
        grid-template-columns: minmax(0, max-content) auto;
        justify-content: center;
        gap: var(--space-8);
    }

    /* Hard against the bottle rather than centred in a column of its own:
       the column is now only as wide as the image, so there is no leftover
       space left to centre it in. */
    .hero-image { justify-self: start; }

    /* Side by side from here on, so each step scales with the viewport rather
       than being one fixed number. A fixed width is right on the screen it
       was chosen on and wrong on every other: 260px is a good share of a
       laptop hero and a stamp on a 4K display, so the bottle appeared to
       shrink as the screen grew. The vw term holds its proportion, and the
       bounds stop it collapsing just past this breakpoint or turning into a
       poster on an ultrawide. */
    .hero-image.img--xsmall { max-width: clamp(100px, 9vw, 160px); }
    .hero-image.img--small { max-width: clamp(150px, 13vw, 230px); }
    .hero-image.img--medium { max-width: clamp(200px, 18vw, 330px); }
    .hero-image.img--large { max-width: clamp(250px, 24vw, 430px); }
}

/* ------------------------------------------------------------ products --- */

/* Centred rather than stretched: a last row that does not fill the grid sits
   in the middle of the section instead of hanging off the left edge. The
   columns take a fixed measure so they keep that width when centred.

   The auto margins are what centre the grid itself. justify-content only
   places the columns inside the grid box, and that box is a block filling the
   full 1180px wrapper -- while three 20rem columns come to far less than
   that. Without them the whole set sits against the left edge and the
   leftover width collects on the right. */
.product-grid {
    display: grid;
    grid-template-columns: 1fr;
    justify-content: center;
    gap: var(--space-5);
}

/* Same as .recipe-grid: once the columns stop growing, the grid box has to
   centre itself inside the full-width wrapper.

   auto-fit rather than a fixed count, so the row is as wide as the number of
   cards actually in it. repeat(2, ...) always lays down two tracks, so a shop
   holding one product measured two columns wide and left the card in the
   first of them -- centring the grid, but not the card inside it. auto-fit
   drops the empty track instead. */
@media (min-width: 30em) {
    .product-grid {
        grid-template-columns: repeat(auto-fit, 20rem);
        width: fit-content;
        margin-left: auto;
        margin-right: auto;
        /* auto-fit fills whatever width it is given, so the cap is what holds
           the row to two here and three further down. */
        max-width: calc(2 * 20rem + var(--space-5));
    }
}

/* Three across, the way the shop reads best: big enough to show the bottle,
   not so many that the row turns into a contact sheet. */
@media (min-width: 60em) {
    /* The cap is what keeps it to three: auto-fit would otherwise keep adding
       tracks across a wide screen until the row became a contact sheet. */
    .product-grid {
        grid-template-columns: repeat(auto-fit, 20rem);
        max-width: calc(3 * 20rem + 2 * var(--space-5));
    }
}

/* ---------------------------------------------------------- page heads --- */

/* Every orange title bar on the site, centred as one set. Listed by header
   class rather than on .section--orange, which is a colour and also paints
   sections that are not headings. */
/* Every orange title bar, whatever the page: one heading on a strip of
   colour. They are listed together so the bar looks the same on all of them
   -- the size and padding used to be set per class further down, which left
   the pages missing from that rule (recepten, contact, winkelwagen, afrekenen,
   bevestiging, bestelling opzoeken) falling back to the page-wide h1 at up to
   4.5rem, nearly twice the size of the others. */
.block-shop-header,
.block-recipes-header,
.block-page-header,
.block-contact-header,
.block-cart-header,
.block-checkout-header,
.block-confirmation-header,
.block-lookup-header {
    text-align: center;
    padding-top: var(--space-5);
    padding-bottom: var(--space-5);
}

/* The heading is the whole block, so it carries no trailing margin of its
   own -- the padding above does that job. */
.block-shop-header h1,
.block-recipes-header h1,
.block-page-header h1,
.block-contact-header h1,
.block-cart-header h1,
.block-checkout-header h1,
.block-confirmation-header h1,
.block-lookup-header h1 {
    margin: 0;
    font-size: clamp(1.8rem, 5vw, 2.6rem);
}

/* The taglines under these headings are prose, so they keep a readable measure
   and centre that measure rather than stretching over the whole bar. */
.block-contact-header .tagline,
.block-page-header .tagline,
.block-confirmation-header .tagline,
.block-lookup-header .tagline {
    max-width: 60ch;
    margin-left: auto;
    margin-right: auto;
}

.block-shop {
    padding-top: var(--space-6);
}

/* The cards centre their own contents, so the section only has to centre the
   heading above them. */
.block-products { text-align: center; }

/* ---------------------------------------------------------------- usps --- */

/* Side by side from tablet up: the columns share the row equally. Three
   columns on a phone leave each one too narrow to read, so they stack. */
.usp-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-4);
    text-align: center;
}

@media (max-width: 47.99em) {
    .usp-grid {
        grid-template-columns: 1fr;
        gap: var(--space-6);
    }
}

@media (min-width: 48em) {
    .usp-grid { gap: var(--space-6); }
}

/* Image on top, text underneath, both centred on the column. */
.usp-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* The editor's chosen size decides the icon now, so the width is the cap
   itself rather than a fixed 100px that the .img--* rule could not beat.
   Square, so the height follows the width the step allows. */
.usp-item img {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    margin: 0 0 var(--space-3);
    flex: none;
}

/* Icon steps of their own: the page scale is sized for photos in a text
   column and would render an icon absurdly large. */
.usp-item .img--xsmall { max-width: 56px; }
.usp-item .img--small { max-width: 100px; }
.usp-item .img--medium { max-width: 140px; }
.usp-item .img--large { max-width: 190px; }
.usp-item .img--mega,
.usp-item .img--full { max-width: 260px; }

/* One stacked column is the full text width, so an icon scaled to it towers
   over its own heading. Cap every step at the same modest size on a phone. */
@media (max-width: 47.99em) {
    .usp-item img { max-width: 120px; }
    .usp-item .img--xsmall { max-width: 56px; }
    .usp-item .img--small { max-width: 100px; }
}

.usp-item h3 {
    margin: 0 0 var(--space-2);
}

.usp-item p {
    margin: 0;
    color: var(--color-muted);
}

/* Four or more: one continuous right-to-left loop. The track holds two copies
   of the list, so translating it by exactly half its width lands on the same
   frame it started from and the restart is invisible. */
.usp-marquee {
    overflow: hidden;
}

.usp-track {
    display: flex;
    width: max-content;
    gap: var(--space-6);
    animation: usp-scroll 40s linear infinite;
}

.usp-track .usp-item {
    flex: 0 0 220px;
}

/* A fixed 220px column plus the gap is wider than the screen on a phone, so
   the row runs past the edge. Stack the copies instead of scrolling them. */
@media (max-width: 47.99em) {
    .usp-track {
        display: flex;
        flex-direction: column;
        align-items: center;
        width: auto;
        animation: none;
    }

    .usp-track .usp-item {
        flex: none;
        width: 100%;
    }

    /* The second copy only exists to make the loop seamless; without the
       animation it would just show every USP twice. */
    .usp-track .usp-item[aria-hidden="true"] {
        display: none;
    }
}

/* Let a reader stop it to actually read an item. */
.usp-marquee:hover .usp-track,
.usp-marquee:focus-within .usp-track {
    animation-play-state: paused;
}

@keyframes usp-scroll {
    from { transform: translateX(0); }
    /* Half the track is one full copy of the list. */
    to { transform: translateX(calc(-50% - var(--space-6) / 2)); }
}

/* Continuous motion is a vestibular trigger and cannot be escaped by
   scrolling past it, so it stops entirely when the visitor asks for that.
   The second copy of the list only exists to make the loop seamless, so it is
   hidden here: wrapping it into view would show every USP twice. */
@media (prefers-reduced-motion: reduce) {
    .usp-track {
        animation: none;
        flex-wrap: wrap;
        justify-content: center;
        width: auto;
    }

    .usp-track .usp-item[aria-hidden="true"] {
        display: none;
    }
}

/* Flat warm tile, no shadow: the product photo carries the card, so the
   container stays quiet and gives it room. */
.product-card {
    position: relative;
    display: flex;
    flex-direction: column;
    color: inherit;
    text-decoration: none;
    padding: var(--space-5) var(--space-4) var(--space-6);
    background: var(--color-tile);
    border-radius: var(--radius-lg);
    transition: background-color 0.18s ease;
}

.product-card:hover {
    background: var(--color-tile-hover);
}

/* Under the title, centred with the rest of the card body. */
.product-card-price {
    font-size: 0.95rem;
    font-weight: bold;
}

/* Fixed height so every photo lands on the same baseline whatever its
   proportions, and contain rather than cover: a bottle must not be cropped. */
.product-card-media {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 260px;
    margin-bottom: var(--space-5);
}

.product-card img {
    max-height: 100%;
    width: auto;
    object-fit: contain;
}

.product-card-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    text-align: center;
}

/* The shared .badge rule aligns to the start for the left-aligned product
   detail page; inside the centred card it has to follow the card. */
.product-card-body .badge {
    align-self: center;
}

.product-card h3 {
    margin: 0;
    font-size: clamp(1rem, 2.4vw, 1.2rem);
    letter-spacing: 0.01em;
}

.price {
    font-family: var(--font-display);
    font-size: 1.3rem;
    color: var(--color-orange-dark);
    margin: 0;
}

.price-old {
    text-decoration: line-through;
    color: var(--color-muted);
    font-family: var(--font-base);
    font-size: 1rem;
    font-weight: normal;
    margin-left: var(--space-2);
}

/* --------------------------------------------------------------- badges -- */

.badge {
    display: inline-block;
    align-self: flex-start;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    font-size: 0.75rem;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: var(--color-border);
    color: var(--color-ink);
}

.badge-sold-out {
    background: var(--color-muted);
    color: var(--color-white);
}

.badge-preorder {
    background: var(--color-green);
    color: var(--color-white);
}

/* -------------------------------------------------------- product detail - */

/* The photo and the detail text read as one pair, so the two columns are
   sized to their content and centred together rather than each filling half
   of the page -- otherwise they drift to opposite edges on a wide screen. */
.block-product-detail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-6);
}

/* .block > * centres every direct child with auto side margins; on these flex
   items that would push the pair back to the outer edges. */
.block-product-detail > * {
    margin-left: 0;
    margin-right: 0;
}

@media (min-width: 48em) {
    .block-product-detail {
        flex-direction: row;
        align-items: flex-start;
        justify-content: center;
        gap: var(--space-6);
    }
}

/* The photo is one column of a two-column page, not a hero: it is capped so a
   tall bottle shot cannot run past the detail text beside it. */
.product-images {
    flex: 0 1 26rem;
    max-width: 26rem;
}

.product-image-main img {
    width: 100%;
    max-height: 26rem;
    object-fit: contain;
    border-radius: var(--radius-md);
    background: var(--color-white);
}

.product-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.product-thumbs img {
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--color-white);
}

/* The global h1 is sized for the hero, where the product name is the headline
   on a full-width orange band. Here it shares a column with the price and
   specs, so it steps down to suit the text beside it. */
/* Capped so the specs stay a readable column beside the bottle instead of
   stretching across the rest of the page. */
.product-info {
    flex: 0 1 34rem;
    min-width: 0;
}

.product-info h1 {
    font-size: clamp(1.8rem, 4vw, 2.6rem);
}

.product-info .price { font-size: 2rem; }

.product-info .description { font-size: 1.05rem; }

/* Heat meter: filled pips up to the product's heat level. */
.heat-meter {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.heat-pip {
    width: 14px;
    height: 14px;
    border-radius: var(--radius-pill);
    border: 2px solid var(--color-orange-dark);
}

.heat-pip.is-on { background: var(--color-orange-dark); }

.heat-label {
    font-weight: bold;
    font-size: 0.9rem;
}

.spec-list {
    margin: var(--space-5) 0;
    padding: var(--space-4) 0 0;
    border-top: 1px solid var(--color-border);
}

.spec-list div {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-1);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}

@media (min-width: 30em) {
    .spec-list div { grid-template-columns: 10rem 1fr; gap: var(--space-4); }
}

.spec-list dt {
    font-weight: bold;
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-muted);
}

.spec-list dd { margin: 0; }

/* Renders stored newlines without needing <br /> tags. */
.preserve-lines { white-space: pre-line; }

/* ---------------------------------------------------------- story block -- */

.split {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
    align-items: center;
}

@media (min-width: 48em) {
    .split { grid-template-columns: 1fr 1fr; gap: var(--space-7); }
}

.split img { border-radius: var(--radius-md); }

/* -------------------------------------------------------- testimonials --- */

.testimonial-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
}

@media (min-width: 48em) {
    .testimonial-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
}

blockquote {
    margin: 0;
    padding: var(--space-5);
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.06);
}

blockquote p {
    font-size: 1.15rem;
    font-style: italic;
}

blockquote cite {
    font-style: normal;
    font-weight: bold;
    color: var(--color-orange);
}

/* ------------------------------------------------------------- footer ---- */

.site-footer {
    padding: var(--space-7) var(--space-4) var(--space-5);
    background: var(--color-ink);
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.92rem;
}

.footer-inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
    max-width: var(--maxw);
    margin: 0 auto;
}

/* Four columns for four blocks: the logo plus the three link lists. A fifth
   track would leave a gap where the contact column used to be. */
@media (min-width: 48em) {
    .footer-inner { grid-template-columns: 1.2fr 1fr 1fr 1fr; }
}

/* Centred on a phone, where the footer is one stacked column and a
   left-aligned mark reads as misplaced. The desktop grid below restores the
   left alignment its columns expect. */
/* align-items, not just justify-content: a flex container stretches its items
   across the cross axis by default, and the grid row is as tall as the link
   columns beside it. Without this the logo is pulled to that full height while
   its width stays 120px -- the same mark, stretched top to bottom. */
.footer-logo {
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

.footer-logo img {
    width: 120px;
    /* The proportions come from the file itself; height: auto is what keeps
       them once a layout starts handing out heights. */
    height: auto;
    filter: invert(1);
}

/* The menu column repeats links the header already carries, and on a phone
   every column is a full-height row: dropping it is what keeps the stacked
   footer short enough to scroll past. */
.footer-menu {
    display: none;
}

@media (min-width: 48em) {
    .footer-logo { justify-content: flex-start; }
    .footer-menu { display: block; }
}

.site-footer h3 {
    font-size: 0.85rem;
    letter-spacing: 0.08em;
    color: var(--color-white);
    margin-bottom: var(--space-3);
}

.footer-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.site-footer a {
    color: rgba(255, 255, 255, 0.75);
    text-decoration: none;
}

.site-footer a:hover { color: var(--color-orange); }

.footer-bottom {
    max-width: var(--maxw);
    margin: var(--space-6) auto 0;
    padding-top: var(--space-4);
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    font-size: 0.85rem;
}

.footer-bottom p { margin: 0; }

/* --------------------------------------------------------------- cart --- */

.cart-button {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    color: var(--color-white);
    text-decoration: none;
}

/* Cart glyph drawn in CSS: a basket body plus a handle. */
.cart-icon {
    position: relative;
    display: block;
    width: 18px;
    height: 14px;
    border: 2px solid currentColor;
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

.cart-icon::before {
    position: absolute;
    left: 50%;
    top: -9px;
    width: 12px;
    height: 10px;
    margin-left: -6px;
    border: 2px solid currentColor;
    border-bottom: 0;
    border-radius: 6px 6px 0 0;
    content: "";
}

.cart-count {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border-radius: var(--radius-pill);
    background: var(--color-orange);
    color: var(--color-ink);
    font-size: 0.72rem;
    font-weight: bold;
    line-height: 20px;
    text-align: center;
}

.cart-count.is-empty { display: none; }

.cart-overlay {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(20, 16, 13, 0.5);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, visibility 0.25s ease;
}

.cart-drawer {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 70;
    display: flex;
    flex-direction: column;
    width: min(420px, 100%);
    height: 100%;
    background: var(--color-cream);
    box-shadow: var(--shadow-lg);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.3s ease, visibility 0.3s ease;
}

.cart-open .cart-overlay { opacity: 1; visibility: visible; }
.cart-open .cart-drawer { transform: translateX(0); visibility: visible; }
.cart-open { overflow: hidden; }

.cart-drawer-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-5);
    background: var(--color-ink);
    color: var(--color-white);
}

.cart-drawer-head h2 {
    margin: 0;
    font-size: 1.3rem;
}

.cart-close {
    border: 0;
    background: none;
    color: var(--color-white);
    font-size: 1.8rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 var(--space-2);
}

.cart-close:hover { color: var(--color-orange); }

.cart-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--space-5);
}

.cart-reservation {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.35em;
    margin: 0 0 var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-left: 4px solid var(--color-green);
    border-radius: var(--radius-sm);
    background: rgba(74, 130, 68, 0.1);
    font-size: 0.85rem;
}

.cart-reservation [data-cart-countdown] {
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;
}

/* Last five minutes: switch from reassuring green to urgent orange. */
.cart-reservation.is-urgent {
    border-left-color: var(--color-orange-dark);
    background: rgba(200, 95, 19, 0.12);
    color: var(--color-orange-dark);
}

/* Unpaid-order hint: an order left behind at the payment step. Orange rather
   than green, because this one asks the customer to act. */
.cart-unpaid {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin: 0 0 var(--space-4);
    padding: var(--space-4);
    border-left: 4px solid var(--color-orange-dark);
    border-radius: var(--radius-sm);
    background: rgba(200, 95, 19, 0.12);
}

.cart-unpaid-text {
    flex: 1 1 100%;
    margin: 0;
    font-size: 0.9rem;
    color: var(--color-orange-dark);
}

.cart-unpaid-link {
    font-size: 0.85rem;
    color: var(--color-muted);
}

/* Cart lines ------------------------------------------------------------- */

.cart-lines {
    list-style: none;
    margin: 0 0 var(--space-5);
    padding: 0;
}

.cart-line {
    display: grid;
    grid-template-columns: 64px 1fr auto;
    gap: var(--space-3);
    padding: var(--space-4) 0;
    border-bottom: 1px solid var(--color-border);
}

.cart-line-img {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--color-white);
}

.cart-line-img--empty {
    display: block;
    border: 1px dashed var(--color-border);
}

.cart-line-title {
    font-weight: bold;
    text-decoration: none;
}

.cart-line-title:hover { color: var(--color-orange-dark); }

.cart-line-price {
    margin: var(--space-1) 0 var(--space-3);
    font-size: 0.85rem;
    color: var(--color-muted);
}

.cart-line-total {
    margin: 0;
    font-family: var(--font-display);
    white-space: nowrap;
}

.qty-control {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.qty-control form { display: flex; margin: 0; }

.qty-btn {
    width: 28px;
    height: 28px;
    border: 2px solid var(--color-ink);
    border-radius: var(--radius-pill);
    background: none;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.qty-btn:hover:not(:disabled) {
    background: var(--color-ink);
    color: var(--color-white);
}

.qty-btn:disabled { opacity: 0.35; cursor: not-allowed; }

.qty-value {
    min-width: 1.5rem;
    text-align: center;
    font-weight: bold;
}

.cart-remove {
    margin-left: var(--space-2);
    border: 0;
    background: none;
    padding: 0;
    color: var(--color-muted);
    font-size: 0.8rem;
    text-decoration: underline;
    cursor: pointer;
}

.cart-remove:hover { color: var(--color-orange-dark); }

.cart-stock-note {
    margin: var(--space-2) 0 0;
    font-size: 0.78rem;
    color: var(--color-orange-dark);
    font-weight: bold;
}

/* Summary and empty state ------------------------------------------------ */

.cart-summary {
    padding-top: var(--space-4);
    border-top: 2px solid var(--color-ink);
}

.cart-summary-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    font-size: 1.1rem;
    margin-bottom: var(--space-2);
}

.cart-summary-row strong {
    font-family: var(--font-display);
    font-size: 1.5rem;
}

.cart-summary-note {
    margin: 0 0 var(--space-3);
    font-size: 0.8rem;
    color: var(--color-muted);
}

.cart-checkout { width: 100%; }

.cart-checkout:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.cart-checkout:disabled:hover { transform: none; background: var(--color-orange); }

.cart-empty {
    padding: var(--space-6) 0;
    text-align: center;
}

.cart-summary-row--total {
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    font-size: 1.2rem;
}

.cart-checkout {
    display: block;
    width: 100%;
    text-align: center;
}

/* Discount ---------------------------------------------------------------- */

.cart-discount {
    margin-bottom: var(--space-4);
}

.cart-discount-form {
    display: flex;
    gap: var(--space-2);
}

.cart-discount-form input {
    flex: 1;
    min-width: 0;
    padding: var(--space-3);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-sm);
    font: inherit;
}

.cart-discount-form .btn {
    padding: var(--space-3) var(--space-4);
    font-size: 0.85rem;
}

.cart-discount-applied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-left: 4px solid var(--color-green);
    border-radius: var(--radius-sm);
    background: rgba(74, 130, 68, 0.1);
    font-size: 0.9rem;
}

.cart-discount-applied form { margin: 0; }

/* Full cart page --------------------------------------------------------- */

.cart-page {
    max-width: 720px;
    margin: 0 auto;
}

/* ----------------------------------------------------------- checkout ---- */

.checkout-grid,
.confirmation-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
}

@media (min-width: 60em) {
    .checkout-grid { grid-template-columns: 1.5fr 1fr; gap: var(--space-7); }
    .confirmation-grid { grid-template-columns: 1fr 1fr; gap: var(--space-7); }
}

.order-status {
    display: inline-block;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-pill);
    background: var(--color-ink);
    color: #fff;
    font-weight: bold;
}

.order-status--pending { background: #8a6d3b; }
.order-status--paid { background: var(--color-green); }
.order-status--shipped { background: #0b3bc8; }
.order-status--cancelled { background: #6b6259; }
.order-status--refunded { background: #b3261e; }
.order-status--failed { background: #b3261e; }

.lookup-form {
    max-width: 28rem;
}

.checkout-summary {
    align-self: start;
    padding: var(--space-5);
    border-radius: var(--radius-md);
    background: var(--color-cream);
}

@media (min-width: 60em) {
    .checkout-summary { position: sticky; top: calc(var(--header-h) + var(--space-4)); }
}

.checkout-summary h2 { font-size: 1.3rem; }

.cart-line--compact { grid-template-columns: 1fr auto; }

/* Form fields ------------------------------------------------------------- */

.form-section {
    margin: 0 0 var(--space-6);
    padding: 0;
    border: 0;
}

.form-section legend {
    padding: 0;
    margin-bottom: var(--space-4);
    font-family: var(--font-display);
    font-size: 1.1rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.form-field {
    margin-bottom: var(--space-4);
}

.form-field label {
    display: block;
    margin-bottom: var(--space-2);
    font-weight: bold;
    font-size: 0.9rem;
}

.form-field .optional {
    font-weight: normal;
    color: var(--color-muted);
}

.form-field input[type="text"],
.form-field input[type="email"],
.form-field input[type="tel"],
.form-field select {
    width: 100%;
    padding: var(--space-3);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-white);
    font: inherit;
    color: inherit;
}

.form-field input:focus,
.form-field select:focus {
    border-color: var(--color-orange);
    outline: none;
}

.form-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

@media (min-width: 30em) {
    .form-row { grid-template-columns: 1fr 2fr; }
}

.form-check {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}

.form-check input { margin-top: 0.3em; }

.form-check label {
    margin: 0;
    font-weight: normal;
}

.form-error {
    margin: var(--space-2) 0 0;
    font-size: 0.85rem;
    font-weight: bold;
    color: #b3261e;
}

.form-errors {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    border-left: 4px solid #b3261e;
    background: rgba(179, 38, 30, 0.08);
}

.form-errors p { margin: 0; }

/* Flash messages ---------------------------------------------------------- */

.messages {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: var(--space-4);
    list-style: none;
}

.messages li {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-2);
    border-left: 4px solid var(--color-green);
    border-radius: var(--radius-sm);
    background: rgba(74, 130, 68, 0.1);
    transition: opacity 0.4s ease, transform 0.4s ease;
}

.messages li.error {
    border-left-color: #b3261e;
    background: rgba(179, 38, 30, 0.08);
}

.messages li.is-hiding {
    opacity: 0;
    transform: translateY(-0.5rem);
}

.message-close {
    margin-left: auto;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
}

/* --------------------------------------------------------- error page --- */

.error-page {
    padding-top: var(--space-8);
    padding-bottom: var(--space-8);
    text-align: center;
}

.error-page .section-intro {
    margin-left: auto;
    margin-right: auto;
}

.error-code {
    font-family: var(--font-display);
    font-size: clamp(5rem, 22vw, 10rem);
    line-height: 0.9;
    color: var(--color-orange);
    margin: 0 0 var(--space-3);
}

.error-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-3);
    margin: var(--space-6) 0 0;
}

/* ------------------------------------------------------------ a11y ------- */

/* --------------------------------------------------------- bundles ------ */

.bundle-offers {
    margin: var(--space-4) 0;
    padding: var(--space-3) var(--space-4);
    background: var(--color-cream);
    border-radius: var(--radius-md);
}

.bundle-offer {
    margin: 0;
    font-size: 0.9rem;
}

.bundle-offer + .bundle-offer {
    margin-top: var(--space-2);
}

/* --------------------------------------------------------- pull quote ---- */

/* Left-aligned like the body text below it, so the quote reads as the opening
   of the story rather than a centred banner. Slightly wider than that measure:
   the display face is uppercase, so it needs the room to stay on few lines.
   Past this the section's own 1180px cap is what limits the line length. */
.pull-quote {
    max-width: 100ch;
    margin: 0 auto;
    padding: 0;
    background: none;
    text-align: left;
}

.pull-quote p {
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 2.4vw, 1.6rem);
    line-height: 1.35;
    letter-spacing: -0.01em;
    text-transform: uppercase;
    margin: 0;
}

.pull-quote cite {
    display: block;
    margin-top: var(--space-4);
    font-style: normal;
    font-size: 0.85rem;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-muted);
}

/* ------------------------------------------------- cms pages and faq ---- */

/* A title bar, like the shop header: without a size of its own the heading
   falls back to the hero-sized base rule, which dwarfs the page under it. */
/* Centred like .page-body below: once a size cap makes the image narrower
   than the section, it would otherwise hug the left edge of the column. */
.page-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--radius-md);
    margin: 0 auto var(--space-5);
}

/* The size an editor picked in the admin (ImageSize in cms/models.py), as a
   cap rather than a width: the image still shrinks with the column, so these
   only decide how large it may get on a wide screen. Without one an uploaded
   photo rendered at its own pixel size, which is why they came out enormous.
   The class sits on the image itself for a page image and on the wrapper for
   a block image, so both are matched here. Normaal is deliberately narrower
   than the text measure -- it is the step that has to sit neatly on the page,
   not the photo's own size; Mega is the one that fills the column. */
.img--xsmall { max-width: 12rem; }
.img--small { max-width: 18rem; }
.img--medium { max-width: 26rem; }
.img--large { max-width: 40rem; }
.img--mega { max-width: 100%; }
.img--full { max-width: 100%; }

/* Long legal copy is easier to read on a narrower measure. The section centres
   its own child at the page width, so the measure has to centre itself inside
   that -- otherwise the text hugs the left edge of a 1180px column. */
.page-body {
    max-width: 68ch;
    margin-left: auto;
    margin-right: auto;
    color: var(--color-muted);
    font-size: 1.05rem;
    line-height: 1.75;
}

/* The paragraphs filter keeps single newlines as newlines rather than
   emitting <br>, which XHTML would reject; CSS renders them instead. */
.page-body p,
.faq-answer p {
    margin: 0 0 var(--space-4);
    white-space: pre-line;
}

.page-body p:last-child,
.faq-answer p:last-child { margin-bottom: 0; }

/* The three fixed per-block line heights the admin toolbar used to store as a
   class. It now writes style="line-height:..." with a free number, which
   carries its own value and needs no rule here -- these stay for pages stored
   before that change (see LINE_HEIGHT_CLASSES in cms/sanitize.py). Mirrored in
   css/richtext.css so the editor previews what the page renders. */
.lh-tight { line-height: 1.25; }
.lh-normal { line-height: 1.6; }
.lh-loose { line-height: 2.1; }

.page-block {
    display: grid;
    gap: var(--space-5);
    margin-top: var(--space-6);
}

.page-block:first-child { margin-top: 0; }

.page-block h2 { margin: 0 0 var(--space-3); }

/* The .img--* cap sits on this wrapper, so the image fills whatever the
   chosen size allows. Centred for the same reason .page-image is: a capped
   image in a full-width block would otherwise sit against the left edge. */
.page-block-image {
    margin-left: auto;
    margin-right: auto;
}

.page-block-image img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--radius-md);
}

/* Side-by-side only where there is room; stacked on mobile. */
@media (min-width: 48em) {
    .page-block--image_left,
    .page-block--image_right {
        grid-template-columns: 1fr 1fr;
        align-items: center;
    }

    .page-block--image_right .page-block-image { order: 2; }
}

.faq-item {
    max-width: 75ch;
    border-bottom: 1px solid var(--color-border);
    padding: var(--space-4) 0;
}

.faq-item summary {
    cursor: pointer;
    font-weight: 600;
    /* The default marker sits badly next to the larger text. */
    list-style: none;
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
}

.faq-item summary::-webkit-details-marker { display: none; }

.faq-item summary::after {
    content: "+";
    flex: none;
    color: var(--color-orange-dark);
}

.faq-item[open] summary::after { content: "2"; }

.faq-answer {
    margin-top: var(--space-3);
    color: var(--color-muted);
}

.faq-answer p { margin: 0 0 var(--space-3); }
.faq-answer p:last-child { margin-bottom: 0; }

@media (prefers-reduced-motion: reduce) {
    * {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }

    .btn:hover,
    .product-card:hover,
    .recipe-card:hover { transform: none; }

    /* The drawer still opens and closes, just without the slide. */
    .cart-drawer { transition: none; }
}
