/*!
 * 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 arrow on a select, since `appearance: none` takes the native one
       away. The same stroke as the catalogue tree's chevron, turned to point
       down. A data URI cannot read a custom property, so the colour is written
       into it and the dark palette gets its own copy below — these are
       --k-muted in each scheme. */
    --k-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a7660' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    /* The glyph on the line under a greyed-out button. Masked and filled with
       currentColor, like the catalogue tree's chevron, so it follows the ink
       in both schemes on its own. */
    --k-info-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5'/%3E%3Cpath d='M12 7.6h.01'/%3E%3C/svg%3E");

    /* 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);
}

/* The one token that is a URL rather than a colour, so `light-dark()` cannot
   carry it: the select arrow on the dark side. Both halves of the scheme
   question are here — the system preference, unless the page is pinned light,
   and the page pinned dark. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --k-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a28d75' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    }
}

:root[data-theme="dark"] {
    --k-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a28d75' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* 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):last-child { padding-inline-end: 0; }

/* A content table in this theme is nearly always a name and an explanation:
   a short label on the left — "KahunaCart Licenses", "Shortcode Core" — and a
   sentence or two on the right. Automatic table layout shares the width out by
   how much each column wants, and a column of sentences wants far more than a
   column of names, so the names end up in a strip barely wide enough for one
   word and come apart a word per line. Holding the first cell of every row on
   one line asks for exactly the width the longest name needs and leaves the
   whole rest of the table to the explanation. */
.k-prose :is(th, td):first-child {
    padding-inline-start: 0;
    white-space: nowrap;
}

.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); }

/* On a phone the two columns can want more room than there is. A markdown
   table has no wrapper to scroll inside — Grav writes the `<table>` straight
   into the content — so the table itself becomes the scroll port, the way the
   plugin's own cart and order tables do at this width: `display: block` puts
   the row groups in a single anonymous table box that keeps the columns lined
   up and is free to be wider than the port. The page then stays put and the
   table is what moves sideways. */
@media (max-width: 40rem) {
    .k-prose table {
        display: block;
        max-inline-size: 100%;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
    }

    /* With the names held on one line there is not much of a phone left for
       the explanation beside them, and a paragraph two words wide is no better
       than a name one word wide. Every column after the first asks for a
       readable measure instead, which is what pushes the table past the port
       and gives the scroll something to do. */
    .k-prose :is(th, td) ~ :is(th, td) { min-inline-size: 15rem; }
}

.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.
 *
 * `a.button` is named for the same reason `button.button` is. KahunaCart's own
 * stylesheet carries a fallback at `.kahunacart :where(.button)`, which lands
 * at the weight of a single class and loads after this file, so a plain
 * `.button` selector loses the tie on source order anywhere inside a
 * storefront section. That is why "Add to cart" on a product page came out as
 * the theme's filled pill — it is a <button>, and `button.button` outweighs
 * the fallback — while "View details" on a listing card, an <a>, came out in
 * the plugin's small outlined box next to it. Naming the element puts every
 * button the theme draws in the same style.
 */
.button,
a.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,
a.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,
a.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,
a.k-button--ghost,
button.k-button--ghost {
    background: transparent;
    border-color: var(--k-line-strong);
    color: var(--k-ink);
}

.k-button--ghost:hover,
a.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,
a.k-button--ink,
button.k-button--ink {
    background: var(--k-ink);
    border-color: var(--k-ink);
    color: var(--k-bg);
}

.k-button--ink:hover,
a.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, a.k-button--lg, button.k-button--lg { padding: .9rem 1.75rem; font-size: 1.02rem; }
.k-button--sm, a.k-button--sm, button.k-button--sm { padding: .45rem .9rem; font-size: .85rem; }

.k-button--block,
a.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);
}

/*
 * A select, which the rule above never actually reached.
 *
 * Two things were happening to Country and State on checkout. The browser
 * still draws a select itself, and on macOS it draws a shorter box that
 * ignores the background and the radius above; and the plugin's own storefront
 * sheet loads after this one and carries `.kahunacart :where(select)` at the
 * weight of a single class — which ties with `.k-select` and wins on order, so
 * the selects took the plugin's padding and the plugin's ground while every
 * text box beside them kept the theme's. Two controls in the middle of the
 * billing address sat short of their neighbours in a colour from nowhere.
 *
 * So the box is stated here in full rather than inherited, `appearance: none`
 * hands it back from the browser, and the selector is written twice — once
 * bare for a page outside the shop, once under `.kahuna` to outweigh the
 * plugin, the same trick the fieldsets above use for the same reason.
 *
 * The state select the script swaps in when the country changes is this same
 * element, in the markup from the first paint with these classes on it, and
 * the plugin's own class names are in the list too, so a page that renders the
 * partial without the theme's classes is caught as well.
 */
select, .k-select,
.kahunacart-country-select, .kahunacart-region-select,
.kahuna select, .kahuna .k-select,
.kahuna .kahunacart-country-select, .kahuna .kahunacart-region-select {
    appearance: none;
    -webkit-appearance: none;
    box-sizing: border-box;
    width: 100%;
    /* The right side carries the arrow; the other three are `.k-input`'s. */
    padding: .66rem 2.3rem .66rem .85rem;
    border: 1px solid var(--k-line-strong);
    border-radius: var(--k-radius-sm);
    background-color: var(--k-surface);
    background-image: var(--k-select-chevron);
    background-repeat: no-repeat;
    background-position: right .85rem center;
    background-size: .7rem .7rem;
    color: var(--k-ink);
    font: inherit;
    /* Stated rather than left to the control: a native select sizes itself
       from the option text and ignored the line-height that gives every text
       box its height. */
    line-height: 1.4;
    min-height: 0;
    text-overflow: ellipsis;
}

select::-ms-expand { display: none; }

/* 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; }

/* A shipping method this basket cannot have, and the sentence that says why.
   The row wraps so the note gets a line of its own under the price rather
   than squeezing in beside it. */
.k-choice { flex-wrap: wrap; }
.k-choice-note { flex-basis: 100%; color: var(--k-muted); font-size: .85rem; }
.k-choice:has(input:disabled) { cursor: default; opacity: .6; }
.k-choice:has(input:disabled):hover { border-color: var(--k-line-strong); }

.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; }

/* A line whose quantity an add-on decided: a number where the box would be,
   on the same right edge and in the same figures, so the column still reads
   as a column. */
.k-qty-fixed { display: inline-block; padding: .45rem 0; font-variant-numeric: tabular-nums; }

.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%; }
/* A note may carry a link, "Sign in" most often. It keeps the note's muted
   colour and is told apart by its underline, like the site's other inline links. */
.k-cart-item-note a,
.k-summary-item-note a { color: inherit; text-decoration-color: currentColor; }

/* 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,
/* The plugin's notice is one paragraph with no mark, and its text can carry a
   link. Flex would turn each run of text and the link into separate items with
   a gap between them, so it lays out as ordinary running text. */
.kahuna .kahunacart-message { display: block; }
.kahuna .kahunacart-message a { color: var(--k-ink); text-decoration-color: currentColor; }
.kahuna .kahunacart-message a:hover { text-decoration-thickness: 2px; }

/* 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); }

/* A notice that carries an action. The cart's frozen-payment warning is the
   only one so far: it says a payment page is still open at the provider, and
   the button under it is the shopper's only way out of a cart that will not
   change until the payment is finished or cancelled. The paragraph is tightened
   because a notice is a denser thing than the prose the browser's default
   margin is written for. */
.kahunacart-payment-open .k-notice-body p { margin: 0 0 .7rem; }
.kahunacart-payment-open .k-notice-body form { margin: 0; }

/* The bundle notice: a cheaper way to buy what is already in the basket, with
   the swap and a plain "keep them separate" side by side under it. */
.kahunacart-bundle-suggestion .k-notice-body p { margin: 0 0 .7rem; }
.k-bundle-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.k-bundle-actions form { margin: 0; }

/* --------------------------------- 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); }
/* Part paid sits with awaiting payment for the same reason: money is still
   owed on the order. */
.k-badge--pending,
.k-badge--partially_paid { 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; }

/*
 * The hero card's pricing line.
 *
 * The plugin draws the price, the struck old price and the campaign badge as
 * separate block paragraphs stacked in the hero body's column, and the badge
 * carries `align-self: center`, which in that column leaves it floating in the
 * middle of the card while the title and the summary are hard left. The
 * theme's own copy of partials/kahunacart-section-hero.html.twig puts all
 * three in this row instead, so a listing card reads the way the product page
 * does: what it costs, what it used to cost, what the sale is called, left to
 * right, wrapping onto a second line when the card runs out of width.
 *
 * The badge needs no reset here. `align-self: center` in a row means vertical
 * centring, which is what a pill beside a price wants anyway.
 */
.k-hero-pricing {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem .55rem;
}

.k-hero-pricing > p { margin: 0; }

.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; }

/* A quantity ladder's standing in the cart. Brand-tinted rather than sunk like
   its neighbours, because it is the one panel in the aside that is an offer
   rather than a fact — the totals below it are the consequence. The plugin's
   own kahunacart-sale-tier-list inside it is already styled by
   assets/kahunacart.css through the token map above. */
.k-tier-panel {
    background: color-mix(in oklab, var(--k-brand) 8%, var(--k-surface));
    border: 1px solid color-mix(in oklab, var(--k-brand) 22%, transparent);
}

.k-tier-panel .k-panel-title { margin-bottom: .5rem; font-size: 1.05rem; }

/* The nudge to the next rung. It is the sentence a shopper acts on, so it
   carries the accent the buttons use rather than the body ink. */
.k-tier-next {
    margin: 0 0 .75rem;
    color: var(--k-accent-strong);
    font-weight: 600;
}

@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;
}

/* The payment step is one element wrapping the payment choices, the notes and
   the button that spends the money, because the plugin's script greys Place
   order against the controls inside the step it sits in — a method nobody has
   picked has to be in the same element as the button that would charge it. This
   layout draws those in two columns, so the wrapper itself draws no box and its
   two halves take their own places in the grid. */
.k-step--payment { display: contents; }

@media (min-width: 58rem) {
    .k-checkout-layout { grid-template-columns: minmax(0, 1.7fr) minmax(19rem, 1fr); }
    /* Stated rather than left to auto-placement, because the payment step's two
       halves arrive as separate items in the same flow as the column above
       them, and the summary has to run beside both rather than start level
       with the second. */
    .k-checkout-main { grid-column: 1; grid-row: 1; }
    .k-checkout-pay { grid-column: 1; grid-row: 2; }
    .k-checkout-aside { grid-column: 2; grid-row: 1 / span 2; }
}

.k-checkout-pay { min-width: 0; }

/* 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. It is
   reset on the form rather than on the left column, because the payment step's
   fieldsets are a column of their own and would otherwise start again at 01. */
.k-checkout-layout { counter-reset: k-step; }
.k-checkout-layout .k-fieldset { counter-increment: k-step; }
/* Only the very first section on the page goes without its rule. The checkout
   is drawn in step wrappers now, and a plain `.k-fieldset:first-child` would
   take the hairline off the first section of every step instead of off the
   first section of the form. */
.k-checkout-main > .k-fieldset:first-child,
.k-checkout-main > :first-child > .k-fieldset:first-child { border-top: 0; padding-top: 0; }

/* ---- express pay ----
   The wallet buttons a provider mounted, at the top of the left column and
   above the first numbered section. The plugin's own sheet already draws the
   caption, the row and the "or continue below" divider; what this adds is the
   theme's voice — the caption in the same small muted weight as a field label,
   the divider on the theme's hairline — and the spacing that puts the block in
   the same rhythm as the sections under it. The buttons stay on the column's
   left edge, level with the inputs, and each keeps the plugin's cap so a lone
   wallet button is a button rather than a bar across the column. */
.kahuna .kahunacart-express {
    margin: 0 0 2rem;

    /* The colours a wallet button paints itself with on the plugin's `auto`
       theme, which is what a store gets until a merchant picks a fixed one.
       The theme's ink as the fill and the page's ground as the label, so the
       button is koa with sand lettering on the light side and sand with koa
       lettering on the dark one — the same pair, read the other way round,
       which is what light-dark() in the token block does for everything else
       on the page. Pinned here rather than left to the plugin's own default so
       the express buttons stay on this palette whatever that default resolves
       to, and so a store that wants its wallet buttons in some other colour has
       one place to say so. A merchant who picked dark, light or outline gets
       that flat colour on both sides and none of this is read. */
    --kahunacart-express-auto-bg: var(--k-ink);
    --kahunacart-express-auto-fg: var(--k-bg);
    --kahunacart-express-auto-border: transparent;
}

.kahuna .kahunacart-express-heading {
    margin: 0 0 .6rem;
    font-size: .86rem;
    font-weight: 500;
    color: var(--k-ink-soft);
}

.kahuna .kahunacart-express-or {
    margin: 1.4rem 0 0;
    font-size: .86rem;
    color: var(--k-muted);
}

.kahuna .kahunacart-express-or::before,
.kahuna .kahunacart-express-or::after { background: var(--k-line); }

/* The divider already separates the block from what follows it, so the first
   numbered section keeps the bare top the opening section of the form has —
   two lines a few millimetres apart read as a mistake. */
.k-checkout-main:has(.kahunacart-express) > #kahunacart-checkout-address > .k-fieldset:first-child {
    border-top: 0;
    padding-top: 0;
}

/* The delivery address is on the page whether the shopper wants it or not, and
   `hidden` is what keeps it out of the way until they untick "ship to the
   billing address". Said out loud here because the browser's own
   `[hidden] { display: none }` sits at (0,1,0) and would lose to any later
   layout rule of ours that gave a fieldset a `display` — and a delivery
   address that paints anyway is a second address form on every checkout.
   A hidden section is not counted either, so the numbering follows it. */
.kahuna .k-fieldset[hidden] { display: none; }

/* Where a Continue lands. The plugin sends the shopper back to the step they
   are now on rather than to the top of the page, so each step wrapper carries
   an id — and the header is sticky, which is what this clears. */
#kahunacart-checkout-address,
#kahunacart-checkout-shipping,
#kahunacart-checkout-payment { scroll-margin-top: calc(var(--k-header-h) + 1.5rem); }

/* ---- the checkout steps ----
   Checkout is one form with a button under each part of it, and the plugin's
   script says out loud which parts are finished: `data-kc-step-ready` on the
   step and on its button, the real `disabled` attribute beside it, and
   `aria-busy` on the delivery region while the options are being fetched. All
   three are set by script alone, so a browser with no scripting meets none of
   them and every button is live — which is the checkout that has always
   worked without JavaScript. */

/* The button that ends a step, at the end of the last numbered section it
   covers. The fieldsets carry 2rem of air below them already, so this pulls
   back up under the last one rather than opening a second gap. */
.k-checkout-layout .k-step-actions {
    display: flex;
    justify-content: flex-end;
    margin: -1rem 0 2rem;
}

@media (max-width: 34rem) {
    .k-checkout-layout .k-step-actions .button { width: 100%; }
}

/* In the summary panel there is one button and it is the width of the panel. */
.k-checkout-layout .k-step-actions--block { display: block; margin: 0; }

/* Greyed out while the step it sits under is unfinished — the address not
   filled in, no delivery method picked, no payment method chosen, the terms
   not accepted. `.button[disabled]` above already dims it and takes it out of
   the pointer's way; what this adds is a state you can read at a glance, the
   reason under the cursor, and no lift on a press that will not come. */
.kahuna .k-step-actions .button[data-kc-step-ready="0"],
.kahuna .k-step-actions .button[disabled] {
    background: var(--k-surface-sunk);
    border-color: var(--k-line-strong);
    color: var(--k-muted);
    opacity: 1;
    transform: none;
    box-shadow: none;
}

.kahuna [data-kc-step-ready="0"] .k-step-actions,
.kahuna .k-step-actions:has(.button[aria-disabled="true"]) { cursor: not-allowed; }

/*
 * What a greyed-out button is waiting for, under the button.
 *
 * The plugin's script makes this element where a theme has not drawn one, and
 * the one it made in the summary panel landed on top of Place order. Every
 * button that can be greyed out has one of its own now — both Continues and
 * Place order — so the line always appears in the same place: under the
 * button, a little below it, reading as a note rather than a caption. Small,
 * but in the body ink rather than the muted one: it is the sentence that says
 * why nothing is happening, and it has to be read.
 */
.kahuna .k-step-missing {
    display: flex;
    align-items: flex-start;
    gap: .45rem;
    margin: .55rem 0 2rem;
    font-size: .88rem;
    line-height: 1.45;
    color: var(--k-ink-soft);
}

/* The summary panel's copy sits directly under a full-width button, so it has
   the panel's own bottom spacing rather than a step's. */
.kahuna .k-step-actions--block + .k-step-missing { margin-bottom: .75rem; }

/* `hidden` has to win over the flex above it, or an empty line would hold
   open a gap under every button on the page. */
.kahuna .k-step-missing[hidden] { display: none; }

.kahuna .k-step-missing::before {
    content: "";
    flex: none;
    width: .95rem;
    height: .95rem;
    margin-top: .14rem;
    background: currentColor;
    opacity: .75;
    -webkit-mask: var(--k-info-glyph) no-repeat center / contain;
    mask: var(--k-info-glyph) no-repeat center / contain;
}

/* The chevron on a Continue: pressing it takes you to the section below, and
   the glyph says so. Only on the two Continues — Place order goes nowhere on
   the page. */
.k-step-chevron {
    width: 1em;
    height: 1em;
    margin-left: .4em;
    vertical-align: -.12em;
    flex: none;
}

.k-step-actions .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* While the delivery options are on their way, and while a method the shopper
   has just picked is being stored and the order repriced. Quiet rather than
   busy: what is there stays readable, it just stops taking clicks until the
   answer has arrived. The summary panel is in the list because the total is
   one of the things about to change, and a figure that fades for a moment is a
   figure nobody reads as final. */
.kahuna [data-kc-step][aria-busy="true"],
.kahuna #kahunacart-checkout-summary[aria-busy="true"] {
    opacity: .55;
    pointer-events: none;
    cursor: progress;
    transition: opacity 120ms var(--k-ease);
}

.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; }
/* The customer's group badges sit tight under their name, and take the gap below. */
.kahuna .kahunacart-account-identity:has(+ .kahunacart-account-groups) { margin-bottom: .25rem; }
.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; }
}
