/* ==================================================================
   home.css — v4 homepage redesign
   Scoped under body.home-v4. Other pages untouched.
   Reference aesthetic: very dark, big bold sans, restrained accents,
   starfield ambient texture, centered pill nav, structural card grids.
   ================================================================== */

body.home-v4 {
    background: var(--bg);
    overflow-x: clip;
}

/* Hide v3 chrome we're not using anymore */
body.home-v4 > .scroll-progress { display: none; }

/* ==================================================================
   INSTRUMENTED BACKGROUND
   ==================================================================

   Replaces the previous starfield. Layers:
     1. A faint white dot grid (22px pitch) — the page's "instrumented"
        feel. Subtle radial mask fades it near the edges so it doesn't
        crowd the corners.
     2. An ignition layer where signature.js drops short-lived red dots
        on random grid cells (1–3 every ~1–3 seconds). Each ignition
        flashes and fades.
     3. A rare, slow horizontal "scan" — a thin band of red light
        traverses the viewport every 25–45 s. Easy to miss; that's the
        point. Like an oscilloscope or radar sweep in the periphery.
     4. Two extremely faint warm radials off-screen suggesting light
        direction without becoming a nebula gradient.
*/

.h-bg {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    /* Transparent — body bg shows through, and the JS dot-grid canvas
       (inserted as first child of body, z:0) renders behind this layer.
       Only the corner warmth (::before), scan line, and ignites paint on
       top of the grid now. */
    background: transparent;
}

/* Old static CSS dot grid + drifting fog blobs + neural mesh — all
   replaced by the interactive JS dot-grid (#dot-grid) with cursor
   gravity-well. Kept selectors so the HTML doesn't 404 on missing
   classes, but suppressed visually. */
.h-bg-grid,
.h-bg-fog,
.h-bg-mesh { display: none !important; }

/* Faint off-screen warmth — replaces the previous bright "nebula" blobs
   that were too generic. These are 8% accent at most and feathered over
   half the viewport, so they read as light direction, not as colour. */
.h-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse 80% 60% at 80% -10%,
            color-mix(in oklab, var(--accent) 8%, transparent),
            transparent 55%),
        radial-gradient(ellipse 70% 50% at 10% 110%,
            color-mix(in oklab, var(--accent) 5%, transparent),
            transparent 55%);
}

/* The dot grid. 22px pitch, ~0.8px dots, low alpha. Radially masked so
   it concentrates toward the centre of the viewport. */
.h-bg-grid {
    position: absolute;
    inset: 0;
    background-image:
        radial-gradient(circle, rgba(255, 255, 255, 0.13) 0.7px, transparent 1.1px);
    background-size: 22px 22px;
    /* Soft vignette mask — dots fade near the edges so they don't compete
       with content at the periphery. */
    -webkit-mask-image: radial-gradient(ellipse 110% 85% at 50% 45%, #000 50%, transparent 100%);
            mask-image: radial-gradient(ellipse 110% 85% at 50% 45%, #000 50%, transparent 100%);
}

.h-bg-ignite-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* Each ignition is a tiny red dot dropped at a grid intersection by
   signature.js. The CSS keyframe handles the flash + fade. */
.h-bg-ignite {
    position: absolute;
    width: 3.5px;
    height: 3.5px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow:
        0 0 4px var(--accent),
        0 0 12px color-mix(in oklab, var(--accent) 60%, transparent),
        0 0 28px color-mix(in oklab, var(--accent) 30%, transparent);
    transform: translate(-50%, -50%) scale(0);
    opacity: 0;
    animation: h-bg-ignite-anim 1.4s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}

@keyframes h-bg-ignite-anim {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(0); }
    20%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
}

/* Heartbeat ignite — used by idle mode at the centre of the viewport.
   Larger ring + a slow ripple so it reads as the site's pulse, not
   just another random ignition. */
.h-bg-ignite.is-heartbeat {
    width: 6px;
    height: 6px;
    box-shadow:
        0 0 6px var(--accent),
        0 0 22px color-mix(in oklab, var(--accent) 55%, transparent),
        0 0 48px color-mix(in oklab, var(--accent) 25%, transparent);
    animation: h-bg-heartbeat-anim 1.8s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}

@keyframes h-bg-heartbeat-anim {
    0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0); }
    18%  { opacity: 0.95; transform: translate(-50%, -50%) scale(1.15); }
    45%  { opacity: 0.75; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0;    transform: translate(-50%, -50%) scale(3.4); }
}

/* The scan-line band. Lives above the dot grid, rides from top of
   viewport to bottom on each run. signature.js toggles .is-running on
   it at a randomised interval (25–45 s). */
.h-bg-scan {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 90px;
    pointer-events: none;
    background: linear-gradient(180deg,
        transparent 0%,
        color-mix(in oklab, var(--accent) 6%, transparent) 60%,
        color-mix(in oklab, var(--accent) 18%, transparent) 95%,
        color-mix(in oklab, var(--accent) 4%, transparent) 99%,
        transparent 100%);
    opacity: 0;
    transform: translateY(-120px);
}

.h-bg-scan.is-running {
    animation: h-bg-scan-anim 4.5s cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

@keyframes h-bg-scan-anim {
    0%   { transform: translateY(-120px); opacity: 0; }
    8%   { opacity: 1; }
    92%  { opacity: 1; }
    100% { transform: translateY(100vh);   opacity: 0; }
}

/* ==================================================================
   FOG & NEURAL MESH
   ================================================================== */
.h-bg-fog {
    position: absolute;
    pointer-events: none;
    border-radius: 50%;
    filter: blur(100px);
    will-change: transform;
    opacity: 0.04;
    background: var(--accent);
}
.h-bg-fog-1 {
    width: 60vw; height: 60vh;
    top: -10vh; left: -10vw;
    animation: h-fog-drift-1 80s linear infinite alternate;
}
.h-bg-fog-2 {
    width: 50vw; height: 50vh;
    bottom: -10vh; right: -10vw;
    animation: h-fog-drift-2 90s linear infinite alternate;
}
.h-bg-fog-3 {
    width: 40vw; height: 40vh;
    top: 30vh; left: 30vw;
    animation: h-fog-drift-3 70s linear infinite alternate;
}

@keyframes h-fog-drift-1 {
    0% { transform: translate(0, 0) scale(1); }
    100% { transform: translate(15vw, 15vh) scale(1.1); }
}
@keyframes h-fog-drift-2 {
    0% { transform: translate(0, 0) scale(1.1); }
    100% { transform: translate(-10vw, -20vh) scale(1); }
}
@keyframes h-fog-drift-3 {
    0% { transform: translate(0, 0) scale(1); }
    100% { transform: translate(-15vw, 10vh) scale(1.2); }
}

.h-bg-mesh {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

/* ==================================================================
   NAV — clean horizontal bar (Antigravity-style)
   ==================================================================
   Full-width sticky bar, logo on left, links grouped beside it,
   actions on the right. No floating pill, no backdrop blur, no
   tracked-out mono caps — just sentence-case sans and quiet hovers. */

body.home-v4 .nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding: 18px 32px;
    pointer-events: none;
    background: none !important;
}

body.home-v4 .nav > * { pointer-events: auto; }

body.home-v4 .nav-inner {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    padding: 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
}

body.home-v4 .nav-mark {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 6px 12px 6px 4px;
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -0.005em;
    text-transform: lowercase;
    color: var(--fg);
}

body.home-v4 .nav-mark .nav-mark-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 8px var(--accent);
    animation: none;
}

body.home-v4 .nav-mark span:last-child { color: inherit; }
body.home-v4 .nav-mark span span { color: var(--accent) !important; }

body.home-v4 .nav-links {
    background: none;
    border: none;
    border-left: none;
    padding: 0;
    margin: 0;
    margin-left: 8px;
    list-style: none;
    gap: 2px;
    display: inline-flex;
    align-items: center;
}

body.home-v4 .nav-links li { list-style: none; }

body.home-v4 .nav-link {
    padding: 8px 14px;
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--fg-2);
    border-radius: 8px;
    transition: color 0.2s var(--ease), background 0.2s var(--ease);
}

body.home-v4 .nav-link:hover {
    color: var(--fg);
    background: color-mix(in oklab, var(--fg) 6%, transparent);
}
body.home-v4 .nav-link[aria-current="page"] {
    color: var(--fg);
    background: color-mix(in oklab, var(--fg) 8%, transparent);
}

/* Actions cluster — anchored top-right, flush with the nav baseline.
   Icon buttons lose their pill chrome and read as ghost glyphs; the
   Contact button keeps the accent pill as the clear primary CTA. */
body.home-v4 .nav-actions {
    position: fixed;
    top: 16px;
    right: 28px;
    display: flex;
    align-items: center;
    gap: 4px;
    z-index: 101;
}

body.home-v4 .nav-btn {
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 1px solid transparent;
    border-radius: 10px;
    height: 38px;
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--fg-2);
    transition: color 0.2s var(--ease), background 0.2s var(--ease), border-color 0.2s var(--ease);
}

body.home-v4 .nav-btn:hover {
    color: var(--fg);
    background: color-mix(in oklab, var(--fg) 6%, transparent);
    border-color: transparent;
    transform: none;
}

body.home-v4 .nav-btn-icon { width: 38px; padding: 0; }

body.home-v4 #contact-btn {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    padding: 0 18px;
    border-radius: 999px;
    margin-left: 4px;
    font-weight: 600;
}
body.home-v4 #contact-btn:hover {
    background: color-mix(in srgb, var(--accent) 90%, white);
    border-color: color-mix(in srgb, var(--accent) 90%, white);
    color: #fff;
}

@media (max-width: 820px) {
    body.home-v4 .nav { padding: 12px 16px; }
    body.home-v4 .nav-actions { right: 12px; top: 12px; }
    body.home-v4 .nav-inner { gap: 6px; }
    body.home-v4 .nav-links { margin-left: 4px; }
}

@media (max-width: 640px) {
    body.home-v4 .nav-link { padding: 6px 10px; font-size: 13px; }
    body.home-v4 .nav-btn .nav-btn-label { display: none; }
    body.home-v4 .nav-mark { font-size: 14px; }
}

/* ==================================================================
   COMMON TYPOGRAPHY
   ================================================================== */

body.home-v4 main { position: relative; z-index: 2; }

.h-shell {
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 32px;
    position: relative;
}

/* Eyebrow pill — small uppercase label that floats above each section */
.h-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 6px 14px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    background: rgba(12, 12, 16, 0.6);
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #8a8a94;
}

.h-eyebrow::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent);
}

/* Display heading — huge bold uppercase, optional gradient fade on a second line.
   Uses Cabinet Grotesk for its flat-sided characterful forms. */
.h-display {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(2.6rem, 8.5vw, 7.5rem);
    line-height: 0.95;
    letter-spacing: -0.04em;
    text-transform: uppercase;
    color: #ffffff;
    margin-top: 24px;
}

.h-display-fade {
    background: linear-gradient(180deg,
        #ffffff 0%,
        #d6d6dc 35%,
        color-mix(in oklab, var(--accent) 55%, #2a1a1c) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.h-display .dot {
    color: var(--accent);
    -webkit-text-fill-color: var(--accent);
}

/* Section sub-deck — short paragraph under display heading */
.h-deck {
    margin-top: 22px;
    color: #8a8a94;
    font-size: 15.5px;
    line-height: 1.6;
    max-width: 520px;
}

/* Center variant — used in hero + architecture intro */
.h-center { text-align: center; }
.h-center .h-deck { margin-left: auto; margin-right: auto; }

/* ==================================================================
   HERO
   ================================================================== */

body.home-v4 .hero {
    min-height: 100svh;
    /* Vertical padding clears the fixed nav at the top and the scroll cue
       at the bottom so centred content never crowds them. */
    padding: 92px 24px 76px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    overflow: visible;
    background: none;
    view-transition-name: none;
}

body.home-v4 .hero-bg { display: none; }

.h-hero-eyebrow {
    margin-bottom: 28px;
}

.h-hero-title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(3rem, 12vw, 10.5rem);
    line-height: 0.92;
    letter-spacing: -0.045em;
    text-transform: uppercase;
    color: #ffffff;
    margin: 0;
    max-width: 1100px;
}

.h-hero-title span { display: block; }

/* "quiet" is set in Gambarino italic — characterful editorial accent that
   pulls the eye to the word that defines the practice. Same colour as the
   surrounding text by default; the italic alone carries the meaning. */
.h-hero-title em,
.h-hero-title .em-italic {
    font-family: var(--font-italic);
    font-style: italic;
    font-weight: 400;
    /* Italics in Gambarino are narrower than Cabinet's caps, so nudge the
       letter-spacing wider to compensate for the optical density change. */
    letter-spacing: -0.01em;
    text-transform: none;
    /* Slight optical lift — italics naturally sit a hair below caps. */
    display: inline-block;
    transform: translateY(-0.02em);
    padding-right: 0.04em;
}

.h-hero-title .ln2 {
    background: linear-gradient(180deg,
        #ffffff 0%,
        #c8c8d0 30%,
        color-mix(in oklab, var(--accent) 60%, #2c1a1c) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.h-hero-deck {
    margin: 14px auto 0;
    max-width: 540px;
    color: #8a8a94;
    font-size: 15.5px;
    line-height: 1.6;
}

.h-hero-cta {
    display: inline-flex;
    gap: 10px;
    margin-top: 28px;
    flex-wrap: wrap;
    justify-content: center;
}

.h-btn {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    height: 48px;
    padding: 0 24px;
    border-radius: 999px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    transition: transform 0.2s var(--ease), background 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
    border: 1px solid transparent;
    cursor: pointer;
}

.h-btn-primary {
    background: #ffffff;
    color: #06060a;
}

.h-btn-primary:hover {
    background: var(--accent);
    color: #ffffff;
    transform: translateY(-1px);
}

.h-btn-ghost {
    background: rgba(255, 255, 255, 0.03);
    color: #c8c8d0;
    border-color: rgba(255, 255, 255, 0.1);
}

.h-btn-ghost:hover {
    color: #fff;
    border-color: rgba(255, 255, 255, 0.22);
    transform: translateY(-1px);
}

.h-btn .arr { transition: transform 0.25s var(--ease); }
.h-btn:hover .arr { transform: translate(2px, -2px); }

/* Hero scroll cue — small, anchored at bottom.
   Stack the line ABOVE the "SCROLL" word so they share the same vertical
   centreline. The base style.css uses flex-row (line beside text) which
   makes the cue read as offset from page centre — overriding to column
   here puts both elements on the same axis under the CTA buttons.
   .hero-scroll is position:absolute with left:50% transform:translateX(-50%)
   for centring; we use a dedicated rise keyframe (h-fade-up-scroll) below
   so the animation doesn't wipe out that X-translation. */
body.home-v4 .hero-scroll {
    bottom: 36px;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.22em;
    color: #5a5a64;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    /* Initial state for the rise — composite translate so X centring survives. */
    transform: translate(-50%, 14px);
    animation: h-fade-up-scroll 0.9s var(--ease) 1.6s forwards;
}

@keyframes h-fade-up-scroll {
    to { opacity: 1; transform: translate(-50%, 0); }
}

/* ==================================================================
   SECTION SHELL
   ================================================================== */

.h-section {
    padding: 120px 32px 80px;  /* top X bottom — 80px bottom gives section
                                   dividers (which jut UP -60px into space
                                   above each section) clearance from the
                                   previous section's content. */
    max-width: 1240px;
    margin: 0 auto;
    position: relative;
}

.h-section:last-of-type { padding-bottom: 60px; }

.h-section-head {
    text-align: center;
    margin-bottom: 64px;
}

@media (max-width: 720px) {
    .h-section { padding: 80px 20px 0; }
    .h-section-head { margin-bottom: 44px; }
}

/* ==================================================================
   ARCHITECTURE — 2x2 feature card grid
   ================================================================== */

.h-arch {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

.h-arch-card {
    position: relative;
    /* Matte obsidian: warm-neutral very dark surface + a 1px inner top
       highlight that reads as ambient light from above (NOT a drop shadow,
       NOT a gradient — restraint is the point). The faint warm shift from
       pure black makes the surface feel like material rather than ink. */
    background: var(--obsidian);
    border: 1px solid var(--line);
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(255, 255, 255, 0.02);
    border-radius: 22px;
    padding: 32px 32px 36px;
    min-height: 280px;
    display: flex;
    flex-direction: column;
    gap: 24px;
    overflow: hidden;
    transition: border-color 0.3s var(--ease), transform 0.3s var(--ease), background 0.3s var(--ease);
}

.h-arch-card::before {
    /* Removed the soft red corner glow — it was an "AI slop" gradient.
       Replaced with a hair-thin diagonal bevel highlight that catches the
       eye on hover without ever looking like a tinted blob. */
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg,
        transparent 0%,
        transparent 65%,
        rgba(255, 255, 255, 0.02) 100%);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.4s var(--ease);
}

.h-arch-card:hover {
    border-color: rgba(255, 255, 255, 0.14);
    background: var(--obsidian-2);
}

.h-arch-card:hover::before { opacity: 1; }

.h-arch-icon {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: rgba(255, 77, 61, 0.1);
    border: 1px solid rgba(255, 77, 61, 0.22);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    flex: none;
}

.h-arch-card h3 {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #ffffff;
    margin: 0 0 10px;
    line-height: 1.1;
}

.h-arch-card p {
    color: #8a8a94;
    font-size: 14.5px;
    line-height: 1.55;
    max-width: 380px;
    margin: 0;
}

.h-arch-meta {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #5a5a64;
    margin-top: auto;
    padding-top: 18px;
}

@media (max-width: 820px) {
    .h-arch { grid-template-columns: 1fr; }
    .h-arch-card { min-height: 220px; padding: 26px 26px 28px; }
}

/* ==================================================================
   PROJECTS — restyled cards
   ================================================================== */

.h-projects {
    display: grid;
    gap: 14px;
}

body.home-v4 .project-card {
    /* Matte obsidian surface — same vocabulary as architecture cards. */
    background: var(--obsidian);
    border: 1px solid var(--line);
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(255, 255, 255, 0.02);
    border-radius: 22px;
    grid-template-columns: 1.05fr 1fr;
    overflow: hidden;
    transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}

body.home-v4 .project-card:hover {
    border-color: var(--line-2);
    background: var(--obsidian-2);
    transform: none;
}

body.home-v4 .project-card-feature {
    /* Feature card: same obsidian base but with a hair more accent in the
       border — no inner red gradient (that was slop). */
    background: var(--obsidian);
    border-color: color-mix(in oklab, var(--accent) 22%, var(--line));
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        0 0 0 1px color-mix(in oklab, var(--accent) 8%, transparent);
}

body.home-v4 .project-card-feature:hover {
    border-color: color-mix(in oklab, var(--accent) 36%, var(--line-2));
}

body.home-v4 .project-card-body {
    padding: 40px 40px 32px;
    gap: 24px;
}

body.home-v4 .project-card-num {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #6a6a72;
    margin-bottom: 18px;
}

body.home-v4 .project-card-title {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 2.2vw, 1.95rem);
    font-weight: 700;
    letter-spacing: -0.025em;
    line-height: 1.05;
    text-transform: none;
    color: #ffffff;
    margin: 0 0 14px;
}

body.home-v4 .project-card-title em {
    font-family: var(--font-sans);
    font-style: normal;
    color: var(--accent);
}

body.home-v4 .project-card-desc {
    color: #8a8a94;
    font-size: 14px;
    line-height: 1.65;
}

body.home-v4 .tag {
    font-family: var(--font-mono);
    font-size: 10.5px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: #c8c8d0;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

body.home-v4 .tag-accent {
    background: rgba(255, 77, 61, 0.1);
    border-color: rgba(255, 77, 61, 0.32);
    color: var(--accent);
}

body.home-v4 .project-card-foot {
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    padding-top: 22px;
    margin-top: 22px;
}

body.home-v4 .project-card-foot-label {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #6a6a72;
}

body.home-v4 .project-card-foot-cta {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #ffffff;
}

body.home-v4 .project-card-media {
    border-left: 1px solid rgba(255, 255, 255, 0.05);
    aspect-ratio: 16 / 11;
}

@media (max-width: 820px) {
    body.home-v4 .project-card-body { padding: 28px 26px 24px; }
    body.home-v4 .project-card-media { border-left: none; border-top: 1px solid rgba(255, 255, 255, 0.05); }
}

/* ------------------------------------------------------------------
   Scroll-driven scale-up for project cards (Antigravity-style).
   Each card starts smaller / dimmer / slightly blurred when it
   enters the viewport from the bottom, and reaches full size +
   crispness as it crosses ~35% into the viewport.
   Native animation-timeline is Chrome/Edge-only — we feature-detect
   so unsupported browsers keep the existing .h-reveal-stagger.
   ------------------------------------------------------------------ */
@supports (animation-timeline: view()) {
    body.home-v4 .h-projects > .project-card {
        opacity: 1;
        filter: none;
        transform-origin: center 70%;
        animation: h-card-scroll-zoom linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 38%;
        will-change: transform, opacity, filter;
    }
    /* Disable the stagger reveal for cards once scroll-driven anim takes over */
    body.home-v4 .h-projects.h-reveal-stagger > .project-card,
    body.home-v4 .h-projects.h-reveal-stagger.is-in > .project-card {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

@keyframes h-card-scroll-zoom {
    from {
        transform: scale(0.78) translateY(40px);
        opacity: 0.35;
        filter: blur(6px);
    }
    to {
        transform: scale(1) translateY(0);
        opacity: 1;
        filter: blur(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    @supports (animation-timeline: view()) {
        body.home-v4 .h-projects > .project-card {
            animation: none;
            transform: none;
            opacity: 1;
            filter: none;
        }
    }
}

/* ==================================================================
   ROADMAP — 3-card row
   ================================================================== */

.h-roadmap {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
}

.h-road-card {
    position: relative;
    /* Matte obsidian */
    background: var(--obsidian);
    border: 1px solid var(--line);
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(255, 255, 255, 0.02);
    border-radius: 22px;
    padding: 28px 28px 30px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 200px;
    transition: border-color 0.3s var(--ease), background 0.3s var(--ease);
}

.h-road-card:hover { border-color: var(--line-2); background: var(--obsidian-2); }

.h-road-card-tag {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #6a6a72;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.h-road-card-tag::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: #5a5a64;
}

.h-road-card[data-status="shipped"] .h-road-card-tag { color: var(--accent); }
.h-road-card[data-status="shipped"] .h-road-card-tag::before {
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent);
}

.h-road-card-title {
    font-family: var(--font-display);
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #fff;
    margin-top: 4px;
    line-height: 1.15;
}

.h-road-card-desc {
    color: #8a8a94;
    font-size: 13.5px;
    line-height: 1.55;
    margin-top: auto;
}

@media (max-width: 820px) {
    .h-roadmap { grid-template-columns: 1fr; }
}

/* ==================================================================
   NOW STRIP — compact horizontal row (replaces the heavy v3 "Now")
   ================================================================== */

.h-now-strip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px;
    /* Hairline grid lines via background + 1px gap. */
    background: var(--line);
    border: 1px solid var(--line);
    box-shadow: inset 0 1px 0 var(--inner-hi);
    border-radius: 18px;
    overflow: hidden;
    margin-top: 32px;
}

.h-now-cell {
    background: var(--obsidian);
    padding: 20px 24px 22px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: background 0.3s var(--ease);
}

.h-now-cell:hover { background: var(--obsidian-2); }

.h-now-label {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #5a5a64;
    display: flex;
    align-items: center;
    gap: 8px;
}

.h-now-label::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent);
}

/* The single chromatic anomaly on the page — sodium-lamp yellow used
   exactly once, on the "open for paid work" status pill. One yellow dot
   in a field of red and obsidian becomes a brand signature. */
.h-now-cell.is-status-open .h-now-label { color: var(--sodium); }
.h-now-cell.is-status-open .h-now-label::before {
    background: var(--sodium);
    box-shadow:
        0 0 6px var(--sodium),
        0 0 14px color-mix(in oklab, var(--sodium) 40%, transparent);
    animation: h-status-pulse 2.4s ease-in-out infinite;
}

@keyframes h-status-pulse {
    0%, 100% { box-shadow: 0 0 6px var(--sodium), 0 0 14px color-mix(in oklab, var(--sodium) 30%, transparent); }
    50%      { box-shadow: 0 0 10px var(--sodium), 0 0 24px color-mix(in oklab, var(--sodium) 55%, transparent); }
}

.h-now-value {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 700;
    color: #fff;
    letter-spacing: -0.01em;
}

.h-now-meta {
    font-family: var(--font-mono);
    font-size: 11px;
    color: #6a6a72;
}

/* Music cell (inherits .now-cell-music behavior from v3 JS) */
.h-now-cell.now-cell-music { cursor: pointer; padding-bottom: 22px; position: relative; }

@media (max-width: 720px) {
    .h-now-strip { grid-template-columns: 1fr; }
}

/* ==================================================================
   CONTACT BAND
   ================================================================== */

.h-contact {
    text-align: center;
    padding: 140px 24px 80px;
}

.h-contact-options {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    max-width: 720px;
    margin: 56px auto 0;
}

.h-contact-card {
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 22px 26px;
    /* Matte obsidian */
    background: var(--obsidian);
    border: 1px solid var(--line);
    box-shadow: inset 0 1px 0 var(--inner-hi);
    border-radius: 18px;
    text-align: left;
    color: #ffffff;
    cursor: pointer;
    transition: border-color 0.25s var(--ease), background 0.25s var(--ease), transform 0.25s var(--ease);
    text-decoration: none;
    font-family: inherit;
}

.h-contact-card:hover {
    border-color: color-mix(in oklab, var(--accent) 36%, var(--line-2));
    background: var(--obsidian-2);
    transform: translateY(-2px);
}

.h-contact-card-icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
}

.h-contact-card-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
}

.h-contact-card-label {
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 600;
    color: #fff;
}

.h-contact-card-meta {
    font-family: var(--font-mono);
    font-size: 11px;
    color: #8a8a94;
    letter-spacing: 0.04em;
}

.h-contact-card-arr {
    color: #5a5a64;
    transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}

.h-contact-card:hover .h-contact-card-arr {
    color: var(--accent);
    transform: translate(3px, -3px);
}

@media (max-width: 640px) {
    .h-contact-options { grid-template-columns: 1fr; }
}

/* ==================================================================
   CONTACT TERMINAL — interactive command bar
   ==================================================================

   A real-feel mini terminal. Type a command, get a response. Discoverable
   commands: hi, help, book, work, discord, telegram, about, sudo, clear,
   matrix, whoami, uptime. Each command is plain text — no JS framework,
   no over-engineered scrollback. Just an input, a screen, and a tiny
   interpreter that returns lines.
*/

.h-terminal {
    max-width: 720px;
    margin: 48px auto 0;
    /* Matte obsidian, slightly warmer than cards so the terminal reads as
       the focal element of the section. */
    background: #0c0b0e;
    border: 1px solid var(--line-2);
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        0 30px 80px -40px rgba(0, 0, 0, 0.9),
        0 0 0 1px rgba(255, 255, 255, 0.01);
    border-radius: 14px;
    overflow: hidden;
    text-align: left;
    font-family: var(--font-mono);
    cursor: text;
    /* Tiny CRT-ish horizontal scanline texture — extremely faint. */
    background-image:
        repeating-linear-gradient(180deg,
            transparent 0px,
            transparent 3px,
            rgba(255, 255, 255, 0.012) 3px,
            rgba(255, 255, 255, 0.012) 4px),
        none;
}

.h-terminal-chrome {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 10px 14px;
    background: linear-gradient(180deg, #15131a, #0e0d11);
    border-bottom: 1px solid var(--line);
}

.h-terminal-dot {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: #2a282d;
}
.h-terminal-dot:nth-child(1) { background: color-mix(in oklab, var(--accent) 70%, #2a282d); }
.h-terminal-dot:nth-child(2) { background: #38353a; }
.h-terminal-dot:nth-child(3) { background: #2c2a2e; }

.h-terminal-title {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.08em;
    color: #5a5a64;
    text-transform: uppercase;
}

.h-terminal-screen {
    padding: 18px 20px 8px;
    max-height: 280px;
    min-height: 80px;
    overflow-y: auto;
    color: #c8c8d0;
    font-size: 13.5px;
    line-height: 1.55;
    /* Hide scrollbar for cleanliness but keep functionality. */
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.08) transparent;
}

.h-terminal-screen::-webkit-scrollbar { width: 6px; }
.h-terminal-screen::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }

.h-terminal-line {
    display: flex;
    gap: 10px;
    align-items: baseline;
    margin-bottom: 4px;
    /* Each new line fades + nudges up — like real CLI output, not a
       slide-in animation. */
    animation: h-term-line 0.22s var(--ease) both;
}

@keyframes h-term-line {
    from { opacity: 0; transform: translateY(2px); }
    to   { opacity: 1; transform: translateY(0); }
}

.h-terminal-line.is-output {
    display: block;
    color: var(--fg-2);
    padding-left: 0;
    white-space: pre-wrap;
}

.h-terminal-line.is-error {
    color: color-mix(in oklab, var(--accent) 80%, #ffffff);
}

.h-terminal-line.is-good {
    color: var(--sodium);
}

.h-terminal-prompt {
    color: var(--accent);
    font-weight: 600;
    flex: none;
    user-select: none;
}

.h-terminal-out {
    color: var(--fg-2);
    word-break: break-word;
}

.h-terminal-out strong {
    color: #ffffff;
    font-weight: 600;
}

.h-terminal-out a {
    color: var(--sodium);
    text-decoration: underline;
    text-decoration-color: rgba(240, 200, 80, 0.4);
    text-underline-offset: 3px;
}

.h-terminal-out a:hover {
    text-decoration-color: var(--sodium);
}

.h-terminal-input-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 20px 18px;
    border-top: 1px solid rgba(255, 255, 255, 0.04);
}

.h-terminal-input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--fg);
    font-family: var(--font-mono);
    font-size: 13.5px;
    caret-color: var(--accent);
    padding: 0;
}

.h-terminal-input::placeholder {
    color: #4a4a52;
    font-style: normal;
}

.h-terminal-caret {
    color: var(--accent);
    font-size: 13px;
    line-height: 1;
    animation: h-term-blink 1.05s steps(2) infinite;
    pointer-events: none;
    margin-left: -4px;
}

@keyframes h-term-blink {
    0%, 49%   { opacity: 1; }
    50%, 100% { opacity: 0; }
}

/* When the input is focused, the caret stops blinking (the browser's
   real caret takes over and the placeholder fake disappears). */
.h-terminal.is-focused .h-terminal-caret { opacity: 0; }
.h-terminal.is-focused .h-terminal-input::placeholder { opacity: 0; }

/* Tab autocomplete — ghost text overlay */
.h-terminal-ghost-wrap {
    position: relative;
    flex: 1;
    display: flex;
    align-items: center;
}

.h-terminal-ghost {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: none;
    color: #3a3a42;
    font-family: var(--font-mono);
    font-size: 13.5px;
    white-space: pre;
    line-height: inherit;
    user-select: none;
}

/* Hidden span used to measure input text width for ghost positioning */
.h-terminal-measure {
    position: absolute;
    visibility: hidden;
    white-space: pre;
    pointer-events: none;
    font-family: var(--font-mono);
    font-size: 13.5px;
}

/* Glitch animation — error lines */
.h-terminal-line.is-glitch {
    animation: h-term-glitch 0.35s ease both;
}

@keyframes h-term-glitch {
    0%   { transform: translateX(0); opacity: 1; }
    10%  { transform: translateX(-4px) skewX(-2deg); opacity: 0.8; }
    20%  { transform: translateX(3px) skewX(1.5deg); }
    30%  { transform: translateX(-2px); opacity: 0.9; }
    50%  { transform: translateX(2px) skewX(-1deg); }
    70%  { transform: translateX(-1px); }
    100% { transform: translateX(0); opacity: 1; }
}

/* Full-terminal glitch — rm -rf easter egg */
.h-terminal.is-glitching {
    animation: h-term-fullglitch 0.12s ease infinite;
}

.h-terminal.is-glitching .h-terminal-screen {
    filter: hue-rotate(90deg) saturate(2);
}

@keyframes h-term-fullglitch {
    0%   { transform: translate(0, 0) skew(0); }
    25%  { transform: translate(-3px, 1px) skew(-0.8deg); }
    50%  { transform: translate(2px, -1px) skew(0.5deg); }
    75%  { transform: translate(3px, 0) skew(-0.3deg); }
    100% { transform: translate(-1px, 1px) skew(0.6deg); }
}

@media (max-width: 640px) {
    .h-terminal { margin-top: 36px; border-radius: 12px; }
    .h-terminal-screen { font-size: 12.5px; padding: 14px 16px 6px; }
    .h-terminal-input-row { padding: 6px 16px 14px; }
    .h-terminal-input { font-size: 12.5px; }
    .h-terminal-ghost,
    .h-terminal-measure { font-size: 12.5px; }
}

/* ==================================================================
   CUSTOM CURSOR — calligraphy pen nib
   ==================================================================
   A fountain-pen nib held at a fixed 40° angle. Ink pools on slow
   movement, dries on fast. Fades naturally.
*/

.nib-cursor {
    position: fixed;
    top: 0;
    left: 0;
    pointer-events: none;
    z-index: 9999;
    opacity: 0;
    will-change: transform;
    transition: opacity 0.25s var(--ease);
    filter:
        drop-shadow(0 0 3px color-mix(in oklab, var(--accent) 40%, transparent))
        drop-shadow(0 0 8px color-mix(in oklab, var(--accent) 15%, transparent));
}

.nib-cursor.is-dipped {
    filter:
        drop-shadow(0 0 5px color-mix(in oklab, var(--accent) 60%, transparent))
        drop-shadow(0 0 12px color-mix(in oklab, var(--accent) 25%, transparent));
}

.nib-cursor.is-dipped .nib-body {
    transform: translateY(2px) scale(1.05);
}

.nib-body {
    transition: transform 0.2s var(--ease);
}



/* ==================================================================
   FOOTER — multi-column
   ================================================================== */

body.home-v4.is-homepage footer.foot { display: none; }

.h-foot {
    position: relative;
    z-index: 2;
    margin-top: 60px;
    padding: 80px 32px 36px;
    max-width: 1240px;
    margin-left: auto;
    margin-right: auto;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.h-foot-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 1fr;
    gap: 56px;
}

.h-foot-brand-name {
    font-family: var(--font-sans);
    font-size: 18px;
    font-weight: 700;
    text-transform: lowercase;
    letter-spacing: -0.01em;
    color: #fff;
    margin: 0 0 12px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.h-foot-brand-name::before {
    content: '';
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 8px var(--accent);
}

.h-foot-brand-desc {
    color: #6a6a72;
    font-size: 13.5px;
    line-height: 1.6;
    max-width: 280px;
    margin: 0 0 22px;
}

.h-foot-social {
    display: flex;
    gap: 8px;
}

.h-foot-social a {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #c8c8d0;
    transition: all 0.25s var(--ease);
}

.h-foot-social a:hover {
    color: #fff;
    border-color: var(--accent);
    background: rgba(255, 77, 61, 0.1);
}

.h-foot-col-label {
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 700;
    color: #ffffff;
    margin: 0 0 16px;
}

.h-foot-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }

.h-foot-col a {
    font-family: var(--font-sans);
    font-size: 13.5px;
    color: #8a8a94;
    transition: color 0.2s var(--ease);
}

.h-foot-col a:hover { color: #fff; }

.h-foot-rule {
    height: 1px;
    background: rgba(255, 255, 255, 0.06);
    margin: 56px 0 28px;
}

.h-foot-base {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.06em;
    color: #5a5a64;
    flex-wrap: wrap;
    gap: 12px;
}

.h-foot-base-r {
    display: inline-flex;
    align-items: center;
    gap: 16px;
}

.h-foot-base-r .dot {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: #5a5a64;
}

@media (max-width: 820px) {
    .h-foot-grid { grid-template-columns: 1fr 1fr; gap: 40px; }
}

@media (max-width: 540px) {
    .h-foot-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* ==================================================================
   IDLE MODE
   ==================================================================
   Triggered by signature.js adding body.is-idle after ~45s of no
   input. Quiets the page so the heartbeat ignite at the centre reads
   as the only living thing in view. Wakes instantly on any input. */

body.home-v4.is-idle main,
body.home-v4.is-idle .nav,
body.home-v4.is-idle .nav-actions {
    filter: brightness(0.86) saturate(0.85);
    transition: filter 1.6s var(--ease);
}

body.home-v4 main,
body.home-v4 .nav,
body.home-v4 .nav-actions {
    transition: filter 0.6s var(--ease);
}

/* Lift the dot grid slightly when idle — the empty page feels less
   empty when its instrumented texture is a touch more visible. */
body.home-v4.is-idle .h-bg-grid {
    opacity: 1.15;
    transition: opacity 1.6s var(--ease);
}

/* Slow random ignites way down by extending each one's keyframe —
   the heartbeat at the centre is the new dominant rhythm. */
body.home-v4.is-idle .h-bg-ignite:not(.is-heartbeat) {
    animation-duration: 3.2s;
    opacity: 0.55;
}

/* ==================================================================
   REDUCED MOTION
   ================================================================== */

@media (prefers-reduced-motion: reduce) {
    .h-bg-ignite-layer { display: none !important; }
    .h-bg-scan { display: none !important; }
    .h-reveal, .h-reveal-stagger > * { opacity: 1 !important; transform: none !important; filter: none !important; }
    .h-hero-title .ln { animation: none !important; transform: none !important; }
    .h-eyebrow::after { display: none !important; }
    .h-tilt { transform: none !important; }
    /* Skip the entire orbit-merge sequence — show a solid resting dot instead. */
    .h-hero-dot-orbit,
    .h-hero-dot-a,
    .h-hero-dot-b,
    .h-hero-dot-tether,
    .h-hero-dot-guide,
    .h-hero-dot-flash,
    .h-hero-dot-ring { animation: none !important; opacity: 0 !important; }
    .h-hero-dot-core {
        animation: none !important;
        opacity: 1 !important;
        r: 26px !important;
    }
    /* And let the page wipe complete instantly without keyframed travel. */
    body.home-v4::before,
    body.home-v4::after { animation-duration: 0.01s !important; }
}

/* ==================================================================
   ANIMATIONS — v4 signature motion
   ================================================================== */

/* ----- Hero word stagger (CSS-only, on load) ----- */

.h-hero-title .ln-clip {
    display: block;
    overflow: hidden;
    padding: 0.04em 0 0.08em;
}

.h-hero-title .ln {
    display: block;
    transform: translateY(110%);
    animation: h-rise 1.15s var(--ease-spring, var(--ease)) forwards;
    will-change: transform;
}

.h-hero-title .ln1 { animation-delay: 0.45s; }
.h-hero-title .ln2 { animation-delay: 0.6s; }

@keyframes h-rise {
    0% { transform: translateY(110%); }
    100% { transform: translateY(0); }
}

/* Hero eyebrow / deck / cta fade-in */

.h-hero-eyebrow,
.h-hero-deck,
.h-hero-cta {
    opacity: 0;
    transform: translateY(14px);
    animation: h-fade-up 0.9s var(--ease) forwards;
}

.h-hero-eyebrow { animation-delay: 0.2s; }
.h-hero-deck    { animation-delay: 1.0s; }
.h-hero-cta     { animation-delay: 1.15s; }
/* .hero-scroll uses its own keyframe (h-fade-up-scroll) — defined earlier —
   so the absolute-positioning translateX(-50%) survives the rise. */

@keyframes h-fade-up {
    to { opacity: 1; transform: translateY(0); }
}

/* ----- Page entry: solid red wall that slides off and reveals -----
   Architectural twin of the original wipe — one opaque panel covers the
   viewport at t=0, then translates off the right. Polished in two places:
   (a) the easing curve is slightly softer (graceful long decel instead of
   a hard in-out), and (b) the trailing edge is a wider, glowing light bleed
   rather than a 2px line that read as a glitch artifact. The panel itself
   carries an ultra-fine film-grain texture so the surface feels velvet,
   not plastic. */

body.home-v4::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 998;
    pointer-events: none;
    /* CRITICAL: style.css sets body::before to opacity 0.035 / mix-blend-mode
       overlay for the global film-grain layer. body.home-v4::before only wins
       on properties it explicitly sets — so we MUST reset both here, otherwise
       the wipe panel paints at 3.5% opacity and looks like "an effect that
       reveals nothing". */
    opacity: 1;
    mix-blend-mode: normal;
    background:
        /* Ultra-fine film grain layered on top — subtle texture, opaque */
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' seed='5'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.08 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>"),
        linear-gradient(108deg,
            color-mix(in srgb, var(--accent) 70%, #100408) 0%,
            color-mix(in srgb, var(--accent) 88%, #2a0a10) 14%,
            var(--accent) 30%,
            color-mix(in srgb, var(--accent) 94%, #ffffff) 50%,
            var(--accent) 70%,
            color-mix(in srgb, var(--accent) 88%, #2a0a10) 86%,
            color-mix(in srgb, var(--accent) 70%, #100408) 100%);
    background-blend-mode: overlay, normal;
    background-size: cover, cover;
    /* Solid fallback colour in case the gradient is mid-paint at first frame —
       guarantees the page is never visible behind a half-rendered panel. */
    background-color: var(--accent);
    transform: translate3d(0, 0, 0);
    will-change: transform;
    /* Total runtime ≈ 1.95s: a palpable HOLD at the start (the wall sits
       there long enough for the eye to register it), then a deliberate
       slide-off. Without the hold the wipe registers as "an effect" rather
       than "a curtain being pulled back". */
    animation: h-wipe-panel 1.95s cubic-bezier(0.62, 0.04, 0.2, 1) forwards;
}

/* Trailing edge — a wider, soft, glowing band that lights up the seam
   between covered and revealed page. Reads as light bleeding through. */
body.home-v4::after {
    content: '';
    position: fixed;
    top: 0;
    bottom: 0;
    left: -6px;
    width: 5px;
    z-index: 999;
    pointer-events: none;
    background: linear-gradient(180deg,
        transparent 0%,
        color-mix(in srgb, var(--accent) 30%, #ffffff) 18%,
        #ffffff 50%,
        color-mix(in srgb, var(--accent) 30%, #ffffff) 82%,
        transparent 100%);
    box-shadow:
        0 0 22px var(--accent),
        0 0 64px var(--accent),
        0 0 120px color-mix(in srgb, var(--accent) 55%, transparent);
    transform: translate3d(0, 0, 0);
    opacity: 0;
    will-change: transform, opacity;
    animation: h-wipe-edge 2.05s cubic-bezier(0.62, 0.04, 0.2, 1) forwards;
}

@keyframes h-wipe-panel {
    /* Hold at full coverage for the first ~18% (≈350ms) so the wall is
       UNMISTAKABLY there before it commits to leaving. Then slide off. */
    0%,  18% { transform: translate3d(0, 0, 0); }
    100%     { transform: translate3d(108%, 0, 0); }
}

@keyframes h-wipe-edge {
    /* Edge stays hidden during the hold, then ignites as the panel begins
       to slide, accompanying the trailing edge across the viewport. */
    0%,  17% { transform: translate3d(0, 0, 0);    opacity: 0; }
    22%      { opacity: 1; }
    88%      { opacity: 1; }
    100%     { transform: translate3d(101vw, 0, 0); opacity: 0; }
}

/* ----- Hero accent dot: binary-orbit → merge → settle -----
   Stand-alone block placed BELOW the title. Two dots spiral inward around
   a common centre, a gravitational tether between them brightens on
   approach, an orbit guide flashes the geometry, then a white flash +
   ring pulse + a small overshoot on the merged core that settles to rest.
   Runs ONCE on load. No infinite loops — resting state is a static dot.

   Timeline (page load):
     0.00s  title lines start rising
     1.85s  dots fade in at ±R, orbit begins (orbit lasts 2.0s)
     3.85s  collision: flash + ring + core overshoot
     4.45s  core settled, sequence done
*/

.h-hero-dot {
    display: block;
    /* Sized in absolute px — this is a feature mark, not text. Kept compact
       so it doesn't push the rest of the hero out of the viewport. */
    width: clamp(90px, 10vw, 115px);
    height: clamp(90px, 10vw, 115px);
    /* Aggressive negative bottom margin pulls the deck right up under the
       visible core, since the SVG box has empty padding around the centered
       dot (needed so the orbit can swing wide during the entry animation). */
    margin: 2px auto -34px;
    color: var(--accent);
    overflow: visible;
    /* Fade the whole dot in just as the title line settles. */
    opacity: 0;
    animation: h-hero-dot-appear 0.6s var(--ease) forwards;
    animation-delay: 1.65s;
}

@keyframes h-hero-dot-appear {
    to { opacity: 1; }
}

.h-hero-dot-svg {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/* The orbit group rotates around (0,0). Children animate their own cx so
   they spiral inward while the group spins. */
.h-hero-dot-orbit {
    transform-origin: 0 0;
    animation: h-hero-dot-spin 2s cubic-bezier(0.45, 0, 0.3, 1) forwards;
    animation-delay: 1.85s;
}

@keyframes h-hero-dot-spin {
    0%   { transform: rotate(-18deg); }
    100% { transform: rotate(940deg); }
}

.h-hero-dot-a,
.h-hero-dot-b {
    fill: var(--accent);
    opacity: 0;
    filter: drop-shadow(0 0 6px var(--accent));
}

.h-hero-dot-a {
    animation: h-hero-dot-orbit-a 2s cubic-bezier(0.45, 0, 0.3, 1) forwards;
    animation-delay: 1.85s;
}

.h-hero-dot-b {
    animation: h-hero-dot-orbit-b 2s cubic-bezier(0.45, 0, 0.3, 1) forwards;
    animation-delay: 1.85s;
}

@keyframes h-hero-dot-orbit-a {
    0%   { cx: 78px; opacity: 0; r: 13px; }
    8%   { opacity: 1; }
    /* Approach phase — gradual inward */
    65%  { cx: 50px; opacity: 1; r: 13px; }
    /* Final magnetic snap */
    95%  { cx: 6px;  opacity: 1; r: 10px; }
    100% { cx: 0px;  opacity: 0; r: 8px; }
}

@keyframes h-hero-dot-orbit-b {
    0%   { cx: -78px; opacity: 0; r: 13px; }
    8%   { opacity: 1; }
    65%  { cx: -50px; opacity: 1; r: 13px; }
    95%  { cx: -6px;  opacity: 1; r: 10px; }
    100% { cx: 0px;   opacity: 0; r: 8px; }
}

/* Gravitational tether — line between the two dots. Faint at distance,
   brightens as they close. Disappears at merge. */
.h-hero-dot-tether {
    stroke: var(--accent);
    stroke-width: 2;
    stroke-linecap: round;
    opacity: 0;
    animation: h-hero-dot-tether 2s cubic-bezier(0.45, 0, 0.3, 1) forwards;
    animation-delay: 1.85s;
}

@keyframes h-hero-dot-tether {
    0%   { x1: 78px; x2: -78px; opacity: 0;    stroke-width: 1; }
    18%  { opacity: 0.18; }
    65%  { x1: 50px; x2: -50px; opacity: 0.45; stroke-width: 2.6; }
    92%  { opacity: 0.85; stroke-width: 4; }
    100% { x1: 0px;  x2: 0px;   opacity: 0;    stroke-width: 0; }
}

/* Orbit guide — invisible most of the time. Briefly visible during the
   final approach to "show" the geometry, then collapses inward with the merge. */
.h-hero-dot-guide {
    fill: none;
    stroke: var(--accent);
    stroke-width: 0.8;
    opacity: 0;
    transform-origin: 0 0;
    animation: h-hero-dot-guide 2s cubic-bezier(0.45, 0, 0.3, 1) forwards;
    animation-delay: 1.85s;
}

@keyframes h-hero-dot-guide {
    0%, 35% { opacity: 0;    transform: scale(1); }
    55%     { opacity: 0.16; transform: scale(0.85); }
    85%     { opacity: 0.28; transform: scale(0.32); }
    100%    { opacity: 0;    transform: scale(0); }
}

/* Collision flash: short, hot white burst centred on merge. */
.h-hero-dot-flash {
    fill: #fff;
    opacity: 0;
    animation: h-hero-dot-flash 0.55s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
    animation-delay: 3.85s;
}

@keyframes h-hero-dot-flash {
    0%   { r: 0px;  opacity: 0.95; }
    40%  { opacity: 0.7; }
    100% { r: 92px; opacity: 0; }
}

/* Expanding ring pulse — energy radiating outward at merge. */
.h-hero-dot-ring {
    fill: none;
    stroke: var(--accent);
    stroke-width: 5;
    opacity: 0;
    animation: h-hero-dot-ring 0.95s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
    animation-delay: 3.85s;
}

@keyframes h-hero-dot-ring {
    0%   { r: 8px;   opacity: 0.95; stroke-width: 8; }
    100% { r: 125px; opacity: 0;    stroke-width: 0.4; }
}

/* Merged core — slight overshoot then settles to a STATIC final radius.
   No infinite breath loop — the sequence resolves and stays at rest. */
.h-hero-dot-core {
    fill: var(--accent);
    opacity: 0;
    filter:
        drop-shadow(0 0 12px var(--accent))
        drop-shadow(0 0 32px color-mix(in srgb, var(--accent) 60%, transparent));
    animation: h-hero-dot-core-in 0.65s cubic-bezier(0.2, 0.85, 0.25, 1) forwards;
    animation-delay: 3.85s;
}

@keyframes h-hero-dot-core-in {
    0%   { r: 0px;  opacity: 1; }
    60%  { r: 32px; opacity: 1; }   /* slight overshoot */
    100% { r: 26px; opacity: 1; }   /* settled — static, no loop */
}

/* ----- Scroll-reveal blur-drop ----- */

/* "Infall" — elements don't just rise; they drift inward toward the page's
   gravitational centre (a hair of extra scale that settles to 1) so the whole
   document feels pulled toward the singularity. */
.h-reveal {
    opacity: 0;
    transform: translateY(28px) scale(1.035);
    filter: blur(8px);
    transition:
        opacity 0.85s var(--ease),
        transform 0.85s var(--ease),
        filter 0.85s var(--ease);
    will-change: opacity, transform, filter;
}

.h-reveal.is-in {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
}

/* Staggered children — apply via .h-reveal-stagger on parent */

.h-reveal-stagger > * {
    opacity: 0;
    transform: translateY(22px) scale(1.03);
    filter: blur(6px);
    transition:
        opacity 0.75s var(--ease),
        transform 0.75s var(--ease),
        filter 0.75s var(--ease);
    will-change: opacity, transform, filter;
}

.h-reveal-stagger.is-in > * {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
}

.h-reveal-stagger.is-in > *:nth-child(1) { transition-delay: 0s; }
.h-reveal-stagger.is-in > *:nth-child(2) { transition-delay: 0.07s; }
.h-reveal-stagger.is-in > *:nth-child(3) { transition-delay: 0.14s; }
.h-reveal-stagger.is-in > *:nth-child(4) { transition-delay: 0.21s; }
.h-reveal-stagger.is-in > *:nth-child(5) { transition-delay: 0.28s; }
.h-reveal-stagger.is-in > *:nth-child(6) { transition-delay: 0.35s; }
.h-reveal-stagger.is-in > *:nth-child(7) { transition-delay: 0.42s; }
.h-reveal-stagger.is-in > *:nth-child(8) { transition-delay: 0.49s; }

/* ----- Eyebrow scan-line sweep ----- */

.h-eyebrow {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}

.h-eyebrow::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 35%;
    background: linear-gradient(90deg,
        transparent,
        color-mix(in srgb, var(--accent) 70%, transparent),
        transparent);
    transform: translateX(-100%);
    pointer-events: none;
    opacity: 0;
    z-index: -1;
}

.h-eyebrow.is-in::after {
    animation: h-eyebrow-scan 1.6s var(--ease) 0.15s forwards;
}

@keyframes h-eyebrow-scan {
    0%   { transform: translateX(-100%); opacity: 0; }
    20%  { opacity: 0.55; }
    100% { transform: translateX(350%); opacity: 0; }
}

/* ----- 3D card tilt ----- */

.h-tilt {
    transform-style: preserve-3d;
    transform: perspective(900px) rotateX(var(--tilt-rx, 0deg)) rotateY(var(--tilt-ry, 0deg));
    transition: transform 0.5s var(--ease);
    will-change: transform;
}

.h-tilt[data-tilt-active="true"] {
    transition: transform 0.08s linear;
}

/* Inner elements get a small parallax via translateZ */

.h-tilt .h-tilt-inner {
    transform: translateZ(12px);
}

/* ----- Architecture card hover: corner glow brightens ----- */

.h-arch-card {
    transition:
        border-color 0.35s var(--ease),
        transform 0.5s var(--ease),
        box-shadow 0.5s var(--ease);
}

.h-arch-card:hover {
    box-shadow:
        0 0 0 1px rgba(255, 77, 61, 0.15),
        0 40px 80px -40px rgba(255, 77, 61, 0.25);
}

.h-arch-card .h-arch-icon {
    transition: transform 0.45s var(--ease), background 0.3s var(--ease), border-color 0.3s var(--ease);
}

.h-arch-card:hover .h-arch-icon {
    background: rgba(255, 77, 61, 0.18);
    border-color: rgba(255, 77, 61, 0.45);
    transform: rotate(-4deg) scale(1.05);
}

/* ----- Section-divider vertical mark ----- */

/* ----- Section terminator: the orbit-merge dot becomes the sigil -----
   Replaces the previous thin vertical divider lines. A single 4px red dot
   sits at the TOP of each non-first section, on the page's centreline. It
   is the same visual mark as the hero's merged-orbit dot — quietly tying
   the brand together across the page. */

.h-section::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 22px;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow:
        0 0 8px var(--accent),
        0 0 18px color-mix(in oklab, var(--accent) 50%, transparent);
    transform: translateX(-50%);
    pointer-events: none;
}

.h-section:first-of-type::before { display: none; }

/* Practice sits directly under the hero — its divider would collide with
   the scroll cue and the (already-animated) wipe edge. Hide it there. */
.h-section#practice::before { display: none; }

.h-section.h-contact::before { display: none; }

/* ==================================================================
   DOWNLOAD CARDS (v4)
   ================================================================== */

.h-dl-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
}

.h-dl-card {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0)),
        rgba(14, 14, 18, 0.6);
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 22px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative;
    transition: border-color 0.35s var(--ease), transform 0.5s var(--ease);
}

.h-dl-card:hover { border-color: rgba(255, 255, 255, 0.18); }

.h-dl-card-feature {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    background:
        linear-gradient(180deg, color-mix(in oklab, var(--accent) 6%, rgba(14, 14, 18, 0.7)), rgba(14, 14, 18, 0.6) 70%);
    border-color: color-mix(in oklab, var(--accent) 28%, rgba(255, 255, 255, 0.1));
    box-shadow:
        0 0 0 1px color-mix(in oklab, var(--accent) 10%, transparent),
        0 40px 80px -30px color-mix(in oklab, var(--accent) 30%, transparent);
}
.h-dl-card-feature:hover {
    border-color: color-mix(in oklab, var(--accent) 45%, rgba(255, 255, 255, 0.1));
}

.h-dl-card-media {
    aspect-ratio: 16 / 10;
    background: rgba(255, 255, 255, 0.02);
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    overflow: hidden;
    position: relative;
}
.h-dl-card-media img {
    width: 100%; height: 100%;
    object-fit: cover;
    transition: transform 0.7s var(--ease);
}
.h-dl-card:hover .h-dl-card-media img { transform: scale(1.04); }

.h-dl-card-feature .h-dl-card-media {
    aspect-ratio: auto;
    border-right: 1px solid rgba(255, 255, 255, 0.05);
    border-bottom: none;
    min-height: 100%;
    padding: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.h-dl-card-feature .h-dl-card-media img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}
.h-dl-card-feature:hover .h-dl-card-media img { transform: none; }

.h-dl-card-body {
    padding: 28px 28px 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    flex: 1;
}

.h-dl-card-feature .h-dl-card-body { padding: 36px 36px 32px; }

.h-dl-card-meta {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #6a6a72;
}

.h-dl-card-title {
    font-size: 1.45rem;
    font-weight: 700;
    letter-spacing: -0.025em;
    color: #fff;
    margin: 0;
    line-height: 1.1;
}

.h-dl-card-feature .h-dl-card-title { font-size: 1.9rem; }

.h-dl-card-desc {
    color: #8a8a94;
    font-size: 14px;
    line-height: 1.6;
    max-width: 480px;
    margin: 0;
}

.h-dl-card-features {
    list-style: none;
    margin: 6px 0 8px;
    padding: 0;
}

.h-dl-card-features li {
    position: relative;
    padding-left: 18px;
    margin-bottom: 8px;
    font-size: 13.5px;
    color: #c8c8d0;
    line-height: 1.55;
}

.h-dl-card-features li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.65em;
    width: 9px;
    height: 1px;
    background: var(--accent);
}

.h-dl-card-foot {
    margin-top: auto;
    padding-top: 18px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.h-dl-card-foot-label {
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #6a6a72;
}

@media (max-width: 820px) {
    .h-dl-grid { grid-template-columns: 1fr; }
    .h-dl-card-feature { grid-template-columns: 1fr; }
    .h-dl-card-feature .h-dl-card-media { border-right: none; border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
}

/* Discontinued banner inside dl card */
.h-dl-discontinued {
    margin-top: 10px;
    padding: 12px 14px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.03);
}
.h-dl-discontinued-head {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #c8c8d0;
}
.h-dl-discontinued-head svg { color: #8a8a94; flex: none; }
.h-dl-discontinued-body {
    margin: 8px 0 0;
    color: #8a8a94;
    font-size: 13.5px;
    line-height: 1.6;
}

/* ==================================================================
   CHANGELOG (v4)
   ================================================================== */

.h-cl {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: 1px solid rgba(255, 255, 255, 0.07);
    border-radius: 22px;
    overflow: hidden;
    background: rgba(14, 14, 18, 0.5);
}

.h-cl-item {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 36px;
    padding: 32px 36px;
    border-top: 1px solid rgba(255, 255, 255, 0.05);
    transition: background 0.3s var(--ease);
    position: relative;
}

.h-cl-item:first-child { border-top: none; }
.h-cl-item:hover { background: rgba(255, 255, 255, 0.015); }

/* Vertical timeline line in the left column */
.h-cl-item::before {
    content: '';
    position: absolute;
    left: 56px;
    top: 0;
    bottom: 0;
    width: 1px;
    background: rgba(255, 255, 255, 0.05);
}
.h-cl-item:first-child::before { top: 36px; }
.h-cl-item:last-child::before { bottom: calc(100% - 56px); }

.h-cl-marker {
    position: absolute;
    left: 50px;
    top: 38px;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    background: rgba(14, 14, 18, 1);
    border: 2px solid #6a6a72;
    z-index: 1;
}

.h-cl-item[data-tag="release"] .h-cl-marker,
.h-cl-item[data-tag="just shipped"] .h-cl-marker {
    border-color: var(--accent);
    box-shadow: 0 0 12px var(--accent);
}

.h-cl-meta {
    padding-left: 36px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.h-cl-date {
    font-family: var(--font-mono);
    font-size: 12px;
    color: #c8c8d0;
    letter-spacing: 0.04em;
}

.h-cl-tag {
    align-self: flex-start;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.04);
    color: #8a8a94;
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.h-cl-item[data-tag="release"] .h-cl-tag,
.h-cl-item[data-tag="just shipped"] .h-cl-tag {
    background: rgba(255, 77, 61, 0.1);
    color: var(--accent);
    border-color: rgba(255, 77, 61, 0.32);
}

.h-cl-item[data-tag="upcoming"] .h-cl-tag {
    color: #ffd175;
    border-color: rgba(255, 200, 80, 0.25);
    background: rgba(255, 200, 80, 0.06);
}

.h-cl-title {
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #fff;
    margin: 0 0 10px;
    line-height: 1.15;
}

.h-cl-body {
    color: #c8c8d0;
    font-size: 14.5px;
    line-height: 1.65;
}

.h-cl-body p { margin: 0 0 10px; }
.h-cl-body p:last-child { margin-bottom: 0; }

.h-cl-body ul {
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

.h-cl-body ul li {
    position: relative;
    padding-left: 18px;
    margin-bottom: 8px;
    font-size: 13.5px;
    color: #c8c8d0;
}

.h-cl-body ul li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.65em;
    width: 9px;
    height: 1px;
    background: var(--accent);
}

.h-cl-body strong { color: #fff; font-weight: 600; }

@media (max-width: 820px) {
    .h-cl-item { grid-template-columns: 1fr; padding: 24px 24px 24px 56px; gap: 16px; }
    .h-cl-item::before { left: 24px; }
    .h-cl-marker { left: 18px; top: 30px; }
    .h-cl-meta { padding-left: 0; flex-direction: row; align-items: center; gap: 12px; }
}

/* ==================================================================
   PAGE INTRO (subtle, for non-homepage v4 pages)
   ================================================================== */

.h-page-intro {
    padding: 160px 32px 80px;
    max-width: 1240px;
    margin: 0 auto;
    text-align: center;
    position: relative;
}

.h-page-intro .h-eyebrow { margin-bottom: 24px; }
.h-page-intro .h-display { margin-top: 0; }
.h-page-intro .h-deck { margin: 24px auto 0; }

@media (max-width: 720px) {
    .h-page-intro { padding: 130px 20px 60px; }
}

/* ==================================================================
   LIGHT THEME — overrides hardcoded dark surfaces / text colors used
   throughout the homepage. Driven by [data-theme="light"] on <html>.
   ================================================================== */

[data-theme="light"] body.home-v4 {
    background: var(--bg);
}

/* Background warmth + dot grid */
[data-theme="light"] .h-bg-grid {
    background-image:
        radial-gradient(circle, rgba(0, 0, 0, 0.10) 0.7px, transparent 1.1px);
}

/* Nav pill */
[data-theme="light"] body.home-v4 .nav-inner {
    background: rgba(255, 255, 255, 0.78);
    border-color: rgba(0, 0, 0, 0.08);
    box-shadow:
        0 0 0 1px rgba(0, 0, 0, 0.04),
        0 16px 40px -20px rgba(0, 0, 0, 0.18);
}

[data-theme="light"] body.home-v4 .nav-mark { color: var(--fg); }

[data-theme="light"] body.home-v4 .nav-links {
    border-left-color: rgba(0, 0, 0, 0.09);
}

[data-theme="light"] body.home-v4 .nav-link { color: var(--fg-3); }
[data-theme="light"] body.home-v4 .nav-link:hover {
    color: var(--fg);
    background: rgba(0, 0, 0, 0.05);
}
[data-theme="light"] body.home-v4 .nav-link[aria-current="page"] {
    color: var(--fg);
    background: rgba(0, 0, 0, 0.06);
}

[data-theme="light"] body.home-v4 .nav-btn {
    background: rgba(255, 255, 255, 0.78);
    border-color: rgba(0, 0, 0, 0.08);
    color: var(--fg-2);
}
[data-theme="light"] body.home-v4 .nav-btn:hover {
    color: var(--fg);
    border-color: rgba(0, 0, 0, 0.16);
}

[data-theme="light"] body.home-v4 #contact-btn,
[data-theme="light"] body.home-v4 #contact-btn:hover { color: #fff; }

/* Common typography */
[data-theme="light"] .h-eyebrow {
    background: rgba(255, 255, 255, 0.7);
    border-color: rgba(0, 0, 0, 0.08);
    color: var(--fg-3);
}

[data-theme="light"] .h-display { color: var(--fg); }
[data-theme="light"] .h-display-fade {
    background: linear-gradient(180deg,
        var(--fg) 0%,
        var(--fg-2) 35%,
        color-mix(in oklab, var(--accent) 65%, var(--fg-2)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

[data-theme="light"] .h-deck { color: var(--fg-3); }

/* Hero */
[data-theme="light"] .h-hero-title { color: var(--fg); }
[data-theme="light"] .h-hero-title .ln2 {
    background: linear-gradient(180deg,
        var(--fg) 0%,
        var(--fg-2) 30%,
        color-mix(in oklab, var(--accent) 70%, var(--fg-2)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
[data-theme="light"] .h-hero-deck { color: var(--fg-3); }

[data-theme="light"] .h-btn-primary {
    background: var(--fg);
    color: var(--bg);
}
[data-theme="light"] .h-btn-primary:hover {
    background: var(--accent);
    color: #fff;
}
[data-theme="light"] .h-btn-ghost {
    background: rgba(0, 0, 0, 0.03);
    color: var(--fg-2);
    border-color: rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .h-btn-ghost:hover {
    color: var(--fg);
    border-color: rgba(0, 0, 0, 0.22);
}

[data-theme="light"] body.home-v4 .hero-scroll { color: var(--fg-4); }

/* Architecture cards */
[data-theme="light"] .h-arch-card {
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(0, 0, 0, 0.02);
}
[data-theme="light"] .h-arch-card::before {
    background: linear-gradient(135deg,
        transparent 0%,
        transparent 65%,
        rgba(0, 0, 0, 0.03) 100%);
}
[data-theme="light"] .h-arch-card:hover {
    border-color: rgba(0, 0, 0, 0.14);
}
[data-theme="light"] .h-arch-card h3 { color: var(--fg); }
[data-theme="light"] .h-arch-card p { color: var(--fg-3); }
[data-theme="light"] .h-arch-meta { color: var(--fg-4); }
[data-theme="light"] .h-arch-card:hover {
    box-shadow:
        0 0 0 1px color-mix(in oklab, var(--accent) 18%, transparent),
        0 40px 80px -40px color-mix(in oklab, var(--accent) 28%, transparent);
}

/* Project cards */
[data-theme="light"] body.home-v4 .project-card {
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(0, 0, 0, 0.02);
}
[data-theme="light"] body.home-v4 .project-card-num { color: var(--fg-3); }
[data-theme="light"] body.home-v4 .project-card-title { color: var(--fg); }
[data-theme="light"] body.home-v4 .project-card-desc { color: var(--fg-3); }
[data-theme="light"] body.home-v4 .tag {
    background: rgba(0, 0, 0, 0.04);
    border-color: rgba(0, 0, 0, 0.10);
    color: var(--fg-2);
}
[data-theme="light"] body.home-v4 .project-card-foot {
    border-top-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] body.home-v4 .project-card-foot-label { color: var(--fg-3); }
[data-theme="light"] body.home-v4 .project-card-foot-cta { color: var(--fg); }
[data-theme="light"] body.home-v4 .project-card-media {
    border-left-color: rgba(0, 0, 0, 0.07);
}
@media (max-width: 820px) {
    [data-theme="light"] body.home-v4 .project-card-media {
        border-left: none;
        border-top: 1px solid rgba(0, 0, 0, 0.07);
    }
}

/* Roadmap cards */
[data-theme="light"] .h-road-card {
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        inset 0 0 0 0.5px rgba(0, 0, 0, 0.02);
}
[data-theme="light"] .h-road-card-tag { color: var(--fg-3); }
[data-theme="light"] .h-road-card-tag::before { background: var(--fg-4); }
[data-theme="light"] .h-road-card-title { color: var(--fg); }
[data-theme="light"] .h-road-card-desc { color: var(--fg-3); }

/* Now strip */
[data-theme="light"] .h-now-label { color: var(--fg-4); }
[data-theme="light"] .h-now-value { color: var(--fg); }
[data-theme="light"] .h-now-meta { color: var(--fg-3); }

/* Contact cards */
[data-theme="light"] .h-contact-card { color: var(--fg); }
[data-theme="light"] .h-contact-card-label { color: var(--fg); }
[data-theme="light"] .h-contact-card-meta { color: var(--fg-3); }
[data-theme="light"] .h-contact-card-arr { color: var(--fg-4); }

/* Terminal — keep it dark even in light mode; reads as a real terminal */
[data-theme="light"] .h-terminal {
    box-shadow:
        inset 0 1px 0 var(--inner-hi),
        0 30px 80px -40px rgba(0, 0, 0, 0.25),
        0 0 0 1px rgba(0, 0, 0, 0.04);
}

/* Footer */
[data-theme="light"] .h-foot {
    border-top-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .h-foot-brand-name { color: var(--fg); }
[data-theme="light"] .h-foot-brand-desc { color: var(--fg-3); }
[data-theme="light"] .h-foot-social a {
    background: rgba(0, 0, 0, 0.04);
    border-color: rgba(0, 0, 0, 0.08);
    color: var(--fg-2);
}
[data-theme="light"] .h-foot-social a:hover {
    color: var(--fg);
    background: color-mix(in oklab, var(--accent) 10%, transparent);
}
[data-theme="light"] .h-foot-col-label { color: var(--fg); }
[data-theme="light"] .h-foot-col a { color: var(--fg-3); }
[data-theme="light"] .h-foot-col a:hover { color: var(--fg); }
[data-theme="light"] .h-foot-rule { background: rgba(0, 0, 0, 0.08); }
[data-theme="light"] .h-foot-base { color: var(--fg-4); }
[data-theme="light"] .h-foot-base-r .dot { background: var(--fg-4); }

/* Download cards */
[data-theme="light"] .h-dl-card {
    background:
        linear-gradient(180deg, rgba(0, 0, 0, 0.015), rgba(0, 0, 0, 0)),
        var(--bg-elev);
    border-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .h-dl-card:hover { border-color: rgba(0, 0, 0, 0.18); }
[data-theme="light"] .h-dl-card-feature {
    background:
        linear-gradient(180deg,
            color-mix(in oklab, var(--accent) 6%, var(--bg-elev)),
            var(--bg-elev) 70%);
}
[data-theme="light"] .h-dl-card-media {
    background: rgba(0, 0, 0, 0.02);
    border-bottom-color: rgba(0, 0, 0, 0.06);
}
[data-theme="light"] .h-dl-card-feature .h-dl-card-media {
    border-right-color: rgba(0, 0, 0, 0.06);
    border-bottom: none;
}
@media (max-width: 820px) {
    [data-theme="light"] .h-dl-card-feature .h-dl-card-media {
        border-right: none;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    }
}
[data-theme="light"] .h-dl-card-meta { color: var(--fg-3); }
[data-theme="light"] .h-dl-card-title { color: var(--fg); }
[data-theme="light"] .h-dl-card-desc { color: var(--fg-3); }
[data-theme="light"] .h-dl-card-features li { color: var(--fg-2); }
[data-theme="light"] .h-dl-card-foot {
    border-top-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .h-dl-card-foot-label { color: var(--fg-3); }
[data-theme="light"] .h-dl-discontinued {
    background: rgba(0, 0, 0, 0.025);
    border-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .h-dl-discontinued-head { color: var(--fg-2); }
[data-theme="light"] .h-dl-discontinued-head svg { color: var(--fg-3); }
[data-theme="light"] .h-dl-discontinued-body { color: var(--fg-3); }

/* Changelog */
[data-theme="light"] .h-cl {
    background: var(--bg-elev);
    border-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .h-cl-item {
    border-top-color: rgba(0, 0, 0, 0.06);
}
[data-theme="light"] .h-cl-item:hover { background: rgba(0, 0, 0, 0.02); }
[data-theme="light"] .h-cl-item::before { background: rgba(0, 0, 0, 0.07); }
[data-theme="light"] .h-cl-marker {
    background: var(--bg-elev);
    border-color: var(--fg-4);
}
[data-theme="light"] .h-cl-date { color: var(--fg-2); }
[data-theme="light"] .h-cl-tag {
    background: rgba(0, 0, 0, 0.04);
    color: var(--fg-3);
    border-color: rgba(0, 0, 0, 0.10);
}
[data-theme="light"] .h-cl-title { color: var(--fg); }
[data-theme="light"] .h-cl-body { color: var(--fg-2); }
[data-theme="light"] .h-cl-body ul li { color: var(--fg-2); }
[data-theme="light"] .h-cl-body strong { color: var(--fg); }

/* ==================================================================
   THE SINGULARITY — WebGL gravitational-lensing black-hole hero
   ==================================================================
   The canvas (created by singularity.js) sits behind all hero content.
   The original orbiting-dots SVG is the JS-controlled fallback when
   WebGL2 is unavailable, so we hide it by default here and let the
   script restore it only on failure. */

body.home-v4 .hero {
    position: relative;            /* anchor the absolute canvas */
    overflow: clip;                /* keep the disk glow from spilling */
}

.singularity-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    /* The shader already feathers its own alpha; this is belt-and-braces
       so the rectangle never reads as a hard edge over the page. */
    -webkit-mask-image: radial-gradient(ellipse 78% 78% at 50% 50%, #000 55%, transparent 100%);
            mask-image: radial-gradient(ellipse 78% 78% at 50% 50%, #000 55%, transparent 100%);
    /* Fade the whole thing in once the GL context is warm. */
    opacity: 0;
    animation: singularity-in 1.1s var(--ease) 0.15s forwards;
}

@keyframes singularity-in { to { opacity: 1; } }

/* Hide the legacy SVG intro — singularity.js un-hides it only if WebGL2
   fails to initialise (graceful fallback). */
body.home-v4 .h-hero-dot { display: none; }

/* Lift every hero element above the canvas. These stay position:relative so
   they remain in the flex flow (their vertical spacing is built with margins);
   relative + z-index just paints them over the accretion-disk canvas. */
body.home-v4 .hero > .h-hero-eyebrow,
body.home-v4 .hero > .h-hero-title,
body.home-v4 .hero > .h-hero-deck,
body.home-v4 .hero > .h-hero-cta { position: relative; z-index: 1; }

/* The scroll cue is the exception: it must be position:absolute so the base
   rule can centre it at the bottom of the hero (left:50% + translateX(-50%)).
   relative here would cancel the centring and fling it to the right. */
body.home-v4 .hero > .hero-scroll { position: absolute; z-index: 1; }

/* Legibility over the accretion disk: wrap the type in a soft void halo
   so it reads as glowing in space rather than fighting the bright ring. */
body.home-v4 .h-hero-title {
    text-shadow:
        0 0 28px rgba(6, 6, 10, 0.72),
        0 2px 10px rgba(6, 6, 10, 0.6);
}
body.home-v4 .h-hero-eyebrow,
body.home-v4 .h-hero-deck {
    text-shadow: 0 0 18px rgba(6, 6, 10, 0.72);
}

[data-theme="light"] .singularity-canvas {
    /* The shader is tuned for the void; in light mode keep it as a quiet
       cosmic accent rather than a full-bleed centrepiece. */
    opacity: 0.55;
    mix-blend-mode: multiply;
}

/* In light mode the type is dark, so swap the void halo for a paper halo —
   keeps the headline legible over the disk without a dark smudge. */
[data-theme="light"] body.home-v4 .h-hero-title {
    text-shadow:
        0 0 26px rgba(250, 250, 247, 0.85),
        0 2px 8px rgba(250, 250, 247, 0.7);
}
[data-theme="light"] body.home-v4 .h-hero-eyebrow,
[data-theme="light"] body.home-v4 .h-hero-deck {
    text-shadow: 0 0 16px rgba(250, 250, 247, 0.85);
}

@media (prefers-reduced-motion: reduce) {
    .singularity-canvas { animation: none; opacity: 1; }
}

/* ------------------------------------------------------------------
   AMBIENT SINGULARITY — subpage header mode.
   Downloads / Changelog / case studies carry the same black hole, but
   as a restrained backdrop behind the page title rather than a full
   centrepiece. The intro band becomes a tall stage so the hole has
   room to breathe; content is vertically centred above it. */
[data-singularity] {
    position: relative;
    overflow: clip;
}
[data-singularity] > *:not(.singularity-canvas) { position: relative; z-index: 1; }

.h-page-intro[data-singularity] {
    min-height: 64vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Case-study header band: a contained stage so the long-form article
   that follows still leads with the same gravitational signature. */
.case-head[data-singularity] {
    min-height: 46vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin: 8px 0 44px;
    padding: 48px 0 56px;
}

.singularity-canvas.is-ambient {
    /* Pull the hole toward the upper third of the band so the heading
       sits over the disk's brightest arc, not the void. */
    -webkit-mask-image: radial-gradient(ellipse 72% 96% at 50% 46%, #000 34%, transparent 80%);
            mask-image: radial-gradient(ellipse 72% 96% at 50% 46%, #000 34%, transparent 80%);
    opacity: 0;
    animation: singularity-ambient-in 1.2s var(--ease) 0.2s forwards;
}
@keyframes singularity-ambient-in { to { opacity: 0.92; } }

/* Heading legibility over the ambient disk (dark + light themes). */
[data-singularity] .h-display,
[data-singularity] .case-title {
    text-shadow:
        0 0 30px rgba(6, 6, 10, 0.74),
        0 2px 12px rgba(6, 6, 10, 0.6);
}
[data-singularity] .h-eyebrow,
[data-singularity] .case-eyebrow,
[data-singularity] .h-deck,
[data-singularity] .case-deck {
    text-shadow: 0 0 18px rgba(6, 6, 10, 0.72);
}
[data-theme="light"] .singularity-canvas.is-ambient {
    opacity: 0.55;
    mix-blend-mode: multiply;
    animation-name: singularity-ambient-in-light;
}
@keyframes singularity-ambient-in-light { to { opacity: 0.55; } }
[data-theme="light"] [data-singularity] .h-display,
[data-theme="light"] [data-singularity] .case-title {
    text-shadow:
        0 0 26px rgba(250, 250, 247, 0.85),
        0 2px 8px rgba(250, 250, 247, 0.7);
}
[data-theme="light"] [data-singularity] .h-eyebrow,
[data-theme="light"] [data-singularity] .case-eyebrow,
[data-theme="light"] [data-singularity] .h-deck,
[data-theme="light"] [data-singularity] .case-deck {
    text-shadow: 0 0 16px rgba(250, 250, 247, 0.85);
}
@media (max-width: 700px) {
    .h-page-intro[data-singularity] { min-height: 52vh; }
    .case-head[data-singularity] { min-height: 40vh; }
}

/* ==================================================================
   RINGDOWN — a single gravitational-wave ripple passes through each
   section head as it enters, then stops. No infinite motion.
   ================================================================== */
.h-section-head { position: relative; }

.h-section-head::before,
.h-section-head::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 42%;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent);
    transform: translate(-50%, -50%) scale(0);
    opacity: 0;
    pointer-events: none;
    z-index: -1;
}

.h-section-head.is-rung::before { animation: h-ringdown 1.7s var(--ease) forwards; }
.h-section-head.is-rung::after  { animation: h-ringdown 1.7s var(--ease) 0.16s forwards; }

@keyframes h-ringdown {
    0%   { opacity: 0.5; transform: translate(-50%, -50%) scale(0); border-width: 2px; }
    14%  { opacity: 0.45; }
    100% { opacity: 0;   transform: translate(-50%, -50%) scale(46); border-width: 0.2px; }
}

/* ==================================================================
   SPAGHETTIFICATION — section headings stream in from the void,
   each glyph stretched toward the singularity then snapping to rest.
   hud.js wraps glyphs in .h-spag-ch and toggles .is-in on the heading.
   ================================================================== */
/* Word wrappers keep each word whole at the wrap boundary (the glyphs
   inside are inline-block and would otherwise offer mid-word break points). */
.h-spag .h-spag-word { display: inline-block; white-space: nowrap; }

.h-spag .h-spag-ch {
    display: inline-block;
    opacity: 0;
    transform: translateY(-0.55em) scaleY(2.4) scaleX(0.7);
    transform-origin: 50% 0%;
    filter: blur(3px);
    will-change: transform, opacity, filter;
}
.h-spag.is-in .h-spag-ch {
    opacity: 1;
    transform: none;
    filter: blur(0);
    transition:
        opacity 0.5s var(--ease),
        transform 0.7s var(--ease),
        filter 0.5s var(--ease);
    transition-delay: var(--spag-d, 0s);
}
/* Preserve whitespace collapse for space glyphs. */
.h-spag .h-spag-sp { display: inline-block; white-space: pre; }

/* When a heading word uses a gradient text-clip (e.g. .h-display-fade),
   splitting it into per-glyph spans would orphan the parent's clipped
   background and render the glyphs transparent. Re-inherit the gradient
   onto each glyph so the faded word survives spaghettification. */
.h-display-fade .h-spag-word,
.h-display-fade .h-spag-ch {
    background: inherit;
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

/* ==================================================================
   DISK-GLINT — on hover, a card's border catches the accretion-disk
   Doppler gradient: deep crimson on one edge, magenta plasma on the
   other. The rarest accent (relativistic cyan) is reserved for the
   single primary contact card only.
   ================================================================== */
.h-arch-card,
.project-card,
.h-road-card,
.h-contact-card { position: relative; }

.h-arch-card::after,
.project-card::after,
.h-road-card::after,
.h-contact-card::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(115deg,
        var(--crimson) 0%,
        transparent 38%,
        transparent 62%,
        var(--plasma) 100%);
    /* Show the gradient on the 1px border ring only (mask-composite cut-out). */
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
            mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.4s var(--ease);
    pointer-events: none;
    z-index: 2;
}

.h-arch-card:hover::after,
.project-card:hover::after,
.h-road-card:hover::after,
.h-contact-card:hover::after { opacity: 0.9; }

/* The single primary contact card earns the rare cyan blue-shift glint. */
.h-contact-card:first-child::after {
    background: linear-gradient(115deg,
        var(--crimson) 0%,
        transparent 36%,
        transparent 60%,
        var(--relativistic) 100%);
}

/* ==================================================================
   TELEMETRY HUD — a thin instrument overlay framing the page as a
   sensor pointed at an unseen, read-only object. This is the thread
   that ties "universe / black hole" to "cheat coder": you don't see
   the tool, you read its gravitational effect. Built by hud.js.
   ================================================================== */
.hud {
    position: fixed;
    inset: 0;
    z-index: 90;
    pointer-events: none;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.08em;
    color: color-mix(in srgb, var(--fg-3) 90%, transparent);
    opacity: 0;
    animation: hud-in 1s var(--ease) 1.2s forwards;
}
@keyframes hud-in { to { opacity: 1; } }

.hud-cluster {
    position: absolute;
    display: flex;
    flex-direction: column;
    gap: 5px;
    line-height: 1.3;
    text-transform: uppercase;
}
.hud-tl { top: 88px; left: 32px; }
.hud-br { bottom: 34px; right: 32px; text-align: right; align-items: flex-end; }

.hud-row { display: flex; gap: 8px; align-items: baseline; white-space: nowrap; }
.hud-key { color: var(--fg-4); }
.hud-val { color: color-mix(in srgb, var(--accent) 85%, var(--fg-2)); font-variant-numeric: tabular-nums; }
.hud-val.is-cyan { color: var(--relativistic); }     /* used once */

.hud-title {
    display: flex;
    align-items: center;
    gap: 7px;
    color: var(--fg-2);
    margin-bottom: 3px;
}
.hud-title .hud-glyph {
    width: 7px; height: 7px; border-radius: 50%;
    border: 1px solid var(--accent);
    box-shadow: 0 0 6px var(--accent);
}

/* The HUD is signal, not noise — retire it on small / touch screens and
   keep it from ever crowding real content. */
@media (max-width: 1100px) { .hud { display: none; } }

[data-theme="light"] .hud { color: var(--fg-3); }

/* ==================================================================
   SUBPAGE CARD MODERNISATION — carry the Singularity motion language
   (disk-glint borders, infall lift, accretion markers) onto the
   Downloads cards, the Changelog timeline, and the case-study grids
   so the inner pages read as the same high-end product as the home.
   ================================================================== */

/* ---- Downloads cards: disk-glint border + infall lift ------------- */
.h-dl-card::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(125deg,
        var(--crimson) 0%,
        transparent 40%,
        transparent 60%,
        var(--plasma) 100%);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
            mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.45s var(--ease);
    pointer-events: none;
    z-index: 3;
}
.h-dl-card:hover {
    transform: translateY(-5px);
    box-shadow: 0 34px 70px -34px rgba(0, 0, 0, 0.72);
}
.h-dl-card:hover::after { opacity: 0.85; }

/* The flagship card keeps its accent glow but still earns the brighter
   plasma-edged glint and a gentler lift (it's a big surface). */
.h-dl-card-feature::after {
    background: linear-gradient(125deg,
        color-mix(in oklab, var(--accent) 80%, var(--crimson)) 0%,
        transparent 42%,
        transparent 58%,
        var(--plasma) 100%);
}
.h-dl-card-feature:hover { transform: translateY(-3px); }

/* ---- Changelog timeline: accretion markers + hover glint ---------- */
.h-cl-item {
    transition: background 0.35s var(--ease), transform 0.45s var(--ease);
}
.h-cl-item:hover { transform: translateX(3px); }

/* A faint disk-glint catches the left rail of the entry on hover. */
.h-cl-item::after {
    content: '';
    position: absolute;
    left: 0; top: 8%; bottom: 8%;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--crimson), var(--plasma));
    opacity: 0;
    transform: scaleY(0.4);
    transform-origin: 50% 50%;
    transition: opacity 0.4s var(--ease), transform 0.5s var(--ease);
    pointer-events: none;
}
.h-cl-item:hover::after { opacity: 0.9; transform: scaleY(1); }

/* The marker becomes a little accretion point; the newest release (the
   first item) gets a slow live pulse — everything else stays still. */
/* Marker stays position:absolute (set above) so it's out of the grid flow —
   otherwise it becomes a grid item and pushes the content div into the narrow
   220px column. z-index is already applied by the base rule. */
.h-cl-item:hover .h-cl-marker {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent);
}
.h-cl-item:first-child .h-cl-marker::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent);
    animation: h-cl-pulse 2.8s var(--ease) infinite;
    pointer-events: none;
}
@keyframes h-cl-pulse {
    0%   { transform: scale(0.6); opacity: 0.8; }
    70%  { transform: scale(2.4); opacity: 0; }
    100% { transform: scale(2.4); opacity: 0; }
}

/* ---- Case-study grids: hover lift on the feature tiles ------------ */
.sair-cat {
    position: relative;
    transition: background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.sair-cat::after {
    content: '';
    position: absolute;
    left: 0; top: 0;
    width: 100%; height: 2px;
    background: linear-gradient(90deg, var(--crimson), var(--plasma));
    transform: scaleX(0);
    transform-origin: 0 50%;
    opacity: 0;
    transition: transform 0.5s var(--ease), opacity 0.4s var(--ease);
}
.sair-cat:hover {
    background: color-mix(in oklab, var(--accent) 4%, var(--bg-elev));
    box-shadow: inset 0 0 60px -30px color-mix(in oklab, var(--accent) 50%, transparent);
}
.sair-cat:hover::after { transform: scaleX(1); opacity: 0.9; }

@media (prefers-reduced-motion: reduce) {
    .h-dl-card:hover,
    .h-cl-item:hover { transform: none; }
    .h-cl-item:first-child .h-cl-marker::after { animation: none; }
}

/* Light-theme glints stay legible against paper. */
[data-theme="light"] .h-dl-card:hover {
    box-shadow: 0 30px 60px -34px rgba(20, 16, 18, 0.32);
}

/* ==================================================================
   CASE-STUDY BODY — bring the long-form pages up to the same finish.
   The article body used flat, pre-system styling with no motion; this
   block gives it the Infall scroll-reveal, gradient accents drawn from
   the accretion-disk palette, and tactile hover on every surface.
   home-anim.js observes these blocks and toggles .is-in on enter.
   ================================================================== */

/* ---- Infall reveal for the long-form blocks ---------------------- */
.case-meta,
.case-hero-frame,
.case-section,
.case-quote,
.case-gallery {
    opacity: 0;
    transform: translateY(26px) scale(0.99);
    transition:
        opacity 0.7s var(--ease),
        transform 0.85s var(--ease);
    will-change: opacity, transform;
}
.case-meta.is-in,
.case-hero-frame.is-in,
.case-section.is-in,
.case-quote.is-in,
.case-gallery.is-in {
    opacity: 1;
    transform: none;
}

/* The text inside a section settles a beat after the block arrives, so
   the heading leads and the body follows — a subtle internal cascade. */
.case-section.is-in > .case-section-label,
.case-section.is-in > .case-section-h,
.case-section.is-in .case-pair > * { animation: case-rise 0.8s var(--ease) both; }
.case-section.is-in > .case-section-h { animation-delay: 0.06s; }
.case-section.is-in > p { animation: case-rise 0.8s var(--ease) 0.1s both; }
@keyframes case-rise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}

/* ---- Section label: a small accretion tick ----------------------- */
.case-section-label {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
.case-section-label::before {
    content: '';
    width: 18px; height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--crimson), var(--plasma));
}

/* ---- Meta grid: gradient crown + per-cell hover ------------------ */
.case-meta { position: relative; }
.case-meta::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 2px;
    background: linear-gradient(90deg,
        transparent 0%, var(--crimson) 22%, var(--plasma) 78%, transparent 100%);
    opacity: 0.7;
    z-index: 1;
}
.case-meta-cell {
    transition: background 0.35s var(--ease);
}
.case-meta-cell:hover {
    background: color-mix(in oklab, var(--accent) 6%, var(--bg-elev));
}
.case-meta-cell:hover .case-meta-cell-value { color: var(--accent); }
.case-meta-cell-value { transition: color 0.3s var(--ease); }

/* ---- Hero frame: disk-glint border + slow zoom ------------------- */
.case-hero-frame { position: relative; }
.case-hero-frame::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(125deg,
        var(--crimson) 0%, transparent 42%, transparent 58%, var(--plasma) 100%);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
            mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.45s var(--ease);
    pointer-events: none;
    z-index: 2;
}
.case-hero-frame:hover::after { opacity: 0.9; }
.case-hero-frame img { transition: transform 0.9s var(--ease); }
.case-hero-frame:hover img { transform: scale(1.03); }

/* ---- Gallery tiles: lift + glint --------------------------------- */
.case-gallery img {
    transition: transform 0.5s var(--ease), border-color 0.4s var(--ease);
}
.case-gallery img:hover {
    transform: translateY(-4px);
    border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
}

/* ---- Pull-quote: gradient bar, void tint, hanging mark ----------- */
.case-quote {
    position: relative;
    border-left: 0;
    padding: 6px 0 6px 30px;
    isolation: isolate;
}
.case-quote::before {
    content: '';
    position: absolute;
    left: 0; top: 4px; bottom: 4px;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--crimson), var(--plasma));
}
.case-quote::after {
    content: '\201C';
    position: absolute;
    left: 16px; top: -0.35em;
    font-family: var(--font-serif);
    font-size: 4.2em;
    line-height: 1;
    color: color-mix(in srgb, var(--accent) 16%, transparent);
    z-index: -1;
    pointer-events: none;
}

/* ---- List markers: a tiny gradient dash -------------------------- */
.case-section ul li::before {
    background: linear-gradient(90deg, var(--crimson), var(--plasma));
}

/* ---- Reduced motion: everything visible, nothing moves ----------- */
@media (prefers-reduced-motion: reduce) {
    .case-meta,
    .case-hero-frame,
    .case-section,
    .case-quote,
    .case-gallery {
        opacity: 1 !important;
        transform: none !important;
        transition: none;
    }
    .case-section.is-in > *,
    .case-section.is-in .case-pair > * { animation: none !important; }
    .case-hero-frame:hover img,
    .case-gallery img:hover { transform: none; }
}

/* ==================================================================
   404 — "past the event horizon". Reuses the centred ambient-hole
   page-intro, just taller and with a centred call-to-action.
   ================================================================== */
.h-404[data-singularity] {
    min-height: 82vh;
    align-items: center;
}
.h-404 .h-deck { max-width: 56ch; }
.h-404-cta {
    justify-content: center;
    margin-top: 36px;
}
@media (max-width: 720px) {
    .h-404[data-singularity] { min-height: 76vh; }
}

/* ==================================================================
   READING-PROGRESS — a thin accretion line across the very top edge
   that fills as the page is scrolled. Element injected by home-anim.js
   (so it only appears when motion is allowed).
   ================================================================== */
.read-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 300;
    pointer-events: none;
    background: transparent;
}
.read-progress-fill {
    height: 100%;
    width: 100%;
    transform: scaleX(0);
    transform-origin: left center;
    background: linear-gradient(90deg, var(--crimson), var(--plasma) 55%, var(--relativistic));
    box-shadow: 0 0 12px rgba(255, 31, 107, 0.55);
    will-change: transform;
}

/* ==================================================================
   FOCUS-VISIBLE — a consistent, on-brand keyboard focus ring. Only
   shows for keyboard navigation (not mouse clicks), so it never
   intrudes on pointer users. WCAG 2.4.7.
   ================================================================== */
:focus-visible {
    outline: 2px solid var(--core);
    outline-offset: 3px;
    border-radius: 4px;
}
a:focus-visible,
button:focus-visible,
.nav-link:focus-visible,
.nav-btn:focus-visible,
.h-btn:focus-visible,
.contact-item:focus-visible,
.cmdk-input:focus-visible,
.project-card:focus-visible,
.h-dl-card:focus-visible {
    outline: 2px solid var(--core);
    outline-offset: 3px;
    box-shadow: 0 0 0 4px rgba(255, 45, 45, 0.18);
}
.cmdk-input:focus-visible { outline-offset: 0; border-radius: 6px; }
