/* ============================================================
   Bizsite v6 — Design System Foundation
   ============================================================
   Modern CSS foundation for the v6 fork. Replaces the !important-heavy
   theme-runtime overrides with predictable cascade layers, derived colors,
   variable-font typography, and reusable motion primitives.

   Loading order in <head>:
     1. tailwind (utility classes)
     2. design-system.css     ← THIS FILE (cascade layers + tokens + variants)
     3. design-styles.css     (legacy v5 design styles — being phased out)
     4. theme-variables.css   (legacy v5 theme vars — being phased out)
     5. theme-runtime.js      (color theme application)

   The cascade layers below let v6 styling win predictably without !important
   wars. Anything inside @layer v6.<name> will override Tailwind utilities and
   v5 legacy styles, but v6 layers themselves cascade in declared order.
   ============================================================ */

@layer reset, tokens, base, layout, personality, variants, motion, utilities;

/* ============================================================
   @layer tokens — the single source of truth for colors, type, space, motion.
   Brand color is the ONE input that drives the entire palette via color-mix.
   ============================================================ */
@layer tokens {
    :root {
        /* ── Brand color (the one input that drives everything else) ── */
        --brand-h: 250;       /* hue, 0-360 */
        --brand-c: 0.18;      /* chroma, 0-0.4 (vibrancy) */
        --brand-l: 55%;       /* lightness, 0-100% */
        --brand: oklch(var(--brand-l) var(--brand-c) var(--brand-h));

        /* ── Derived palette (no hand-tuning needed per theme) ── */
        --brand-50:  oklch(97% calc(var(--brand-c) * 0.15) var(--brand-h));
        --brand-100: oklch(94% calc(var(--brand-c) * 0.25) var(--brand-h));
        --brand-200: oklch(88% calc(var(--brand-c) * 0.4)  var(--brand-h));
        --brand-300: oklch(80% calc(var(--brand-c) * 0.6)  var(--brand-h));
        --brand-400: oklch(70% calc(var(--brand-c) * 0.8)  var(--brand-h));
        --brand-500: var(--brand);
        --brand-600: oklch(48% var(--brand-c) var(--brand-h));
        --brand-700: oklch(40% calc(var(--brand-c) * 0.9) var(--brand-h));
        --brand-800: oklch(30% calc(var(--brand-c) * 0.7) var(--brand-h));
        --brand-900: oklch(20% calc(var(--brand-c) * 0.5) var(--brand-h));

        /* Accent — a complementary hue for highlights, derived automatically */
        --accent-h: calc(var(--brand-h) + 180);
        --accent: oklch(60% calc(var(--brand-c) * 0.7) var(--accent-h));

        /* ── Surface tones — derived from brand for cohesion, very low chroma ── */
        --surface-page:    oklch(99% calc(var(--brand-c) * 0.05) var(--brand-h));
        --surface-card:    #ffffff;
        --surface-muted:   oklch(96% calc(var(--brand-c) * 0.08) var(--brand-h));
        --surface-sunken:  oklch(93% calc(var(--brand-c) * 0.1)  var(--brand-h));

        /* ── Text — neutral but with a hint of brand for warmth ── */
        --text-primary:   oklch(18% calc(var(--brand-c) * 0.15) var(--brand-h));
        --text-secondary: oklch(38% calc(var(--brand-c) * 0.2)  var(--brand-h));
        --text-muted:     oklch(45% calc(var(--brand-c) * 0.15) var(--brand-h));
        --text-on-brand:  oklch(98% 0.005 var(--brand-h));

        /* ── Borders — also derived ── */
        --border-subtle: color-mix(in oklch, var(--brand) 8%, transparent);
        --border-default: color-mix(in oklch, var(--brand) 15%, transparent);
        --border-strong: color-mix(in oklch, var(--brand) 30%, transparent);

        /* ── Shadows — premium soft ── */
        --shadow-sm: 0 1px 2px color-mix(in oklch, var(--brand) 8%, transparent);
        --shadow-md: 0 4px 12px color-mix(in oklch, var(--brand) 10%, transparent),
                     0 2px 4px color-mix(in oklch, var(--brand) 6%, transparent);
        --shadow-lg: 0 10px 30px color-mix(in oklch, var(--brand) 12%, transparent),
                     0 4px 10px color-mix(in oklch, var(--brand) 8%, transparent);
        --shadow-xl: 0 25px 50px color-mix(in oklch, var(--brand) 15%, transparent),
                     0 10px 20px color-mix(in oklch, var(--brand) 10%, transparent);

        /* ── Type scale — fluid, viewport-aware via clamp() ── */
        --font-display: 'Manrope Variable', 'Inter Variable', system-ui, sans-serif;
        --font-body:    'Inter Variable', system-ui, sans-serif;
        --font-mono:    'JetBrains Mono Variable', ui-monospace, monospace;

        --text-xs:   clamp(0.75rem, 0.7rem + 0.2vw, 0.8rem);
        --text-sm:   clamp(0.875rem, 0.825rem + 0.2vw, 0.9rem);
        --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.0625rem);
        --text-lg:   clamp(1.125rem, 1.05rem + 0.4vw, 1.25rem);
        --text-xl:   clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
        --text-2xl:  clamp(1.5rem, 1.35rem + 0.75vw, 1.875rem);
        --text-3xl:  clamp(1.875rem, 1.65rem + 1.125vw, 2.5rem);
        --text-4xl:  clamp(2.5rem, 2.1rem + 2vw, 3.75rem);
        --text-5xl:  clamp(3rem, 2.4rem + 3vw, 5rem);
        --text-6xl:  clamp(3.75rem, 2.8rem + 4.75vw, 7rem);

        /* ── Spacing scale — consistent rhythm ── */
        --space-1: 0.25rem;
        --space-2: 0.5rem;
        --space-3: 0.75rem;
        --space-4: 1rem;
        --space-6: 1.5rem;
        --space-8: 2rem;
        --space-12: 3rem;
        --space-16: 4rem;
        --space-20: 5rem;
        --space-24: 6rem;
        --space-32: 8rem;

        /* ── Radius scale ── */
        --radius-sm:  6px;
        --radius-md:  10px;
        --radius-lg:  16px;
        --radius-xl:  24px;
        --radius-2xl: 32px;
        --radius-full: 9999px;

        /* ── Motion timing ── */
        --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
        --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
        --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
        --duration-fast: 150ms;
        --duration-base: 250ms;
        --duration-slow: 500ms;

        /* ── Container widths ── */
        --container-sm: 640px;
        --container-md: 768px;
        --container-lg: 1024px;
        --container-xl: 1280px;
        --container-2xl: 1440px;

        /* ── Bridge tokens to legacy v5 vars so existing code keeps working ── */
        --theme-primary: var(--brand-600);
        --theme-secondary: var(--brand-700);
        --theme-shadow: var(--shadow-md);
        --theme-light: var(--surface-muted);
        --surface-50: var(--brand-50);
        --surface-100: var(--brand-100);
    }

    /* Honour user's reduced-motion preference for everything timing-related */
    @media (prefers-reduced-motion: reduce) {
        :root {
            --duration-fast: 0ms;
            --duration-base: 0ms;
            --duration-slow: 0ms;
        }
    }

}

/* ============================================================
   @layer base — body/section defaults that quietly modernise the look.
   ============================================================ */
@layer base {
    body[data-v6="true"] {
        font-family: var(--font-body);
        color: var(--text-primary);
        /* Split background-color + background-image so accessibility tooling
           (axe, Lighthouse) can sample a solid surface colour for contrast
           checks instead of reporting white when it can't resolve a gradient. */
        background-color: var(--surface-page);
        background-image:
            var(--page-overlay, none),
            var(--page-bg, none);
        background-attachment: fixed, scroll;
        background-size: 240px 240px, cover;
        font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11', 'ss01';
        text-rendering: optimizeLegibility;
        -webkit-font-smoothing: antialiased;
    }

    body[data-v6="true"] section {
        padding: var(--space-20) 0;
    }

    /* Heading typography is scoped to <main> so it doesn't leak into the
       footer (which has its own dark theme via Tailwind's bg-gray-900 +
       text-white) — that was leaving light-palette dark text on dark footer
       and failing AA contrast. Footer keeps inherited Tailwind colours. */
    body[data-v6="true"] main h1,
    body[data-v6="true"] main h2,
    body[data-v6="true"] main h3,
    body[data-v6="true"] main h4 {
        font-family: var(--font-display);
        color: var(--text-primary);
        line-height: 1.1;
        letter-spacing: -0.02em;
        font-weight: 650;
    }
    body[data-v6="true"] main h1 { font-size: var(--text-5xl); letter-spacing: -0.035em; }
    body[data-v6="true"] main h2 { font-size: var(--text-4xl); letter-spacing: -0.03em; }
    body[data-v6="true"] main h3 { font-size: var(--text-2xl); }
    body[data-v6="true"] main h4 { font-size: var(--text-xl); }
    body[data-v6="true"] main p { line-height: 1.65; color: var(--text-secondary); }
}

/* ============================================================
   @layer personality — restrained "voice" variants applied via
   data-personality attr on <body>. Replaces v5's heavy design styles.
   Each variant tunes typography weight/letterspacing/radius — no
   skew, no clip-path, no brutalist borders. The personality should
   be felt, not announced.
   ============================================================ */
@layer personality {

    /* refined: editorial, generous whitespace, thin display weights */
    body[data-personality="refined"] {
        --font-display: 'Fraunces Variable', 'Playfair Display', Georgia, serif;
        --radius-md: 4px;
        --radius-lg: 8px;
        --radius-xl: 12px;
    }
    body[data-personality="refined"] h1,
    body[data-personality="refined"] h2 {
        font-weight: 350;
        letter-spacing: -0.04em;
        font-variation-settings: 'opsz' 144, 'SOFT' 50;
    }
    body[data-personality="refined"] section {
        padding: var(--space-24) 0;
    }

    /* bold: heavy display, tight leading, vivid surfaces */
    body[data-personality="bold"] {
        --font-display: 'Manrope Variable', 'Archivo Variable', system-ui, sans-serif;
    }
    body[data-personality="bold"] h1,
    body[data-personality="bold"] h2,
    body[data-personality="bold"] h3 {
        font-weight: 800;
        letter-spacing: -0.04em;
        line-height: 0.95;
    }

    /* friendly: rounded radii, slightly looser type, warm */
    body[data-personality="friendly"] {
        --radius-md: 16px;
        --radius-lg: 24px;
        --radius-xl: 32px;
    }
    body[data-personality="friendly"] h1,
    body[data-personality="friendly"] h2 {
        font-weight: 700;
        letter-spacing: -0.015em;
    }

    /* minimal: monochrome, low chroma, system font */
    body[data-personality="minimal"] {
        --brand-c: 0.04;
        --font-display: 'Inter Variable', system-ui, sans-serif;
        --radius-md: 2px;
        --radius-lg: 4px;
    }
    body[data-personality="minimal"] h1,
    body[data-personality="minimal"] h2 {
        font-weight: 500;
    }

    /* default: balanced — applied when no data-personality is set */
    body[data-v6="true"]:not([data-personality]) {
        /* Inherits :root defaults */
    }
}

/* ============================================================
   @layer variants — section-shape variants.
   v6 hard-codes intentional layout VARIETY into the defaults so the
   page never looks like a repeating grid. The variety is curated:

       services   →  bento (mixed-size auto-flow cards)
       products   →  spotlight (first product is the hero, rest tile)
       gallery    →  masonry (Pinterest-style variable heights)
       team       →  bento (asymmetric)
       about      →  split (text + features 50/50)
       testimonials → grid (intentional symmetry as a visual rest)

   No data-layout attribute needed — these apply by default in v6.
   We keep the data-layout opt-out so a future "Classic Grid" toggle
   can override section-by-section if you ever want it.
   ============================================================ */
@layer variants {

    /* ── ABOUT (split = default, kept as-is) ───────────────── */
    body[data-v6="true"] #about:not([data-layout="bento"]):not([data-layout="stacked"]) .container > div:first-child {
        display: grid;
        grid-template-columns: 1fr;
        gap: var(--space-12);
        align-items: center;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] #about:not([data-layout="bento"]):not([data-layout="stacked"]) .container > div:first-child {
            grid-template-columns: 1fr 1fr;
        }
    }

    /* ── SERVICES (bento = default) ────────────────────────── */
    body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid {
        display: grid;
        gap: var(--space-4);
        grid-template-columns: repeat(6, 1fr);
        grid-auto-flow: dense;
    }
    body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > * {
        grid-column: span 2;
        background: var(--surface-card);
        border-radius: var(--radius-lg);
        padding: var(--space-6);
        box-shadow: var(--shadow-sm);
        transition: box-shadow var(--duration-base) var(--ease-out),
                    transform var(--duration-base) var(--ease-out);
    }
    body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *:hover {
        box-shadow: var(--shadow-lg);
        transform: translateY(-2px);
    }
    body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *:nth-child(5n+1) {
        grid-column: span 4;
    }
    body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *:nth-child(7n+3) {
        grid-column: span 3;
    }
    /* On narrow viewports drop to a single column for legibility.
       Override grid-template-columns to 1fr too — leaving the 6-col template
       in place allowed long unbreakable words ("Service") to widen the first
       implicit track and bleed the grid past the viewport. Also matches the
       specificity of the desktop nth-child rules above (which carry a
       :nth-child pseudo = +1 class) by adding !important; otherwise the
       desktop "span 4 / span 3" wins on equal selector chain. */
    @media (max-width: 640px) {
        body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid {
            grid-template-columns: 1fr !important;
        }
        body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *,
        body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *:nth-child(5n+1),
        body[data-v6="true"] #services:not([data-layout="grid"]):not([data-layout="timeline"]) #services-grid > *:nth-child(7n+3) {
            grid-column: 1 / -1 !important;
        }
    }

    /* ── PRODUCTS (spotlight = default) ────────────────────── */
    body[data-v6="true"] #yext-products-section:not([data-layout="grid"]):not([data-layout="masonry"]) #yext-products-container > div {
        display: grid;
        gap: var(--space-6);
        grid-template-columns: 1fr;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] #yext-products-section:not([data-layout="grid"]):not([data-layout="masonry"]) #yext-products-container > div {
            grid-template-columns: 2fr 1fr 1fr;
            grid-auto-rows: minmax(260px, auto);
        }
        body[data-v6="true"] #yext-products-section:not([data-layout="grid"]):not([data-layout="masonry"]) #yext-products-container > div > *:first-child {
            grid-row: span 2;
        }
    }

    /* ── GALLERY (masonry = default) ───────────────────────── */
    body[data-v6="true"] #gallery #gallery-grid:not([data-layout="grid"]) {
        column-count: 1;
        column-gap: var(--space-4);
    }
    @media (min-width: 640px) {
        body[data-v6="true"] #gallery #gallery-grid:not([data-layout="grid"]) {
            column-count: 2;
        }
    }
    @media (min-width: 1024px) {
        body[data-v6="true"] #gallery #gallery-grid:not([data-layout="grid"]) {
            column-count: 3;
        }
    }
    body[data-v6="true"] #gallery #gallery-grid:not([data-layout="grid"]) > * {
        break-inside: avoid;
        margin-bottom: var(--space-4);
        display: inline-block;
        width: 100%;
        border-radius: var(--radius-lg);
        overflow: hidden;
    }

    /* TEAM grid is owned by the inline auto-fit rule that renderBios() and
       renderSkeletonBios() inject — see app.js. The earlier "asymmetric
       bento" 6-col override was forcing every card to grid-column: span 6
       below 640px and otherwise fragmenting the row, which is why the
       v5 inline rule never won. Removed. */
}

/* ============================================================
   @layer hero — modern hero treatments. Each variant is opt-in via
   the existing .hero-layout-{name} class added by applyHeroLayout().
   The classic centered/product/inset stay in legacy theme-runtime.js;
   the variants below add bolder modern shapes including the "stage"
   card-on-photo treatment.

   For variants that use the business photo as a full-bleed background
   (stage, frame), theme-runtime.js syncs #hero-image src into a CSS var
   --hero-bg-image on #home. Falls back to the brand gradient if no
   image is set yet.

   IMPORTANT: v5 base styles paint `.hero-pattern` with the theme
   gradient via `!important`. We override the gradient inline through
   CSS custom properties + reset background-image where needed.
   ============================================================ */
@layer variants {

    /* Reset hero-pattern gradient + the v5 padding for our variants so
       the layout below has full control of the section box. */
    body[data-v6="true"] #home[class*="hero-layout-split-image-right"],
    body[data-v6="true"] #home[class*="hero-layout-stage"],
    body[data-v6="true"] #home[class*="hero-layout-editorial"],
    body[data-v6="true"] #home[class*="hero-layout-asymmetric"],
    body[data-v6="true"] #home[class*="hero-layout-frame"],
    body[data-v6="true"] #home[class*="hero-layout-overlay-grid"] {
        padding: 0 !important;
    }

    /* On mobile the fixed navbar (~80px tall) sits over the top of the hero.
       The Tailwind pt-24 (96px) on the hero leaves only ~16px clearance,
       which clips the logo's white-circle background under the nav shadow.
       Bump to --space-32 (128px) so the logo has ~48px breathing room.
       Includes #home (one ID) to beat line 410's `padding: 0 !important`
       (which carries an #home + class[] attribute, total 1,2,1 — without
       #home here, our 0,2,2 loses despite being later in source order).
       Also flips align-items to flex-start on centred layouts: on mobile
       the wrapper's content is taller than (90vh − nav clearance), so
       centring would pull the wrapper top back behind the nav. Frame
       keeps its flex-end (bottom-aligned card) so it's excluded. */
    @media (max-width: 640px) {
        body[data-v6="true"] section#home[data-section="hero"] {
            padding-top: var(--space-32) !important;
        }
        body[data-v6="true"] section#home.hero-layout-stage,
        body[data-v6="true"] section#home.hero-layout-editorial,
        body[data-v6="true"] section#home.hero-layout-asymmetric,
        body[data-v6="true"] section#home.hero-layout-overlay-grid,
        body[data-v6="true"] section#home.hero-layout-split-image-right,
        body[data-v6="true"] section#home.hero-layout-split-panel {
            align-items: flex-start !important;
        }
    }

    /* split-image-right — text left, image right, ~55/45 split.
       LAYOUT only: do NOT override background or text colour. Each colour
       theme defines its own hero treatment (brand gradient + heroText)
       and split-image-right inherits it via .hero-pattern, exactly the
       way Centered/Product/Inset do. Earlier we forced --surface-page +
       --text-primary here, which fought every theme's gradient and made
       contrast a per-theme problem. */
    body[data-v6="true"] .hero-layout-split-image-right {
        min-height: clamp(560px, 80vh, 800px);
        display: flex !important;
        align-items: center;
    }
    body[data-v6="true"] .hero-layout-split-image-right .container { width: 100%; max-width: var(--container-2xl); }
    body[data-v6="true"] .hero-layout-split-image-right .hero-content-wrapper {
        display: grid !important;
        grid-template-columns: 1fr;
        gap: var(--space-12);
        align-items: center;
        padding-top: 0 !important;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] .hero-layout-split-image-right .hero-content-wrapper {
            grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
            gap: var(--space-16);
        }
    }
    body[data-v6="true"] .hero-layout-split-image-right .hero-content-wrapper > div:first-child {
        text-align: left !important;
    }
    body[data-v6="true"] .hero-layout-split-image-right h1 {
        font-size: clamp(2.5rem, 2rem + 3vw, 4.5rem);
        line-height: 1.05;
    }
    body[data-v6="true"] .hero-layout-split-image-right .hero-content-wrapper > div:last-child {
        display: block !important; /* override .hidden md:block at small widths */
    }
    /* Belt-and-braces: the IMG also ships with class="hidden" which would
       cancel display:block via specificity (.hidden = 0,1,0 vs this rule
       0,3,1 — split should win, but quick-presets sometimes leave a stale
       inline style or a sibling layout override mid-flight). !important
       guarantees the image renders here regardless of prior state. */
    body[data-v6="true"] .hero-layout-split-image-right #hero-image {
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-xl);
        max-width: 100%;
        height: auto;
        display: block !important;
        aspect-ratio: 4 / 3;
        object-fit: cover;
    }

    /* split-panel — "carded composition". Two panels float side-by-side
       inside a neutral section with generous breathing room.
       Left  = soft brand-tinted rounded card holding dark text + brand button.
       Right = D-shaped image card (square left edge, fully-rounded right
               edge — looks like a capital D, opening towards the panel).

       Section background: PURE WHITE on light themes (cleaner than the
       slightly-brand-tinted --surface-page); --surface-page on dark themes
       so dark themes still get their dark background. */
    body[data-v6="true"] .hero-layout-split-panel {
        background: #ffffff !important;
        background-image: none !important;
        /* Top padding is taller than bottom — the nav is fixed (~88px) so
           top clearance needs to clear that plus a comfortable buffer. */
        padding: clamp(var(--space-20), 9vw, var(--space-24)) 0 clamp(var(--space-12), 6vw, var(--space-20)) 0 !important;
    }
    body[data-v6="true"][data-palette="dark"] .hero-layout-split-panel {
        background: var(--surface-page) !important;
    }
    body[data-v6="true"] .hero-layout-split-panel .container {
        width: 100%;
        /* Match the rest of the page's container width (Tailwind max-w-7xl =
           1280px) so the image card doesn't bleed past the page grid. */
        max-width: var(--container-xl);
    }
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper {
        display: grid !important;
        grid-template-columns: 1fr;
        gap: var(--space-6);
        align-items: stretch;
        padding-top: 0 !important;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper {
            grid-template-columns: 1fr 1fr;
            gap: var(--space-8);
        }
    }
    /* LEFT — soft tinted brand wash, rounded card, dark text. The mix is
       small so the wash reads as a tint, not a solid colour, which lets
       --text-primary stay readable without an inverse text colour. */
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child {
        background: color-mix(in oklch, var(--brand) 12%, var(--surface-page)) !important;
        color: var(--text-primary);
        padding: clamp(var(--space-8), 4vw, var(--space-12));
        border-radius: var(--radius-xl);
        display: flex;
        flex-direction: column;
        justify-content: center;
        text-align: left !important;
        /* Height matches the image card via grid align-items: stretch. No
           min-height here — it used to fight the image's aspect-ratio at
           small-desktop widths (cell width × 3/4 fell below the floor,
           stretching the IMG out of shape). */
    }
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child > * {
        margin-left: 0 !important;
        margin-right: 0 !important;
    }
    /* Type scale is intentionally smaller than the bolder hero variants
       (centered, stage, frame). Split-panel reads as a "card hero" — text
       sits on a tinted panel beside an image, so it should feel like
       editorial body copy with a confident headline, not a billboard.
       !important needed to beat the `body[data-v6="true"] main h1` base
       rule and Tailwind's responsive .text-6xl utility on the h1 element. */
    body[data-v6="true"] .hero-layout-split-panel h1 {
        font-size: clamp(1.5rem, 1rem + 1.6vw, 2.5rem) !important;
        line-height: 1.1;
    }
    body[data-v6="true"] .hero-layout-split-panel #hero-subtitle,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child p {
        font-size: clamp(0.95rem, 0.85rem + 0.4vw, 1.0625rem) !important;
        line-height: 1.55;
    }
    /* Keep each CTA button's text on one line; let the flex row wrap when
       the column is too narrow (small-desktop ~768-1100px) so each button
       sits cleanly instead of being squeezed into 2-line text. Buttons also
       get a smaller font + tighter padding to match the editorial scale. */
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child a {
        white-space: nowrap;
        font-size: 0.875rem !important;
        padding: 0.625rem 1rem !important;
    }
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child .flex {
        flex-wrap: wrap;
    }
    /* On md (768) through just below lg (1024) the split-cell is ~360-470px
       wide — 3 row-laid buttons don't fit comfortably even when nowrap.
       Stack them column in that range to match the small-mobile pattern. */
    @media (min-width: 768px) and (max-width: 1099px) {
        body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child .flex.sm\:flex-row {
            flex-direction: column !important;
            align-items: flex-start !important;
        }
    }
    /* RIGHT — D-SHAPED image card. Left edge has the same gentle radius as
       the text panel's corners (--radius-xl, ~24px); right edge fully-rounded
       (9999px collapses to half the cell's height) for the iconic capital-D
       silhouette.
       Aspect ratio: 1/1 (square) on mobile single-column layout so the
       image doesn't get unreasonably tall; 4/3 on desktop split. No
       min-height — aspect-ratio is the single source of truth for height
       so the IMG never gets stretched out of shape at small-desktop widths. */
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:last-child {
        display: block !important;
        border-radius: var(--radius-xl) 9999px 9999px var(--radius-xl);
        overflow: hidden;
        box-shadow: var(--shadow-xl);
        aspect-ratio: 1 / 1;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:last-child {
            aspect-ratio: 4 / 3;
        }
    }
    body[data-v6="true"] .hero-layout-split-panel #hero-image {
        width: 100% !important;
        height: 100% !important;
        object-fit: cover;
        display: block !important;
        border-radius: 0 !important;
        box-shadow: none !important;
    }
    /* Override the v6 brand-gradient hero rule (.hero-pattern { background: ... })
       so the section itself stays on the section bg defined above (white on
       light themes, --surface-page on dark themes). */
    body[data-v6="true"] #home.hero-layout-split-panel.hero-pattern {
        background: #ffffff !important;
        background-image: none !important;
    }
    body[data-v6="true"][data-palette="dark"] #home.hero-layout-split-panel.hero-pattern {
        background: var(--surface-page) !important;
    }

    /* stage — full-bleed photo background, centered card with text on top.
       Mirrors the modern "magazine cover" hero shown in the reference. */
    body[data-v6="true"] .hero-layout-stage {
        min-height: clamp(640px, 90vh, 880px);
        display: flex !important;
        align-items: center;
        justify-content: center;
        position: relative;
        background-image:
            linear-gradient(180deg,
                color-mix(in oklch, black 30%, transparent) 0%,
                color-mix(in oklch, black 55%, transparent) 100%),
            var(--hero-bg-image, var(--hero-gradient)) !important;
        background-size: cover, cover;
        background-position: center, center;
        background-repeat: no-repeat, no-repeat;
        color: var(--text-primary);
    }
    body[data-v6="true"] .hero-layout-stage .container {
        width: 100%;
        display: flex;
        justify-content: center;
    }
    body[data-v6="true"] .hero-layout-stage .hero-content-wrapper {
        display: block !important;
        max-width: var(--container-md);
        padding: var(--space-12);
        background: color-mix(in oklch, var(--surface-card) 92%, transparent);
        backdrop-filter: blur(14px);
        -webkit-backdrop-filter: blur(14px);
        border: 1px solid color-mix(in oklch, white 30%, transparent);
        border-radius: var(--radius-2xl);
        box-shadow: var(--shadow-xl);
        text-align: center !important;
        margin: 0 auto;
        padding-top: var(--space-12) !important;
    }
    body[data-v6="true"] .hero-layout-stage .hero-content-wrapper > div:first-child { text-align: center !important; }
    body[data-v6="true"] .hero-layout-stage .hero-content-wrapper > div:last-child { display: none; }
    body[data-v6="true"] .hero-layout-stage h1 {
        color: var(--text-primary);
        font-size: clamp(2rem, 1.5rem + 3vw, 3.5rem);
    }
    body[data-v6="true"] .hero-layout-stage p { color: var(--text-secondary); }
    body[data-v6="true"] .hero-layout-stage #hero-image { display: none !important; }
    body[data-v6="true"] .hero-layout-stage #hero-logo {
        margin-left: auto !important;
        margin-right: auto !important;
    }
    body[data-v6="true"] .hero-layout-stage .flex {
        justify-content: center !important;
    }

    /* editorial — oversized display type left, image right (40% column) */
    body[data-v6="true"] .hero-layout-editorial {
        min-height: clamp(560px, 85vh, 820px);
        display: flex !important;
        align-items: center;
        background: var(--surface-page) !important;
        background-image: none !important;
        color: var(--text-primary);
    }
    body[data-v6="true"] .hero-layout-editorial .container { width: 100%; max-width: var(--container-2xl); }
    body[data-v6="true"] .hero-layout-editorial .hero-content-wrapper {
        display: grid !important;
        grid-template-columns: 1fr;
        gap: var(--space-8);
        align-items: end;
        padding-top: 0 !important;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] .hero-layout-editorial .hero-content-wrapper {
            grid-template-columns: 2fr 1fr;
        }
    }
    body[data-v6="true"] .hero-layout-editorial .hero-content-wrapper > div:first-child {
        text-align: left !important;
    }
    body[data-v6="true"] .hero-layout-editorial h1 {
        font-size: clamp(3rem, 2rem + 5vw, 6rem);
        line-height: 0.95;
        letter-spacing: -0.045em;
        font-weight: 700;
        color: var(--text-primary);
    }
    body[data-v6="true"] .hero-layout-editorial p { color: var(--text-secondary); }
    body[data-v6="true"] .hero-layout-editorial .hero-content-wrapper > div:last-child { display: block !important; }
    body[data-v6="true"] .hero-layout-editorial #hero-image {
        border-radius: var(--radius-lg);
        max-width: 100%;
        height: auto;
        display: block;
        aspect-ratio: 4 / 5;
        object-fit: cover;
        box-shadow: var(--shadow-lg);
    }

    /* asymmetric — wide copy column + offset image */
    body[data-v6="true"] .hero-layout-asymmetric {
        min-height: clamp(560px, 80vh, 820px);
        display: flex !important;
        align-items: center;
        position: relative;
        overflow: hidden;
        background: var(--surface-page) !important;
        background-image: none !important;
        color: var(--text-primary);
    }
    body[data-v6="true"] .hero-layout-asymmetric .container { width: 100%; max-width: var(--container-2xl); }
    body[data-v6="true"] .hero-layout-asymmetric .hero-content-wrapper {
        display: grid !important;
        grid-template-columns: 1fr;
        gap: var(--space-8);
        align-items: center;
        padding-top: 0 !important;
    }
    @media (min-width: 768px) {
        body[data-v6="true"] .hero-layout-asymmetric .hero-content-wrapper {
            grid-template-columns: 1.5fr 1fr;
            gap: var(--space-12);
        }
    }
    body[data-v6="true"] .hero-layout-asymmetric .hero-content-wrapper > div:first-child {
        text-align: left !important;
    }
    body[data-v6="true"] .hero-layout-asymmetric h1 {
        font-size: clamp(2.5rem, 2rem + 3vw, 5rem);
        line-height: 1;
        color: var(--text-primary);
    }
    body[data-v6="true"] .hero-layout-asymmetric p { color: var(--text-secondary); }
    body[data-v6="true"] .hero-layout-asymmetric .hero-content-wrapper > div:last-child { display: block !important; }
    /* See split-image-right note: !important on display ensures presets
       don't leave the image hidden via .hidden / sibling overrides. */
    body[data-v6="true"] .hero-layout-asymmetric #hero-image {
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-xl);
        max-width: 100%;
        height: auto;
        display: block !important;
        aspect-ratio: 3 / 4;
        object-fit: cover;
    }

    /* frame — full-bleed image with copy in a bottom-left card.
       The hero image comes from the customer's GoldenPages listing — many
       are low-resolution. Sized to `cover` over a 900px-tall hero, those
       images pixelate badly. Move the photo onto a ::before pseudo so we
       can blur it: blur completely hides pixelation regardless of source
       resolution, and a dark overlay on top of that brings the image down
       to a moody texture that contrasts with the floating text card. */
    body[data-v6="true"] .hero-layout-frame {
        min-height: clamp(640px, 90vh, 900px);
        position: relative;
        background: var(--hero-gradient);
        display: flex !important;
        align-items: flex-end;
        padding: var(--space-12) var(--space-12) var(--space-16) var(--space-12) !important;
        color: var(--text-primary);
        overflow: hidden;
    }
    body[data-v6="true"] .hero-layout-frame::before {
        content: '';
        position: absolute;
        inset: -10px;
        background-image: var(--hero-bg-image, var(--hero-gradient));
        background-size: cover;
        background-position: center;
        background-repeat: no-repeat;
        filter: blur(10px) brightness(0.55);
        z-index: 0;
    }
    body[data-v6="true"] .hero-layout-frame::after {
        content: '';
        position: absolute;
        inset: 0;
        background: linear-gradient(0deg,
            color-mix(in oklch, black 55%, transparent) 0%,
            color-mix(in oklch, black 25%, transparent) 60%,
            color-mix(in oklch, black 10%, transparent) 100%);
        z-index: 0;
        pointer-events: none;
    }
    body[data-v6="true"] .hero-layout-frame > * {
        position: relative;
        z-index: 1;
    }
    body[data-v6="true"] .hero-layout-frame .container { width: 100%; max-width: var(--container-2xl); padding: 0 !important; }
    body[data-v6="true"] .hero-layout-frame .hero-content-wrapper {
        display: block !important;
        max-width: var(--container-md);
        background: var(--surface-card);
        padding: var(--space-8);
        /* Top corners rounded, bottom corners square — visually anchors the
           card to the bottom edge of the hero section as if it's resting on
           the photo. */
        border-radius: var(--radius-xl) var(--radius-xl) 0 0;
        box-shadow: var(--shadow-xl);
        padding-top: var(--space-8) !important;
    }
    body[data-v6="true"] .hero-layout-frame .hero-content-wrapper > div:first-child { text-align: left !important; }
    body[data-v6="true"] .hero-layout-frame .hero-content-wrapper > div:last-child { display: none; }
    body[data-v6="true"] .hero-layout-frame h1 {
        color: var(--text-primary);
        font-size: clamp(2rem, 1.5rem + 2.5vw, 3rem);
    }
    body[data-v6="true"] .hero-layout-frame p { color: var(--text-secondary); }
    body[data-v6="true"] .hero-layout-frame #hero-image { display: none !important; }

    /* ── Hero text colour PER LAYOUT ──
       Why this is per-layout instead of one .hero-pattern rule: the v5
       layouts (centered/product/inset) paint the brand gradient as the
       hero bg, so text needs --hero-text-color (white usually). The v6
       light-card layouts (split-image-right/editorial/asymmetric) paint
       the page surface, so text needs --text-primary. Overlay-grid paints
       a brand-color gradient so text needs --text-on-brand. Mixing them
       in one .hero-pattern rule + a separate variant rule kept the v5
       rule winning on cascade because #hero-title in its selector list
       gave it ID specificity that the variant rule couldn't beat.

       Solution: scope each rule to the SPECIFIC hero layout class so
       only one set of selectors targets each element at any time. */

    /* v5-style hero layouts (centered/product/inset): text on brand gradient */
    body[data-v6="true"] .hero-layout-centered h1,
    body[data-v6="true"] .hero-layout-centered h2,
    body[data-v6="true"] .hero-layout-centered p,
    body[data-v6="true"] .hero-layout-centered #hero-subtitle,
    body[data-v6="true"] .hero-layout-centered #hero-title,
    body[data-v6="true"] .hero-layout-centered #rating-text,
    body[data-v6="true"] .hero-layout-centered .text-purple-100,
    body[data-v6="true"] .hero-layout-centered .text-white,
    body[data-v6="true"] .hero-layout-product h1,
    body[data-v6="true"] .hero-layout-product h2,
    body[data-v6="true"] .hero-layout-product p,
    body[data-v6="true"] .hero-layout-product #hero-subtitle,
    body[data-v6="true"] .hero-layout-product #hero-title,
    body[data-v6="true"] .hero-layout-product #rating-text,
    body[data-v6="true"] .hero-layout-product .text-purple-100,
    body[data-v6="true"] .hero-layout-product .text-white,
    body[data-v6="true"] .hero-layout-inset h1,
    body[data-v6="true"] .hero-layout-inset h2,
    body[data-v6="true"] .hero-layout-inset p,
    body[data-v6="true"] .hero-layout-inset #hero-subtitle,
    body[data-v6="true"] .hero-layout-inset #hero-title,
    body[data-v6="true"] .hero-layout-inset #rating-text,
    body[data-v6="true"] .hero-layout-inset .text-purple-100,
    body[data-v6="true"] .hero-layout-inset .text-white,
    body[data-v6="true"] .hero-layout-split-image-right h1,
    body[data-v6="true"] .hero-layout-split-image-right h2,
    body[data-v6="true"] .hero-layout-split-image-right p,
    body[data-v6="true"] .hero-layout-split-image-right #hero-subtitle,
    body[data-v6="true"] .hero-layout-split-image-right #hero-title,
    body[data-v6="true"] .hero-layout-split-image-right #rating-text,
    body[data-v6="true"] .hero-layout-split-image-right .text-purple-100,
    body[data-v6="true"] .hero-layout-split-image-right .text-white {
        color: var(--hero-text-color, #ffffff) !important;
    }

    /* split-panel: text sits on a SOFT TINTED panel (~12% brand on white),
       so it reads as page text — use --text-primary (dark) for headings
       and --text-secondary for sub-copy. Same treatment as the v6 light-card
       layouts (stage/editorial/etc.) below. */
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child h1,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child h2,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child #hero-title {
        color: var(--text-primary) !important;
    }
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child p,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child #hero-subtitle,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child #rating-text {
        color: var(--text-secondary) !important;
    }
    /* CTAs on the tinted panel: solid brand pill (--brand-700 for AA contrast
       on white text even with light primaries — same approach as the other
       light-card hero variants). Phone CTA stays as an outlined brand pill. */
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child a.bg-white,
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child a[href="#contact"],
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child a[href="#action"] {
        background: var(--brand-700) !important;
        color: #ffffff !important;
    }
    body[data-v6="true"] .hero-layout-split-panel .hero-content-wrapper > div:first-child #hero-phone {
        background: transparent !important;
        color: var(--brand) !important;
        border: 2px solid var(--brand) !important;
    }

    /* v6 light-card hero layouts: text on page surface, dark for AA.
       (split-image-right was here historically; moved up to the v5-style
       group above so it inherits the theme's brand-gradient hero look
       instead of forcing --surface-page on every theme.) */
    body[data-v6="true"] .hero-layout-stage h1,
    body[data-v6="true"] .hero-layout-stage h2,
    body[data-v6="true"] .hero-layout-stage #hero-subtitle,
    body[data-v6="true"] .hero-layout-stage #hero-title,
    body[data-v6="true"] .hero-layout-stage #rating-text,
    body[data-v6="true"] .hero-layout-stage .text-purple-100,
    body[data-v6="true"] .hero-layout-stage .text-white,
    body[data-v6="true"] .hero-layout-editorial h1,
    body[data-v6="true"] .hero-layout-editorial h2,
    body[data-v6="true"] .hero-layout-editorial #hero-subtitle,
    body[data-v6="true"] .hero-layout-editorial #hero-title,
    body[data-v6="true"] .hero-layout-editorial #rating-text,
    body[data-v6="true"] .hero-layout-editorial .text-purple-100,
    body[data-v6="true"] .hero-layout-editorial .text-white,
    body[data-v6="true"] .hero-layout-asymmetric h1,
    body[data-v6="true"] .hero-layout-asymmetric h2,
    body[data-v6="true"] .hero-layout-asymmetric #hero-subtitle,
    body[data-v6="true"] .hero-layout-asymmetric #hero-title,
    body[data-v6="true"] .hero-layout-asymmetric #rating-text,
    body[data-v6="true"] .hero-layout-asymmetric .text-purple-100,
    body[data-v6="true"] .hero-layout-asymmetric .text-white,
    body[data-v6="true"] .hero-layout-frame h1,
    body[data-v6="true"] .hero-layout-frame h2,
    body[data-v6="true"] .hero-layout-frame #hero-subtitle,
    body[data-v6="true"] .hero-layout-frame #hero-title,
    body[data-v6="true"] .hero-layout-frame #rating-text,
    body[data-v6="true"] .hero-layout-frame .text-purple-100,
    body[data-v6="true"] .hero-layout-frame .text-white {
        color: var(--text-primary) !important;
    }
    /* Body paragraph text in light-card variants is the secondary muted text.
       split-image-right intentionally excluded — it now uses the brand-
       gradient hero treatment (see v5-style block above). */
    body[data-v6="true"] .hero-layout-stage p:not(#hero-subtitle),
    body[data-v6="true"] .hero-layout-editorial p:not(#hero-subtitle),
    body[data-v6="true"] .hero-layout-asymmetric p:not(#hero-subtitle),
    body[data-v6="true"] .hero-layout-frame p:not(#hero-subtitle) {
        color: var(--text-secondary) !important;
    }
    /* Sub-headline gets a slightly muted treatment too */
    body[data-v6="true"] .hero-layout-stage #hero-subtitle,
    body[data-v6="true"] .hero-layout-editorial #hero-subtitle,
    body[data-v6="true"] .hero-layout-asymmetric #hero-subtitle,
    body[data-v6="true"] .hero-layout-frame #hero-subtitle {
        color: var(--text-secondary) !important;
    }

    /* v6 overlay-grid: text on brand gradient (always light needed).
       Force #ffffff directly — do NOT route through --text-on-brand here.
       --text-on-brand is computed for contrast against --brand, but
       overlay-grid paints brand-700 → brand-900 (much darker), and for
       some themes (cobalt-blue family) text-on-brand resolves to a dark
       theme-text colour that ends up dark-on-dark on this layout. */
    body[data-v6="true"] .hero-layout-overlay-grid h1,
    body[data-v6="true"] .hero-layout-overlay-grid h2,
    body[data-v6="true"] .hero-layout-overlay-grid p,
    body[data-v6="true"] .hero-layout-overlay-grid #hero-subtitle,
    body[data-v6="true"] .hero-layout-overlay-grid #hero-title,
    body[data-v6="true"] .hero-layout-overlay-grid #rating-text,
    body[data-v6="true"] .hero-layout-overlay-grid .text-purple-100,
    body[data-v6="true"] .hero-layout-overlay-grid .text-white {
        color: #ffffff !important;
    }

    /* ── Hero CTA hardening ─────────────────────────────────
       Hero text colours are handled by the per-layout rules above.
       What's left is the call-to-action buttons that live in the
       hero (Book/Quote/Call). Tailwind ships them as bg-white +
       text-purple-600 + text-white, which doesn't translate well to
       light-card variants (white pill on white card) or to themes
       with light primaries (white text on light brand). */

    /* CTAs in light-card variants: brand-coloured pills.
       Use --brand-700 (the OKLCH-derived darker brand variant) for the bg
       instead of --brand, so white text always passes AA — even for
       light-primary themes like Saffron / Honey / Sand where #ffffff on
       --brand only hits ~3.4:1. Same fix that solved the nav-phone /
       hero-phone "contrast valley" problem. */
    /* CTAs in light-card variants get the brand-700 pill (white text passes
       AA on the darker brand variant even for light primaries like Saffron).
       split-image-right is NOT in this group — it uses the brand-gradient
       hero treatment, which means the existing per-theme CTA rules already
       give it the right pill style. */
    body[data-v6="true"] .hero-layout-stage a.bg-white,
    body[data-v6="true"] .hero-layout-stage a[href="#contact"],
    body[data-v6="true"] .hero-layout-stage a[href="#action"],
    body[data-v6="true"] .hero-layout-editorial a.bg-white,
    body[data-v6="true"] .hero-layout-editorial a[href="#contact"],
    body[data-v6="true"] .hero-layout-editorial a[href="#action"],
    body[data-v6="true"] .hero-layout-asymmetric a.bg-white,
    body[data-v6="true"] .hero-layout-asymmetric a[href="#contact"],
    body[data-v6="true"] .hero-layout-asymmetric a[href="#action"],
    body[data-v6="true"] .hero-layout-frame a.bg-white,
    body[data-v6="true"] .hero-layout-frame a[href="#contact"],
    body[data-v6="true"] .hero-layout-frame a[href="#action"] {
        background: var(--brand-700) !important;
        color: #ffffff !important;
    }
    /* Tel button: outline brand pill on light-card variants */
    body[data-v6="true"] .hero-layout-stage #hero-phone,
    body[data-v6="true"] .hero-layout-editorial #hero-phone,
    body[data-v6="true"] .hero-layout-asymmetric #hero-phone,
    body[data-v6="true"] .hero-layout-frame #hero-phone {
        background: transparent !important;
        color: var(--brand) !important;
        border: 2px solid var(--brand) !important;
    }
    body[data-v6="true"] .hero-layout-stage #rating-text,
    body[data-v6="true"] .hero-layout-editorial #rating-text,
    body[data-v6="true"] .hero-layout-asymmetric #rating-text,
    body[data-v6="true"] .hero-layout-frame #rating-text {
        color: var(--text-primary) !important;
    }

    /* Hero CTA text alignment.
       Several layouts (split-image-right / asymmetric / editorial / split-panel)
       set text-align:left on their content wrapper so headings/subtitle sit
       hard left, but that bleeds into the CTA buttons too — the row uses
       `flex flex-col sm:flex-row` so on mobile each <a> is a full-width
       block and its inner text inherits the left alignment, giving the
       mismatched look the user flagged (Book/Get a Quote left, Call Us
       arbitrarily centred by the icon spacer). Force CTA text centred
       everywhere by default — looks balanced on desktop where buttons sit
       at content width too. Brutalist + antidesign opt out on mobile only;
       their off-kilter typography stays. */
    body[data-v6="true"] section[data-section="hero"] a[href="#contact"],
    body[data-v6="true"] section[data-section="hero"] a[href="#action"],
    body[data-v6="true"] section[data-section="hero"] a.cc_loylopen,
    body[data-v6="true"] section[data-section="hero"] #hero-phone {
        text-align: center !important;
    }
    @media (max-width: 640px) {
        body.style-brutalist[data-v6="true"] section[data-section="hero"] a[href="#contact"],
        body.style-brutalist[data-v6="true"] section[data-section="hero"] a[href="#action"],
        body.style-brutalist[data-v6="true"] section[data-section="hero"] a.cc_loylopen,
        body.style-brutalist[data-v6="true"] section[data-section="hero"] #hero-phone,
        body.style-antidesign[data-v6="true"] section[data-section="hero"] a[href="#contact"],
        body.style-antidesign[data-v6="true"] section[data-section="hero"] a[href="#action"],
        body.style-antidesign[data-v6="true"] section[data-section="hero"] a.cc_loylopen,
        body.style-antidesign[data-v6="true"] section[data-section="hero"] #hero-phone {
            text-align: inherit !important;
        }
    }

    /* overlay-grid — DARK brand gradient + grid backdrop, copy floats above.
       Use brand-700 → brand-900 for the gradient so it's consistently dark
       across the whole surface. That way white text passes AA everywhere on
       the gradient regardless of the theme's primary lightness. */
    body[data-v6="true"] .hero-layout-overlay-grid {
        min-height: clamp(640px, 90vh, 900px);
        position: relative;
        display: flex !important;
        align-items: center;
        justify-content: center;
        text-align: center;
        background:
            linear-gradient(135deg, var(--brand-700) 0%, var(--brand-900) 100%) !important;
        overflow: hidden;
        color: #ffffff;
    }
    body[data-v6="true"] .hero-layout-overlay-grid::before {
        content: '';
        position: absolute;
        inset: 0;
        background-image:
            linear-gradient(color-mix(in oklch, white 10%, transparent) 1px, transparent 1px),
            linear-gradient(90deg, color-mix(in oklch, white 10%, transparent) 1px, transparent 1px);
        background-size: 48px 48px;
        opacity: 0.7;
        pointer-events: none;
    }
    body[data-v6="true"] .hero-layout-overlay-grid #hero-image { display: none !important; }
    body[data-v6="true"] .hero-layout-overlay-grid .container { width: 100%; }
    body[data-v6="true"] .hero-layout-overlay-grid .hero-content-wrapper {
        display: block !important;
        max-width: var(--container-md);
        position: relative;
        z-index: 1;
        padding: var(--space-8);
        margin: 0 auto;
    }
    body[data-v6="true"] .hero-layout-overlay-grid .hero-content-wrapper > div:first-child { text-align: center !important; }
    body[data-v6="true"] .hero-layout-overlay-grid .hero-content-wrapper > div:last-child { display: none; }
    body[data-v6="true"] .hero-layout-overlay-grid h1 {
        font-size: clamp(2.5rem, 2rem + 4vw, 5rem);
        line-height: 1;
    }
    body[data-v6="true"] .hero-layout-overlay-grid .flex {
        justify-content: center !important;
    }
    body[data-v6="true"] .hero-layout-overlay-grid #hero-logo {
        margin-left: auto !important;
        margin-right: auto !important;
    }
}

/* ============================================================
   @layer motion — scroll-driven entrance animations using modern
   CSS animation-timeline. Falls back gracefully on older browsers.
   Apply via [data-reveal] attribute on any element.
   ============================================================ */
@layer motion {
    @supports (animation-timeline: view()) {
        body[data-v6="true"] [data-reveal] {
            animation: v6-reveal-up linear both;
            animation-timeline: view();
            animation-range: entry 5% cover 30%;
        }
        body[data-v6="true"] [data-reveal="fade"] {
            animation-name: v6-reveal-fade;
        }
        body[data-v6="true"] [data-reveal="scale"] {
            animation-name: v6-reveal-scale;
        }
    }

    @keyframes v6-reveal-up {
        from { opacity: 0; transform: translateY(30px); }
        to   { opacity: 1; transform: translateY(0);    }
    }
    @keyframes v6-reveal-fade {
        from { opacity: 0; }
        to   { opacity: 1; }
    }
    @keyframes v6-reveal-scale {
        from { opacity: 0; transform: scale(0.96); }
        to   { opacity: 1; transform: scale(1);    }
    }

    /* Subtle hover lift for cards */
    body[data-v6="true"] .v6-card {
        transition: transform var(--duration-base) var(--ease-out),
                    box-shadow var(--duration-base) var(--ease-out);
    }
    body[data-v6="true"] .v6-card:hover {
        transform: translateY(-3px);
        box-shadow: var(--shadow-lg);
    }

    /* Smooth focus rings derived from brand */
    body[data-v6="true"] :focus-visible {
        outline: 2px solid var(--brand);
        outline-offset: 3px;
        border-radius: var(--radius-sm);
    }
}

/* ============================================================
   @layer components — quiet upgrades that compound.
   These selectors aim at existing markup so app.js + index.html
   don't need rewriting; the upgrades just appear in v6 mode.
   ============================================================ */
@layer components {

    /* ── Buttons ─────────────────────────────────────────────
       Primary CTAs are the existing .bg-purple-600/-700 (which the legacy
       theme-variables.css remaps to var(--theme-primary), itself bridged
       to var(--brand-600)). We layer a gradient + inset border + hover
       lift on top — all derived from --brand so it tunes per business.

       The :not() chain excludes:
        • demo-panel chrome
        • tab controls (menu/bio/product/google-reviews carousel buttons)
        • text-link-style buttons (anything with .text-purple-* class) —
          these are inline links visually, not solid pill CTAs. Without
          this exclusion they'd get a brand gradient background WHILE
          their text was already remapped to the brand colour, producing
          brand-on-brand and zero contrast. The "Read More" expander
          (#about-read-more-btn) is the canonical case.
        • #about-read-more-btn pinned by id as a belt-and-braces guard. */
    body[data-v6="true"] section button:not(.demo-panel button):not(.menu-tab):not(.bio-tab):not(.product-tab):not(#google-reviews button):not(#google-reviews-prev):not(#google-reviews-next):not(.google-review-readmore):not([class*="text-purple-"]):not(#about-read-more-btn):not(.faq-question),
    body[data-v6="true"] section a.bg-purple-600,
    body[data-v6="true"] section a[href="#contact"],
    body[data-v6="true"] section a[href="#action"] {
        background-image: linear-gradient(180deg,
            color-mix(in oklch, var(--brand) 100%, white 8%),
            var(--brand-600)) !important;
        border: 1px solid color-mix(in oklch, white 18%, transparent) !important;
        box-shadow:
            0 1px 0 color-mix(in oklch, white 20%, transparent) inset,
            0 1px 2px color-mix(in oklch, var(--brand) 25%, transparent),
            0 4px 10px color-mix(in oklch, var(--brand) 18%, transparent) !important;
        transition:
            transform var(--duration-fast) var(--ease-out),
            box-shadow var(--duration-base) var(--ease-out),
            background-image var(--duration-base) var(--ease-out) !important;
    }
    body[data-v6="true"] section button:not(.demo-panel button):not(.menu-tab):not(.bio-tab):not(.product-tab):not(#google-reviews button):not(#google-reviews-prev):not(#google-reviews-next):not(.google-review-readmore):not([class*="text-purple-"]):not(#about-read-more-btn):not(.faq-question):hover,
    body[data-v6="true"] section a.bg-purple-600:hover,
    body[data-v6="true"] section a[href="#contact"]:hover,
    body[data-v6="true"] section a[href="#action"]:hover {
        transform: translateY(-1px);
        box-shadow:
            0 1px 0 color-mix(in oklch, white 25%, transparent) inset,
            0 4px 8px color-mix(in oklch, var(--brand) 30%, transparent),
            0 12px 24px color-mix(in oklch, var(--brand) 22%, transparent) !important;
        background-image: linear-gradient(180deg,
            color-mix(in oklch, var(--brand) 100%, white 14%),
            color-mix(in oklch, var(--brand-600) 100%, black 6%)) !important;
    }
    body[data-v6="true"] section button:active {
        transform: translateY(0);
        transition-duration: 80ms;
    }

    /* ── Form inputs ─────────────────────────────────────────
       Brand-tinted focus ring; underline animation on focus instead
       of a full hard outline jump. */
    body[data-v6="true"] section input[type="text"],
    body[data-v6="true"] section input[type="email"],
    body[data-v6="true"] section input[type="tel"],
    body[data-v6="true"] section input[type="number"],
    body[data-v6="true"] section input[type="search"],
    body[data-v6="true"] section input[type="url"],
    body[data-v6="true"] section textarea,
    body[data-v6="true"] section select {
        background: var(--surface-card);
        border: 1px solid var(--border-default);
        border-radius: var(--radius-md);
        padding: var(--space-3) var(--space-4);
        font-family: var(--font-body);
        font-size: var(--text-base);
        color: var(--text-primary);
        transition:
            border-color var(--duration-base) var(--ease-out),
            box-shadow var(--duration-base) var(--ease-out);
    }
    body[data-v6="true"] section input:focus,
    body[data-v6="true"] section textarea:focus,
    body[data-v6="true"] section select:focus {
        outline: none;
        border-color: var(--brand);
        box-shadow:
            0 0 0 3px color-mix(in oklch, var(--brand) 25%, transparent),
            0 1px 3px color-mix(in oklch, var(--brand) 15%, transparent);
    }
    body[data-v6="true"] section input::placeholder,
    body[data-v6="true"] section textarea::placeholder {
        color: var(--text-muted);
    }

    /* ── FAQ accordion ───────────────────────────────────────
       The FAQ items are <div class="bg-gray-50"> wrappers containing a
       <button class="faq-question hover:bg-gray-100"> trigger. We already
       exclude .faq-question from the section-wide button-gradient sweep
       (so the button stays transparent and the parent card colour shows
       through), but two side-effects remained:
         1. Browsers paint a 1px user-agent border on <button>; with
            text colour mapped to var(--text-primary) on dark themes
            (cream), that border becomes a visible cream outline around
            every FAQ item.
         2. Tailwind's `hover:bg-gray-100` paints #f3f4f6 on hover —
            that's an explicit Tailwind hover utility, not the bare
            .bg-gray-100, so the dark-palette remap at line 1505 doesn't
            match it. On dark themes the hovered button flashes light
            grey under cream text → unreadable.
       Kill the browser border and define a deliberate hover treatment
       (brand-tinted lift on top of the card colour) that reads on both
       light and dark themes. Design-style overrides (antidesign /
       brutalist) can still layer their own border on top — they target
       `section button:not(...)` with higher-specificity rules that fall
       outside this selector. */
    body[data-v6="true"] section .faq-question {
        border: 0 !important;
        background: transparent !important;
    }
    body[data-v6="true"] section .faq-question:hover {
        background: color-mix(in oklch, var(--brand) 8%, var(--surface-card)) !important;
    }

    /* ── Cards ───────────────────────────────────────────────
       Targets section .bg-white (the universal card pattern in app.js).
       Brand-tinted surface, hairline border, 2-layer ambient+cast shadow.
       Excludes Google reviews + form fields + menu items already styled. */
    body[data-v6="true"] section .bg-white:not(button):not(input):not(textarea):not(.google-reviews-card):not(#google-reviews-header):not(.menu-display):not(#contact .bg-white) {
        background: var(--surface-card) !important;
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-lg) !important;
        box-shadow:
            0 1px 2px color-mix(in oklch, var(--brand) 5%, transparent),
            0 4px 12px color-mix(in oklch, var(--brand) 8%, transparent) !important;
        transition:
            box-shadow var(--duration-base) var(--ease-out),
            transform var(--duration-base) var(--ease-out);
    }
    body[data-v6="true"] section .bg-white:not(button):not(input):not(textarea):not(.google-reviews-card):not(#google-reviews-header):not(.menu-display):not(#contact .bg-white):hover {
        box-shadow:
            0 2px 4px color-mix(in oklch, var(--brand) 6%, transparent),
            0 12px 28px color-mix(in oklch, var(--brand) 12%, transparent) !important;
        transform: translateY(-2px);
    }

    /* ── Navigation ─────────────────────────────────────────
       Floating glass pill (extends the v5 inset-only behaviour to all
       hero variants) with backdrop blur. Falls back gracefully if
       backdrop-filter unsupported.
       :not(.style-swiss) excludes the Swiss design style — Swiss wants a
       totally flat solid nav (no glass, no blur, no border). The CSS-layer
       cascade reverses for !important (layered > non-layered), so this
       override has to live IN-RULE rather than as a separate non-layered
       sheet, or Swiss would never beat this !important glass rule. */
    body[data-v6="true"]:not(.style-swiss) nav {
        backdrop-filter: blur(14px) saturate(140%);
        -webkit-backdrop-filter: blur(14px) saturate(140%);
        background: color-mix(in oklch, var(--surface-card) 80%, transparent) !important;
        border-bottom: 1px solid var(--border-subtle);
    }
    body[data-v6="true"] nav .nav-link {
        font-weight: 500;
        transition: color var(--duration-fast) var(--ease-out);
    }
    body[data-v6="true"] nav .nav-link:hover {
        color: var(--brand);
    }

    /* ── Image treatment ────────────────────────────────────
       Aspect-ratio container + cover fit + brand-tinted hover overlay.
       Targets gallery grid img and similar — keeps logos/avatars alone. */
    body[data-v6="true"] #gallery-grid > * {
        position: relative;
        overflow: hidden;
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-md);
    }
    body[data-v6="true"] #gallery-grid img {
        width: 100%;
        height: auto;
        display: block;
        transition: transform var(--duration-slow) var(--ease-out);
    }
    body[data-v6="true"] #gallery-grid > *:hover img {
        transform: scale(1.04);
    }

    /* ── Section header eyebrow auto-injection ──────────────
       For sections whose h2 is the first child of a .text-center wrapper,
       prepend a small brand eyebrow. Uses ::before so no markup changes. */
    body[data-v6="true"] section .text-center > h2:first-child::before,
    body[data-v6="true"] section h2.text-4xl::before {
        content: attr(data-eyebrow);
        display: block;
        font-size: var(--text-xs);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.12em;
        color: var(--brand);
        margin-bottom: var(--space-3);
    }

    /* ── Section dividers replaced with brand-tinted underline ─ */
    body[data-v6="true"] section .text-center .w-24.h-1 {
        background: var(--brand) !important;
        height: 3px !important;
        width: 48px !important;
        border-radius: 2px;
    }
}

/* ============================================================
   @layer styles — v6 industry-aligned design styles.
   Replace v5's swiss/brutalist/active/etc. with 5 styles tied to
   actual GoldenPages business segments. Each style is a TRAIT BUNDLE
   (font feel, weight curve, radius, density, motion intensity) — not
   a costume of skews and clip-paths.
   ============================================================ */
@layer styles {

    /* ── EDITORIAL — magazine-style. Spas, hotels, luxe brands, professional services. ── */
    body[data-v6="true"][data-style="editorial"] {
        --font-display: 'Fraunces Variable', 'Playfair Display', Georgia, serif;
        --radius-md: 4px;
        --radius-lg: 8px;
        --radius-xl: 12px;
    }
    body[data-v6="true"][data-style="editorial"] h1,
    body[data-v6="true"][data-style="editorial"] h2 {
        font-weight: 350;
        letter-spacing: -0.04em;
        font-variation-settings: 'opsz' 144, 'SOFT' 50;
    }
    body[data-v6="true"][data-style="editorial"] h1 { font-size: var(--text-6xl); }
    body[data-v6="true"][data-style="editorial"] section {
        padding: var(--space-32) 0;
    }
    body[data-v6="true"][data-style="editorial"] .text-center > h2:first-child {
        text-align: center;
        max-width: 18ch;
        margin-inline: auto;
    }
    /* Pull-quote treatment for testimonial-like text */
    body[data-v6="true"][data-style="editorial"] section blockquote,
    body[data-v6="true"][data-style="editorial"] section .italic {
        font-size: var(--text-2xl);
        font-weight: 400;
        line-height: 1.35;
        font-family: var(--font-display);
        color: var(--text-primary);
        max-width: 32ch;
    }

    /* ── SHOWROOM — product-led. Retail, automotive, beauty, jewellery. ── */
    body[data-v6="true"][data-style="showroom"] {
        --font-display: 'Manrope Variable', 'Inter Variable', sans-serif;
        --radius-md: 2px;
        --radius-lg: 4px;
        --radius-xl: 8px;
    }
    body[data-v6="true"][data-style="showroom"] h1,
    body[data-v6="true"][data-style="showroom"] h2 {
        font-weight: 750;
        letter-spacing: -0.04em;
        text-transform: uppercase;
    }
    body[data-v6="true"][data-style="showroom"] section {
        padding: var(--space-16) 0;
    }
    /* Hero/product imagery dominates: shrink padding, expand image areas */
    body[data-v6="true"][data-style="showroom"] #yext-products-section #yext-products-container > div > * .aspect-square,
    body[data-v6="true"][data-style="showroom"] .yext-product-card .aspect-square {
        aspect-ratio: 1 / 1.2;
    }

    /* ── WORKSHOP — hands-on, trades-friendly. Builders, mechanics, electricians. ── */
    body[data-v6="true"][data-style="workshop"] {
        --font-display: 'Manrope Variable', 'Inter Variable', sans-serif;
        --radius-md: 6px;
        --radius-lg: 10px;
        --radius-xl: 14px;
        /* Subtle gridded backdrop to feel like blueprint paper */
        background-image:
            linear-gradient(color-mix(in oklch, var(--brand) 6%, transparent) 1px, transparent 1px),
            linear-gradient(90deg, color-mix(in oklch, var(--brand) 6%, transparent) 1px, transparent 1px);
        background-size: 32px 32px;
    }
    body[data-v6="true"][data-style="workshop"] h1,
    body[data-v6="true"][data-style="workshop"] h2,
    body[data-v6="true"][data-style="workshop"] h3 {
        font-weight: 800;
        letter-spacing: -0.02em;
    }
    body[data-v6="true"][data-style="workshop"] section .bg-white {
        border: 2px solid var(--border-default);
        box-shadow: 4px 4px 0 color-mix(in oklch, var(--brand) 18%, transparent) !important;
    }
    body[data-v6="true"][data-style="workshop"] section .bg-white:hover {
        transform: translate(-1px, -1px);
        box-shadow: 6px 6px 0 color-mix(in oklch, var(--brand) 28%, transparent) !important;
    }

    /* ── HOSPITALITY — soft, warm, high-touch. Restaurants, cafes, salons, B&Bs. ── */
    body[data-v6="true"][data-style="hospitality"] {
        --radius-md: 14px;
        --radius-lg: 22px;
        --radius-xl: 32px;
        --radius-2xl: 40px;
    }
    body[data-v6="true"][data-style="hospitality"] h1,
    body[data-v6="true"][data-style="hospitality"] h2 {
        font-weight: 600;
        letter-spacing: -0.015em;
    }
    body[data-v6="true"][data-style="hospitality"] section .bg-white {
        border-radius: var(--radius-xl) !important;
    }
    body[data-v6="true"][data-style="hospitality"] section button:not(.demo-panel button) {
        border-radius: var(--radius-full) !important;
        padding-inline: var(--space-8) !important;
    }

    /* ── CIVIC — institutional polish. Medical, legal, finance, public sector. ── */
    body[data-v6="true"][data-style="civic"] {
        --font-display: 'Inter Variable', system-ui, sans-serif;
        --radius-md: 4px;
        --radius-lg: 6px;
        --radius-xl: 8px;
    }
    body[data-v6="true"][data-style="civic"] h1,
    body[data-v6="true"][data-style="civic"] h2 {
        font-weight: 600;
        letter-spacing: -0.02em;
    }
    body[data-v6="true"][data-style="civic"] section {
        padding: var(--space-20) 0;
    }
    /* Disciplined whitespace — every section centred, capped, generous */
    body[data-v6="true"][data-style="civic"] section .container {
        max-width: var(--container-lg);
    }
    /* Strong text contrast, traditional-looking link colour */
    body[data-v6="true"][data-style="civic"] section a:not(.bg-purple-600):not([href="#contact"]):not([href="#action"]) {
        color: var(--brand-700);
        text-decoration: underline;
        text-underline-offset: 3px;
        text-decoration-thickness: 1px;
    }
}

/* ============================================================
   @layer base — dark-palette utility-class overrides.
   When a v6 theme has isDark:true, theme-runtime.js sets
   body[data-palette="dark"]. The rules below remap common Tailwind
   utility classes (text-gray-*, bg-white, etc.) to v6 surface/text
   tokens so dark-palette themes look cohesive without per-theme
   customStyles.
   ============================================================ */
@layer base {
    body[data-v6="true"][data-palette="dark"] {
        background: var(--surface-page);
        color: var(--text-primary);
    }
    body[data-v6="true"][data-palette="dark"] section:not(.hero-pattern) {
        background: var(--surface-page) !important;
    }
    /* Generalised — dark palette flips Tailwind light bg classes wherever
       they appear (sections, error UI, app.js-generated cards), so light
       text doesn't end up on light bg. Excludes nav (its own glass treatment)
       and form fields (different rule). */
    body[data-v6="true"][data-palette="dark"] .bg-white:not(nav):not(input):not(textarea):not(button):not(.preview-footer-keep),
    body[data-v6="true"][data-palette="dark"] .bg-gray-50,
    body[data-v6="true"][data-palette="dark"] .bg-gray-100 {
        background: var(--surface-card) !important;
        color: var(--text-primary) !important;
    }
    body[data-v6="true"][data-palette="dark"] .text-gray-900,
    body[data-v6="true"][data-palette="dark"] .text-gray-800,
    body[data-v6="true"][data-palette="dark"] .text-gray-700 {
        color: var(--text-primary) !important;
    }
    body[data-v6="true"][data-palette="dark"] .text-gray-600,
    body[data-v6="true"][data-palette="dark"] .text-gray-500,
    body[data-v6="true"][data-palette="dark"] .text-gray-400 {
        color: var(--text-secondary) !important;
    }
    /* Elements with an intentionally LIGHT background regardless of theme
       (translucent chip overlays sitting on imagery, the Facebook page
       widget shell which renders a white iframe). Their text content usually
       carries .text-gray-700 / .text-gray-500 etc. which the dark-palette
       rules above remap to light cream → invisible on the light bg. Must
       come AFTER those remaps so equal specificity (0,3,1) loses on source
       order in our favour.
       Note: in an attribute selector the class attribute VALUE contains the
       literal "/" character (Tailwind's `bg-white/90` class), so we match
       the unescaped string "bg-white/" directly. */
    body[data-v6="true"][data-palette="dark"] [class*="bg-white/"],
    body[data-v6="true"][data-palette="dark"] [class*="bg-white/"] *,
    body[data-v6="true"][data-palette="dark"] .fb-page,
    body[data-v6="true"][data-palette="dark"] .fb-page * {
        color: #1f2937 !important;
    }
    body[data-v6="true"][data-palette="dark"] h1,
    body[data-v6="true"][data-palette="dark"] h2,
    body[data-v6="true"][data-palette="dark"] h3,
    body[data-v6="true"][data-palette="dark"] h4 {
        color: var(--text-primary);
    }
    body[data-v6="true"][data-palette="dark"] .bg-purple-50,
    body[data-v6="true"][data-palette="dark"] .bg-purple-100 {
        background: var(--surface-muted) !important;
        color: var(--text-primary) !important;
    }
    body[data-v6="true"][data-palette="dark"] nav {
        background: color-mix(in oklch, var(--surface-card) 78%, transparent) !important;
        border-bottom: 1px solid color-mix(in oklch, white 12%, transparent);
    }
    body[data-v6="true"][data-palette="dark"] nav .nav-link,
    body[data-v6="true"][data-palette="dark"] nav .text-gray-700,
    body[data-v6="true"][data-palette="dark"] #nav-business-name,
    body[data-v6="true"][data-palette="dark"] #mobile-menu-btn {
        color: var(--text-primary) !important;
    }
    body[data-v6="true"][data-palette="dark"] nav .nav-link:hover {
        color: var(--brand) !important;
    }
    body[data-v6="true"][data-palette="dark"] footer {
        background: oklch(8% calc(var(--brand-c) * 0.1) var(--brand-h)) !important;
        color: var(--text-secondary) !important;
        border-top: 1px solid color-mix(in oklch, white 10%, transparent);
    }
    body[data-v6="true"][data-palette="dark"] footer * {
        color: var(--text-secondary) !important;
    }
    body[data-v6="true"][data-palette="dark"] footer a:hover {
        color: var(--text-primary) !important;
    }
    /* Loading overlay covers the page during data fetch and on error.
       It has hardcoded background:white. For dark palettes the white
       overlay + my dark-mode text-primary remap = light text on white.
       Flip the overlay bg to surface-page so contrast stays correct. */
    body[data-v6="true"][data-palette="dark"] .loading-overlay {
        background: var(--surface-page) !important;
    }

    /* The "preview created by bizsite.ie" footer is inline-styled and
       should render identically regardless of theme. Force its inherited
       colours back to its inline parent so my Tailwind utility-class
       overrides don't leak in. */
    body[data-v6="true"] #preview-footer,
    body[data-v6="true"] #preview-footer * {
        color: inherit !important;
        background: inherit;
    }
    body[data-v6="true"] #preview-footer {
        background: #f3f4f6 !important;
        color: #111827 !important;
    }
    body[data-v6="true"] #preview-footer a {
        color: #2563eb !important;
    }
    body[data-v6="true"][data-palette="dark"] section input,
    body[data-v6="true"][data-palette="dark"] section textarea,
    body[data-v6="true"][data-palette="dark"] section select {
        background: oklch(15% calc(var(--brand-c) * 0.1) var(--brand-h));
        color: var(--text-primary);
        border-color: color-mix(in oklch, white 18%, transparent);
    }
    body[data-v6="true"][data-palette="dark"] section input::placeholder,
    body[data-v6="true"][data-palette="dark"] section textarea::placeholder {
        color: var(--text-muted);
    }
    /* Dark palettes: shadows tinted dark, not brand-tinted-light */
    body[data-v6="true"][data-palette="dark"] {
        --shadow-sm: 0 1px 2px color-mix(in oklch, black 35%, transparent);
        --shadow-md: 0 4px 12px color-mix(in oklch, black 45%, transparent),
                     0 2px 4px color-mix(in oklch, black 30%, transparent);
        --shadow-lg: 0 10px 30px color-mix(in oklch, black 50%, transparent),
                     0 4px 10px color-mix(in oklch, black 35%, transparent);
        --shadow-xl: 0 25px 50px color-mix(in oklch, black 55%, transparent),
                     0 10px 20px color-mix(in oklch, black 40%, transparent);
        --border-subtle: color-mix(in oklch, white 8%, transparent);
        --border-default: color-mix(in oklch, white 16%, transparent);
        --border-strong: color-mix(in oklch, white 30%, transparent);
    }
}

/* ============================================================
   @layer components — decorative section corner accents.
   Subtle radial glows in section corners using --brand-accent so
   sections feel intentional rather than "endless boxes". Alternates
   corner per section so the rhythm has variation. Works on light AND
   dark palettes because color-mix on accent at low opacity falls
   over either surface gracefully.
   ============================================================ */
@layer components {
    /* Sections that should NOT get accents: the hero (has its own bg)
       and #contact (has its own dense layout). Everything else gets a
       soft accent in alternating corners. */
    body[data-v6="true"] main section:not(.hero-pattern):not(#contact):not(#google-reviews) {
        position: relative;
        isolation: isolate; /* keeps the accent layer below content w/o needing z-index */
        /* The ::before/::after accents below extend up to 120px past the
           section edges. Without clipping, they push body scrollWidth past
           the viewport (horizontal scroll on every page width). Clip the
           accents here — they're decorative, never interactive content. */
        overflow: hidden;
    }

    /* Odd sections: top-right accent */
    body[data-v6="true"] main section:not(.hero-pattern):not(#contact):not(#google-reviews):nth-of-type(odd)::before {
        content: '';
        position: absolute;
        top: -120px;
        right: -120px;
        width: 480px;
        height: 480px;
        background: radial-gradient(circle at center,
            color-mix(in oklch, var(--brand-accent, var(--brand)) 16%, transparent) 0%,
            color-mix(in oklch, var(--brand-accent, var(--brand)) 6%, transparent) 30%,
            transparent 65%);
        pointer-events: none;
        z-index: -1;
    }
    /* Even sections: bottom-left accent (uses the brand itself for variety) */
    body[data-v6="true"] main section:not(.hero-pattern):not(#contact):not(#google-reviews):nth-of-type(even)::before {
        content: '';
        position: absolute;
        bottom: -120px;
        left: -120px;
        width: 480px;
        height: 480px;
        background: radial-gradient(circle at center,
            color-mix(in oklch, var(--brand) 14%, transparent) 0%,
            color-mix(in oklch, var(--brand) 5%, transparent) 30%,
            transparent 65%);
        pointer-events: none;
        z-index: -1;
    }
    /* Smaller secondary accent on every 3rd section, opposite corner */
    body[data-v6="true"] main section:not(.hero-pattern):not(#contact):not(#google-reviews):nth-of-type(3n+1)::after {
        content: '';
        position: absolute;
        bottom: -60px;
        right: 10%;
        width: 220px;
        height: 220px;
        background: radial-gradient(circle at center,
            color-mix(in oklch, var(--brand-accent, var(--brand)) 10%, transparent) 0%,
            transparent 70%);
        pointer-events: none;
        z-index: -1;
    }
}

/* ============================================================
   @layer base — accessibility audit fixes.
   Contrast issues identified:
   1. Tailwind .text-purple-600 (used for "Read More" links, directions
      links, footer accents) gets remapped to var(--theme-primary). On
      dark palette themes the brand colour might lack contrast on dark
      surfaces — promote to --brand-300 (the lighter end of the OKLCH
      ramp) so links stay readable.
   2. Tailwind .text-purple-100 on subtitles gets washed out on light
      backgrounds — already overridden in @layer variants for hero,
      add a body fallback.
   3. Form input placeholder text sometimes too low contrast — bump
      to --text-secondary.
   4. Footer links on dark palettes need explicit light colour.
   ============================================================ */
@layer base {
    /* Dark-palette link contrast: lift "purple-600" usage to brand-300 */
    body[data-v6="true"][data-palette="dark"] .text-purple-600,
    body[data-v6="true"][data-palette="dark"] .hover\:text-purple-600:hover,
    body[data-v6="true"][data-palette="dark"] #directions-link,
    body[data-v6="true"][data-palette="dark"] a[style*="color: var(--theme-primary)"],
    body[data-v6="true"][data-palette="dark"] a[style*="color:var(--theme-primary)"],
    body[data-v6="true"][data-palette="dark"] a[href^="mailto:"] {
        color: var(--brand-300) !important;
    }

    /* Dark-palette: ANY .bg-purple-50/.bg-purple-100 utility container.
       The default :root rule remaps these to --surface-muted (oklch 96%)
       which is near-white — on a dark page that's a glaring light card,
       AND the icons + text inside (which the dark-palette rules nudge
       to lighter tones) end up as pale-on-pale and disappear.
       Override every such container to a brand-tinted dark surface so
       icons + text in --text-primary and --brand both contrast cleanly.
       Covers: services-grid icon discs, about-callouts cards, the
       "Established 20XX" badge, and any future use of these utilities. */
    body[data-v6="true"][data-palette="dark"] .bg-purple-100,
    body[data-v6="true"][data-palette="dark"] .bg-purple-50 {
        background: color-mix(in oklch, var(--brand) 22%, var(--surface-card)) !important;
        color: var(--text-primary) !important;
    }
    /* Icons inside those containers — use --text-primary (light cream/white)
       for guaranteed contrast against the brand-tinted dark disc, regardless
       of what the brand hue is. Beats theming via --brand which can equal
       the container colour and disappear (e.g. coal-smoke = orange brand
       on orange-tinted disc). */
    body[data-v6="true"][data-palette="dark"] .bg-purple-100 i.text-purple-600,
    body[data-v6="true"][data-palette="dark"] .bg-purple-50 i.text-purple-600 {
        color: var(--text-primary) !important;
    }
    /* Ensure plain text inside the badge (e.g. "Established <year>") stays
       in --text-primary too. .text-gray-900 inside is already remapped at
       the body level but be explicit here so specificity beats stragglers. */
    body[data-v6="true"][data-palette="dark"] .bg-purple-100 .text-gray-900,
    body[data-v6="true"][data-palette="dark"] .bg-purple-50 .text-gray-900,
    body[data-v6="true"][data-palette="dark"] .bg-purple-100 .text-gray-700,
    body[data-v6="true"][data-palette="dark"] .bg-purple-50 .text-gray-700,
    body[data-v6="true"][data-palette="dark"] .bg-purple-100 .text-gray-600,
    body[data-v6="true"][data-palette="dark"] .bg-purple-50 .text-gray-600 {
        color: var(--text-primary) !important;
    }

    /* Dark-palette: product prices and other inline-styled brand-coloured
       text. The link rule above only covers <a> elements; product prices
       are <div style="color: var(--theme-primary)"> so they fall through.
       Lift to --brand-300 for AA contrast on the dark card surface. */
    body[data-v6="true"][data-palette="dark"] [style*="color: var(--theme-primary)"]:not(a),
    body[data-v6="true"][data-palette="dark"] [style*="color:var(--theme-primary)"]:not(a) {
        color: var(--brand-300) !important;
    }

    /* Subtitle washouts: .text-purple-100 in body sections (NOT the hero —
       hero text colour is handled per-layout) on light themes falls back to
       --text-secondary so it has visible contrast on the page surface.
       The :not(.hero-pattern) is critical because @layer base !important
       beats @layer variants !important — without it, this rule wins over
       the per-hero-layout rules and breaks every hero subtitle. */
    body[data-v6="true"]:not([data-palette="dark"]) section:not(.hero-pattern) .text-purple-100 {
        color: var(--text-secondary) !important;
    }

    /* Light theme + light hero gradient: ensure sub-headers picked up. */
    body[data-v6="true"] .text-gray-500,
    body[data-v6="true"] .text-gray-400 {
        /* ensure these are at least textMuted-equivalent for aa contrast */
        color: var(--text-muted) !important;
    }

    /* Light-card visible borders (subtle, brand-tinted) */
    body[data-v6="true"]:not([data-palette="dark"]) section .bg-white {
        border: 1px solid var(--border-subtle);
    }

    /* ── AA-safe brand text on light surfaces ──
       For light-brand themes (Saffron, Honey, Coral) the v5 Tailwind map
       hands back a colour that fails AA on white (e.g. #ea580c at 3.4:1
       for Coral). --brand-text falls back to the SECONDARY when the
       primary's lightness > 60%, so links/CTAs always pass AA.

       NOTE: applies to body sections + v5 hero layouts (centered/product/inset)
       where the CTA is a white pill on a dark brand gradient. v6 light-card
       hero variants (split-image-right, stage, editorial, asymmetric, frame)
       are excluded because their CTAs use a brand-700 pill + white text
       instead — applying brand text on top would make it invisible. */
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) #directions-link,
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) .text-purple-600,
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) a[href^="mailto:"],
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) .cc_loylopen,
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) a[style*="color: var(--theme-primary)"],
    body[data-v6="true"] section:not(.hero-layout-split-image-right):not(.hero-layout-stage):not(.hero-layout-editorial):not(.hero-layout-asymmetric):not(.hero-layout-frame):not(.hero-layout-split-panel) a[style*="color:var(--theme-primary)"] {
        color: var(--brand-text, var(--brand)) !important;
    }

    /* ── Brand-coloured BG buttons get AA-safe text ──
       text-white inside a brand-coloured pill is invisible on light primaries.
       Override to --text-on-brand which the theme set to be contrast-safe.
       Also pin the BG to v6 --brand so the v5 Tailwind primary-colour map
       (Coral=#ea580c, Saffron=#bc6c25 etc.) doesn't leak through. */
    body[data-v6="true"] [class*="bg-purple-6"].text-white,
    body[data-v6="true"] [class*="bg-purple-7"].text-white,
    body[data-v6="true"] #nav-phone,
    body[data-v6="true"] #hero-phone,
    body[data-v6="true"] #nav-phone *,
    body[data-v6="true"] #hero-phone * {
        color: var(--text-on-brand, #ffffff) !important;
    }
    /* nav-phone / hero-phone use --brand-700 (the OKLCH-derived darker
       variant) instead of --brand, so white text on the button always passes
       AA — even for mid-lightness brands like Midnight Indigo where neither
       white nor dark text would pass on the primary itself. */
    body[data-v6="true"] #nav-phone,
    body[data-v6="true"] #hero-phone {
        background-color: var(--brand-700) !important;
        color: #ffffff !important;
    }
    body[data-v6="true"] #nav-phone *,
    body[data-v6="true"] #hero-phone * {
        color: #ffffff !important;
    }
    body[data-v6="true"] section .bg-purple-600,
    body[data-v6="true"] section .bg-purple-700 {
        background-color: var(--brand) !important;
    }
}

/* ============================================================
   @layer utilities — small helpers used by section variants.
   ============================================================ */
@layer utilities {
    .v6-container {
        max-width: var(--container-xl);
        margin-inline: auto;
        padding-inline: var(--space-6);
    }
    .v6-eyebrow {
        font-size: var(--text-xs);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.12em;
        color: var(--brand);
    }
}
