/* products.css - Velvet Cinema products section (item 14)
 * Shared by products / product-detail / product-item (the latter two @import this).
 * Tokens only; primitives (.btn, .section, .container, .eyebrow, .cms-content)
 * come from style.css. Mobile-first, min-width queries only.
 */

/* ============================================================
   Logo plates (shared) - SVG inherits text colour in BOTH themes.
   fill:currentColor is the key: paths with no explicit fill inherit
   it too, so monochrome logos read on cream AND on dark teal.
   ============================================================ */
.kbp-logo { display: flex; align-items: center; justify-content: center; color: var(--color-heading); }
.kbp-logo svg { fill: currentColor; color: inherit; width: auto; height: auto; display: block; }
/* Force every shape to currentColor so monochrome logos read in both themes,
   even when the source SVG set fills via inline style (CSS beats presentation
   attrs; this also covers shapes that defaulted to black). */
.kbp-logo svg path, .kbp-logo svg polygon, .kbp-logo svg rect,
.kbp-logo svg circle, .kbp-logo svg ellipse, .kbp-logo svg g, .kbp-logo svg text { fill: currentColor; }
.kbp-wordmark {
    font-family: var(--font-display); font-weight: var(--weight-bold);
    color: var(--color-heading); text-align: center; letter-spacing: -0.01em;
    line-height: 1.1; text-wrap: balance;
}

/* ============================================================
   HUB - Hero (type-led, atmospheric)
   DOMINANT MOMENT: weight-contrast masthead headline over a soft
   accent/rose glow - .kbp-hero__title
   ============================================================ */
.kbp-hero { position: relative; overflow: hidden; padding: clamp(3rem, 2.5rem + 4vw, 6rem) 0 clamp(2.5rem, 2rem + 3vw, 4rem); }
/* Atmosphere: two soft brand-tinted glows so the hero is never a flat slab. */
.kbp-hero::before {
    content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background:
      radial-gradient(115% 80% at 94% 2%, color-mix(in srgb, var(--color-accent-glow) 13%, transparent), transparent 56%),
      radial-gradient(80% 70% at -8% 108%, color-mix(in srgb, var(--color-rose) 14%, transparent), transparent 60%);
}
/* Split: editorial text left, image panel right - balances the masthead. */
.kbp-hero__inner { display: grid; grid-template-columns: 1fr; gap: clamp(2rem, 1.5rem + 3vw, 3.5rem); align-items: center; }
/* Batch 3 of the 768-1023 sweep: the GRID moves to 768, the viewport height does NOT.
   Same split as the home hero, and the same reasoning Ben picked there on 2026-08-12 -
   the 880 block below does two separable things, and forcing `min-height: 100svh` onto a
   768-879 tablet makes it surrender the whole screen to a hero for no gain. The media
   plate was the actual defect here: frozen at min(19rem, 62%) = 304px inside a 721-810px
   row, leaving a 417-506px one-sided void. Two columns closes that.
   The media cap is released here too, because from this width up the TRACK governs the
   panel (minmax(220px, 0.78fr)), which is the same handover the 880 rule always made. */
@media (min-width: 768px) {
    .kbp-hero__inner { width: 100%; grid-template-columns: minmax(0, 1.7fr) minmax(220px, 0.78fr); gap: clamp(2.5rem, 1.5rem + 4vw, 5rem); }
    .kbp-hero__media { max-width: none; margin-inline: 0; }
}
@media (min-width: 880px) {
    /* Fill one viewport below the 96px sticky header so the whole hero fits without scrolling. */
    /* --header-h, not a hardcoded 96px: the header is 98px here and 157px at
       1280+, so the old constant left the hero 61px too tall on wide desktop. */
    .kbp-hero { min-height: calc(100svh - var(--header-h)); display: flex; align-items: center; padding-block: clamp(1.5rem, 4vh, 3rem); }
}
.kbp-hero__eyebrow { margin-bottom: var(--space-lg); }
.kbp-hero__title {
    /* Velvet Cinema editorial serif hero (matches .svcs-hero__title). */
    font-family: var(--font-serif); font-optical-sizing: auto; font-weight: 350;
    font-size: clamp(2.6rem, 1.6rem + 4vw, 5rem); line-height: 1.02; letter-spacing: -0.015em;
    max-width: 18ch; color: var(--color-heading);
}
.kbp-hero__title em { font-style: italic; font-weight: 480; color: var(--color-rose-deep); }
/* Explicit line so "Behind Every" stay together; "Transformation" falls to its own line. */
.kbp-hero__title-line { display: block; }
/* Lighter lead line - the 300/800 weight contrast carries the hierarchy at full contrast. */
.kbp-hero__title-soft { display: block; font-weight: var(--weight-light); letter-spacing: -0.02em; color: var(--color-muted); }
.kbp-hero__lede { max-width: 52ch; margin-top: var(--space-lg); font-size: var(--text-lg); line-height: 1.55; color: var(--color-body); }
.kbp-hero__rule { display: block; width: 72px; height: 3px; margin-top: var(--space-xl); border-radius: var(--radius-full); background: var(--gradient-accent); }
/* Quiet editorial meta line - replaces the generic 3-up stats band (an anti-pattern). */
.kbp-hero__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.55rem 1.05rem; margin-top: var(--space-xl); font-size: var(--text-2xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--color-muted); }
.kbp-hero__meta-item { display: inline-flex; align-items: baseline; gap: 0.5em; }
.kbp-hero__meta-num { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-lg); letter-spacing: -0.01em; line-height: 1; color: var(--color-heading); }
.kbp-hero__meta-dot { width: 4px; height: 4px; border-radius: 50%; background: var(--color-accent); align-self: center; opacity: 0.7; }
/* Hero image / placeholder panel (right column).
   NO CROP: the panel takes the image's own ratio rather than forcing one and
   letting object-fit:cover trim it. The shoot is portrait (~3:4) and Ben's
   standing rule is that portrait photography is never cropped - narrow the
   column instead (the /specials/ gift panel set the precedent). That rule wins
   over the generic "hero images use object-fit:cover" default. */
.kbp-hero__media { position: relative; border-radius: var(--radius-xl); overflow: hidden; background: var(--color-bg-elevated); box-shadow: var(--shadow-lg); }
/* 768-879 only, which is why it hid: at 880 the two-column rule below hands the panel a
   minmax(220px, 0.78fr) track and everything looks fine again. Below that gate the shelf
   photograph is `width:100%` in a 1-col hero with no cap of its own - the `max-height:56svh`
   further down scopes to `.kbp-media-ph`, the EMPTY placeholder variant, not to a real photo -
   so it renders 721x962 at 768 and 771x1028 at 820: screen two is wall-to-wall shelving.
   Inert from 880 up, where the track resolves to 248-359px, well inside this cap. */
/* Left-aligned, not centred: eyebrow, title, lede, rule and the stat row are all left-set at
   x60, so a centred photo below them reads as a second, competing axis. */
@media (min-width: 768px) {
    .kbp-hero__media { max-width: 24rem; margin-inline: 0; }
}
.kbp-hero__media picture { display: block; }
.kbp-hero__media img { display: block; width: 100%; height: auto; }
/* The empty panel has no intrinsic size, so it declares the portrait shape the
   photo will take - the slot previews its own replacement. */
.kbp-hero__media.kbp-media-ph { aspect-ratio: 3 / 4; max-height: 56svh; }
@media (min-width: 880px) {
    .kbp-hero__media.kbp-media-ph { aspect-ratio: auto; height: clamp(420px, calc(100svh - var(--header-h) - 7rem), 660px); max-height: none; }
}

/* ============================================================
   Shared image placeholder panel - a designed stand-in until real
   product photography / distributor graphics are supplied. Brand-tinted,
   never a flat grey box. Swap by populating the relevant image field.
   ============================================================ */
.kbp-media-ph { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-sm); border: 1px solid var(--color-border);
    background:
      radial-gradient(120% 90% at 78% 12%, color-mix(in srgb, var(--color-accent-glow) 22%, transparent), transparent 55%),
      linear-gradient(155deg, var(--color-bg-elevated), color-mix(in srgb, var(--color-rose) 14%, var(--color-bg-elevated))); }
.kbp-media-ph__icon { color: color-mix(in srgb, var(--color-heading) 30%, transparent); }
.kbp-media-ph__label { font-size: var(--text-2xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--color-muted); }

/* ============================================================
   HUB - "The K Bella Standard" intro (editorial composition)
   The page body is one CMS blob; rendered raw it's a centred wall.
   We split it into beats: an asymmetric lead, supporting prose, the
   education credibility feature (the dominant moment), and a real CTA.
   DOMINANT MOMENT: the boxless education statement - .kbp-standard__feature
   ============================================================ */
.kbp-standard__inner { max-width: var(--container-max); margin-inline: auto; }
.kbp-standard__head-eyebrow { margin-bottom: clamp(1.75rem, 1.25rem + 2vw, 3rem); }

/* Lead: heading rail + lede body, asymmetric on desktop */
.kbp-standard__lead { display: grid; grid-template-columns: 1fr; gap: var(--space-md); }
.kbp-standard__lead-heading { font-family: var(--font-serif); font-optical-sizing: auto; font-weight: 350; font-size: clamp(2rem, 1.4rem + 2.6vw, 3.2rem); line-height: 1.04; letter-spacing: -0.015em; color: var(--color-heading); text-wrap: balance; }
.kbp-standard__lead-heading em { font-style: italic; font-weight: 480; color: var(--color-rose-deep); }
.kbp-standard__lead-body { font-size: var(--text-lg); line-height: 1.6; color: var(--color-body); }
@media (min-width: 880px) {
    .kbp-standard__lead { grid-template-columns: minmax(220px, 0.78fr) 1.7fr; gap: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); align-items: start; }
    .kbp-standard__lead-heading { position: sticky; top: var(--sticky-top); }
}

/* Supporting prose: heading rail left, body right (mirrors the lead split) */
.kbp-standard__prose { margin-top: var(--space-3xl); display: grid; grid-template-columns: 1fr; gap: var(--space-md); }
.kbp-standard__sub { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-xl); letter-spacing: -0.01em; line-height: 1.15; color: var(--color-heading); padding-left: var(--space-md); border-left: 3px solid var(--color-accent); }
.kbp-standard__prose-body { max-width: 64ch; }
@media (min-width: 880px) {
    .kbp-standard__prose { grid-template-columns: minmax(220px, 0.78fr) 1.7fr; gap: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); align-items: start; }
    .kbp-standard__sub { position: sticky; top: var(--sticky-top); }
}

/* Education feature - image + text band (the dominant intro moment) */
.kbp-standard__feature { margin-top: var(--space-3xl); display: grid; grid-template-columns: 1fr; gap: var(--space-xl); align-items: center; }
/* Same no-crop contract as the hero: the photo keeps its own ratio. */
.kbp-standard__feature-media { position: relative; border-radius: var(--radius-xl); overflow: hidden; box-shadow: var(--shadow-md); }
.kbp-standard__feature-media picture { display: block; }
.kbp-standard__feature-media img { display: block; width: 100%; height: auto; }
.kbp-standard__feature-media.kbp-media-ph { aspect-ratio: 4 / 5; }
.kbp-standard__feature-text { display: flex; flex-direction: column; gap: var(--space-md); }
.kbp-standard__feature-icon { display: inline-flex; color: var(--color-accent); }
.kbp-standard__feature-heading { font-family: var(--font-serif); font-optical-sizing: auto; font-weight: 350; font-size: clamp(1.8rem, 1.3rem + 2vw, 2.7rem); letter-spacing: -0.015em; line-height: 1.06; color: var(--color-heading); text-wrap: balance; }
.kbp-standard__feature-heading em { font-style: italic; font-weight: 480; color: var(--color-rose-deep); }
.kbp-standard__feature-body { font-size: var(--text-lg); line-height: 1.62; }
@media (min-width: 880px) {
    .kbp-standard__feature { grid-template-columns: minmax(220px, 0.78fr) 1.7fr; gap: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); }
}

/* Consultation CTA - real buttons, dropping the legacy bootstrap classes */
.kbp-standard__cta { margin-top: var(--space-3xl); padding-top: var(--space-2xl); border-top: 1px solid var(--color-border); display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-md); }
.kbp-standard__cta-heading { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-xl); letter-spacing: -0.01em; color: var(--color-heading); }
.kbp-standard__cta-text { max-width: 56ch; font-size: var(--text-base); line-height: 1.55; color: var(--color-body); }
.kbp-standard__cta-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-md); margin-top: var(--space-xs); }

/* Dark depth: a soft off-axis teal glow behind the Standard block so the dark
   section reads as an authored, lit field rather than a flat navy slab (the
   .noise grain is already on the section). Light theme unchanged. (#10 theme.) */
[data-theme="dark"] .kbp-standard { position: relative; isolation: isolate; }
[data-theme="dark"] .kbp-standard::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: radial-gradient(85% 55% at 15% 0%, var(--color-accent-glow) 0%, transparent 55%);
    opacity: 0.13;
}

/* Signature detail: an editorial serif drop cap opens the Standard lead prose
   (the one bespoke flourish that does not touch the deliberately-quiet stat
   row). (Punch-list #10 distinctive-detail.) */
.kbp-standard__lead-body > p:first-of-type::first-letter {
    float: left; margin: 0.02em 0.1em 0 0; font-family: var(--font-serif);
    font-optical-sizing: auto; font-weight: 380; font-size: 3.3em; line-height: 0.82;
    color: var(--color-rose-deep);
}

/* Studio intro (raw-body fallback when the blob can't be parsed) */
.kbp-intro__inner { max-width: var(--container-narrow); margin-inline: auto; text-align: center; }

/* ============================================================
   HUB - Category bands
   ============================================================ */
/* Tighter than the global .section rhythm: the numbered bands read as one
   continuous directory, not far-flung islands of cream. */
.kbp-band { padding-block: clamp(2.5rem, 1.8rem + 3vw, 4.5rem); }

/* Editorial band header - title and brand count on one baseline, note beneath */
.kbp-band__head {
    display: grid; grid-template-columns: 1fr auto; align-items: baseline;
    column-gap: clamp(0.85rem, 0.4rem + 2vw, 1.75rem); row-gap: var(--space-sm);
    padding-bottom: var(--space-lg); margin-bottom: var(--space-2xl);
    border-bottom: 1px solid var(--color-border);
}
.kbp-band__title { font-family: var(--font-serif); font-optical-sizing: auto; font-weight: 350; font-size: clamp(1.5rem, 1.05rem + 1.9vw, 2.5rem); letter-spacing: -0.015em; line-height: 1.05; color: var(--color-heading); text-wrap: balance; }
.kbp-band__title em { font-style: italic; font-weight: 480; color: var(--color-rose-deep); }
/* Category headings are anchor targets of the Products mega menu
   (/products/#kbp-cat-<key>): offset the landing so the sticky header
   doesn't cover the band top (same precedent as #beauty-services/#awards). */
.kbp-band__title[id^="kbp-cat-"] { scroll-margin-top: clamp(5.5rem, 8vw, 7rem); }
.kbp-band__count { justify-self: end; white-space: nowrap; font-size: var(--text-2xs); font-weight: var(--weight-medium); letter-spacing: 0.14em; text-transform: uppercase; color: var(--color-muted); }
.kbp-band__note { grid-column: 1 / -1; margin: 0; max-width: 56ch; font-size: var(--text-base); color: var(--color-muted); }

/* Per-category photo rail: one representative shot beside the brand index.
   Mobile = an editorial plate above the index. Desktop = a portrait plate in
   the narrow column that sticks and follows the scroll on tall bands.

   NO CROP (see the hero note): the plate takes the photo's own ratio. The old
   16/10 landscape box would have cut over half the height out of the 3:4
   shoot, and the desktop `height:100%` stretch trimmed the sides on top of
   that. Height is now the image's business; the column just sets the width. */
.kbp-band__layout { display: grid; grid-template-columns: 1fr; gap: clamp(2rem, 1.5rem + 3vw, 3.5rem); }
.kbp-band__media { width: min(19rem, 62%); border-radius: var(--radius-xl); box-shadow: var(--shadow-md); overflow: hidden; }
.kbp-band__media picture { display: block; }
.kbp-band__media img { display: block; width: 100%; height: auto; }
/* An empty slot has no intrinsic size, so it declares the portrait shape its
   photo will take. Width-capped above, so a missing photo can never inflate
   into a full-viewport panel on mobile (the /beauty/ placeholder defect). */
.kbp-band__media.kbp-media-ph { aspect-ratio: 3 / 4; }
/* Mobile carries the zig-zag too: the flipped bands push their plate right, so
   the alternating rhythm survives the single-column stack instead of collapsing
   into six identical left-aligned rows. */
.kbp-band--flip .kbp-band__media { margin-inline-start: auto; }
/* Batch 3: gate 880 -> 768. Six bands down the page, and below the gate every one of
   them froze its media plate at min(19rem, 62%) = 304px inside a 721-810px row, leaving a
   417-506px void that alternated side with the zig-zag - the same hole six times, mirrored.
   That is the single worst repetition in the band sweep. Pure grid plus sticky here, no
   viewport height involved, so the whole block moves. */
@media (min-width: 768px) {
    .kbp-band__layout { grid-template-columns: minmax(220px, 0.78fr) minmax(0, 1.7fr); gap: clamp(2.5rem, 1.5rem + 4vw, 4.5rem); align-items: stretch; }
    /* align-self:start opts out of the stretch (which would both distort the
       plate and break position:sticky). width:100% rather than auto: an empty
       slot is aspect-ratio-only, and with auto width it would size from the
       icon's min-content and collapse to a ~140px chip instead of filling the
       column. */
    .kbp-band__media { width: 100%; margin-inline: 0; align-self: start; position: sticky; top: var(--sticky-top); }
}

/* ── Zig-zag rhythm ───────────────────────────────────────────────────────
   The category bands alternate so the overview reads as an editorial sequence
   rather than one repeated CMS row. Every other band flips its media rail to
   the right AND carries a subtle alt-tone field; the opening band reads a size
   larger as the lead chapter. Photography still lands in every rail - the slots
   are unchanged, only the composition alternates. (Punch-list #10 BLOCKER.)
   DOMINANT MOMENT: the alternating media/index zig-zag down the page - .kbp-band--flip */
/* Alt-tone field: --color-bg-alt is theme-aware (deeper cream in light, deeper
   teal in dark), so the long scroll gains vertical rhythm instead of one flat tone. */
.kbp-band--tint { background: var(--color-bg-alt); }
/* Lead band: the first category opens with more air and a larger chapter title. */
.kbp-band--lead { padding-top: clamp(3.25rem, 2.25rem + 4vw, 5.5rem); }
.kbp-band--lead .kbp-band__title { font-size: clamp(1.85rem, 1.15rem + 2.7vw, 3.1rem); }
/* Gated at 768 to MATCH .kbp-band__layout above, not at 880. Batch 3 of the 768-1023
   sweep moved the two-column gate down to 768 and left this flip block at 880, so
   from 768 to 879 all six bands rendered two-column in the SAME direction and the
   alternating zig-zag - named as the dominant moment directly above - collapsed into
   six identical rows. That is precisely the repetition the layout comment calls "the
   single worst in the band sweep", reintroduced by moving one gate and not its pair.
   These two blocks are one mechanism; if either gate moves again, move both. */
@media (min-width: 768px) {
    /* Flip: brand index to the wide left column, media rail to the narrow right. */
    .kbp-band--flip .kbp-band__layout { grid-template-columns: 1.7fr minmax(220px, 0.78fr); }
    .kbp-band--flip .kbp-band__media { grid-column: 2; grid-row: 1; }
    .kbp-band--flip .kbp-band__body { grid-column: 1; grid-row: 1; }
}

/* ============================================================
   HUB - Boxless brand index (multi-brand categories)
   DOMINANT MOMENT: hairline-ruled directory rows - .kbp-row
   An editorial stockist index, not a card grid: the brand mark (clean
   logo on the section bg, or its name set in display type) reads left,
   a one-line descriptor centre, an Explore affordance right. Rows are
   divided by hairlines only - no plate, no box, no empty-cell void.
   Same [mark | rule | copy] language as the spotlight band, compact.
   ============================================================ */
.kbp-index { list-style: none; margin: 0; padding: 0; }
.kbp-index > li { border-bottom: 1px solid var(--color-border); }
.kbp-row {
    display: grid; grid-template-columns: 1fr; align-items: start;
    gap: var(--space-md) var(--space-xl);
    padding: clamp(1.5rem, 1rem + 1.6vw, 2.25rem) var(--space-sm);
    color: inherit; text-decoration: none;
    transition: background var(--transition-base);
}
/* LEFT: the written brand name leads, description beneath - the readable anchor. */
.kbp-row__text { min-width: 0; }
.kbp-row__name {
    margin: 0 0 0.4em; font-family: var(--font-display); font-weight: var(--weight-bold);
    font-size: clamp(1.25rem, 1rem + 0.9vw, 1.65rem); letter-spacing: -0.01em;
    line-height: 1.12; color: var(--color-heading); text-wrap: balance;
    transition: color var(--transition-base);
}
.kbp-row__desc { margin: 0; font-size: var(--text-base); line-height: 1.55; color: var(--color-muted); max-width: 56ch; }
/* RIGHT: logo + Explore as a supporting brand mark (the name now carries identity). */
.kbp-row__brand { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-sm); }
.kbp-row__mark {
    display: flex; align-items: center; justify-content: flex-start;
    min-height: 36px; color: var(--color-heading);
    transition: color var(--transition-base), filter var(--transition-base);
}
/* Equal optical footprint: --logo-h is computed per logo (products.php) from its
   aspect ratio so every mark hits the same visual area. */
.kbp-row__mark svg { height: var(--logo-h, 30px); width: auto; max-width: 100%; }
.kbp-row__more {
    position: relative;
    display: inline-flex; align-items: center; gap: 0.45em; white-space: nowrap;
    font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: 0.12em;
    text-transform: uppercase; color: var(--color-accent);
}
/* Underline-reveal on the EXPLORE label (stops short of the arrow) - the row's
   signature hover micro-interaction (Punch-list #10 minor). */
.kbp-row__more::after { content: ""; position: absolute; left: 0; right: 1.55em; bottom: -2px; height: 1.5px; background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--transition-base); }
.kbp-row__arrow { width: 1.1em; height: 1.1em; transition: transform var(--transition-base); }
@media (min-width: 700px) {
    .kbp-row {
        grid-template-columns: minmax(0, 2fr) minmax(180px, 0.7fr);
        gap: clamp(1.5rem, 1rem + 2vw, 3.5rem);
        align-items: center;
    }
    /* Logo + Explore align to the right edge as a brand block. */
    .kbp-row__brand { align-items: flex-end; text-align: right; }
    .kbp-row__mark { justify-content: flex-end; }
}

/* ============================================================
   Spotlight band (single brand + the XTC system) - boxless,
   large logo on the section bg with a hairline divider to the copy.
   ============================================================ */
.kbp-band--feature { position: relative; }
.kbp-band--feature::before {
    content: ""; position: absolute; inset: 0; pointer-events: none; z-index: -1;
    background: radial-gradient(ellipse at 18% 30%, color-mix(in srgb, var(--color-accent-glow) 7%, transparent), transparent 60%);
}
.kbp-spotlight {
    display: grid; grid-template-columns: 1fr; align-items: center; gap: var(--space-xl);
    color: inherit; text-decoration: none;
}
.kbp-spotlight__logo {
    display: flex; align-items: center; justify-content: center;
    min-height: 150px; padding: var(--space-xl) var(--space-md);
    color: var(--color-heading); transition: color var(--transition-base);
}
.kbp-spotlight__logo svg { max-height: 104px; max-width: 70%; }
.kbp-spotlight__logo .kbp-wordmark { font-size: var(--text-3xl); }
.kbp-spotlight__body { display: flex; flex-direction: column; gap: var(--space-md); }
/* Logo-less feature: the big left wordmark already names the brand - don't repeat it. */
.kbp-spotlight--wordmark .kbp-spotlight__name { display: none; }
.kbp-spotlight__badge { align-self: flex-start; font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-accent); border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent); padding: 0.3rem 0.75rem; border-radius: var(--radius-full); }
.kbp-spotlight__name { font-family: var(--font-display); font-weight: var(--weight-extrabold); font-size: clamp(1.6rem, 1.2rem + 1.8vw, 2.6rem); letter-spacing: -0.02em; line-height: 1.05; color: var(--color-heading); text-wrap: balance; }
/* Brand mark in the spotlight body: the brand's own logo set inline with the
   description (same role the wordmark name plays), not a generic plate. Sized a
   touch larger than the grid-row marks for the feature scale. */
.kbp-spotlight__mark { justify-content: flex-start; min-height: 44px; color: var(--color-heading); transition: color var(--transition-base), filter var(--transition-base); }
.kbp-spotlight__mark svg { height: clamp(34px, 4.5vw, 54px); width: auto; max-width: min(100%, 16rem); }
.kbp-spotlight__desc { font-size: var(--text-base); line-height: 1.6; color: var(--color-muted); max-width: 56ch; }
.kbp-spotlight__more { margin-top: var(--space-xs); align-self: flex-start; display: inline-flex; align-items: center; gap: 0.5em; font-size: var(--text-sm); font-weight: var(--weight-semibold); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-accent); }
.kbp-spotlight__more svg { transition: transform var(--transition-base); }
@media (min-width: 760px) {
    .kbp-spotlight { grid-template-columns: 0.8fr 1.2fr; gap: clamp(2rem, 1rem + 3vw, 4rem); }
    .kbp-spotlight__logo { border-right: 1px solid var(--color-border); padding-right: clamp(1.5rem, 1rem + 2vw, 3rem); }
}
/* Plain spotlight: no logo column (the band's graphic rail is the visual), so it
   stays single-column and always shows the brand name. Higher specificity beats
   the 760px two-column rule above. */
.kbp-spotlight.kbp-spotlight--plain { grid-template-columns: 1fr; }
.kbp-spotlight--plain .kbp-spotlight__name { display: block; }

/* ============================================================
   Lineup / related section header (the cards use .kbp-block, below)
   ============================================================ */
.kbd-lineup__head { margin-bottom: var(--space-2xl); }
.kbd-lineup__heading { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-2xl); letter-spacing: -0.01em; color: var(--color-heading); text-wrap: balance; }
.kbd-lineup__sub { margin-top: var(--space-xs); font-size: var(--text-sm); color: var(--color-muted); }

/* ============================================================
   BRAND detail - Editorial Ledger hero (reuses basic-page.css .bp-hero
   + .bp-body so the brand page matches every other interior page).
   These rules only add the boxless brand letterhead mark above the
   ledger title and style the "Visit site" link in the meta row.
   ============================================================ */
/* Lead row: ledger title left, boxless brand logo right - the logo fills the
   right-hand white space the left-aligned ledger title leaves empty. Mobile
   stacks the logo above the title (column-reverse); no plate, ever. */
.kbd-lead { display: flex; flex-direction: column-reverse; align-items: flex-start; gap: clamp(1.1rem, 0.8rem + 1vw, 1.75rem); }
.kbd-lead__mark { display: flex; color: var(--color-heading); }
/* explicit height (not auto) so the boxless, width-less flex mark doesn't collapse to 0 */
.kbd-lead__mark svg { height: clamp(44px, 6vw, 60px); width: auto; max-width: min(240px, 66vw); }
@media (min-width: 760px) {
    /* Title left, logo right, vertically centred against the title block. */
    .kbd-lead--logo { flex-direction: row; align-items: center; justify-content: space-between; gap: clamp(2rem, 1rem + 4vw, 5rem); }
    .kbd-lead__text { flex: 1 1 auto; min-width: 0; }
    .kbd-lead--logo .kbd-lead__mark { flex: 0 0 auto; justify-content: flex-end; }
    .kbd-lead--logo .kbd-lead__mark svg { height: clamp(78px, 9vw, 128px); max-width: min(320px, 34vw); }
}
/* "Visit site" link in the .bp-hero__meta row - link-coloured with arrow */
.kbd-visit { display: inline-flex; align-items: center; gap: 0.4em; color: var(--color-link); font-weight: var(--weight-semibold); }
.kbd-visit svg { transition: transform var(--transition-base); }

/* ============================================================
   BRAND detail - story + sticky consideration rail (2-col)
   Fills the empty left gutter the lone centred reading column used to leave
   under the ledger title, turning the lopsided single column into an
   intentional [rail | story] split. Mobile stacks the rail above the story.
   (Punch-list #10 MAJOR.)
   DOMINANT MOMENT: the sticky Book-a-consultation card anchoring the story - .kbd-railcard
   ============================================================ */
.kbd-article__grid { display: grid; grid-template-columns: 1fr; gap: var(--space-xl); }
.kbd-railcard {
    display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-sm);
    padding: clamp(1.5rem, 1.2rem + 1vw, 2rem);
    background: var(--color-bg-elevated); border: 1px solid var(--color-border);
    border-radius: var(--radius-card); box-shadow: var(--shadow-sm);
}
.kbd-railcard__hook { font-family: var(--font-serif); font-optical-sizing: auto; font-weight: 400; font-style: italic; font-size: var(--text-lg); line-height: 1.15; color: var(--color-heading); text-wrap: balance; }
.kbd-railcard__note { font-size: var(--text-sm); line-height: 1.6; color: var(--color-muted); }
.kbd-railcard__book { margin-top: var(--space-xs); align-self: stretch; justify-content: center; }
/* Inline flow (not a flex row) so the label + arrow wrap together in the narrow
   rail - a flex row orphaned the arrow onto its own centred line for long
   category names (e.g. "Professional Hair Care"). */
.kbd-railcard__link { font-size: var(--text-2xs); font-weight: var(--weight-semibold); letter-spacing: 0.08em; line-height: 1.5; text-transform: uppercase; color: var(--color-link); text-decoration: none; }
.kbd-railcard__link svg { display: inline-block; vertical-align: -0.15em; margin-left: 0.35em; transition: transform var(--transition-base); }
/* Batch 3: gate 880 -> 768, across 22 product-detail pages. Below the gate the sticky
   rail became a full-width banner, `align-self: stretch` inflated its CTA into a 666-714px
   pill, and the note ran to 86 characters. The sweep measured the two-column form fitting
   at 768 (230/436), so this gate was a default rather than a floor. */
@media (min-width: 768px) {
    .kbd-article__grid { grid-template-columns: minmax(230px, 0.72fr) minmax(0, 1.7fr); gap: clamp(2.5rem, 1.5rem + 4vw, 5rem); align-items: start; }
    /* Left-align the story in its wide column (override the shared .bp-body auto-centring). */
    .bp-body.kbd-article .cms-content { margin-inline: 0; }
    .kbd-railcard { position: sticky; top: var(--sticky-top); }
}
@media (hover: hover) {
    .kbd-railcard__link:hover { text-decoration: underline; text-underline-offset: 3px; }
    .kbd-railcard__link:hover svg { transform: translateX(3px); }
}

.kbd-related { padding-top: clamp(2.5rem, 2rem + 2vw, 4rem); }

/* BRAND / PRODUCT - prev/next nav */
.kbd-nav { padding: var(--space-xl) 0; }
.kbd-nav__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md); }
.kbd-nav__link { display: inline-flex; align-items: center; gap: var(--space-sm); min-height: 44px; color: var(--color-heading); text-decoration: none; max-width: 42%; }
.kbd-nav__link--next { text-align: right; }
.kbd-nav__arrow { color: var(--color-accent); flex-shrink: 0; transition: transform var(--transition-base); }
.kbd-nav__meta { display: flex; flex-direction: column; }
.kbd-nav__eyebrow { font-size: var(--text-2xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-muted); }
.kbd-nav__name { font-family: var(--font-display); font-weight: var(--weight-semibold); font-size: var(--text-base); line-height: 1.2; }
.kbd-nav__back { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: var(--radius-full); border: 1px solid var(--color-border); color: var(--color-heading); flex-shrink: 0; transition: color var(--transition-base), border-color var(--transition-base), background var(--transition-base); }

/* ============================================================
   SUB-PRODUCT - reuses basic-page .bp-hero/.bp-body (same family as the
   brand page). Ledger title hero, then the description paired with a
   PORTRAIT-cropped product shot in a sticky side column. The source shots
   are landscape with the product centred; a portrait crop (object-fit:cover)
   zooms into the product and drops the wide empty margins.
   ============================================================ */
/* Portrait product shot floated beside the description: text wraps to its left
   and flows full-width beneath it, so long bodies never leave an empty column.
   Mobile = centred block above the copy; tablet+ = floated right. */
.kbi-figure { position: relative; margin: 0 auto var(--space-lg); width: 100%; max-width: 320px; aspect-ratio: 3 / 4; border-radius: var(--radius-xl); overflow: hidden; background: var(--color-product-mat); border: 1px solid var(--color-border); box-shadow: var(--shadow-md); }
/* img_webp() wraps the <img> in an inline <picture>. Absolutely fill the frame
   so there's no baseline/line-box offset (which left a gap at the top + clipped
   the bottom - invisible in light, visible in dark). Image is pre-cropped to 3:4
   by kbProductCrop(); contain then shows the whole product with no clip. */
.kbi-figure picture { position: absolute; inset: 0; display: block; }
/* margin:0 + border-radius:0 override .cms-content img (the figure floats INSIDE
   the reading column, whose `img { margin:1.5rem 0 }` was shoving the photo down
   ~24px - the gap-at-top / clipped-bottom bug). */
.kbi-figure img { display: block; width: 100%; height: 100%; margin: 0; border-radius: 0; object-fit: contain; object-position: center; }
.kbi-figure.kbp-media-ph { aspect-ratio: 3 / 4; }
/* Give the wrapped reading column a touch more measure so the text beside the
   float isn't cramped, then the body flows full-width below. */
.bp-body .kbi-doc { max-width: 78ch; }
@media (min-width: 680px) {
    .kbi-figure { float: right; width: clamp(240px, 34%, 330px); margin: 0.35rem 0 1.25rem clamp(1.5rem, 1rem + 2vw, 2.5rem); }
    /* Keep headings from riding up tight against the float top edge. */
    .kbi-doc > h2:first-child, .kbi-doc > h3:first-child { margin-top: 0; }
}

/* ============================================================
   Product blocks - heading + description LEFT, portrait shot RIGHT.
   Used by the "More from the system" related list. Mobile stacks the
   photo on top; tablet+ goes side-by-side.
   ============================================================ */
.kbp-blocks { display: flex; flex-direction: column; gap: var(--space-lg); }
.kbp-block { display: flex; flex-direction: column-reverse; gap: var(--space-md); padding: var(--space-lg); background: var(--color-bg-card); border: 1px solid var(--color-border); border-radius: var(--radius-card); color: inherit; text-decoration: none; transition: transform var(--transition-smooth), box-shadow var(--transition-base), border-color var(--transition-base); }
.kbp-block__body { display: flex; flex-direction: column; gap: var(--space-xs); flex: 1 1 auto; min-width: 0; }
.kbp-block__name { font-family: var(--font-display); font-weight: var(--weight-semibold); font-size: var(--text-xl); line-height: 1.15; color: var(--color-heading); }
.kbp-block__size { align-self: flex-start; font-size: var(--text-2xs); font-weight: var(--weight-medium); letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-muted); background: var(--color-bg-mid); border: 1px solid var(--color-border); padding: 0.2rem 0.55rem; border-radius: var(--radius-full); }
.kbp-block__desc { font-size: var(--text-base); line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
.kbp-block__link { margin-top: var(--space-xs); display: inline-flex; align-items: center; gap: 0.4em; font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--color-accent); }
.kbp-block__arrow { width: 1em; height: 1em; transition: transform var(--transition-base); }
.kbp-block__media { position: relative; flex: 0 0 auto; width: 100%; max-width: 220px; margin-inline: auto; aspect-ratio: 3 / 4; border-radius: var(--radius-lg); overflow: hidden; background: var(--color-product-mat); border: 1px solid var(--color-border); }
.kbp-block__media picture { position: absolute; inset: 0; display: block; }
.kbp-block__media img { display: block; width: 100%; height: 100%; margin: 0; border-radius: 0; object-fit: contain; object-position: center; transition: transform var(--transition-slow); }
.kbp-block__media.kbp-media-ph { aspect-ratio: 3 / 4; }
@media (min-width: 640px) {
    .kbp-block { flex-direction: row; align-items: center; gap: clamp(1.5rem, 1rem + 2vw, 3rem); padding: clamp(1.25rem, 1rem + 1vw, 2rem); }
    .kbp-block__media { align-self: center; margin-inline: 0; width: clamp(150px, 22%, 230px); }
}
/* Two-column grid variant for the long XTC lineup (keeps 12 items compact). */
@media (min-width: 920px) {
    .kbp-blocks--grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-lg); }
    .kbp-blocks--grid .kbp-block__media { width: clamp(140px, 30%, 190px); }
}

/* ============================================================
   Hover / motion - gated to pointer + motion-OK
   ============================================================ */
@media (hover: hover) {
    /* Brand index row: warm the mark to accent, tint the row, slide arrow */
    .kbp-row:hover { background: var(--color-bg-elevated); }
    .kbp-row:hover .kbp-row__name { color: var(--color-accent); }
    .kbp-row:hover .kbp-row__mark { color: var(--color-accent); filter: drop-shadow(0 0 14px color-mix(in srgb, var(--color-accent) 30%, transparent)); }
    .kbp-row:hover .kbp-row__arrow { transform: translateX(4px); }
    .kbp-row:hover .kbp-row__more::after { transform: scaleX(1); }
    /* Spotlight */
    .kbp-spotlight:hover .kbp-spotlight__logo { color: var(--color-accent); }
    .kbp-spotlight:hover .kbp-spotlight__mark { color: var(--color-accent); filter: drop-shadow(0 0 14px color-mix(in srgb, var(--color-accent) 30%, transparent)); }
    .kbp-spotlight:hover .kbp-spotlight__more svg { transform: translateX(5px); }
    /* Product block (text left / photo right) */
    .kbp-block:hover { transform: translateY(-4px); box-shadow: var(--shadow-xl); border-color: var(--color-border-hover); }
    .kbp-block:hover .kbp-block__arrow { transform: translateX(4px); }
    .kbp-block:hover .kbp-block__media img { transform: scale(1.04); }
    /* Brand hero visit link */
    .kbd-visit:hover { color: var(--color-accent); }
    .kbd-visit:hover svg { transform: translate(2px, -2px); }
    /* Prev / next nav */
    .kbd-nav__link:hover .kbd-nav__arrow { transform: translateX(4px); }
    .kbd-nav__link--prev:hover .kbd-nav__arrow { transform: translateX(-4px); }
    .kbd-nav__back:hover { color: var(--color-accent); border-color: var(--color-accent); background: var(--color-bg-elevated); }
}

@media (prefers-reduced-motion: reduce) {
    .kbp-row, .kbp-row__mark, .kbp-row__arrow,
    .kbp-spotlight__logo, .kbp-spotlight__mark, .kbp-spotlight__more svg,
    .kbp-block, .kbp-block__media img, .kbp-block__arrow, .kbd-nav__arrow, .kbd-nav__back { transition: none !important; }
    .kbp-block:hover { transform: none; }
}
