/*!
 * Kahuna — storefront theme for Grav + KahunaCart
 *
 * One hand-written stylesheet, no build step. Everything is driven by the
 * custom properties in the token block below: the admin options write
 * --k-accent and --k-grid-max inline, a site's css/custom.css overrides
 * whatever else it wants, and nothing in the rules below needs touching.
 *
 * Light and dark come from the same token block. Every colour is written as
 * light-dark(light, dark) and the page's `color-scheme` picks the side: the
 * system preference by default, or the admin's Colour Scheme option, which
 * pins it through data-theme on <html>. There is no second palette to keep in
 * sync.
 *
 * The storefront's own markup is very nearly NOT styled here. KahunaCart
 * ships assets/kahunacart.css, which styles every kahunacart-* class in the
 * plugin's templates and partials and resolves its internals through
 * --kahunacart-* -> --grav-* -> --theme-accent -> neutral fallback. This
 * theme integrates by publishing those tokens (see "KahunaCart integration"
 * below), not by writing rules against the plugin's classes.
 *
 * Four blocks are the exception, and each says so where it sits: the product
 * gallery (13), the catalog sidebar (14), the storefront search form (12) and
 * the account area (18). Those are partials and pages the theme lays out
 * rather than merely spaces, and every rule in them is scoped under a theme
 * class — which is also what puts them ahead of the plugin's single-class
 * rules, since the plugin's stylesheet loads after this one.
 *
 * Order of business:
 *   1. Tokens / 2. Texture / KahunaCart integration
 *   3. Reset & base / 4. Typography
 *   5. Layout / 6. Header & nav / 7. Footer / 8. Buttons / 9. Forms
 *  10. Tables / 11. Callouts / 12. Storefront: listing head, grid & cards
 *  13. Product detail / 14. Catalog: sidebar, tree, filters, crumbs, tags
 *  15. Cart / 16. Checkout / 17. Receipt & downloads
 *  18. Account area & login / 19. Home page / 20. Processing, denied, error
 *  21. Utilities / 22. Print
 */

/* ------------------------------------------------------------------ 1. tokens */

/*
 * The brand block. These are the ones a site changes; everything else is
 * derived from them or is furniture.
 */
:root {
    color-scheme: light dark;

    /* Two brand colours, split by job. --k-brand is the identity: links,
       current states, emphasis. --k-accent is the action: buttons, the cart
       count, the lead price — the things that want a hand on them. */
    --k-brand: #1a6f83;
    --k-accent: #ca5415;

    --k-font-display: "Bricolage Grotesque", "Avenir Next", "Helvetica Neue", Arial, sans-serif;
    --k-font: "Albert Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
              Roboto, "Helvetica Neue", Arial, sans-serif;
    --k-font-mono: "Spline Sans Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
                   Consolas, "Liberation Mono", monospace;

    --k-radius: 18px;         /* containers: tiles, panels, the receipt */
    --k-radius-sm: 10px;      /* inner elements: inputs, thumbnails, menus */
    --k-radius-btn: 999px;    /* buttons and chips — set to var(--k-radius-sm) for square */
}

/* The admin's Colour Scheme option. `auto` sets nothing and the system
   preference decides; light and dark pin the page either way. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

/*
 * The palette, light side first in every pair. KahunaCart's own: salt and
 * sand grounds, koa ink, lagoon and board for the two brand colours. Every
 * neutral shares the same warm hue so nothing on the page is grey-blue next
 * to something grey-brown.
 */
:root {
    --k-bg: light-dark(#fcf6ea, #17110b);
    --k-bg-alt: light-dark(#f6ead7, #1e160e);
    --k-surface: light-dark(#fffcf4, #241b12);
    --k-surface-sunk: light-dark(#f3e6d0, #1c140d);
    --k-ink: light-dark(#2b1c0c, #f6ead7);
    --k-ink-soft: light-dark(#5c4a38, #d8c8b1);
    --k-muted: light-dark(#8a7660, #a28d75);
    --k-line: light-dark(#e4d5bc, #382b1d);
    --k-line-strong: light-dark(#c9b9a4, #4d3d2c);

    /* A brand colour used as ink (links, labels) needs to be deeper than the
       same colour used as a fill on the light side, and lighter on the dark
       side. Both are derived, so changing --k-brand or --k-accent is enough. */
    --k-brand-strong: light-dark(
        color-mix(in oklab, var(--k-brand) 82%, #2b1c0c),
        color-mix(in oklab, var(--k-brand) 58%, #ffffff)
    );
    --k-brand-deep: color-mix(in oklab, var(--k-brand) 80%, #0b1a1e);
    --k-brand-soft: light-dark(
        color-mix(in oklab, var(--k-brand) 14%, var(--k-surface)),
        color-mix(in oklab, var(--k-brand) 22%, var(--k-surface))
    );
    --k-brand-line: light-dark(
        color-mix(in oklab, var(--k-brand) 40%, var(--k-line)),
        color-mix(in oklab, var(--k-brand) 45%, var(--k-line))
    );
    --k-on-brand-deep: #f6ead7;

    --k-accent-ink: #ffffff;
    --k-accent-strong: light-dark(
        color-mix(in oklab, var(--k-accent) 84%, #2b1c0c),
        color-mix(in oklab, var(--k-accent) 72%, #ffffff)
    );
    --k-accent-soft: light-dark(
        color-mix(in oklab, var(--k-accent) 11%, var(--k-surface)),
        color-mix(in oklab, var(--k-accent) 18%, var(--k-surface))
    );
    --k-accent-line: light-dark(
        color-mix(in oklab, var(--k-accent) 40%, var(--k-line)),
        color-mix(in oklab, var(--k-accent) 45%, var(--k-line))
    );
    --k-focus: color-mix(in oklab, var(--k-brand) 50%, transparent);

    /* The footer is the one region painted in the ink: koa with a board-
       coloured rule across the top, sand text. */
    --k-footer-bg: light-dark(#2b1c0c, #100b07);
    --k-footer-ink: #e8decf;
    --k-footer-muted: #9a8670;
    --k-footer-line: rgb(246 234 215 / .14);

    --k-ok: light-dark(#2e7d4f, #6fc893);
    --k-warn: light-dark(#99610f, #e3ae52);
    --k-danger: light-dark(#b4382c, #f18d80);

    /* Shadows carry the hue of the ground they fall on, never plain black. */
    --k-shadow-rgb: light-dark(62 44 22, 0 0 0);
    --k-shadow: 0 1px 2px rgb(var(--k-shadow-rgb) / .06), 0 10px 30px -14px rgb(var(--k-shadow-rgb) / .22);
    --k-shadow-lift: 0 2px 6px rgb(var(--k-shadow-rgb) / .08), 0 24px 48px -20px rgb(var(--k-shadow-rgb) / .35);
}

/* Browsers without light-dark() would otherwise lose every colour above.
   They get the light palette and no dark mode, which is a graceful place to
   land. */
@supports not (color: light-dark(#000, #fff)) {
    :root {
        --k-bg: #fcf6ea;
        --k-bg-alt: #f6ead7;
        --k-surface: #fffcf4;
        --k-surface-sunk: #f3e6d0;
        --k-ink: #2b1c0c;
        --k-ink-soft: #5c4a38;
        --k-muted: #8a7660;
        --k-line: #e4d5bc;
        --k-line-strong: #c9b9a4;
        --k-brand-strong: color-mix(in oklab, var(--k-brand) 82%, #2b1c0c);
        --k-brand-soft: color-mix(in oklab, var(--k-brand) 14%, #fffcf4);
        --k-brand-line: color-mix(in oklab, var(--k-brand) 40%, #e4d5bc);
        --k-accent-strong: color-mix(in oklab, var(--k-accent) 84%, #2b1c0c);
        --k-accent-soft: color-mix(in oklab, var(--k-accent) 11%, #fffcf4);
        --k-accent-line: color-mix(in oklab, var(--k-accent) 40%, #e4d5bc);
        --k-footer-bg: #2b1c0c;
        --k-ok: #2e7d4f;
        --k-warn: #99610f;
        --k-danger: #b4382c;
        --k-shadow-rgb: 62 44 22;
    }
}

/* Scale, rhythm and the few numbers the layout is built from. */
:root {
    --k-step--1: .875rem;
    --k-step-0: 1rem;
    --k-step-1: 1.125rem;
    --k-step-2: clamp(1.45rem, 1.15rem + 1.2vw, 1.95rem);
    --k-step-3: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
    --k-step-4: clamp(2.7rem, 1.5rem + 4.8vw, 5rem);

    --k-gap: 1.75rem;
    --k-gutter: clamp(1rem, 4vw, 2.5rem);
    --k-container: 80rem;
    --k-auth-width: 26rem;   /* the sign-in card, and the flash region above it */
    --k-grid-max: 3;
    --k-header-h: 4.25rem;

    --k-ease: cubic-bezier(.2, .7, .2, 1);
    --k-dur: 180ms;

    --k-z-header: 30;
    --k-z-menu: 40;
    --k-z-grain: 60;
    --k-z-skip: 100;
}

/* Kept for sites whose custom.css keys off the body class the font option
   used to set; the font stacks above already fall back on their own. */
body.has-display-font { --k-font-display: "Bricolage Grotesque", "Avenir Next", "Helvetica Neue", Arial, sans-serif; }

/* ----------------------------------------------------------------- 2. texture */

/*
 * A film of grain over the whole page. It is what stops a flat sand colour
 * from reading as a flat sand colour. Fixed, blended, and inert to the
 * pointer; remove it with `body::before { content: none }` in custom.css.
 */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: var(--k-z-grain);
    pointer-events: none;
    opacity: .055;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 180px 180px;
}

/* ------------------------------------------------- KahunaCart integration */

/*
 * The entire hand-off between this theme and the KahunaCart storefront.
 *
 * The plugin's own stylesheet (assets/kahunacart.css) owns the appearance of
 * every kahunacart-* class in its templates and partials. It resolves each of
 * its internal --kc-* values through the chain
 *
 *     --kahunacart-*  (site or theme override — what this block writes)
 *       -> --grav-*   (a theme's design-token system)
 *       -> --theme-accent (generic hook any theme can publish)
 *       -> neutral fallback that follows the page's own palette
 *
 * so a theme claims the storefront by naming tokens, never by out-specifying
 * the plugin's selectors. Nothing in this block is a rule against plugin
 * markup, and the general answer to "the storefront looks wrong" is a token
 * here or a change in the plugin's CSS — not a selector.
 *
 * These map to Kahuna's own --k-* tokens, which already carry both sides of
 * the palette — so light and dark are both covered by defining the hand-off
 * exactly once.
 */
:root {
    --kahunacart-fg: var(--k-ink);
    --kahunacart-bg: var(--k-bg);
    --kahunacart-muted: var(--k-muted);
    --kahunacart-subtle: var(--k-muted);
    --kahunacart-border: var(--k-line);
    --kahunacart-border-strong: var(--k-line-strong);

    /* Split by job, the way the plugin uses them: --accent is ink and
       borders, --accent-strong is the only one that ever fills a box. */
    --kahunacart-accent: var(--k-brand-strong);
    --kahunacart-accent-strong: var(--k-accent);
    --kahunacart-accent-ink: var(--k-accent-strong);
    --kahunacart-on-accent-strong: var(--k-accent-ink);

    --kahunacart-surface: var(--k-surface);
    --kahunacart-surface-2: var(--k-surface-sunk);
    --kahunacart-surface-sunk: var(--k-surface-sunk);
    --kahunacart-card: var(--k-surface);
    --kahunacart-input: var(--k-surface);

    --kahunacart-radius: var(--k-radius-sm);
    --kahunacart-radius-lg: var(--k-radius);
    --kahunacart-font-mono: var(--k-font-mono);

    --kahunacart-success: var(--k-ok);
    --kahunacart-warning: var(--k-warn);
    --kahunacart-danger: var(--k-danger);

    --kahunacart-ease: var(--k-ease);
    --kahunacart-duration: var(--k-dur);

    /* --- generic tokens, for anything else that reads them ---------------- */
    --theme-accent: var(--k-brand);

    --grav-bg: var(--k-bg);
    --grav-bg-subtle: var(--k-surface-sunk);
    --grav-bg-elevated: var(--k-surface);
    --grav-fg: var(--k-ink);
    --grav-fg-muted: var(--k-muted);
    --grav-fg-subtle: var(--k-muted);
    --grav-border: var(--k-line);
    --grav-border-strong: var(--k-line-strong);
    --grav-radius-md: var(--k-radius-sm);
    --grav-radius-lg: var(--k-radius);
    --grav-font-display: var(--k-font-display);
    --grav-font-mono: var(--k-font-mono);
    --grav-success: var(--k-ok);
    --grav-warning: var(--k-warn);
    --grav-danger: var(--k-danger);
    --grav-header-height: var(--k-header-h);
    --grav-ease: var(--k-ease);
    --grav-duration-2: var(--k-dur);
}

/* --------------------------------------------------------- 3. reset and base */

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

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--k-header-h) + 1rem);
}

body {
    margin: 0;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--k-bg);
    color: var(--k-ink);
    font-family: var(--k-font);
    font-size: var(--k-step-0);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

a {
    color: var(--k-brand-strong);
    text-decoration-thickness: 1px;
    text-underline-offset: .2em;
    text-decoration-color: var(--k-brand-line);
    transition: color var(--k-dur) var(--k-ease), text-decoration-color var(--k-dur) var(--k-ease);
}

a:hover { color: var(--k-ink); text-decoration-color: currentColor; }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 3px solid var(--k-focus);
    outline-offset: 2px;
    border-radius: var(--k-radius-sm);
}

::selection { background: var(--k-brand); color: var(--k-on-brand-deep); }

hr {
    border: 0;
    border-top: 1px solid var(--k-line);
    margin: 2.5rem 0;
}

code, kbd, samp, pre { font-family: var(--k-font-mono); font-size: .9em; }

code {
    background: var(--k-surface-sunk);
    border: 1px solid var(--k-line);
    border-radius: 5px;
    padding: .1em .35em;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

/* ------------------------------------------------------------ 4. typography */

h1, h2, h3, h4, h5, h6 {
    font-family: var(--k-font-display);
    font-weight: 700;
    font-optical-sizing: auto;
    line-height: 1.1;
    letter-spacing: -.02em;
    margin: 0 0 .5em;
    text-wrap: balance;
}

h1, .k-page-title { font-size: var(--k-step-3); font-weight: 800; letter-spacing: -.03em; line-height: 1.02; }
h2 { font-size: var(--k-step-2); }
h3 { font-size: var(--k-step-1); font-family: var(--k-font); font-weight: 600; letter-spacing: -.01em; }
h4, h5, h6 { font-family: var(--k-font); font-size: var(--k-step-0); font-weight: 600; }

p, ul, ol, dl, table, figure, blockquote { margin: 0 0 1.1rem; }

/* Labels: the small-caps voice the theme uses for anything that names a
   region rather than reads as a sentence. One place to change it. */
.k-label-caps, .k-panel-title, .k-section-eyebrow {
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.k-page-lede {
    font-size: var(--k-step-1);
    color: var(--k-ink-soft);
    max-width: 48ch;
    text-wrap: pretty;
}

.k-prose { max-width: 66ch; text-wrap: pretty; }
.k-prose > :last-child { margin-bottom: 0; }
.k-prose h2 { margin-top: 2em; }
.k-prose h3 { margin-top: 1.6em; }
.k-prose li + li { margin-top: .25em; }

.k-prose blockquote {
    border-left: 3px solid var(--k-brand);
    padding-left: 1.25rem;
    margin-left: 0;
    color: var(--k-ink-soft);
    font-size: 1.08em;
}

.k-prose pre {
    background: var(--k-surface-sunk);
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius-sm);
    padding: 1rem;
    overflow-x: auto;
}

.k-prose pre code { background: none; border: 0; padding: 0; }

.k-prose ul, .k-prose ol { padding-inline-start: 1.4rem; }
.k-prose li::marker { color: var(--k-muted); }
.k-prose h2, .k-prose h3, .k-prose h4 { text-wrap: balance; }
.k-prose strong { color: var(--k-ink); font-weight: 600; }
.k-prose hr { margin-block: 2rem; }

/* Markdown tables. `.k-table` is the class the theme's own templates put on a
   cart or an order table; a table written in a page has no class to give it,
   so the same treatment is written against the element inside prose. */
.k-prose table {
    width: 100%;
    border-collapse: collapse;
    border-top: 1px solid var(--k-line);
    font-size: .95rem;
}

.k-prose :is(th, td) {
    padding: .7rem .9rem;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--k-line);
    overflow-wrap: anywhere;
}

.k-prose :is(th, td):first-child { padding-inline-start: 0; }
.k-prose :is(th, td):last-child { padding-inline-end: 0; }

.k-prose thead th {
    padding-block: .55rem;
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.k-prose tbody tr:hover { background: var(--k-surface); }

.k-num, .k-price, .k-tabular { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- 5. layout */

.k-container {
    width: 100%;
    max-width: var(--k-container);
    margin-inline: auto;
    padding-inline: var(--k-gutter);
}

.k-main {
    flex: 1 0 auto;
    padding-block: clamp(1.75rem, 5vw, 3.5rem) clamp(2.5rem, 6vw, 4.5rem);
}

/* The home page opens with its own hero and needs no top padding of its own. */
body.tmpl-home .k-main { padding-top: 0; }

.k-modular > * + * { margin-top: clamp(2rem, 6vw, 4rem); }

/*
 * An ordinary page — the `default` template, which is what a hand-written
 * markdown page gets.
 *
 * The storefront templates fill the container because they are grids of
 * things. A page of prose is not, and a 68ch measure pinned to the left edge
 * of an 80rem container is a narrow column of text with half a screen of
 * nothing beside it. So the article is centred in the container and the
 * measure stays a measure: nobody wants an 80rem line of text either.
 *
 * The two things in a markdown page that genuinely want more room than a
 * sentence does — a table and a code block — lean out past the measure by
 * `--k-measure-bleed`, which is zero until the viewport is wide enough that
 * leaning out cannot push them off the screen. Everything else stays on the
 * measure, so the left edge of the article is one straight line all the way
 * down.
 *
 * The marketing `home` template is not this; it has its own full-width layout
 * in section 19 and never carries `.k-page`.
 */
.k-page {
    --k-measure: 68ch;
    --k-measure-bleed: 0rem;
    max-width: var(--k-measure);
    margin-inline: auto;
}

/* The measure is the article's now, so the wrapper stops setting a second,
   narrower one of its own. */
.k-page > .k-prose { max-width: none; }

.k-page > .k-prose > :is(table, pre, figure, .k-wide) {
    width: calc(100% + 2 * var(--k-measure-bleed));
    margin-inline: calc(-1 * var(--k-measure-bleed));
}

@media (min-width: 64rem) {
    .k-page { --k-measure-bleed: 5rem; }
}

.k-page-hero { margin-bottom: clamp(1.5rem, 4vw, 2.5rem); }

/* A section heading with an action on the right: "Featured — View all". */
.k-section-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem 2rem;
    margin-bottom: 1.5rem;
}

.k-section-head h2 { margin: 0; }
.k-section-eyebrow { display: block; margin-bottom: .5rem; }

.k-link-arrow {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-weight: 500;
    text-decoration: none;
    color: var(--k-ink-soft);
    white-space: nowrap;
}

.k-link-arrow::after {
    content: "\2192";
    transition: transform var(--k-dur) var(--k-ease);
}

.k-link-arrow:hover { color: var(--k-brand-strong); }
.k-link-arrow:hover::after { transform: translateX(3px); }

.k-back {
    margin-top: 1.5rem;
    font-size: .93rem;
}

.k-back a { text-decoration: none; color: var(--k-muted); }
.k-back a:hover { color: var(--k-brand-strong); text-decoration: underline; }

.k-empty {
    color: var(--k-muted);
    font-size: var(--k-step-1);
}

.k-empty-state {
    background: var(--k-surface);
    border: 1px dashed var(--k-line-strong);
    border-radius: var(--k-radius);
    padding: clamp(2rem, 6vw, 4rem);
    text-align: center;
}

.k-empty-state > :last-child { margin-bottom: 0; }

/*
 * Spacing wrappers around the plugin's own partials. These exist so the theme
 * can place the storefront's blocks in its layout without writing a single
 * rule against a kahunacart-* class — the wrapper is theme markup, what is
 * inside it belongs to the plugin's stylesheet.
 */
.k-messages:not(:empty) { margin-bottom: 1.75rem; }
.k-totals { margin-top: 1rem; }
.k-coupon { margin-top: .5rem; }

/*
 * The cart's estimate box. It is a panel's worth of content that htmx replaces
 * whole, so everything it needs is inside `#kahunacart-estimate` and the panel
 * around it is the part that survives a swap. Same loading state as the search
 * grid, for the same reason: a spinner over a block about to be replaced by a
 * nearly identical block is movement rather than information.
 */
.k-estimate { transition: opacity var(--k-dur) var(--k-ease); }
.k-estimate.htmx-request { opacity: .5; }

.k-estimate .k-panel-title { margin-bottom: .85rem; }

.k-estimate-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
    gap: .75rem .85rem;
    margin-bottom: .9rem;
}

.k-estimate-form .button { width: 100%; }

.k-estimate-lines {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: .45rem 1rem;
    margin: 1.1rem 0 0;
    padding-top: .9rem;
    border-top: 1px solid var(--k-line-strong);
    font-size: .93rem;
}

.k-estimate-lines dt { margin: 0; color: var(--k-ink-soft); }
.k-estimate-lines dd { margin: 0; text-align: right; white-space: nowrap; }
.k-estimate-lines dd.k-estimate-quiet { color: var(--k-muted); white-space: normal; }

.k-estimate-total-label, .k-estimate-lines .k-estimate-total {
    font-weight: 600;
    color: var(--k-ink);
    padding-top: .45rem;
    border-top: 1px solid var(--k-line);
}

.k-estimate-note {
    margin: .8rem 0 0;
    font-size: .82rem;
    line-height: 1.5;
    color: var(--k-muted);
}

/* The coupon form ships in a dashed box of its own; inside a Kahuna panel
   that is a box in a box, so the wrapper takes the box away. */
.k-coupon .kahunacart-coupon { border: 0; padding: 0; margin: 0; }

/* -------------------------------------------------------- 6. header and nav */

.k-skip-link {
    position: absolute;
    left: .75rem;
    top: -4rem;
    z-index: var(--k-z-skip);
    background: var(--k-ink);
    color: var(--k-bg);
    padding: .6rem 1rem;
    border-radius: var(--k-radius-sm);
    text-decoration: none;
    transition: top .15s ease;
}

.k-skip-link:focus { top: .75rem; color: var(--k-bg); }

/* The announcement bar: one line above the header, off until the option is
   filled in. Tinted with the accent rather than painted a different colour
   so it reads as part of the page, not a banner dropped on it. */
.k-announce {
    background: var(--k-brand-deep);
    color: var(--k-on-brand-deep);
    font-size: .88rem;
    font-weight: 500;
    text-align: center;
    padding: .5rem var(--k-gutter);
    text-wrap: balance;
}

.k-announce p { margin: 0; }
.k-announce a { color: inherit; text-decoration-color: currentColor; }
.k-announce strong { color: #fff; }

.k-header {
    position: relative;
    z-index: var(--k-z-header);
    background: color-mix(in srgb, var(--k-bg) 82%, transparent);
    backdrop-filter: saturate(140%) blur(14px);
    -webkit-backdrop-filter: saturate(140%) blur(14px);
    border-bottom: 1px solid var(--k-line);
}

body.has-sticky-header .k-header {
    position: sticky;
    top: 0;
}

/* Brand on the left, the page links in the middle, the store controls on the
   right. The outer columns share the leftover space so the middle stays on
   the centre line whatever the brand and the controls weigh. */
.k-header-inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    min-height: var(--k-header-h);
}

.k-brand {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: .7rem;
    font-family: var(--k-font-display);
    font-weight: 800;
    font-size: 1.5rem;
    letter-spacing: -.02em;
    color: var(--k-ink);
    text-decoration: none;
}

.k-brand:hover { color: var(--k-ink); }

/* The second word of a two-word store name takes the action colour:
   Kahuna<em>Cart</em>. A one-word name has no <em> and is simply the ink. */
.k-brand-name em { font-style: normal; color: var(--k-accent); }

/* The default mark is KahunaCart's microbus, shipped with the theme. A logo
   uploaded in the theme options replaces the whole lockup. */
.k-brand-mark {
    width: 3rem;
    height: 3rem;
    flex: none;
}

.k-brand-logo { height: 2.5rem; width: auto; }

.k-footer .k-brand { color: var(--k-footer-ink); font-size: 1.35rem; }
.k-footer .k-brand-mark { width: 2.5rem; height: 2.5rem; }

.k-nav-list {
    display: flex;
    align-items: center;
    gap: .25rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.k-nav-link {
    display: inline-block;
    padding: .45rem .8rem;
    border-radius: var(--k-radius-btn);
    color: var(--k-ink);
    font-weight: 600;
    font-size: .95rem;
    text-decoration: none;
    transition: background-color var(--k-dur) var(--k-ease), color var(--k-dur) var(--k-ease);
}

.k-nav-link:hover { background: var(--k-bg-alt); color: var(--k-ink); }

.k-nav-link.is-active {
    color: var(--k-brand-strong);
    background: var(--k-brand-soft);
}

.k-actions {
    justify-self: end;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.k-cart-link {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .95rem .5rem .8rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-btn);
    color: var(--k-ink);
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color var(--k-dur) var(--k-ease), background-color var(--k-dur) var(--k-ease);
}

.k-cart-link:hover {
    border-color: var(--k-ink);
    background: var(--k-surface);
    color: var(--k-ink);
}

.k-cart-link.has-items { border-color: var(--k-accent-line); }

.k-cart-icon { width: 1.15rem; height: 1.15rem; flex: none; }

.k-cart-badge {
    min-width: 1.4rem;
    padding: 0 .35rem;
    border-radius: var(--k-radius-btn);
    background: var(--k-bg-alt);
    color: var(--k-muted);
    font-family: var(--k-font-mono);
    font-size: .74rem;
    font-weight: 600;
    line-height: 1.4rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.k-cart-link.has-items .k-cart-badge {
    background: var(--k-accent);
    color: var(--k-accent-ink);
}

.k-signin {
    padding: .5rem .8rem;
    border-radius: var(--k-radius-btn);
    color: var(--k-ink-soft);
    text-decoration: none;
    font-weight: 500;
    white-space: nowrap;
}

.k-signin:hover { background: var(--k-bg-alt); color: var(--k-ink); }

/*
 * The light / dark / auto control.
 *
 * Which of the three icons and which of the three state names are visible is
 * decided entirely here, from `data-scheme-pref` on <html> — written by the
 * inline script in the head before the first paint. No JavaScript writes into
 * the button, so the control never shows one state for a frame and another
 * afterwards.
 *
 * A page with nothing stored carries no attribute at all, so every `auto` rule
 * is paired with a `:not([data-scheme-pref])` twin. That is also what a
 * JavaScript-free browser lands on, which is the honest answer for it: the
 * system preference is what it is following.
 */
.k-scheme {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-btn);
    background: transparent;
    color: var(--k-ink-soft);
    font: inherit;
    cursor: pointer;
    transition: border-color var(--k-dur) var(--k-ease),
                background-color var(--k-dur) var(--k-ease),
                color var(--k-dur) var(--k-ease);
}

.k-scheme:hover {
    border-color: var(--k-ink);
    background: var(--k-surface);
    color: var(--k-ink);
}

.k-scheme--control {
    width: 2.6rem;
    height: 2.6rem;
    padding: 0;
    justify-content: center;
}

.k-scheme-icons { display: inline-flex; }
.k-scheme-icon { display: none; width: 1.2rem; height: 1.2rem; flex: none; }

:root:not([data-scheme-pref]) .k-scheme-icon--auto,
:root[data-scheme-pref="auto"] .k-scheme-icon--auto,
:root[data-scheme-pref="light"] .k-scheme-icon--light,
:root[data-scheme-pref="dark"] .k-scheme-icon--dark { display: block; }

.k-scheme-state > span { display: none; }

:root:not([data-scheme-pref]) .k-scheme-state--auto,
:root[data-scheme-pref="auto"] .k-scheme-state--auto,
:root[data-scheme-pref="light"] .k-scheme-state--light,
:root[data-scheme-pref="dark"] .k-scheme-state--dark { display: inline; }

/* The icon variant says everything with the icon, so the two words go
   off-screen rather than away — they are the button's whole accessible name
   once the icon is aria-hidden. */
.k-scheme--control .k-scheme-title,
.k-scheme--control .k-scheme-state {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* The panel copy: a labelled row in the mobile menu, matching the nav links
   it sits under. Hidden until that menu is the one in use. */
.k-scheme--panel {
    display: none;
    width: 100%;
    margin-top: .5rem;
    padding: .7rem .9rem;
    border: 0;
    border-radius: var(--k-radius-sm);
    color: var(--k-ink);
    font-size: 1.05rem;
    font-weight: 600;
    text-align: left;
}

.k-scheme--panel:hover { background: var(--k-bg-alt); }
.k-scheme--panel .k-scheme-state { margin-left: auto; color: var(--k-muted); font-weight: 500; font-size: .95rem; }

.k-nav-toggle {
    display: none;
    width: 2.6rem;
    height: 2.6rem;
    padding: 0;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-btn);
    background: transparent;
    color: var(--k-ink);
    cursor: pointer;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
}

.k-nav-toggle-bar {
    display: block;
    width: 1.05rem;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: transform .18s ease, opacity .18s ease;
}

@media (max-width: 51.99rem) {
    .k-header-inner {
        grid-template-columns: 1fr auto;
        padding-block: .4rem;
    }

    .k-nav-toggle { display: flex; }

    /* Wordless on a phone; the icon and the badge carry it. */
    .k-cart-label { display: none; }
    .k-cart-link { padding-inline: .7rem; }

    /* The panel opens under the whole header row; `order` keeps the controls
       in the top row rather than letting the panel push them down. */
    .k-nav {
        display: none;
        order: 10;
        grid-column: 1 / -1;
        padding-block: .75rem 1.25rem;
        border-top: 1px solid var(--k-line);
    }

    body.k-nav-open .k-nav { display: block; }

    body.k-nav-open .k-nav-toggle-bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
    body.k-nav-open .k-nav-toggle-bar:nth-child(2) { opacity: 0; }
    body.k-nav-open .k-nav-toggle-bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

    .k-nav-list { flex-direction: column; align-items: stretch; gap: .1rem; }
    .k-nav-link { padding: .7rem .9rem; font-size: 1.05rem; border-radius: var(--k-radius-sm); }
    .k-nav-link.is-active { box-shadow: inset 3px 0 0 var(--k-brand); background: var(--k-brand-soft); }

    .k-nav .k-signin { display: block; margin-top: .5rem; padding: .7rem .9rem; }
    .k-actions .k-signin { display: none; }

    /* The scheme control moves into the panel with the sign-in link, for the
       same reason: the controls row on a phone is already carrying the cart
       and the menu button. */
    .k-nav .k-scheme--panel { display: flex; }
    .k-actions .k-scheme--control { display: none; }
}

@media (min-width: 52rem) {
    .k-nav .k-signin { display: none; }
}

/* ---------------------------------------------------------------- 7. footer */

.k-footer {
    margin-top: clamp(3rem, 10vw, 6rem);
    border-top: 5px solid var(--k-accent);
    background: var(--k-footer-bg);
    color: var(--k-footer-ink);
    font-size: .93rem;
}

.k-footer-grid {
    display: grid;
    gap: 2.25rem 3rem;
    padding-block: clamp(2.5rem, 6vw, 4rem) clamp(2rem, 5vw, 3rem);
}

@media (min-width: 52rem) {
    .k-footer-grid { grid-template-columns: minmax(0, 1.6fr) repeat(auto-fit, minmax(9rem, 1fr)); }
}

.k-footer-brand { max-width: 36ch; }
.k-footer-brand .k-brand { margin-bottom: .9rem; }
.k-footer-tagline { color: var(--k-footer-muted); margin: 0 0 1rem; text-wrap: pretty; }
.k-footer a { color: var(--k-footer-ink); text-decoration-color: var(--k-footer-line); }
.k-footer a:hover { color: #fff; text-decoration-color: currentColor; }
.k-footer-text > :last-child { margin-bottom: 0; }

.k-footer-group h2 {
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-footer-muted);
    margin: 0 0 .9rem;
}

.k-footer-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.k-footer-group a { color: var(--k-footer-ink); text-decoration: none; }
.k-footer-group a:hover { color: #fff; text-decoration: underline; }

.k-footer-bottom {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.5rem;
    align-items: baseline;
    justify-content: space-between;
    padding-block: 1.25rem 1.75rem;
    border-top: 1px solid var(--k-footer-line);
    font-size: .85rem;
    color: var(--k-footer-muted);
}

.k-footer-bottom p { margin: 0; }
.k-footer-bottom a { color: inherit; text-decoration: none; }
.k-footer-bottom a:hover { color: #fff; text-decoration: underline; }
.k-footer-meta { display: flex; gap: .6rem; }

/* --------------------------------------------------------------- 8. buttons */

/*
 * `.button` is the class the plugin's partials and the Form plugin both emit,
 * so it is the one the theme styles. A bare <button type="submit"> with no
 * class gets the same treatment; one that carries its own class (the plugin's
 * link-style buttons, for instance) is left to its own stylesheet.
 */
.button,
button.button,
button[type="submit"]:not([class]) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    padding: .7rem 1.35rem;
    border: 1px solid var(--k-accent);
    border-radius: var(--k-radius-btn);
    background: var(--k-accent);
    color: var(--k-accent-ink);
    font: inherit;
    font-family: var(--k-font-display);
    font-weight: 700;
    font-size: .95rem;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--k-dur) var(--k-ease), background-color var(--k-dur) var(--k-ease),
                border-color var(--k-dur) var(--k-ease), box-shadow var(--k-dur) var(--k-ease);
}

.button:hover,
button.button:hover,
button[type="submit"]:not([class]):hover {
    background: var(--k-accent-strong);
    border-color: var(--k-accent-strong);
    color: var(--k-accent-ink);
    transform: translateY(-1px);
    box-shadow: var(--k-shadow);
}

.button:active,
button.button:active,
button[type="submit"]:not([class]):active {
    transform: translateY(0) scale(.985);
    box-shadow: none;
}

.button[disabled], .button.is-disabled, button[disabled] {
    opacity: .5;
    pointer-events: none;
}

.k-button--ghost,
button.k-button--ghost {
    background: transparent;
    border-color: var(--k-line-strong);
    color: var(--k-ink);
}

.k-button--ghost:hover,
button.k-button--ghost:hover {
    background: var(--k-surface);
    border-color: var(--k-ink);
    color: var(--k-ink);
    box-shadow: none;
}

.k-button--ink,
button.k-button--ink {
    background: var(--k-ink);
    border-color: var(--k-ink);
    color: var(--k-bg);
}

.k-button--ink:hover,
button.k-button--ink:hover {
    background: var(--k-ink-soft);
    border-color: var(--k-ink-soft);
    color: var(--k-bg);
}

.k-button--lg, button.k-button--lg { padding: .9rem 1.75rem; font-size: 1.02rem; }
.k-button--sm, button.k-button--sm { padding: .45rem .9rem; font-size: .85rem; }

.k-button--block,
button.k-button--block {
    width: 100%;
    margin-top: .5rem;
}

.k-remove {
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 50%;
    background: transparent;
    color: var(--k-muted);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    transition: color var(--k-dur) var(--k-ease), border-color var(--k-dur) var(--k-ease);
}

.k-remove:hover {
    border-color: var(--k-danger);
    color: var(--k-danger);
}

/* ----------------------------------------------------------------- 9. forms */

.k-input, .k-select,
input[type="text"], input[type="email"], input[type="number"],
input[type="tel"], input[type="url"], input[type="password"],
input[type="search"], textarea, select,
.kahuna-input, .kahuna-select {
    width: 100%;
    padding: .66rem .85rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    color: var(--k-ink);
    font: inherit;
    line-height: 1.4;
    transition: border-color var(--k-dur) var(--k-ease), box-shadow var(--k-dur) var(--k-ease);
}

textarea { resize: vertical; min-height: 5.5rem; }

input::placeholder, textarea::placeholder { color: var(--k-muted); opacity: .8; }

input:focus, textarea:focus, select:focus {
    border-color: var(--k-brand);
    outline: none;
    box-shadow: 0 0 0 3px var(--k-focus);
}

/* Sections of a form. Not boxes: a hairline above and a heading, so a long
   checkout reads as one document with parts rather than a stack of cards. */
/* `.kahuna` in front of each: the plugin boxes every fieldset under its
   `.kahunacart` wrapper at the same weight, and loads after this sheet. */
.kahuna .k-fieldset, .kahuna .kahuna-form fieldset {
    border: 0;
    border-top: 1px solid var(--k-line);
    border-radius: 0;
    background: none;
    padding: 1.5rem 0 0;
    margin: 0 0 2rem;
    min-width: 0;
}

.kahuna .k-legend, .kahuna .kahuna-form legend {
    float: left;            /* renders as an ordinary block instead of sitting in the border */
    width: 100%;
    margin: 0 0 1.1rem;
    padding: 0;
    font-family: var(--k-font-display);
    font-weight: 600;
    font-size: 1.35rem;
    letter-spacing: -.015em;
}

.kahuna .k-legend + *, .kahuna .kahuna-form legend + * { clear: both; }

.k-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: 1rem 1.25rem;
    clear: both;
}

.k-field, .kahuna-field { margin: 0; }
.k-field--wide { grid-column: 1 / -1; }

.k-label, .kahuna-label {
    display: block;
    margin-bottom: .35rem;
    font-size: .86rem;
    font-weight: 500;
    color: var(--k-ink-soft);
}

.k-checkbox {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    margin-top: 1rem;
    font-size: .95rem;
    cursor: pointer;
}

.k-checkbox input { width: auto; margin-top: .25rem; accent-color: var(--k-brand); }

.k-choice-list { display: grid; gap: .5rem; }

.k-choice {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .8rem 1rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    cursor: pointer;
    transition: border-color var(--k-dur) var(--k-ease), background-color var(--k-dur) var(--k-ease);
}

.k-choice:hover { border-color: var(--k-ink); }

.k-choice input { width: auto; margin: 0; accent-color: var(--k-brand); }
.k-choice:has(input:checked) { border-color: var(--k-brand); background: var(--k-brand-soft); }
.k-choice-label { flex: 1; }
.k-choice-price { font-family: var(--k-font-display); font-weight: 600; font-variant-numeric: tabular-nums; }

.k-hint {
    margin: .5rem 0 0;
    color: var(--k-muted);
    font-size: .9rem;
}

.k-hint--warn { color: var(--k-warn); }

.kahuna-form-errors, .form-errors {
    border-left: 3px solid var(--k-danger);
    background: color-mix(in srgb, var(--k-danger) 8%, var(--k-surface));
    color: var(--k-danger);
    padding: .6rem .9rem;
    border-radius: var(--k-radius-sm);
}

.kahuna-form-actions { margin-top: 1rem; display: flex; gap: .6rem; flex-wrap: wrap; }

/* ---------------------------------------------------------------- 10. tables */

.k-table {
    width: 100%;
    border-collapse: collapse;
    border-top: 1px solid var(--k-line);
}

.k-table th, .k-table td {
    padding: 1rem .75rem;
    text-align: left;
    border-bottom: 1px solid var(--k-line);
    vertical-align: middle;
}

.k-table th:first-child, .k-table td:first-child { padding-left: 0; }
.k-table th:last-child, .k-table td:last-child { padding-right: 0; }

.k-table thead th {
    padding-block: .6rem;
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.k-table .k-num { text-align: right; font-variant-numeric: tabular-nums; }

.k-qty-input { width: 4.5rem; margin-left: auto; text-align: center; }

.k-cart-item-title { font-weight: 600; display: block; }
.k-cart-item-sku { color: var(--k-muted); font-size: .78rem; font-family: var(--k-font-mono); }
.k-cart-line-total { font-family: var(--k-font-display); font-weight: 600; font-size: 1.05rem; }

/* A plugin's note about the line — a free trial, where the price above it is
   not what the card is charged today. A qualification of that price rather
   than a second thing to read, so it sits quiet and small beneath it. */
.k-cart-item-note,
.k-summary-item-note { display: block; margin-block-start: .2rem; color: var(--k-muted); font-size: .82rem; line-height: 1.35; }
.k-summary-item-note { flex-basis: 100%; }

/* Narrow screens: the row becomes a card and each cell labels itself. */
@media (max-width: 40rem) {
    .k-table, .k-table tbody, .k-table tr, .k-table td { display: block; width: 100%; }
    .k-table thead { display: none; }

    .k-table tr {
        border-bottom: 1px solid var(--k-line);
        padding: .6rem 0;
    }

    .k-table td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: 0;
        padding: .35rem 0;
        text-align: right;
    }

    .k-table td::before {
        content: attr(data-label);
        font-family: var(--k-font-mono);
        font-size: .7rem;
        font-weight: 500;
        letter-spacing: .12em;
        text-transform: uppercase;
        color: var(--k-muted);
        text-align: left;
    }

    .k-table td:not([data-label]) { justify-content: flex-end; }
    .k-qty-input { width: 4.5rem; }

    /* The product cell holds a title and a SKU; stacked under their label
       rather than fighting for one line. */
    .k-table td:first-child {
        flex-direction: column;
        align-items: flex-start;
        gap: .1rem;
        text-align: left;
    }
}

/* --------------------------------------------------- 11. callouts & notices */

.k-callout {
    border: 1px solid var(--k-brand-line);
    border-left-width: 3px;
    background: var(--k-brand-soft);
    border-radius: var(--k-radius-sm);
    padding: 1.1rem 1.25rem;
    margin-bottom: 1.5rem;
}

.k-callout > :last-child { margin-bottom: 0; }

.k-callout--warn {
    border-color: color-mix(in srgb, var(--k-warn) 45%, var(--k-line));
    background: color-mix(in srgb, var(--k-warn) 9%, var(--k-surface));
}

/*
 * Flash messages — "Login failed", "Your address was saved", every one-line
 * answer a plugin gives a form. Drawn by `partials/messages.html.twig` for
 * Grav and the Login plugin, and reused below for KahunaCart's own message
 * partial so a storefront never has two vocabularies for the same event.
 *
 * A callout is a box the page author put there; a notice is the site
 * answering, and it has one job — to be seen. Hence the filled mark, the
 * shadow and the ink-weight text, none of which the callout has.
 */
.k-notices { display: grid; gap: .75rem; margin-bottom: 1.75rem; }

.k-notice,
.kahuna .kahunacart-message {
    display: flex;
    align-items: flex-start;
    gap: .85rem;
    margin: 0;
    padding: .95rem 1.15rem;
    border: 1px solid var(--k-line-strong);
    border-inline-start: 4px solid var(--k-muted);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface);
    box-shadow: var(--k-shadow);
    color: var(--k-ink);
    font-weight: 500;
    text-wrap: pretty;
}

.k-notice-body > :first-child { margin-top: 0; }
.k-notice-body > :last-child { margin-bottom: 0; }
.k-notice a { color: var(--k-ink); text-decoration-color: currentColor; }

/* One character in a filled disc. Not an icon font and not an SVG per scope:
   the glyph is set from the scope class, so a new scope is one rule. */
.k-notice-mark {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    margin-top: .1rem;
    border-radius: 50%;
    background: var(--k-muted);
    color: var(--k-surface);
    font-family: var(--k-font-display);
    font-size: .95rem;
    font-weight: 800;
    line-height: 1.5rem;
    text-align: center;
}

.k-notice-mark::before { content: "i"; }

.k-notice--error,
.kahuna .kahunacart-message--error {
    border-inline-start-color: var(--k-danger);
    background: color-mix(in srgb, var(--k-danger) 12%, var(--k-surface));
    border-color: color-mix(in srgb, var(--k-danger) 35%, var(--k-line));
}

.k-notice--error .k-notice-mark { background: var(--k-danger); }
.k-notice--error .k-notice-mark::before { content: "!"; }

.k-notice--warning,
.kahuna .kahunacart-message--warning {
    border-inline-start-color: var(--k-warn);
    background: color-mix(in srgb, var(--k-warn) 12%, var(--k-surface));
    border-color: color-mix(in srgb, var(--k-warn) 35%, var(--k-line));
}

.k-notice--warning .k-notice-mark { background: var(--k-warn); }
.k-notice--warning .k-notice-mark::before { content: "!"; }

.k-notice--success,
.kahuna .kahunacart-message--success {
    border-inline-start-color: var(--k-ok);
    background: color-mix(in srgb, var(--k-ok) 12%, var(--k-surface));
    border-color: color-mix(in srgb, var(--k-ok) 35%, var(--k-line));
}

.k-notice--success .k-notice-mark { background: var(--k-ok); }
.k-notice--success .k-notice-mark::before { content: "\2713"; }

.k-notice--info,
.kahuna .kahunacart-message--info {
    border-inline-start-color: var(--k-brand);
    background: var(--k-brand-soft);
    border-color: var(--k-brand-line);
}

.k-notice--info .k-notice-mark { background: var(--k-brand); }

/* --------------------------------- 12. storefront: listing head, grid, cards */

/* The listing's masthead: title and count on the left, the search on the
   right, one hairline under both. */
.k-shop-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2.5rem;
    margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
    padding-bottom: 1.25rem;
    border-bottom: 1px solid var(--k-line);
}

.k-shop-head-text { min-width: 0; flex: 1 1 22rem; }
.k-shop-head .k-page-title { margin-bottom: .25rem; }
.k-shop-head .k-page-lede { margin: .5rem 0 0; }
.k-shop-head > :last-child { margin-bottom: 0; }

.k-shop-count {
    display: block;
    font-family: var(--k-font-mono);
    font-size: .75rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--k-muted);
    margin-top: .5rem;
}

/*
 * The search form. The theme overrides the plugin's partial to add the htmx
 * attributes that make typing live, but the appearance is still written
 * against the plugin's own class names — the third place the theme does that —
 * so a store that drops the form somewhere else gets the same control.
 *
 * `.k-search` is only the masthead's sizing wrapper; the form dresses itself.
 */
.k-search { flex: 0 1 24rem; min-width: min(100%, 16rem); }
.kahuna .kahunacart-search { display: flex; gap: .5rem; margin: 0 0 1.5rem; }
.k-search .kahunacart-search { margin-bottom: 0; }
.kahuna .kahunacart-search-field { flex: 1; margin: 0; }

.kahuna .kahunacart-search input[type="search"] {
    border-radius: var(--k-radius-btn);
    padding-inline: 1.1rem;
}

.kahuna .kahunacart-search .button {
    background: transparent;
    border-color: var(--k-line-strong);
    color: var(--k-ink);
}

.kahuna .kahunacart-search .button:hover { border-color: var(--k-ink); background: var(--k-surface); box-shadow: none; }

/*
 * The results region, on the listing and on the search page alike — the same
 * element either way, because the search route swaps one for the other.
 *
 * htmx puts `.htmx-request` on it for the length of a request. Fading it a
 * little is the whole loading state: a spinner over a grid that is about to be
 * replaced by a nearly identical grid is more movement than information, and
 * the request is usually over before the transition finishes.
 */
#kahunacart-search-results {
    transition: opacity var(--k-dur) var(--k-ease);
}

#kahunacart-search-results.htmx-request { opacity: .5; }

/* The line above the grid — the shop's product count, or what a search
   matched. Both say the same kind of thing in the same place, and after a
   live swap one has literally replaced the other, so they share a voice. */
.kahuna .kahunacart-search-summary {
    margin: 0 0 1.25rem;
    font-family: var(--k-font-mono);
    font-size: .75rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.kahuna .kahunacart-search-more {
    margin-top: 1.5rem;
    color: var(--k-muted);
    font-size: .93rem;
}

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

.k-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: clamp(1.25rem, 3vw, var(--k-gap)) var(--k-gap);
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
}

@media (min-width: 64rem) {
    .k-grid { grid-template-columns: repeat(var(--k-grid-max), minmax(0, 1fr)); }
}

/* cards ------------------------------------------------------------------- */

/*
 * No border, no shadow, no box. A product tile is the picture and two lines
 * of text under it; the grid gap does the separating and the hover lives in
 * the picture. Boxes are for things that need to be lifted off the page, and
 * a catalog is the page.
 */
.k-card,
.kahuna .k-card.kahunacart-product-card {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

.kahuna .k-card:hover { transform: none; box-shadow: none; }

.k-card.is-sold-out .k-product-image,
.k-card.is-sold-out .k-product-placeholder { filter: grayscale(.7); opacity: .7; }

.k-card-link {
    display: flex;
    flex-direction: column;
    gap: .8rem;
    flex: 1;
    color: inherit;
    text-decoration: none;
}

.k-card-link:hover { color: inherit; }

.k-card-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .15rem .9rem;
    align-items: baseline;
}

.k-card-title {
    grid-column: 1;
    margin: 0;
    font-family: var(--k-font);
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -.005em;
    line-height: 1.3;
    text-decoration: underline transparent;
    text-underline-offset: .2em;
    text-decoration-thickness: 1px;
    transition: text-decoration-color var(--k-dur) var(--k-ease);
}

.k-card-link:hover .k-card-title { text-decoration-color: var(--k-brand); }

.k-card-price,
.kahuna .k-card .k-card-price {
    grid-column: 2;
    margin: 0;
    font-family: var(--k-font-display);
    font-weight: 600;
    font-size: 1.08rem;
    color: var(--k-ink);
    white-space: nowrap;
}

.k-card-summary {
    grid-column: 1 / -1;
    margin: .1rem 0 0;
    color: var(--k-muted);
    font-size: .9rem;
    line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.k-card-stock { grid-column: 1 / -1; margin-top: .25rem; }

/* The lead tile of a grid that has one: twice the width, twice the height,
   and a picture that fills whatever the two rows beside it add up to. */
@media (min-width: 64rem) {
    .k-grid--lead > .k-card:first-child { grid-column: span 2; grid-row: span 2; }
    .k-grid--lead > .k-card:first-child .k-product-media--card { aspect-ratio: auto; flex: 1; min-height: 22rem; }
    .k-grid--lead > .k-card:first-child .k-card-title { font-size: 1.2rem; }
    .k-grid--lead > .k-card:first-child .k-card-price { font-size: 1.3rem; }
    .k-grid--lead > .k-card:first-child .k-product-monogram { font-size: clamp(3rem, 14cqi, 7rem); }
}

/* media ------------------------------------------------------------------- */

.k-product-media {
    position: relative;
    border-radius: var(--k-radius-sm);
    overflow: hidden;
    background: var(--k-surface-sunk);
    /* the monogram sizes itself off the tile, not the viewport */
    container-type: inline-size;
    isolation: isolate;
}

/* A card is always 4:3 whether it holds a photograph or a monogram, so a grid
   never reflows as the pictures land — the plugin crops its card derivatives
   to the same ratio, so nothing is lost to the crop. */
.k-product-media--card { aspect-ratio: 4 / 3; }
.k-product-media--detail { aspect-ratio: 1 / 1; border-radius: var(--k-radius); }

/* A real photograph on a product page keeps its own proportions; the width
   and height attributes on the <img> reserve the box just as well. */
.k-product-media--detail.k-product-media--photo { aspect-ratio: auto; }

.k-product-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .6s var(--k-ease);
}

.k-card-link:hover .k-product-media--card .k-product-image { transform: scale(1.04); }

.k-product-media--detail.k-product-media--photo .k-product-image {
    height: auto;
    object-fit: contain;
}

/* The stand-in for a product with no picture: a tonal tile in a hue picked
   from the product's id, kept to the sand family so a grid of them reads as
   one catalog rather than a paint chart, with a wave across the bottom. */
.k-product-placeholder {
    width: 100%;
    height: 100%;
    display: grid;
    place-items: center;
    background:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 20' preserveAspectRatio='none'%3E%3Cpath d='M0 10c15-8 30-8 45 0s30 8 45 0 30-8 45 0' fill='none' stroke='%23000' stroke-opacity='.12' stroke-width='1.5'/%3E%3C/svg%3E")
            bottom / 34% 10% repeat-x,
        linear-gradient(160deg,
            light-dark(hsl(var(--k-tile-hue, 30) 34% 88%), hsl(var(--k-tile-hue, 30) 14% 22%)),
            light-dark(hsl(calc(var(--k-tile-hue, 30) + 25) 28% 79%), hsl(calc(var(--k-tile-hue, 30) + 25) 10% 15%)));
}

.k-product-monogram {
    font-family: var(--k-font-display);
    font-size: clamp(2rem, 18cqi, 4.25rem);
    font-weight: 600;
    letter-spacing: -.03em;
    line-height: 1;
    color: light-dark(rgb(30 26 20 / .55), rgb(242 235 224 / .72));
    transform: translateY(-4%);
}

/* flags on a tile ---------------------------------------------------------- */

.k-badge {
    display: inline-block;
    padding: .22rem .55rem;
    border-radius: 4px;
    font-family: var(--k-font-mono);
    font-size: .66rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    line-height: 1.3;
    background: var(--k-bg-alt);
    color: var(--k-ink-soft);
}

.k-badges {
    position: absolute;
    top: .7rem;
    left: .7rem;
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    z-index: 1;
}

.k-badge--digital { background: var(--k-ink); color: var(--k-bg); }
.k-badge--sale { background: var(--k-accent); color: var(--k-accent-ink); }
.k-badge--sold-out { background: var(--k-surface); color: var(--k-ink); }

.k-badge--paid { background: color-mix(in srgb, var(--k-ok) 16%, transparent); color: var(--k-ok); }
.k-badge--pending { background: color-mix(in srgb, var(--k-warn) 16%, transparent); color: var(--k-warn); }
.k-badge--failed,
.k-badge--refunded,
.k-badge--partially_refunded { background: color-mix(in srgb, var(--k-danger) 14%, transparent); color: var(--k-danger); }

/* price and stock --------------------------------------------------------- */

.k-price {
    font-family: var(--k-font-display);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    margin: 0;
}

.k-price--lead { font-size: var(--k-step-2); color: var(--k-accent-strong); }

.k-price-was {
    margin-left: .4rem;
    color: var(--k-muted);
    font-weight: 400;
    font-size: .78em;
    white-space: nowrap;
}

/*
 * A price a campaign has reduced, on a tile, in the hero stack and up beside a
 * product title. See the plugin's docs/sales.md for what decides it.
 *
 * The number takes the store's action colour rather than the plugin's
 * --kc-danger. A Kahuna tile already carries a badge naming the campaign, and
 * two urgent-red elements on one line read as an error state rather than as an
 * offer. The struck figure keeps the muted treatment the compare-at price has
 * always had — whichever claim put it there, it is the number nobody is paying.
 *
 * The card and hero rules restate the selector because both set a colour and a
 * nowrap of their own; letting the pair wrap is what keeps a long reduced price
 * from pushing a narrow tile sideways.
 */
.k-price--sale,
.kahuna .k-card .k-card-price.k-price--sale { color: var(--k-accent-strong); }

.k-card-price.k-price--sale,
.k-hero-card-price.k-price--sale { white-space: normal; }

/* The campaign's name beside the lead price, in the same pill the tiles carry,
   so a shopper meets the same badge twice on the way to the button. */
.k-price-badge { margin-left: .55rem; vertical-align: .2em; }

.k-price-was[hidden],
.k-price-badge[hidden] { display: none; }

.k-stock {
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .02em;
}

.k-stock--in { color: var(--k-ok); }
.k-stock--low { color: var(--k-warn); }
.k-stock--out { color: var(--k-danger); }
.k-stock-line { margin: 0 0 1rem; min-height: 1.2rem; }

/* ------------------------------------------------------- 13. product detail */

.k-product-layout {
    display: grid;
    gap: clamp(1.5rem, 5vw, 4rem);
    align-items: start;
}

@media (min-width: 52rem) {
    .k-product-layout { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); }
    .k-product-figure { position: sticky; top: calc(var(--k-header-h) + 1.5rem); }
}

/* gallery ----------------------------------------------------------------- */

/*
 * The product gallery is one of the places this theme dresses markup it
 * shares with the plugin: the elements carry both class sets, kahunacart-
 * gallery-* so the plugin's shipped stylesheet still describes them on a
 * site that has turned this one off, and k-gallery-* for everything below.
 * Every selector here is a theme class under .k-product-figure, which also
 * puts it ahead of the plugin's single-class rules.
 *
 * No JavaScript is involved, and none should be: the pictures are a
 * scroll-snapping row and the thumbnails are ordinary in-page links to them,
 * so swapping the image works with a click, a swipe, a keyboard and with
 * scripting off.
 */
.k-product-figure .k-gallery {
    display: flex;
    flex-direction: column;
    gap: .75rem;
    margin: 0;
}

.k-product-figure .k-gallery-main {
    display: flex;
    gap: .75rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    border-radius: var(--k-radius);
}

.k-product-figure .k-gallery-main::-webkit-scrollbar { display: none; }

.k-product-figure .k-gallery-main:focus-visible {
    outline: 3px solid var(--k-focus);
    outline-offset: 3px;
}

.k-product-figure .k-gallery-slide {
    flex: 0 0 100%;
    margin: 0;
    scroll-snap-align: center;
}

.k-product-figure .k-gallery-slide img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--k-radius);
    background: var(--k-surface-sunk);
}

.k-product-figure .k-gallery-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.k-product-figure .k-gallery-thumbs a {
    display: block;
    overflow: hidden;
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius-sm);
    background: var(--k-surface-sunk);
    transition: border-color var(--k-dur) var(--k-ease);
}

.k-product-figure .k-gallery-thumbs a:hover,
.k-product-figure .k-gallery-thumbs a:focus-visible { border-color: var(--k-ink); }

.k-product-figure .k-gallery-thumbs img {
    display: block;
    width: 64px;
    height: 64px;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
    .k-product-figure .k-gallery-main { scroll-behavior: auto; }
}

/* the detail column ------------------------------------------------------- */

.k-product-title { margin-bottom: .6rem; }

.k-product-summary {
    color: var(--k-ink-soft);
    font-size: var(--k-step-1);
    text-wrap: pretty;
    max-width: 44ch;
}

.k-buy { margin-top: 1.25rem; }

/* The facts under the buy box: SKU, kind, anything else a template adds.
   A definition list laid out as rows with a label column. */
.k-facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: .35rem 1.25rem;
    margin: 1.5rem 0 0;
    padding-top: 1.25rem;
    border-top: 1px solid var(--k-line);
    font-size: .9rem;
}

.k-facts dt {
    font-family: var(--k-font-mono);
    font-size: .7rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
    padding-top: .2rem;
}

.k-facts dd { margin: 0; color: var(--k-ink-soft); }
.k-facts code { font-size: .82rem; }

.k-product-description {
    margin-top: clamp(2.5rem, 6vw, 4rem);
    padding-top: clamp(1.5rem, 4vw, 2.5rem);
    border-top: 1px solid var(--k-line);
    display: grid;
    gap: 1rem 3rem;
}

@media (min-width: 52rem) {
    .k-product-description { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); }
    .k-product-description > .k-prose { grid-column: 2; }
}

.k-product-description-head { margin: 0; }

/* ------------------ 14. catalog: sidebar, tree, filters, crumbs, tags */

/*
 * The catalog sidebar and the taxonomy blocks around it.
 *
 * This is the other large place the theme dresses markup it does not write.
 * The tree, the facet panel, the breadcrumb trail, the subcategory cards and
 * the tag list are all plugin partials, included whole and never forked — so
 * there is no element here the theme can hang a k-* class on, and the only
 * way to give them Kahuna's own furniture is to reach in.
 *
 * Every rule below is therefore scoped under a theme class the theme *does*
 * own: .k-catalog on the layout wrapper, .k-shop or .k-product on the page
 * section. Two classes beats the plugin's one whichever sheet loads last.
 *
 * What is NOT here is colour. The token hand-off at the top of this file
 * already resolves every --kc-* the plugin's stylesheet reads into a Kahuna
 * value. These rules take the plugin's panels *away* — the rail is a column
 * of typography with hairlines, not a stack of boxes beside a grid.
 */

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

.k-shop .k-catalog {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
}

@media (min-width: 52rem) {
    .k-shop .k-catalog { grid-template-columns: 15rem minmax(0, 1fr); }
    .k-catalog .kahunacart-catalog-nav { position: sticky; top: calc(var(--k-header-h) + 1.5rem); }
}

/* minmax(0, 1fr) above, and min-width: 0 here: both stop a wide product card
   from setting the column's floor and shoving the rail off the page. */
.k-shop .k-catalog-main { min-width: 0; }

/* The grid is living in a column, not in the container, so it auto-fills
   until the container is wide enough to give the column its own columns. */
.k-catalog-main .k-grid { grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }

@media (min-width: 78rem) {
    .k-catalog-main .k-grid { grid-template-columns: repeat(var(--k-grid-max), minmax(0, 1fr)); }
}

/* the rail ---------------------------------------------------------------- */

.k-catalog .kahunacart-catalog-nav {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    font-size: .93rem;
}

.k-catalog .kahunacart-cat-tree,
.k-catalog .kahunacart-filters {
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    padding: 0;
}

.k-catalog .kahunacart-filters {
    border-top: 1px solid var(--k-line);
    padding-top: 1.5rem;
}

.k-catalog .kahunacart-nav-title,
.k-catalog .kahunacart-filters legend:not(.kahunacart-visually-hidden) {
    font-family: var(--k-font-mono);
    font-size: .7rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
    margin: 0 0 .8rem;
    padding: 0;
}

/* the tree ---------------------------------------------------------------- */

/*
 * One column system, at every depth.
 *
 * The browser's own `<details>` marker is what the plugin uses, and in a rail
 * it does not line up with anything: it is laid out as a list marker outside
 * the summary's box, its width depends on the platform, and a leaf row — which
 * has no marker at all — starts somewhere else entirely. Three depths of that
 * and no two labels share a left edge.
 *
 * So the marker is taken away and every row is built the same way: a fixed
 * `--k-tree-slot` for the chevron, then the label. A leaf gets the slot
 * as empty space rather than as nothing, which is what makes "Tops" line up
 * with "Womens" whether or not either has children. The indent guide is drawn
 * down the centre of the parent's slot, so it points at the chevron it belongs
 * to, and stops half a row short of the bottom so it ends on the last child
 * rather than dangling past it.
 */
.k-catalog .kahunacart-cat-tree {
    --k-tree-slot: 1.35rem;   /* the chevron column, present on every row */
    --k-tree-indent: 1.15rem; /* how far one depth steps in */
    --k-tree-row: 1.9rem;     /* one row, for the guide's bottom stop */
    --k-tree-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 5 7 7-7 7'/%3E%3C/svg%3E");
}

.k-catalog .kahunacart-cat-list .kahunacart-cat-list {
    position: relative;
    margin: .1rem 0 .35rem calc(var(--k-tree-slot) / 2);
    padding-inline-start: calc(var(--k-tree-indent) - var(--k-tree-slot) / 2);
    border-inline-start: 0;
}

.k-catalog .kahunacart-cat-list .kahunacart-cat-list::before {
    content: "";
    position: absolute;
    inset-block: 0 calc(var(--k-tree-row) / 2);
    inset-inline-start: 0;
    width: 1px;
    background: var(--k-line);
}

.k-catalog .kahunacart-cat-item + .kahunacart-cat-item { margin-top: .1rem; }

/* A row with children. Flex rather than the list-item display the plugin
   sets, which is what puts the marker back outside the box. */
.k-catalog .kahunacart-cat-summary {
    display: flex;
    align-items: center;
    list-style: none;
    padding: 0;
}

.k-catalog .kahunacart-cat-summary::-webkit-details-marker { display: none; }

.k-catalog .kahunacart-cat-summary::before {
    content: "";
    flex: none;
    width: var(--k-tree-slot);
    height: var(--k-tree-row);
    background-color: var(--k-line-strong);
    -webkit-mask: var(--k-tree-chevron) no-repeat center / .55rem .55rem;
    mask: var(--k-tree-chevron) no-repeat center / .55rem .55rem;
    transition: transform var(--k-dur) var(--k-ease), background-color var(--k-dur) var(--k-ease);
}

.k-catalog .kahunacart-cat-branch[open] > .kahunacart-cat-summary::before { transform: rotate(90deg); }
.k-catalog .kahunacart-cat-summary:hover::before { background-color: var(--k-brand); }

/* The empty slot that keeps a leaf's label on the same line as its cousins'. */
.k-catalog .kahunacart-cat-item > .kahunacart-cat-link { margin-inline-start: var(--k-tree-slot); }

.k-catalog .kahunacart-cat-link {
    display: inline-block;
    min-width: 0;
    padding: .3rem .5rem;
    border-radius: var(--k-radius-sm);
    color: var(--k-ink-soft);
    line-height: 1.35;
    text-decoration: none;
    transition: background-color var(--k-dur) var(--k-ease), color var(--k-dur) var(--k-ease);
}

.k-catalog .kahunacart-cat-link:hover {
    background: var(--k-bg-alt);
    color: var(--k-ink);
    text-decoration: none;
}

.k-catalog .kahunacart-cat-link.is-current {
    background: var(--k-brand-soft);
    color: var(--k-brand-strong);
    font-weight: 600;
}

.k-catalog .kahunacart-cat-item.is-ancestor > .kahunacart-cat-branch > .kahunacart-cat-summary > .kahunacart-cat-link {
    color: var(--k-ink);
    font-weight: 600;
}

/* An open branch on the trail to the current category reads as part of the
   heading, so its chevron stops being furniture too. */
.k-catalog .kahunacart-cat-item.is-ancestor > .kahunacart-cat-branch > .kahunacart-cat-summary::before {
    background-color: var(--k-ink-soft);
}

.k-catalog .kahunacart-cat-count,
.k-catalog .kahunacart-filter-count {
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-variant-numeric: tabular-nums;
    color: var(--k-muted);
}

/* The link already carries .5rem of padding on that side; this is the gap
   between the two, not between the label and the count. */
.k-catalog .kahunacart-cat-count { margin-inline-start: .3rem; }

/* the facet panel --------------------------------------------------------- */

.k-catalog .kahunacart-filter-group {
    border: 0;
    border-top: 1px solid var(--k-line);
    border-radius: 0;
    margin: 0;
    padding: 1.1rem 0 0;
    min-width: 0;
}

/* A legend sits in its fieldset's border by default, which puts the hairline
   through the word. Floated, it is an ordinary block above the options. */
.k-catalog .kahunacart-filter-group > legend {
    float: left;
    width: 100%;
}

.k-catalog .kahunacart-filter-group > legend + * { clear: both; }

.k-catalog .kahunacart-filters > .kahunacart-filter-group:first-of-type {
    border-top: 0;
    padding-top: 0;
}

.k-catalog .kahunacart-filter-options {
    gap: .4rem;
    max-height: 17em;
    padding-inline-end: .2rem;
    scrollbar-width: thin;
}

.k-catalog .kahunacart-filter-option {
    color: var(--k-ink-soft);
    line-height: 1.35;
}

.k-catalog .kahunacart-filter-option:hover { color: var(--k-ink); }

.k-catalog .kahunacart-filter-option input {
    width: auto;
    flex: none;
    margin: 0;
    accent-color: var(--k-brand);
}

.k-catalog .kahunacart-filter-field input {
    padding: .45rem .55rem;
    text-align: center;
}

.k-catalog .kahunacart-filter-actions { padding-top: .5rem; }
.k-catalog .kahunacart-filter-actions .button { flex: 1 1 auto; justify-content: center; }

.k-catalog .kahunacart-filter-clear {
    color: var(--k-muted);
    font-size: .85rem;
    text-decoration: none;
}

.k-catalog .kahunacart-filter-clear:hover { color: var(--k-brand-strong); text-decoration: underline; }

/* The rest of a facet the `catalog.facets.max_values` cap has shortened: a
   <details> holding real checkboxes in the same form, so opening it costs no
   request and needs no script. Styled like the Clear link rather than like a
   button, because it reveals rather than does. */
.k-catalog .kahunacart-filter-more { margin-top: .4rem; }

.k-catalog .kahunacart-filter-more-toggle {
    color: var(--k-muted);
    font-size: .85rem;
    cursor: pointer;
}

.k-catalog .kahunacart-filter-more-toggle:hover { color: var(--k-brand-strong); }

.k-catalog .kahunacart-filter-more > .kahunacart-filter-options { margin-top: .4rem; }

/* A value nothing reachable answers. Counts follow the current filters, so a
   value that would give an empty grid reads 0 and its input is disabled;
   greying it in place rather than removing it keeps the panel from reshuffling
   under the cursor on every tick. `catalog.facets.empty: hide` drops them
   instead and nothing then reaches these rules. What the shopper has ticked is
   never disabled, at any count. */
.k-catalog .kahunacart-filter-option.is-disabled,
.k-catalog .kahunacart-filter-range.is-disabled {
    color: var(--k-muted);
    opacity: .5;
    cursor: not-allowed;
}

.k-catalog .kahunacart-filter-option.is-disabled:hover { color: var(--k-muted); }
.k-catalog .kahunacart-filter-option.is-disabled input { cursor: not-allowed; }

/* Under a facet whose every value is out of reach: the heading stays and says
   so once, instead of a column of a dozen dead boxes all reading 0. */
.k-catalog .kahunacart-filter-none {
    margin: 0;
    color: var(--k-muted);
    font-size: .85rem;
    font-style: italic;
}

/* A category holding nothing under the filters currently on. Still a link, so
   the tree stays the way out of a corner somebody has filtered themselves
   into; the row rather than the whole item, because a dead branch's children
   carry the class too and two opacities multiply. */
.k-catalog .kahunacart-cat-item.is-unavailable > .kahunacart-cat-link,
.k-catalog .kahunacart-cat-item.is-unavailable > .kahunacart-cat-count,
.k-catalog .kahunacart-cat-item.is-unavailable > .kahunacart-cat-branch > .kahunacart-cat-summary {
    opacity: .5;
}

/* A specification value that links to the rest of the catalogue answering it.
   Ink at rest with a dotted rule under it: a spec table where every second
   cell is brand-coloured reads as a list of links rather than a table of
   facts. */
.kahunacart-attribute-link {
    color: var(--k-ink);
    text-decoration: none;
    border-bottom: 1px dotted var(--k-line);
}

.kahunacart-attribute-link:hover,
.kahunacart-attribute-link:focus-visible {
    color: var(--k-brand-strong);
    border-bottom-color: currentColor;
}

.kahunacart-attribute-link .kahunacart-spec-hex { color: inherit; }

.k-listing-more {
    margin-top: 1.5rem;
    color: var(--k-muted);
    font-size: .9rem;
}

/* breadcrumbs ------------------------------------------------------------- */

.k-shop .kahunacart-breadcrumbs,
.k-product .kahunacart-breadcrumbs {
    margin-bottom: 1.25rem;
    font-size: .85rem;
}

.k-shop .kahunacart-breadcrumb-item a,
.k-product .kahunacart-breadcrumb-item a {
    color: var(--k-muted);
    text-decoration: none;
}

.k-shop .kahunacart-breadcrumb-item a:hover,
.k-product .kahunacart-breadcrumb-item a:hover {
    color: var(--k-brand-strong);
    text-decoration: underline;
}

/* the category banner ----------------------------------------------------- */

.k-category-media {
    margin: 1.25rem 0 1.5rem;
    border-radius: var(--k-radius);
    overflow: hidden;
    background: var(--k-surface-sunk);
}

.k-category-media img {
    display: block;
    width: 100%;
    height: auto;
    max-height: 22rem;
    object-fit: cover;
}

/* subcategory cards ------------------------------------------------------- */

/* A department card is a sunk tile with the name set large in the display
   face — it is a door, not a product, and should not look like one. */
.k-shop .kahunacart-subcategory-grid {
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: var(--k-gap);
    margin: 0 0 clamp(2rem, 5vw, 3rem);
}

.k-shop .kahunacart-subcategory-card {
    border: 0;
    border-radius: var(--k-radius-sm);
    background: var(--k-surface-sunk);
    box-shadow: none;
    overflow: hidden;
    transition: background-color var(--k-dur) var(--k-ease);
}

.k-shop .kahunacart-subcategory-card:hover { background: var(--k-brand-soft); }

.k-shop .kahunacart-subcategory-media {
    aspect-ratio: 16 / 9;
    background: var(--k-bg-alt);
}

.k-shop .kahunacart-subcategory-title {
    font-family: var(--k-font-display);
    font-size: 1.35rem;
    font-weight: 600;
    letter-spacing: -.02em;
    padding: 1.25rem 1.25rem .15rem;
}

.k-shop .kahunacart-subcategory-card:not(.has-image) .kahunacart-subcategory-title { padding-top: 2rem; }

.k-shop .kahunacart-subcategory-link:hover .kahunacart-subcategory-title { color: var(--k-brand-strong); }

.k-shop .kahunacart-subcategory-count {
    padding: 0 1.25rem 1.25rem;
    color: var(--k-muted);
    font-family: var(--k-font-mono);
    font-size: .75rem;
    letter-spacing: .06em;
    text-transform: uppercase;
}

/* tags -------------------------------------------------------------------- */

.k-product .kahunacart-tags {
    margin-top: clamp(2rem, 5vw, 3rem);
    padding-top: clamp(1.25rem, 3vw, 1.75rem);
    border-top: 1px solid var(--k-line);
}

.k-product .kahunacart-tags-title {
    font-family: var(--k-font-mono);
    font-size: .7rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
    margin: 0 0 .7rem;
}

.k-product .kahunacart-tag-list { gap: .45rem; }

.k-product .kahunacart-tag {
    padding: .28rem .8rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-btn);
    background: transparent;
    color: var(--k-ink-soft);
    font-size: .82rem;
    text-decoration: none;
    transition: border-color var(--k-dur) var(--k-ease), background-color var(--k-dur) var(--k-ease), color var(--k-dur) var(--k-ease);
}

.k-product .kahunacart-tag:hover {
    border-color: var(--k-brand);
    background: var(--k-brand-soft);
    color: var(--k-brand-strong);
    text-decoration: none;
}

/* narrow screens ---------------------------------------------------------- */

@media (max-width: 51.99rem) {
    .k-shop .k-catalog { gap: 1.5rem; }
    .k-catalog .kahunacart-catalog-nav { gap: 1.25rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--k-line); }
    .k-catalog .kahunacart-filter-options { max-height: 13em; }
    .k-catalog .kahunacart-filter-actions .button { width: 100%; }
}

/* ------------------------------------------------------------------ 15. cart */

.k-cart-layout {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
}

@media (min-width: 58rem) {
    .k-cart-layout { grid-template-columns: minmax(0, 1.9fr) minmax(18rem, 1fr); }
}

.k-cart-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    justify-content: flex-end;
    margin-top: 1.25rem;
}

.k-panel {
    border-radius: var(--k-radius);
    background: var(--k-surface-sunk);
    padding: 1.35rem 1.5rem 1.5rem;
}

.k-panel + .k-panel { margin-top: 1.25rem; }

.k-panel-title { margin: 0 0 1rem; }

@media (min-width: 58rem) {
    .k-panel--sticky { position: sticky; top: calc(var(--k-header-h) + 1.5rem); }
}

/* -------------------------------------------------------------- 16. checkout */

/* The plugin caps its checkout form at 42rem for the one-column layout it
   ships; this one is two columns and wants the container. */
.kahuna .k-checkout-layout {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3.5rem);
    align-items: start;
    max-width: none;
}

@media (min-width: 58rem) {
    .k-checkout-layout { grid-template-columns: minmax(0, 1.7fr) minmax(19rem, 1fr); }
}

/* Numbered steps. The counter is incremented by each fieldset and printed in
   front of its legend, so a section added to the form numbers itself. */
.k-checkout-main { counter-reset: k-step; }
.k-checkout-main .k-fieldset { counter-increment: k-step; }
.k-checkout-main .k-fieldset:first-child { border-top: 0; padding-top: 0; }

.k-checkout-main .k-legend::before {
    content: counter(k-step, decimal-leading-zero);
    display: inline-block;
    margin-right: .7rem;
    font-family: var(--k-font-mono);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .1em;
    color: var(--k-brand-strong);
    vertical-align: .35em;
}

.k-summary-items {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0 0 .9rem;
    border-bottom: 1px solid var(--k-line-strong);
    display: grid;
    gap: .55rem;
    font-size: .93rem;
}

.k-summary-item {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
}

.k-summary-qty { color: var(--k-muted); }
.k-summary-item-total { font-variant-numeric: tabular-nums; white-space: nowrap; }

.k-coupon-active {
    margin: 0 0 .75rem;
    font-size: .88rem;
    color: var(--k-ok);
    font-weight: 600;
}

/* --------------------------------------------------- 17. receipt & downloads */

.k-receipt {
    max-width: 46rem;
    margin-inline: auto;
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius);
    background: var(--k-surface);
    padding: clamp(1.5rem, 5vw, 3rem);
    box-shadow: var(--k-shadow);
}

.k-receipt-head { text-align: center; margin-bottom: 2rem; }

.k-receipt-check {
    width: 3.25rem;
    height: 3.25rem;
    margin: 0 auto 1rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--k-brand-soft);
    color: var(--k-brand-strong);
    font-size: 1.5rem;
    line-height: 1;
}

.k-receipt-meta {
    display: grid;
    gap: .4rem;
    justify-content: center;
    margin: 0;
    font-size: .95rem;
}

.k-meta-row {
    display: flex;
    gap: .6rem;
    align-items: baseline;
    justify-content: center;
}

.k-meta-row dt { color: var(--k-muted); }
.k-meta-row dd { margin: 0; }

/* The receipt's way out: invoice, orders, shop — spaced, centred. */
.k-order .kahunacart-order-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem 1.5rem;
    margin-top: 2rem;
}

.k-downloads { margin-top: 2rem; }

.k-download-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }

.k-download {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem 1rem;
    padding: .85rem 1rem;
    border-radius: var(--k-radius-sm);
    background: var(--k-surface-sunk);
}

.k-download-link { font-weight: 600; }
.k-download-meta { color: var(--k-muted); font-size: .85rem; }

/* ----------------------------------------------- 18. account area & login */

/*
 * The customer account pages are the plugin's own templates, extending this
 * theme's base and styled by the plugin's stylesheet through the token
 * hand-off. What the plugin draws is a row of tabs over a column of panels.
 * Kahuna wants a rail: the section links down the left, the page on the
 * right, the same arrangement the catalog uses. That is a layout change, not
 * a colour, so it is written here against the plugin's classes — scoped under
 * the body class the theme owns, which is what carries it past the plugin's
 * single-class rules.
 */
.kahuna .kahunacart-account > h1 { margin-bottom: 1.25rem; }

@media (min-width: 58rem) {
    .kahuna .kahunacart-account {
        display: grid;
        grid-template-columns: 13rem minmax(0, 1fr);
        column-gap: clamp(2rem, 5vw, 4rem);
        align-items: start;
    }

    .kahuna .kahunacart-account > h1,
    .kahuna .kahunacart-account > .kahunacart-messages { grid-column: 1 / -1; }

    .kahuna .kahunacart-account > .kahunacart-account-nav {
        grid-column: 1;
        grid-row: span 40;
        position: sticky;
        top: calc(var(--k-header-h) + 1.5rem);
    }

    .kahuna .kahunacart-account > :not(h1, .kahunacart-messages, .kahunacart-account-nav) { grid-column: 2; }
}

.kahuna .kahunacart-account-nav {
    margin: 0 0 2rem;
    border: 0;
}

.kahuna .kahunacart-account-nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
}

@media (min-width: 58rem) {
    .kahuna .kahunacart-account-nav ul { flex-direction: column; }
}

.kahuna .kahunacart-account-nav li { padding: 0; margin: 0; }

.kahuna .kahunacart-account-nav li > a,
.kahuna .kahunacart-account-nav li > span {
    display: block;
    padding: .5rem .8rem;
    border-radius: var(--k-radius-btn);
    color: var(--k-ink-soft);
    text-decoration: none;
    font-weight: 500;
    transition: background-color var(--k-dur) var(--k-ease), color var(--k-dur) var(--k-ease);
}

.kahuna .kahunacart-account-nav li > a:hover { background: var(--k-bg-alt); color: var(--k-ink); }

.kahuna .kahunacart-account-nav-item--current { border: 0; font-weight: 500; }

.kahuna .kahunacart-account-nav-item--current > span {
    background: var(--k-brand-soft);
    color: var(--k-brand-strong);
    font-weight: 600;
}

.kahuna .kahunacart-account-nav-item--logout { margin-top: .5rem; }
.kahuna .kahunacart-account-nav-item--logout > a { color: var(--k-muted); }

.kahuna .kahunacart-account-identity { margin-bottom: 1.5rem; }
.kahuna .kahunacart-account-profile-header .kahunacart-account-identity { margin: 0; }
.kahuna .kahunacart-account > h2 { margin-top: 2rem; }
.kahuna .kahunacart-account-panel { margin: 0 0 2.5rem; }
.kahuna .kahunacart-account-panel:first-of-type { margin-top: 0; }

.kahuna .kahunacart-account-orders thead th {
    font-family: var(--k-font-mono);
    font-size: .7rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--k-muted);
}

.kahuna .kahunacart-address-card {
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius);
    background: var(--k-surface);
    padding: 1.25rem 1.4rem;
}

.kahuna .kahunacart-account-empty {
    border: 1px dashed var(--k-line-strong);
    border-radius: var(--k-radius);
    padding: 1.5rem;
    color: var(--k-muted);
}

/* The Login plugin ships a hardcoded near-white card and sets no text colour
   of its own, so it is restated in theme tokens. Qualified with `body` on
   purpose: the plugin's stylesheet is enqueued after the theme's. */
/*
 * The flash region on a sign-in page belongs to the card, not to the page: it
 * is answering the form directly under it, and left full-container-width up in
 * the corner it reads as something that happened to a different page.
 *
 * Keyed off the card itself rather than a list of template names, because the
 * Login plugin renders the same section on seven routes — sign in, forgot,
 * reset, magic link, register, profile, unauthorized — and a theme should not
 * have to keep that list.
 */
body:has(#grav-login) .k-notices {
    max-width: var(--k-auth-width);
    margin: 4rem auto 0;
}

body:has(#grav-login) .k-notices + #grav-login { margin-top: 1rem; }

body #grav-login {
    max-width: var(--k-auth-width);
    margin: 4rem auto;
    padding: 2rem 2.25rem 2.25rem;
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius);
    box-shadow: var(--k-shadow);
    color: var(--k-ink);
    text-align: left;
}

#grav-login h1 {
    margin: 0 0 1.4rem;
    font-family: var(--k-font-display);
    font-size: 1.6rem;
    font-weight: 600;
    color: var(--k-ink);
    text-align: center;
}

#grav-login label {
    display: block;
    margin-bottom: .35rem;
    font-size: .86rem;
    font-weight: 500;
    color: var(--k-ink-soft);
}

#grav-login input[type="checkbox"] + label,
#grav-login label:has(input[type="checkbox"]) {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    margin: 0;
    font-weight: 400;
    color: var(--k-ink-soft);
}

#grav-login input[type="checkbox"] { width: auto; accent-color: var(--k-brand); }

#grav-login .form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .6rem;
    margin-top: 1.25rem;
}

#grav-login a:not(.button) { color: var(--k-brand-strong); }

/* ------------------------------------------------------------- 19. home page */

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

/* A band of sand across the top of the page: the copy on the left, the
   store's own goods fanned out on the right. */
.k-hero-wrap {
    background:
        radial-gradient(70% 90% at 100% 0%, var(--k-brand-soft), transparent 65%),
        var(--k-bg-alt);
    border-bottom: 1px solid var(--k-line);
}

.k-hero {
    display: grid;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
    padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(3rem, 8vw, 6rem);
}

@media (min-width: 52rem) {
    .k-hero { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); }
    .k-hero--solo { grid-template-columns: minmax(0, 1fr); }
    .k-hero--solo .k-hero-title { max-width: 18ch; }
}

.k-hero-eyebrow {
    display: block;
    font-family: var(--k-font-mono);
    font-size: .74rem;
    font-weight: 500;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--k-brand-strong);
    margin-bottom: 1.25rem;
}

.k-hero-title {
    font-size: var(--k-step-4);
    line-height: .96;
    letter-spacing: -.035em;
    font-weight: 800;
    max-width: 13ch;
    margin: 0 0 1.25rem;
}

.k-hero-title em {
    font-style: normal;
    color: var(--k-brand);
}

.k-hero-lede {
    font-size: var(--k-step-1);
    color: var(--k-ink-soft);
    max-width: 42ch;
    margin: 0 0 1.75rem;
    text-wrap: pretty;
}

.k-hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem 1.5rem;
}

/* The picture on the right: a photograph from the page's folder in a tile,
   or three product tiles fanned out like cards on a table. */
.k-hero-visual { position: relative; }

.k-hero-visual--photo {
    aspect-ratio: 5 / 4;
    border-radius: var(--k-radius);
    overflow: hidden;
    background: var(--k-surface-sunk);
}

@media (min-width: 52rem) {
    .k-hero-visual--photo { aspect-ratio: 4 / 5; max-height: 34rem; justify-self: end; width: 100%; }
}

.k-hero-visual--photo img { width: 100%; height: 100%; object-fit: cover; }

.k-hero-stack {
    position: relative;
    list-style: none;
    margin: 0 auto;
    padding: 0;
    width: min(100%, 30rem);
    aspect-ratio: 1;
}

/* Three cards fanned out, stacking fixed. Hover grows the card a touch and
   tips it slightly toward the viewer — the stack carries the perspective,
   so the tilt reads as depth rather than a skew. Nothing else moves. */
.k-hero-stack {
    isolation: isolate;
    perspective: 1000px;
}

.k-hero-card {
    position: absolute;
    width: 60%;
    transform: rotateX(0) rotateY(0);
    transition: scale .35s var(--k-ease), transform .35s var(--k-ease);
}

.k-hero-card:nth-child(1) { left: 0;   top: 6%;   rotate: -6deg; z-index: 1; }
.k-hero-card:nth-child(2) { right: 0;  top: 0;    rotate: 4deg;  z-index: 2; }
.k-hero-card:nth-child(3) { left: 19%; bottom: 0; rotate: -2deg; z-index: 3; width: 62%; }

.k-hero-card:hover,
.k-hero-card:has(a:focus-visible) {
    scale: 1.03;
    transform: rotateX(5deg) rotateY(-4deg);
}

.k-hero-card:hover a { box-shadow: var(--k-shadow-lift), 0 30px 50px -24px rgb(var(--k-shadow-rgb) / .45); }

.k-hero-card a {
    display: block;
    padding: .55rem .55rem .65rem;
    transition: box-shadow .35s var(--k-ease);
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: calc(var(--k-radius-sm) + .55rem);
    box-shadow: var(--k-shadow-lift);
    color: inherit;
    text-decoration: none;
}

.k-hero-card .k-product-media--card { border-radius: var(--k-radius-sm); }

.k-hero-card-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .75rem;
    padding: .6rem .3rem 0;
    font-size: .88rem;
}

.k-hero-card-title {
    font-weight: 600;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.k-hero-card-price {
    font-family: var(--k-font-display);
    font-weight: 600;
    white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .k-hero-card { transition: none; }
    .k-hero-card:hover { transform: none; }
}

/* category strip ---------------------------------------------------------- */

/* The departments as a row of doors: name set in the display face, count in
   mono, a hairline between each. No tiles, no pictures needed. */
.k-cats {
    display: flex;
    flex-wrap: wrap;
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid var(--k-line);
    border-bottom: 1px solid var(--k-line);
}

.k-cats li { flex: 1 1 12rem; display: flex; }

.k-cat {
    flex: 1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 1.1rem;
    border-right: 1px solid var(--k-line);
    font-family: var(--k-font-display);
    font-size: 1.35rem;
    font-weight: 600;
    letter-spacing: -.02em;
    color: var(--k-ink);
    text-decoration: none;
    transition: background-color var(--k-dur) var(--k-ease), color var(--k-dur) var(--k-ease);
}

.k-cats li:first-child .k-cat { padding-left: 0; }
.k-cats li:last-child .k-cat { border-right: 0; }

.k-cat:hover { background: var(--k-brand-soft); color: var(--k-brand-strong); }
.k-cats li:first-child .k-cat:hover { padding-left: 1.1rem; margin-left: -1.1rem; }

.k-cat-count {
    font-family: var(--k-font-mono);
    font-size: .74rem;
    letter-spacing: .06em;
    color: var(--k-muted);
    white-space: nowrap;
}

@media (max-width: 40rem) {
    .k-cats li { flex-basis: 100%; }
    .k-cat { border-right: 0; border-bottom: 1px solid var(--k-line); padding-inline: 0; }
    .k-cats li:last-child .k-cat { border-bottom: 0; }
    .k-cat:hover { padding-left: 0; margin-left: 0; }
}

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

.k-home-section { padding-block: clamp(2rem, 6vw, 4.5rem) 0; }
.k-home-section--cats { padding-top: 0; }

/* The facts strip: a list of what the store does, as a two-column definition
   list with hairlines. Not cards, not icons. */
.k-facts-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 0 3rem;
    margin: 0;
}

.k-fact {
    padding: 1.25rem 0 1.4rem;
    border-top: 1px solid var(--k-line);
}

.k-fact dt {
    font-family: var(--k-font-display);
    font-size: 1.3rem;
    font-weight: 600;
    letter-spacing: -.02em;
    margin-bottom: .3rem;
}

.k-fact dd { margin: 0; color: var(--k-ink-soft); text-wrap: pretty; }

.k-home-intro { display: grid; gap: 1rem 3rem; margin-bottom: 1.5rem; }

@media (min-width: 52rem) {
    .k-home-intro { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: end; }
}

.k-home-intro h2 { margin: 0; font-size: var(--k-step-3); font-weight: 800; letter-spacing: -.03em; max-width: 14ch; }
.k-home-intro .k-prose { max-width: 52ch; }

/* ------------------------------------------- 20. processing, denied, error */

.k-processing { display: grid; place-items: center; min-height: 40vh; }

.k-processing-card {
    max-width: 32rem;
    text-align: center;
    padding: clamp(1.5rem, 5vw, 3rem);
    border-radius: var(--k-radius);
    background: var(--k-surface-sunk);
}

.k-spinner {
    display: block;
    width: 2.25rem;
    height: 2.25rem;
    margin: 0 auto 1.25rem;
    border: 3px solid var(--k-line-strong);
    border-top-color: var(--k-accent);
    border-radius: 50%;
    animation: k-spin 900ms linear infinite;
}

@keyframes k-spin { to { transform: rotate(360deg); } }

.k-processing-help { color: var(--k-muted); }

.k-denied { max-width: 42rem; }
.k-denied-message { margin: 0; color: var(--k-ink-soft); }

.k-error {
    display: grid;
    gap: 1rem 3rem;
    align-items: center;
    padding-block: clamp(2rem, 8vw, 5rem);
}

@media (min-width: 52rem) {
    .k-error { grid-template-columns: auto minmax(0, 1fr); }
}

.k-error-code {
    font-family: var(--k-font-display);
    font-size: clamp(5rem, 18vw, 11rem);
    font-weight: 800;
    line-height: .9;
    margin: 0;
    color: var(--k-accent);
    letter-spacing: -.05em;
}

.k-error-actions { display: flex; flex-wrap: wrap; gap: .75rem 1.5rem; align-items: center; margin-top: 1.5rem; }

/* ------------------------------------------------------------- 21. utilities */

.k-visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

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

.k-account { position: relative; }

.k-account-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    border: 1px solid var(--k-line-strong);
    border-radius: 50%;
    background: var(--k-surface);
    cursor: pointer;
    transition: border-color var(--k-dur) var(--k-ease);
}

.k-account-toggle:hover { border-color: var(--k-ink); }

.k-avatar {
    display: block;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    background: var(--k-surface-sunk);
    object-fit: cover;
}

.k-account-menu {
    position: absolute;
    top: calc(100% + .6rem);
    right: 0;
    z-index: var(--k-z-menu);
    min-width: 14rem;
    padding: .45rem;
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: var(--k-radius-sm);
    box-shadow: var(--k-shadow-lift);
}

.k-account-menu[hidden] { display: none; }

.k-account-who {
    display: grid;
    gap: .1rem;
    padding: .55rem .65rem .7rem;
    border-bottom: 1px solid var(--k-line);
    margin-bottom: .35rem;
    line-height: 1.3;
}

.k-account-who strong { color: var(--k-ink); font-size: .92rem; }
.k-account-who span { color: var(--k-muted); font-size: .8rem; word-break: break-all; }

.k-account-menu a {
    display: block;
    padding: .5rem .65rem;
    border-radius: 7px;
    color: var(--k-ink-soft);
    text-decoration: none;
    font-size: .92rem;
}

.k-account-menu a:hover,
.k-account-menu a:focus-visible {
    background: var(--k-brand-soft);
    color: var(--k-ink);
}

.k-account-signout {
    border-top: 1px solid var(--k-line);
    margin-top: .35rem;
    padding-top: .6rem !important;
    border-radius: 0 0 7px 7px;
    color: var(--k-muted) !important;
}

/* ----------------------------------------------------------------- 22. print */

@media print {
    body::before { content: none; }
    .k-header, .k-footer, .k-back, .k-skip-link, .k-nav-toggle, .k-announce { display: none !important; }
    body { background: #fff; color: #000; }
    .k-receipt { border: 0; box-shadow: none; padding: 0; }
    .k-table { border-color: #999; }
}
