/* ===================================================================
   V3 HOME — Full static editorial stylesheet
   Structures the Cortical+Even reference design onto index-v4.html
   (itself a fork of index-v3.html). Lives alongside global-v3.css +
   home-overrides-v4.css (which drive some inherited rules like
   .section-title sizing); the .v4-* + .v3-* classes scoped here
   take priority where layout diverges.

   Pattern source:  references/archive/mock-design/mock-home.css
   Reference:       references/frontend-design-reference.md
   =================================================================== */

:root {
    /* Visual palette — duplicated root declaration from home-overrides-v4.css
       so this stylesheet can stand alone if needed. */
    --v-bg-canvas: #F8F7F5;
    --v-bg-midtone: #B6BAB9;
    /* Cortical sage */
    --v-bg-dark: #0A0A0A;
    --v-bg-charcoal: #232323;
    /* Even footer */
    --v-text-primary: #0A0A0A;
    --v-text-on-dark: #F8F7F5;
    --v-text-muted-d: #919191;
    --v-accent-canary: #E2C0A0;
    --v-accent-yellow: #E2C0A0;
    --v-accent-canary-light: #EFD8BC;
    --v-accent-canary-dark: #C09D87;

    /* Typography */
    --v-font-sans: "Helvetica Neue", "Avenir", Arial, sans-serif;
    --v-font-serif: "Times New Roman", Times, serif;
    --v-h1-size: clamp(3rem, 9vw, 7.125rem);
    --v-h1-tracking: -1.5px;
    --v-body-weight: 300;
    --v-body-tracking: -0.5px;
    --v-quote-tracking: 0;

    /* Layout */
    --v-site-max: 1120px;
    --v-gutter: 5%;
    --v-margin-top: 8rem;
    --v-margin-bot: 8rem;
    --v-header-h: 64px;

    /* Motion */
    --v-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- LAYOUT PRIMITIVES ---------- */
.v3-wrap {
    width: 100%;
    max-width: var(--v-site-max);
    margin: 0 auto;
    padding: 0 var(--v-gutter);
    box-sizing: border-box;
    display: block;
    position: relative;
}

.v3-section {
    padding: var(--v-margin-top) 0 var(--v-margin-bot);
    scroll-margin-top: var(--v-header-h);
}

/* ---------- HERO ---------- */
.v3-hero {
    min-height: 110svh;
    width: 100%;
    position: relative;
    /* [v4-r22] BACKGROUND-ATTACHMENT: FIXED — the "hero image sinks
       behind next section" effect via native CSS. The hero image is
       the CSS background-image of .v3-hero, set with
       background-attachment:fixed, which anchors the image to the
       viewport (not the hero element). As the user scrolls down:

         · The hero text content (.v3-hero__content) scrolls up
           normally past the still-pinned background
         · The intro section (#read-more .v4-capabilities) scrolls up
           from below with its solid white bg
         · The intro's white bg paints OVER the still-pinned hero
           background — the image visibly "sinks behind" the white
           intro bg as the seam rises up the screen

       The meeting line between pinned image (still visible at top)
       and rising white bg (covering the bottom) creates the
       "disappearing border" effect the user wants. This is the
       standard CSS-only pattern, no JS, no transform, no fixed-
       positioned children, no z-index gymnastics — background-
       attachment:fixed does everything natively.

       Image: new-hero2.png (the new light-themed hero). Layered with
       a subtle dark-to-transparent bottom-up gradient on top so the
       CTA buttons have a small shadowed foothold at the hero bottom.
       The bottom gradient is also `background-attachment:fixed` so
       it pins with the image.
    */
    background:
        url('../images/Hero/new-hero2.png') center / cover no-repeat;
    background-attachment: fixed;
    color: var(--v-text-primary);
    display: flex;
    align-items: center;
    /* [v4-r22] overflow:visible — needed so the hero text content
       can extend past hero bounds if required. background-attachment:
       fixed handles the image-pinning natively, no fixed children
       needed. */
    overflow: visible;
}

/* [v4-r22] Hide the <img class="v4-hero-bg"> element. The image is
   now painted via CSS background-image on .v3-hero with background-
   attachment:fixed, so the <img> would duplicate the image (one in
   the hero's static element flow, one as the pinned CSS bg) and look
   wrong. display:none keeps the markup stable for any future JS that
   expects the element to exist. */
.v4-hero-bg {
    display: none !important;
}

/* [v4-r15] Two-layer hero image stack.
   .v4-hero-bg         — background layer (z:0), full-bleed cover.
   .v4-hero-overlay    — topmost image layer (z:2), in front of text.
   .v3-hero__content   — text content (z:1), sits between the two images.
   Per user request: overlay must be "at the most forefront position, even in
   front of the texts." If you want overlay BEHIND text instead, swap z-indexes
   of .v4-hero-overlay and .v3-hero__content. */
.v4-hero-bg,
.v4-hero-overlay {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
    display: block;
}

.v4-hero-bg {
    z-index: 0;
    /* [v4-r22] FIXED-POSITION hero bg — the "image sinks behind intro
       bg" parallax effect. position:fixed pins the image to viewport
       top-left at full 100vw × 100vh. As the user scrolls down:

       · The hero text scrolls normally up past the still-pinned image
       · The intro section (#read-more .v4-capabilities) scrolls up
         from below the viewport
       · The intro section's bg is solid pure white #FFFFFF at
         z-index 25 (home-overrides-v4.css:418) which PAINTS OVER the
         pinned hero image as the intro rises into view
       · The image visibly "sinks behind" the white intro bg — the
         meeting line between pinned image (still visible at top) and
         rising white bg (covering the bottom) creates the "disappearing
         border" effect

       The fixed image stays pinned for the entire page lifetime —
       every section's opaque bg naturally paints over it as each
       section scrolls up into the viewport. The user gets a clean
       parallax illusion where the hero bg appears to anchor while
       everything else scrolls past.
    */
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
}

.v4-hero-overlay {
    z-index: 2;
}

.v3-hero__content {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--v-site-max);
    margin: 0 auto;
    padding: 0 var(--v-gutter) 8rem;
}

.v3-hero__eyebrow {
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--v-accent-canary);
    margin-bottom: 1.5rem;
}

.v3-hero__title {
    font-size: var(--v-h1-size);
    font-weight: 500;
    line-height: 1.05;
    letter-spacing: var(--v-h1-tracking);
    color: var(--v-text-on-dark);
    margin-bottom: 2rem;
    text-shadow: 0 4px 24px rgba(0, 0, 0, 0.45);
}

.v3-hero__sub {
    font-size: clamp(1.1rem, 1.5vw, 1.35rem);
    font-weight: var(--v-body-weight);
    letter-spacing: var(--v-body-tracking);
    color: rgba(255, 255, 255, 0.88);
    max-width: 580px;
    margin-bottom: 3rem;
    line-height: 1.55;
}

.v3-cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

/* ---------- BUTTONS ---------- */
/* [v4-r21] Single-shape button grammar — soft rectangle (8px) used
   everywhere. The previous two-shape grammar (pill for hero, sharp-
   cornered square for the rest) was incoherent; the page now reads as
   one button family. Hero CTAs still differentiate as the "primary"
   tier via fill (white-on-dark / hairline-ghost against the 110svh
   hero image), not via shape or size — they share the 8px radius and
   the 0.55rem 1.1rem padding spec with every other chrome button.
   Hairline text-anchors (.v4-greet-skip, .v4-sage-shortcut) are NOT
   buttons and stay out of the button grammar entirely.

   These are the family-wide base rules for `.v3-btn-pill-*` selectors.
   In the hero, `.v4-hero .v3-btn-pill-*` (later in this file) overrides
   padding/size with `!important` to match the sage spec; outside the
   hero, these rules resolve to 8px via the --v-radius-chrome token.
   The original 100px pill radius is retired. */
.v3-btn-pill-solid {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border-radius: var(--v-radius-chrome, 8px);
    background: #ffffff;
    color: var(--v-text-primary);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: 0.6px;
    border: none;
    transition: opacity 0.3s var(--v-ease), transform 0.3s var(--v-ease);
}

.v3-btn-pill-solid:hover {
    opacity: 0.85;
}

.v3-btn-pill-ghost {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border-radius: var(--v-radius-chrome, 8px);
    background: transparent;
    color: var(--v-text-on-dark);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: 0.6px;
    border: 1px solid rgba(255, 255, 255, 0.4);
    transition: background 0.3s var(--v-ease), color 0.3s var(--v-ease), border-color 0.3s var(--v-ease);
}

.v3-btn-pill-ghost:hover {
    background: #ffffff;
    color: var(--v-text-primary);
    border-color: #ffffff;
}

/* Square buttons (Even) — hairline borders, 0 radius. Used for all CTAs below the hero. */
.v3-btn-square-light {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border: 1px solid var(--v-text-primary);
    background: #ffffff;
    color: var(--v-text-primary);
    font-size: 0.85rem;
    font-weight: 400;
    letter-spacing: var(--v-body-tracking);
    text-decoration: none;
    border-radius: 0;
    transition: background 0.25s ease, color 0.25s ease;
}

.v3-btn-square-light:hover {
    background: var(--v-text-primary);
    color: #ffffff;
}

.v3-btn-square-bordered {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: transparent;
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.85rem;
    font-weight: 400;
    letter-spacing: var(--v-body-tracking);
    text-decoration: none;
    border-radius: 0;
    transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.v3-btn-square-bordered:hover {
    background: #ffffff;
    color: var(--v-text-primary);
    border-color: #ffffff;
}

.v3-btn-square-yellow {
    display: inline-block;
    padding: 0.55rem 1.1rem;
    border: 1px solid var(--v-accent-yellow);
    background: var(--v-accent-yellow);
    color: var(--v-bg-charcoal);
    font-size: 0.85rem;
    font-weight: 500;
    letter-spacing: var(--v-body-tracking);
    text-decoration: none;
    border-radius: 0;
    margin-left: 0.5rem;
    transition: opacity 0.25s ease;
}

.v3-btn-square-yellow:hover {
    opacity: 0.85;
}

/* ---------- QUOTE EYEBROW (italic serif editorial label) ---------- */
/* Replaces .small-caps on 3 sections per user decision (Capabilities, Gallery, Connect).
   Reads as an editorial pull-quote eyebrow rather than a section label. */
.v3-quote-eyebrow {
    font-family: var(--v-font-serif);
    font-style: italic;
    font-size: 1.05rem;
    font-weight: 400;
    letter-spacing: var(--v-quote-tracking);
    color: #7A7A7A;
    margin-bottom: 1.5rem;
    max-width: 720px;
    line-height: 1.5;
}

.v3-section-sage .v3-quote-eyebrow {
    color: var(--v-accent-canary);
}

/* ---------- CAPABILITIES CARDS (static, no hover-lift) ----------
   [v4-r16] Gutted the inherited `inset 0 2px 0 rgba(255,255,255,0.7)`
   box-shadow — it was a glassmorphism-era window-highlight that survived
   from the v3 register and showed up as a 2px white top-edge line坐在
   the cover image (user-visible "border" artifact). Replaced with the
   v4 drop shadow only. Safe to gut because .v3-cards is used exclusively
   by the v4 bento (confirmed: `grep v3-cards *.html` → only index-v4.html
   line 110). */
.v3-cards .readmore-card {
    transition: none !important;
    transform: none !important;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04) !important;
}

.v3-cards .readmore-card:hover {
    transform: none !important;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04) !important;
}

.v3-cards .slick-arrow:hover {
    opacity: 0.75;
    /* colour/opacity only — no scale, no shadow rise */
    background: #f5f5f7 !important;
    transform: none !important;
    box-shadow: none !important;
}

.v3-cards .card-title:hover,
.v3-cards .card-title {
    transform: none !important;
}

/* ---------- GALLERY RAIL (only section with retained hover-scale) ---------- */
/* Inherit the existing .gallery-window / .gallery-track / .gallery-item rules
   from home-overrides-v4.css (which duplicates the original home-overrides.css
   gallery rules). The hover-dim + hover-scale behaviour is intentional here. */

/* Magnifying-glass inner button — drop scale, keep colour/contrast swap only */
.v3-section .gallery-item .liquid-button:hover {
    background: #f5f5f7 !important;
    color: #0A0A0A !important;
    transform: none !important;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
    /* keep gentle base shadow, no escalation */
}

/* ---------- SAGE BREAKTHROUGH BAND (replaces outreach video stage + manifesto) ---------- */
.v3-section-sage {
    background: var(--v-bg-midtone);
    color: var(--v-text-on-dark);
    padding: var(--v-margin-top) 0 var(--v-margin-bot);
    scroll-margin-top: var(--v-header-h);
}

.v3-breakthrough {
    font-family: var(--v-font-sans);
    font-size: clamp(1.75rem, 3vw, 2.75rem);
    font-weight: 300;
    line-height: 1.25;
    letter-spacing: -1px;
    color: var(--v-text-on-dark);
    max-width: 920px;
    margin-bottom: 2.5rem;
}

.v3-breakthrough strong {
    font-weight: 500;
    /* medium-weight emphasis (not bold) — Cortical register */
    color: #ffffff;
}

.v3-breakthrough-cta {
    margin-top: 0;
}

.v3-section-sage .v3-btn-square-light {
    background: var(--v-text-on-dark);
    color: var(--v-bg-dark);
    border-color: var(--v-text-on-dark);
}

.v3-section-sage .v3-btn-square-light:hover {
    background: var(--v-bg-dark);
    color: var(--v-text-on-dark);
    border-color: var(--v-bg-dark);
}

/* ---------- CONNECT (restyled to match hero's editorial restraint) ---------- */
.v3-contact {
    padding: var(--v-margin-top) 0 var(--v-margin-bot);
}

.v3-connect-card {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 3rem;
    max-width: 920px;
    margin: 0 auto;
    padding: 5rem 0;
    border-top: 1px solid rgba(0, 0, 0, 0.06);
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.v3-connect-text {
    max-width: 540px;
}

.v3-connect-text .section-title {
    font-size: clamp(2.5rem, 4vw, 3.5rem) !important;
}

.v3-contact .v3-quote-eyebrow {
    max-width: 100%;
    margin-bottom: 0.5rem;
}

.v3-connect-cta {
    display: flex;
    flex-shrink: 0;
    gap: 1rem;
    flex-wrap: wrap;
}

@media (max-width: 768px) {
    .v3-connect-card {
        flex-direction: column;
        align-items: flex-start;
        gap: 2.5rem;
        padding: 3rem 0;
    }
}

/* ---------- DARK ANNOUNCEMENT BAND (Even §3.6 — recruiter's last-glance signal) ---------- */
.v3-band-announce {
    background: #333333;
    color: #919191;
    padding: 2.25rem 0;
    font-size: 0.95rem;
    font-weight: 300;
    letter-spacing: var(--v-body-tracking);
}

.v3-band-announce .v3-wrap {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: flex-start;
}

/* ---------- FOOTER (Even square hairline pills + tracking) ---------- */
.v3-footer .footer-container {
    max-width: var(--v-site-max);
    margin: 0 auto;
    padding: 0 var(--v-gutter);
}

.v3-footer .footer-contact-section {
    max-width: var(--v-site-max);
    margin-left: auto;
    margin-right: auto;
    padding-left: var(--v-gutter);
    padding-right: var(--v-gutter);
}

.v3-footer .footer-contact-links a {
    display: inline-block;
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: -0.3px;
    text-decoration: none;
    padding: 8px 14px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 0;
    background: transparent;
    color: rgba(255, 255, 255, 0.85);
    transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.v3-footer .footer-contact-links a:hover {
    background: #ffffff;
    color: #0A0A0A;
    border-color: #ffffff;
}

.v3-footer .footer-links a,
.v3-footer .footer-bottom-meta {
    letter-spacing: -0.3px;
    /* Even footer quietness */
}

/* ---------- MOBILE RESPONSIVE (v3 base) ---------- */
@media (max-width: 768px) {

    .v3-section,
    .v3-section-sage,
    .v3-contact {
        padding: 4rem 0;
    }

    .v3-hero__content {
        padding: 0 var(--v-gutter) 5rem;
    }

    .v3-band-announce {
        padding: 1.5rem 0;
    }

    .v3-band-announce .v3-wrap {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
    }
}

/* ===================================================================
   V4 SUPERSESSION RULES
   All divergences from v3 base live below. Read top-down by block.
   v3 rules above remain on the cascade; v4 selectors override where
   polygon intends a different shape, layout, or dynamic policy.
   =================================================================== */

:root {
    /* Corner-radius policy (radius reduction per comments.md line 16) */
    --v-radius-card: 4px;
    /* bentos, gallery items, thesis card */
    --v-radius-chrome: 8px;
    /* all chrome buttons (hero CTAs, cushion CTAs, sage CTAs,
       announcement band, connect social buttons) — single-shape grammar
       per v4-r21. Was 0px/100px (two-shape: sharp + pill); unified to
       8px soft rectangle matching the sage/community section button. */
}

/* ---------- HERO CHEVRON (opt-in cinematic scroll trigger) ---------- */
.v4-continue {
    margin-top: 3.5rem;
    background: transparent;
    border: none;
    color: var(--v-accent-canary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    font-family: var(--v-font-sans);
    font-size: 0.85rem;
    font-weight: 400;
    letter-spacing: 0.2px;
    padding: 0;
    transition: opacity 0.25s var(--v-ease);
}

.v4-continue:hover {
    opacity: 0.7;
}

/* colour/opacity only — no scale, no shadow */
.v4-continue__icon {
    transition: transform 0.4s var(--v-ease);
}

.v4-continue:hover .v4-continue__icon {
    transform: translateY(2px);
}

.v4-continue.is-loading {
    pointer-events: none;
    opacity: 0.5;
}

.v4-continue.is-hidden {
    display: none;
}

/* after cinematic engine boots, chevron disappears */

/* ---------- OPT-IN CINEMATIC MODE (when .is-cinematic is set on hero) ---------- */
/* When the chevron click fires (home-engine-v4.js), the static hero morphs into
   the original 4200vh scroll-sequence container. The dormant greetings section
   becomes visible, the cinematic engine attaches its scroll handlers, and the
   heavy scripts (three.js + manifesto-bg.js + full home-engine) lazy-load. */
.v4-hero.is-cinematic {
    height: 4200vh;
    min-height: 0;
    align-items: stretch;
}

.v4-hero.is-cinematic .v3-hero__content {
    display: none;
}

.v4-hero.is-cinematic .v4-continue,
.v4-hero.is-cinematic .v4-greetings-dormant {
    display: revert;
}

.v4-hero.is-cinematic .v4-greetings-dormant {
    display: block;
    visibility: visible;
}

/* Override the home-overrides-v4.css reset block for cinematic classes
   ONLY inside the activated hero. The reset block at top of overrides
   blanket-killed .cinematic-greetings + .cg-*; we selectively revive them. */
.is-cinematic .cinematic-greetings,
.is-cinematic .cg-phrase-wrap,
.is-cinematic .cg-element,
.is-cinematic .cg-p1,
.is-cinematic .cg-p2,
.is-cinematic .cg-p3,
.is-cinematic .cg-p4-master,
.is-cinematic .cg-p4-word,
.is-cinematic .cg-p5,
.is-cinematic .cg-p6,
.is-cinematic .cg-read-more,
.is-cinematic .cg-stat-box,
.is-cinematic .stats-column,
.is-cinematic .cg-left-vertical,
.is-cinematic .greetings-inner,
.is-cinematic .greetings-title,
.is-cinematic .read-more-text,
.is-cinematic .read-more-arrow,
.is-cinematic .stat-number,
.is-cinematic .stat-label,
.is-cinematic .plus {
    all: revert !important;
    display: revert !important;
}

/* Default (no .is-cinematic): keep greetings visually inert but rendered.
   Position absolute so nothing affects layout flow. The cinematic engine
   will power the phases only after activation. */
.v4-greetings-dormant {
    position: absolute;
    top: 100vh;
    left: 0;
    width: 100%;
    pointer-events: none;
    visibility: hidden;
    opacity: 0;
}

/* ---------- RETOKENIZED SMALL-CAPS (replaces v3 quote-eyebrows) ---------- */
/* Stays as an inline tag at section top. Per your review: italic serif
   quote-eyebrows are too much across every section; restored on
   Capabilities + Gallery + Connect; quote-eyebrows survive only on
   Sage band and Connect body pull-quote.
   v4-r11 typography: migrated ALL CAPS +2px tracking → sentence case
   +0.1px tracking, 0.7rem → 1rem (user: "bigger"). Color #999 → #6e6e73
   (Apple-canonical muted eyebrow color, more legible on white). */
.v4-small-caps {
    display: block;
    font-size: 1.5rem;
    font-weight: 500;
    letter-spacing: 0.1px;
    text-transform: none;
    color: #6e6e73;
    margin-bottom: 1.25rem;
    /* Override any inherited italic serif from v3 spec where it was applied
       to .small-caps descendants of v3-section. */
    font-style: normal;
    font-family: var(--v-font-sans);
}

/* ---------- CAPABILITIES 2x2 BENTO ---------- */
/* 2x2 bento. Layout:
     [ Thesis card, tall ][  Card 1: Qualifications ]
     [                   ][  Card 2: Experiences    ]
     [   Card 3: Portfolio, wide                   ]
*/
.v4-bento {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: minmax(260px, 1fr) minmax(260px, 1fr) minmax(260px, auto);
    gap: 1.5rem;
    align-items: stretch;
}

/* Thesis card — left column, spans rows 1 + 2 */
.v4-bento .v4-thesis-card {
    grid-column: 1 / 2;
    grid-row: 1 / 3;
}

/* [v4-r18] Three real capability cards — now using the same template as
   the thesis card. They are <div> elements carrying class .v4-cap-card
   (no longer <a class="readmore-card slick-card v4-card">).
   :nth-child(N) counts ALL children of .v4-bento regardless of type/class.
   Child #1 = thesis-card (gets grid placement from the .v4-thesis-card rule
   above). Child #2 = first cap-card (Qualifications). Child #3 = second
   cap-card (Experience). Child #4 = third cap-card (Portfolio, wide). */
.v4-bento>.v4-cap-card:nth-child(2) {
    grid-column: 2 / 3;
    grid-row: 1 / 2;
}

.v4-bento>.v4-cap-card:nth-child(3) {
    grid-column: 2 / 3;
    grid-row: 2 / 3;
}

.v4-bento>.v4-cap-card:nth-child(4) {
    grid-column: 1 / 3;
    grid-row: 3 / 4;
}

/* Thesis card visual treatment */
.v4-thesis-card {
    background: var(--v-bg-dark);
    color: var(--v-text-on-dark);
    border-radius: var(--v-radius-card);
    padding: 2.5rem 2.25rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    min-height: 280px;
    box-sizing: border-box;
}

/* Thesis card — image variant: About-me card uses images/About/about.png
   as full-bleed background image, with the eyebrow + body text overlaid
   in the SAME visual coordinates they occupied in the text-only variant.
   The parent .v4-thesis-card flex rules (justify-content:space-between,
   padding:2.5rem 2.25rem) are preserved by giving the overlay the same
   padding and a flex column with justify-content:space-between — so the
   eyebrow stays anchored to the top of the card and the body to the
   bottom, with 2rem gap between, exactly as before. The image fills the
   card as object-fit:cover behind the overlay; a bottom-up dark gradient
   ensures the body text remains legible against varied image content. */
.v4-thesis-card.v4-thesis-card--image {
    position: relative;
    padding: 0;
    overflow: hidden;
}

.v4-thesis-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 46% center;
    z-index: 0;
    transition: transform 0.5s var(--v-ease);
}

.v4-thesis-card--image:hover .v4-thesis-image {
    transform: scale(1.03);
}

.v4-thesis-overlay {
    position: relative;
    z-index: 1;
    height: 100%;
    box-sizing: border-box;
    padding: 2.5rem 2.25rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    /* [REMOVED] Dark bottom-up linear-gradient overlay — dropped per user
       request. Text is now inverted to black so it reads directly against
       the image without a dark wash. */
}

.v4-thesis-overlay .v4-thesis-eyebrow {
    margin: 0;
    /* [v4-r21] Eyebrow now white-on-image at idle, matches the body's
       white-on-image colour so the whole text stack reads in one tone
       against the portrait. Copper arrives only on hover (see
       :hover block below — unified copper-on-hover across the bento).
       Idle copper on the eyebrow was originally an artefact of the
       text-only-variant spec at :774 (which inherits copper against
       the dark non-image card background); it does NOT apply cleanly
       on the --image variant because the portrait is already a
       complex tonal surface and copper at idle competes with the
       portrait's hues rather than anchoring to it. */
    color: rgba(255, 255, 255, 0.92);
    transition: color 0.25s var(--v-ease);
}

.v4-thesis-overlay .v4-thesis-body {
    margin: 0;
    /* [v4-r21] Body white-on-image at idle. Matches the eyebrow tone
       above so the whole card reads as one luminance value against
       the portrait. The default .v4-thesis-body at :812 also sets
       rgba(255, 255, 255, 0.92) — this is the --image variant's
       explicit reaffirmation in case the default ever changes. */
    color: rgba(255, 255, 255, 0.92);
    transition: color 0.25s var(--v-ease);
}

/* [v4-r21] Unified copper-on-hover across the bento. The thesis card
   and the three cap cards share one hover gesture: text warms from
   its idle colour to copper as the cursor lands. The idle colours
   stay different (white for thesis against the dark portrait bottom
   / black for caps against the white covers) — those encode the
   authorial-vs-declarative distinction. The hover accent unifies
   them as "this card is alive" signal.
   Transient copper-on-hover does NOT dilute the copper-reservation
   rule because (a) only one card is hovered at a time, not all four;
   (b) no other idle copper exists in the bento anymore — the thesis
   eyebrow's idle colour is now white. Hover is the only place copper
   appears in the bento's text. */
.v4-thesis-card:hover .v4-thesis-overlay .v4-thesis-eyebrow,
.v4-thesis-card:hover .v4-thesis-overlay .v4-thesis-body {
    color: var(--v-accent-canary);
}

/* Stretched-link overlay — the whole thesis-card <div> is clickable via this
   absolutely-positioned <a> that fills the card. Preserves the <div> parent
   type so the bento's :nth-of-type selectors for sibling .v4-card elements
   remain correct (qualifications=#1, experiences=#2, portfolio=#3). */
.v4-thesis-link {
    position: absolute;
    inset: 0;
    z-index: 2;
    text-decoration: none;
    color: inherit;
}

.v4-thesis-eyebrow {
    font-size: 1rem;
    font-weight: 500;
    letter-spacing: 0.1px;
    text-transform: none;
    color: var(--v-accent-canary);
    margin: 0;
}

.v4-thesis-body {
    font-family: var(--v-font-serif);
    font-style: italic;
    font-size: clamp(1.25rem, 1.6vw, 1.75rem);
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0;
    color: rgba(255, 255, 255, 0.92);
    margin: 2rem 0 0;
}

/* ---------- [v4-r18] CAPABILITY CARDS — rebuilt on the thesis-card template ----------
   Mirrors .v4-thesis-card–image / .v4-thesis-image / .v4-thesis-overlay / .v4-thesis-link
   exactly. Replaces the v3-era .readmore-card / .slick-card / .slick-content stack
   that carried inherited backdrop-filter, padding-56px, translateY transforms, and
   persistent corner halos across the old chrome. These rules below are the ONLY
   styles applied to the three capability cards — they do not inherit from any
   external cascade.
   Pattern:
     .v4-cap-card       — <div> parent, position relative, overflow hidden, radius 4px
     .v4-cap-image      — <img> absolute fill, object-fit cover, no border-radius
     .v4-cap-overlay   — <div> position relative, z-index 1, flex column space-between,
                        padding 2.5rem 2.25rem (mirrors thesis overlay padding)
     .v4-cap-link       — <a> absolute inset 0, z-index 2 (stretched-link, on top)
*/
.v4-cap-card {
    position: relative;
    border-radius: var(--v-radius-card);
    overflow: hidden;
    /* [v4-r18] Preserve the previous 400px height established via
       home-overrides-v4.css:481 (.readmore-card { height: 400px !important }).
       Setting it directly here as min-height+height so the bento's
       `minmax(260px, 1fr)` grid row stretches to 400px as before. */
    min-height: 400px;
    height: 400px;
    display: block;
    box-sizing: border-box;
    /* No background-color — the cover image is always opaque OR has a white
       backing via the image element's own background-color (see below). The
       thesis card uses --v-bg-dark (#0A0A0A) here, but for object-on-white
       covers we want a neutral that hides alpha seams rather than a dark
       that highlights them. */
    background-color: #ffffff;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.10);
}

.v4-cap-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    z-index: 0;
    transition: transform 0.5s var(--v-ease);
    /* White backing — fills any transparent regions of the cover image
       (e.g. qual.png ships with alpha=0 in its top-right corner). Without
       this, those regions would show the parent's background-color. With
       it, they show white, matching the object-on-white art direction. */
    background-color: #ffffff;
    /* No border-radius — the parent .v4-cap-card's overflow:hidden clips
       corners. Image's own radius would create a visible gap during
       transform: scale() because the radius scales with the transform. */
}

.v4-cap-card:hover .v4-cap-image {
    /* [v4-r18] Subtle hover-zoom matching the thesis card's scale(1.03).
       Previously the v4-r15 had scale(1.18) which was excessively kinetic
       for the object-on-white register. 1.04 is a hair breath — enough
       "alive" signal without flagging the page as having motion. */
    transform: scale(1.04);
}

/* [v4-r19] Per-card idle zoom overrides. qual.png's subject sits small
   in the frame and needs a tighter idle crop to read at card scale. */
#card-qual .v4-cap-image {
    transform: scale(1.1);
    transform-origin: center center;
}

#card-qual:hover .v4-cap-image {
    transform: scale(1.15);
}

/* [v4-r21] #card-port split-element override — title and desc are pulled
   out of the .v4-cap-body flex stack and absolutely positioned
   independently within the card. This breaks the "grouped body block"
   grammar that Qual + Exp use, and only applies to the port card (the
   panoramic cell) so you can dial title and desc positions manually
   relative to the card's edges.

   CRITICAL: the .v4-cap-body wrapper must itself be the full-card
   coordinate frame (inset: 0 on all sides + position: absolute) so the
   title + desc `top/left/right` percentages resolve against the full
   card. If body collapses to height: 0 or drops its positioned-ancestor
   status, the absolute children collapse onto the 0×0 anchor and render
   on top of each other — that was the previous bug.

   DIALS — adjust each property below to move title or desc independently:
   #card-port .v4-cap-title   → top / left / right / text-align / font-size
   #card-port .v4-cap-desc    → top / left / right / text-align / font-size
   Both use transform: translateY(-50%) on `top` so the `top` value sets the
   vertical CENTER of the element (not its top edge). Set top in % to scale
   with card height, or in rem for fixed offset from the card's top edge.
*/
#card-port .v4-cap-body {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    max-width: none;
    height: 100%;
    margin: 0;
    padding: 0;
    display: block;
}

#card-port .v4-cap-title {
    position: absolute;
    top: -40%;
    left: 0;
    right: 0;
    transform: translateY(-50%);
    text-align: center;
    width: 100%;
    margin: 0;
}

#card-port .v4-cap-desc {
    position: absolute;
    top: 350%;
    left: 0;
    right: 0;
    transform: translateY(-50%);
    text-align: center;
    width: 100%;
    margin: 0;
}

.v4-cap-overlay {
    position: absolute;
    top: 30%;
    left: 0;
    right: 0;
    transform: translateY(-50%);
    z-index: 1;
    box-sizing: border-box;
    padding: 2.25rem 2.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

/* [v4-r21] Eyebrow hidden — cap cards are declarative labels, not editorial
   pull-quotes. Earlier experiment promoted them to italic-serif eyebrows
   matching Gallery + Connect, but per user feedback: cap titles are NOT
   quotes and should not borrow the Times New Roman serif grammar. The cap
   overlay stack is just title + desc, both sans. The .v4-cap-eyebrow
   selector + spec is retained only for future opt-in cases. */
.v4-cap-eyebrow {
    display: none;
    font-family: var(--v-font-sans, -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif);
    font-size: 0.85rem;
    font-weight: 500;
    letter-spacing: 0.5px;
    color: rgba(10, 10, 10, 0.6);
    margin: 0;
}

.v4-cap-body {
    /* Title + desc grouped. Width capped to keep the text block a readable
       column. The block itself is centered horizontally on the card by
       .v4-cap-overlay (align-items: center); inside the block, both title
       and desc are text-align: center so the cap card reads as a centered
       editorial caption over the cover image. */
    margin: 0;
    width: 100%;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.v4-cap-title {
    /* [v4-r21] Inverted hierarchy — title demoted to a small editorial
       label matching the thesis card's "About me" eyebrow. Tuned to
       echo the thesis grammar deliberately through size/weight rhythm
       (NOT color — copper stays reserved for the thesis eyebrow so the
       bento keeps a single authorial anchor):
         · size 1rem          — same as thesis eyebrow (1rem)
         · weight 600         — bumps from 500 to match thesis eyebrow's
                                 perceptual weight on solid (non-accent)
                                 text. Sans family kept (cap titles are
                                 NOT pull-quotes; Times New Roman stays
                                 reserved for author-voice gestures
                                 in sage/contact/greet-hero).
         · color #0A0A0A      — solid black topic marker. Contrast vs.
                                 the rgba(10,10,10,0.8) desc gives the
                                 sharp/soft tonal pair that drives eye-
                                 path. Copper intentionally NOT used here. */
    font-family: var(--v-font-sans, -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif);
    font-size: 1.05rem;
    letter-spacing: 0;
    font-weight: 500;
    line-height: 1.25;
    margin: 0 0 0.6rem;
    color: #0A0A0A;
    transform: none !important;
    text-align: center;
    transition: color 0.25s var(--v-ease);
}

/* [v4-r21] Cap title hover → copper. Restored per user review: the
   title color-shift on hover reads as "alive" editorial chrome and
   complements the image zoom (scale 1.04). Original removal was an
   over-cautious application of the copper-reservation rule; the cap
   titles turning copper transiently does not dilute the thesis card's
   permanent-copper authorial anchor because (a) hover is a transient
   state — only one card is hovered at a time, not all three; (b) the
   thesis eyebrow stays copper statically regardless of hover, so the
   permanent copper anchor is preserved at idle. Hover target is
   --v-accent-canary-dark (#C09D87 — the deep rosewood end of the
   copper system), warmer + more saturated than the title's static
   #0A0A0A. */

.v4-cap-card:hover .v4-cap-title {
    color: var(--v-accent-canary-dark);
}

.v4-cap-desc {
    /* [v4-r21] Inverted hierarchy — desc promoted to the lead statement.
       Clamped to scale with viewport so it stays just below the thesis
       body's clamp ceiling (1.75rem): on phones both read ~1.15rem; on
       desktop the thesis body grows to 1.75rem while cap desc caps at
       1.4rem — thesis retains the largest voice in the bento, cap cards
       follow. Weight 400, sans family, centered + wrapping body-copy
       behaviour so the descriptive sentence reads as the muscle of the
       card rather than a quiet caption under the title. */
    font-family: var(--v-font-sans, -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif);
    font-size: clamp(1.125rem, 1.4vw, 1.25rem);
    font-weight: 400;
    line-height: 1.4;
    letter-spacing: -0.2px;
    color: rgba(10, 10, 10, 0.8);
    margin: 0;
    width: 100%;
    text-align: center;
    white-space: normal;
    overflow: visible;
    max-height: none;
    transition: color 0.25s var(--v-ease);
}

.v4-cap-card:hover .v4-cap-desc {
    color: rgba(10, 10, 10, 0.9);
}

.v4-cap-footer {
    /* [v4-r18] Match previous .slick-footer + .slick-arrow format from
       home-overrides-v4.css:584-614. Positioned absolutely below the
       overlay's content block, anchored at bottom: -8rem (i.e. pulls it
       below the natural content flow). The pill button is centered. */
    position: absolute;
    bottom: -8rem;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
    border-top: none;
}

.v4-cap-footer .v4-cap-arrow {
    /* White pill button with hairline border — the previous .slick-arrow
       format from home-overrides-v4.css:598-614. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 40px;
    padding: 0.45rem 1.1rem;
    color: #1d1d1f;
    font-family: var(--v-font-sans, -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif);
    font-size: 0.75rem;
    letter-spacing: 0.8px;
    font-weight: 500;
    transition: opacity 0.4s var(--v-ease),
        background 0.4s var(--v-ease),
        box-shadow 0.4s var(--v-ease);
    pointer-events: none;
}

.v4-cap-card:hover .v4-cap-footer .v4-cap-arrow {
    background: #f5f5f7;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
    opacity: 0.7;
}

.v4-cap-link {
    /* Stretched-link overlay — the whole .v4-cap-card <div> is clickable
       via this absolutely-positioned <a> that fills the card. Mirrors
       the .v4-thesis-link pattern. */
    position: absolute;
    inset: 0;
    z-index: 3;
    text-decoration: none;
    color: inherit;
}

/* ---------- end v4-r18 capability cards ----------

/* Placeholder background where the video used to be. Solid black so it reads
   as "real footage incoming" rather than "something broken here".
   [v4-r16] Removed border-radius — let parent overflow:hidden clip corners.
   Image's own radius caused a visible dark gap during hover scale(). */
.v4-card .card-bg-placeholder {
    position: absolute;
    inset: 0;
    background: var(--v-bg-dark);
    z-index: 0;
}

/* [v4-r15] Static cover image for bento cards (object-on-white grammar).
   Sits above the placeholder, beneath .slick-content. Inherits the card's
   border-radius + overflow:hidden so corners clip cleanly. object-fit:cover
   so the image fills the portrait cell. object-position:center center by
   default — override with #card-port .card-bg-img { object-position: ... }
   if the subject needs re-anchoring.

   [v4-r16 fix] Removed border-radius on the image itself. Previously the
   image had its own border-radius: var(--v-radius-card), but when
   transform: scale(1.15) applied on hover, the scaled image's radius
   scaled with it, leaving a visible dark gap between the image's inner
   curve and the parent's outer curve. Letting the parent .v4-card's
   overflow:hidden + border-radius do all the clipping (matching the
   .v4-thesis-card--image / .v4-thesis-image pattern) eliminates the gap.

   [v4-r17 fix — the actual root cause of the persistent "corner halo"]
   Some cover assets (notably qual.png) ship with transparent (alpha=0)
   regions at their corners. When the card's parent clip applies the 8px
   border-radius to the cover image, the anti-aliased seam between the
   corner curve and the image's transparent corner shows the underlying
   .card-bg-placeholder's dark #0A0A0A color through — rendering as a
   dark halo along the rounded corner of the card. Two-part defense:
     1. Background-color: white. The image carrier (this rule) paints
        white UNLESS the image is opaque. Transparent regions now show
        white (matching object-on-white grammar) instead of dark.
     2. Transform scale 1.15. The larger idle scale pushes the
        transparent corner regions physically outside the card's clip
        rect, so even the anti-aliased seam doesn't land on alpha=0. */
.v4-card .card-bg-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    z-index: 0;
    background-color: #ffffff;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
    display: block;
    transform: scale(1.15);
    transform-origin: center center;
    transition: transform 0.45s var(--v-ease);
}

/* [v4-r15] Hover-zoom on static cover — matches the qual card's video
   hover-zoom gesture (1.18 → 1.28 for video; 1.15 → 1.22 for image).
   Larger idle scale (1.15) is required because some cover assets (notably
   qual.png) have transparent regions at the corners — the extra scale-on-
   idle pushes those alpha=0 regions outside the card's clipping boundary
   so the underlying #0A0A0A .card-bg-placeholder doesn't bleed through
   along the corner curve. */
.v4-card:hover .card-bg-img {
    transform: scale(1.22);
}

.v4-card .slick-content {
    position: relative;
    z-index: 1;
    background: transparent;
}

/* Drop the inherited background video rounding; healthcare the slick-content
   backgrounds that previously rendered the cap1-3.mov tile as a backdrop. */
.v4-card .bg-video,
.v4-card video.bg-video,
.v4-card .slick-card video {
    display: none !important;
}

/* [v4-r15] Hover-play background video for qualification card.
   Override the blanket display:none above by re-declaring display + layout
   for elements carrying [data-hover-video]. Specificity: attribute selector
   + class wins over the older .v4-card .slick-card video rule via !important
   re-declaration here. Paused / muted / looping — JS controls play state on
   hover. Visually sits above the placeholder (#0A0A0A still shows through
   during the brief loading gap before first frame is decoded). */
.v4-card video[data-hover-video] {
    display: block !important;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    z-index: 0;
    border-radius: var(--v-radius-card);
    opacity: 0;
    transition: opacity 0.35s var(--v-ease), transform 0.45s var(--v-ease);
    transform: scale(1.18);
    transform-origin: center center;
    pointer-events: none;
    background: var(--v-bg-dark);
}

.v4-card video[data-hover-video].is-ready {
    opacity: 1;
}

/* Keep .slick-content above the video so headline/desc remain legible.
   .card-bg-placeholder is z:0 — video lives at z:0 too; both sit beneath
   .slick-content at z:1. The video replaces the placeholder visually once
   .is-ready is set; the placeholder still shows during initial poster gap. */
#card-qual:hover video[data-hover-video] {
    opacity: 1;
    /* Slight eased push-in on hover: from 1.18 → 1.28 over 450ms. */
    transform: scale(1.28);
}

/* Radius enforcement — overrides any inherited 25px from home-overrides */
.v4-card,
.v4-card .slick-content,
.v4-card .slick-header,
.v4-card .slick-body,
.v4-card .slick-footer {
    border-radius: var(--v-radius-card) !important;
    overflow: hidden;
}

/* [v4-r15] Kill inherited chrome from base .readmore-card rules
   (global-v3.css:321-353 + home-overrides-v4.css:471-523) that shows up
   as a black border ring + hover scrim on v4 bento cards. Sources being
   neutralized:
     - background-color:#333  (global-v3:326) → transparent
     - background: linear-gradient(...) (home-overrides-v4:474-476) → transparent
     - border: 1px solid rgba(255,255,255,1) (home-overrides-v4:477) → none
     - ::before rgba(0,0,0,0.4→0.6) scrim (global-v3:343-353) → display:none
       (already !important-killed at home-overrides-v4:512, re-affirmed here
       for defensive specificity)
   Also enforce 4px radius on the thesis-card parent (was inheriting 25px
   via cascade from the global .readmore-card stack). */
.v4-card,
.v4-thesis-card {
    border-radius: var(--v-radius-card) !important;
    background-color: transparent !important;
    background-image: none !important;
    background: transparent !important;
    border: none !important;
    overflow: hidden;
}

.v4-card::before,
.v4-thesis-card::before {
    display: none !important;
    content: none !important;
    background: transparent !important;
}

/* [v4-r16] ID-prefixed overrides for the three capability cards.
   These win against the high-specificity `.readmore-card` class-level
   !important rules in home-overrides-v4.css:478-490 that were bleeding
   through to the v4 bento:
     - `padding: 3.5rem 0.5rem !important` (i.e. 56px 8px) — was forcing
       the .slick-content's flex payload (eyebrow+title+desc+arrow) into
       a 56px-padded box. Combined with the inherited translateY(-144px)
       transform, this exposed the cover image's edges during the hover
       transition (the user-reported "bottom border on hover" artifact).
     - `box-shadow: ..., inset 0 2px 0 rgba(255,255,255,0.8)` from line 478
       also re-asserted the white top inset shadow at class-level !important
       (the .v3-cards .readmore-card override above neutralizes the
       v4-home.css instance, but the home-overrides-v4.css one needed
       this ID-prefixed override to fall fully).
   Padding-zero lets .slick-content flex naturally inside the 0-padded
   anchor; .slick-content's own `position: absolute; inset: 28.79...px 0`
   rule (from home-overrides-v4.css:525) still centers it as designed.

   [v4-r17 — the actual cause of the persistent "border" halo]
   `backdrop-filter: blur(30px) !important` from home-overrides-v4.css:475
   was the smoking gun. It causes the browser to sample the page-area
   BEHIND the card, blur it 30px, and composite that blurred backdrop
   THROUGH any transparent regions of the card. Where the cover image
   meets the card's 8px rounded corners (clipped by overflow:hidden),
   a 1-2px anti-aliased gap lets the blurred backdrop bleed through,
   rendering as a translucent halo along all four corners — the "border"
   the user was seeing on Qual / Exp / Port cards. The thesis card
   (<div>, not .readmore-card) never inherited this rule, which is why
   it alone was clean. */
#card-qual,
#card-exp,
#card-port {
    padding: 0 !important;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04) !important;
    background: transparent !important;
    background-image: none !important;
    border: none !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
}

/* ---------- CONTENT-REVEAL HOVER (Cortical pattern, no scale) ---------- */
.v4-card .slick-desc {
    max-height: 1.4em;
    overflow: hidden;
    transition: max-height 0.35s var(--v-ease), color 0.25s var(--v-ease);
}

.v4-card:hover .slick-desc {
    max-height: 4em;
}

.v4-card .card-title {
    transition: color 0.25s var(--v-ease) !important;
    transform: none !important;
}

.v4-card:hover .card-title {
    color: var(--v-accent-canary);
}

.v4-card {
    transition: opacity 0.3s var(--v-ease) !important;
    transform: none !important;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.10) !important;
    /* [v4-r16] Force-clean clipping context. The v4-r15 override above
       sets .v4-card + .v4-thesis-card chrome, but the .v4-card anchor
       still inherited 25px radius + display:flex from .readmore-card
       in global-v3.css:324. Re-declare here at class level so the
       anchor's own box matches the thesis card's clipping behavior. */
    border-radius: var(--v-radius-card) !important;
    overflow: hidden !important;
    background: transparent !important;
    background-image: none !important;
    border: none !important;
}

.v4-card:hover {
    opacity: 0.92;
    transform: none !important;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.10) !important;
}

/* ---------- GALLERY RADIUS ---------- */
.v4-gallery .gallery-item,
.v4-gallery .portrait-clip,
.v4-gallery .portrait-crisp,
.v4-gallery .portrait-blur-bg {
    border-radius: var(--v-radius-card) !important;
}

/* ---------- APHORISM SEPARATOR (between Gallery and Sage band) ---------- */
.v4-aphorism {
    padding: 10rem 0;
    background: var(--v-bg-canvas);
    scroll-margin-top: var(--v-header-h);
}

.v4-aphorism-text {
    font-family: var(--v-font-serif);
    font-style: italic;
    font-size: var(--v-serif-italic-size);
    font-weight: 500;
    line-height: 1.5;
    letter-spacing: 0;
    color: var(--v-serif-italic-color);
    max-width: 720px;
    margin: 0;
}

/* ---------- SAGE BAND V4 ALTERATIONS ---------- */
/* Cycling canary eyebrow word (Inventing → Connecting → Discovering, 3s) */
.v4-sage-eyebrow .v4-cycle-word {
    display: inline-block;
    transition: opacity 0.4s var(--v-ease);
}

.v4-sage-eyebrow .v4-cycle-word.is-fading {
    opacity: 0;
}

/* Sage band pull-quote (seated beside thesis statement, attributed) */
.v4-pullquote {
    margin: 2rem 0 2.5rem;
    padding: 0;
    border: none;
    font-family: var(--v-font-serif);
    font-style: italic;
    font-size: 1.125rem;
    font-weight: 500;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.78);
    max-width: 540px;
}

.v4-pullquote p {
    margin: 0 0 0.5rem;
}

.v4-pullquote cite {
    display: block;
    font-style: normal;
    font-family: var(--v-font-sans);
    font-size: 0.75rem;
    font-weight: 400;
    letter-spacing: 0.4px;
    color: rgba(255, 255, 255, 0.55);
    text-transform: none;
}

/* Variant pullquote inside Connect: muted dark grey on light bg */
.v4-pullquote--inline {
    margin: 1rem 0 1.5rem;
    color: var(--v-serif-italic-color);
    max-width: 480px;
}

.v4-pullquote--inline cite {
    color: #999;
}

/* ---------- CONNECT V4 ALTERATIONS ---------- */
.v4-contact .v4-small-caps {
    margin-bottom: 2.5rem;
}

.v4-contact .v3-connect-card {
    border-radius: var(--v-radius-chrome);
}

.v4-contact .section-subtitle {
    margin-top: 1.5rem;
}

/* ---------- FOOTER V4 CHANGES — split-meta + changelog line ---------- */
.v4-footer .footer-bottom-meta.v4-footer-meta {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    width: 100%;
}

.v4-change-meta {
    font-size: 0.75rem;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.45);
    letter-spacing: -0.3px;
}

.v4-change-meta a {
    color: rgba(255, 255, 255, 0.65);
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color 0.2s ease;
}

.v4-change-meta a:hover {
    color: var(--v-accent-canary);
}

/* ---------- V4 MOBILE RESPONSIVE OVERRIDES ---------- */
@media (max-width: 768px) {

    /* Bento collapses to single column on mobile */
    .v4-bento {
        grid-template-columns: 1fr !important;
        grid-template-rows: none !important;
        gap: 1.25rem;
    }

    .v4-bento .v4-thesis-card,
    .v4-bento>.v4-cap-card {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
    }

    .v4-aphorism {
        padding: 5rem 0;
    }

    .v4-aphorism-text {
        font-size: 1.5rem;
    }

    .v4-continue {
        margin-top: 2.5rem;
    }

    .v4-footer .footer-bottom-meta.v4-footer-meta {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
    }
}

/* ===================================================================
   V4 COMMENTS-11JUL002 SUPERSESSION RULES
   Addresses the 11 user comments in comments-11jul002.md after a live
   browser review. Choices locked via interactive Q&A panel. Each block
   cites the comment number it resolves.
   =================================================================== */

/* ---------- Comment 1: bento corners — keep 8px (radius reduction from earlier 12px) ---------- */
/* [v4-r21] Token unification — --v-radius-chrome now locked to 8px in the
   root block above. The earlier two-shape grammar (pill 100px for hero,
   sharp 0px for the rest) is retired; all chrome buttons now share the
   sage/community section's soft-rectangle radius (8px). --v-radius-pill
   token removed; any selector that still references it falls back to
   the chrome value. */
:root {
    --v-radius-card: 8px;
    --v-radius-chrome: 8px;
}

/* ---------- Comment 2: navbar 'Lucan Leung' must return to v4, not original ---------- */
/* HTML href already changed to index-v4.html — no CSS needed. */

/* ---------- Comment 10: hero text — restore original 12rem bold + asymmetric ---------- */
/* The original .hero-title treatment (home-overrides.css line 84):
     font-size: 12.0rem; font-family: Helvetica Neue; font-weight: 425;
   plus (home-overrides.css line 90): .hero-content { position relative; bottom 12vh; left 13.5%; }
   We target the v4 hero title (currently using clamp 3-7rem via .v3-hero__title) and restore
   the bold + asymmetric anchor. The hero is light-on-dark using black_pic1.png backdrop. */
.v3-hero__title.v4-hero__restore,
.v4-hero .v3-hero__title {
    font-size: clamp(4rem, 14vw, 12rem) !important;
    /* up to 192px on wide viewports */
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important;
    font-weight: 425 !important;
    letter-spacing: -2px !important;
    line-height: 0.95 !important;
    margin-bottom: 3rem !important;
    text-shadow: 0 4px 20px rgba(0, 0, 0, 0.5) !important;
}

.v4-hero .v3-hero__content {
    position: relative;
    align-self: center;
    /* Close to true vertical center, with a small upward offset. The 8vh
       bottom padding nudges the block just slightly above the optical
       center of the 110svh hero — keeps the CTA buttons in view on a
       standard 100svh viewport while giving the text a touch more breath
       above than below, which reads as 'cinematically centered' rather
       than 'mechanically centered'. Previous 18vh lifted too far up. */
    padding-top: 0vh;
    padding-bottom: 0vh;
    margin: auto;
    width: 100%;
}

/* ---------- Comment 4: gallery rail — align left edge to title ---------- */
/* The .v3-wrap caps content at 1120px but the gallery window was inheriting
   a negative margin from v3's home-overrides (extending the gallery wider).
   Pull .gallery-window back inside the wrap by removing its inherited margin
   and clamping width to the same content edge as the title. */
.v4-gallery .gallery-window {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
}

/* Re-apply the existing gallery-window negative-margin pattern only on viewports
   wide enough to NOT trigger overflow. Cap at 1280px to be safe. */
@media (min-width: 1280px) {
    .v4-gallery .gallery-window {
        /* Re-allow slight bleed to align with title's left edge — title sits at
           the same gutter as gallery items. */
        margin-left: 0;
    }
}

/* Align the section-inner / v3-wrap so the title (h2.section-title) and the
   first gallery item share the exact same left x. This is a gutter re-alignment. */
.v4-gallery .section-inner.v3-wrap {
    padding-left: var(--v-gutter, 5%);
    padding-right: var(--v-gutter, 5%);
}

.v4-gallery .gallery-track {
    padding-left: 0;
}

/* ---------- Comment 5: sage band — text bonded within wrap width ---------- */
.v4-sage .v3-breakthrough,
.v4-sage .v4-pullquote,
.v4-sage .v3-quote-eyebrow,
.v4-sage .v3-breakthrough-cta {
    max-width: var(--v-site-max, 1120px);
    margin-left: 0;
    margin-right: 0;
    width: 100%;
}

/* Constrain breakthrough text width so it doesn't run wider than the wrap on
   ultrawide viewports. The wrap is already capped at 1120px, but inner block
   widths in v3 base (max-width: 920px) were inconsistent — bond to .v3-wrap. */
.v4-sage .section-inner.v3-wrap {
    max-width: var(--v-site-max, 1120px);
    margin: 0 auto;
    padding-left: var(--v-gutter, 5%);
    padding-right: var(--v-gutter, 5%);
}

.v4-sage .v3-breakthrough {
    max-width: 720px;
}

.v4-sage .v4-pullquote {
    max-width: 540px;
}

/* ---------- Comment 6: Community & Philosophy section — same constraint ---------- */
/* Same rule re-applied to Outreach outbound link band. Already covered by .v4-sage
   rules above (sage band IS this section). Reaffirming the wrap discipline. */
.v3-section-sage.v4-sage .section-inner {
    width: 100%;
    max-width: var(--v-site-max, 1120px);
    margin: 0 auto;
}

/* ---------- Comment 9 (mock-home border adoption) — all sections constrained to 1120px wrap ---------- */
/* Apply uniform wrap discipline to every major section. */
.v3-section .section-inner.v3-wrap,
.v4-contact .section-inner.v3-wrap,
.v4-aphorism .section-inner.v3-wrap,
.v3-band-announce .section-inner.v3-wrap,
.v4-footer-mock .section-inner.v3-wrap {
    max-width: var(--v-site-max, 1120px);
    margin: 0 auto;
    padding-left: var(--v-gutter, 5%);
    padding-right: var(--v-gutter, 5%);
    width: 100%;
}

/* ---------- Comment 8: unify buttons — original format + slightly-rounded corners ---------- */
/* [v4-r21] Hero CTAs — same soft-rectangle grammar as the rest of the
   page, but at a proportionally-smaller radius than the sage/community
   button so the hero CTAs read at the SAME visual roundness rather than
   the same px value. The hero buttons are larger overall (visually
   heavier against the 110svh dark image), and 8px on a larger button
   reads as noticeably more rounded than 8px on the smaller sage button.
   Per user feedback DevTools confirmed both buttons compute to 8px,
   but the hero CTAs *looked* rounder — that's the proportional-radius
   perception. Setting hero to 4px lands the same visual corner-radius
   relative to the hero button's larger surface area. */
.v4-hero .v3-btn-pill-solid,
.v4-hero .v3-btn-pill-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 4px !important;
    padding: 0.55rem 1.1rem !important;
    color: #1d1d1f !important;
    font-size: 0.78rem !important;
    letter-spacing: 0.6px !important;
    font-weight: 400 !important;
    transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1),
        background 0.4s cubic-bezier(0.16, 1, 0.3, 1) !important;
    text-decoration: none;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    box-shadow: none !important;
}

.v4-hero .v3-btn-pill-solid {
    /* Dark-theme primary CTA — charcoal bg with cream text. Reads as the
       authoritative affordance on the light-themed hero backdrop (white-
       tinted new-hero2.png) — inverse of the ghost CTA's pale treatment. */
    background: #1d1d1f !important;
    color: #F8F7F5 !important;
    border-color: #1d1d1f !important;
}

.v4-hero .v3-btn-pill-ghost {
    background: transparent;
    color: #ffffff !important;
    border: 1px solid rgba(255, 255, 255, 0.4) !important;
}

.v4-hero .v3-btn-pill-solid:hover {
    /* Hover nudges charcoal slightly lighter (#1d1d1f → #2a2a2c) and text
       stays cream. No inversion here — the dark bg is already the active
       treatment, so hover just lifts the surface. */
    background: #2a2a2c !important;
    border-color: #2a2a2c !important;
}

.v4-hero .v3-btn-pill-solid:active {
    /* Active press — small inset: lightens further + scales 0.98 so the
       press registers visually without overpowering the resting state. */
    background: #3a3a3c !important;
    border-color: #3a3a3c !important;
    transform: scale(0.98);
}

.v4-hero .v3-btn-pill-ghost:hover {
    background: #ffffff;
    color: #1d1d1f !important;
    border-color: #ffffff !important;
}

/* ---------- [v4-r22] Light-theme hero — new-hero2.png backdrop ----------
   The hero bg was swapped from new-main.JPEG (dark, high-contrast portrait)
   to new-hero2.png (white-themed, lighter lumload). The overlay layer
   (new-overlay.png) is temporarily commented out in index-v4.html because
   it was tuned against the dark backdrop and reads muddy against the new
   one. This block inverts all hero text + ghost CTA colours from
   light-on-dark → dark-on-light. The solid CTA was already dark-on-white
   and needs no change (it stays as the "primary tier" against any backdrop).

   What changes here:
     · .v3-hero background gradient (line 72-73) was dark fallback —
       flipped to a light fallback so image-load-failure still reads as
       "light hero".
     · .v3-hero__title colour: --v-text-on-dark (cream) → --v-text-primary
       (charcoal). Text-shadow was dark (0,0,0,0.45) → inverted to light
       (0,0,0,0.18 — small dark glow that ensures legibility against
       busy whites without darkening glyph).
     · .v4-hero .v3-hero__title text-shadow同理.
     · .v3-hero__sub colour: rgba(255,255,255,0.88) → rgba(10,10,10,0.78).
     · .v3-hero__eyebrow colour stays var(--v-accent-canary) — copper
       reads the same against either bg tone.
     · .v4-hero .v3-btn-pill-ghost color/border inverts to dark-on-light
       to match the new backdrop. Solid CTA unchanged.

   To revert: revert this block, drop the bg-gradient edits, swap the
   img src back to new-main.JPEG and uncomment the overlay <img>.
   ------------------------------------------------------------------------ */
.v3-hero {
    /* [v4-r22] Carry the background-attachment:fixed forward into this
       duplicate .v3-hero rule (line 1814). The primary .v3-hero spec
       at line 67 sets `background-attachment: fixed` for the parallax
       hero image, but this duplicate rule cascades later and was
       silently overriding `background` back to a light canvas gradient
       (because the `background` shorthand resets background-attachment
       to scroll when re-declared). User observed: "now the hero image
       is just gone" — fix by repeating the shorthand WITH
       background-attachment:fixed in the same declaration.

       [v4-r22] NO OVERLAY GRADIENT — per user feedback, the
       beige-tinted linear-gradient overlay I had here created a
       "film of filter" that wasn't requested. Just the hero image,
       pure. */
    background:
        url('../images/Hero/new-hero2.png') center / cover no-repeat;
    background-attachment: fixed;
    color: var(--v-text-primary);
}

.v4-hero .v3-hero__title {
    /* [v4-r22] Solid charcoal base — necessary fallback so glyph renders
       visibly if the per-word gradient rule below is stripped or fails
       (background-clip:text needs both -webkit-text-fill-color:transparent
       AND a non-transparent `color` fallback on the parent for older
       browsers; the transparent fallback is supplied on .v4-hero__word). */
    color: var(--v-text-primary) !important;
    /* [v4-r22] Text-shadow temporarily commented out per user request
       to evaluate the per-word gradient effect unmediated.
       Re-enable by uncommenting the rule below.
    text-shadow: 0 2px 16px rgba(255, 255, 255, 0.6),
                 0 1px 3px rgba(0, 0, 0, 0.08) !important;
    */
    /* [v4-r22] Kill ALL inherited text-shadows on the title that read as
       visible blur against the per-word gradient. The title inherits
       shadows from THREE cascade sites:
         .v3-hero__title                        (line 134 — `0 4px 24px rgba(0,0,0,0.45)`)
         .v4-hero .v3-hero__title.v4-hero__restore (line 1563 — `0 4px 20px rgba(0,0,0,0.5) !important`)
         .v4-hero .v3-hero__title                  (line 1764 — commented out above)
       The 1563 `!important` would otherwise win and render the dark glow
       that reads as a visible blur around the gradient glyphs. `none !important`
       here defeats it cleanly; remove this line to restore the inherited
       shadow behaviour. */
    text-shadow: none !important;
}

.v4-hero .v4-hero__word {
    /* [v4-r22] Per-word gradient — dark-grey → full opaque white across
       each glyph group. alpha=0.7 preserved at the dark end (keeps the
       'etched' feel against the photo); the tail of each word snaps
       to solid #FFFFFF alpha 1.0 so the right edge of "Invent." and
       "Innovate." reads as a crisp, completely white terminal glyph.

       Each <span> is its own gradient context via display:inline-block.
       The background gradient itself + the text-clip mechanics are
       defined on the per-word :nth-of-type rules below so they live
       together on the same selector — avoids the longhand-reorder issue
       where setting `background:` (shorthand) on the :nth-of-type rule
       silently resets `-webkit-background-clip: text` if it was set
       on a different (base) selector.

       Tail-start per word:
         · Invent.   → 90% (last 10% is solid white)
         · Innovate. → 80% (last 20% is solid white)
    */
    display: inline-block;
}

/* [v4-r22] Invent. — 10% solid-white tail. Hue fade 0–70%, opacity ramp
   70–90%, locked solid white 90–100%. The shorter word gets the tighter
   tail — reads as the *origin* of the gradient idea. */
.v4-hero .v4-hero__word:nth-of-type(1) {
    background: linear-gradient(to right,
        rgba(29, 29, 31, 0.7) 0%,
        rgba(255, 255, 255, 0.7) 70%,
        rgba(255, 255, 255, 1.0) 90%,
        rgba(255, 255, 255, 1.0) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

/* [v4-r22] Innovate. — 20% solid-white tail. Same 0–70% hue fade base;
   opacity ramp 70–80%, locked solid white 80–100%. The longer word
   reads as the *fulfilment* of the gradient idea — wider white tail
   gives the terminal glyph an emphatic arrival. */
.v4-hero .v4-hero__word:nth-of-type(2) {
    background: linear-gradient(to right,
        rgba(29, 29, 31, 0.7) 0%,
        rgba(255, 255, 255, 0.7) 70%,
        rgba(255, 255, 255, 1.0) 80%,
        rgba(255, 255, 255, 1.0) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.v4-hero .v3-hero__sub {
    color: rgba(10, 10, 10, 0.78) !important;
}

.v4-hero .v3-btn-pill-ghost {
    background: transparent;
    color: #1d1d1f !important;
    border: 1px solid rgba(10, 10, 10, 0.35) !important;
}

.v4-hero .v3-btn-pill-ghost:hover {
    background: #1d1d1f !important;
    color: #ffffff !important;
    border-color: #1d1d1f !important;
}

/* [v4-r21] Inline CTA + sage + announcement + connect social buttons —
   single-shape soft-rectangle grammar. Inherits --v-radius-chrome (8px)
   from the root block via var(). This is the spec the sage/community
   section button uses, and every other chrome button now matches it.
   Hero CTAs (above) inherit the same 8px via their own override block. */
.v3-btn-square-light,
.v3-btn-square-bordered,
.v3-btn-square-yellow,
.v4-btn-light,
.v4-btn-yellow {
    border-radius: var(--v-radius-chrome) !important;
    /* 8px — matches the sage/community section button */
    padding: 0.55rem 1.1rem !important;
    font-size: 0.78rem !important;
    font-weight: 400 !important;
    letter-spacing: 0.6px !important;
    transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1),
        background 0.4s cubic-bezier(0.16, 1, 0.3, 1),
        color 0.4s cubic-bezier(0.16, 1, 0.3, 1),
        border-color 0.4s cubic-bezier(0.16, 1, 0.3, 1) !important;
}

.v3-btn-square-light:hover,
.v4-btn-light:hover {
    opacity: 0.7;
    background: #f5f5f7;
}

/* v4 light button (Connect section, dark bg) — light square Even-style, 8px */
.v4-btn-light {
    display: inline-block;
    background: var(--v-text-on-dark, #F8F7F5);
    color: var(--v-bg-dark, #0A0A0A);
    border: 1px solid var(--v-text-on-dark, #F8F7F5);
    text-decoration: none;
    padding: 0.55rem 1.4rem !important;
    font-size: 0.78rem !important;
    font-weight: 400 !important;
    letter-spacing: 0.6px !important;
}

.v4-btn-light:hover {
    background: rgba(255, 255, 255, 0.85);
    opacity: 0.85;
}

/* v4 social icon buttons (LinkedIn, GitHub) — replace text labels with
   greyscale SVG logos. Keeps the Even-square-hairline button language via
   .v4-btn-light, dropping only the text content. SVG sits inline, sized to
   ~1em so its visual weight matches the adjacent Email button's text.
   filter: grayscale(1) ensures brand colours are neutralized consistently
   (LinkedIn blue and GitHub black both become mid-grey on the light bg).
   Since the GitHub logo was supplied as #1B1F23 and the LinkedIn logo as
   a path with no fill (inherits currentColor), grayscale(1) plus opacity
   adjustment on hover keeps both glyphs reading as quiet chrome accents. */
.v4-social-btn {
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 3.5rem !important;
    height: 2.35rem !important;
    padding: 0 !important;
}

.v4-social-icon {
    width: 1.35rem;
    height: 1.35rem;
    fill: currentColor;
    filter: grayscale(1);
    display: block;
    transition: filter 0.25s var(--v-ease);
}

.v4-social-img {
    fill: none;
    width: 1.9rem;
    height: 1.9rem;
    object-fit: contain;
    /* Crush to pure black silhouette: grayscale drops hue, brightness 0
       zeroes every channel so the icon reads as solid #000 regardless of
       the source artwork's tonal values. */
    filter: grayscale(1) brightness(0);
}

.v4-social-btn:hover .v4-social-img {
    filter: grayscale(1) brightness(0) opacity(0.85);
}

.v4-social-btn:hover .v4-social-icon {
    filter: grayscale(1) brightness(0.85);
}

/* v4 copper-beige button (announcement band) — flat lighter beige fill with
   dark-charcoal gradient text. Text gradient is applied to an INNER span
   (.v4-btn-yellow__label) so that background-clip:text only clips the inner
   element. If the gradient were applied to the button element itself, the
   background-image (charcoal gradient) would override the background-color
   (beige fill), making the entire button charcoal and the text would
   vanish. Gradient runs between the two dark anchors of the page (#232323
   the cushion/footer charcoal, #0A0A0A the connect/announcement-band
   charcoal) — so the button's text colour rhymes with the dark band it
   sits inside, while the fill stays in the copper-beige family. Hue delta
   is small (~6% lightness), reads as a soft sheen on the charcoal glyphs. */
.v4-btn-yellow,
.v3-btn-square-yellow {
    /* Gradient fill (copper-beige → mid-copper) running on the 95° axis so
       the sheen reads left-to-right across the button. The label inside is
       solid charcoal text (no longer text-gradient — the bg gradient now
       does the visual lifting, so a second gradient on the text would
       compete). Hover + active invert the bg to the dark anchors of the
       page (#232323 → #0A0A0A) and flip the text to cream — the dark band
       the button sits inside is roughly #333333, so this creates a clean
       "button pushes forward into the band" inversion. */
    background: linear-gradient(95deg,
        var(--v-accent-canary-light, #EFD8BC) 0%,
        var(--v-accent-canary-mid, #C09D87) 100%) !important;
    border: 1px solid var(--v-accent-canary-mid, #C09D87) !important;
    padding: 0.55rem 1.4rem !important;
    font-size: 0.78rem !important;
    font-weight: 500 !important;
    letter-spacing: 0.6px !important;
    text-decoration: none !important;
    box-shadow: 0 1px 2px rgba(192, 157, 135, 0.25) !important;
    transition: background 0.35s var(--v-ease),
        border-color 0.35s var(--v-ease),
        box-shadow 0.25s var(--v-ease),
        color 0.35s var(--v-ease);
    color: #1d1d1f !important;
}

.v4-btn-yellow__label {
    /* Charcoal text — the same dark anchor the page uses for body text and
       the dark-theme hero CTA. Sits in clear contrast against the beige bg
       gradient at rest. On hover/active the bg inverts to charcoal, so the
       text must invert in parallel — handled below (text → #EFD8BC, the
       lightest beige-copper anchor). The label keeps its inline-block
       wrapper so any future text-gradient experiments don't need HTML
       changes. */
    color: #1d1d1f;
    display: inline-block;
    transition: color 0.35s var(--v-ease);
}

.v4-btn-yellow:hover,
.v3-btn-square-yellow:hover {
    /* Invert to the dark variant: charcoal gradient bg + beige-copper text.
       The bg gradient mirrors the resting gradient's 95° axis (and same
       lightness delta ~6%) so the cross-fade reads as a clean inversion
       rather than two unrelated colours swapping. The text simultaneously
       flips from charcoal (#1d1d1f) to the lightest beige-copper (#EFD8BC)
       — same family as the resting bg gradient, now the text carries the
       warm hue against the dark bg. */
    background: linear-gradient(95deg, #232323 0%, #0A0A0A 100%) !important;
    border-color: #0A0A0A !important;
    box-shadow: 0 2px 5px rgba(10, 10, 10, 0.35) !important;
    color: #EFD8BC !important;
}

.v4-btn-yellow:hover .v4-btn-yellow__label,
.v3-btn-square-yellow:hover .v4-btn-yellow__label {
    color: #EFD8BC !important;
}

.v4-btn-yellow:active,
.v3-btn-square-yellow:active {
    /* Active press — same inverted colours as hover but with a small scale
       nudge so the press registers without a heavier colour shift. */
    background: linear-gradient(95deg, #1d1d1f 0%, #000000 100%) !important;
    border-color: #000000 !important;
    color: #EFD8BC !important;
    transform: scale(0.98);
}

.v4-btn-yellow:active .v4-btn-yellow__label,
.v3-btn-square-yellow:active .v4-btn-yellow__label {
    color: #EFD8BC !important;
}

/* Footer contact links — keep Even square hairline but with 8px corners too
   (per Comment 8 — unified slightly-rounded rectangle language) */
.v4-footer-mock .v4-footer__links a {
    border-radius: var(--v-radius-chrome);
}

/* ---------- Comment 7: Connect section — dark theme ---------- */
.v4-contact--dark {
    background: var(--v-bg-dark, #0A0A0A) !important;
    color: var(--v-text-on-dark, #F8F7F5) !important;
    padding: var(--v-margin-top, 8rem) 0 var(--v-margin-bot, 8rem) !important;
}

.v4-contact--dark .v4-contact__inner {
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.v4-contact--dark .v4-contact__eyebrow {
    color: var(--v-accent-canary, #E2C0A0);
    letter-spacing: 1.5px;
    margin-bottom: 1rem;
}

.v4-contact--dark .v4-contact__title {
    font-size: clamp(3rem, 6vw, 5rem);
    font-weight: 500;
    letter-spacing: -1px;
    color: #ffffff !important;
    margin: 0.5rem 0 1.5rem;
    text-align: center;
}

.v4-contact--dark .v4-contact__subtitle {
    font-size: 1.15rem;
    font-weight: 300;
    color: rgba(255, 255, 255, 0.85) !important;
    max-width: 560px;
    margin: 1rem auto 3rem;
    line-height: 1.55;
    text-align: center;
}

.v4-contact--dark .v4-connect__cta {
    display: flex;
    justify-content: center;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Pull-quote on dark: muted slate-on-almost-black, italic serif */
.v4-pullquote--on-dark {
    color: rgba(248, 247, 245, 0.78) !important;
    max-width: 560px;
    margin: 1rem auto 1.5rem !important;
    text-align: center;
}

.v4-pullquote--on-dark cite {
    color: rgba(248, 247, 245, 0.55) !important;
}

/* ---------- Comment 9: Footer — mock-home Even 5-column grid (1.5fr repeat(4, 1fr)) ---------- */
.v4-footer-mock {
    background: #232323;
    /* mock-home charcoal */
    color: #F8F7F5;
    padding: 6rem 0 0;
    font-size: 0.85rem;
    font-weight: 300;
    line-height: 1.5;
    letter-spacing: -0.3px;
}

.v4-footer-mock .v4-footer-grid {
    display: grid;
    grid-template-columns: 1.5fr repeat(4, 1fr);
    column-gap: 6rem;
    row-gap: 3rem;
    padding-bottom: 4rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}

.v4-footer-mock .v4-footer__brand-name {
    font-size: 1rem;
    font-weight: bold;
    letter-spacing: 1px;
    margin-bottom: 1rem;
    color: #FFFFFF;
}

.v4-footer-mock .v4-footer__desc {
    color: #919191;
    max-width: 240px;
}

.v4-footer-mock .v4-footer__heading {
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: #F8F7F5;
    margin-bottom: 1.25rem;
}

.v4-footer-mock .v4-footer__links {
    list-style: none;
    padding: 0;
    margin: 0;
}

.v4-footer-mock .v4-footer__links a {
    display: block;
    padding: 0.35rem 0;
    color: rgba(255, 255, 255, 0.75);
    transition: color 0.2s ease;
    text-decoration: none;
    font-size: 0.8rem;
}

.v4-footer-mock .v4-footer__links a:hover {
    color: #F8F7F5;
}

.v4-footer-mock .v4-footer__bottom {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 2rem 0;
    color: #919191;
    font-size: 0.78rem;
}

.v4-footer-mock .v4-footer__legal {
    display: flex;
    gap: 1.5rem;
}

.v4-footer-mock .v4-footer__legal a {
    color: inherit;
    text-decoration: none;
}

.v4-footer-mock .v4-footer__legal a:hover {
    color: #F8F7F5;
}

.v4-footer-mock .v4-copyright {
    letter-spacing: -0.3px;
}

.v4-footer-mock .v4-change-meta {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.45);
    letter-spacing: -0.3px;
}

.v4-footer-mock .v4-change-meta a {
    color: rgba(255, 255, 255, 0.65);
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color 0.2s ease;
}

.v4-footer-mock .v4-change-meta a:hover {
    color: var(--v-accent-canary, #E2C0A0);
}

/* Footer support-logos row — institutional trustline at the bottom of the
   footer. Greyscaled + brightness-lift (not opacity-faded) so the logos
   read as quiet provenance without dimming into the dark bg. Wide horizontal
   source images (680x85) scale with the wrap while preserving aspect. */
.v4-footer__support {
    margin-top: 0.75rem;
    padding: 3.5rem 0 2.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
}

.v4-footer__support-img {
    max-width: 360px;
    width: 100%;
    height: auto;
    object-fit: contain;
    filter: grayscale(1) brightness(1.1);
    transition: filter 0.3s var(--v-ease);
}

.v4-footer__support-img:hover {
    filter: grayscale(1) brightness(1.25);
}

/* ---------- Comment 3: chevron no-op — dim + unclickable visual ---------- */
.v4-continue[disabled],
.v4-continue[aria-disabled="true"] {
    opacity: 0.35;
    cursor: not-allowed;
    pointer-events: none;
}

.v4-continue[disabled]:hover,
.v4-continue[disabled] .v4-continue__icon {
    opacity: 0.35;
    transform: none;
}

/* ---------- Mobile override for mock-home footer grid ---------- */
@media (max-width: 768px) {
    .v4-footer-mock .v4-footer-grid {
        grid-template-columns: 1fr;
        gap: 2rem;
    }

    .v4-footer-mock .v4-footer__bottom {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
    }

    .v4-footer-mock .v4-footer__legal {
        margin-top: 0.5rem;
    }

    .v4-contact--dark .v4-contact__inner {
        text-align: left;
        align-items: flex-start;
    }

    .v4-contact--dark .v4-contact__title,
    .v4-contact--dark .v4-contact__subtitle,
    .v4-pullquote--on-dark {
        text-align: left;
        margin-left: 0;
    }

    .v4-contact--dark .v4-connect__cta {
        justify-content: flex-start;
    }
}

/* ===================================================================
   V4 COMMENTS-11JUL003 SUPERSESSION RULES
   Root cause diagnosis: home-overrides-v4.css line 53 declares
     .section-inner { max-width: 1100px !important; padding: 0 5% !important; }
   This competes with v3's .v3-wrap (1120px max, 5% gutter) and wins
   due to !important. Result: every non-hero section's text boundary
   was 1100px centered → 5% inner padding, giving a different left
   edge than the hero (which uses .v3-hero__content, not .section-inner,
   and inherits the v3 1120px wrap).

   The fix below enforces ONE canonical text boundary everywhere:
     max-width: 1120px, centered, 5% horizontal gutter (var(--v-gutter)).
   Hero already follows this. We pull every other section into match.
   =================================================================== */

/* ---- 1. Override the competing .section-inner rule from home-overrides-v4.css ---- */
/* Restore the v3-wrap geometry on every .section-inner so all sections share
   the hero's 1120px max-width with 5% gutter. The !important here is required
   to defeat the home-overrides-v4.css line 53 !important. */
/* [v4-r20] Extra bottom padding for capabilities section to add whitespace
   between the bento and cushion #2 below. Scales with viewport via clamp so
   it reads as breath and not as a blank void on smaller screens. */
#read-more.section-readmore.v4-capabilities {
    padding-bottom: calc(var(--v-margin-bot, 8rem) + 8rem) !important;
    /* scroll-margin-top so the .v4-greet-skip anchor's smooth-scroll lands
       the section's visible top border below the sticky navbar instead of
       burying the first ~64px under it. Matches the --v-header-h token used
       by other scroll-snap targets in this file. */
    scroll-margin-top: var(--v-header-h, 64px);
    /* [v4-r22] The "disappearing border" effect — the intro section's
       solid white background must definitively paint OVER the
       fixed-positioned .v4-hero-bg (which sits at z-index:0 and
       position:fixed, pinned to viewport top-left). Three reinforcing
       properties guarantee the intro wins:

       1. `isolation: isolate` — forces the intro into its own clean
          stacking context, severing any inherited ancestor trap
          from .v3-hero (which is position:relative + z-index:auto
          and could conceivably compete with the fixed bg's
          root-context positioning).

       2. `z-index: 100 !important` — well above the home-overrides
          default of 25 and the fixed bg's 0. The `!important` defeats
          any future revisions that might try to lower this.

       3. `background: #FFFFFF !important` — pure white, definitively
          opaque. Uses the `background` shorthand (not just
          background-color) so any inherited `background:
          linear-gradient(...)` from home-overrides-v4.css:99 is
          overridden cleanly — the shorthand resets all bg longhands.

       Result: as the intro section scrolls up from below the viewport,
       its solid white bg paints OVER the still-pinned hero image
       from the bottom up. The hero image visibly "sinks behind" the
       white intro bg as the seam rises — the requested disappearing
       border effect.
    */
    isolation: isolate;
    z-index: 100 !important;
    background: #FFFFFF !important;
}

.section-inner.v3-wrap,
.v4-capabilities .section-inner,
.v4-gallery .section-inner,
.v4-aphorism .section-inner,
.v4-sage .section-inner,
.v4-band-announce .section-inner,
.v4-contact--dark .section-inner,
.v4-footer-mock .section-inner {
    max-width: var(--v-site-max, 1120px) !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    width: 100% !important;
    box-sizing: border-box !important;
}

/* ---- 1a. Override the per-section 900px narrow-column constraint ---- */
/* home-overrides-v4.css lines 909-919 and 2303-2315 push .small-caps,
   .section-title, .section-subtitle, .cards-container into a 900px centered
   sub-column with auto margins + 5% inner padding. This created the 39px gap
   between hero text (x=224) and capabilities title (x=263).
   Override so the titles + content fill the full 1120px wrap, sitting flush
   with the hero's left text edge. */
#read-more .section-inner>.small-caps,
#read-more .section-inner>.section-title,
#read-more .section-inner>.section-subtitle,
#read-more .section-inner>.cards-container,
#gallery .section-inner>.small-caps,
#gallery .section-inner>.section-title,
#gallery .section-inner>.section-subtitle {
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    width: 100% !important;
    box-sizing: border-box !important;
}

/* Make caps/gallery .section-title spacing match cushion #2's *perceived*
   visual ratio (gap / title-height = 0.41 for label→title, 0.83 for title→sub).
   Raw px transfer (20/40px) didn't read as cohesive because caps/gallery's
   .section-title is 72px (vs cushion's 44px) — same raw gap knocks the visual
   ratio down by ~60%. Scaled gaps below compensate.
   Caps/title-h = 108px → 108×0.83 ≈ 90px = ~5.6rem.
   Beats home-overrides-v4.css line 209's `margin-bottom: 1.5rem !important`
   via ID-prefixed specificity. */
#read-more .section-inner>.section-title,
#gallery .section-inner>.section-title {
    /* v4-r12: titles became more descriptive ("Get to know who I am." /
       "Take a closer look.") — originally matched cushion #2's exact size.
       Bumped ~10% larger per user review: dark-on-white reads ~10% smaller
       than dark-on-dark, so titles need slightly larger sizing to visually
       match cushion #2's title-on-charcoal read.
       Beats home-overrides-v4.css line 241's clamp(3rem, 6vw, 4.5rem)
       via ID specificity + !important. */
    font-size: clamp(2.2rem, 4.4vw, 3.0rem) !important;
    margin-bottom: 1.3rem !important;
}

/* Tighten the subtitle's negative margin-top — its current -32px pulls it
   up so hard the title's 2.5rem margin-bottom collapses to ~8px effective.
   Undo that so the title's 5.5rem bottom actually reads unbroken. */
#read-more .section-inner>.section-subtitle,
#gallery .section-inner>.section-subtitle {
    margin-top: 0 !important;
}

/* Eyebrow margin-bottom: scale to match cushion's gap-to-title-height
   ratio of 0.41. Caps/gallery .section-title is 108px tall, so target
   gap = 108 × 0.41 ≈ 44px = 2.75rem. Was 1.5rem (24px) at 0.22 ratio,
   now 2.75rem (44px) at 0.41 ratio — exactly matches cushion's perceived
   tightness. */
#read-more .section-inner>.small-caps,
#gallery .section-inner>.small-caps {
    margin-bottom: 0rem !important;
}

/* ---- 2. Gallery rail — RESTORE original full-bleed kinetic scroll (comments-12jul001 line 2) ---- */
/* The constrained text-boundary rail broke the only kinetic gesture on the page.
   Restore the original `width: 100vw; margin-left: calc(50% - 50vw);` so the
   rail bleeds past the right edge of the 1120px wrap. The section title +
   eyebrow and the gallery controls row still bond to the text boundary; the
   rail itself escapes it. This was the original homepage gesture, and remains
   worth keeping per user review (comments-12jul001.md line 2). */
.v4-gallery .gallery-window {
    width: 100vw !important;
    max-width: 100vw !important;
    margin-left: calc(50% - 50vw) !important;
    margin-right: 0 !important;
    overflow: visible;
}

.v4-gallery .gallery-track {
    padding-left: max(var(--v-gutter, 5%), calc((100vw - var(--v-site-max, 1120px)) / 2 + var(--v-gutter, 5%))) !important;
    padding-right: 2rem !important;
    margin-top: -2rem;
    padding-top: 2rem;
    padding-bottom: 4rem;
}

/* ---- 3. Sage / Community section — video background restored + text aligned ---- */
/* First: revive the .outreach-* classes that the v3 reset block in
   home-overrides-v4.css line 36-39 blanket-killed with `display: none !important`.
   We scope the revival to .v4-sage--video so the v3 reset stays in force
   for every other context (no risk of reanimating a stray manifesto canvas
   or greetings section elsewhere on the page).
   Note: `all: revert !important` strips ALL cascade — including our wrap
   geometry. So we do NOT use `all: revert` here. Instead, we surgically
   flip only display + the specific properties we need to restore. */
.v4-sage--video.outreach-stage,
.v4-sage--video .outreach-video,
.v4-sage--video .outreach-overlay,
.v4-sage--video .outreach-stage .outreach-video,
.v4-sage--video .outreach-content {
    display: revert !important;
    visibility: visible !important;
    opacity: 1 !important;
}

.v4-sage--video.outreach-stage {
    position: relative !important;
}

.v4-sage--video .outreach-overlay {
    position: absolute !important;
    inset: 0 !important;
}

.v4-sage--video .v4-sage__inner {
    display: block !important;
}

/* Re-apply only the v4-relevant outreach-stage styling that we DO want.
   These are minimal reassurances to undo the v3 reset's `all: unset !important`.
   [v4-r9] Added margin-top: 8rem to give ~128px of breathing room between
   the end of gallery (white) and the start of the sage video (full-black).
   The margin is filled by body's white bg — reads as a deliberate 8rem
   canvas-on-white breath between two otherwise-abrupt sections (gallery
   ends with 12rem internal pad, +8rem margin = 20rem of total white space
   between gallery content's last line and sage video's first frame). */
.v4-sage--video.outreach-stage {
    position: relative;
    width: 100% !important;
    height: 100vh !important;
    background: #000000 !important;
    overflow: hidden;
    margin: 8rem 0 0 !important;
    padding: 0 !important;
}

/* ID-prefixed overrides of #outreach.outreach-stage { height: 150vh !important }
   and #outreach .outreach-video { width:100% !important; height:100% !important }
   from home-overrides-v4.css line 1828 + 1841. The ID-prefix lifts our
   specificity from 20 to 120 — defeats the 110 of the original rules. */
#outreach.v4-sage--video.outreach-stage {
    height: 100vh !important;
}

.v4-sage--video .outreach-video {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 100% !important;
    height: 100% !important;
    object-fit: cover !important;
    opacity: 1 !important;
    filter: brightness(0.45) !important;
    z-index: 10;
}

.v4-sage--video .outreach-overlay {
    position: absolute;
    inset: 0;
    background: radial-gradient(circle at 20% 50%, transparent 20%, rgba(0, 0, 0, 0.6) 100%) !important;
    display: flex !important;
    align-items: center !important;
    z-index: 100 !important;
    pointer-events: none !important;
}

/* The original outreach-stage styling in home-overrides-v4.css sets:
     #outreach.outreach-stage { height: 150vh; background: #000; overflow: hidden; }
     #outreach .outreach-video { position:absolute; cover-fit; filter: brightness(0.45); }
     .outreach-overlay { position:absolute; inset:0; radial vignette; display:flex; }
     .outreach-content { max-width: 650px; text-align: left; }
   We keep all of that and layer v4 sage content on top. Three additions:
     (a) Force .outreach-content's max-width to follow the text boundary,
         not its original 650px (so breakthrough text reaches the right edge).
     (b) Repaint the breakthrough text + pullquote + CTA with the canary + serif
         treatment v4 introduced, so they read as the sage-band voice not the
         original outreach voice.
     (c) Pull .v4-sage__inner out of the .outreach-content max-width constraint
         so the cycling eyebrow + breakthrough + pullquote + CTA all left-align
         to the text boundary, not nested inside a 650px column. */
.v4-sage--video .outreach-overlay {
    align-items: flex-start !important;
    display: block !important;
}

.v4-sage--video .v4-sage__inner {
    max-width: var(--v-site-max, 1120px) !important;
    width: 100% !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    box-sizing: border-box !important;
    text-align: left !important;
    pointer-events: auto;
    position: absolute !important;
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    height: 100vh !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    align-items: flex-start !important;
    z-index: 110 !important;
}

/* Override original outreach-content max-width:650px when v4 sage is active */
.v4-sage--video .outreach-content,
.v4-sage--video .v4-sage__inner {
    max-width: var(--v-site-max, 1120px) !important;
}

/* Sage band v4 text colours on the dark video bg */
.v4-sage--video .v4-sage-eyebrow {
    font-size: 1.05rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--v-accent-canary-light);
    margin-bottom: 1.5rem;
    max-width: 100%;
}

.v4-sage--video .v3-breakthrough {
    font-family: var(--v-font-sans);
    font-size: clamp(1.75rem, 3vw, 2.75rem);
    font-weight: 300;
    line-height: 1.25;
    letter-spacing: -1px;
    color: #ffffff;
    max-width: 720px;
    margin: 0 0 2.5rem !important;
    text-align: left !important;
    text-shadow: 0 4px 24px rgba(0, 0, 0, 0.55);
}

.v4-sage--video .v3-breakthrough strong {
    font-weight: 500;
    color: #ffffff;
}

.v4-sage--video .v4-pullquote {
    color: rgba(255, 255, 255, 0.85) !important;
    max-width: 540px;
    margin: 2rem 0 2.5rem !important;
    text-align: left !important;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}

.v4-sage--video .v4-pullquote cite {
    color: rgba(255, 255, 255, 0.65) !important;
}

.v4-sage--video .v3-breakthrough-cta {
    margin-top: 0;
    display: flex !important;
    flex-wrap: wrap;
    gap: 1.25rem 2rem;
    justify-content: flex-start !important;
    align-items: center !important;
}

.v4-sage--video .v3-btn-square-light {
    background: var(--v-text-on-dark, #F8F7F5);
    color: var(--v-bg-dark, #0A0A0A);
    border-color: var(--v-text-on-dark, #F8F7F5);
}

.v4-sage--video .v3-btn-square-light:hover {
    background: transparent;
    color: var(--v-text-on-dark, #F8F7F5);
    border-color: var(--v-text-on-dark, #F8F7F5);
}

/* Neutralize the v3-section-sage background so the video shows through. */
.v4-sage--video.v3-section-sage {
    background: #000000 !important;
}

/* ---- 4. Connect — drop the centered workaround, left-align to text boundary ---- */
/* Override home-overrides-v4.css's `#contact .section-inner { max-width: 940px !important; }`
   AND `.section-light { padding: 26rem 5% !important; }` AND `#contact .section-inner { width: auto !important; }`
   — all inherited by v4 connect. They were pushing the connect content into a
   centered 940px box. Override with the canonical 1120px wrap geometry,
   same as hero + capabilities + footer.
   Specificity game:
   - #contact .section-inner                                    = 110 + !important
   - #contact.v4-contact--dark .section-inner                   = 111 + !important (mine, wins)
   - #contact.v4-contact--dark .v4-contact__inner              = 120 + !important (mine, wins)
   - #contact.v4-contact--dark .section-inner.v3-wrap             = 112 + !important (mine, max)
*/
.v4-contact--dark,
#contact.v4-contact--dark {
    padding: 14rem 0 14rem !important;
}

#contact.v4-contact--dark .section-inner,
#contact.v4-contact--dark .section-inner.v3-wrap,
#contact.v4-contact--dark .v4-contact__inner,
.v4-contact--dark .v4-contact__inner,
.v4-contact--dark .section-inner.v3-wrap {
    width: 100% !important;
    max-width: var(--v-site-max, 1120px) !important;
    margin-left: auto !important;
    margin-right: auto !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    padding-left: var(--v-gutter, 5%) !important;
    padding-right: var(--v-gutter, 5%) !important;
    box-sizing: border-box !important;
    display: block !important;
    text-align: left !important;
}

.v4-contact--dark .v4-contact__eyebrow,
.v4-contact--dark .v4-contact__title,
.v4-contact--dark .v4-contact__subtitle,
.v4-contact--dark .v4-pullquote--on-dark {
    text-align: center !important;
    margin-left: auto !important;
    margin-right: auto !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
}

.v4-contact--dark .v4-contact__title {
    font-size: clamp(3rem, 6vw, 5rem);
    color: #ffffff !important;
    margin: 0.5rem auto 1.5rem !important;
}

.v4-contact--dark .v4-contact__subtitle {
    max-width: 560px;
    margin: 1rem auto 3rem !important;
    color: rgba(255, 255, 255, 0.85) !important;
    text-align: center !important;
}

.v4-contact--dark .v4-pullquote--on-dark {
    max-width: 540px;
    margin: 1rem auto 1.5rem !important;
    text-align: center !important;
}

.v4-contact--dark .v4-connect__cta {
    justify-content: center !important;
    flex-wrap: wrap;
    gap: 1rem;
    display: flex;
}

/* ---- 5. Announcement band — text + CTA centered (comments-12jul001 line 4) ---- */
.v4-band-announce .v3-wrap {
    max-width: var(--v-site-max, 1120px) !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center !important;
    text-align: center !important;
}

.v4-band-announce .v3-wrap>* {
    text-align: center !important;
}

/* ---- 6. Footer — bond Even grid to the 1120px text boundary ---- */
.v4-footer-mock .v3-wrap,
.v4-footer-mock .section-inner {
    max-width: var(--v-site-max, 1120px) !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    width: 100% !important;
}

.v4-footer-mock .v4-footer-grid {
    width: 100%;
    column-gap: 6rem;
    row-gap: 3rem;
}

.v4-footer-mock .v4-footer__bottom {
    width: 100%;
}

/* ---- 7. Bento — confirm bento spans the full wrap width (no overlap into gutter) ---- */
.v4-bento {
    width: 100%;
    max-width: 100%;
}

/* Cards + thesis already inherit 8px radius from the prior revision; nothing more to do here
   except confirm they fill the wrap. */

/* ---- 8. Aphorism — left-align to text boundary (already uses .section-inner.v3-wrap) ---- */
/* The wrap is already bonded by the rule in §1 above. The .v4-aphorism-text inherits its
   parent's padding so it sits at the text boundary left edge. Reaffirm max-width. */
.v4-aphorism .v4-aphorism-text {
    margin-left: 0;
    margin-right: 0;
    max-width: 720px;
}

/* ---- 9. Mobile override — footer still collapses + connect stays left-aligned ---- */
@media (max-width: 768px) {
    .v4-footer-mock .v4-footer-grid {
        grid-template-columns: 1fr;
        gap: 2rem;
    }

    .v4-footer-mock .v4-footer__bottom {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
    }

    .v4-footer-mock .v4-footer__legal {
        margin-top: 0.5rem;
    }

    /* Connect stays left-aligned on mobile (per the new policy) */
    .v4-contact--dark .v4-contact__inner {
        text-align: left !important;
    }

    /* Sage video shrinks gracefully */
    .v4-sage--video .v3-breakthrough {
        font-size: 1.5rem;
    }
}

/* ============================================================
   V4 COMMENTS-12JUL002 SUPERSESSION RULES (v4-r4) — corrected (r4-c1)
   ============================================================
   Original Q&A misread "sage" as the community section. User clarification:
   "sage" meant the APHORISM quote above community. The decisions below
   reflect that correction.
   1. Pullquotes: drop `"` curly glyphs + drop `— Lucan Leung` self-attribution.
      (HTML edits in index-v4.html — already done.)
   2. APHORISM text (the quote line above community): center-align within the
      1120px wrap, instead of left-aligned. This is what comments-12jul002 line
      5 meant by "the texts of the sage should be centrally aligned as well"
      — referring to the aphorism / quote block, NOT the community section.
   3. Sage stage height: 150vh → 100vh — keeps the height trim the user asked
      for (less vertical real estate per sage scroll). Video coverage FULL-BLEED
      (100% w/h object-fit: cover) — no dark space on sides.
   4. Community section text alignment: LEFT (v4-r3 state, NOT centered).
      Centering was a misread; revert.
   5. Connect section padding: 8rem → 14rem top/bot (doubles the breathing
      room so Connect sits as a deliberate CTA moment).
   6. 2nd sage band ("Until it becomes us.") REMOVED — user didn't request it.
      Although the original Q&A locked "add 2nd sage between", user-clarification
      flagged it as "out of nowhere, not instructed". Section + CSS removed.
   7. Sage CTA row: restored "Explore network initiatives" hairline text link
      beside the "Community & Philosophy" CTA button. Hairline styling below.
   8. Bento radius (8px) + button radius (40px hero pill / 8px chrome square):
      user reviewed, chose to keep current default. No change here.
   ============================================================ */

/* APHORISM text center-align (per user clarification of comments-12jul002 line 5) */
.v4-aphorism .v4-aphorism-text {
    margin-left: auto !important;
    margin-right: auto !important;
    text-align: center !important;
}

/* Sage "Explore network initiatives" hairline shortcut link.
   Sits beside the v3-btn-square-light CTA in the breakthrough-cta row.
   Even-style hairline (border-bottom 1px rgba, no border-radius), sizes
   with the body, canary-on-dark hover. Matches the original homepage link
   aesthetic you referenced (comments-12jul002.md line 7). */
.v4-sage-shortcut {
    display: inline-flex;
    align-items: center;
    font-family: var(--v-font-sans);
    font-size: 0.95rem;
    font-weight: 400;
    letter-spacing: 0.3px;
    color: rgba(255, 255, 255, 0.78);
    text-decoration: none;
    padding: 0.5rem 0.25rem 0.3rem;
    margin-left: 0.5rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.35);
    transition: color 0.25s ease, border-color 0.25s ease;
    text-transform: none;
}

.v4-sage-shortcut::after {
    content: ' \2197';
    font-size: 0.9em;
    opacity: 0.7;
    margin-left: 0.2rem;
}

/* Sage shortcut hover — flat base beige. The accent reads as warmth
   arriving on interaction, matching the family used across all other accent
   sites (eyebrows, bento hover, contact eyebrow). No decorative gradient. */
.v4-sage-shortcut:hover {
    color: var(--v-accent-canary, #E2C0A0);
    border-bottom-color: var(--v-accent-canary, #E2C0A0);
}

.v4-sage-shortcut:focus-visible {
    outline: 2px solid var(--v-accent-canary, #E2C0A0);
    outline-offset: 4px;
}

/* Mobile override — sage CTA stacks vertically on narrow viewports */
@media (max-width: 768px) {

    /* Center connect content on mobile too */
    .v4-contact--dark .v4-contact__inner {
        text-align: center !important;
    }

    /* Sage CTA row stacks vertically on narrow viewports */
    .v4-sage--video .v3-breakthrough-cta {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
    }

    .v4-sage-shortcut {
        margin-left: 0;
    }
}

/* ===================================================================
   V4-R6 — EDITORIAL CUSHIONS, GREETING, EXPANSIONS, PARALLAX
   Per comments-12jul003.md (5 corrections to v4-r5 cushions):
   1. Cushion #1 (hero → caps): CONVERTED to centrally-aligned
      scroll-revealed greeting sequence. White-grey canvas bg, lines
      fade in one-by-one as user scrolls. Copy: short Lucan intro
      in editorial register.
   2. Cushion #2 (caps → gallery): kept copy + CTA but VERTICALLY
      EXPANDED + bg swapped to charcoal #232323 (dark tonal inversion
      moment) + text inverted to light.
   3. Cushion #3 (gallery → community): kept text-only (no image —
      the frontier thesis stands alone). VERTICALLY EXPANDED for
      breathing room.
   4. Cushion #4 (community → connect): REPLACED the 2-col image-left/
      text-right layout (which broke on viewport width changes) with a
      FULL-BLEED bg image (Drawing-7.png, 1920×1080) + OFFSIDE SKEW
      OFFSET + SCROLL PARALLAX (bg pulls up on scroll-down, reverses
      on scroll-up; honors prefers-reduced-motion).
   5. Button roundness: tightened non-hero button radius (8px → 4px).
   =================================================================== */

/* ---------- 1. CUSHION BASE — shared by all 4 cushions ---------- */
.v4-editor-cushion {
    padding: 7rem 0;
    scroll-margin-top: var(--v-header-h);
    background: var(--v-bg-canvas);
    width: 100%;
    box-sizing: border-box;
}

/* Expanded vertical variant — for cushions #2 and #3 (comments-12jul003
   lines 2 + 3: "indulge much more breathing room and white space"). */
.v4-cushion--expanded {
    padding: 11rem 0;
}

/* Shorter variant — for cushion #4 synthesis restatement (revokes the
   14rem tall image-parallax version). Quiet pivot, not a major beat. */
.v4-cushion--short {
    padding: 8rem 0;
}

/* Dark charcoal variant — for cushion #2 (comments-12jul003 line 2:
   "either dark charcoal, or grey or dark grey from our colour palette").
   Uses #232323 (Even footer charcoal) — distinct from the pure-black
   hero above it and the canvas gallery below it. */
.v4-cushion--dark {
    background: var(--v-bg-charcoal);
}

.v4-cushion--dark .v4-tile-title,
.v4-cushion--dark .v4-tile-col {
    color: var(--v-text-on-dark);
}

/* Cushion #2 title — copper-beige gradient text, DRAMATIC variant. Earned
   because (a) it sits on the charcoal #232323 cushion where warm copper
   reads as glowing rather than washing out, and (b) it's a single
   declarative editorial title, not a repeated section header — so the
   gradient is a moment, not a system. Endpoints pulled wider in lightness
   so the gradient reads as gradient: cream-ivory start → deeper rosewood
   end, ~30% delta. Eyebrow above stays flat #E2C0A0 for hierarchy contrast. */
.v4-cushion--dark .v4-tile-title {
    background: linear-gradient(95deg,
            #F4E2C6 0%,
            #E2C0A0 38%,
            #C09D87 68%,
            #9D7860 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #E2C0A0;
}

.v4-cushion--dark .v4-tile-col {
    opacity: 0.72;
}

/* Bond the cushion's .section-inner to the canonical 1120px text boundary
   (extends the §1 rule above). Defeats any home-overrides-v4.css narrower
   sub-column rules that might bleed in.
   Cushion #4 EXEMPT — its .section-inner is the content node itself
   (.v4-cushion-image-content--right), and needs its own /margin/padding tuning. */
.v4-editor-cushion:not(.v4-cushion--image) .section-inner,
.v4-editor-cushion.v4-aphorism:not(.v4-cushion--image) .section-inner {
    max-width: var(--v-site-max, 1120px) !important;
    margin: 0 auto !important;
    padding: 0 var(--v-gutter, 5%) !important;
    width: 100% !important;
    box-sizing: border-box !important;
}

/* ---------- 2. CUSHION TILE TITLE (short, punchy section-statement — w700
                          declaration register to match caps' "What I do."
                          rather than sage's long w300 descriptive line.
                          Same weight as caps' .section-title; smaller size
                          because cushion is a side-statement, not the
                          section's hero title.) ---------- */
.v4-tile-title {
    font-family: var(--v-font-sans);
    font-weight: 700;
    font-size: clamp(2rem, 4vw, 2.75rem);
    line-height: 1.1;
    letter-spacing: -1.5px;
    color: var(--v-text-primary);
    margin: 0 0 2.5rem;
    max-width: 100%;
    text-align: left;
}

/* ---------- 3. CUSHION 2-COL DESCRIPTION GRID ---------- */
.v4-tile-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 4rem;
    row-gap: 1.5rem;
    margin: 0 0 2.5rem;
    max-width: 100%;
}

/* Cushion column body — w400 + 18px + normal tracking to match caps'
   .section-subtitle register (w400, ~20px, sentence case), not the
   previous w300/16px/−0.5px which read as caption-like footnote text. */
.v4-tile-col {
    font-family: var(--v-font-sans);
    font-weight: 400;
    font-size: 1.125rem;
    line-height: 1.7;
    letter-spacing: normal;
    color: var(--v-text-primary);
    margin: 0;

    opacity: 0.78;
}

/* ---------- 4. CUSHION CTA ---------- */
.v4-tile-cta {
    display: inline-block;
}

/* ---------- 5. CUSHION #1 — SCROLL GREETING SEQUENCE (comments-13jul001 #1) ----------
   One line visible at a time. As user scrolls DOWN, current line fades out +
   next line fades in. Scrolling UP reverses. Implemented via sticky container
   + per-line IntersectionObserver (JS §9 in home-engine-v4.js) that toggles
   .is-active on the line whose scroll-step is closest to viewport center.
   Each step is 100vh tall (one full viewport per line), so the user scrolls
   through the greeting line-by-line. Last line ("Welcome to the work.")
   enlarged to ~2.4× body size per user review. Background: pure white
   (drop canvas beige per comments-13jul001 #3 — beige doesn't match vibe). */
.v4-cushion--greet {
    background: #FFFFFF;
    padding: 0;
    text-align: center;
    overflow: visible !important;
    /* sticky needs visible overflow */
}

.v4-greet-viewport {
    /* One viewport per greeting step. 6 steps total → 600vh tall. */
    position: relative;
    height: 600vh;
}

.v4-greet-sticky {
    /* Sticks to top of viewport while the parent viewport scrolls past.
       Each line stacks absolutely inside this sticky box; only .is-active line
       is visible at a time. The `!important` here overrides
       home-overrides-v4.css line 60's `.section-inner { position: relative !important }`. */
    position: sticky !important;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 var(--v-gutter, 5%);
}

.v4-greet-line {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 var(--v-gutter, 5%);
    font-family: var(--v-font-sans);
    font-weight: 400;
    font-size: clamp(1.5rem, 3.5vw, 2.5rem);
    line-height: 1.3;
    letter-spacing: -0.6px;
    color: var(--v-text-primary);
    margin: 0;
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.5s var(--v-ease), transform 0.6s var(--v-ease);
    pointer-events: none;
}

.v4-greet-line.is-active {
    opacity: 1;
    transform: translateY(0);
}

/* Final hero line — enlarged ~2.4× per comments-13jul001 line 1. */
.v4-greet-line--hero {
    font-family: var(--v-font-serif);
    font-style: italic;
    font-weight: 400;
    font-size: clamp(3rem, 7vw, 6rem);
    letter-spacing: -1px;
}

/* Skip-to-work shortcut — Even-style hairline link pinned to the bottom of
   the greeting sticky box so it persists across every greeting step. Quiet
   chrome: small caps register, hairline border-bottom, base-beige hover
   (matches the locked copper-beige accent system + .v4-sage-shortcut grammar).
   Sits outside the layered .v4-greet-line stack (which are position:absolute)
   so the anchor occupies its own flex row below them — no overlap, always
   clickable. pointer-events auto guarantees it stays tappable even while
   the greet lines toggle pointer-events:none between steps. */
.v4-greet-skip {
    position: absolute;
    bottom: clamp(2rem, 6vh, 5rem);
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    font-family: var(--v-font-sans);
    font-size: 0.9rem;
    font-weight: 400;
    letter-spacing: 0.3px;
    color: rgba(10, 10, 10, 0.55);
    text-decoration: none;
    padding: 0.5rem 0.25rem 0.3rem;
    border-bottom: 1px solid rgba(10, 10, 10, 0.35);
    pointer-events: auto;
    background: none;
    cursor: pointer;
    transition: color 0.25s ease, border-color 0.25s ease;
    z-index: 3;
}

/* Pin the centering transform so any inherited transform cascade
   (e.g. future .fade-up re-add) cannot silently recenter this element. */
.v4-greet-skip,
.v4-greet-skip.visible {
    transform: translateX(-50%) !important;
}

.v4-greet-skip::after {
    content: ' \2193';
    font-size: 0.9em;
    opacity: 0.7;
    margin-left: 0.2rem;
}

.v4-greet-skip:hover,
.v4-greet-skip:focus-visible {
    color: var(--v-accent-canary-dark, #C09D87);
    border-bottom-color: var(--v-accent-canary-dark, #C09D87);
    outline: none;
}

.v4-greet-skip:focus-visible {
    outline: 2px solid var(--v-accent-canary, #E2C0A0);
    outline-offset: 4px;
}

/* Mobile override — slightly larger padding to clear the navbar / safe area */
@media (max-width: 768px) {
    .v4-greet-skip {
        bottom: clamp(1.5rem, 8vh, 4rem);
        font-size: 0.85rem;
    }
}

/* ---------- 6. CUSHION #4 — IMAGE PARALLAX TREATMENT ----------
   Per comments-13jul001.md line 5: text aligned RIGHT within 1120px boundary,
   height significantly increased (padding 14rem), parallax range ±80px.
   Skew offset kept (8% rightward bleed). Vignette weighted right for
   text legibility on the right side.
   Parallax math lives in JS (home-engine-v4.js §8) — sets --parallax-y
   as a CSS var; here we compose it into the transform alongside the skew. */
.v4-cushion--image.v4-cushion--parallax {
    position: relative;
    padding: 11rem 0;
    /* default expanded; overridden by --tall */
    overflow: hidden;
    background: var(--v-bg-dark);
    /* fallback if image fails to load */
}

.v4-cushion--tall {
    padding: 28rem 0 !important;
    /* taller than #2/#3 — gives parallax travel distance */
}

.v4-cushion-image-bg {
    position: absolute;
    inset: -5% -5%;
    /* 110% wide, 120% tall */
    background-size: cover;
    background-position: top, bottom, 50% 30%;
    background-repeat: no-repeat;
    /* Skew offset + parallax y-translation (set by JS scroll handler, now ±80px). */
    transform: translateX(-1%) translateY(var(--parallax-y, 0px));
    will-change: transform;
    z-index: 0;
}

.v4-cushion-image-vignette {
    position: absolute;
    inset: 0;
    /* Vignette weighted to the LEFT side (text moved left per user 14Jul). */
    background:
        linear-gradient(90deg,
            rgba(10, 10, 10, 0.85) 0%,
            rgba(10, 10, 10, 0.78) 30%,
            rgba(10, 10, 10, 0.45) 65%,
            rgba(10, 10, 10, 0.55) 100%);
    z-index: 1;
}

.v4-cushion-image-content {
    position: relative;
    z-index: 2;
}

/* Cushion #4 text-block nudge — push the text right + down WITHIN the centered
   1120px wrap (without disturbing the wrap's own centering).
   Cushion #4's .section-inner.v3-wrap node IS ALSO the content node, so we
   can't separate them via margins. Instead: keep the wrap centered at 1120px
   (via the §1 bond), and add padding-left + padding-top to this element to
   push the text origin right + down WITHIN the wrap's content box.
   Specificity (.v4-editor-cushion .v4-cushion--image .section-inner.v3-wrap
   .v4-cushion-image-content--right = 0,0,5,0 + !important) out-ranks the §1
   bond (0,0,2,0 + !important) at line 1365 — but we ONLY override the
   properties we mean to (padding), NOT margin/width/max-width, so the wrap
   stays centered + 1120px. */
.v4-editor-cushion.v4-cushion--image .section-inner.v3-wrap.v4-cushion-image-content--right {
    padding-left: 560px !important;
    padding-top: 12rem !important;
    padding-right: 0 !important;
    padding-bottom: 0 !important;
    text-align: left;
}

.v4-cushion-image-content--right .v4-cushion-image-title {
    color: #232323;
    font-size: clamp(2rem, 4vw, 2.75rem);
    margin-bottom: 1.5rem;
    max-width: 540px;
}

.v4-cushion-image-content--right .v4-cushion-image-caption {
    color: rgba(35, 35, 35, 0.82);
    max-width: 460px;
}

.v4-cushion-image-content--right .v4-cushion-label {
    color: rgba(35, 35, 35, 0.7);
}

/* ---------- 6a. CUSHION LABEL (comments-13jul001 #4) ---------- */
/* Short 2-5 word sentence above each cushion editorial title. Small caps
   treatment matching existing section eyebrows (.small-caps + .v4-small-caps
   tokens) but lighter weight + lower opacity so it reads as a quiet prefix. */
.v4-cushion-label {
    font-family: var(--v-font-sans);
    font-size: 1.5rem;
    font-weight: 500;
    letter-spacing: 0.1px;
    text-transform: none;
    color: var(--v-text-muted-d, #919191);
    margin: 0 0 1.25rem;
    line-height: 1;
}

.v4-cushion--dark .v4-cushion-label {
    color: rgba(248, 247, 245, 0.7);
}

/* ---------- 7. BUTTON RADIUS TIGHTENED (comments-12jul003 #5) ---------- */
/* Non-hero button corner radius: 8px → 4px. A touch less round, per user
   review. Applied to .v3-btn-square-light (used in cushions + sage CTA + band
   CTA) and .v4-btn-light (connect CTAs). Hero pill buttons (.v3-btn-pill-*)
   keep their 40px — only the chrome buttons below the hero change. */
.v3-btn-square-light,
.v4-btn-light,
.v3-btn-square-yellow,
.v4-btn-yellow {
    border-radius: 4px !important;
}

/* ---------- 8. MOBILE OVERRIDES ---------- */
@media (max-width: 768px) {
    .v4-editor-cushion {
        padding: 4rem 0;
    }

    .v4-cushion--expanded {
        padding: 6rem 0;
    }

    .v4-cushion--greet {
        padding: 5rem 0;
    }

    #read-more .section-inner>.section-title,
    #gallery .section-inner>.section-title {
        font-size: 2rem !important;
        margin-bottom: 1.5rem;
    }

    .v4-tile-title {
        font-size: 1.75rem;
        margin-bottom: 1.5rem;
    }

    .v4-tile-grid {
        grid-template-columns: 1fr;
        column-gap: 0;
        row-gap: 1rem;
        margin-bottom: 1.5rem;
    }

    /* Cushion #4 image: drop skew on mobile so image fills full-bleed cleanly. */
    .v4-cushion-image-bg {
        transform: translateX(0) translateY(var(--parallax-y, 0px));
        inset: 0;
        /* center the bg, no overflow */
    }

    /* Mobile greeting sequence — smaller line size, full viewport still per step. */
    .v4-greet-viewport {
        height: 600vh;
        /* unchanged — keeps 6 viewport steps */
    }

    .v4-greet-line {
        font-size: 1.375rem;
    }

    .v4-greet-line--hero {
        font-size: 2.75rem;
    }
}

/* ---------- 9. RESPECT REDUCED MOTION ---------- */
@media (prefers-reduced-motion: reduce) {

    /* Parallax CSS variable sits at 0 when global reduced-motion is set
       (JS handles the gate, but pin it in CSS too as a belt-and-braces). */
    .v4-cushion-image-bg {
        transform: translateX(8%) translateY(0) !important;
    }
}

/* ---------- [v4-r22] NAVBAR SECTION-ADAPTIVE THEME ----------
   The navbar text color flips based on the section it currently
   overlaps. JS at home-engine-v4.js §7b toggles data-theme="dark"
   or data-theme="light" on the .navbar element based on which
   section's bounding rect is currently intersecting the navbar's
   top area.

   Theme map:
     data-theme="dark"  → navbar text is dark charcoal (#1d1d1f)
                          Used over LIGHT sections: hero (light image),
                          greeting cushion (white), intro bento (#fff),
                          gallery (light), footer (light).
     data-theme="light" → navbar text is cream/off-white (#F8F7F5)
                          Used over DARK sections: cushion #2 dark,
                          sage video, dark connect, announcement band.

   Selector specificity: [data-theme="dark"] (0,1,0,0) > .navbar (0,0,1,0),
   so these override global-v3.css:87's `color: var(--text-light)`.

   Note: the about-page approach at css/about-page.css:4-11 uses a
   simple .navbar.scrolled class toggle. We're using data-theme
   here because the homepage has multiple light↔dark↔light transitions
   (not just one scroll-past), so a single scrolled toggle wouldn't
   handle the back-and-forth cleanly.
   ----------------------------------------------------------------------- */
.navbar[data-theme="dark"] {
    color: #1d1d1f;
}

.navbar[data-theme="light"] {
    color: #F8F7F5;
}

/* Once the navbar collapses to the centered pill (.scrolled), lock it
   to the light theme for the rest of the scroll — regardless of which
   section passes under it. The pill sits on rgba(128,128,128,0.25) grey
   glass (global-v3.css:108) which reads better with cream/off-white text. */
.navbar.scrolled {
    color: #F8F7F5 !important;
}