/* ============================================================================
   WoBooks Composed Ecommerce Theme — production design system
   Recolor-safe: every color derives from runtime tokens (--primary, --surface…).
   Motion baseline: CSS scroll-driven .reveal, base opacity:1, guarded.
   ========================================================================== */

:root {
  /* Runtime overrides these — never hardcode hex inside component rules. */
  --primary: #2d2a26;
  --primary-dark: #1a1815;
  --primary-light: #4a463f;
  --secondary: #8a7d6b;
  --accent: #b8965a;
  --background: #ffffff;
  --surface: #f7f5f1;
  --text: #1f1d1a;
  --muted: #6f6a61;
  --border: #e4e0d8;
  --font-sans: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --radius: 10px;

  /* Motion tokens — reference everywhere, never hardcode durations/eases. */
  --dur-micro: 140ms;
  --dur-ui: 240ms;
  --dur-reveal: 640ms;
  --dur-slow: 1100ms;
  --ease-standard: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);

  --container: 1200px;
  --space-section: clamp(3.5rem, 7vw, 6.5rem);
}

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

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

body {
  font-family: var(--font-sans);
  background: var(--background);
  color: var(--text);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }
img[src=""], img:not([src]) { display: none !important; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.12;
  text-wrap: balance;
  color: var(--text);
}
h1 { font-size: clamp(2.5rem, 1.9rem + 3vw, 4.6rem); }
h2 { font-size: clamp(1.9rem, 1.5rem + 1.9vw, 3rem); }
h3 { font-size: clamp(1.2rem, 1.05rem + .7vw, 1.6rem); }
p { text-wrap: pretty; }

.container { max-width: var(--container); margin-inline: auto; padding-inline: clamp(1rem, 4vw, 2.5rem); }
.eyebrow {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .9rem;
}
.section-head { max-width: 640px; margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.section-head p { color: var(--muted); margin-top: .75rem; font-size: 1.05rem; }
.section-head--center { margin-inline: auto; text-align: center; }

/* ── Accessibility ──────────────────────────────────────────────────────── */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--primary); color: var(--background);
  padding: .75rem 1.25rem; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font-family: var(--font-sans); font-weight: 600; font-size: .9rem;
  padding: .85rem 1.75rem; border-radius: var(--radius); border: 1.5px solid transparent;
  cursor: pointer; transition: background var(--dur-ui) var(--ease-standard),
    color var(--dur-ui) var(--ease-standard), border-color var(--dur-ui) var(--ease-standard),
    transform var(--dur-micro) var(--ease-standard);
}
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--primary); color: var(--background); }
.btn--primary:hover { background: var(--primary-dark); }
.btn--accent { background: var(--accent); color: var(--background); }
.btn--accent:hover { background: color-mix(in oklab, var(--accent) 82%, #000); }
.btn--outline { background: transparent; color: var(--text); border-color: var(--border); }
.btn--outline:hover { border-color: var(--primary); background: var(--surface); }
.btn--block { width: 100%; }

/* ── Header ─────────────────────────────────────────────────────────────── */
.header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in oklab, var(--background) 88%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--border);
}
.header__nav { display: flex; align-items: center; justify-content: space-between; height: 72px; gap: 1.5rem; }
.header__brand { display: flex; align-items: center; gap: .6rem; }
.header__logo { height: 32px; width: auto; }
.header__brand-name { font-family: var(--font-display); font-size: 1.4rem; font-weight: 600; }
.header__links { display: flex; gap: clamp(1.25rem, 3vw, 2.5rem); }
.header__links a { font-size: .9rem; font-weight: 500; color: var(--muted); transition: color var(--dur-ui) var(--ease-standard); }
.header__links a:hover { color: var(--text); }
.header__actions { display: flex; align-items: center; gap: 1rem; }
.cart-icon-btn { position: relative; display: inline-flex; color: var(--text); }
.cart-badge {
  position: absolute; top: -8px; right: -10px; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 9px; background: var(--accent); color: var(--background);
  font-size: .68rem; font-weight: 700; line-height: 18px; text-align: center;
}
.hamburger { display: none; flex-direction: column; gap: 4px; background: none; border: none; cursor: pointer; padding: 6px; }
.hamburger span { width: 22px; height: 2px; background: var(--text); transition: transform var(--dur-ui) var(--ease-standard); }
.nav-overlay { display: none; }

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero { position: relative; min-height: clamp(480px, 82vh, 820px); display: flex; align-items: flex-end; overflow: hidden; background: var(--surface); }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; }
.hero__overlay { position: absolute; inset: 0; background: linear-gradient(to top, color-mix(in oklab, var(--primary-dark) 88%, transparent) 0%, color-mix(in oklab, var(--primary-dark) 30%, transparent) 55%, transparent 100%); }
.hero__content { position: relative; z-index: 1; padding-block: clamp(2.5rem, 7vw, 5.5rem); max-width: 760px; }
.hero--has-image .hero__content, .hero--has-image .hero__content :is(h1, p, .eyebrow) { color: var(--background); }
.hero--has-image .eyebrow { color: var(--accent); }
/* An image hero paints its content with --background (the light half of the
   pair) because it sits on the dark overlay above. `.btn--outline` hard-sets
   `color: var(--text)` — a real declaration on the element, so it BEATS that
   inherited colour, and the secondary CTA rendered dark-on-dark: a visible
   bordered box with an invisible label, on the hero of every composed theme in
   this family. Seen 2026-08-16 on `recipe-ecommerce-sell-trust` ("Browse
   categories"), and the same two lines are in business / local-service /
   real-estate / restaurant, whose image heroes carry the same outline CTA.
   Written token-relative (never a literal colour) so it stays recolor-safe:
   the hero's foreground is --background here for the same reason the heading's
   is. */
.hero--has-image .hero__ctas .btn--outline {
  color: var(--background);
  border-color: color-mix(in oklab, var(--background) 55%, transparent);
}
.hero--has-image .hero__ctas .btn--outline:hover {
  color: var(--background);
  background: color-mix(in oklab, var(--background) 16%, transparent);
  border-color: var(--background);
}
.hero__title-prefix { display: block; font-style: italic; font-weight: 400; opacity: .9; }
.hero__subtitle { font-size: clamp(1rem, .95rem + .3vw, 1.2rem); max-width: 520px; margin-block: 1.25rem 2rem; opacity: .92; }
/* `hero.content` is declared `markdown` on the business contract and inherited
   by ecommerce / local-service / real-estate / restaurant, the Manager offers
   it as an editable control, and until 2026-08-28 no generic hero shape read
   it — an owner's intro paragraph was accepted and silently dropped (TFS-13,
   and the named upstream cause of the recipe-* seed-filled-dead-field bucket).
   The marker ships on an EMPTY element body on purpose: the converter then
   compiles `{!! theme_var('hero.content', '') !!}` with no baked fallback copy,
   which is why the `:empty` collapse below is load-bearing — an unset field
   must render byte-identically to a hero that never had one. Same idiom as
   `.cine-hero__body:empty` in the cinematic-stage variant. */
.hero__body { max-width: 56ch; margin-block: 0 2rem; opacity: .92; }
.hero__body:empty { display: none; }
.hero__body p + p { margin-top: 1rem; }
.hero__ctas { display: flex; flex-wrap: wrap; gap: 1rem; }

/* Hero variant: split (content + media, no overlay) */
.hero--split { min-height: auto; align-items: center; background: var(--background); padding-block: clamp(2.5rem, 6vw, 5rem); }
.hero__split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.5rem, 4vw, 3.5rem); align-items: center; }
.hero__split-content :is(h1, .hero__subtitle) { color: var(--text); }
.hero__split-media { border-radius: var(--radius); overflow: hidden; aspect-ratio: 4/5; background: var(--surface); }
.hero__split-media img { width: 100%; height: 100%; object-fit: cover; }

/* Hero variant: minimal (centered text, no image) */
.hero--minimal { min-height: auto; align-items: center; background: var(--surface); text-align: center; padding-block: clamp(4rem, 10vw, 8rem); }
.hero__minimal { position: relative; z-index: 1; max-width: 760px; margin-inline: auto; }
/* Decorative backdrop for the `minimal` shape. The minimal gene stays
   `imagery: none` in `_components/hero/component.json` — do NOT "fix" it. This
   is a low-opacity wash behind the copy, not a picture, so nothing about the
   genome's shape selection changes; it exists only so `hero.image`, a field the
   contract declares and the Manager accepts edits into, is no longer dropped on
   this shape. The <img> is inert: empty alt, aria-hidden wrapper, low fetch
   priority, lazy — it is deferred so it cannot steal bandwidth from the copy.
   KNOWN, MEASURED (2026-08-28): a full-bleed image is still an LCP candidate in
   Chrome even at .12 opacity, so on a tenant that sets `hero.image` the LCP
   element becomes this backdrop rather than the <h1>. Local medians showed no
   slowdown (1310ms with it, 1775ms with it blocked — the webfont gates the
   heading), but on a slow mobile link this photo would govern LCP. If that
   shows up in field data, serve a downscaled variant here rather than deleting
   the binding — the field must stay reachable.
   Gated on the WRAPPER, not just the <img>: the fleet-wide
   `img[src=""] { display: none }` rule hides the image but would leave the
   ::after gradient painting a wash over every minimal hero with no photo. Same
   wrapper-level `:has()` idiom as `.about__media` in `_components/about/style.css`.
   With the image unset the entire scrim is gone and the render is byte-identical
   to before this rule existed. */
.hero__scrim { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.hero__scrim img { width: 100%; height: 100%; object-fit: cover; opacity: .12; }
/* The veil is an ACCESSIBILITY control, not decoration. Measured 2026-08-28 on
   a live minimal hero: with a plain top-to-bottom fade the texture reached the
   copy column and dragged `.hero__subtitle` from 3.75:1 to 3.36:1 — a scrim
   must never move text contrast at all. The radial stop is opaque `--surface`
   out to 410px each side of centre — deliberately expressed against the 760px
   `.hero__minimal` column rather than a viewport percentage, because a
   percentage narrows with the viewport and re-exposed the copy to the texture
   at 390px (measured 3.51:1 there before this stop was pinned). Every
   character now sits on pure surface at every width, and the texture reads
   only in the margin beyond the column. Keep the opaque stop wider than
   `.hero__minimal` if you ever retune it. */
.hero__scrim::after { content: ""; position: absolute; inset: 0; background: radial-gradient(ellipse 760px 78% at 50% 46%, var(--surface) 0%, var(--surface) 54%, transparent 100%), linear-gradient(to bottom, transparent 0%, var(--surface) 100%); }
.hero__scrim:has(> img[src=""]), .hero__scrim:has(> img:not([src])) { display: none; }
.hero--minimal :is(h1) { color: var(--text); }
.hero--minimal .hero__subtitle { margin-inline: auto; color: var(--muted); }
/* Deliberately inherits `--text` rather than taking `--muted` like the subtitle
   above it: at 16px, `--muted` on `--surface` measures 3.44:1 — below the 4.5:1
   WCAG AA floor for body copy. This is the owner's own paragraph, the longest
   run of reading text in the hero, and it must be legible. Softening comes from
   the inherited `opacity: .92`, which keeps it ~10:1. */
.hero--minimal .hero__body { margin-inline: auto; }
.hero--minimal .hero__ctas { justify-content: center; }

/* ── Categories ─────────────────────────────────────────────────────────── */
.categories { padding-block: var(--space-section); }
.categories__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: clamp(1rem, 2vw, 1.5rem); }
.category-card { position: relative; display: block; aspect-ratio: 4/5; border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.category-card img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur-reveal) var(--ease-out); }
.category-card:hover img { transform: scale(1.06); }
.category-card__label { position: absolute; inset: auto 0 0 0; padding: 1.5rem 1.25rem .9rem; color: #fff; font-family: var(--font-display); font-size: 1.3rem; background: linear-gradient(to top, rgba(0,0,0,.6), transparent); }

/* ── Products (carousel/grid) ───────────────────────────────────────────── */
.products { padding-block: var(--space-section); background: var(--surface); }
.products__head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: clamp(1.5rem, 3vw, 2.5rem); flex-wrap: wrap; }
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: clamp(1.25rem, 2.5vw, 2rem); }
.product-card { background: var(--background); border-radius: var(--radius); overflow: hidden; display: flex; flex-direction: column; }
.product-card__image-wrap { position: relative; display: block; aspect-ratio: 3/4; overflow: hidden; background: var(--surface); }
.product-card__image-wrap img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur-reveal) var(--ease-out); }
.product-card__image-wrap:hover img { transform: scale(1.05); }
.product-card__quick-view {
  position: absolute; inset: auto .75rem .75rem auto; width: 38px; height: 38px;
  display: grid; place-items: center; border-radius: 50%; background: var(--background); color: var(--text);
  opacity: 0; transform: translateY(8px); transition: opacity var(--dur-ui) var(--ease-standard), transform var(--dur-ui) var(--ease-standard);
}
.product-card__image-wrap:hover .product-card__quick-view { opacity: 1; transform: translateY(0); }
.product-card__info { padding: 1rem 1.1rem 1.25rem; display: flex; flex-direction: column; gap: .4rem; flex: 1; }
.product-card__category { font-size: .7rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.product-card__title { font-family: var(--font-display); font-size: 1.2rem; font-weight: 500; }
.product-card__title a:hover { color: var(--accent); }
.product-card__price { display: flex; align-items: baseline; gap: .5rem; margin-top: auto; padding-top: .35rem; }
.product-card__price-current { font-weight: 600; font-size: 1rem; }
.product-card__price-original { font-size: .85rem; color: var(--muted); text-decoration: line-through; }
.product-card__add-btn { margin-top: .85rem; width: 100%; padding: .7rem 1rem; font-size: .8rem; letter-spacing: .04em; text-transform: uppercase; background: var(--primary); color: var(--background); border: none; border-radius: var(--radius); cursor: pointer; transition: background var(--dur-ui) var(--ease-standard); }
.product-card__add-btn:hover { background: var(--primary-dark); }
.product-card__badge { position: absolute; top: .75rem; left: .75rem; background: var(--accent); color: var(--background); font-size: .65rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; padding: .25rem .55rem; border-radius: 5px; }

/* ── Testimonials ───────────────────────────────────────────────────────── */
.testimonials { padding-block: var(--space-section); }
.testimonials__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: clamp(1.25rem, 2.5vw, 2rem); }
.testimonial-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem; }
.testimonial-card__quote { font-family: var(--font-display); font-size: 1.2rem; line-height: 1.5; margin-bottom: 1.5rem; }
.testimonial-card__author { display: flex; align-items: center; gap: .85rem; }
.testimonial-card__author img { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; }
.testimonial-card__name { font-weight: 600; font-size: .95rem; }
.testimonial-card__role { font-size: .82rem; color: var(--muted); }

/* ── FAQs ───────────────────────────────────────────────────────────────── */
.faqs { padding-block: var(--space-section); background: var(--surface); }
.faqs__list { max-width: 780px; margin-inline: auto; }
.faq-item { border-bottom: 1px solid var(--border); }
.faq-item__q { display: flex; align-items: center; justify-content: space-between; gap: 1rem; width: 100%; padding: 1.35rem 0; background: none; border: none; cursor: pointer; text-align: left; font-family: var(--font-display); font-size: 1.15rem; color: var(--text); }
.faq-item__icon { flex: none; transition: transform var(--dur-ui) var(--ease-standard); }
.faq-item[open] .faq-item__icon { transform: rotate(45deg); }
.faq-item__a { padding-bottom: 1.35rem; color: var(--muted); max-width: 68ch; }

/* ── Policies ───────────────────────────────────────────────────────────── */
.policies { padding-block: var(--space-section); }
.policies__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: clamp(1.25rem, 2.5vw, 2rem); }
.policy-card { padding: 1.75rem; border: 1px solid var(--border); border-radius: var(--radius); }
.policy-card h3 { margin-bottom: .6rem; }
.policy-card p { color: var(--muted); }

/* ── Contact ────────────────────────────────────────────────────────────── */
.contact { padding-block: var(--space-section); background: var(--surface); }
.contact__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.5rem; max-width: 900px; }
.contact__item { display: flex; flex-direction: column; gap: .3rem; }
.contact__item span:first-child { font-size: .72rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.contact__item a, .contact__item p { font-size: 1.05rem; }

/* ── Breadcrumbs ────────────────────────────────────────────────────────── */
.breadcrumbs { padding-block: 1.25rem; }
.breadcrumbs ol { display: flex; flex-wrap: wrap; gap: .5rem; font-size: .85rem; color: var(--muted); }
.breadcrumbs li:not(:last-child)::after { content: '/'; margin-left: .5rem; opacity: .5; }
.breadcrumbs a:hover { color: var(--text); }

/* ── Product detail ─────────────────────────────────────────────────────── */
.product-detail { padding-block: clamp(2rem, 4vw, 3.5rem) var(--space-section); }
.product-detail__grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: clamp(2rem, 5vw, 4rem); align-items: start; }
.product-gallery__main { aspect-ratio: 1; border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.product-gallery__main img { width: 100%; height: 100%; object-fit: cover; }
.product-gallery__thumbs { display: flex; gap: .75rem; margin-top: .85rem; }
.product-gallery__thumbs button { width: 76px; height: 76px; border: 1px solid var(--border); border-radius: var(--radius, 8px); overflow: hidden; background: none; cursor: pointer; padding: 0; }
.product-info__category { font-size: .72rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.product-info h1 { margin-block: .5rem .75rem; }
.product-info__price { font-size: 1.6rem; font-weight: 600; margin-bottom: 1.25rem; }
.product-info__price-original { font-size: 1.05rem; color: var(--muted); text-decoration: line-through; margin-left: .6rem; }
.product-info__desc { color: var(--muted); margin-bottom: 1.75rem; }
.variant-selector { margin-bottom: 1.25rem; }
.variant-selector fieldset { border: none; }
.variant-selector__label { font-size: .8rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; margin-bottom: .6rem; }
.variant-selector__options { display: flex; flex-wrap: wrap; gap: .5rem; }
.variant-chip { display: inline-flex; align-items: center; padding: .5rem .95rem; border: 1.5px solid var(--border); border-radius: var(--radius); cursor: pointer; font-size: .85rem; }
.variant-chip input { position: absolute; opacity: 0; }
.variant-chip--active, .variant-chip:has(input:checked) { border-color: var(--primary); background: var(--primary); color: var(--background); }
.product-info__actions { display: flex; gap: 1rem; margin-block: 1.5rem; }
.trust-signals { display: flex; flex-wrap: wrap; gap: 1.25rem; padding-top: 1.5rem; border-top: 1px solid var(--border); }
.trust-signals__item { display: flex; align-items: center; gap: .5rem; font-size: .85rem; color: var(--muted); }

/* ── Reviews ────────────────────────────────────────────────────────────── */
.reviews { padding-block: var(--space-section); background: var(--surface); }
.reviews-list { display: grid; gap: 1.25rem; max-width: 780px; margin-bottom: 2.5rem; }
.review-item { background: var(--background); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; }
.review-author { font-weight: 600; }
.review-stars { color: var(--accent); margin-left: .5rem; }
.review-title { display: block; margin-block: .5rem .25rem; }
.review-body { color: var(--muted); }
.review-form-placeholder { max-width: 560px; display: grid; gap: .85rem; }
.review-form-placeholder input, .review-form-placeholder textarea, .form-input, .form-select {
  width: 100%; padding: .85rem 1rem; border: 1.5px solid var(--border); border-radius: var(--radius);
  font: inherit; background: var(--background); color: var(--text);
}
.form-input:focus, .form-select:focus, textarea:focus { border-color: var(--primary); outline: none; }

/* ── Cart ───────────────────────────────────────────────────────────────── */
.cart { padding-block: clamp(2rem, 4vw, 3.5rem) var(--space-section); }
.cart__grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: clamp(2rem, 4vw, 3rem); align-items: start; }
.cart-item { display: grid; grid-template-columns: 100px 1fr auto auto auto; gap: 1.25rem; align-items: center; padding: 1.25rem 0; border-bottom: 1px solid var(--border); }
.cart-item__img-wrap { width: 100px; aspect-ratio: 1; border-radius: 8px; overflow: hidden; background: var(--surface); }
.cart-item__img-wrap img { width: 100%; height: 100%; object-fit: cover; }
.cart-item__title { font-family: var(--font-display); font-size: 1.1rem; display: block; }
.cart-item__price { font-weight: 600; }
.cart-item__original { color: var(--muted); text-decoration: line-through; font-size: .85rem; margin-right: .4rem; }
.cart-item__qty { display: inline-flex; align-items: center; gap: .5rem; border: 1px solid var(--border); border-radius: var(--radius); padding: .25rem .5rem; }
.qty-btn { width: 26px; height: 26px; border: none; background: none; cursor: pointer; font-size: 1.1rem; color: var(--text); }
.cart-item__remove { background: none; border: none; cursor: pointer; color: var(--muted); }
.cart-item__remove:hover { color: var(--text); }
.cart-summary { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.75rem; position: sticky; top: 96px; }
.cart-summary__row { display: flex; justify-content: space-between; padding: .5rem 0; }
.cart-summary__row--total { border-top: 1px solid var(--border); margin-top: .5rem; padding-top: 1rem; font-weight: 700; font-size: 1.15rem; }
.empty-state { text-align: center; padding: clamp(3rem, 8vw, 6rem) 1rem; max-width: 460px; margin-inline: auto; }
.empty-state__icon { width: 64px; height: 64px; color: var(--muted); margin-inline: auto; margin-bottom: 1.25rem; }
.empty-state h2 { margin-bottom: .75rem; }
.empty-state p { color: var(--muted); margin-bottom: 1.5rem; }

/* ── Checkout ───────────────────────────────────────────────────────────── */
.checkout { padding-block: clamp(2rem, 4vw, 3.5rem) var(--space-section); }
/* Order-blocked notice (e.g. oversell guard). Semantic status colours are fixed
   by design — an error must read as an error under any brand recolour. */
.checkout-notice { display: flex; flex-direction: column; gap: .25rem; padding: .9rem 1.15rem; margin-bottom: 1.75rem; border: 1px solid #eab8b3; border-left: 3px solid #c0392b; border-radius: var(--radius); background: #fcecea; color: #7d241c; }
.checkout-notice__title { font-weight: 700; }
.checkout-notice__text { color: #7d241c; }
.checkout-progress { margin-bottom: 2.5rem; }
.checkout-progress ol { display: flex; align-items: flex-start; max-width: 380px; }
.checkout-progress__step { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; position: relative; font-size: .8rem; color: var(--muted); }
.checkout-progress__step span { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; background: var(--surface); border: 1.5px solid var(--border); font-weight: 600; }
.checkout-progress__step:not(:last-child)::after { content: ''; position: absolute; top: 13px; left: 50%; width: 100%; height: 2px; background: var(--border); z-index: -1; }
.checkout-progress__step--completed span, .checkout-progress__step--active span { background: var(--primary); color: var(--background); border-color: var(--primary); }
.checkout-progress__step--active { color: var(--text); font-weight: 600; }
.checkout__grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: clamp(2rem, 4vw, 3rem); align-items: start; }
.checkout__fieldset { border: none; margin-bottom: 2rem; }
.checkout__fieldset legend { font-family: var(--font-display); font-size: 1.3rem; margin-bottom: 1rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; font-size: .82rem; font-weight: 600; margin-bottom: .4rem; }
.method-option { display: flex; align-items: center; gap: .75rem; padding: 1rem; border: 1.5px solid var(--border); border-radius: var(--radius); margin-bottom: .75rem; cursor: pointer; }
.method-option:has(input:checked) { border-color: var(--primary); }
.checkout-summary-item { display: grid; grid-template-columns: 56px 1fr auto; gap: .85rem; align-items: center; padding: .75rem 0; border-bottom: 1px solid var(--border); }
.checkout-summary-item img { border-radius: 6px; object-fit: cover; }
.checkout-summary-item__title { font-weight: 500; font-size: .9rem; }
.checkout-summary-item__qty { font-size: .8rem; color: var(--muted); }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.footer { background: var(--primary-dark); color: color-mix(in oklab, var(--background) 78%, var(--primary)); padding-block: clamp(3rem, 6vw, 4.5rem) 1.75rem; }
.footer__top { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.4fr; gap: clamp(1.5rem, 3vw, 2.5rem); padding-bottom: 2.5rem; border-bottom: 1px solid color-mix(in oklab, var(--background) 14%, transparent); }
.footer__brand-name { font-family: var(--font-display); font-size: 1.5rem; color: var(--background); display: block; margin-bottom: .6rem; }
.footer__brand p { font-size: .92rem; opacity: .85; max-width: 30ch; }
.footer__social { display: flex; gap: .65rem; margin-top: 1.1rem; }
.footer__social-link { width: 38px; height: 38px; display: grid; place-items: center; border-radius: var(--radius, 50%); border: 1px solid color-mix(in oklab, var(--background) 22%, transparent); color: var(--background); transition: background var(--dur-ui) var(--ease-standard); }
.footer__social-link:hover { background: var(--accent); border-color: var(--accent); }
.footer__links-col h4, .footer__newsletter h4 { color: var(--background); font-family: var(--font-sans); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 1rem; }
.footer__links-col ul { display: grid; gap: .6rem; }
.footer__links-col a { font-size: .92rem; opacity: .85; }
.footer__links-col a:hover { opacity: 1; color: var(--accent); }
.footer__newsletter p { font-size: .9rem; opacity: .85; margin-bottom: 1rem; }
.newsletter-form { display: flex; gap: .5rem; }
.newsletter-form .form-input { background: color-mix(in oklab, var(--background) 12%, transparent); border-color: color-mix(in oklab, var(--background) 22%, transparent); color: var(--background); }
.footer__bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .75rem; padding-top: 1.75rem; font-size: .82rem; opacity: .75; }

/* ── Motion: scroll-driven reveal (base visible, progressively enhanced) ── */
.reveal { opacity: 1; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      opacity: 0; transform: translateY(28px);
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 38%;
    }
  }
}
@keyframes reveal-in { to { opacity: 1; transform: none; } }

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .product-detail__grid, .cart__grid, .checkout__grid, .hero__split { grid-template-columns: 1fr; }
  .hero__split-media { order: -1; }
  .footer__top { grid-template-columns: 1fr 1fr; }
  .cart-summary { position: static; }
}
@media (max-width: 720px) {
  .header__links { display: none; }
  .hamburger { display: flex; }
  .products__head { flex-direction: column; align-items: flex-start; }
  .form-row { grid-template-columns: 1fr; }
  .cart-item { grid-template-columns: 72px 1fr auto; grid-template-areas: 'img title remove' 'img qty total'; row-gap: .5rem; }
  .cart-item__img-wrap { grid-area: img; width: 72px; }
  .footer__top { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   WB form baseline — assembled-form controls (2026-07-19).
   Harvested contact/booking/quote variants ship structural form markup
   (form-group / form-input / contact-form …) but relied on donor CSS that the
   composer never carries. Without this block their inputs render as raw
   browser defaults (verified live on an assembled karyana site). Token-driven
   so Style Presets retoken it like everything else.
--------------------------------------------------------------------------- */
.contact-form, .contact__form, .contact__form-card form, .booking-form, .quote-form, .reservation-form {
  display: flex; flex-direction: column; gap: 1rem;
}
.form-row { display: grid; gap: 1rem; }
.form-row--2col { grid-template-columns: 1fr 1fr; }
@media (max-width: 640px) { .form-row--2col { grid-template-columns: 1fr; } }
.form-group { display: flex; flex-direction: column; gap: .4rem; margin-bottom: 0; }
.form-label,
.form-group label { font-size: .82rem; font-weight: 600; color: var(--text); }
.form-input,
.form-textarea,
.form-group input, .form-group textarea, .form-group select,
.contact-form input, .contact-form textarea, .contact-form select,
.contact__form input, .contact__form textarea, .contact__form select {
  width: 100%;
  padding: .75rem 1rem;
  font: inherit;
  color: var(--text);
  background: var(--background);
  border: 1.5px solid var(--border);
  border-radius: var(--radius, 10px);
  transition: border-color var(--dur-ui, .18s) var(--ease-standard, ease);
}
.form-input:focus, .form-textarea:focus,
.form-group :is(input, textarea, select):focus,
.contact-form :is(input, textarea, select):focus,
.contact__form :is(input, textarea, select):focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}
.form-textarea,
.form-group textarea, .contact-form textarea, .contact__form textarea { min-height: 7.5rem; resize: vertical; }
.form-submit,
.contact-form button[type="submit"], .contact__form button[type="submit"] {
  align-self: flex-start;
  padding: .8rem 1.9rem;
  font: inherit; font-weight: 600;
  color: var(--background, #fff);
  background: var(--primary);
  border: none;
  border-radius: var(--radius, 10px);
  cursor: pointer;
  transition: background var(--dur-ui, .18s) var(--ease-standard, ease), transform var(--dur-ui, .18s) var(--ease-standard, ease);
}
.form-submit:hover,
.contact-form button[type="submit"]:hover, .contact__form button[type="submit"]:hover {
  background: var(--primary-dark, var(--primary));
  transform: translateY(-1px);
}
.form-honeypot { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }


/* ── section component: hero.cinematic-stage ── */
/* Cinematic Stage — a full-bleed hero built around the Cinematic Kernel's DOM.
   .wb-sc-stage is the direct child pin-stage sticks; .wb-sc-media wraps the
   always-visible .wb-sc-poster with the decorative .wb-sc-frames canvas over it.
   STRUCTURE + STATIC STYLING ONLY — SceneCompiler emits every scene rule, so
   nothing here animates on scroll and the resting state is fully readable with
   no JS and no motion. Every colour is a canonical token or a color-mix() of one.

   The three .wb-sc-layer elements carry a signed --wb-depth the stage-sequence
   scene reads: the media plate rises the most (1), the copy drifts gently so the
   reading text stays near-steady (.35), the keylight wash counter-drifts (-.5) so
   the layers cross into depth while the hero is pinned. These are static custom
   properties — the settle itself is the compiler's keyframe, never authored here.
   The value is transparent to a recolor (a number, not a colour) and the settle's
   end state is each layer's own resting position, so no motion == the composed frame. */

.cine-hero {
  /* Fluid type: dramatic display step, minor-third supporting steps. */
  --cine-display: clamp(2.35rem, 1.55rem + 3.9vw, 6rem);
  --cine-step-2: clamp(1.2rem, 1.09rem + .55vw, 1.6rem);
  --cine-step-1: clamp(1.05rem, 1rem + .28vw, 1.28rem);
  --cine-step-0: clamp(.94rem, .91rem + .16vw, 1.05rem);
  --cine-step--1: clamp(.7rem, .68rem + .12vw, .78rem);
  /* 8-point spacing. */
  --cine-1: .5rem; --cine-2: 1rem; --cine-3: 1.5rem; --cine-4: 2rem; --cine-6: 3rem;
  /* Honour the theme radius, but keep a cinematic plate from becoming a pill. */
  --cine-radius: clamp(0px, var(--radius, 10px), 20px);
  /* Motion feel — author-owned, untouched by the recolor runtime. ease-out-expo
     is decelerating with no overshoot; a luxury set never bounces. */
  --cine-dur-micro: 180ms;
  --cine-dur-ui: 320ms;
  --cine-ease: cubic-bezier(.19, 1, .22, 1);
  /* Tonal locals — honest derivatives of canonical anchors, so any recolor
     reaches them and no palette_map entry is needed. */
  --cine-ink-soft: color-mix(in oklab, var(--text) 74%, var(--background));
  --cine-hairline: color-mix(in oklab, var(--text) 16%, transparent);
  --cine-plate: color-mix(in oklab, var(--surface) 92%, var(--text));
  /* Four layers: growing offset/blur, decreasing opacity, one light source,
     tinted with the brand hue rather than black. */
  --cine-lift:
    0 1px 2px color-mix(in oklab, var(--primary) 14%, transparent),
    0 6px 12px color-mix(in oklab, var(--primary) 11%, transparent),
    0 16px 30px color-mix(in oklab, var(--primary) 8%, transparent),
    0 34px 60px color-mix(in oklab, var(--primary) 6%, transparent);

  position: relative; display: block;
  background: var(--background); color: var(--text);
  font-family: var(--font-sans);
  /* Deliberately NO min-height: pin-stage sets the section's scroll span at the
     same specificity, so the stage owns the resting height instead. */
}

/* ── Stage ──────────────────────────────────────────────────────────────── */
.cine-hero__stage {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; justify-content: center;
  min-height: clamp(520px, 82vh, 900px);
  min-height: clamp(520px, 82svh, 900px);
  padding-block: clamp(3rem, 7vh, 5.5rem);
}

/* Keylight. Two single-hue falloffs; every stop is a color-mix() so a palette
   token TINTS the layer instead of replacing the whole gradient. */
.cine-hero__wash {
  --wb-depth: -.5;
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(86% 60% at 16% 6%, color-mix(in oklab, var(--primary) 15%, transparent) 0%, transparent 62%),
    radial-gradient(68% 56% at 90% 94%, color-mix(in oklab, var(--accent) 12%, transparent) 0%, transparent 64%);
}

/* Film grain, rasterised once from a tiled data-URI — a composite, not a live
   filter — and blended so it tints from the layer beneath (recolor-safe). */
.cine-hero__stage::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  opacity: .055; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='cine-grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23cine-grain)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

.cine-hero__inner {
  position: relative; z-index: 1;
  width: 100%; max-width: 82rem; margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 3.5rem);
  display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center;
}

/* ── Copy ───────────────────────────────────────────────────────────────── */
.cine-hero__copy { --wb-depth: .35; display: flex; flex-direction: column; align-items: flex-start; }

/* Label stays ink so contrast holds on any palette; the accent rides the
   decorative dot, which carries no contrast requirement. */
.cine-hero__kicker {
  display: inline-flex; align-items: center; gap: .6rem;
  margin: 0 0 var(--cine-3);
  font-size: var(--cine-step--1); font-weight: 600; line-height: 1;
  letter-spacing: .2em; text-transform: uppercase; color: var(--text);
}
.cine-hero__kicker-dot { flex: none; width: .4rem; height: .4rem; border-radius: 50%; background: var(--accent); }

.cine-hero__prefix {
  margin: 0 0 var(--cine-1);
  font-family: var(--font-display); font-size: var(--cine-step-2);
  font-style: italic; font-weight: 400; line-height: 1.25;
  color: var(--cine-ink-soft); text-wrap: balance;
}

.cine-hero__title {
  margin: 0; max-width: 15ch;
  font-family: var(--font-display); font-size: var(--cine-display);
  font-weight: 600; line-height: 1.02; letter-spacing: -.025em;
  color: var(--text); text-wrap: balance;
}

.cine-hero__subtitle {
  margin: var(--cine-3) 0 0; max-width: 34ch;
  font-size: var(--cine-step-1); line-height: 1.45;
  color: var(--text); text-wrap: pretty;
}

.cine-hero__body {
  margin: var(--cine-2) 0 0; max-width: 46ch;
  font-size: var(--cine-step-0); line-height: 1.65;
  color: var(--cine-ink-soft); text-wrap: pretty;
}
.cine-hero__body:empty { display: none; }

.cine-hero__actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--cine-2) var(--cine-4); margin-top: var(--cine-6);
}

.cine-hero__cta {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3rem; padding: .9rem 1.9rem;
  border: 1px solid transparent; border-radius: var(--cine-radius);
  background: var(--primary); color: var(--background);
  font-family: inherit; font-size: var(--cine-step-0); font-weight: 600; line-height: 1.2;
  text-decoration: none; box-shadow: var(--cine-lift);
}
.cine-hero__cta:hover { background: color-mix(in oklab, var(--primary) 88%, var(--text)); }

.cine-hero__ghost {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 2.75rem; padding-block: .5rem;
  color: var(--text); font-size: var(--cine-step-0); font-weight: 600; line-height: 1.2;
  text-decoration: none;
}
.cine-hero__ghost-label { padding-bottom: .2rem; border-bottom: 1px solid var(--cine-hairline); }
.cine-hero__ghost:hover .cine-hero__ghost-label { border-bottom-color: var(--accent); }
.cine-hero__ghost-arrow { flex: none; }

/* Branded focus ring, hardened with a little ink so it stays visible even on a
   palette whose accent sits close to the background. Never removed. */
.cine-hero a:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--accent) 65%, var(--text));
  outline-offset: 3px; border-radius: var(--cine-radius);
}

/* ── Media: the scene's stage plate ─────────────────────────────────────── */
.cine-hero__frame {
  --wb-depth: 1;
  position: relative; border-radius: var(--cine-radius); overflow: clip;
  background: var(--cine-plate); box-shadow: var(--cine-lift);
}

/* Mirrors the resting layers SceneCompiler emits for scrub-sequence (poster
   width:100%/height:auto), so the layout is byte-identical whether or not a
   scene is compiled. aspect-ratio, not height, gives the poster a definite box
   for object-fit — the compiler's height:auto would otherwise undo a crop. */
.cine-hero__media { position: relative; display: block; aspect-ratio: 4 / 3; }
.cine-hero__poster {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover; object-position: center;
}
/* No photo yet: hide the broken image so its alt can never bleed through and
   let the plate stand alone. Specific enough to beat .wb-sc-poster{display:block}. */
.cine-hero__media .cine-hero__poster[src=""],
.cine-hero__media .cine-hero__poster:not([src]) { display: none !important; }

/* Decorative scrub layer — hidden until the kernel has actually drawn a frame,
   so no-JS, reduced-motion and failed-asset visitors all keep the poster. */
.cine-hero__frames {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none;
}

/* Vignette over the photo: gradient structure stays literal and each stop is
   tinted from a token, so a recolor can never flatten it into an opaque veil. */
.cine-hero__veil {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; pointer-events: none;
  background:
    linear-gradient(to top,
      color-mix(in oklab, var(--background) 40%, transparent) 0%,
      color-mix(in oklab, var(--background) 8%, transparent) 34%,
      transparent 66%),
    radial-gradient(118% 96% at 50% 40%,
      transparent 44%,
      color-mix(in oklab, var(--background) 32%, transparent) 100%);
}

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (min-width: 62rem) {
  .cine-hero__inner { grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr); }
  .cine-hero__media, .cine-hero__poster { aspect-ratio: 6 / 5; }
}
/* Short laptop: go cinemascope so the whole stage still fits one viewport when
   pin-stage holds it (a pinned stage clips what overflows). */
@media (min-width: 62rem) and (max-height: 46rem) {
  .cine-hero__media, .cine-hero__poster { aspect-ratio: 16 / 10; }
  .cine-hero__stage { min-height: 100svh; }
}
@media (max-width: 26rem) {
  .cine-hero__actions { gap: var(--cine-2); }
  .cine-hero__cta { width: 100%; }
}

/* ── Micro-interactions ─────────────────────────────────────────────────── */
/* Authored opt-IN: under prefers-reduced-motion: reduce there is simply no
   transition to suppress. transform/colour only — never a layout property. */
@media (prefers-reduced-motion: no-preference) {
  .cine-hero__cta {
    transition:
      background-color var(--cine-dur-micro) var(--cine-ease),
      box-shadow var(--cine-dur-ui) var(--cine-ease),
      transform var(--cine-dur-micro) var(--cine-ease);
  }
  .cine-hero__cta:hover { transform: translateY(-2px); }
  .cine-hero__cta:active { transform: translateY(0); }
  .cine-hero__ghost-label { transition: border-bottom-color var(--cine-dur-micro) var(--cine-ease); }
  .cine-hero__ghost-arrow { transition: transform var(--cine-dur-micro) var(--cine-ease); }
  .cine-hero__ghost:hover .cine-hero__ghost-arrow { transform: translateX(.35rem); }
}

/* ── section component: testimonials ── */
/* Section Component: testimonials — self-contained, token-only, recolor-safe.
   Relies on the shared primitive layer for .container / .section-head /
   .eyebrow / .reveal. Dormant until the L1 CSS collector. */
.testimonials { padding-block: var(--space-section); }
.testimonials__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: clamp(1.25rem, 2.5vw, 2rem); }
.testimonial-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem; }
.testimonial-card__quote { font-family: var(--font-display); font-size: 1.2rem; line-height: 1.5; margin-bottom: 1.5rem; }
.testimonial-card__author { display: flex; align-items: center; gap: .85rem; }
.testimonial-card__author img { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; }
/* Empty-image guard, component-scoped so it travels with an INJECTED section:
   the L2 renderer leaves src="" until the owner uploads a photo, and a visible
   <img src=""> is the browser's broken-image icon. */
.testimonial-card__author img[src=""], .testimonial-card__author img:not([src]) { display: none !important; }
.testimonial-card__name { font-weight: 600; font-size: .95rem; }
.testimonial-card__role { font-size: .82rem; color: var(--muted); }

/* ── section component: faqs ── */
/* Section Component: faqs — self-contained, token-only, recolor-safe.
   Relies on the shared primitive layer for .container / .section-head /
   .eyebrow / .reveal (present in every composed theme). Dormant until the
   L1 CSS collector wires it into the composed stylesheet. */
.faqs { padding-block: var(--space-section); background: var(--surface); }
.faqs__list { max-width: 780px; margin-inline: auto; }
.faq-item { border-bottom: 1px solid var(--border); }
.faq-item__q { display: flex; align-items: center; justify-content: space-between; gap: 1rem; width: 100%; padding: 1.35rem 0; background: none; border: none; cursor: pointer; text-align: left; font-family: var(--font-display); font-size: 1.15rem; color: var(--text); }
.faq-item__icon { flex: none; transition: transform var(--dur-ui) var(--ease-standard); }
.faq-item[open] .faq-item__icon { transform: rotate(45deg); }
.faq-item__a { padding-bottom: 1.35rem; color: var(--muted); max-width: 68ch; }

/* ── section component: contact ── */
/* Section Component: contact — self-contained, token-only, recolor-safe.
   Relies on the shared primitive layer for .container / .section-head /
   .eyebrow / .reveal. Dormant until the L1 CSS collector. */
.contact { padding-block: var(--space-section); background: var(--surface); }
.contact__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.5rem; max-width: 900px; }
.contact__item { display: flex; flex-direction: column; gap: .3rem; }
.contact__item span:first-child { font-size: .72rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.contact__item a, .contact__item p { font-size: 1.05rem; }

/* ── list empty state (TFS8-2) ── */
.wb-list-empty { grid-column: 1 / -1; margin: 0; padding: var(--space-md, 1.5rem) 0; color: var(--muted); text-align: center; }


/* Preset: Noir — sharp, high-contrast luxe. Appended after base; :root wins. */
:root {
  --primary: #15130f;
  --primary-dark: #000000;
  --primary-light: #3a352d;
  --secondary: #6f675a;
  --accent: #c9a24b;
  --background: #ffffff;
  --surface: #f2efe9;
  --text: #15130f;
  --muted: #746f64;
  --border: #e1ddd3;
  --radius: 3px;
}

/* ── motion pack: cinematic (P2.1 — vibe-driven reveal) ───────────────────────
   Resting state is fully visible; the hidden `from` is gated behind @supports
   AND prefers-reduced-motion. transform/opacity only. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: wb-reveal-cinematic 1s cubic-bezier(.19,1,.22,1) both;
      animation-timeline: view();
      animation-range: entry 0% cover 35%;
    }
      .reveal:nth-child(2) { animation-range: entry 12% cover 47%; }
      .reveal:nth-child(3) { animation-range: entry 24% cover 59%; }
      .reveal:nth-child(4) { animation-range: entry 36% cover 71%; }
      .reveal:nth-child(5) { animation-range: entry 48% cover 83%; }
      .reveal:nth-child(6) { animation-range: entry 60% cover 95%; }

    @keyframes wb-reveal-cinematic {
      from { opacity: 0; transform: translateY(34px) scale(.97); }
      to   { opacity: 1; transform: none; }
    }
  }
}

/* Reduced-motion + no-support safety net: content is always visible. */
@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none; opacity: 1; transform: none; }
}
/* ── surface finish (P2.2) — hero-scoped, token-driven, pointer-transparent ── */
[data-section="hero"] { position: relative; isolation: isolate; }
[data-section="hero"]::after {
  content: ""; position: absolute; inset: -20%; z-index: -1; pointer-events: none;
  background:
    radial-gradient(45% 45% at 25% 30%, color-mix(in srgb, var(--primary, #2563eb) 22%, transparent) 0%, transparent 70%),
    radial-gradient(40% 40% at 75% 60%, color-mix(in srgb, var(--accent, var(--primary, #2563eb)) 18%, transparent) 0%, transparent 70%);
  filter: blur(38px);
  transform: translate3d(0, 0, 0);
}
@media (prefers-reduced-motion: no-preference) {
  [data-section="hero"]::after { animation: wb-aurora-drift 24s ease-in-out infinite alternate; }
  @keyframes wb-aurora-drift {
    from { transform: translate3d(-3%, -2%, 0) scale(1); }
    to   { transform: translate3d(3%, 2%, 0) scale(1.08); }
  }
}
/* ── surface finish (P2.2) — hero-scoped, token-driven, pointer-transparent ── */
[data-section="hero"] { position: relative; isolation: isolate; }
[data-section="hero"]::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  background-repeat: repeat;
  opacity: 0.07;
  mix-blend-mode: overlay;
}
/* ── imagery treatment (P2.3) — per-team token, editorial images only ────────
   Product, menu and logo images are intentionally excluded: their colour is
   information, not decoration. */
[data-section="hero"] img,
[data-section="about"] img {
  filter: var(--img-filter, none);
}

/* __wobooks-defensive__ — appended by HtmlZipThemeConverterV2.
   Hide images whose src resolves to empty (e.g. data-src-field bindings
   for Items / categories the owner hasn't uploaded a photo for yet).
   Without this rule, the browser shows the alt-text fallback —
   that's the bug behind the literal word 'image' showing in avatar
   slots and About images on the production Braise theme. */
img[src=""], img:not([src]) { display: none !important; }

/* Grid-collapse fix: [data-list] is the WoBooks repeater wrapper. When the
   grid/flex layout lives on the PARENT, the wrapper would otherwise become
   a single grid/flex item and collapse every [data-item] row into one cell.
   display:contents makes the wrapper layout-transparent so each row
   participates in the parent track. Mirrors TemplateSkeletonGenerator so
   converted themes match skeleton/AI-generated themes. (Convention: never
   put the grid/flex container ON the [data-list] element itself.) */
[data-list] { display: contents; }
