/* Two Shelves — assembled stylesheet (design-system tokens + components + site + pages). */
/* Generated from the Claude Design handoff bundle. */
/* ───────────────────────────────────────────────────────────
   Two Shelves — Webfonts
   Loaded from fonts.bunny.net (a GDPR-safe Google-Fonts drop-in —
   see Layout::font_head_html in src/views.rs for the same choice on
   the merchant-selectable fonts) rather than Google's own CDN, so a
   visitor's IP never reaches Google on page load. See readme.md →
   "Font substitution" note: these are stand-ins picked to match the
   brand intent until licensed brand binaries are supplied.

   Bunny's css2 endpoint is Google-compatible but serves discrete
   static weight instances, not a true variable font: the `..` range
   syntax (e.g. `300..800`) returns an API error, so every weight this
   stylesheet actually uses is spelled out individually below (still every
   weight/style the original ranges covered — 300–800 upright /
   400–600 italic for Hanken Grotesk, 400–600 upright / 400–500
   italic for Newsreader — just enumerated). Newsreader's `opsz`
   (optical-size) axis has no Bunny equivalent at all, so this loads
   its default optical-size instance instead of Google's fluid
   6pt–72pt interpolation — the closest available match, not a
   silent axis drop.

   • Newsreader      → editorial serif, display & headings
   • Hanken Grotesk  → humanist grotesque, UI + body
   • JetBrains Mono  → mono, labels / SKU / price ticks

   THE @import THAT USED TO LIVE HERE IS NOW A <link> IN `tpl/base.html`.
   This sheet is no longer inlined into the document — it is fetched as
   `/twoshelves.css?v=<hash>` (see `render::css_url`). An `@import` inside a
   LINKED stylesheet is a CHAINED request: the browser cannot even discover the
   font CSS until this file has arrived and parsed, so the fonts would land a
   full round trip later than they used to. The URL now lives in
   `theme::FONT_CSS_URL` and `base.html` emits it as a <link> beside a
   `preconnect`, which the preload scanner sees in the initial HTML — the fonts
   and this sheet are then fetched in PARALLEL. Do not move it back.
   ─────────────────────────────────────────────────────────── */

/* ───────────────────────────────────────────────────────────
   Two Shelves — Color
   Palette: old forest · stone · wood · gold, on warm paper.
   Scandinavian-minimal: paper-light surfaces, ink-green text,
   forest as the single confident brand color, gold used sparingly.
   ─────────────────────────────────────────────────────────── */

:root {
  /* ── Forest (primary brand) ─────────────────────────────── */
  /* --primary-700 is now `var(--brand)`, not the other way round — see the "Brand actions"
     comment below for why (a tenant brand override used to only repaint --brand/-hover/-active
     and leave these ten steps, and the 88 places across this sheet that read them, stuck at the
     old green). The other ten steps stay LITERAL: this is a hand-picked designer ramp, not a
     mathematical tint/shade of the primary — the closest achievable color-mix(brand, white/black)
     fit measured against these exact hexes is up to ΔE76≈9.5 on -500/-400/-300 (see
     `theme_css::token_block`'s doc comment), a visible shift on the untouched default shop. A
     tenant that sets a custom brand via the no-code picker gets these ten re-tinted through a
     generated `.storefront{…}` override (still color-mix, same fit cost, but only a customised
     shop pays it); the raw hexes here are what an untouched shop — messless.pl included —
     actually renders.
  */
  --primary-950: #161F19;
  --primary-900: #1E2A22;
  --primary-800: #26362B;
  --primary-700: var(--brand);
  --primary-600: #3B5142;
  --primary-500: #4C6A55;
  --primary-400: #6B8773;
  --primary-300: #97AE9D;
  --primary-200: #C6D3C9;
  --primary-100: #DEE7E0;
  --primary-50:  #EFF3EF;

  /* ── Stone (warm neutral) ───────────────────────────────── */
  --neutral-950: #1C1B18;
  --neutral-900: #2A2825;   /* ink */
  --neutral-800: #3A3833;
  --neutral-700: #4B4842;
  --neutral-600: #5F5B53;
  --neutral-500: #76716A;
  --neutral-400: #948F86;
  --neutral-300: #B6B1A8;
  --neutral-200: #D6D1C7;
  --neutral-150: #E2DDD3;
  --neutral-100: #ECE8DF;
  --neutral-50:  #F4F1EA;   /* paper */
  --neutral-25:  #FAF8F3;   /* card warm-white */

  /* ── Wood (warm secondary) ──────────────────────────────── */
  --tertiary-800: #6E4427;
  --tertiary-700: #875533;
  --tertiary-600: #A06A43;
  --tertiary-500: #B5825A;   /* secondary */
  --tertiary-400: #C89C78;
  --tertiary-300: #DBBA9B;
  --tertiary-200: #EAD6C1;
  --tertiary-100: #F3E7D7;

  /* ── Gold (accent) ──────────────────────────────────────── */
  /* Same inversion as forest/--brand above: --secondary-500 is `var(--accent)`, the other six steps
     stay literal defaults, and a tenant-set accent re-tints them via the picker's generated
     override (measured fit: up to ΔE76≈4.1, see `theme_css::token_block`). */
  --secondary-700: #6E5619;   /* darkened from #8C6C24 — the badge text/bg pair fell short of 4.5:1 */
  --secondary-600: #A7842F;
  --secondary-500: var(--accent);
  --secondary-400: #D2B361;
  --secondary-300: #E2CB8C;
  --secondary-200: #EFDFB6;
  --secondary-100: #F7EED5;

  /* ── Functional hues ────────────────────────────────────── */
  /* -600 shades darkened from #3C7A4E/#B5821F — used as plain text (e.g. `.summary__free`) as
     well as on the -100 tint, and both were short of 4.5:1 against white and/or their own tint. */
  --success-600: #336842;
  --success-500: #4C9061;
  --success-100: #DCEBDF;
  --warning-600: #886217;
  --warning-500: #CD9A33;
  --warning-100: #F6E9C8;
  --error-700:  #8F3A28;
  /* Darkened slightly from #B0492F — see the admin sheet's identical comment. */
  --error-600:  #A7452D;
  --error-500:  #C25A40;
  --error-100:  #F2DDD5;
  --info-600:    #4A6675;
  --info-500:    #5C7C8C;
  --info-100:    #DCE6EA;

  --white: #FFFFFF;
  --black: #14160F;

  /* ═════════ Semantic aliases ═════════ */
  /* Every alias below that resolves a raw `--primary-*`/`--secondary-*` ramp step lives on `.storefront`
     instead, further down — see that block's comment for why. Everything that stays here is
     `--neutral-*` or a literal, which never derives from a tenant brand/accent, so `:root` vs.
     `.storefront` makes no difference for it. */

  /* Surfaces */
  --surface-page:      var(--neutral-50);
  --surface-card:      var(--white);
  --surface-card-warm: var(--neutral-25);
  --surface-sunken:    var(--neutral-100);
  --surface-overlay:   rgba(28, 27, 24, 0.42);

  /* Text */
  --text-strong:    var(--neutral-900);
  --text-body:      var(--neutral-700);
  /* stone-600, not -500/-400 — the lighter two steps read as ≥4.28:1 on the paper/warm/sunken
     surfaces these tokens actually sit on (product tiles, breadcrumbs, spec labels…), short of
     WCAG AA's 4.5:1 for normal text. stone-600 clears 4.5:1 against every surface color in use. */
  --text-muted:     var(--neutral-600);
  --text-subtle:    var(--neutral-600);
  --text-onbrand:   var(--neutral-25);

  /* Borders */
  --border-subtle:  var(--neutral-150);
  --border-default: var(--neutral-200);
  --border-strong:  var(--neutral-300);

  /* Brand actions */
  /* --brand is the literal seed for the whole forest ramp now (--primary-700 above reads
     `var(--brand)`) — inverted from the old `--brand: var(--primary-700)`, which meant a tenant
     brand override only ever repainted these four --brand-* tokens and left --primary-* (88 uses
     across this sheet: badges, section heads, the hero <em>, borders…) pinned at the hardcoded
     green. Never restore `--brand: var(--primary-700)` here — with --primary-700 now defined AS
     var(--brand), that would be a circular reference (both compute to their initial value, i.e.
     no color). Same relationship for --accent / --secondary-500 just below.
  */
  --brand:          #2F4135;
  --accent:         #C19B3D;

  /* Focus ring */
  --ring: 0 0 0 3px rgba(76, 106, 85, 0.35);
}

/* Anything that resolves a raw `--primary-*`/`--secondary-*` ramp step is declared HERE, on
   `.storefront`, deliberately NOT in the `:root` block above.
   A CSS custom property's value is resolved at computed-value time on the element that DECLARES
   it, not the element that reads it. A brand/accent override — the no-code picker
   (`theme_css::token_block`) or a tenant's own raw `.storefront{--primary-800:…}` — is scoped to
   `.storefront`, so anything declared at `:root` that references e.g. `--primary-800` resolves
   against `:root`'s OWN (unoverridden) ramp the instant it's computed there, and the
   already-resolved value just inherits down unchanged — the override never reaches it. Declaring
   the same thing on `.storefront` instead makes it resolve in the same scope the override lands
   on, so it sees it.

   Two things needed this, not one:

   1. `--surface-inverse`/`--text-brand`/`--text-link`/`--border-brand`/`--border-focus`/
      `--brand-subtle` (the semantic aliases) — `--surface-inverse` was the reported live bug: a
      merchant's brand colour didn't reach the newsletter card or the "Notatnik, przemyślany"
      section, both `background: var(--surface-inverse)`. The other five had the identical
      defect, just less visible (brand-coloured links/text, not a whole section background).
      `--brand-hover`/`--brand-active`/`--accent-hover` didn't strictly need to move — `token_block`
      already re-emits them directly with their own `color-mix`, and a same-element declaration on
      `.storefront` always wins over anything inherited from `:root` regardless of where the
      `:root` copy resolved — but they're included anyway so this is the complete, structural
      answer rather than a partial list a future alias could fall through.

   2. `--primary-700`/`--secondary-500` THEMSELVES (found while fixing #1 — moving `--text-brand` etc.
      here does nothing if the `--primary-700` it reads is still frozen at `:root`, and a real
      headless-Chromium check proved it was: `.site-logo`, `.avatar`, `.badge--brand`,
      `.tag--selected`, `.button--ghost` and ~85 other direct `var(--primary-700)`/`var(--secondary-500)`
      reads across this sheet stayed the shipped green/gold under a brand-only picker override,
      contrary to `token_block`'s doc comment, which assumed overriding `--brand` alone was
      enough — it isn't, without a `.storefront`-scoped place for `--primary-700`'s own
      `var(--brand)` to re-resolve). `token_block` deliberately does NOT re-emit `--primary-700`/
      `--secondary-500` (see its doc comment) — it only overrides `--brand`/`--accent` directly, so
      this redeclaration (the SAME formula as `:root`'s, just reachable from `.storefront`) is
      what makes that override actually propagate to every direct reader.

   On an untouched shop this computes byte-identical to the old `:root` declarations:
   `.storefront` simply inherits `--primary-*`/`--secondary-*`/`--brand`/`--accent` from `:root` when
   nothing overrides them, so every property below reduces to exactly the same value as before —
   verified against a real headless-Chromium cascade during development (the only thing that can
   actually prove resolution rather than just the CSS text; not wired into `cargo test`, see that
   test's doc comment for why). `render.rs`'s
   `no_root_scoped_token_references_a_ramp_step_the_tenant_override_cant_reach` is the static
   guard that DOES run in `cargo test`: every `:root` declaration here that references the ramp
   must also be re-declared in this `.storefront{…}` block. */
.storefront {
  --primary-700:      var(--brand);
  --secondary-500:        var(--accent);
  --surface-inverse: var(--primary-800);
  --text-brand:      var(--primary-700);
  --text-link:       var(--primary-700);
  --border-brand:    var(--primary-700);
  --border-focus:    var(--primary-500);
  --brand-hover:     var(--primary-800);
  --brand-active:    var(--primary-900);
  --brand-subtle:    var(--primary-50);
  --accent-hover:    var(--secondary-600);
}
/* ───────────────────────────────────────────────────────────
   Two Shelves — Typography
   Newsreader (serif display) · Hanken Grotesk (sans UI/body)
   · JetBrains Mono (mono labels). Editorial headings, calm body,
   monospace for the small functional labels stationery loves.
   ─────────────────────────────────────────────────────────── */

:root {
  /* Families */
  --font-serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --font-sans:  'Hanken Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:  'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  /* Weights */
  --weight-light:    300;
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  /* Type scale — fluid-ish editorial scale (rem @ 16px root) */
  --text-display:  4.5rem;   /* 72 — hero */
  --text-h1:       3rem;     /* 48 */
  --text-h2:       2.25rem;  /* 36 */
  --text-h3:       1.75rem;  /* 28 */
  --text-h4:       1.375rem; /* 22 */
  --text-lg:       1.125rem; /* 18 */
  --text-base:     1rem;     /* 16 */
  --text-sm:       0.875rem; /* 14 */
  --text-xs:       0.75rem;  /* 12 */
  --text-2xs:      0.6875rem;/* 11 — overline / mono labels */

  /* Line heights */
  --leading-tight:   1.08;
  --leading-snug:    1.2;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;

  /* Letter spacing */
  --tracking-tight:   -0.02em;
  --tracking-snug:    -0.01em;
  --tracking-normal:  0em;
  --tracking-wide:    0.04em;
  --tracking-caps:    0.14em;   /* overlines / eyebrows */

  /* Semantic role bundles (use via the helper classes below) */
  --display-family: var(--font-serif);
  --heading-family: var(--font-serif);
  --body-family:    var(--font-sans);
  --label-family:   var(--font-mono);
}

/* Optional helper classes — handy for cards & quick layouts.
   Components should reference the tokens above directly. */
.t-display {
  font-family: var(--display-family);
  font-weight: var(--weight-regular);
  font-size: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-strong);
}
.t-h1 { font-family: var(--heading-family); font-weight: 500; font-size: var(--text-h1); line-height: var(--leading-snug); letter-spacing: var(--tracking-snug); color: var(--text-strong); }
.t-h2 { font-family: var(--heading-family); font-weight: 500; font-size: var(--text-h2); line-height: var(--leading-snug); letter-spacing: var(--tracking-snug); color: var(--text-strong); }
.t-h3 { font-family: var(--heading-family); font-weight: 500; font-size: var(--text-h3); line-height: var(--leading-snug); color: var(--text-strong); }
.t-h4 { font-family: var(--body-family); font-weight: 600; font-size: var(--text-h4); line-height: var(--leading-snug); color: var(--text-strong); }
.t-body { font-family: var(--body-family); font-weight: 400; font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-body); }
.t-sm { font-family: var(--body-family); font-weight: 400; font-size: var(--text-sm); line-height: var(--leading-normal); color: var(--text-body); }
.t-label {
  font-family: var(--label-family);
  font-weight: 500;
  font-size: var(--text-2xs);
  line-height: 1;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}
/* ───────────────────────────────────────────────────────────
   Two Shelves — Spacing & Layout
   4px base grid. Generous, airy rhythm for a Scandinavian feel.
   ─────────────────────────────────────────────────────────── */

:root {
  --space-0:   0;
  --space-1:   0.25rem;  /* 4  */
  --space-2:   0.5rem;   /* 8  */
  --space-3:   0.75rem;  /* 12 */
  --space-4:   1rem;     /* 16 */
  --space-5:   1.25rem;  /* 20 */
  --space-6:   1.5rem;   /* 24 */
  --space-8:   2rem;     /* 32 */
  --space-10:  2.5rem;   /* 40 */
  --space-12:  3rem;     /* 48 */
  --space-16:  4rem;     /* 64 */
  --space-20:  5rem;     /* 80 */
  --space-24:  6rem;     /* 96 */
  --space-32:  8rem;     /* 128 */

  /* Layout */
  --container-sm:  640px;
  --container-md:  840px;
  --container-lg:  1080px;
  --container-xl:  1280px;
  --container-2xl: 1440px;
  /* Fluid: 24px on desktop, easing to 16px on narrow phones — a fixed 24px is 17% of a
     280px viewport and was a top cause of "no margin / padding too wide" on small devices. */
  --gutter:        clamp(1rem, 5vw, 1.5rem);
  --section-y:     var(--space-24);
}
/* ───────────────────────────────────────────────────────────
   Two Shelves — Elevation, Radii, Borders, Motion
   Minimal shadows. Structure comes from hairline borders and
   warm paper layering, not heavy drop shadows.
   ─────────────────────────────────────────────────────────── */

:root {
  /* Corner radii — small & calm */
  --radius-xs:   3px;
  --radius-sm:   6px;
  --radius-md:   10px;
  --radius-lg:   14px;
  --radius-xl:   20px;
  --radius-2xl:  28px;
  --radius-full: 999px;

  /* Border widths */
  --border-hairline: 1px;
  --border-thick:    1.5px;

  /* Shadows — soft, warm-tinted, low contrast */
  --shadow-xs:  0 1px 2px rgba(30, 42, 34, 0.05);
  --shadow-sm:  0 1px 2px rgba(30, 42, 34, 0.06), 0 2px 6px rgba(30, 42, 34, 0.05);
  --shadow-md:  0 2px 4px rgba(30, 42, 34, 0.05), 0 8px 20px rgba(30, 42, 34, 0.07);
  --shadow-lg:  0 4px 8px rgba(30, 42, 34, 0.06), 0 18px 40px rgba(30, 42, 34, 0.10);
  --shadow-xl:  0 24px 60px rgba(22, 31, 25, 0.16);
  --shadow-focus: var(--ring);

  /* Inset / pressed */
  --shadow-inset: inset 0 1px 2px rgba(30, 42, 34, 0.08);

  /* Motion — quiet, no bounce */
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);  /* @kind other */
  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1); /* @kind other */
  --ease-in:       cubic-bezier(0.4, 0, 1, 1);  /* @kind other */
  --dur-fast:   120ms;  /* @kind other */
  --dur-base:   200ms;  /* @kind other */
  --dur-slow:   320ms;  /* @kind other */
}
/* ===================== Design-system components ===================== */

  .site-logo { display: inline-flex; align-items: center; gap: 0.5em; color: var(--primary-700);
    font-family: var(--font-serif); line-height: 1; -webkit-font-smoothing: antialiased; }
  .site-logo--inverse { color: var(--neutral-25); }
  .site-logo--mono { color: currentColor; }
  .site-logo__mark { flex: none; }
  .site-logo__word { font-weight: 500; letter-spacing: -0.02em; font-size: 1em; }
  .site-logo__word b { font-weight: 500; }
  .site-logo__dot { color: var(--secondary-500); }
  .site-logo--inverse .site-logo__dot { color: var(--secondary-400); }
  


  .avatar { display: inline-flex; align-items: center; justify-content: center; flex: none;
    border-radius: var(--radius-full); overflow: hidden; background: var(--primary-100);
    color: var(--primary-700); font-family: var(--font-sans); font-weight: 600;
    border: 1px solid rgba(20,22,15,0.06); user-select: none; }
  .avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .avatar--sm { width: 28px; height: 28px; font-size: 11px; }
  .avatar--md { width: 38px; height: 38px; font-size: 14px; }
  .avatar--lg { width: 52px; height: 52px; font-size: 18px; }
  


  .badge {
    display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-sans);
    font-size: var(--text-xs); font-weight: 600; line-height: 1; letter-spacing: 0.01em;
    padding: 4px 9px; border-radius: var(--radius-full); white-space: nowrap;
    border: 1px solid transparent;
  }
  .badge--solid { background: var(--brand); color: var(--text-onbrand); }
  .badge--neutral { background: var(--neutral-100); color: var(--neutral-700); border-color: var(--neutral-200); }
  .badge--brand { background: var(--primary-50); color: var(--primary-700); border-color: var(--primary-100); }
  .badge--success { background: var(--success-100); color: var(--success-600); }
  .badge--warning { background: var(--warning-100); color: var(--warning-600); }
  .badge--danger { background: var(--error-100); color: var(--error-700); }
  .badge--info { background: var(--info-100); color: var(--info-600); }
  .badge--accent { background: var(--secondary-100); color: var(--secondary-700); border-color: var(--secondary-200); }
  .badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
  


  .card { background: var(--surface-card); border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg); color: var(--text-body); display: block; }
  .card--pad { padding: var(--space-6); }
  .card--shadow { box-shadow: var(--shadow-sm); border-color: transparent; }
  .card--warm { background: var(--surface-card-warm); }
  .card--interactive { cursor: pointer; transition: box-shadow var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard), transform var(--dur-base) var(--ease-standard); }
  .card--interactive:hover { box-shadow: var(--shadow-md); border-color: var(--border-default); transform: translateY(-2px); }
  .card--interactive:active { transform: translateY(0); }
  


  .rating { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-sans); }
  .rating__stars { display: inline-flex; gap: 1px; color: var(--secondary-500); }
  .rating__stars svg { width: 1em; height: 1em; display: block; }
  .rating__star--empty { color: var(--neutral-300); }
  .rating__count { font-size: var(--text-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }
  


  .product-card { display: flex; flex-direction: column; font-family: var(--font-sans);
    background: var(--surface-card); border-radius: var(--radius-lg); cursor: pointer;
    text-decoration: none; color: inherit; }
  .product-card__media { position: relative; aspect-ratio: 4/5; border-radius: var(--radius-md);
    overflow: hidden; background: var(--neutral-100); border: 1px solid var(--border-subtle); }
  .product-card__media img { width: 100%; height: 100%; object-fit: cover; display: block;
    transition: transform var(--dur-slow) var(--ease-out); }
  .product-card:hover .product-card__media img { transform: scale(1.035); }
  .product-card__ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    background:
      radial-gradient(120% 90% at 50% 0%, var(--neutral-50), var(--neutral-100));
    color: var(--neutral-300); }
  .product-card__ph svg { width: 38%; height: 38%; }
  .product-card__badges { position: absolute; top: 10px; left: 10px; display: flex; gap: 6px; }
  .product-card__fav { position: absolute; top: 8px; right: 8px; width: 34px; height: 34px;
    border-radius: 50%; border: none; background: rgba(250,248,243,0.85); backdrop-filter: blur(4px);
    color: var(--neutral-600); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
    transition: color var(--dur-fast), background var(--dur-fast); }
  .product-card__fav:hover { color: var(--error-600); background: var(--surface-card); }
  .product-card__fav svg { width: 17px; height: 17px; }
  .product-card__body { padding: 13px 2px 4px; display: flex; flex-direction: column; gap: 5px; }
  .product-card__eyebrow { font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: 0.12em;
    text-transform: uppercase; color: var(--text-subtle); }
  .product-card__title { font-family: var(--font-serif); font-size: var(--text-lg); font-weight: 500;
    color: var(--text-strong); line-height: 1.25; letter-spacing: -0.01em; }
  .product-card__meta { display: flex; align-items: center; justify-content: space-between; margin-top: 3px; }
  .product-card__price { display: flex; align-items: baseline; gap: 7px; font-family: var(--font-mono); }
  .product-card__price b { font-size: var(--text-base); font-weight: 600; color: var(--text-strong); }
  .product-card__price s { font-size: var(--text-sm); color: var(--text-subtle); text-decoration: line-through; }
  .product-card__swatches { display: flex; gap: 5px; }
  .product-card__swatch { width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(20,22,15,0.15); }
  


  .tag {
    display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-sans);
    font-size: var(--text-sm); font-weight: 500; line-height: 1; color: var(--text-body);
    background: var(--surface-card); border: 1px solid var(--border-default);
    border-radius: var(--radius-full); padding: 7px 12px; cursor: default;
    transition: border-color var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard);
  }
  .tag--selectable { cursor: pointer; }
  .tag--selectable:hover { border-color: var(--primary-400); }
  .tag--selected { background: var(--primary-700); border-color: var(--primary-700); color: var(--text-onbrand); }
  /* A selectable tag is a LABEL wrapping a visually-hidden checkbox (see the listing sidebar's
     `fgroup__tags` in tpl/shop/listing.html), so clicking one changes real form state that nothing
     was painting: `.tag--selected` above is written by the SERVER, on the next render, after
     "Zastosuj filtry" is pressed. Until then a shopper clicked "mała" and the tag did not move —
     it read as a filter that refuses to switch on, which is exactly how it was reported. The
     checkbox-style facet in the same sidebar never had this problem because it has always carried
     its own `:checked` rule (`.checkbox input:checked + .checkbox__box`).
     `:has()` and not a sibling combinator because the input is a CHILD of the label, not a
     preceding sibling. A browser without `:has()` support simply falls back to today's behaviour
     (server-rendered `.tag--selected` only), so this needs no feature query of its own. */
  .tag--selectable:has(input:checked) { background: var(--primary-700); border-color: var(--primary-700); color: var(--text-onbrand); }
  /* The OTHER direction, and it is not optional. `.tag--selected` is a class the server wrote onto
     the label; unchecking the box inside cannot take a class off. Without this rule a shopper
     clicking an already-applied filter watched it stay lit — the same "this filter will not
     switch" complaint the rule above fixes, just running the other way. Restates `.tag`'s own
     three values rather than trying to unset them, because `.tag--selected` sets exactly these
     three and there is nothing to inherit them back from. */
  .tag--selectable:has(input:not(:checked)) { background: var(--surface-card); border-color: var(--border-default); color: var(--text-body); }
  /* Hover, restored on top of both states. The revert rule above is (0,2,1) and would otherwise
     outrank `.tag--selectable:hover` (0,2,0), silently costing an un-checked tag its hover
     affordance. On the CHECKED side the hover hint would land `--primary-400` on brand-filled
     ground — but note the case that actually needs guarding is a SERVER-rendered `.tag--selected`
     (0,1,0), which plain `:hover` (0,2,0) outranks; `:has(input:checked)` (0,2,1) already wins on
     its own. Both get the darker `--primary-800` so "on" reads as one state under the pointer. */
  .tag--selectable:has(input:not(:checked)):hover { border-color: var(--primary-400); }
  .tag--selectable:has(input:checked):hover,
  .tag--selected:hover { border-color: var(--primary-800); }
  /* The checkbox inside is `opacity:0`, so it can never show a focus ring of its own. Keyboard
     users had no way to see which tag they were on — the `.checkbox` kind solves the same problem
     with `input:focus-visible + .checkbox__box`. */
  .tag--selectable:has(input:focus-visible) { box-shadow: var(--ring); }
  .tag__remove { display: inline-flex; margin: -2px -4px -2px 0; padding: 2px; border-radius: 50%;
    cursor: pointer; color: inherit; opacity: 0.7; }
  .tag__remove:hover { opacity: 1; background: rgba(0,0,0,0.08); }
  .tag__remove svg { width: 13px; height: 13px; }
  


  .dialog__scrim { position: fixed; inset: 0; background: var(--surface-overlay);
    backdrop-filter: blur(2px); display: flex; align-items: center; justify-content: center;
    padding: var(--space-6); z-index: 1000; animation: dialog-fade var(--dur-base) var(--ease-out); }
  .dialog { background: var(--surface-card); border-radius: var(--radius-xl);
    box-shadow: var(--shadow-xl); width: 100%; max-width: 460px; overflow: hidden;
    animation: dialog-pop var(--dur-base) var(--ease-out); border: 1px solid var(--border-subtle); }
  .dialog--sm { max-width: 380px; }
  .dialog--lg { max-width: 620px; }
  .dialog__head { display: flex; align-items: flex-start; gap: 12px; padding: 22px 24px 0; }
  .dialog__titles { flex: 1; }
  .dialog__title { font-family: var(--font-serif); font-size: var(--text-h3); font-weight: 500;
    color: var(--text-strong); margin: 0; line-height: 1.2; letter-spacing: -0.01em; }
  .dialog__desc { font-family: var(--font-sans); font-size: var(--text-sm); color: var(--text-muted);
    margin: 6px 0 0; line-height: 1.55; }
  .dialog__x { flex: none; width: 34px; height: 34px; border: none; background: transparent;
    border-radius: var(--radius-sm); cursor: pointer; color: var(--text-muted); display: inline-flex;
    align-items: center; justify-content: center; transition: background var(--dur-fast); margin: -4px -6px 0 0; }
  .dialog__x:hover { background: var(--neutral-100); color: var(--text-strong); }
  .dialog__x svg { width: 18px; height: 18px; }
  .dialog__body { padding: 16px 24px; font-family: var(--font-sans); font-size: var(--text-base);
    color: var(--text-body); line-height: 1.6; }
  .dialog__foot { display: flex; justify-content: flex-end; gap: 10px; padding: 8px 24px 22px; }
  @keyframes dialog-fade { from { opacity: 0; } }
  @keyframes dialog-pop { from { opacity: 0; transform: translateY(8px) scale(0.98); } }
  @media (prefers-reduced-motion: reduce) {
    .dialog__scrim, .dialog { animation: none; }
  }
  


  .toast { display: flex; align-items: flex-start; gap: 11px; font-family: var(--font-sans);
    background: var(--surface-card-warm); color: var(--text-body); padding: 14px 16px;
    border-radius: var(--radius-md); box-shadow: var(--shadow-md); max-width: 380px;
    border: 1px solid var(--border-default); }
  /* A single, quiet icon — no chip, no competing fills. */
  .toast__icon { flex: none; width: 20px; height: 20px; margin-top: 1px; display: inline-flex;
    align-items: center; justify-content: center; color: var(--primary-600); }
  .toast__icon svg { width: 18px; height: 18px; }
  .toast--danger .toast__icon { color: var(--error-500); }
  .toast--info .toast__icon { color: var(--text-muted); }
  .toast__body { flex: 1; padding-top: 1px; }
  .toast__title { font-size: var(--text-sm); font-weight: 600; line-height: 1.35; color: var(--text-strong); }
  .toast__msg { font-size: var(--text-sm); color: var(--text-muted); margin-top: 2px; line-height: 1.45; }
  .toast__action { background: none; border: none; color: var(--text-brand); font-family: inherit;
    font-size: var(--text-sm); font-weight: 600; cursor: pointer; padding: 0; margin-top: 8px;
    text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--primary-200); }
  .toast__action:hover { text-decoration-color: var(--primary-600); }
  .toast__x { flex: none; background: none; border: none; color: var(--text-subtle); cursor: pointer;
    padding: 2px; margin: -2px -5px 0 0; display: inline-flex; opacity: 0.9; transition: color var(--dur-fast); }
  .toast__x:hover { color: var(--text-body); }
  .toast__x svg { width: 15px; height: 15px; }
  


  .tooltip { position: relative; display: inline-flex; }
  .tooltip__pop { position: absolute; z-index: 900; background: var(--neutral-900); color: var(--neutral-25);
    font-family: var(--font-sans); font-size: var(--text-xs); font-weight: 500; line-height: 1.3;
    padding: 6px 9px; border-radius: var(--radius-sm); white-space: nowrap; pointer-events: none;
    opacity: 0; transform: translateY(2px); box-shadow: var(--shadow-md);
    transition: opacity var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard); }
  .tooltip:hover .tooltip__pop, .tooltip:focus-within .tooltip__pop { opacity: 1; transform: translateY(0); }
  .tooltip__pop::after { content: ''; position: absolute; width: 7px; height: 7px;
    background: var(--neutral-900); transform: rotate(45deg); }
  .tooltip__pop--top { bottom: calc(100% + 8px); left: 50%; translate: -50% 0; }
  .tooltip__pop--top::after { top: 100%; left: 50%; margin: -4px 0 0 -4px; }
  .tooltip__pop--bottom { top: calc(100% + 8px); left: 50%; translate: -50% 0; }
  .tooltip__pop--bottom::after { bottom: 100%; left: 50%; margin: 0 0 -4px -4px; }
  .tooltip__pop--left { right: calc(100% + 8px); top: 50%; translate: 0 -50%; }
  .tooltip__pop--left::after { left: 100%; top: 50%; margin: -4px 0 0 -4px; }
  .tooltip__pop--right { left: calc(100% + 8px); top: 50%; translate: 0 -50%; }
  .tooltip__pop--right::after { right: 100%; top: 50%; margin: -4px -4px 0 0; }
  


  .button {
    --_bg: var(--brand); --_fg: var(--text-onbrand); --_bd: transparent;
    display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
    font-family: var(--font-sans); font-weight: 600; line-height: 1;
    border: 1px solid var(--_bd); background: var(--_bg); color: var(--_fg);
    border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap;
    transition: background var(--dur-fast) var(--ease-standard),
                border-color var(--dur-fast) var(--ease-standard),
                box-shadow var(--dur-fast) var(--ease-standard),
                transform var(--dur-fast) var(--ease-standard);
    -webkit-tap-highlight-color: transparent;
  }
  .button:focus-visible { outline: none; box-shadow: var(--ring); }
  .button:active { transform: translateY(0.5px); }
  .button:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }

  .button--sm { font-size: var(--text-sm); padding: 0 0.75rem; height: 34px; }
  .button--md { font-size: var(--text-sm); padding: 0 1.1rem; height: 42px; }
  .button--lg { font-size: var(--text-base); padding: 0 1.5rem; height: 52px; }
  /* Block buttons may carry long Polish labels ("Wyślij link do zmiany hasła") — let them
     wrap inside narrow cards instead of painting outside the button. */
  .button--block { width: 100%; white-space: normal; height: auto; min-height: 52px; padding-block: 10px; }
  .button--block.button--sm { min-height: 34px; }
  .button--block.button--md { min-height: 42px; }

  .button--primary { --_bg: var(--brand); --_fg: var(--text-onbrand); }
  .button--primary:hover:not(:disabled) { --_bg: var(--brand-hover); }
  .button--primary:active:not(:disabled) { --_bg: var(--brand-active); }

  .button--secondary { --_bg: var(--surface-card); --_fg: var(--text-strong); --_bd: var(--border-strong); }
  .button--secondary:hover:not(:disabled) { --_bg: var(--neutral-50); --_bd: var(--neutral-400); }

  .button--ghost { --_bg: transparent; --_fg: var(--text-brand); --_bd: transparent; }
  .button--ghost:hover:not(:disabled) { --_bg: var(--brand-subtle); }

  .button--accent { --_bg: var(--secondary-500); --_fg: var(--primary-950); }
  .button--accent:hover:not(:disabled) { --_bg: var(--secondary-600); --_fg: var(--white); }

  .button--danger { --_bg: var(--error-600); --_fg: var(--white); }
  .button--danger:hover:not(:disabled) { --_bg: var(--error-700); }

  .button__icon { display: inline-flex; width: 1.15em; height: 1.15em; }
  .button__icon svg { width: 100%; height: 100%; }
  


  .checkbox { display: inline-flex; align-items: flex-start; gap: 10px; font-family: var(--font-sans);
    cursor: pointer; color: var(--text-body); font-size: var(--text-sm); line-height: 1.45; }
  .checkbox--disabled { opacity: 0.5; cursor: not-allowed; }
  .checkbox input { position: absolute; opacity: 0; width: 0; height: 0; }
  .checkbox__box {
    width: 20px; height: 20px; flex: none; border-radius: var(--radius-xs);
    border: 1.5px solid var(--border-strong); background: var(--surface-card);
    display: inline-flex; align-items: center; justify-content: center; margin-top: 1px;
    transition: background var(--dur-fast) var(--ease-standard),
                border-color var(--dur-fast) var(--ease-standard);
  }
  .checkbox__box svg { width: 13px; height: 13px; stroke: var(--text-onbrand); stroke-width: 3;
    fill: none; opacity: 0; transform: scale(0.6); transition: all var(--dur-fast) var(--ease-out); }
  .checkbox input:checked + .checkbox__box { background: var(--brand); border-color: var(--brand); }
  .checkbox input:checked + .checkbox__box svg { opacity: 1; transform: scale(1); }
  .checkbox input:indeterminate + .checkbox__box { background: var(--brand); border-color: var(--brand); }
  .checkbox input:focus-visible + .checkbox__box { box-shadow: var(--ring); }
  .checkbox:hover input:not(:checked):not(:disabled) + .checkbox__box { border-color: var(--primary-500); }
  .checkbox__label small { display: block; color: var(--text-muted); font-size: var(--text-xs); margin-top: 1px; }
  


  .icon-button {
    --_bg: transparent; --_fg: var(--text-body); --_bd: transparent;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--_bg); color: var(--_fg); border: 1px solid var(--_bd);
    border-radius: var(--radius-sm); cursor: pointer; flex: none;
    transition: background var(--dur-fast) var(--ease-standard),
                color var(--dur-fast) var(--ease-standard),
                border-color var(--dur-fast) var(--ease-standard);
  }
  .icon-button:focus-visible { outline: none; box-shadow: var(--ring); }
  .icon-button:disabled { opacity: 0.4; cursor: not-allowed; }
  .icon-button svg { width: 1.25em; height: 1.25em; display: block; }

  .icon-button--sm { width: 34px; height: 34px; font-size: 15px; }
  .icon-button--md { width: 42px; height: 42px; font-size: 17px; }
  .icon-button--lg { width: 50px; height: 50px; font-size: 19px; }

  .icon-button--ghost:hover:not(:disabled) { --_bg: var(--neutral-100); --_fg: var(--text-strong); }
  .icon-button--outline { --_bd: var(--border-strong); --_fg: var(--text-strong); --_bg: var(--surface-card); }
  .icon-button--outline:hover:not(:disabled) { --_bg: var(--neutral-50); --_bd: var(--neutral-400); }
  .icon-button--solid { --_bg: var(--brand); --_fg: var(--text-onbrand); }
  .icon-button--solid:hover:not(:disabled) { --_bg: var(--brand-hover); }
  


  .field { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans); }
  .field__label { font-size: var(--text-sm); font-weight: 500; color: var(--text-strong); }
  .field__req { color: var(--error-600); margin-left: 2px; }
  .field__hint { font-size: var(--text-xs); color: var(--text-muted); }
  .field__hint--error { color: var(--error-600); }

  .input-wrap {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface-card); border: 1px solid var(--border-default);
    border-radius: var(--radius-sm); padding: 0 12px; height: 44px;
    transition: border-color var(--dur-fast) var(--ease-standard),
                box-shadow var(--dur-fast) var(--ease-standard);
  }
  .input-wrap:hover { border-color: var(--border-strong); }
  .input-wrap:focus-within { border-color: var(--border-focus); box-shadow: var(--ring); }
  .input-wrap--error { border-color: var(--error-500); }
  .input-wrap--error:focus-within { box-shadow: 0 0 0 3px rgba(176,73,47,0.25); }
  .input-wrap--disabled { background: var(--surface-sunken); opacity: 0.7; cursor: not-allowed; }

  .input {
    flex: 1; border: none; outline: none; background: transparent;
    font-family: var(--font-sans); font-size: var(--text-base); color: var(--text-strong);
    min-width: 0; height: 100%;
  }
  .input::placeholder { color: var(--text-subtle); }
  .input:disabled { cursor: not-allowed; }
  .input-wrap__adorn { display: inline-flex; align-items: center; color: var(--text-muted); flex: none; }
  .input-wrap__adorn svg { width: 18px; height: 18px; }

  /* ── Auth / notice card (login, register, password reset) ──────────── */
  .auth-page { padding: var(--space-16) var(--gutter) var(--space-24); }
  .auth-card { max-width: 440px; margin: 0 auto; background: var(--surface-card);
    border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
    padding: clamp(20px, 7vw, var(--space-10)); }
  .auth-card__head { text-align: center; margin-bottom: var(--space-8); }
  .auth-card__title { font-family: var(--font-serif); font-weight: 500;
    font-size: clamp(1.5rem, 7vw, var(--text-h2)); letter-spacing: -0.02em;
    color: var(--text-strong); margin: 10px 0 6px; }
  .auth-card__subtitle { font-size: var(--text-sm); color: var(--text-muted); margin: 0; }
  .auth-card .field { margin-bottom: 16px; }
  .auth-card__note { text-align: center; font-size: var(--text-sm); color: var(--text-muted); margin-top: 18px; }
  .auth-card__note--subtle { font-size: var(--text-xs); color: var(--text-subtle); margin-top: 10px; }
  .auth-card__note a { color: var(--text-link); font-weight: 500; }

  /* Inline feedback note (form error / success) */
  .alert { border-radius: var(--radius-sm); padding: 10px 12px; font-size: var(--text-sm); margin-bottom: 16px; }
  .alert--error { background: var(--error-100); color: var(--error-700); }
  .alert--success { background: var(--success-100); color: var(--success-700); }

  .quantity { display: inline-flex; align-items: center; background: var(--surface-card);
    border: 1px solid var(--border-default); border-radius: var(--radius-sm); height: 44px;
    font-family: var(--font-sans); overflow: hidden; }
  .quantity--sm { height: 36px; }
  .quantity__btn { width: 42px; height: 100%; border: none; background: transparent; cursor: pointer;
    color: var(--text-strong); display: inline-flex; align-items: center; justify-content: center;
    font-size: 18px; transition: background var(--dur-fast) var(--ease-standard); flex: none; }
  .quantity--sm .quantity__btn { width: 34px; }
  .quantity__btn:hover:not(:disabled) { background: var(--neutral-100); }
  .quantity__btn:disabled { opacity: 0.35; cursor: not-allowed; }
  .quantity__btn:focus-visible { outline: none; box-shadow: inset var(--ring); }
  .quantity__val { min-width: 40px; text-align: center; font-size: var(--text-base);
    font-variant-numeric: tabular-nums; color: var(--text-strong); font-weight: 500;
    border-left: 1px solid var(--border-subtle); border-right: 1px solid var(--border-subtle);
    align-self: stretch; display: inline-flex; align-items: center; justify-content: center; }
  


  .radio { display: inline-flex; align-items: flex-start; gap: 10px; font-family: var(--font-sans);
    cursor: pointer; color: var(--text-body); font-size: var(--text-sm); line-height: 1.45; }
  .radio--disabled { opacity: 0.5; cursor: not-allowed; }
  .radio input { position: absolute; opacity: 0; width: 0; height: 0; }
  .radio__dot {
    width: 20px; height: 20px; flex: none; border-radius: var(--radius-full);
    border: 1.5px solid var(--border-strong); background: var(--surface-card);
    display: inline-flex; align-items: center; justify-content: center; margin-top: 1px;
    transition: border-color var(--dur-fast) var(--ease-standard);
  }
  .radio__dot::after { content: ''; width: 9px; height: 9px; border-radius: var(--radius-full);
    background: var(--brand); transform: scale(0); transition: transform var(--dur-fast) var(--ease-out); }
  .radio input:checked + .radio__dot { border-color: var(--brand); }
  .radio input:checked + .radio__dot::after { transform: scale(1); }
  .radio input:focus-visible + .radio__dot { box-shadow: var(--ring); }
  .radio:hover input:not(:checked):not(:disabled) + .radio__dot { border-color: var(--primary-500); }
  .radio__label small { display: block; color: var(--text-muted); font-size: var(--text-xs); margin-top: 1px; }
  


  .select-field { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans); }
  .select-field__label { font-size: var(--text-sm); font-weight: 500; color: var(--text-strong); }
  .select-wrap { position: relative; display: flex; align-items: center; }
  .select {
    appearance: none; -webkit-appearance: none; width: 100%;
    font-family: var(--font-sans); font-size: var(--text-base); color: var(--text-strong);
    background: var(--surface-card); border: 1px solid var(--border-default);
    border-radius: var(--radius-sm); height: 44px; padding: 0 38px 0 12px; cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard);
  }
  .select:hover { border-color: var(--border-strong); }
  .select:focus-visible { outline: none; border-color: var(--border-focus); box-shadow: var(--ring); }
  .select:disabled { background: var(--surface-sunken); opacity: 0.7; cursor: not-allowed; }
  .select-wrap__chev {
    position: absolute; right: 12px; pointer-events: none; color: var(--text-muted);
    width: 16px; height: 16px;
  }
  .select-field__hint { font-size: var(--text-xs); color: var(--text-muted); }
  


  .switch { display: inline-flex; align-items: center; gap: 10px; font-family: var(--font-sans);
    cursor: pointer; color: var(--text-body); font-size: var(--text-sm); }
  .switch--disabled { opacity: 0.5; cursor: not-allowed; }
  .switch input { position: absolute; opacity: 0; width: 0; height: 0; }
  .switch__track {
    width: 40px; height: 24px; flex: none; border-radius: var(--radius-full);
    background: var(--neutral-300); position: relative;
    transition: background var(--dur-base) var(--ease-standard);
  }
  .switch__track::after {
    content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
    border-radius: var(--radius-full); background: var(--white); box-shadow: var(--shadow-sm);
    transition: transform var(--dur-base) var(--ease-out);
  }
  .switch input:checked + .switch__track { background: var(--brand); }
  .switch input:checked + .switch__track::after { transform: translateX(16px); }
  .switch input:focus-visible + .switch__track { box-shadow: var(--ring); }
  


  .breadcrumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    font-family: var(--font-sans); font-size: var(--text-sm); }
  .breadcrumbs a, .breadcrumbs span.breadcrumb { color: var(--text-muted); text-decoration: none;
    transition: color var(--dur-fast) var(--ease-standard); }
  .breadcrumbs a:hover { color: var(--text-brand); }
  .breadcrumbs__sep { color: var(--neutral-300); display: inline-flex; }
  .breadcrumbs__sep svg { width: 14px; height: 14px; }
  .breadcrumbs [aria-current="page"] { color: var(--text-strong); font-weight: 500; }
  


  .tabs { display: inline-flex; font-family: var(--font-sans); position: relative; }
  .tabs--line { gap: 4px; border-bottom: 1px solid var(--border-default); }
  .tabs--pill { gap: 4px; background: var(--surface-sunken); padding: 4px; border-radius: var(--radius-md); }
  .tab { appearance: none; border: none; background: transparent; cursor: pointer;
    font-family: inherit; font-size: var(--text-sm); font-weight: 500; color: var(--text-muted);
    padding: 10px 14px; display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
    transition: color var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard); }
  .tab:hover { color: var(--text-strong); }
  .tab:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-sm); }
  .tabs--line .tab { position: relative; }
  /* [aria-current="page"] alongside [aria-selected="true"] — the same .tabs--line/.tabs--pill
     classes style both a real JS tab widget (aria-selected) and plain server-navigation links to
     different pages (aria-current, e.g. the account page's tab-styled nav), so both attributes
     need to trigger the active look. */
  .tabs--line .tab[aria-selected="true"], .tabs--line .tab[aria-current="page"] { color: var(--text-brand); }
  .tabs--line .tab[aria-selected="true"]::after, .tabs--line .tab[aria-current="page"]::after { content: ''; position: absolute;
    left: 8px; right: 8px; bottom: -1px; height: 2px; background: var(--brand); border-radius: 2px; }
  .tabs--pill .tab { border-radius: var(--radius-sm); padding: 7px 14px; }
  .tabs--pill .tab[aria-selected="true"], .tabs--pill .tab[aria-current="page"] { background: var(--surface-card); color: var(--text-strong);
    box-shadow: var(--shadow-xs); }
  .tab__count { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--text-subtle); }
  


  * { box-sizing: border-box; }
  .k-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
    font-family: var(--font-sans); font-weight: 600; line-height: 1; border: 1px solid transparent;
    border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap; text-decoration: none;
    transition: background var(--dur-fast) var(--ease-standard), border-color var(--dur-fast), transform var(--dur-fast); }
  .k-btn:active { transform: translateY(0.5px); }
  .k-btn:disabled { opacity: 0.45; cursor: not-allowed; }
  .k-btn--sm { font-size: var(--text-sm); height: 36px; padding: 0 0.85rem; }
  .k-btn--md { font-size: var(--text-sm); height: 44px; padding: 0 1.15rem; }
  .k-btn--lg { font-size: var(--text-base); height: 54px; padding: 0 1.6rem; }
  .k-btn--block { width: 100%; }
  .k-btn--primary { background: var(--brand); color: var(--text-onbrand); }
  .k-btn--primary:hover { background: var(--brand-hover); }
  .k-btn--secondary { background: var(--surface-card); color: var(--text-strong); border-color: var(--border-strong); }
  .k-btn--secondary:hover { background: var(--neutral-50); border-color: var(--neutral-400); }
  .k-btn--ghost { background: transparent; color: var(--text-brand); }
  .k-btn--ghost:hover { background: var(--brand-subtle); }
  .k-btn--accent { background: var(--secondary-500); color: var(--primary-950); }
  .k-btn--accent:hover { background: var(--secondary-600); color: #fff; }

  .k-iconbtn { display: inline-flex; align-items: center; justify-content: center; flex: none;
    border: 1px solid transparent; background: transparent; color: var(--text-body);
    border-radius: var(--radius-sm); cursor: pointer; width: 42px; height: 42px;
    transition: background var(--dur-fast), color var(--dur-fast); position: relative; }
  .k-iconbtn:hover { background: var(--neutral-100); color: var(--text-strong); }
  .k-iconbtn--sm { width: 36px; height: 36px; }
  .k-count { position: absolute; top: 3px; right: 3px; min-width: 17px; height: 17px; padding: 0 4px;
    border-radius: 999px; background: var(--secondary-500); color: var(--primary-950); font-family: var(--font-mono);
    font-size: 10px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }

  .k-badge { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-sans);
    font-size: var(--text-xs); font-weight: 600; line-height: 1; padding: 4px 9px; border-radius: 999px;
    border: 1px solid transparent; white-space: nowrap; }
  .k-badge--accent { background: var(--secondary-100); color: var(--secondary-700); border-color: var(--secondary-200); }
  .k-badge--brand { background: var(--primary-50); color: var(--primary-700); border-color: var(--primary-100); }
  .k-badge--success { background: var(--success-100); color: var(--success-600); }
  .k-badge--danger { background: var(--error-100); color: var(--error-700); }
  .k-badge--neutral { background: var(--neutral-100); color: var(--neutral-700); border-color: var(--neutral-200); }
  .k-badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

  .k-tag { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-sans);
    font-size: var(--text-sm); font-weight: 500; color: var(--text-body); background: var(--surface-card);
    border: 1px solid var(--border-default); border-radius: 999px; padding: 7px 13px; cursor: pointer;
    transition: border-color var(--dur-fast), background var(--dur-fast), color var(--dur-fast); }
  .k-tag:hover { border-color: var(--primary-400); }
  .k-tag--on { background: var(--primary-700); border-color: var(--primary-700); color: var(--text-onbrand); }

  .k-rating { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-sans); }
  .k-rating__stars { display: inline-flex; gap: 1px; color: var(--secondary-500); }
  .k-rating__count { font-size: var(--text-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }

  .k-qty { display: inline-flex; align-items: center; background: var(--surface-card);
    border: 1px solid var(--border-default); border-radius: var(--radius-sm); height: 44px; overflow: hidden; }
  .k-qty button { width: 42px; height: 100%; border: none; background: transparent; cursor: pointer;
    color: var(--text-strong); font-size: 18px; display: inline-flex; align-items: center; justify-content: center; }
  .k-qty button:hover:not(:disabled) { background: var(--neutral-100); }
  .k-qty button:disabled { opacity: 0.35; cursor: not-allowed; }
  .k-qty span { min-width: 40px; text-align: center; font-size: var(--text-base); font-weight: 500;
    font-variant-numeric: tabular-nums; color: var(--text-strong); border-left: 1px solid var(--border-subtle);
    border-right: 1px solid var(--border-subtle); align-self: stretch; display: inline-flex; align-items: center; justify-content: center; }

  .k-input { width: 100%; font-family: var(--font-sans); font-size: var(--text-base); color: var(--text-strong);
    background: var(--surface-card); border: 1px solid var(--border-default); border-radius: var(--radius-sm);
    height: 44px; padding: 0 13px; transition: border-color var(--dur-fast), box-shadow var(--dur-fast); }
  .k-input::placeholder { color: var(--text-subtle); }
  .k-input:focus { outline: none; border-color: var(--border-focus); box-shadow: var(--ring); }

  .k-pmedia { position: relative; aspect-ratio: 4/5; border-radius: var(--radius-md); overflow: hidden;
    border: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: center; }
  .k-pmedia__mark { width: 34%; height: 34%; color: rgba(47,65,53,0.18); }
  .k-crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-family: var(--font-sans); font-size: var(--text-sm); }
  .k-crumbs a { color: var(--text-muted); text-decoration: none; }
  .k-crumbs a:hover { color: var(--text-brand); }
  .k-crumbs .k-sep { color: var(--neutral-300); display: inline-flex; }
  .k-crumbs .k-now { color: var(--text-strong); font-weight: 500; }
  /* ===================== Site layout & components ===================== */
/* ───────────────────────────────────────────────────────────
   Two Shelves site — layout & component styles.
   Built on the design-system tokens (colors / type / spacing / elevation).
   Mood themes via [data-mood="paper" | "forest"] on the app root.
   ─────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--surface-page); color: var(--text-body);
  font-family: var(--font-sans); -webkit-font-smoothing: antialiased; }
img { max-width: 100%; display: block; }
::selection { background: var(--primary-200); }

.storefront { min-height: 100vh; display: flex; flex-direction: column; }
.storefront > main { flex: 1; }

/* Off-screen until focused (Tab from the very top of the page) — a keyboard user can then jump
   straight past the announcement bar/header/mobile-nav to the page's actual content. */
.skip-link { position: absolute; top: -100%; left: 0; z-index: 1000; padding: 12px 20px;
  background: var(--primary-900); color: var(--neutral-25); font-family: var(--font-sans);
  font-size: var(--text-sm); font-weight: 600; text-decoration: none; border-radius: 0 0 var(--radius-sm) 0; }
.skip-link:focus { top: 0; }

/* The page content rail: every section centres its content in this container. Width is
   token-driven — override --container-xl / --gutter to re-measure the whole storefront. */
.site-container { width: 100%; max-width: var(--container-xl); margin: 0 auto; padding: 0 var(--gutter); }

/* Theme accent driver (set per mood / tweak) */
.storefront { --accent-strong: var(--secondary-500); --accent-ink: var(--primary-950); }

/* Defensive line-height baseline so serif headings never collapse / overlap
   when they wrap. Explicitly-set line-heights (hero etc.) win on specificity. */
.storefront :is(h1, h2, h3, h4) { line-height: 1.18; }

/* ── Eyebrow / section heads ───────────────────────────────────────── */
.eyebrow { font-family: var(--font-mono); font-size: var(--text-2xs);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-muted);
  display: inline-block; }
.section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
  margin-bottom: var(--space-10); }
.section-head[data-align="center"] { flex-direction: column; align-items: center; text-align: center; }
.section-head__title { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-h2);
  line-height: var(--leading-snug); letter-spacing: var(--tracking-snug); color: var(--text-strong);
  margin: 8px 0 0; text-wrap: balance; }

/* ── Announcement bar ──────────────────────────────────────────────── */
.announce-bar { background: var(--primary-800); color: var(--neutral-100);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  height: 38px; display: flex; align-items: center; }
.announce-bar span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.announce-bar svg { color: var(--secondary-400); }

/* ── Cookie-consent banner (RODO) ──────────────────────────────────────
   LOCKED compliance zone. A tenant stylesheet may RECOLOUR it via tokens, but MUST NOT
   hide it (no display:none) — consent gating is a legal requirement, server-enforced too.
   Class-free on purpose: a singleton (#consent) whose colours track --primary-900 /
   --text-onbrand and whose two actions are the cancel default + the [value="all"] accept. */
#consent { position: fixed; left: 0; right: 0; bottom: 0; z-index: 90; box-sizing: border-box;
  width: 100%; background: var(--primary-900); color: var(--text-onbrand); padding: 16px var(--gutter); }
#consent > div { width: 100%; max-width: var(--container-xl); margin: 0 auto;
  display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
#consent p { margin: 0; flex: 1; min-width: min(260px, 100%); font-size: 14px; line-height: 1.55; }
#consent a { color: inherit; text-decoration: underline; }
#consent form { display: flex; gap: 10px; flex-wrap: wrap; }
#consent button { padding: 10px 16px; font: inherit; font-size: 14px; cursor: pointer;
  background: transparent; color: var(--text-onbrand);
  border: 1px solid color-mix(in srgb, var(--text-onbrand) 45%, transparent); }
#consent button[value="all"] { background: var(--text-onbrand); color: var(--primary-900); border-color: var(--text-onbrand); }

/* ── Header ────────────────────────────────────────────────────────── */
.site-header { position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--surface-page) 88%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-subtle); }
.site-header__logo { display: inline-flex; text-decoration: none; flex: none; color: var(--primary-700); }
.site-header__logo svg { display: block; }
.site-nav { display: flex; align-items: center; gap: 4px; margin-left: 12px; }

/* Header search (the lupa → a live GET form posting to /szukaj). Hidden on mobile, where
   search is reachable from the burger drawer instead. */
.search { display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 12px;
  border: 1px solid var(--border-default); border-radius: var(--radius-sm);
  background: var(--surface-card); color: var(--text-muted);
  transition: border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard); }
.search:hover { border-color: var(--border-strong); }
.search:focus-within { border-color: var(--border-focus); box-shadow: var(--ring); color: var(--text-strong); }
.search__icon { display: inline-flex; flex: none; }
.search__icon svg { width: 18px; height: 18px; display: block; }
.search__input { border: none; outline: none; background: transparent; min-width: 0; width: 150px;
  font-family: var(--font-sans); font-size: var(--text-sm); color: var(--text-strong); }
.search__input::placeholder { color: var(--text-subtle); }
/* Combined language/currency picker — ONE <details>/<summary> disclosure replacing the old flat
   `.lang-switch`/`.cur-switch` rows (see `tpl/_locale_switch.html` for why <details>, not a JS
   dropdown: it must work with zero JavaScript). `.locale-switch` itself is the positioning
   context for its panel — `position: relative` is load-bearing, not decorative. */
.locale-switch { position: relative; }
.locale-switch__summary { display: flex; align-items: center; gap: 4px; list-style: none;
  cursor: pointer; font-size: 13px; font-weight: 600; color: var(--text-body);
  padding: 8px 6px; border-radius: var(--radius-sm); user-select: none;
  transition: background var(--dur-fast), color var(--dur-fast); }
.locale-switch__summary:hover { background: var(--surface-sunken); color: var(--text-strong); }
/* Kill both browsers' native disclosure marker (the triangle) — the chevron icon after the state
   text is the marker now, and drawing both would duplicate the affordance. */
.locale-switch__summary::-webkit-details-marker { display: none; }
.locale-switch__summary::marker { content: ""; }
.locale-switch__state { max-width: 14ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Chevron flips on open — a free, CSS-only "expanded" affordance `<details>` gives for nothing
   (`[open]` is the browser's own reflection of the disclosure state, not a class we maintain). */
.locale-switch__summary svg { color: var(--text-muted); transition: transform var(--dur-fast) var(--ease-standard); }
.locale-switch[open] .locale-switch__summary svg { transform: rotate(180deg); }
/* The panel: absolutely positioned so opening it can NEVER push the header's own layout around
   (a flex/grid sibling of the summary would otherwise reflow the whole bar), right-aligned to the
   summary rather than the header edge (there's more free room to the left, under the nav/search,
   than to the right, under the 3 icon buttons) — see `tpl/_locale_switch.html` for the summary
   markup this positions against. No ancestor between here and `.site-header` sets
   `overflow: hidden` (checked — `.site-header`, `.site-header__bar`, `.site-header__actions`,
   `.storefront` are all overflow:visible), which is the classic trap that would silently clip a
   `<details>` panel in a header. `z-index: 1` only has to beat OTHER positioned children within
   `.site-header`'s own stacking context (the icon buttons after it in the DOM, each
   `position: relative` for their count badge) — the panel opens downward past the 72px header row
   so it doesn't actually overlap them today, but a future header tweak shouldn't get to silently
   flip that by DOM order alone. Beating `<main>` below the header needs no z-index here at all:
   `.site-header`'s own `z-index: 40` already wins that against a static, unstacked sibling. */
.locale-switch__panel { position: absolute; top: calc(100% + 6px); right: 0; z-index: 1;
  min-width: 190px; background: var(--surface-card); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md); box-shadow: var(--shadow-md); padding: 10px; display: flex;
  flex-direction: column; gap: 12px; }
.locale-switch__group { display: flex; flex-direction: column; gap: 2px; }
.locale-switch__group-label { margin: 0 0 2px; padding: 0 8px; font-family: var(--font-mono);
  font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-subtle); }
.locale-switch__group a, .locale-switch__group [aria-current] { display: block; padding: 7px 8px;
  border-radius: var(--radius-sm); font-size: var(--text-sm); text-decoration: none; color: var(--text-body); }
.locale-switch__group a:hover { background: var(--surface-sunken); color: var(--text-strong); }
/* color, not opacity — opacity blends the inherited text down against the panel background hard
   enough to drop it under WCAG AA's 4.5:1 (a fixed color doesn't blend). */
.locale-switch__group [aria-current] { color: var(--text-muted); font-weight: 600; }
/* The desktop header (logo + 5 nav links + search + 3 icon buttons) needs ~1105px — below
   that the nav wrapped to two lines (iPad landscape!) or overflowed. Collapse to the
   burger early enough that one line always fits. */
@media (max-width: 1120px) { .search { display: none; } }
/* Same reasoning for the picker — an enabled multi-currency shop has no room next to the 3 icon
   buttons once the desktop nav is already gone. Moves into the mobile-nav drawer instead
   (`.mobile-nav__switch`, its own flat list — see that component's own comment for why it does
   NOT reuse this `<details>`) rather than disappearing outright. */
@media (max-width: 1120px) { .locale-switch { display: none; } }

/* Search results page: the prominent query field above the result grid. */
.search-form { display: flex; gap: 10px; align-items: stretch; max-width: 560px; margin: 6px 0 30px; }
.search-form .input-wrap { flex: 1; }
.site-nav__link { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 500;
  color: var(--text-body); text-decoration: none; padding: 9px 12px; border-radius: var(--radius-sm);
  transition: color var(--dur-fast), background var(--dur-fast); }
.site-nav__link:hover { color: var(--text-strong); background: var(--surface-sunken); }
.site-header__actions { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.icon-button { position: relative; width: 42px; height: 42px; border: 1px solid transparent;
  background: transparent; color: var(--text-body); border-radius: var(--radius-sm); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast), color var(--dur-fast); }
.icon-button:hover { background: var(--surface-sunken); color: var(--text-strong); }
.icon-button__count { position: absolute; top: 4px; right: 4px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: var(--accent-strong); color: var(--accent-ink); font-family: var(--font-mono);
  font-size: 10px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }
.icon-button__count[hidden] { display: none; }
.nav-burger { display: none; width: 40px; height: 40px; border: none; background: transparent;
  color: var(--text-strong); cursor: pointer; align-items: center; justify-content: center; border-radius: var(--radius-sm); }
.mobile-nav { display: none; flex-direction: column; padding: 8px var(--gutter) 16px; gap: 2px;
  border-top: 1px solid var(--border-subtle); background: var(--surface-page); }
.mobile-nav a { font-family: var(--font-serif); font-size: var(--text-h4); color: var(--text-strong);
  text-decoration: none; padding: 10px 4px; border-bottom: 1px solid var(--border-subtle); }
/* Language/currency switch, moved here from the header actions row (it has no room there on
   mobile — see the `@media (max-width: 1120px) { .locale-switch { display: none } }` rule above).
   A flat row rather than a second `<details>`: nesting one inside the drawer's own disclosure
   would trade the solved problem (header crowding) for a worse one. Overrides `.mobile-nav a`'s
   heavy serif nav-link style back down to a compact inline code row. */
.mobile-nav__switch { display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  padding: 12px 4px 4px; font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.04em; }
.mobile-nav .mobile-nav__switch a, .mobile-nav .mobile-nav__switch span { font: inherit;
  color: var(--text-body); text-decoration: none; padding: 0; border: 0; }
/* `.mobile-nav` prefixed, not a bare `.mobile-nav__switch [aria-current]` — the reset rule above
   (`.mobile-nav .mobile-nav__switch span`, specificity 0,2,1) would otherwise outrank a plain
   attribute selector (0,2,0) and silently win. Also color, not opacity: opacity blends the
   inherited dark text down against the drawer background hard enough to drop it under WCAG AA's
   4.5:1, and a fixed color doesn't blend. */
.mobile-nav .mobile-nav__switch [aria-current] { color: var(--text-muted); }

/* ── Placeholder notebook art ──────────────────────────────────────── */
.product-cover { position: relative; width: 100%; overflow: hidden; border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center; }
.product-cover__book { position: relative; width: 52%; height: 70%; border-radius: 4px 8px 8px 4px;
  transform: rotate(-3deg); }
.product-cover__pages { position: absolute; top: 4%; right: -7px; width: 9px; height: 92%;
  border-radius: 0 3px 3px 0; box-shadow: inset -1px 0 0 rgba(20,22,15,0.08); }
.product-cover__spine { position: absolute; top: 8%; left: 9px; width: 2px; height: 84%; border-radius: 2px;
  background: repeating-linear-gradient(to bottom, rgba(255,255,255,0.5) 0 5px, transparent 5px 12px); opacity: 0.5; }
.product-cover__band { position: absolute; top: -2%; right: 26%; width: 7px; height: 104%; border-radius: 2px; opacity: 0.85; }
.product-cover__ear { position: absolute; bottom: 0; right: 0; width: 22px; height: 22px;
  background: linear-gradient(135deg, transparent 50%, rgba(250,248,243,0.92) 50%);
  border-radius: 0 0 8px 0; }
.product-cover__ruling { position: absolute; inset: 16% 14% 16% 22%; opacity: 0.18; border-radius: 2px; }
.product-cover__ruling[data-ruling="Ruled"] { background: repeating-linear-gradient(to bottom, transparent 0 9px, rgba(250,248,243,0.9) 9px 10px); }
.product-cover__ruling[data-ruling="Dotted"] { background-image: radial-gradient(rgba(250,248,243,0.95) 1px, transparent 1.4px); background-size: 11px 11px; }
.product-cover__ruling[data-ruling="Grid"] { background-image: linear-gradient(rgba(250,248,243,0.85) 1px, transparent 1px), linear-gradient(90deg, rgba(250,248,243,0.85) 1px, transparent 1px); background-size: 11px 11px; }
.product-cover__label { position: absolute; left: 12px; bottom: 11px; font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.75; }

/* Cover-art paint: split out of the inline format!() string so the cover art is CSS-themeable.
   The two dynamic hues arrive as --cover / --tone (set inline on .product-cover, inherited by
   the children); everything else is the fixed recipe a tenant can override by re-declaring. */
.product-cover { background: radial-gradient(125% 100% at 50% 8%, var(--tone), color-mix(in srgb, var(--tone) 62%, var(--neutral-200))); }
.product-cover__book { background: var(--cover); box-shadow: 0 18px 34px -18px rgba(22,31,25,0.55), inset 0 0 0 1px rgba(255,255,255,0.06); }
.product-cover__pages { background: color-mix(in srgb, #FAF8F3 88%, var(--cover)); }
.product-cover__band { background: color-mix(in srgb, var(--cover) 62%, #14160F); }
.product-cover__label { color: rgba(20,22,15,0.55); }

/* ── Product tile ──────────────────────────────────────────────────── */
.product-tile { display: flex; flex-direction: column; text-decoration: none; color: inherit; min-width: 0; }
.product-tile__media { position: relative; }
.product-tile__media .product-cover { transition: transform var(--dur-slow) var(--ease-out); }
.product-tile:hover .product-tile__media .product-cover { transform: translateY(-3px); }
.product-tile__badge { position: absolute; top: 10px; left: 10px; }
.product-tile__fav { position: absolute; top: 8px; right: 8px; width: 34px; height: 34px; border: none;
  border-radius: 50%; background: rgba(250,248,243,0.85); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  color: var(--neutral-600); cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: color var(--dur-fast), background var(--dur-fast); }
.product-tile__fav:hover { color: var(--error-600); background: var(--surface-card); }
.product-tile__fav[data-on="1"] { color: var(--error-600); }
.product-tile__body { padding: 13px 2px 4px; display: flex; flex-direction: column; gap: 5px; }
.product-tile__eyebrow { font-family: var(--font-mono); font-size: var(--text-2xs); letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--text-subtle); }
.product-tile__title { font-family: var(--font-serif); font-size: var(--text-lg); font-weight: 500;
  color: var(--text-strong); line-height: 1.25; letter-spacing: -0.01em; }
/* Wraps: price + struck compare + swatches are ~186px of unbreakable min-content — in a
   ~110px phone-grid column they must stack, not stretch the track. */
.product-tile__meta { display: flex; align-items: center; justify-content: space-between; margin-top: 3px;
  flex-wrap: wrap; gap: 4px 8px; }
.product-tile__price { display: flex; align-items: baseline; gap: 7px; font-family: var(--font-mono); }
.product-tile__price b { font-size: var(--text-base); font-weight: 600; color: var(--text-strong); }
.product-tile__price s { font-size: var(--text-sm); color: var(--text-subtle); text-decoration: line-through; }
.product-tile__swatches { display: flex; gap: 5px; }
.product-tile__sw { width: 14px; height: 14px; border-radius: 50%; border: 1px solid rgba(20,22,15,0.15); }

/* Product grid. minmax(0,1fr) everywhere: a bare 1fr floors at the tile's min-content
   (the no-wrap price+swatches row), which inflated tracks past phone viewports — the
   reported "images too wide" horizontal scroll. */
.grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-8) var(--space-6); }
/* 3-up variant for grids inside narrower containers (listing, search, wishlist tab).
   Same specificity as .grid, declared BEFORE the responsive blocks below, so the
   2-column phone breakpoint still wins — never hard-code columns inline (it can't
   respond and forces 3 cramped tiles on a phone). */
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* ── Footer ────────────────────────────────────────────────────────── */
.site-footer { background: var(--primary-900); color: var(--neutral-200); margin-top: var(--space-24);
  padding: var(--space-20) 0 var(--space-10); }
.site-footer__top { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: var(--space-12); }
.site-footer__brand > svg { color: var(--neutral-25); margin-bottom: 4px; }
.site-footer__brand p { font-size: var(--text-sm); line-height: var(--leading-relaxed); color: var(--primary-200);
  max-width: 34ch; margin: 18px 0; }
.site-footer__social { display: flex; gap: 8px; }
.site-footer__social a { width: 38px; height: 38px; border: 1px solid var(--primary-700); border-radius: var(--radius-sm);
  display: inline-flex; align-items: center; justify-content: center; color: var(--neutral-200); text-decoration: none;
  transition: background var(--dur-fast), border-color var(--dur-fast); }
.site-footer__social a:hover { background: var(--primary-800); border-color: var(--primary-500); }
/* h2, not h4 — footer content follows `<main>`'s own heading outline (often ending at h1/h2), so
   an h4 here was a heading-order skip; h2 is a safe sibling-or-shallower level regardless of where
   the page body left off (dropping back to a shallower level is valid, only skipping deeper isn't). */
.site-footer__col h2 { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 600; color: var(--neutral-25);
  margin: 0 0 16px; }
.site-footer__col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.site-footer__col a { font-size: var(--text-sm); color: var(--primary-200); text-decoration: none; transition: color var(--dur-fast); }
.site-footer__col a:hover { color: var(--secondary-400); }
/* Both rows wrap: the legal links alone are ~261px of min-content — on a phone the row
   was the single biggest "footer too wide" horizontal-scroll cause. */
.site-footer__bottom { display: flex; align-items: center; justify-content: space-between; margin-top: var(--space-16);
  padding-top: var(--space-6); border-top: 1px solid var(--primary-800); font-family: var(--font-mono);
  font-size: var(--text-xs); color: var(--primary-300); letter-spacing: 0.04em; flex-wrap: wrap; gap: 8px 18px; }
.site-footer__legal { display: flex; gap: 6px 18px; flex-wrap: wrap; }
.site-footer__legal a { color: var(--primary-300); text-decoration: none; }
.site-footer__legal a:hover { color: var(--secondary-400); }

/* ── View transitions (SLICE 3) ───────────────────────────────────────
   The opt-in itself (`@view-transition { navigation: auto }`) is NOT here — it's a per-DOCUMENT
   at-rule, and one document (the admin design-composer's preview iframe) must not carry it, so it
   lives in `tpl/base.html` behind `{% if view_transitions_on %}` (`views::Layout::
   view_transitions_on`'s doc has the why). Everything below is inert without that opt-in present
   in BOTH the old and new document a navigation is between, so none of it needs its own gate.

   What's named, and why:
   - `.site-header__bar` (NOT `.site-header`, see below) — the 72px chrome strip (logo, nav,
     search, action icons), byte-identical on every storefront page, so naming it is what makes the
     browser treat "the header on the old page" and "the header on the new page" as the SAME
     element continuing, rather than fading one out while fading the other in — the flicker the
     brief calls out by name. Named on `.site-header__bar`, deliberately NOT its parent
     `.site-header`: that outer element also contains `.mobile-nav` (`tpl/base.html`), which is a
     plain in-flow child toggled by `display` (`tpl/base.html`'s own `<style>`, plus the
     `@media(min-width:1121px)` override below) — an OPEN mobile menu makes `.site-header`'s own box
     tall, so naming IT would morph a full-height open-menu header down to the 72px bar on the very
     next navigation (the primary mobile nav path). `.site-header__bar` has a fixed 72px height
     (`tpl/base.html`'s inline `style`) regardless of the menu, so it's the part that genuinely
     holds still.
   - The footer is deliberately left UNNAMED. It was named in an earlier draft of this slice and
     removed: `.site-footer` sits in normal document flow, so its viewport rect (and its distance
     from the top of the page) varies by thousands of pixels between a tall listing and a short
     empty-cart page — naming it made the dark footer block sweep across the viewport on navigations
     where nothing about the footer changed, the opposite of "hold still". A sticky header can claim
     a stable identity because it's pinned to a fixed viewport position; a normal-flow footer can't.
   - The two header badges (`#badge-cart` / `#badge-wish`) are also deliberately left UNNAMED — see
     the comment directly above their (removed) declarations, below.
   - `<main>` is deliberately left with NO name, i.e. it takes the default root cross-fade: a
     listing, a product page and the cart are genuinely different shapes and heights, and forcing
     the browser to morph one bounding box between them would read as a lurch, not the "meaning
     something" transition the brief asks for — a plain, fast fade is the honest choice for content
     that really did just change.
   - The product photo (`.product-tile__media`'s cover/img, and the PDP `.pd__hero`'s) gets a name
     DERIVED FROM THE PRODUCT SLUG, set inline per-instance from Rust (`theme::vt_product_name`,
     `controllers::shop::product`) — never here, since it's per-product, not a fixed selector. A
     tile clicked into morphs its own photo straight into the hero instead of the whole viewport
     cross-fading over it. Uniqueness-per-document is handled where the name is minted — see that
     function's doc, and `render::dedupe_view_transition_names` for the page-wide backstop.

   Durations: the UA default for every `::view-transition-*` pseudo is already ~250ms; pulled down
   slightly so this reads as FAST (the brief's own word), not as "the same crossfade every other
   view-transition demo ships". `ease-out`: a transition that's ABOUT TO STOP moving should feel
   like it's arriving, not still accelerating when it's cut off at 180ms. */
::view-transition-group(*) { animation-duration: 200ms; animation-timing-function: ease-out; }
::view-transition-old(*),
::view-transition-new(*) { animation-duration: 180ms; animation-timing-function: ease-out; }

.site-header__bar { view-transition-name: site-header; }

/* `#badge-cart` / `#badge-wish` deliberately carry NO `view-transition-name` of their own. Both
   are server-rendered `hidden` and empty (`tpl/base.html`) — the real counts only arrive later via
   `GET /koszyk/licznik` (`controllers::cart::counters`), an htmx fragment swapped in client-side.
   A cross-document transition captures the OLD document's live, already-patched DOM (a shopper who
   added something to their cart minutes ago has a visible "3") against the NEW document's very
   first paint (always hidden/empty, before that round-trip resolves) — naming the badge would give
   it its own `::view-transition-old(cart-badge)` with no counterpart in the new snapshot, so the
   count ghost-fades OUT on every single navigation and pops back in once htmx lands: exactly the
   flicker this slice exists to remove, self-inflicted. Left unnamed, the badge has no independent
   identity — it's just pixels inside the already-named `.site-header__bar` group above, so the
   (rare) case where its content actually differs between the two captured frames reads as a subtle
   part of that one group's own crossfade, not as a distinct floating element appearing/vanishing.
   Baking the real counts into SSR (so both documents would agree) was considered and rejected here:
   `render::cacheable` marks anonymous listing/product/search pages `public`-cacheable precisely
   because their HTML doesn't depend on session state (`counters`' own doc: "the surrounding page
   HTML no longer bakes these counts in ... so it's safe for a CDN to cache") — reversing that would
   leak one shopper's cart count into another visitor's cached response. Fixing THAT is a separate,
   non-surgical change; dropping the name is the safe fix for this slice. */

/* No movement for a shopper (or merchant reviewing the storefront) who asked for none — dropping
   the animation is the standard reduced-motion pattern for this API (there is nothing to "jump to
   the end state" here the way a `transition`/`animation` on an ordinary element would: the browser
   already swaps DOM + snapshots instantly, ALL the motion lives in these pseudo-elements' own
   animations). The existing `@media (prefers-reduced-motion: reduce) { * { … } }` rule above this
   section can't reach these — `*` matches real DOM nodes, and `::view-transition-*` renders in a
   document-level overlay tree the universal selector doesn't select into. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ═══════════════ Mood: Forest ═══════════════
   A moodier theme — warmer paper, bolder gold, forest section bands. */
.storefront[data-mood="forest"] { --surface-page: #EFEBE1; --accent-strong: var(--secondary-400); --accent-ink: var(--primary-950); }
.storefront[data-mood="forest"] .announce-bar { background: var(--primary-950); }
.storefront[data-mood="forest"] .section-head__title { font-style: italic; }

/* ═══════════════ Responsive ═══════════════ */
@media (max-width: 1120px) {
  .site-nav { display: none; }
  .nav-burger { display: inline-flex; }
  .mobile-nav { display: flex; }
  .site-header__logo { margin-left: 2px; }
}
@media (max-width: 1024px) {
  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .site-footer__top { grid-template-columns: 1fr 1fr; gap: var(--space-10); }
}
@media (max-width: 860px) {
  /* Let the title + action wrap — "Zobacz wszystkie notatniki" next to a section title
     doesn't fit a phone width and would push past the right edge (horizontal scroll). */
  .section-head { align-items: flex-start; flex-wrap: wrap; gap: 10px 24px; }
  .section-head__title { font-size: var(--text-h3); }
}
@media (max-width: 640px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-4); }
  .site-footer__top { grid-template-columns: 1fr 1fr; }
  .announce-bar { font-size: 10px; }
  .announce-bar > div > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  :root { --section-y: var(--space-16); }
}
@media (max-width: 480px) {
  /* The 2-col footer floors at the brand column's min-content (social row + mailto link)
     and overflowed Fold/SE-class widths — stack it. */
  .site-footer__top { grid-template-columns: 1fr; gap: var(--space-8); }
}
@media (max-width: 420px) {
  .product-tile__title { font-size: var(--text-base); }
  /* Compact header: 3×42px icon buttons + logo + burger didn't fit ≤360px. */
  .icon-button { width: 36px; height: 36px; }
  .site-header__logo svg { height: 17px; }
  /* The bar gap is an inline style reading this variable (inline always wins rules). */
  .site-header__bar { --header-gap: 10px; }
  /* Tile chrome scaled for ~110-130px tiles (badge + heart covered the cover art). */
  .product-tile__badge .badge { font-size: 10px; padding: 3px 7px; }
  .product-tile__fav { width: 28px; height: 28px; }
}
@media (max-width: 320px) {
  /* Galaxy Fold class: long no-wrap CTA labels ("Zobacz wszystkie formaty") overflow. */
  .button--lg { white-space: normal; height: auto; min-height: 52px; padding: 10px 1.25rem; text-align: center; }
}
/* The contact block had no rule of its own, so it fell through to `.site-footer__brand p` — the
   BRAND BLURB's styling, including that paragraph's `max-width: 34ch`. That clamp is right for a
   prose sentence and wrong for a postal address: a normal Polish one ("ul. Stryjeńskich 15a/60,
   02-791 Warszawa") is about 40 characters, so it wrapped inside itself and split the postcode
   from the city — the address was all there and still hard to read as an address.
   Wider clamp, and `nowrap` on the whole thing is NOT the fix (a long address would then overflow
   the column); what matters is that the line breaks at a comma rather than mid-postcode, which is
   what a looser measure plus `pretty` gives without forbidding a wrap outright. */
.site-footer__contact { max-width: 46ch; text-wrap: pretty; }
.site-footer__contact a { overflow-wrap: anywhere; color: var(--primary-200); text-decoration: none; }
.site-footer__contact a:hover { color: var(--secondary-400); }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
/* ===================== Page-level styles ===================== */
/* === pages-home.jsx === */

    /* --section-bg / --section-accent: set inline on `.block-hero`'s own root, per placed
       instance, by the section editor's swatch picker (docs/BLOCKS.md, SlotKind::Swatch) — see
       tpl/blocks/hero.html's comment. `var(…, transparent)` / `var(…, var(--primary-700))` are
       the shipped look when nothing is chosen, so an untouched shop renders byte-identically. */
    .home-hero { padding: var(--space-16) 0 var(--space-20); background: var(--section-bg, transparent); }
    .home-hero__grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: var(--space-16); align-items: center; }
    .home-hero__title { font-family: var(--font-serif); font-weight: 500; font-size: clamp(2.6rem, 5.2vw, 4.5rem);
      line-height: 1.04; letter-spacing: -0.025em; color: var(--section-heading, var(--section-text, var(--text-strong))); margin: 18px 0 0; text-wrap: balance; }
    .home-hero__title em { font-style: italic; color: var(--section-accent, var(--primary-700)); }
    .home-hero__sub { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--section-text, var(--text-body));
      max-width: 42ch; margin: 22px 0 30px; }
    .home-hero__cta { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
    .home-hero__trust { display: flex; flex-wrap: wrap; gap: 22px; margin-top: 34px; padding-top: 26px;
      border-top: 1px solid var(--section-line, var(--border-subtle)); }
    .home-hero__trust div { display: flex; align-items: center; gap: 9px; font-family: var(--font-mono);
      font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--section-muted, var(--text-muted)); }
    .home-hero__trust svg { color: var(--section-accent, var(--primary-500)); }

    .home-stage { position: relative; aspect-ratio: 1 / 1; border-radius: var(--radius-2xl);
      background: linear-gradient(160deg, var(--tertiary-100), var(--neutral-100) 60%, var(--primary-50));
      border: 1px solid var(--section-line, var(--border-subtle)); overflow: hidden; box-shadow: var(--shadow-md); }
    .home-stage__grain { position: absolute; inset: 0; opacity: 0.5;
      background-image: radial-gradient(rgba(47,65,53,0.05) 1px, transparent 1.4px); background-size: 18px 18px; }
    .home-stage__book { position: absolute; width: 42%; box-shadow: var(--shadow-lg); border-radius: var(--radius-md); }
    .home-stage__book.b1 { left: 12%; top: 16%; transform: rotate(-7deg); z-index: 2; }
    .home-stage__book.b2 { right: 11%; top: 22%; transform: rotate(5deg); width: 38%; z-index: 1; }
    .home-stage__book.b3 { left: 30%; bottom: 9%; transform: rotate(-2deg); width: 40%; z-index: 3; }
    .home-stage__chip { position: absolute; right: 8%; bottom: 12%; z-index: 5; background: var(--section-surface, var(--surface-card));
      border: 1px solid var(--section-line, var(--border-subtle)); border-radius: var(--radius-md); padding: 10px 14px; box-shadow: var(--shadow-md);
      font-family: var(--font-mono); font-size: 11px; color: var(--section-text, var(--text-body)); display: flex; gap: 9px; align-items: center; }
    .home-stage__chip b { color: var(--section-heading, var(--section-text, var(--text-strong))); }
    .home-stage__chip svg { color: var(--section-accent, var(--secondary-600)); }

    /* --section-bg: see the `.home-hero` comment above for the mechanism. */
    .home-collections { padding: var(--space-12) 0; background: var(--section-bg, transparent); }
    .home-colls { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-6); }
    .coll-card { display: block; text-decoration: none; color: inherit; }
    .coll-card__art { border-radius: var(--radius-lg); overflow: hidden; position: relative; }
    .coll-card:hover .product-cover { transform: scale(1.02); }
    .coll-card .product-cover { transition: transform var(--dur-slow) var(--ease-out); }
    .coll-card__h { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; color: var(--text-strong);
      margin: 16px 0 4px; display: flex; align-items: center; gap: 8px; }
    .coll-card__h svg { color: var(--primary-500); transition: transform var(--dur-base) var(--ease-out); }
    .coll-card:hover .coll-card__h svg { transform: translateX(4px); }
    .coll-card p { font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-normal); margin: 0; max-width: 28ch; }

    /* --section-bg / --section-text: see the `.home-hero` comment above for the mechanism. The
       fallbacks stay the dark `--surface-inverse` + light copy this section always rendered.
       `--section-text` exists because the older note here conceded that a merchant picking a LIGHT
       background got copy still styled for a dark one and called that "the trade-off is theirs" —
       it wasn't a trade-off, it was a missing control: there was no way to lift the text off the
       background they had just chosen. Now there is, and the two travel together. */
    .home-considered { background: var(--section-bg, var(--surface-inverse)); color: var(--section-text, var(--neutral-100)); padding: var(--space-24) 0;
      margin-top: var(--space-16); }
    .home-considered .eyebrow { color: var(--section-accent, var(--secondary-400)); }
    .home-considered__title { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-h1);
      line-height: 1.1; letter-spacing: -0.02em; color: var(--section-heading, var(--section-text, var(--neutral-25))); margin: 14px 0 0; max-width: 16ch; }
    .home-considered__intro { display: grid; grid-template-columns: 1.2fr 1fr; gap: var(--space-12); align-items: end;
      margin-bottom: var(--space-16); }
    .home-considered__intro p { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--section-text, var(--primary-200));
      margin: 0; max-width: 44ch; }
    .home-feats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-10); }
    .home-feat { border-top: 1px solid var(--section-line, var(--primary-700)); padding-top: 22px; }
    .home-feat__ico { width: 46px; height: 46px; border-radius: var(--radius-md); border: 1px solid var(--section-line, var(--primary-600));
      display: inline-flex; align-items: center; justify-content: center; color: var(--section-accent, var(--secondary-400)); margin-bottom: 18px; }
    .home-feat h3 { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; color: var(--section-heading, var(--section-text, var(--neutral-25))); margin: 0 0 8px; }
    .home-feat p { font-size: var(--text-sm); line-height: var(--leading-relaxed); color: var(--section-text, var(--primary-200)); margin: 0 0 14px; }
    .home-feat__spec { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
      color: var(--section-muted, var(--primary-300)); }

    /* --section-bg: see the `.home-hero` comment above for the mechanism. */
    .home-best { padding: var(--space-24) 0 var(--space-12); background: var(--section-bg, transparent); }

    .home-flat { padding: var(--space-16) 0; background: var(--section-bg, transparent); }
    .home-flat__grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: var(--space-16); align-items: center; }
    .home-flat__art { aspect-ratio: 5 / 4; border-radius: var(--radius-xl); overflow: hidden; border: 1px solid var(--section-line, var(--border-subtle));
      background: radial-gradient(120% 100% at 30% 0%, var(--neutral-25), var(--tertiary-100)); position: relative;
      display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-sm); }
    .home-flat__specs { margin: 26px 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
      background: var(--section-line, var(--border-subtle)); border: 1px solid var(--section-line, var(--border-subtle)); border-radius: var(--radius-md); overflow: hidden; }
    .home-flat__specs > div { background: var(--section-surface, var(--surface-card)); padding: 16px 18px; }
    .home-flat__specs dt { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
      color: var(--section-muted, var(--text-subtle)); margin-bottom: 5px; }
    .home-flat__specs dd { margin: 0; font-family: var(--font-serif); font-size: var(--text-h4); color: var(--section-text, var(--text-strong)); }

    .home-news { padding: var(--space-12) 0 0; }
    /* --section-bg: set on `.home-news` (this card's ancestor), not here — it inherits down the
       DOM like any custom property. See the `.home-hero` comment above for the mechanism and
       `.home-considered`'s for why a light token chosen against this card's hardcoded light text
       is the merchant's own trade-off. */
    .home-news__card { background: var(--section-bg, var(--surface-inverse)); border-radius: var(--radius-2xl); padding: var(--space-16);
      display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12); align-items: center; }
    /* --section-text / --section-accent / --section-field: this card's own colours, set inline on
       `.home-news` from the placed instance's props (tpl/blocks/news.html). Each fallback is the
       exact step the card shipped with, so an instance that sets none of them renders unchanged.
       Text, eyebrow and field used to BE those steps, hardcoded — which meant a merchant could
       pick a light card background and have no way to lift the heading off it. */
    .home-news__card h2 { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.75rem, 8vw, var(--text-h1)); line-height: 1.08; overflow-wrap: break-word;
      letter-spacing: -0.02em; color: var(--section-heading, var(--section-text, var(--neutral-25))); margin: 10px 0 0; }
    .home-news__card .eyebrow { color: var(--section-accent, var(--secondary-400)); }
    .home-news__card p { color: var(--section-text, var(--primary-200)); font-size: var(--text-base); line-height: var(--leading-relaxed); margin: 16px 0 0; max-width: 42ch; }
    .home-news__form { display: flex; gap: 10px; }
    .home-news__form input { flex: 1; height: 52px; border-radius: var(--radius-sm); border: 1px solid var(--section-line, var(--primary-600));
      background: var(--section-field, var(--primary-950)); color: var(--section-text, var(--neutral-25)); padding: 0 16px; font-family: var(--font-sans); font-size: var(--text-base); }
    /* The placeholder deliberately keeps the shop-palette step rather than following
       `--section-text`: a placeholder at full text colour stops reading as a placeholder, and
       --primary-300 is a mid tone that stays legible against any field colour the picker offers. */
    .home-news__form input::placeholder { color: var(--section-muted, var(--primary-300)); }
    .home-news__fine { font-family: var(--font-mono); font-size: 11px; color: var(--section-muted, var(--primary-300)); margin-top: 14px; letter-spacing: 0.04em; }

    @media (max-width: 980px) {
      .home-hero__grid { grid-template-columns: 1fr; gap: var(--space-10); }
      .home-stage { max-width: 460px; }
      .home-colls { grid-template-columns: repeat(2, 1fr); gap: var(--space-8); }
      .home-considered__intro { grid-template-columns: 1fr; gap: var(--space-6); }
      .home-feats { grid-template-columns: 1fr; gap: var(--space-8); }
      .home-flat__grid { grid-template-columns: 1fr; }
      .home-news__card { grid-template-columns: 1fr; padding: var(--space-12); }
    }
    @media (max-width: 560px) {
      .home-colls { grid-template-columns: 1fr 1fr; }
      .home-flat__specs { grid-template-columns: 1fr 1fr; }
      .home-news__form { flex-direction: column; }
    }
    /* Forest mood: warmer hero stage, italic hero accents already global */
    .storefront[data-mood="forest"] .home-stage { background: linear-gradient(160deg, var(--tertiary-200), var(--neutral-100) 55%, var(--primary-100)); }
    .storefront[data-mood="forest"] .home-considered { background: var(--primary-950); }
    

/* === pages-shop.jsx === */

    .shop { padding: var(--space-8) 0 var(--space-12); }
    .shop__head { padding: var(--space-6) 0 var(--space-10); border-bottom: 1px solid var(--border-subtle); margin-bottom: var(--space-10); }
    .shop__title { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.75rem, 6.5vw, var(--text-h1)); letter-spacing: -0.02em; overflow-wrap: anywhere;
      color: var(--text-strong); margin: 14px 0 0; }
    .shop__blurb { font-size: var(--text-lg); color: var(--text-body); line-height: var(--leading-relaxed); margin: 12px 0 0; max-width: 52ch; }
    .shop__layout { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: var(--space-12); align-items: start; }
    .shop__layout > * { min-width: 0; }
    .shop__side { position: sticky; top: 96px; display: flex; flex-direction: column; gap: var(--space-8); }
    .fgroup__h { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
      color: var(--text-muted); margin: 0 0 14px; }
    .fgroup__checks { display: flex; flex-direction: column; gap: 12px; }
    .fgroup__tags { display: flex; flex-wrap: wrap; gap: 8px; }
    .fgroup + .fgroup { border-top: 1px solid var(--border-subtle); padding-top: var(--space-8); }
    .shop__toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: var(--space-8); flex-wrap: wrap; }
    .shop__count { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
    .shop__sort { min-width: 190px; }
    @media (max-width: 360px) { .shop__sort { min-width: 0; flex: 1; } .shop__sort .select { width: 100%; } }
    .shop__empty { text-align: center; padding: var(--space-20) 0; color: var(--text-muted); font-family: var(--font-serif); font-size: var(--text-h4); }
    .shop__filterbtn { display: none; }

    .pd { padding: var(--space-8) 0 var(--space-12); }
    .pd__grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: var(--space-16); align-items: start; margin-top: var(--space-8); }
    .pd__gallery { position: sticky; top: 96px; display: flex; flex-direction: column; gap: 14px; }
    .pd__hero { border-radius: var(--radius-xl); overflow: hidden; border: 1px solid var(--border-subtle); box-shadow: var(--shadow-sm); }
    /* flex-wrap: a 5-thumb gallery is 420px of intrinsic min-content — without wrapping
       it inflates the product grid's 1fr track past a phone viewport and the whole page
       scrolls sideways. */
    .pd__thumbs { display: flex; gap: 10px; flex-wrap: wrap; }
    .pd__thumb { width: 76px; border-radius: var(--radius-md); overflow: hidden; border: 1px solid var(--border-default);
      cursor: pointer; padding: 0; background: none; transition: border-color var(--dur-fast); }
    .pd__thumb[data-on="1"] { border-color: var(--primary-700); box-shadow: 0 0 0 1px var(--primary-700); }
    .pd__buy { display: flex; flex-direction: column; }
    .pd__title { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-h1); line-height: 1.06;
      letter-spacing: -0.02em; color: var(--text-strong); margin: 12px 0 14px; }
    .pd__ratingrow { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
    .pd__sku { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; color: var(--text-subtle); }
    .pd__price { display: flex; align-items: baseline; gap: 6px 12px; font-family: var(--font-mono); margin-bottom: 22px; flex-wrap: wrap; }
    .pd__price b { font-size: 28px; font-weight: 600; color: var(--text-strong); }
    .pd__price s { font-size: var(--text-lg); color: var(--text-subtle); text-decoration: line-through; }
    .pd__price .pd__save { font-family: var(--font-sans); font-size: var(--text-sm); font-weight: 600; color: var(--error-600);
      background: var(--error-100); padding: 3px 9px; border-radius: 999px; }
    .pd__lede { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-body); margin: 0 0 26px; }
    .pd__opt { margin-bottom: 22px; }
    .pd__opt__label { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; }
    .pd__opt__label span:first-child { font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); }
    .pd__opt__label span:last-child { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
    .pd__swatches { display: flex; gap: 10px; flex-wrap: wrap; }
    .pd__swatch { width: 40px; height: 40px; border-radius: var(--radius-sm); cursor: pointer; border: 1px solid rgba(20,22,15,0.15);
      position: relative; transition: transform var(--dur-fast); }
    .pd__swatch[data-on="1"] { box-shadow: 0 0 0 2px var(--surface-page), 0 0 0 4px var(--primary-700); }
    .pd__radios { display: flex; flex-wrap: wrap; gap: 10px; }
    .pd__radio { border: 1px solid var(--border-default); border-radius: var(--radius-sm); padding: 11px 14px; cursor: pointer;
      background: var(--surface-card); transition: border-color var(--dur-fast), background var(--dur-fast); flex: 1; min-width: 110px; }
    .pd__radio[data-on="1"] { border-color: var(--primary-700); background: var(--brand-subtle); }
    .pd__radio b { display: block; font-family: var(--font-sans); font-size: var(--text-sm); color: var(--text-strong); font-weight: 600; }
    .pd__radio small { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }
    /* A cover/ruling with no in-stock variant: dimmed so the shopper sees it's unavailable
       (still clickable — the picker resolves to the nearest real variant). */
    .pd__swatch[data-unavail="1"], .pd__radio[data-unavail="1"] { opacity: 0.4; }
    .pd__radio[data-unavail="1"] b { text-decoration: line-through; }
    /* The selected variant's stock state ("Na stanie" / "Ostatnie sztuki: N" / "Brak"). */
    .pd__stock { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
    .pd__actions { display: flex; gap: 12px; align-items: stretch; margin: 8px 0 22px; }
    .pd__wish { width: 52px; flex: none; border: 1px solid var(--border-strong); background: var(--surface-card); border-radius: var(--radius-sm);
      cursor: pointer; color: var(--text-body); display: inline-flex; align-items: center; justify-content: center; transition: color var(--dur-fast), border-color var(--dur-fast); }
    .pd__wish:hover { color: var(--error-600); border-color: var(--neutral-400); }
    .pd__wish[data-on="1"] { color: var(--error-600); }
    .pd__assure { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 18px; padding: 20px; background: var(--surface-card-warm);
      border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); }
    .pd__assure div { display: flex; gap: 11px; align-items: flex-start; font-size: var(--text-sm); color: var(--text-body); line-height: 1.4; }
    .pd__assure svg { color: var(--primary-600); margin-top: 1px; }
    .pd__assure b { color: var(--text-strong); display: block; font-weight: 600; }

    .pd__tabs { margin-top: var(--space-16); border-top: 1px solid var(--border-subtle); padding-top: var(--space-10); }
    .pd__panel { margin-top: var(--space-8); display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--space-12); align-items: start; }
    .pd__panel p { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-body); margin: 0 0 16px; max-width: 60ch; }
    .pd__specs { margin: 0; padding: 0; border: 1px solid var(--border-subtle); border-radius: var(--radius-md); overflow: hidden; }
    .pd__specs > div { display: flex; justify-content: space-between; gap: 16px; padding: 13px 16px; font-size: var(--text-sm); }
    .pd__specs > div:nth-child(odd) { background: var(--surface-card-warm); }
    .pd__specs dt { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); margin: 0; }
    .pd__specs dd { margin: 0; color: var(--text-strong); font-weight: 500; font-variant-numeric: tabular-nums; }

    .pd__reviews { margin-top: var(--space-16); }
    .pd__revhead { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; margin-bottom: var(--space-8); }
    .pd__revscore { font-family: var(--font-serif); font-size: 52px; color: var(--text-strong); line-height: 1; }
    .pd__revgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
    .pd__rev { border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); padding: 20px; background: var(--surface-card); }
    .pd__rev__top { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; }
    .pd__rev__top b { font-size: var(--text-sm); color: var(--text-strong); }
    .pd__rev__top small { font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }
    .pd__rev p { font-size: var(--text-sm); line-height: var(--leading-relaxed); color: var(--text-body); margin: 8px 0 0; }
    .pd__related { margin-top: var(--space-20); }

    @media (max-width: 900px) {
      .shop__layout { grid-template-columns: 1fr; }
      .shop__side { position: static; flex-direction: row; flex-wrap: wrap; gap: var(--space-6); display: none; }
      .shop__side[data-open="1"] { display: flex; }
      .fgroup + .fgroup { border-top: none; padding-top: 0; }
      .shop__filterbtn { display: inline-flex; }
      .pd__grid { grid-template-columns: 1fr; gap: var(--space-10); }
      /* Grid items default to min-width:auto — any wide intrinsic content (long SKU,
         unwrappable row) would silently stretch the 1fr track past the viewport. */
      .pd__grid > * { min-width: 0; }
      .pd__gallery { position: static; }
      .pd__panel { grid-template-columns: 1fr; }
      .pd__revgrid { grid-template-columns: 1fr; }
    }
    @media (max-width: 560px) {
      .pd__assure { grid-template-columns: 1fr; }
      .pd__title { font-size: var(--text-h2); }
    }
    

/* === pages-checkout.jsx === */

    .co { padding: var(--space-8) 0 var(--space-16); }
    .co__title { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.75rem, 7.5vw, var(--text-h1)); letter-spacing: -0.02em;
      color: var(--text-strong); margin: 14px 0 var(--space-10); }
    .co__layout { display: grid; grid-template-columns: 1fr 380px; gap: var(--space-12); align-items: start; }

    .cart__lines { display: flex; flex-direction: column; }
    .cart__line { display: grid; grid-template-columns: 92px 1fr auto; gap: 18px; padding: var(--space-6) 0;
      border-bottom: 1px solid var(--border-subtle); align-items: start; }
    .cart__line:first-child { padding-top: 0; }
    .cart__thumb { width: 92px; border-radius: var(--radius-md); overflow: hidden; border: 1px solid var(--border-subtle); }
    .cart__info h2 { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; line-height: 1.2; color: var(--text-strong); margin: 0 0 5px; }
    .cart__meta { overflow-wrap: anywhere; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; color: var(--text-muted); text-transform: uppercase; margin-bottom: 14px; display: flex; gap: 10px; flex-wrap: wrap; }
    .cart__cover { display: inline-flex; align-items: center; gap: 6px; }
    .cart__dot { width: 11px; height: 11px; border-radius: 50%; border: 1px solid rgba(20,22,15,0.15); }
    .cart__line__right { text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
    .cart__price { font-family: var(--font-mono); font-size: var(--text-lg); font-weight: 600; color: var(--text-strong); }
    .cart__remove { background: none; border: none; cursor: pointer; color: var(--text-subtle); display: inline-flex; align-items: center; gap: 6px;
      font-family: var(--font-sans); font-size: var(--text-xs); transition: color var(--dur-fast); }
    .cart__remove:hover { color: var(--error-600); }
    .cart__foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--space-6); }

    .summary { background: var(--surface-card-warm); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
      padding: var(--space-6); position: sticky; top: 96px; }
    .summary h2 { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; color: var(--text-strong); margin: 0 0 18px; }
    .summary__row { display: flex; justify-content: space-between; gap: 14px; line-height: 1.35; font-size: var(--text-sm); color: var(--text-body); padding: 7px 0; }
    .summary__row span:last-child { white-space: nowrap; }
    .summary__row.t { border-top: 1px solid var(--border-default); margin-top: 8px; padding-top: 16px; font-size: var(--text-lg); color: var(--text-strong); font-weight: 600; }
    .summary__row span:last-child { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
    .summary__free { color: var(--success-600); font-weight: 600; }
    .summary__promo { display: flex; gap: 8px; margin: 16px 0; }
    .summary__promo .field { flex: 1; }
    .summary__note { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; color: var(--text-subtle); text-align: center; margin-top: 14px; text-transform: uppercase; }
    .summary__assure { display: flex; flex-direction: column; gap: 9px; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }
    .summary__assure div { display: flex; gap: 9px; align-items: flex-start; line-height: 1.4; font-size: var(--text-xs); color: var(--text-muted); }
    .summary__assure svg { color: var(--primary-500); margin-top: 1px; flex: none; }

    .co__sec { margin-bottom: var(--space-10); }
    .co__sec__h { display: flex; align-items: center; gap: 12px; margin-bottom: var(--space-6); }
    .co__sec__n { width: 26px; height: 26px; border-radius: 50%; background: var(--brand); color: var(--text-onbrand);
      font-family: var(--font-mono); font-size: 12px; display: inline-flex; align-items: center; justify-content: center; flex: none; }
    .co__sec__h h2 { font-family: var(--font-serif); font-size: var(--text-h3); font-weight: 500; line-height: 1.15; color: var(--text-strong); margin: 0; }
    .co__fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); }
    .co__fields .full { grid-column: 1 / -1; }
    .co__methods { display: flex; flex-direction: column; gap: 12px; }
    .co__method { display: flex; align-items: center; gap: 14px; border: 1px solid var(--border-default); border-radius: var(--radius-md);
      padding: 16px 18px; cursor: pointer; transition: border-color var(--dur-fast), background var(--dur-fast); }
    .co__method[data-on="1"] { border-color: var(--primary-700); background: var(--brand-subtle); }
    .co__method__body { flex: 1; }
    .co__method__body b { display: block; font-size: var(--text-sm); color: var(--text-strong); font-weight: 600; }
    .co__method__body small { font-size: var(--text-xs); color: var(--text-muted); }
    .co__method__price { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); }
    .co__sumline { display: flex; gap: 12px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border-subtle); }
    .co__sumline:last-of-type { border-bottom: none; }
    .co__sumthumb { width: 48px; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border-subtle); flex: none; }
    .co__sumline__info { flex: 1; min-width: 0; font-size: var(--text-sm); }
    .co__sumline__info b { color: var(--text-strong); font-weight: 600; line-height: 1.3; display: block; }
    .co__sumline__info small { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); overflow-wrap: anywhere; }
    .co__sumline__price { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-strong); white-space: nowrap; }

    .cf { max-width: 640px; margin: 0 auto; text-align: center; padding: var(--space-20) 0 var(--space-12); }
    .cf__check { width: 72px; height: 72px; border-radius: 50%; background: var(--primary-50); color: var(--primary-700);
      display: inline-flex; align-items: center; justify-content: center; margin-bottom: var(--space-6); border: 1px solid var(--primary-100); }
    .cf__title { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.9rem, 8.5vw, var(--text-display)); line-height: 1.05; letter-spacing: -0.025em; overflow-wrap: break-word;
      color: var(--text-strong); margin: 0 0 16px; }
    .cf__sub { font-size: var(--text-lg); color: var(--text-body); line-height: var(--leading-relaxed); margin: 0 auto var(--space-10); max-width: 46ch; overflow-wrap: anywhere; }
    .cf__card { text-align: left; background: var(--surface-card); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
      padding: var(--space-6); margin-bottom: var(--space-8); }
    .cf__meta { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px; padding-bottom: 18px; margin-bottom: 18px; border-bottom: 1px solid var(--border-subtle); }
    .cf__meta dt { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-subtle); margin-bottom: 4px; }
    .cf__meta dd { margin: 0; font-family: var(--font-mono); font-size: var(--text-base); color: var(--text-strong); font-weight: 600; }
    .cf__actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

    @media (max-width: 900px) {
      .co__layout { grid-template-columns: 1fr; }
      .summary { position: static; }
      .co__fields { grid-template-columns: 1fr; }
    }
    

/* === pages-account.jsx === */

    .acc { padding: var(--space-8) 0 var(--space-16); }
    .acc__head { display: flex; align-items: center; gap: 18px; padding-bottom: var(--space-8); }
    .acc__head__info { flex: 1; min-width: 0; }
    .acc__head__info h1 { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-h2); line-height: 1.12; color: var(--text-strong); margin: 0; }
    .acc__head__info p { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); margin: 4px 0 0; overflow-wrap: anywhere; }
    .acc__signout { margin-left: auto; }
    .acc__tabs { border-bottom: 1px solid var(--border-subtle); margin-bottom: var(--space-10); overflow-x: auto; }
    .acc__body { min-height: 40vh; }

    .order { border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-card); }
    .order__top { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: var(--space-6); background: var(--surface-card-warm); border-bottom: 1px solid var(--border-subtle); }
    .order__top dl { margin: 0; }
    .order__top dt { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-subtle); }
    .order__top dd { margin: 3px 0 0; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-strong); font-weight: 600; }
    .order__status { margin-left: auto; }
    .order__body { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--space-10); padding: var(--space-8) var(--space-6); }
    .order__items { display: flex; flex-direction: column; gap: 14px; }
    .order__item { display: flex; gap: 14px; align-items: center; }
    .order__item__thumb { width: 56px; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border-subtle); flex: none; }
    .order__item__info { flex: 1; min-width: 0; }
    .order__item__info b { display: block; font-family: var(--font-serif); font-size: var(--text-base); line-height: 1.25; color: var(--text-strong); margin-bottom: 2px; }
    .order__item__info small { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }
    .timeline { display: flex; flex-direction: column; }
    .timeline__step { display: grid; grid-template-columns: 26px 1fr; gap: 14px; position: relative; padding-bottom: 22px; }
    .timeline__step:last-child { padding-bottom: 0; }
    .timeline__dot { width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--border-strong); background: var(--surface-card);
      display: inline-flex; align-items: center; justify-content: center; z-index: 2; color: transparent; }
    .timeline__step[data-done="1"] .timeline__dot { background: var(--primary-700); border-color: var(--primary-700); color: var(--neutral-25); }
    .timeline__step[data-current="1"] .timeline__dot { background: var(--secondary-500); border-color: var(--secondary-500); color: var(--primary-950); box-shadow: 0 0 0 4px var(--secondary-100); }
    .timeline__step::before { content: ''; position: absolute; left: 12px; top: 26px; bottom: 0; width: 2px; background: var(--border-subtle); }
    .timeline__step:last-child::before { display: none; }
    .timeline__step[data-done="1"]::before { background: var(--primary-300); }
    .timeline__label b { font-size: var(--text-sm); color: var(--text-strong); font-weight: 600; }
    .timeline__label small { display: block; font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); margin-top: 2px; }
    .order__track { display: flex; gap: 10px; margin-top: var(--space-6); padding: var(--space-6); border-top: 1px solid var(--border-subtle); flex-wrap: wrap; }

    .acc__empty { text-align: center; padding: var(--space-16) 0; color: var(--text-muted); }
    .acc__empty h2 { font-family: var(--font-serif); font-size: var(--text-h3); color: var(--text-strong); margin: 0 0 10px; }
    .acc__cards { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6); max-width: 760px; }
    .acc__card { border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); padding: var(--space-6); background: var(--surface-card); }
    .acc__card h2 { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; color: var(--text-strong); margin: 0 0 8px; display: flex; align-items: center; gap: 8px; }
    .acc__card address { font-style: normal; font-size: var(--text-sm); line-height: 1.7; color: var(--text-body); }
    .acc__form { max-width: 480px; display: flex; flex-direction: column; gap: var(--space-5); }
    .acc__form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
    .acc__prefs { max-width: 480px; display: flex; flex-direction: column; gap: 18px; margin-top: var(--space-8); padding-top: var(--space-6); border-top: 1px solid var(--border-subtle); }
    .acc__pref { display: flex; align-items: center; justify-content: space-between; gap: 18px; }
    .acc__pref b { font-size: var(--text-sm); color: var(--text-strong); }
    .acc__pref small { display: block; font-size: var(--text-xs); color: var(--text-muted); margin-top: 2px; }

    @media (max-width: 800px) {
      .order__body { grid-template-columns: 1fr; }
      .acc__cards { grid-template-columns: 1fr; }
      .acc__form__row { grid-template-columns: 1fr; }
    }
    

/* === pages-account.jsx === */

    .ab__hero { padding: var(--space-16) 0 var(--space-12); text-align: center; }
    .ab__hero h1 { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.85rem, 8vw, 4rem); line-height: 1.06;
      letter-spacing: -0.025em; color: var(--text-strong); margin: 16px auto 0; max-width: 18ch; text-wrap: balance; }
    .ab__hero p { font-size: var(--text-lg); color: var(--text-body); line-height: var(--leading-relaxed); max-width: 54ch; margin: 22px auto 0; }
    .ab__banner { aspect-ratio: 21 / 9; border-radius: var(--radius-2xl); overflow: hidden; border: 1px solid var(--border-subtle); margin: var(--space-10) 0 var(--space-16);
      background: linear-gradient(160deg, var(--tertiary-100), var(--neutral-100) 55%, var(--primary-100)); position: relative; display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-md); }
    .ab__banner__grain { position: absolute; inset: 0; opacity: 0.5; background-image: radial-gradient(rgba(47,65,53,0.05) 1px, transparent 1.4px); background-size: 18px 18px; }
    .ab__banner__books { display: flex; gap: 22px; align-items: center; }
    .ab__banner__books > div { width: 120px; box-shadow: var(--shadow-lg); border-radius: var(--radius-md); }
    .ab__banner__books > div:nth-child(2) { width: 150px; }
    .ab__split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-16); align-items: center; padding: var(--space-12) 0; }
    /* No photo in the About split ⇒ no empty half. The two-column grid would otherwise reserve
       a blank 1fr where the image column used to be and push the prose into a narrow gutter,
       which looks like a broken image rather than a deliberate text-only section. */
    .ab__split[data-art="none"] { grid-template-columns: 1fr; }
    .ab__split h2 { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.75rem, 6vw, var(--text-h1)); line-height: 1.1; letter-spacing: -0.02em; color: var(--text-strong); margin: 14px 0 0; }
    .ab__split p { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-body); margin: 18px 0 0; max-width: 50ch; }
    .ab__art { aspect-ratio: 4 / 5; border-radius: var(--radius-xl); overflow: hidden; border: 1px solid var(--border-subtle); box-shadow: var(--shadow-sm);
      background: radial-gradient(120% 100% at 30% 0%, var(--neutral-25), var(--tertiary-100)); display: flex; align-items: center; justify-content: center; }
    .ab__values { background: var(--surface-inverse); color: var(--neutral-100); padding: var(--space-20) 0; margin: var(--space-12) 0; }
    .ab__values .eyebrow { color: var(--secondary-400); }
    .ab__values h2 { font-family: var(--font-serif); font-weight: 500; font-size: clamp(1.75rem, 6vw, var(--text-h1)); color: var(--neutral-25); margin: 14px 0 var(--space-12); max-width: 18ch; }
    .ab__vgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-10); }
    .ab__v { border-top: 1px solid var(--primary-700); padding-top: 20px; }
    .ab__v__ico { width: 44px; height: 44px; border-radius: var(--radius-md); border: 1px solid var(--primary-600); display: inline-flex; align-items: center; justify-content: center; color: var(--secondary-400); margin-bottom: 16px; }
    .ab__v h3 { font-family: var(--font-serif); font-size: var(--text-h4); font-weight: 500; color: var(--neutral-25); margin: 0 0 8px; }
    .ab__v p { font-size: var(--text-sm); line-height: var(--leading-relaxed); color: var(--primary-200); margin: 0; }
    .ab__quote { text-align: center; padding: var(--space-16) 0; max-width: 820px; margin: 0 auto; }
    .ab__quote p { font-family: var(--font-serif); font-style: italic; font-size: var(--text-h2); line-height: 1.3; letter-spacing: -0.01em; color: var(--text-strong); margin: 0; text-wrap: balance; }
    .ab__quote cite { display: block; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); font-style: normal; margin-top: 24px; }
    .ab__cta { text-align: center; padding: var(--space-12) 0 0; }
    @media (max-width: 800px) {
      .ab__split { grid-template-columns: 1fr; gap: var(--space-8); }
      .ab__vgrid { grid-template-columns: 1fr; gap: var(--space-8); }
      .ab__banner { aspect-ratio: 4 / 3; }
      .ab__banner__books > div { width: 86px; } .ab__banner__books > div:nth-child(2) { width: 108px; }
    }

/* === content pages (/strona/:slug) === */
    .prose h1 { font-family: var(--font-serif); font-weight: 500; font-size: clamp(2rem, 4vw, var(--text-h1, 3rem)); line-height: 1.1;
      letter-spacing: -0.02em; color: var(--text-strong); }
    .prose h2 { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-h3); line-height: var(--leading-snug);
      letter-spacing: -0.01em; color: var(--text-strong); margin: var(--space-10) 0 var(--space-4); }
    .prose h3 { font-family: var(--font-serif); font-weight: 500; font-size: var(--text-lg); line-height: var(--leading-snug);
      color: var(--text-strong); margin: var(--space-8) 0 var(--space-3, 0.75rem); }
    .prose { overflow-wrap: break-word; }
    .prose a { overflow-wrap: anywhere; }
    .prose p { font-size: var(--text-lg); color: var(--text-body); line-height: var(--leading-relaxed); margin: 0 0 var(--space-5, 1.25rem); }
    .prose ul { margin: 0 0 var(--space-5, 1.25rem); padding-left: 1.4em; }
    .prose li { font-size: var(--text-lg); color: var(--text-body); line-height: var(--leading-relaxed); margin: 0 0 0.4em; }
    .prose a { color: var(--primary-700, var(--text-strong)); text-underline-offset: 3px; }
    
/* ═══════════ Responsive hardening (small phones ≤480 / Fold ≤320) ═══════════
   Appended last so equal-specificity overrides win. Each rule answers a measured
   overflow from the 280-1024px audit; see git history for the full findings. */

/* Product page */
.pd__tabs .tabs { display: flex; max-width: 100%; overflow-x: auto;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.pd__tabs .tabs::-webkit-scrollbar { display: none; }
/* The add-to-cart label ("Dodaj do koszyka · 189 zł") is re-applied by the variant JS,
   so it must be allowed to wrap here, not shortened server-side. */
.pd__actions .button { white-space: normal; height: auto; min-height: 52px;
  padding-block: 10px; min-width: 0; }

@media (max-width: 560px) {
  .home-news__card { padding: var(--space-8) var(--space-6); }
}

@media (max-width: 480px) {
  /* Cart line: 92px thumb + qty stepper + price/remove column needed ~292px — stack the
     price/remove under the info instead of a third column. */
  .cart__line { grid-template-columns: 64px minmax(0, 1fr); gap: 12px; }
  .cart__thumb { width: 64px; }
  .cart__line__right { grid-column: 2; flex-direction: row; justify-content: space-between;
    align-items: center; text-align: left; }
  /* Account header: avatar + name + Wyloguj never fit one row on phones. */
  .acc__head { flex-wrap: wrap; }
  .acc__head__info h1 { font-size: var(--text-h3); }
}

@media (max-width: 360px) {
  .summary { padding: var(--space-4); }
  .summary__promo { flex-wrap: wrap; }
  .summary__promo .button { flex: 1; }
  .quantity--sm .quantity__btn { width: 30px; }
  .quantity--sm .quantity__val { min-width: 34px; }
}

/* ── Slots the merchant deliberately emptied ──────────────────────────────────
   A content slot saved as a blank means "show nothing here" (see `src/content.rs`'s
   `resolve` — a saved blank is an answer, not an absence, and no longer falls back to the
   shipped default copy). The slot then renders as literally nothing, but the element AROUND
   it survives, and a `<p>`/`<h2>` still carries its own margins — so a removed line leaves a
   ghost gap exactly where the merchant asked for nothing.

   Every storefront slot sits directly between its tags (`<p>{{ content("…") }}</p>`), with no
   whitespace, so an emptied one leaves an element with NO child nodes at all — which is
   precisely what `:empty` selects. That is also this rule's one fragility: put a newline
   inside those tags and the element holds a whitespace text node, `:empty` stops matching,
   and the gap comes back. Keep slot calls tight against their tags.

   Enumerated, not a blanket `*:empty`: these are the block-level text carriers that own
   vertical margin. An empty inline `<span>` already occupies nothing, and several
   (`.button__icon`, `.toast__icon`) legitimately hold only an SVG — sweeping them in would
   buy no layout and risk hiding something real. */
.storefront :is(h1, h2, h3, h4, p, .eyebrow, .home-feat__spec):empty { display: none; }

/* ── Blocks (composable page sections — src/blocks.rs, docs/BLOCKS.md) ─────────────────────────
   Each block's root carries `.block .block-<name>` PLUS the `home-*` scope class the section
   always had, so every existing selector (and every tenant sheet written against it) keeps
   matching — the block classes are an addition to the markup contract, not a replacement. The
   six home blocks are therefore already fully styled by the `home-*` rules above and need
   nothing here.

   `richtext` is the exception: it is a NEW section (the prose block a content page becomes when
   pages move onto block lists), so it brings its own two lines. `narrow` keeps a reading measure
   for legal/prose copy — the same 760px `tpl/page.html` has always used inline — while `wide`
   lets it fill the rail between full-width sections. */
/* --section-bg / --section-accent: see `.home-hero`'s comment (pages-home.jsx section, above) for
   the mechanism — set inline on this block's own root by the section editor's swatch picker.
   `.block-richtext__title` already had a colour before this, from `.prose h2` (`--text-strong`,
   above under "content pages"). That rule wins on specificity alone ((0,1,1) vs a bare `body`
   inherit), so it — not `body` — is the fallback an absent choice must reproduce. */
.storefront .block-richtext { padding: var(--space-16) 0; background: var(--section-bg, transparent); }
.storefront .block-richtext__title { color: var(--section-heading, var(--section-accent, var(--text-strong))); }
.storefront .block-page-body { padding: 0 0 var(--space-16); }

/* The prose measure. 760px is what `tpl/page.html` carried as an inline style before content
   pages became block lists, so a legal page's line length is unchanged. Applied to the rail
   rather than to `.prose` itself, so the heading above and the body below line up on the same
   left edge; `wide` simply doesn't narrow the rail.

   ONE rule for every section, keyed on `data-width` — the axis each block template now carries
   (`{{ b.width }}`, from that placement's own width). It used to be two selectors naming
   `.block-richtext`/`.block-page-body` and keyed on `data-variant`, because narrow/wide was those
   two blocks' variant vocabulary rather than a property every section has; a merchant asking for a
   narrower hero was asking a question the markup had no way to answer. A block gets the axis by
   rendering the attribute — there is nothing per-block to add here, and nothing to forget. */
.storefront .block[data-width="narrow"] .site-container,
.storefront .page-head .site-container { max-width: 760px; }

/* The content page's H1 — outside the block loop, since it is the page's identity rather than a
   section a merchant can reorder away. */
.storefront .page-head { padding: var(--space-16) 0 0; }
.storefront .page-head__title { margin: 0 0 var(--space-6); }
