/*
 * The Bookshop storefront.
 *
 * Written by hand rather than compiled, because this project ships CSS as
 * plain files in public/ and has no node_modules installed — a Tailwind build
 * step would put npm between a code change and a working deploy for the first
 * time.
 *
 * The values below are the ones from the design system, not approximations:
 * Academic Forest palette, Source Serif 4 over Inter, an 8px rhythm, hairline
 * outlines instead of shadows, and a 4px radius that echoes the corner of a
 * hardcover.
 */

:root {
    /* Surfaces — never pure white for the page, so long reading is easier on
       the eye and the paper feel survives. */
    --sf-surface: #faf9f7;
    --sf-surface-lowest: #ffffff;
    --sf-surface-low: #f4f3f1;
    --sf-surface-container: #efeeec;
    --sf-surface-high: #e9e8e6;
    --sf-surface-highest: #e3e2e0;
    --sf-surface-dim: #dadad8;

    --sf-on-surface: #1a1c1b;
    --sf-on-surface-variant: #414848;
    --sf-outline: #727878;
    --sf-outline-variant: #c1c8c7;

    --sf-primary: #032121;
    --sf-primary-container: #1a3636;
    --sf-on-primary: #ffffff;
    --sf-inverse-surface: #2f3130;
    --sf-inverse-on-surface: #f1f1ef;

    /* Used sparingly — a staff pick badge, an accent rule on a quote. */
    --sf-secondary: #735b30;
    --sf-secondary-container: #fddba6;
    --sf-on-secondary-container: #775f34;

    --sf-error: #ba1a1a;
    --sf-error-container: #ffdad6;
    --sf-on-error-container: #93000a;
    --sf-success: #1e7a4d;
    --sf-success-container: #e7f4ed;

    --sf-serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;
    --sf-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

    --sf-radius: 0.25rem;
    --sf-radius-lg: 0.5rem;
    --sf-radius-pill: 9999px;

    /* The header's height, shared with anything that has to sit clear of it. */
    --sf-header-h: 72px;

    --sf-container: 1280px;
    --sf-gutter: 24px;
    --sf-margin: 64px;
    --sf-margin-mobile: 16px;

    --sf-stack-sm: 12px;
    --sf-stack-md: 24px;
    --sf-stack-lg: 48px;

    /* The one shadow in the system: diffuse, barely there, for lifted states
       only. Everything structural uses a 1px outline instead. */
    --sf-lift: 0 8px 20px rgba(26, 54, 54, 0.05);
}

/* --- reset -------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

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

body.sf {
    margin: 0;
    /* A long unbroken word — an ISBN, a URL in a blurb — must wrap rather
       than widen the page. */
    overflow-wrap: break-word;
    background: var(--sf-surface);
    color: var(--sf-on-surface);
    font-family: var(--sf-sans);
    font-size: 16px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/*
 * Every rule below is wrapped in :where(), which strips it of all specificity.
 *
 * This matters more than it looks. A selector like `.sf p` scores one class
 * plus one element, which beats any plain single-class rule that comes after
 * it — so the reset silently outranked the components it exists to support.
 * It has bitten three separate things already:
 *
 *   - a link styled as a button took body ink instead of white, giving
 *     near-black text on dark green, and only on the anchors, never <button>s;
 *   - <button class="sf-btn"> used the body's 16px/1.5 while
 *     <a class="sf-btn"> used the designed 15px/1, so side by side the two
 *     rendered at different heights;
 *   - an empty-state paragraph lost the `margin: 0 auto` that centres it, and
 *     sat hard against the left of its box.
 *
 * At zero specificity these still supply the defaults, but never win an
 * argument with a component that has an opinion.
 */
:where(.sf h1, .sf h2, .sf h3, .sf h4) {
    font-family: var(--sf-serif);
    color: var(--sf-on-surface);
    margin: 0;
    font-weight: 600;
    letter-spacing: -0.01em;
}

:where(.sf p) { margin: 0; }

:where(.sf img) { max-width: 100%; display: block; }

:where(.sf a) { color: inherit; text-decoration: none; }

:where(.sf button) { font: inherit; cursor: pointer; }

.sf-main { flex: 1 0 auto; }

.sf-container {
    width: 100%;
    max-width: var(--sf-container);
    margin: 0 auto;
    padding: 0 var(--sf-margin-mobile);
}

@media (min-width: 900px) {
    .sf-container { padding: 0 var(--sf-margin); }
}

/* --- typography scale --------------------------------------------------- */

.sf-display {
    font-family: var(--sf-serif);
    font-size: clamp(34px, 5vw, 48px);
    line-height: 1.1;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.sf-headline { font-size: clamp(26px, 3.4vw, 32px); line-height: 1.2; }
.sf-title { font-size: 24px; line-height: 1.3; font-weight: 500; }

.sf-lead {
    font-size: 18px;
    line-height: 1.6;
    color: var(--sf-on-surface-variant);
}

.sf-muted { color: var(--sf-on-surface-variant); }

.sf-eyebrow {
    font-family: var(--sf-sans);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--sf-secondary);
}

.sf-price {
    font-family: var(--sf-sans);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.sf-was {
    color: var(--sf-outline);
    text-decoration: line-through;
    font-weight: 400;
    margin-left: 8px;
}

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

.sf-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 32px;
    border: 1px solid transparent;
    border-radius: var(--sf-radius);
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.sf-btn--primary {
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
}

.sf-btn--primary:hover { background: var(--sf-primary); }

.sf-btn--ghost {
    background: transparent;
    border-color: var(--sf-primary-container);
    color: var(--sf-primary-container);
}

.sf-btn--ghost:hover {
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
}

.sf-btn--quiet {
    background: transparent;
    border-color: var(--sf-outline-variant);
    color: var(--sf-on-surface-variant);
    padding: 10px 18px;
    font-weight: 500;
}

.sf-btn--quiet:hover { border-color: var(--sf-on-surface); color: var(--sf-on-surface); }

.sf-btn--sm { padding: 9px 18px; font-size: 13px; }

.sf-btn--block { width: 100%; }

.sf-btn[disabled], .sf-btn.is-disabled {
    opacity: 0.45;
    pointer-events: none;
}

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

.sf-header {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(250, 249, 247, 0.92);
    /* Frosted rather than opaque, so the page reads as continuous when it
       scrolls under the bar. */
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--sf-outline-variant);
}

.sf-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-stack-md);
    height: var(--sf-header-h);
}

.sf-brand {
    font-family: var(--sf-serif);
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.sf-nav {
    display: none;
    gap: 28px;
    font-size: 14px;
    font-weight: 500;
}

@media (min-width: 900px) { .sf-nav { display: flex; } }

.sf-nav a {
    color: var(--sf-on-surface-variant);
    padding-bottom: 2px;
    border-bottom: 1px solid transparent;
}

.sf-nav a:hover,
.sf-nav a.is-active {
    color: var(--sf-on-surface);
    border-bottom-color: var(--sf-primary-container);
}

.sf-header__actions {
    display: flex;
    align-items: center;
    gap: 6px;
}

.sf-iconbtn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: 0;
    background: transparent;
    border-radius: var(--sf-radius-pill);
    color: var(--sf-on-surface);
}

.sf-iconbtn:hover { background: var(--sf-surface-high); }

/* The basket count. Absolute so it rides the corner of the icon. */
.sf-badge {
    position: absolute;
    top: 2px;
    right: 0;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--sf-radius-pill);
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
    font-size: 11px;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
}

/* --- mobile navigation -------------------------------------------------- */

/*
 * Below 900px the horizontal nav has nowhere to go, so it is replaced by a
 * disclosure panel under the header. Without this a phone had no way to reach
 * the collections at all — only the three icons.
 */
.sf-burger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: 0;
    background: transparent;
    border-radius: var(--sf-radius-pill);
    color: var(--sf-on-surface);
}

.sf-burger:hover { background: var(--sf-surface-high); }

@media (min-width: 900px) {
    .sf-burger { display: none; }
}

.sf-mobilenav {
    border-top: 1px solid var(--sf-outline-variant);
    background: var(--sf-surface);
    /* Never taller than the screen under the header, so a long list of
       collections can still be scrolled to the bottom. */
    max-height: calc(100vh - 72px);
    overflow-y: auto;
}

.sf-mobilenav[hidden] { display: none; }

@media (min-width: 900px) {
    /* The desktop nav is back, so this must not reappear on rotate/resize. */
    .sf-mobilenav { display: none !important; }
}

.sf-mobilenav ul {
    list-style: none;
    margin: 0;
    padding: 8px 0;
}

.sf-mobilenav a {
    display: block;
    padding: 14px var(--sf-margin-mobile);
    font-size: 16px;
    font-weight: 500;
    color: var(--sf-on-surface);
}

.sf-mobilenav a:hover,
.sf-mobilenav a.is-active {
    background: var(--sf-surface-high);
}

.sf-mobilenav__divider {
    height: 1px;
    margin: 8px var(--sf-margin-mobile);
    background: var(--sf-outline-variant);
}

.sf-mobilenav__minor a {
    font-size: 14px;
    font-weight: 400;
    color: var(--sf-on-surface-variant);
    padding-top: 11px;
    padding-bottom: 11px;
}

/* --- disclosure toggle (filters) ---------------------------------------- */

/*
 * On a phone the facet column sits above the books and fills the whole first
 * screen, so somebody landing on the catalogue sees no books at all. It
 * collapses behind this button instead; above 1000px it is a sidebar again and
 * the button goes away.
 */
.sf-disclosure {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 12px 16px;
    margin-bottom: var(--sf-stack-sm);
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius);
    background: var(--sf-surface-lowest);
    font-size: 14px;
    font-weight: 600;
    color: var(--sf-on-surface);
}

.sf-disclosure__label { display: inline-flex; align-items: center; gap: 8px; }

.sf-disclosure__label .material-symbols-outlined { font-size: 18px; }

.sf-disclosure__chevron { transition: transform 0.18s ease; }

.sf-disclosure[aria-expanded="true"] .sf-disclosure__chevron { transform: rotate(180deg); }

@media (min-width: 1000px) {
    .sf-disclosure { display: none; }
}

@media (max-width: 999px) {
    .sf-facets[hidden] { display: none; }

    /* Open on a phone, it reads as a panel rather than a stray column. */
    .sf-facets:not([hidden]) {
        padding: 18px 16px;
        margin-bottom: var(--sf-stack-md);
        border: 1px solid var(--sf-outline-variant);
        border-radius: var(--sf-radius);
        background: var(--sf-surface-lowest);
    }
}

@media (min-width: 1000px) {
    /* The button is gone, so the panel must never stay hidden. */
    .sf-facets[hidden] { display: block !important; }
}

/* --- flash messages ----------------------------------------------------- */

/*
 * The space lives on the message, not on its wrapper.
 *
 * The header is sticky, so a message rendered at the top of <main> otherwise
 * lands hard against its underside with no gap at all and reads as part of
 * the bar. Putting the margin here means a page with nothing to say does not
 * carry the gap — the wrapper is never actually :empty, because Blade leaves
 * whitespace in it.
 */
.sf-flash {
    margin-top: var(--sf-stack-md);
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 14px 18px;
    border-radius: var(--sf-radius);
    border: 1px solid;
    font-size: 14px;
    margin-bottom: var(--sf-stack-md);
}

.sf-flash--good {
    background: var(--sf-success-container);
    border-color: rgba(30, 122, 77, 0.28);
    color: #145636;
}

.sf-flash--bad {
    background: var(--sf-error-container);
    border-color: rgba(186, 26, 26, 0.28);
    color: var(--sf-on-error-container);
}

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

/*
 * Vertical only, deliberately.
 *
 * These are used on the same element as .sf-container — `class="sf-container
 * sf-section"` — and a `padding` shorthand here would reset the container's
 * horizontal padding to zero, putting the text hard against the edge of the
 * screen on anything narrower than the 1280px max width.
 */
.sf-section {
    padding-top: var(--sf-stack-lg);
    padding-bottom: var(--sf-stack-lg);
}

.sf-section--tight {
    padding-top: var(--sf-stack-md);
    padding-bottom: var(--sf-stack-md);
}

.sf-section__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sf-stack-md);
    margin-bottom: var(--sf-stack-md);
    padding-bottom: var(--sf-stack-sm);
    border-bottom: 1px solid var(--sf-outline-variant);
}

.sf-section__link {
    font-size: 13px;
    font-weight: 600;
    color: var(--sf-primary-container);
    white-space: nowrap;
}

.sf-section__link:hover { text-decoration: underline; }

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

.sf-hero {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-lg);
    align-items: center;
    padding: var(--sf-stack-lg) 0;
}

@media (min-width: 900px) {
    .sf-hero {
        /* The cover gets the smaller half: the type is what carries the
           editorial voice. */
        grid-template-columns: 1.15fr 0.85fr;
        gap: 64px;
        padding: 72px 0;
    }
}

.sf-hero__body > * + * { margin-top: var(--sf-stack-md); }

.sf-hero__author {
    font-family: var(--sf-sans);
    font-size: 18px;
    color: var(--sf-on-surface-variant);
}

.sf-hero__quote {
    font-size: 18px;
    line-height: 1.6;
    color: var(--sf-on-surface-variant);
    border-left: 2px solid var(--sf-secondary-container);
    padding-left: 20px;
}

.sf-hero__art {
    position: relative;
    aspect-ratio: 3 / 4;
    background: var(--sf-surface-container);
    border-radius: var(--sf-radius-lg);
    overflow: hidden;
    box-shadow: var(--sf-lift);
}

.sf-hero__art img { width: 100%; height: 100%; object-fit: cover; }

/*
 * A 3:4 box at full phone width is taller than the screen, which pushes the
 * collections below it out of sight entirely. Capped to roughly half a
 * viewport so the page still reads as a page.
 */
@media (max-width: 899px) {
    .sf-hero { padding: var(--sf-stack-md) 0; gap: var(--sf-stack-md); }
    .sf-hero__art { aspect-ratio: 4 / 3; max-height: 52vh; }
}

/* --- category tiles ----------------------------------------------------- */

.sf-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--sf-gutter);
}

.sf-tile {
    display: block;
    padding: 26px 22px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius);
    background: var(--sf-surface-lowest);
    transition: border-color 0.15s ease, transform 0.15s ease;
}

.sf-tile:hover {
    border-color: var(--sf-primary-container);
    transform: translateY(-2px);
}

.sf-tile__name { font-family: var(--sf-serif); font-size: 20px; font-weight: 600; }

.sf-tile__meta { margin-top: 6px; font-size: 13px; color: var(--sf-on-surface-variant); }

/* --- book grid ---------------------------------------------------------- */

.sf-books {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sf-gutter);
}

@media (min-width: 700px) { .sf-books { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .sf-books { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.sf-book { display: flex; flex-direction: column; }

.sf-book__cover {
    position: relative;
    display: block;
    aspect-ratio: 2 / 3;
    background: var(--sf-surface-container);
    border-radius: var(--sf-radius);
    overflow: hidden;
    margin-bottom: var(--sf-stack-sm);
}

/* The link fills the cover so the whole artwork is clickable, while the
   add-to-basket form stays a sibling rather than a child of the anchor. */
.sf-book__coverlink {
    display: block;
    width: 100%;
    height: 100%;
}

.sf-book__cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s ease;
}

.sf-book:hover .sf-book__cover img { transform: scale(1.03); }

/* Stands in for a cover we do not have, rather than a broken image icon. */
.sf-book__cover--empty .sf-book__coverlink {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--sf-outline-variant);
    font-family: var(--sf-serif);
    font-size: 13px;
    text-align: center;
    padding: 16px;
}

/*
 * Clamp a title to a set number of lines.
 *
 * Catalogue-imported books carry the publisher's full record as their name —
 * main title, colon, a sentence of subtitle, then the series in brackets — and
 * two hundred characters of that pushes a card's price below the fold and
 * leaves the grid ragged.
 *
 * Clamped in CSS rather than cut short in PHP on purpose. A character count
 * has to be guessed against one column width and is wrong at every other
 * breakpoint, whereas this stops at whatever actually fits. It also leaves the
 * whole title in the markup, so find-in-page, screen readers and search
 * engines still see the real name; only the drawing is shortened. The elements
 * carry a title attribute, so the full name is a hover away.
 */
.sf-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--sf-clamp-lines, 2);
    line-clamp: var(--sf-clamp-lines, 2);
    overflow: hidden;
}

.sf-book__title {
    font-family: var(--sf-serif);
    font-size: 16px;
    font-weight: 600;
    line-height: 1.35;
}

/*
 * Held at two lines' height whether the title needs them or not, so a row of
 * cards keeps its authors and prices on the same baseline instead of stepping
 * up and down with the length of each name.
 */
.sf-book .sf-book__title {
    min-height: calc(2em * 1.35);
}

.sf-book__author {
    margin-top: 2px;
    font-size: 13px;
    color: var(--sf-on-surface-variant);
}

.sf-book__price { margin-top: 8px; font-size: 15px; }

/* The add-to-basket bar slides up over the cover on hover. On touch, where
   there is no hover, it simply sits visible at the bottom. */
.sf-book__action {
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: 8px;
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.18s ease, transform 0.18s ease;
}

.sf-book:hover .sf-book__action,
.sf-book:focus-within .sf-book__action {
    opacity: 1;
    transform: none;
}

@media (hover: none) {
    .sf-book__action { opacity: 1; transform: none; }
}

/* Quick view and the buy button, side by side across the artwork. */
.sf-book__action {
    display: flex;
    gap: 6px;
}

/*
 * Sized from their own labels, then grown to fill the cover — not forced to
 * equal halves. "Quick view" is a wider word than "Add", and splitting the
 * width down the middle clips the longer of the two on a narrow card.
 */
.sf-book__action > * {
    flex: 1 1 auto;
    min-width: 0;
}

/* A plain flex item. display:contents would work visually but has known
   accessibility-tree quirks, and buys nothing here. */
.sf-book__action form { display: block; }

/* The button inside that form does need to fill it — the form is the flex
   item, the button is just its contents. */
.sf-book__action form .sf-btn { width: 100%; }

/*
 * Buttons that sit on top of the artwork. Their own variants rather than the
 * page ones, because they have to stay legible over a photograph whatever
 * colour it happens to be underneath — hence the solid fills and the blur.
 */
.sf-btn--onart {
    /*
     * No width here on purpose. These are flex items, and a `width: 100%`
     * resolves flex-basis to the full row for the button while the form beside
     * it uses its content width — so the two shrink by wildly different
     * amounts and the shorter label ends up clipped.
     */
    padding: 9px 8px;
    /* Small enough for two controls to share the narrowest card the grid
       produces, without dropping below a readable size. */
    font-size: 12px;
    letter-spacing: 0;
    white-space: nowrap;
    line-height: 1.2;
    border-color: transparent;
    backdrop-filter: blur(4px);
}

/* The buy button keeps the brand green. */
.sf-btn--onart-dark {
    background: rgba(3, 33, 33, 0.92);
    color: #fff;
    gap: 5px;
}

.sf-btn--onart-dark:hover { background: rgba(3, 33, 33, 1); color: #fff; }

/* Quick view is the secondary of the pair, so white with dark ink. */
.sf-btn--onart-light {
    background: rgba(255, 255, 255, 0.94);
    color: var(--sf-primary-container);
}

.sf-btn--onart-light:hover { background: #fff; color: var(--sf-primary); }

/*
 * A card with only one control — an out-of-stock book, which has quick view
 * and nothing else — should not leave half the width empty.
 */
.sf-book__action > :only-child { flex-basis: 100%; }

.sf-flag {
    position: absolute;
    top: 8px;
    left: 8px;
    padding: 4px 10px;
    border-radius: var(--sf-radius-pill);
    background: var(--sf-secondary-container);
    color: var(--sf-on-secondary-container);
    font-size: 11px;
    font-weight: 600;
}

.sf-flag--out {
    background: var(--sf-inverse-surface);
    color: var(--sf-inverse-on-surface);
}

/* --- quick view dialog -------------------------------------------------- */

.sf-quickview {
    width: min(840px, calc(100vw - 32px));
    max-height: calc(100vh - 48px);
    padding: 0;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-lg);
    background: var(--sf-surface);
    color: var(--sf-on-surface);
    overflow: visible;
}

.sf-quickview::backdrop {
    background: rgba(26, 28, 27, 0.45);
    backdrop-filter: blur(2px);
}

.sf-quickview__body {
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    padding: 28px;
}

.sf-quickview__close {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-pill);
    background: var(--sf-surface-lowest);
    color: var(--sf-on-surface);
}

.sf-quickview__close:hover { background: var(--sf-surface-high); }

.sf-quickview__status {
    padding: 48px 0;
    text-align: center;
    color: var(--sf-on-surface-variant);
}

.sf-quickview__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-md);
}

@media (min-width: 700px) {
    .sf-quickview__grid {
        grid-template-columns: 280px 1fr;
        gap: 32px;
        align-items: start;
    }
}

.sf-quickview__cover {
    aspect-ratio: 3 / 2;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    text-align: center;
    background: var(--sf-surface-container);
    border-radius: var(--sf-radius);
    overflow: hidden;
}

@media (min-width: 700px) {
    /* Room for a portrait crop once the panel is two columns. */
    .sf-quickview__cover { aspect-ratio: 2 / 3; padding: 0; }
}

.sf-quickview__cover img { width: 100%; height: 100%; object-fit: cover; }

/*
 * Quantity, buy, and the link to the full page.
 *
 * align-items: flex-end throughout, so the bottom edge of the number field
 * lines up with the bottom edge of both buttons — the field carries a label
 * above it and is therefore taller, and centring it leaves the controls
 * stepped against each other.
 */
.sf-quickview__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--sf-stack-sm);
    margin-top: var(--sf-stack-md);
    padding-top: var(--sf-stack-md);
    border-top: 1px solid var(--sf-outline-variant);
}

/* Alignment comes from .sf-buyrow; this only says how it shares the row with
   the Full details button beside it. */
.sf-quickview__buy {
    gap: 10px;
    /* Holds together as one unit and only drops to its own line when the
       panel is genuinely too narrow for all three controls. */
    flex: 1 1 260px;
}

.sf-quickview__buy .sf-btn { flex: 1 1 auto; }

/*
 * The page buttons carry 32px of padding each side, which is right at full
 * width and leaves too little for "Add to Basket" once the panel narrows —
 * the label wrapped to two lines. Trimmed horizontally only, so the height
 * still matches the field beside it.
 */
.sf-quickview__actions .sf-btn {
    padding-left: 18px;
    padding-right: 18px;
}

.sf-quickview__actions > .sf-btn { flex: 0 0 auto; }

/*
 * Below this the three controls cannot share a line without one of them
 * being squeezed, so they become two full-width rows instead of wrapping
 * into a ragged stack of different widths.
 */
@media (max-width: 560px) {
    .sf-quickview__actions {
        display: grid;
        grid-template-columns: 1fr;
        gap: 10px;
    }

    .sf-quickview__actions > .sf-btn { width: 100%; }

    /* A narrower number field, so the buy button keeps enough room for its
       label on one line. Nobody types four digits into a book quantity. */
    .sf-quickview__buy .sf-qty { width: 64px; }
}

/* --- catalogue layout --------------------------------------------------- */

.sf-catalog {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-sm);
    align-items: start;
}

@media (min-width: 1000px) {
    .sf-catalog { grid-template-columns: 272px 1fr; gap: 48px; }
}

.sf-catalog__query { margin-top: 6px; font-size: 14px; }

/* Still the label style for form questions elsewhere, e.g. a return reason. */
.sf-facet__title {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--sf-on-surface-variant);
    padding-bottom: 8px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--sf-outline-variant);
}

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

/* --- filter panel -------------------------------------------------------- */

/*
 * One card, sections divided by hairlines, each list a column of large tick
 * targets. Sticky on desktop so the filters stay in reach down a long shelf;
 * its own scroll if it is taller than the window.
 */
@media (min-width: 1000px) {
    .sf-facets {
        position: sticky;
        top: calc(var(--sf-header-h) + 20px);
        max-height: calc(100vh - var(--sf-header-h) - 40px);
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-width: thin;
        padding: 20px;
        border: 1px solid var(--sf-outline-variant);
        border-radius: var(--sf-radius-lg);
        background: var(--sf-surface-lowest);
    }
}

.sf-facets__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}

.sf-facets__heading {
    font-size: 20px;
    letter-spacing: -0.015em;
}

/* On a phone the Filters button above already says what this panel is. */
@media (max-width: 999px) {
    .sf-facets__heading { visibility: hidden; height: 0; }
    .sf-facets__head:not(:has(.sf-facets__reset)) { display: none; }
}

.sf-facets__reset {
    font-size: 13px;
    font-weight: 600;
    color: var(--sf-secondary);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: rgb(115 91 48 / 35%);
    transition: text-decoration-color 0.2s ease;
}

.sf-facets__reset:hover { text-decoration-color: currentColor; }

.sf-facet-group {
    padding: 16px 0;
    border-top: 1px solid var(--sf-surface-high);
}

.sf-facet-group--search { padding-top: 0; border-top: 0; }

.sf-facet-group__summary {
    display: flex;
    align-items: center;
    gap: 8px;
    list-style: none;
    cursor: pointer;
    font-size: 14px;
    font-weight: 600;
    color: var(--sf-on-surface);
    border-radius: var(--sf-radius);
    user-select: none;
}

.sf-facet-group__summary::-webkit-details-marker { display: none; }

.sf-facet-group__summary::after {
    content: '';
    width: 7px;
    height: 7px;
    margin: -3px 4px 0 auto;
    border-right: 1.5px solid var(--sf-on-surface-variant);
    border-bottom: 1.5px solid var(--sf-on-surface-variant);
    transform: rotate(45deg);
    transition: transform 0.2s ease;
}

.sf-facet-group:not([open]) > .sf-facet-group__summary::after { transform: rotate(-45deg); margin-top: 0; }

.sf-facet-group__summary:focus-visible {
    outline: 2px solid var(--sf-primary-container);
    outline-offset: 4px;
}

.sf-facet-group__empty {
    margin-top: 10px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--sf-outline);
    text-wrap: pretty;
}

.sf-count-badge {
    display: inline-grid;
    place-items: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--sf-radius-pill);
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

/* Search: a filled field with the icon inside, not a bare underline. */
.sf-search-field {
    position: relative;
}

.sf-search-field .material-symbols-outlined {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 20px;
    color: var(--sf-outline);
    pointer-events: none;
}

.sf-search-field input {
    width: 100%;
    height: 44px;
    padding: 0 12px 0 40px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-lg);
    background: var(--sf-surface);
    font: inherit;
    font-size: 14px;
    color: var(--sf-on-surface);
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.sf-search-field input::placeholder { color: var(--sf-outline); }

.sf-search-field input:hover { border-color: var(--sf-outline); }

.sf-search-field input:focus {
    outline: none;
    background: var(--sf-surface-lowest);
    border-color: var(--sf-primary-container);
    box-shadow: 0 0 0 3px rgb(26 54 54 / 10%);
}

/* --- option lists --- */

.sf-optlist { margin-top: 10px; }

.sf-optlist__filter {
    width: 100%;
    height: 34px;
    margin-bottom: 6px;
    padding: 0 10px;
    border: 1px solid var(--sf-surface-high);
    border-radius: var(--sf-radius);
    background: var(--sf-surface);
    font: inherit;
    font-size: 13px;
    color: var(--sf-on-surface);
    transition: border-color 0.2s ease;
}

.sf-optlist__filter:focus { outline: none; border-color: var(--sf-primary-container); }

.sf-optlist__items { list-style: none; margin: 0; padding: 0; }

.sf-optlist__item[hidden] { display: none; }

.sf-optlist__group {
    margin: 12px 0 2px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--sf-outline);
}

.sf-optlist__group:first-of-type { margin-top: 4px; }

.sf-option {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 -8px;
    padding: 7px 8px;
    border-radius: var(--sf-radius);
    font-size: 14px;
    line-height: 1.35;
    color: var(--sf-on-surface-variant);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.sf-option:hover { background: var(--sf-surface-low); color: var(--sf-on-surface); }

.sf-option input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.sf-option__box {
    position: relative;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--sf-outline-variant);
    border-radius: 5px;
    background: var(--sf-surface-lowest);
    transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

.sf-option:hover .sf-option__box { border-color: var(--sf-outline); }

.sf-option:active .sf-option__box { transform: scale(0.92); }

/* The tick: two borders of a rotated box, drawn only when checked. */
.sf-option__box::after {
    content: '';
    position: absolute;
    left: 5px;
    top: 1.5px;
    width: 5px;
    height: 10px;
    border: solid var(--sf-on-primary);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg) scale(0.4);
    opacity: 0;
    transition: transform 0.15s ease, opacity 0.15s ease;
}

.sf-option input:checked + .sf-option__box,
.sf-option input:indeterminate + .sf-option__box {
    border-color: var(--sf-primary-container);
    background: var(--sf-primary-container);
}

.sf-option input:checked + .sf-option__box::after { transform: rotate(45deg) scale(1); opacity: 1; }

/* Half-ticked: only some of what is under this collection is picked. */
.sf-option input:indeterminate + .sf-option__box::after {
    left: 3.5px;
    top: 6.5px;
    width: 8px;
    height: 0;
    border-width: 0 0 2px;
    transform: none;
    opacity: 1;
}

.sf-option input:checked ~ .sf-option__name,
.sf-option input:indeterminate ~ .sf-option__name { color: var(--sf-on-surface); font-weight: 500; }

.sf-option input:focus-visible + .sf-option__box {
    outline: 2px solid var(--sf-primary-container);
    outline-offset: 2px;
}

.sf-option__name { min-width: 0; }

.sf-optlist__more {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 6px;
    padding: 4px 0;
    border: 0;
    background: none;
    font-size: 13px;
    font-weight: 600;
    color: var(--sf-primary-container);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: rgb(26 54 54 / 30%);
}

.sf-optlist__more:hover { text-decoration-color: currentColor; }

.sf-optlist__more[hidden], .sf-optlist__filter[hidden], .sf-optlist__none[hidden] { display: none; }

.sf-optlist__none { padding: 6px 0; font-size: 13px; color: var(--sf-outline); }

/* --- availability switch --- */

.sf-switch {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
}

.sf-switch__text { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; }

.sf-switch__title { font-size: 14px; font-weight: 600; color: var(--sf-on-surface); }

.sf-switch__hint { font-size: 12px; color: var(--sf-outline); }

.sf-switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }

.sf-switch__track {
    position: relative;
    flex: 0 0 38px;
    height: 22px;
    border-radius: var(--sf-radius-pill);
    background: var(--sf-surface-highest);
    transition: background-color 0.2s ease;
}

.sf-switch__track::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--sf-surface-lowest);
    box-shadow: 0 1px 2px rgb(26 54 54 / 25%);
    transition: transform 0.2s cubic-bezier(0.3, 1.4, 0.6, 1);
}

.sf-switch input:checked + .sf-switch__track { background: var(--sf-primary-container); }

.sf-switch input:checked + .sf-switch__track::after { transform: translateX(16px); }

.sf-switch input:focus-visible + .sf-switch__track {
    outline: 2px solid var(--sf-primary-container);
    outline-offset: 2px;
}

/* With JavaScript every control applies itself; the button stays for search. */
.sf-facets__apply { margin-top: 4px; }

form.is-live .sf-facets__apply { display: none; }

/* --- active filters, above the results --- */

.sf-results { min-width: 0; transition: opacity 0.2s ease; }

.sf-results.is-loading { opacity: 0.45; pointer-events: none; }

.sf-active-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: var(--sf-stack-md);
}

.sf-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 32px;
    padding: 0 8px 0 12px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-pill);
    background: var(--sf-surface-lowest);
    font-size: 13px;
    font-weight: 500;
    color: var(--sf-on-surface);
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.sf-chip .material-symbols-outlined {
    font-size: 16px;
    color: var(--sf-outline);
    transition: color 0.15s ease;
}

.sf-chip:hover { border-color: var(--sf-on-surface); background: var(--sf-surface-low); }

.sf-chip:hover .material-symbols-outlined { color: var(--sf-on-surface); }

.sf-chip:active { transform: translateY(1px); }

.sf-chip__label { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.sf-active-filters__clear {
    margin-left: 4px;
    font-size: 13px;
    font-weight: 600;
    color: var(--sf-on-surface-variant);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.sf-active-filters__clear:hover { color: var(--sf-on-surface); }

/* The filter breadcrumb sits above the grid, so it needs no top padding. */
.sf-breadcrumb--filter { padding-top: 0; margin-bottom: var(--sf-stack-md); }

.sf-breadcrumb--filter .sf-breadcrumb__sep { font-size: 16px; }

/* --- forms -------------------------------------------------------------- */

.sf-field { margin-bottom: 18px; }

.sf-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--sf-on-surface-variant);
}

/*
 * A bottom rule rather than a box, per the design system. The 1px sides are
 * transparent rather than absent so focus does not shift the layout.
 */
.sf-input,
.sf-select,
.sf-textarea {
    width: 100%;
    padding: 10px 2px;
    border: 0;
    border-bottom: 1px solid var(--sf-outline-variant);
    border-radius: 0;
    background: transparent;
    font: inherit;
    color: var(--sf-on-surface);
    transition: border-color 0.15s ease;
}

.sf-input:focus,
.sf-select:focus,
.sf-textarea:focus {
    outline: none;
    border-bottom-color: var(--sf-primary-container);
    border-bottom-width: 2px;
    padding-bottom: 9px;
}

.sf-input::placeholder, .sf-textarea::placeholder { color: var(--sf-outline); }

.sf-textarea { resize: vertical; min-height: 90px; }

.sf-select {
    appearance: none;
    /* Room for the chevron drawn by the background image. */
    padding-right: 24px;
    background-image: linear-gradient(45deg, transparent 50%, var(--sf-on-surface-variant) 50%),
                      linear-gradient(135deg, var(--sf-on-surface-variant) 50%, transparent 50%);
    background-position: right 10px center, right 5px center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}

.sf-input.is-invalid, .sf-select.is-invalid { border-bottom-color: var(--sf-error); }

.sf-error { display: block; margin-top: 5px; font-size: 12px; color: var(--sf-error); }

.sf-hint { display: block; margin-top: 5px; font-size: 12px; color: var(--sf-on-surface-variant); }

.sf-grid-2 { display: grid; grid-template-columns: 1fr; gap: 0 var(--sf-gutter); }
.sf-grid-3 { display: grid; grid-template-columns: 1fr; gap: 0 var(--sf-gutter); }

@media (min-width: 640px) {
    .sf-grid-2 { grid-template-columns: repeat(2, 1fr); }
    .sf-grid-3 { grid-template-columns: repeat(3, 1fr); }
}

.sf-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 14px;
    color: var(--sf-on-surface-variant);
}

.sf-check input { margin-top: 3px; accent-color: var(--sf-primary-container); }

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

.sf-product {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-lg);
    padding: var(--sf-stack-md) 0 var(--sf-stack-lg);
}

@media (min-width: 900px) {
    .sf-product { grid-template-columns: 0.85fr 1fr; gap: 64px; }
}

.sf-product__cover {
    aspect-ratio: 2 / 3;
    background: var(--sf-surface-container);
    border-radius: var(--sf-radius-lg);
    overflow: hidden;
    box-shadow: var(--sf-lift);
}

.sf-product__cover img { width: 100%; height: 100%; object-fit: cover; }

/* Same reasoning as the hero: a 2:3 cover at phone width buries the price and
   the Add to Basket button below the fold. */
@media (max-width: 899px) {
    .sf-product { padding-top: var(--sf-stack-sm); gap: var(--sf-stack-md); }
    .sf-product__cover { aspect-ratio: 3 / 2; max-height: 46vh; }
}

.sf-thumbs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
    gap: 10px;
    margin-top: var(--sf-stack-sm);
}

.sf-thumbs img {
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: var(--sf-radius);
    border: 1px solid var(--sf-outline-variant);
}

.sf-product__body > * + * { margin-top: var(--sf-stack-md); }

.sf-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--sf-on-surface-variant);
    padding: var(--sf-stack-md) 0 0;
}

.sf-breadcrumb a:hover { color: var(--sf-on-surface); text-decoration: underline; }

.sf-breadcrumb__sep { opacity: 0.5; }

.sf-buy {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--sf-stack-sm);
    padding: var(--sf-stack-md) 0;
    border-top: 1px solid var(--sf-outline-variant);
    border-bottom: 1px solid var(--sf-outline-variant);
}

.sf-qty { width: 88px; flex: 0 0 auto; }

.sf-specs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--sf-stack-sm) var(--sf-gutter);
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 14px;
}

.sf-specs dt {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--sf-on-surface-variant);
}

.sf-specs dd { margin: 3px 0 0; }

.sf-prose { font-size: 17px; line-height: 1.7; color: var(--sf-on-surface-variant); }

.sf-prose p + p { margin-top: 1em; }

/* The featured-quote component: large serif, gold rule. */
.sf-quote {
    font-family: var(--sf-serif);
    font-size: 22px;
    font-style: italic;
    line-height: 1.5;
    color: var(--sf-on-surface);
    border-left: 3px solid var(--sf-secondary-container);
    padding: 4px 0 4px 24px;
    margin: 0;
}

.sf-stock { font-size: 14px; font-weight: 500; }
.sf-stock--in { color: var(--sf-success); }
.sf-stock--low { color: var(--sf-secondary); }
.sf-stock--out { color: var(--sf-error); }

/* --- basket ------------------------------------------------------------- */

.sf-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-lg);
    align-items: start;
    padding: var(--sf-stack-md) 0 var(--sf-stack-lg);
}

@media (min-width: 1000px) {
    .sf-layout { grid-template-columns: 1fr 360px; gap: 56px; }
}

.sf-line {
    display: grid;
    grid-template-columns: 72px 1fr;
    gap: 18px;
    padding: 20px 0;
    border-bottom: 1px solid var(--sf-outline-variant);
}

.sf-line__cover {
    aspect-ratio: 2 / 3;
    background: var(--sf-surface-container);
    border-radius: var(--sf-radius);
    overflow: hidden;
}

.sf-line__cover img { width: 100%; height: 100%; object-fit: cover; }

.sf-line__body {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sf-stack-sm);
}

.sf-line__tools {
    display: flex;
    /* Update and Remove line up with the bottom of the quantity field rather
       than floating against its middle. */
    align-items: flex-end;
    gap: var(--sf-stack-sm);
    margin-top: 10px;
}

.sf-linkish {
    border: 0;
    background: none;
    padding: 0;
    font-size: 13px;
    color: var(--sf-on-surface-variant);
    text-decoration: underline;
}

.sf-linkish:hover { color: var(--sf-error); }

/* --- summary panel ------------------------------------------------------ */

.sf-panel {
    background: var(--sf-surface-lowest);
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-lg);
    padding: 26px;
}

.sf-panel--sticky { position: sticky; top: 96px; }

.sf-panel__title {
    font-family: var(--sf-serif);
    font-size: 20px;
    font-weight: 600;
    padding-bottom: var(--sf-stack-sm);
    margin-bottom: var(--sf-stack-sm);
    border-bottom: 1px solid var(--sf-outline-variant);
}

.sf-totals { list-style: none; margin: 0; padding: 0; font-size: 15px; }

.sf-totals li {
    display: flex;
    justify-content: space-between;
    gap: var(--sf-stack-sm);
    padding: 7px 0;
    color: var(--sf-on-surface-variant);
}

.sf-totals li span:last-child { font-variant-numeric: tabular-nums; color: var(--sf-on-surface); }

.sf-totals li.is-total {
    margin-top: 10px;
    padding-top: 16px;
    border-top: 2px solid var(--sf-on-surface);
    font-family: var(--sf-serif);
    font-size: 20px;
    font-weight: 600;
    color: var(--sf-on-surface);
}

.sf-totals li.is-free span:last-child { color: var(--sf-success); }

.sf-trust {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--sf-outline-variant);
    font-size: 12px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--sf-on-surface-variant);
}

/* --- mini order lines in a summary -------------------------------------- */

.sf-mini {
    display: grid;
    grid-template-columns: 48px 1fr;
    gap: var(--sf-stack-sm);
    padding: var(--sf-stack-sm) 0;
    border-bottom: 1px solid var(--sf-surface-highest);
}

.sf-mini:last-of-type { border-bottom: 0; }

.sf-mini__cover {
    aspect-ratio: 2 / 3;
    background: var(--sf-surface-container);
    border-radius: 2px;
    overflow: hidden;
}

.sf-mini__cover img { width: 100%; height: 100%; object-fit: cover; }

.sf-mini__title { font-family: var(--sf-serif); font-size: 14px; font-weight: 600; line-height: 1.3; }

.sf-mini__meta {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-top: 4px;
    font-size: 12px;
    color: var(--sf-on-surface-variant);
}

/* --- payment options ---------------------------------------------------- */

.sf-choice {
    display: flex;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius);
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.sf-choice + .sf-choice { margin-top: 10px; }

.sf-choice:hover { border-color: var(--sf-outline); }

/* Driven by :has() so the whole card reacts to its own radio, with no JS. */
.sf-choice:has(input:checked) {
    border-color: var(--sf-primary-container);
    background: var(--sf-surface-low);
    box-shadow: inset 0 0 0 1px var(--sf-primary-container);
}

.sf-choice input { margin-top: 3px; accent-color: var(--sf-primary-container); }

.sf-choice__name { font-weight: 600; font-size: 15px; }
.sf-choice__desc { margin-top: 3px; font-size: 13px; color: var(--sf-on-surface-variant); }

/* --- account ------------------------------------------------------------ */

.sf-account {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-stack-lg);
    align-items: start;
    padding: var(--sf-stack-lg) 0;
}

@media (min-width: 900px) {
    .sf-account { grid-template-columns: 240px 1fr; gap: 56px; }
}

.sf-sidenav { list-style: none; margin: 0; padding: 0; }

.sf-sidenav a, .sf-sidenav button {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 11px 14px;
    border: 0;
    background: none;
    border-radius: var(--sf-radius);
    font-size: 14px;
    font-weight: 500;
    color: var(--sf-on-surface-variant);
    text-align: left;
}

.sf-sidenav a:hover, .sf-sidenav button:hover { background: var(--sf-surface-high); color: var(--sf-on-surface); }

.sf-sidenav a.is-active {
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
}

.sf-order {
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius-lg);
    background: var(--sf-surface-lowest);
    padding: 22px;
}

.sf-order + .sf-order { margin-top: var(--sf-stack-md); }

.sf-order__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sf-stack-sm);
    padding-bottom: var(--sf-stack-sm);
    border-bottom: 1px solid var(--sf-surface-highest);
}

.sf-order__number { font-family: var(--sf-serif); font-size: 17px; font-weight: 600; }

.sf-order__covers {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding: var(--sf-stack-sm) 0;
}

.sf-order__covers img,
.sf-order__covers span {
    width: 46px;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 2px;
    background: var(--sf-surface-container);
}

.sf-status {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 11px;
    border-radius: var(--sf-radius-pill);
    font-size: 12px;
    font-weight: 600;
}

.sf-status--good { background: var(--sf-success-container); color: #145636; }
.sf-status--busy { background: #e8f1f8; color: #1f5f8b; }
.sf-status--warn { background: var(--sf-secondary-container); color: var(--sf-on-secondary-container); }
.sf-status--bad { background: var(--sf-error-container); color: var(--sf-on-error-container); }
.sf-status--idle { background: var(--sf-surface-highest); color: var(--sf-on-surface-variant); }

/* --- narrow single-column pages (sign in, confirmation) ----------------- */

.sf-narrow {
    max-width: 460px;
    margin: 0 auto;
    padding: 64px 0;
}

.sf-narrow--wide { max-width: 660px; }

.sf-narrow__head { text-align: center; margin-bottom: var(--sf-stack-lg); }

.sf-narrow__head p { margin-top: 10px; }

.sf-seal {
    width: 64px;
    height: 64px;
    margin: 0 auto var(--sf-stack-md);
    border-radius: 50%;
    background: var(--sf-success-container);
    color: var(--sf-success);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* --- toast -------------------------------------------------------------- */

/*
 * Confirmation for something that happened without the page moving.
 *
 * Top right, clear of the header. The offset is measured from the header's
 * own height rather than typed as a number, so the gap cannot quietly close
 * up if that height ever changes — sitting too close to a sticky bar with a
 * bottom border makes the message read as part of the bar.
 */
.sf-toast {
    position: fixed;
    z-index: 60;
    left: var(--sf-margin-mobile);
    right: var(--sf-margin-mobile);
    /* The same clearance at every width — a gap that reads as deliberate on a
       desktop should not shrink to something borderline on a phone. */
    top: calc(var(--sf-header-h) + var(--sf-stack-lg));
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 14px 18px;
    border: 1px solid rgba(30, 122, 77, 0.3);
    border-radius: var(--sf-radius);
    background: var(--sf-success-container);
    color: #145636;
    font-size: 14px;
    box-shadow: var(--sf-lift);
    animation: sf-toast-in 0.18s ease-out;
}

.sf-toast[hidden] { display: none; }

.sf-toast.is-bad {
    background: var(--sf-error-container);
    border-color: rgba(186, 26, 26, 0.3);
    color: var(--sf-on-error-container);
}

.sf-toast__icon { font-size: 20px; flex: 0 0 auto; }

/* Wider than a phone: pinned to the right rather than spanning the screen.
   The vertical position is the same at every width. */
@media (min-width: 700px) {
    .sf-toast {
        left: auto;
        right: 24px;
        max-width: 340px;
    }
}

@keyframes sf-toast-in {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: none; }
}

/* Nothing should slide about for somebody who has asked for less motion. */
@media (prefers-reduced-motion: reduce) {
    .sf-toast { animation: none; }
}

/* --- empty states ------------------------------------------------------- */

.sf-empty {
    text-align: center;
    padding: 64px 20px;
    border: 1px dashed var(--sf-outline-variant);
    border-radius: var(--sf-radius-lg);
}

.sf-empty__title { font-family: var(--sf-serif); font-size: 22px; font-weight: 600; }

.sf-empty__text {
    margin: 10px auto var(--sf-stack-md);
    max-width: 420px;
    color: var(--sf-on-surface-variant);
}

/* --- newsletter --------------------------------------------------------- */

.sf-newsletter {
    background: var(--sf-primary-container);
    color: var(--sf-on-primary);
    border-radius: var(--sf-radius-lg);
    padding: 56px var(--sf-margin-mobile);
    text-align: center;
}

.sf-newsletter h2 { color: var(--sf-on-primary); }

.sf-newsletter p {
    margin: var(--sf-stack-sm) auto var(--sf-stack-md);
    max-width: 520px;
    color: rgba(255, 255, 255, 0.78);
}

.sf-newsletter form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-stack-sm);
    max-width: 460px;
    margin: 0 auto;
}

.sf-newsletter .sf-input {
    flex: 1 1 220px;
    color: #fff;
    border-bottom-color: rgba(255, 255, 255, 0.4);
}

.sf-newsletter .sf-input::placeholder { color: rgba(255, 255, 255, 0.55); }

.sf-newsletter .sf-input:focus { border-bottom-color: var(--sf-secondary-container); }

.sf-newsletter .sf-btn {
    background: var(--sf-secondary-container);
    color: var(--sf-on-secondary-container);
}

.sf-newsletter .sf-btn:hover { background: #ffe9bf; }

/*
 * The line that replaces the form once an address is in, and the one that
 * appears under it when the address was not an address. Sits on the dark
 * newsletter panel, so it carries its own colours rather than the page's.
 */
.sf-newsletter__note {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0 auto;
    max-width: 460px;
    color: #fff;
    font-size: 15px;
}

.sf-newsletter__note--bad {
    margin-top: var(--sf-stack-sm);
    color: var(--sf-secondary-container);
}

/* --- image loading ------------------------------------------------------ */

/*
 * A shimmer where a picture is going to be.
 *
 * It sits on the image element itself rather than on a wrapper: covers are
 * already boxed at a fixed aspect ratio by their container, an <img> with no
 * data yet paints nothing but its own background, and a wrapper around each
 * one would mean restyling every thumbnail in the shop. The class comes off
 * the moment the file lands, which is also the moment the picture covers it.
 */
.sf-media {
    background-color: var(--sf-surface-container);
    background-image: linear-gradient(
        100deg,
        var(--sf-surface-container) 30%,
        var(--sf-surface-high) 50%,
        var(--sf-surface-container) 70%
    );
    background-size: 220% 100%;
    animation: sf-shimmer 1.4s ease-in-out infinite;
}

/* Loaded, or given up on: either way the shimmer has nothing left to promise. */
.sf-media.is-loaded,
.sf-media.is-failed {
    background-image: none;
    animation: none;
}

.sf-media.is-loaded { animation: sf-fade-in 260ms ease-out; }

/* A picture that will never arrive should not leave a broken-image glyph. */
.sf-media.is-failed { visibility: hidden; }

@keyframes sf-shimmer {
    from { background-position: 180% 0; }
    to { background-position: -80% 0; }
}

@keyframes sf-fade-in {
    from { opacity: 0.35; }
    to { opacity: 1; }
}

/* A shimmer is decoration; the still background says the same thing. */
@media (prefers-reduced-motion: reduce) {
    .sf-media { background-image: none; animation: none; }
    .sf-media.is-loaded { animation: none; }
}

/* --- pagination --------------------------------------------------------- */

.sf-pagination { margin-top: var(--sf-stack-lg); }

.sf-pagination nav > div:first-child { display: none; }

.sf-pagination svg { width: 16px; height: 16px; }

.sf-pagination .relative.inline-flex,
.sf-pagination span[aria-current='page'] > span,
.sf-pagination a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    padding: 0 10px;
    margin: 0 3px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius);
    font-size: 14px;
    color: var(--sf-on-surface-variant);
    background: var(--sf-surface-lowest);
}

.sf-pagination a:hover { border-color: var(--sf-on-surface); color: var(--sf-on-surface); }

/*
 * Cursor paging renders two controls and no page numbers: a link where there
 * is somewhere to go, a bare span where there is not. The span needs the same
 * pill as the link, muted, or the row reads as half-drawn.
 */
.sf-pagination nav { display: flex; justify-content: center; gap: 6px; }

.sf-pagination nav > span:not([aria-current]) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    padding: 0 10px;
    margin: 0 3px;
    border: 1px solid var(--sf-outline-variant);
    border-radius: var(--sf-radius);
    font-size: 14px;
    color: var(--sf-on-surface-variant);
    background: var(--sf-surface-lowest);
    opacity: 0.45;
}

.sf-pagination span[aria-current='page'] > span {
    background: var(--sf-primary-container);
    border-color: var(--sf-primary-container);
    color: var(--sf-on-primary);
    font-weight: 600;
}

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

.sf-footer {
    flex-shrink: 0;
    margin-top: var(--sf-stack-lg);
    padding: var(--sf-stack-lg) 0;
    background: var(--sf-surface-low);
    border-top: 1px solid var(--sf-outline-variant);
}

.sf-footer__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sf-stack-md);
}

.sf-footer__note { margin-top: 8px; font-size: 13px; color: var(--sf-on-surface-variant); }

.sf-footer__links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-stack-md);
    font-size: 14px;
    color: var(--sf-on-surface-variant);
}

.sf-footer__links a:hover { color: var(--sf-on-surface); text-decoration: underline; }

/* --- utilities ---------------------------------------------------------- */

.sf-stack-sm > * + * { margin-top: var(--sf-stack-sm); }
.sf-stack-md > * + * { margin-top: var(--sf-stack-md); }
.sf-stack-lg > * + * { margin-top: var(--sf-stack-lg); }

.sf-row { display: flex; align-items: center; gap: var(--sf-stack-sm); flex-wrap: wrap; }

/*
 * A quantity field beside its button — the product page, the basket line and
 * the quick view panel.
 *
 * flex-end rather than centre, so the field's underline and the button's
 * bottom edge land on the same line. The field is the taller of the two
 * (more so when it carries a label above it), and centring leaves the two
 * visibly stepped against each other.
 */
.sf-buyrow {
    display: flex;
    align-items: flex-end;
    gap: var(--sf-stack-sm);
    flex-wrap: wrap;
}
.sf-row--between { justify-content: space-between; }

.sf-hr { height: 1px; background: var(--sf-outline-variant); border: 0; margin: var(--sf-stack-lg) 0; }

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

/* --- returns ------------------------------------------------------------ */

/*
 * A line on the return form: tick, title, and how many of it are coming back.
 * The whole row is the label, so the tick has a target the width of the panel
 * rather than 14 square pixels.
 */
.sf-returnline {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    margin: 0;
    border-bottom: 1px solid var(--sf-outline-variant);
    cursor: pointer;
}

.sf-returnline:last-child { border-bottom: 0; }

.sf-returnline__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.sf-returnline__title { font-weight: 600; }

.sf-returnline__qty { flex: 0 0 auto; width: 72px; }

/* Nothing left to return on this line: still listed, so it is clear why. */
.sf-returnline.is-spent { opacity: 0.55; cursor: default; }

.sf-panel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.sf-panel__list { list-style: none; margin: 0; padding: 0; font-size: 14px; }

.sf-panel__list li + li { margin-top: 4px; }

.sf-panel__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--sf-outline-variant);
    font-size: 13px;
}
