/* © 2026 Vishwa Pipaliya — Maeven Design. All rights reserved. */
/* ============================================================
   Maeven Design — style.css
   ============================================================ */
:root {
    /* primaries */
    --blue: #0052FF;
    --teal: #00C8A3;
    --gradient: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);

    /* backgrounds */
    --bg: #F8FAFB;
    --bg-warm: #F1F5F4;
    --bg-navy: #333A4E;
    --bg-gray: #EAECF1;
    --surface: #0D1B2A;

    /* text */
    --ink: #0D1B2A;
    /* Both pass WCAG AA (4.5:1) on every light background the site uses —
       #F8FAFB, white, the #EAECF1 grey and Bloom's tints. --muted was
       #8B99A8 (2.5–2.9:1); --ink-soft moved a step darker with it so body
       copy stays distinct from the small labels. */
    --ink-soft: #465564;
    --muted: #5C6B7B;

    /* borders */
    --line: rgba(13, 27, 42, 0.10);
    --line-strong: rgba(13, 27, 42, 0.20);

    /* functional */
    --accent:#0D1B2A;
    --accent-glow: rgba(0, 82, 255, 0.08);
    --teal-soft: rgba(0, 200, 163, 0.12);
}

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

html, body {
    width: 100%; height: 100%;
    background: var(--bg);
    color: var(--ink);
    scroll-behavior: smooth;
    font-family: 'Fraunces', Georgia, serif;
    -webkit-font-smoothing: antialiased;
}



#work{
    scroll-margin-top: 100px;
}

/* Landing page only: smooth anchor scrolling is done in script.js. A CSS
   scroll-behavior here animates ScrollTrigger's own scroll restoration on
   refresh, which reads as the page lurching. */
html.landing { scroll-behavior: auto; -webkit-tap-highlight-color: transparent; }

/* Lenis (desktop wheel smoothing) */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ============================================================
   NEW (1/2) — TOP SCROLL-PROGRESS BAR
   Fixed hairline across the top; script.js scales it on scroll.
   ============================================================ */
.progress {
    position: fixed;
    top: 0; left: 0;
    height: 2px;
    width: 100%;
    z-index: 999;
    background: var(--ink);
    /* Scaled, not resized, from script.js — no layout per frame. */
    transform: scaleX(0);
    transform-origin: 0 50%;
    will-change: transform;
}
/* ── NAV ──
   Injected by /assets/nav.js on every page.
   One floating glass bar in two tones — [data-tone="light"] over light
   backgrounds, [data-tone="dark"] over dark ones — chosen by nav.js from what
   is actually behind it, so it stays legible everywhere.
   Desktop: logo · links · Resume; folds to logo · Resume on scroll (.collapsed).
   Phones: logo · Menu, opening a full-screen .nav-menu.
   ────────────────────────────────────────────────────────────── */

/* The previous generic rule, kept only for other <nav> elements (the MSC
   case study's mock navbar leans on it), so they render exactly as before.
   :where() keeps it at zero specificity — below their own class rules, as
   the bare `nav` selector was; a plain :not() outranked them and pinned the
   mock navbar to the top of the screen. */
:where(nav:not(.site-nav)) {
    position: fixed;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 100;
    display: flex;
    align-items: center;
    gap: 2rem;
    padding: 0.4rem 0.5rem 0.4rem 0.75rem;
    background: rgba(248, 250, 251, 0.65);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-radius: 999px;
    width: fit-content;
    transition: gap 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.site-nav {
    /* tone tokens — light glass by default */
    --nav-bg: rgba(248, 250, 251, 0.72);
    --nav-border: rgba(13, 27, 42, 0.10);
    --nav-fg: #0D1B2A;
    --nav-fg-soft: rgba(13, 27, 42, 0.7);    /* 4.5:1+ on the light glass */
    --nav-glide: rgba(13, 27, 42, 0.07);
    --nav-shadow: 0 8px 30px rgba(13, 27, 42, 0.08);
    --nav-resume-bg: #F8FAFB;
    --nav-resume-fg: #0D1B2A;
    --ease: cubic-bezier(0.65, 0, 0.35, 1);

    position: fixed;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding: 0.35rem 0.35rem 0.35rem 1rem;
    border-radius: 999px;
    background: var(--nav-bg);
    border: 1px solid var(--nav-border);
    box-shadow: var(--nav-shadow);
    backdrop-filter: blur(16px) saturate(1.4);
    -webkit-backdrop-filter: blur(16px) saturate(1.4);
    color: var(--nav-fg);
    font-family: 'Inter', sans-serif;
    width: fit-content;
    transition: gap 0.5s var(--ease), background-color 0.45s ease, border-color 0.45s ease,
                box-shadow 0.45s ease, color 0.45s ease;
}

.site-nav[data-tone="dark"] {
    --nav-bg: rgba(13, 17, 26, 0.55);
    --nav-border: rgba(255, 255, 255, 0.14);
    --nav-fg: #FFFFFF;
    --nav-fg-soft: rgba(255, 255, 255, 0.62);
    --nav-glide: rgba(255, 255, 255, 0.14);
    --nav-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
    --nav-resume-bg: #0D1B2A;
    --nav-resume-fg: #FFFFFF;
}

.site-nav.collapsed { gap: 0.6rem; }

/* ── Logo — the mark is inline SVG in currentColor, so it follows the tone ── */
.site-nav .nav-logo {
    display: flex;
    align-items: center;
    color: var(--nav-fg);
    text-decoration: none;
    flex-shrink: 0;
    transition: color 0.45s ease;
}
.site-nav .nav-mark {
    width: 15px;
    height: 15px;
    display: block;
    transition: transform 0.6s var(--ease);
}
.site-nav .nav-logo:hover .nav-mark { transform: rotate(-12deg) scale(1.08); }

.site-nav .nav-logo-text {
    font-style: italic;
    font-weight: 500;
    font-size: 14px;
    letter-spacing: -0.01em;
    display: inline-block;
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    white-space: nowrap;
    margin-left: 0;
    transition: max-width 0.5s var(--ease), opacity 0.3s ease, margin 0.5s var(--ease);
}
.site-nav.collapsed .nav-logo-text {
    max-width: 120px;
    opacity: 1;
    margin-left: 8px;
}

/* ── Rolling labels: the text rolls up and an identical copy rolls in ── */
.site-nav .nav-roll {
    display: inline-flex;
    flex-direction: column;
    height: 1.25em;
    line-height: 1.25em;
    overflow: hidden;
    vertical-align: middle;
}
.site-nav .nav-roll > span { transition: transform 0.5s var(--ease); }
.site-nav a:hover .nav-roll > span,
.site-nav a:focus-visible .nav-roll > span,
.site-nav .nav-menu-btn:hover .nav-roll > span { transform: translateY(-100%); }

/* ── Links + the gliding highlight ── */
.site-nav .nav-links {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.1rem;
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    max-width: 320px;
    min-width: 0;
    opacity: 1;
    transition: max-width 0.5s var(--ease), opacity 0.3s ease;
}
.site-nav.collapsed .nav-links {
    max-width: 0;
    opacity: 0;
    transition: max-width 0.45s var(--ease) 0.05s, opacity 0.2s ease;
}

.site-nav .nav-glide {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 0;
    border-radius: 999px;
    background: var(--nav-glide);
    opacity: 0;
    pointer-events: none;
    transition: transform 0.55s var(--ease), width 0.55s var(--ease), opacity 0.3s ease, background-color 0.45s ease;
}
.site-nav .nav-glide.no-anim { transition: none; }

.site-nav .nav-links a {
    position: relative;
    z-index: 1;
    display: block;
    padding: 0.45rem 0.85rem;
    font-size: 0.85rem;
    font-weight: 400;
    color: var(--nav-fg-soft);
    text-decoration: none;
    white-space: nowrap;
    border-radius: 999px;
    transition: color 0.3s ease;
}
.site-nav .nav-links a:hover,
.site-nav .nav-links a.active { color: var(--nav-fg); }
.site-nav .nav-links a.active { font-weight: 500; }

/* ── Resume — your animated gradient ring, now magnetic with an arrow ── */
.site-nav .nav-resume-wrap {
    flex-shrink: 0;
    border-radius: 999px;
    padding: 1.5px;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    animation: gradient-shift 10s linear infinite;
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
    will-change: transform;
}
.site-nav .nav-resume-wrap:hover { animation-play-state: paused; }

.site-nav .nav-resume {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.68rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-decoration: none;
    padding: 0.45rem 0.95rem 0.45rem 1.05rem;
    border-radius: 999px;
    background: var(--nav-resume-bg);
    color: var(--nav-resume-fg);
    transition: background-color 0.3s ease, color 0.3s ease;
}
.site-nav .nav-resume-wrap:hover .nav-resume { background: #0D1B2A; color: #fff; }
.site-nav[data-tone="dark"] .nav-resume-wrap:hover .nav-resume { background: #fff; color: #0D1B2A; }

/* An SVG arrow drawn centred in its own box, so it turns about its true
   centre: ↗ at rest, → on hover. (A text ↗ sits off-centre in its line box
   and floated above the label once rotated.) */
.site-nav .nav-resume-arrow {
    display: block;
    width: 11px;
    height: 11px;
    flex-shrink: 0;
    transform: rotate(-45deg);
    transition: transform 0.45s var(--ease);
}
.site-nav .nav-resume-wrap:hover .nav-resume-arrow { transform: rotate(0deg) translateX(1px); }

/* ── Menu button (phones only) ── */
.site-nav .nav-menu-btn {
    display: none;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.55rem 0.5rem 0.95rem;
    border: 0;
    border-radius: 999px;
    background: var(--nav-fg);
    color: var(--nav-resume-bg);
    font: 500 0.68rem/1 'Inter', sans-serif;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background-color 0.45s ease, color 0.45s ease;
}
.site-nav .nav-burger {
    position: relative;
    width: 18px;
    height: 18px;
    border-radius: 50%;
}
.site-nav .nav-burger i {
    position: absolute;
    left: 3px;
    right: 3px;
    height: 1.5px;
    border-radius: 2px;
    background: currentColor;
    transition: transform 0.5s var(--ease), top 0.5s var(--ease);
}
.site-nav .nav-burger i:nth-child(1) { top: 6px; }
.site-nav .nav-burger i:nth-child(2) { top: 11px; }
.site-nav.menu-open .nav-burger i:nth-child(1) { top: 8.5px; transform: rotate(45deg); }
.site-nav.menu-open .nav-burger i:nth-child(2) { top: 8.5px; transform: rotate(-45deg); }

.site-nav :focus-visible { outline: 2px solid #00C8A3; outline-offset: 2px; }

/* ── Full-screen menu (phones) ── */
.nav-menu {
    position: fixed;
    inset: 0;
    z-index: 998;
    display: none;
    background: #0D1B2A;
    color: #FFFFFF;
    clip-path: inset(0 0 100% 0 round 0 0 40px 40px);
    transition: clip-path 0.7s cubic-bezier(0.76, 0, 0.24, 1);
}
.nav-menu.is-open { clip-path: inset(0 0 0 0 round 0); }

.nav-menu-inner {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 7rem 1.5rem calc(2.25rem + env(safe-area-inset-bottom, 0px));
}
.nav-menu-eyebrow {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}
.nav-menu-links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.nav-menu-links li { overflow: hidden; padding-bottom: 0.1em; }
.nav-menu-links a {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    color: #FFFFFF;
    text-decoration: none;
    transform: translateY(110%);
    transition: transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-menu.is-open .nav-menu-links a {
    transform: none;
    transition-delay: calc(0.25s + var(--i) * 0.07s);
}
.nav-menu-num {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.4);
}
.nav-menu-word {
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 300;
    font-size: clamp(2.6rem, 13vw, 3.6rem);
    line-height: 1.05;
    letter-spacing: -0.03em;
}
.nav-menu-word em {
    font-style: italic;
    font-weight: 500;
    background: linear-gradient(90deg, #4D86FF, #00C8A3, #4D86FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    animation: gradient-shift 10s linear infinite;
    padding: 0 0.1em 0.12em 0;
}
.nav-menu-foot {
    display: flex;
    gap: 0.75rem;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.5s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-menu.is-open .nav-menu-foot {
    opacity: 1;
    transform: none;
    transition-delay: 0.5s;
}
.nav-menu-foot a {
    flex: 1;
    text-align: center;
    padding: 0.95rem 1rem;
    border-radius: 999px;
    font: 500 0.72rem/1 'Inter', sans-serif;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    color: #FFFFFF;
    border: 1px solid rgba(255, 255, 255, 0.2);
}
.nav-menu-foot .nav-menu-resume {
    border: 0;
    color: #0D1B2A;
    background: linear-gradient(90deg, #7FA8FF, #5FE3C7);
}

/* Scroll is locked in nav.js by pinning <body> at its offset — overflow:hidden
   here would snap these 100%-tall pages back to the top. */
html.nav-menu-lock { overscroll-behavior: none; }

/* ── Phones: logo · Menu, and the menu itself ── */
@media (max-width: 768px) {
    .site-nav {
        gap: 1rem;
        padding: 0.3rem 0.3rem 0.3rem 0.95rem;
    }
    .site-nav .nav-links,
    .site-nav .nav-resume-wrap { display: none; }
    .site-nav .nav-menu-btn { display: inline-flex; }
    /* The wordmark always shows on phones — there are no links beside it. */
    .site-nav .nav-logo-text { max-width: 120px; opacity: 1; margin-left: 8px; }
    .nav-menu { display: block; }
}

@media (prefers-reduced-motion: reduce) {
    .site-nav .nav-roll > span,
    .site-nav .nav-glide,
    .site-nav .nav-mark,
    .nav-menu,
    .nav-menu-links a,
    .nav-menu-foot { transition: none; }
    .site-nav .nav-resume-wrap,
    .nav-menu-word em { animation: none; }
}

/* ── CANVAS ──
   The particle scene, fixed behind the landing page's content. */
#particles {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 0;
}

/* ── HERO ── */
.hero {
    position: relative;
    z-index: 1;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 2rem 4rem;
}

.hero-top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}
.brand {
    font-family: 'Fraunces', serif;
    font-style: italic;
    font-weight: 500;
    font-size: 1.1rem;
    color: var(--ink);
}
.nav-hint {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--muted);
}

.hero-main {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    align-items: center;
    text-align: center;
}
.eyebrow {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 1rem;
}
.eyebrow::before {
    content: '';
    width: 28px; height: 1px;
    background: var(--ink);
    flex-shrink: 0;
}
.hero-title {
    font-size: clamp(2rem, 7vw, 6.5rem);
    line-height: 0.93;
    font-weight: 300;
    letter-spacing: -0.03em;
    max-width: 1000px;
}
.hero-title em {
    display: inline-block;
    font-style: italic;
    font-weight: 600;
    letter-spacing: -0.01em;
    padding-right: 0.12em;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
}

@keyframes gradient-shift {
    0%   { background-position: 0% 50%; }
    100% { background-position: -200% 50%; }
}

.hero-subtitle {
    font-size: clamp(1rem, 4vw, 4rem);
    line-height: 0.93;
    font-weight: 100;
    letter-spacing: -0.03em;
    max-width: 1000px;
}

.hero-bottom {
    display: flex;
    justify-content: center;
    gap: 2rem;
}
.lede {
    max-width: 400px;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--ink-soft);
}
.scroll-cue {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--muted);
    transform: rotate(0deg);
    animation: bob 2.5s ease-in-out infinite;
}

@keyframes bob {
    0%, 100% { transform: rotate(0deg) translateY(0);   opacity: 0.55; }
    50%       { transform: rotate(0deg) translateY(-20px); opacity: 1;    }
}

.scroll-cue-projects {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--muted);
    position: absolute;
    left: 50%;
    /* Below the hi-fi frame, following the edge script.js measures each
       frame into --frame-bottom. The frame rides a scroll-driven camera, so
       its on-screen size isn't its layout size and can't be derived here —
       a flat 48rem sat inside the frame on anything bigger than a 15" laptop,
       and even solving the static geometry still fell ~50px short once the
       camera zoom was in play. The fallback matches the frame's untransformed
       bottom, for the first paint before the loop has run. The outer min()
       keeps the cue on screen if the frame reaches the bottom of a short
       window. */
    top: min(calc(var(--frame-bottom, calc(50% + min(300px, 15.75vw))) + 3.5rem),
             calc(100% - 3.5rem));
    /* `translate`, not `transform`: the bob animation owns transform, and it
       was wiping out the centring (hence the old 44% eyeballed offset). */
    translate: -50% 0;
    white-space: nowrap;
    animation: bob 2.5s ease-in-out infinite;
}

/* ── STAGE NAVIGATOR ──
   The four stage names, with a gradient underline that stretches from one to
   the next as you scroll (script.js measures the words and sets --a / the
   line's transform). Laid out as a row; desktop turns the whole row 90° into
   the left margin, which is why the JS can stay axis-agnostic. */
.stage-nav {
    position: fixed;
    z-index: 2;
    display: flex;
    align-items: baseline;
    padding-bottom: 0.7rem;
    opacity: 0;
    pointer-events: none;
    will-change: opacity;
    /* Desktop: rotated to read top-to-bottom, centred on the viewport's height. */
    left: 2.6rem;
    top: 50%;
    gap: 2.75rem;
    transform-origin: 0 0;
    transform: rotate(90deg) translateX(-50%);
}
.stage-nav-item {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.62rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--muted);
    color: color-mix(in srgb, var(--ink) calc(var(--a, 0) * 100%), var(--muted));
}
/* A 1px bar scaled to the measured span of the word(s) it sits under. */
.stage-nav-line {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 1px;
    height: 1.5px;
    border-radius: 1px;
    background: linear-gradient(90deg, var(--blue), var(--teal));
    transform-origin: left center;
    will-change: transform;
}

/* ── PROCESS SECTIONS ── */
.discover { position: relative; z-index: 1; }
.discover-track { height: 100vh; }

.design { position: relative; z-index: 1; }
.design-track { height: 100vh; }
.design-sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    padding: 0 4rem;
    gap: 4rem;
}
.step-text {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    max-width: 500px;
}
.step-number {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 0.85rem;
}
.step-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
}
.step-title {
    font-size: clamp(2.5rem, 5vw, 4.5rem);
    line-height: 1.02;
    font-weight: 300;
    letter-spacing: -0.025em;
    max-width: 700px;
}
.step-title em {
    font-style: italic;
    font-weight: 600;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
}

.step-body {
    font-size: 1.05rem;
    line-height: 1.65;
    color: var(--ink-soft);
}

.discover-sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    padding: 0 4rem;
    gap: 4rem;
}

.step-meta {
    display: flex;
    gap: 2rem;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--muted);
    padding-top: 1rem;
    border-top: 1px solid rgba(26, 25, 22, 0.15);
    margin-top: 0.5rem;
}
.step-meta span strong {
    display: block;
    color: var(--ink);
    font-weight: 500;
    letter-spacing: 0.12em;
    margin-top: 0.35rem;
}

.build { position: relative; z-index: 1; }
.build-track { height: 100vh; }
.build-sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    padding: 0 4rem;
    gap: 4rem;
}
.launch { position: relative; z-index: 1; }
.launch-track { height: 100vh; }
.launch-sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    padding: 0 4rem;
    gap: 4rem;
}

/* ── WORK / PROJECTS ── */
.work { position: relative; z-index: 1; }
.work-track { height: 500vh; }
.work-cue {
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding-top: 15vh;
    text-align: center;
    opacity: 0;
    pointer-events: none;
    z-index: 0;
}
.work-cue-eyebrow {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.25em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.75rem;
}
.work-cue-title {
    font-size: clamp(1.8rem, 3.5vw, 2.8rem);
    font-weight: 300;
    letter-spacing: -0.02em;
    color: var(--ink);
}
.work-cue-title em {
    font-style: italic;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
}

/* ── PROJECTS STRIP ── */
.projects-strip {
    position: fixed;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    pointer-events: none;
    opacity: 0;
    z-index: 5;
    will-change: transform;
}

.projects-strip.visible {
    opacity: 1;
    pointer-events: auto;
}


.proj-card {
    flex: 0 0 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    position: relative;
}
.proj-inner {
    position: absolute;
    background: var(--card-bg);
    border-radius: 16px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
    padding: 4rem;
    overflow: hidden;
}
.proj-left {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.2rem;
}
.proj-num {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.72rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--card-sub);
}
.proj-title {
    font-size: clamp(2rem, 4vw, 3.4rem);
    font-weight: 300;
    line-height: 1.05;
    letter-spacing: -0.02em;
    margin: 0;
    color: var(--card-fg);
}
.proj-title em {
    font-style: italic;
    color: var(--card-accent);
}
.proj-body {
    font-size: clamp(0.85rem, 1.2vw, 1rem);
    line-height: 1.6;
    color: var(--card-sub);
    margin: 0;
    max-width: 380px;
}
.proj-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.proj-tags span {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.6rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--card-sub);
    padding: 0.4rem 0.8rem;
    border: 1px solid color-mix(in srgb, var(--card-sub) 40%, transparent);
    border-radius: 999px;
}
.proj-cta {
    align-self: flex-start;
    margin-top: 0.5rem;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--card-bg);
    background: var(--card-accent);
    padding: 0.8rem 1.3rem;
    text-decoration: none;
    border-radius: 4px;
    transition: opacity 0.2s ease;
}
.proj-cta:hover { opacity: 0.85; }
.proj-right {
    display: flex;
    align-items: center;
    justify-content: center;
}
.proj-img {
    width: 100%;
    height: 90%;
    display: block;
    border-radius: 8px;
    overflow: hidden;   /* the shot drifts inside it as the strip slides */
}

.proj-img img {
    width: 100%;
    height: 100%;
    /*aspect-ratio: 16 / 9;*/
    object-fit: cover;
    object-position: center center;
    display: block;
    border-radius: 8px;
    transform: scale(var(--card-zoom, 1.18));
    will-change: transform;
}

/* ── CARD THUMBNAIL ZOOM (desktop) ──
   The frame is portrait, so a landscape shot is already cropped hard to the
   middle by object-fit: cover before any zoom — MSC's 4:3 render loses about
   half its width that way, and the default 1.18 was taking the monitor's
   right edge with it. Shown at its cover size instead.

   Safe to drop to 1 here precisely because of that mismatch: the scaled photo
   is still twice the frame's width, so the 12% parallax drift in script.js
   has far more overhang than it needs. A card whose photo roughly fits its
   frame would want to stay near 1.18, or the drift would pull an edge into
   view mid-slide. Tune by eye; script.js reads this when it sets the
   transform each frame. */
@media (min-width: 769px) {
    .proj-card:nth-child(1) .proj-img img { --card-zoom: 1; }
}

.proj-card { will-change: transform; }
.proj-inner { will-change: clip-path; }
.proj-left, .proj-right {
    opacity: 0;
    transition: opacity 0.15s ease;
}

/* ── GALLERY / MY OTHER DESIGN SYSTEM ── */

.gallery-track {
    height: 200vh;
}

.gallery {
    position: relative;
    z-index: 6;
    padding: 6vh 4rem 8vh;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    background: #EAECF1;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow: hidden;
    /*background: var(--gradient);*/
}

.gallery-header {
    text-align: center;
    margin-bottom: 4vh;
}
.gallery-title {
    font-size: clamp(1.4rem, 3vw, 2.4rem);
    font-weight: 300;
    letter-spacing: -0.02em;
    color: var(--ink);
    margin: 0 0 0.6rem;
}
.gallery-title em {
    font-style: italic;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
}
.gallery-sub {
    font-size: 0.85rem;
    line-height: 1.55;
    color: var(--ink-soft);
    max-width: 380px;
    margin: 0 auto;
}

/* NEW (2/2) — `perspective` here makes the polaroids' rotateX/rotateY (added in
   script.js on hover) read as real 3D depth instead of a flat skew. */
.polaroids {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
    max-width: 1000px;
    margin: 0 auto;
    padding: 0 1rem;
    perspective: 1200px;
}

.polaroid {
    background: #FFFFFF;
    padding: 8px 8px 34px;
    border-radius: 8px;
    box-shadow:
            0 2px 8px rgba(26, 25, 22, 0.08),
            0 6px 20px rgba(26, 25, 22, 0.06);
    transform: rotate(var(--rot, 0deg));
    transition: transform 0.4s cubic-bezier(0.2, 0, 0.2, 1),
    box-shadow 0.4s ease, z-index 0s;
    cursor: pointer;
    position: relative;
    z-index: 1;
    will-change: transform; /* NEW — smoother tilt */
}

/* Pop-up on hover (the JS tilt extends this with rotateX/rotateY).
   .is-active is the tap equivalent for touch, which never fires :hover —
   toggled in script.js. It skips the scale/z-index pop-up (the tight
   4-row mobile grid has no room to spare) and only swaps colour + label. */
.polaroid:hover {
    transform: rotate(0deg) scale(1.12);
    box-shadow:
            0 8px 28px rgba(26, 25, 22, 0.16),
            0 2px 8px rgba(26, 25, 22, 0.08);
    z-index: 10;
}

/* Grayscale → colour on hover */
.polaroid-img {
    width: 100%;
    display: block;
    border-radius: 6px;
    filter: grayscale(100%) contrast(1.05);
    transition: filter 0.5s ease;
    object-fit: cover;
    aspect-ratio: 4 / 4;
    height: auto;
}

.polaroid:hover .polaroid-img,
.polaroid.is-active .polaroid-img {
    filter: grayscale(0%) contrast(1);
}

.polaroid-label {
    position: absolute;
    bottom: 8px;
    left: 8px;
    right: 8px;
    text-align: center;
    font-family: 'Fraunces', serif;
    font-style: italic;
    font-size: 0.7rem;
    color: var(--ink-soft);
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.35s ease, transform 0.35s ease;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.polaroid:hover .polaroid-label,
.polaroid.is-active .polaroid-label {
    opacity: 1;
    transform: translateY(0);
}

/* Overlap: row 2 pulls up into row 1 */
.polaroid:nth-child(1) { margin-top: 1rem; }
.polaroid:nth-child(2) { margin-top: 1rem; }
.polaroid:nth-child(3) { margin-top: 1rem; }
.polaroid:nth-child(4) { margin-top: 1rem; }
.polaroid:nth-child(5) { margin-top: -2rem; z-index: 3; }
.polaroid:nth-child(6) { margin-top: -2rem; z-index: 2; }
.polaroid:nth-child(7) { margin-top: -2rem; z-index: 4; }
.polaroid:nth-child(8) { margin-top: -2rem; z-index: 1; }

@media (max-width: 900px) {
    .gallery { padding: 4vh 2rem 6vh; }

    /* Two columns means eight polaroids make four rows, not two. Rather than
       sizing them off the width and hoping the result clears 100vh — the
       gallery is a pinned, overflow-hidden screen, so anything that doesn't
       fit is simply cut off — the grid takes whatever height is left over and
       splits it four ways. Fits any phone without per-device tuning. */
    .polaroids {
        grid-template-columns: repeat(2, 1fr);
        /* minmax(0, 1fr), not 1fr: a bare 1fr is minmax(auto, 1fr), whose auto
           floor keeps each row at least as tall as the image's natural height,
           so the rows overflow instead of sharing the space. */
        grid-template-rows: repeat(4, minmax(0, 1fr));
        flex: 1;
        min-height: 0;
        gap: 10px;
    }

    /* The staggered offsets above are keyed to the four-column rows; at two
       columns they land on the wrong children and open a gap between rows one
       and two. The rotation already supplies the scattered look. */
    .polaroids .polaroid {
        margin-top: 0;
        display: flex;
        flex-direction: column;
        min-height: 0;
        /* Bottom chin roomy enough for a two-line caption to sit on the white
           frame instead of directly over the image — the image (flex: 1)
           gives up whatever this takes. */
        padding: 6px 6px 32px;
    }

    /* Fills whatever the row leaves after the frame's padding and crops to it,
       rather than dictating the row's height from its own proportions. */
    .polaroids .polaroid-img {
        flex: 1 1 0;
        min-height: 0;
        aspect-ratio: auto;
        object-fit: cover;
    }

    /* Absolutely positioned over the image, so keeping it doesn't cost the
       tight 4-row grid any space — it now reveals on tap via .is-active. */
    .polaroid-label {
        font-size: 0.6rem;
        white-space: normal;
        line-height: 1.2;
    }
}

/* ── ABOUT ── */
.about {
    position: sticky;
    z-index: 6;
    margin-top: -100vh;
    min-height: 100vh;
    border-radius: 58px;
    background: var(--bg);
    padding: 12vh 4rem;
    overflow: hidden;
    color: var(--ink);
}

.about-container {
    max-width: 1200px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 0.85fr 1.15fr;
    gap: 90px;
    align-items: center;
}

/* Photo — single clean tilt-on-hover, no extra ornament */
.about-image {
    border-radius: 24px;
    overflow: hidden;
    box-shadow: 0 30px 70px rgba(13, 27, 42, 0.14);
    transition: transform 0.2s ease-out;
    will-change: transform;
}

.about-image img {
    width: 100%;
    height: 100%;
    min-height: 520px;
    object-fit: cover;
    display: block;
}

/* Labels */
.about-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--muted);
    display: flex;
    align-items: center;
    gap: 0.65rem;
}
.about-label::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    flex-shrink: 0;
}

.about-content { display: flex; flex-direction: column; }

.about-heading {
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 300;
    font-size: clamp(1.5rem, 2.4vw, 2.6rem);
    line-height: 1.35;
    color: var(--ink);
    padding: 1rem 0 1.5rem;
    max-width: 30ch;
}
.about-heading em {
    font-style: italic;
    font-weight: 500;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
    display: inline-block;
    padding-right: 0.08em;
    margin-right: -0.08em;
}

/* Inspiration line — moved up under the heading */
.inspiration-text {
    max-width: 50ch;
    font-family: 'Fraunces', Georgia, serif;
    font-style: italic;
    font-weight: 400;
    font-size: 1.05rem;
    line-height: 1.6;
    color: var(--ink-soft);
}
.inspiration-text .hl {
    color: var(--ink);
    font-weight: 500;
    font-style: normal;
    background: linear-gradient(to top, rgba(0, 200, 163, 0.28) 40%, transparent 40%);
    padding: 0 0.1em;
}

.inspiration-text em {
    font-style: italic;
    font-weight: 500;
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
    display: inline-block;
    padding-right: 0.08em;
    margin-right: -0.08em;
}

/* Skills + Tools — one shared row instead of two stacked blocks */
.meta-row {
    display: flex;
    gap: 3rem;
    flex-wrap: wrap;
    padding-top: 2rem;
    margin-top: 1.5rem;
    border-top: 1px solid var(--line);
}
.meta-col { display: flex; flex-direction: column; gap: 0.9rem; }

.meta-col--skills { flex: 1 1 420px; }

.skills-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(160px, 1fr));
    gap: 0 1.75rem;
    max-width: 420px;
    list-style: none;
}
.skills-list li {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--line);
    cursor: default;
}
.skills-num {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    letter-spacing: 0.02em;
    color: var(--muted);
    transition: background 0.2s ease, -webkit-text-fill-color 0.2s ease;
}
.skills-name {
    font-family: 'Inter', sans-serif;
    font-size: 0.85rem;
    color: var(--ink-soft);
    transition: color 0.2s ease, transform 0.2s ease;
}
.skills-list li:hover {
    border-bottom-color: var(--line-strong);
}
.skills-list li:hover .skills-name {
    color: var(--ink);
    transform: translateX(3px);
}
.skills-list li:hover .skills-num {
    background: linear-gradient(90deg, var(--blue), var(--teal));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.tools-inline { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.tools-inline span {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-soft);
    padding: 0.4rem 0.85rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    transition: color 0.2s ease, border-color 0.2s ease;
}
/*.tools-inline span:hover { color: var(--ink); border-color: var(--blue); }*/

/* ===== Responsive ===== */
@media (max-width: 992px) {
    .about { padding: 8vh 2rem; }
    .about-container { grid-template-columns: 1fr; gap: 48px; }
    .about-image img { min-height: 420px; }
    .meta-row { flex-direction: column; gap: 2rem; }
    /* Stacked, the 420px basis is a height — it left a blank block above Tools. */
    .meta-col--skills { flex-basis: auto; }
}

@media (max-width: 576px) {
    .about { padding: 6vh 1.25rem; }
    .about-heading { font-size: 1.4rem; }
    .inspiration-text { font-size: 1rem; max-width: 100%; }
}

/* ── FOOTER ── */
.footer {
    position: relative;
    z-index: 6;
    background: #EAECF1;
    padding: 10vh 10vh 0 10vh;
    overflow: hidden;
}

.footer-top {
    max-width: 1200px;
    margin: 0 auto 8vh;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.footer-lead { width: 42rem; max-width: 100%; }
.footer-hook {
    font-size: clamp(1.6rem, 3.5vw, 2.8rem);
    font-weight: 300;
    line-height: 1.2;
    color: var(--ink);
    margin: 0 0 1.25rem;
}
.footer-email {
    display: inline-block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    color: var(--ink);
    text-decoration: none;
    padding-bottom: 3px;
    background: linear-gradient(90deg, var(--blue), var(--teal)) left bottom / 100% 1.5px no-repeat;
    transition: background-size 0.35s ease;
}
.footer-email:hover { background-size: 0% 1.5px; background-position: right bottom; }

.footer-legal {
    max-width: 1200px;
    margin: -3vh auto 3vh;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    line-height: 1.7;
    color: var(--muted);
}

.footer-avail {
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    line-height: 1.7;
    color: var(--ink-soft);
}
.footer-avail a {
    color: var(--ink);
    text-decoration: none;
    padding-bottom: 2px;
    background: linear-gradient(90deg, var(--blue), var(--teal)) left bottom / 100% 1.5px no-repeat;
    transition: background-size 0.35s ease;
}
.footer-avail a:hover { background-size: 0% 1.5px; background-position: right bottom; }

.footer-hook em {
    background: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gradient-shift 10s linear infinite;
}

.footer-actions {
    width: 50%;
    display: flex;
    align-items: end;
    flex-direction: column;
    gap: 1rem;
}

.footer-navigation,
.footer-contact {
    width: max(45%, 15rem);   /* never narrower than its four links need */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;        /* ← consistent gap between items in both rows */
    transition: background 0.2s ease;
}

.footer-navigation a {
    font-size: 0.875rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    color: var(--muted);
    text-decoration: none;
    position: relative;
    padding-bottom: 4px;
    transition: color 0.2s;
}

.footer-navigation a::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    width: 0;
    height: 1.5px;
    background: var(--accent);
    transition: width 0.25s ease;
}

.footer-navigation a:hover,
.footer-navigation a.active {
    color: var(--ink);
}

.footer-navigation a:hover::after,
.footer-navigation a.active::after {
    width: 100%;
}

.footer-social {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--ink);
    color: var(--bg);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease;
}

.footer-social:hover {
    background: var(--accent);
}

.footer-cta {
    white-space: nowrap;      /* the label stays on one line in narrow footers */
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.75rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--bg);
    background: var(--ink);
    padding: 0.9rem 1.6rem;
    text-decoration: none;
    border-radius: 999px;
    transition: background 0.2s ease;
}
.footer-cta:hover {
    background: var(--accent);
}

.footer-brand {
    max-width: 1200px;
    margin: 0 auto;
    overflow: hidden;
}

.footer-maeven {
    width: 100%;
    height: auto;
    display: block;
    transform: scaleY(1.4);
    transform-origin: top;
    user-select: none;
    margin-bottom: 11.5vh;
}

.footer-bottom {
    max-width: 1200px;
    margin: 3vh auto 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 2rem;
    border-top: 1px solid rgba(26, 25, 22, 0.12);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.65rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--muted);
}

@media (max-width: 900px) {
    .about-layout {
        grid-template-columns: 1fr;
        gap: 3rem;
    }
    .about { padding: 8vh 2rem; }
    .footer { padding: 8vh 2rem 3vh; }
    .carousel-track img {
        width: 140px;
        height: 140px;
    }
}

/* ══════════════════════════════════════════════
   NEXT PROJECT — shared component, injected by /assets/next-project.js
   into <div id="maeven-next-project" data-href="..." data-title="...">
   ══════════════════════════════════════════════ */

.next-project {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 34vh 0;
    text-decoration: none;
    cursor: pointer;
    overflow: hidden;
    isolation: isolate;
}

.next-project-glow {
    position: absolute;
    width: 640px;
    height: 640px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: radial-gradient(circle, rgba(51, 58, 78, 0.10) 0%, rgba(51, 58, 78, 0.04) 45%, transparent 70%);
    filter: blur(10px);
    pointer-events: none;
    z-index: 0;
}

.next-project-eyebrow {
    position: relative;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #6E6E6E;
    margin-bottom: 1.5rem;
    padding-bottom: 0.4rem;
}

.next-project-eyebrow-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: #6E6E6E;
    flex-shrink: 0;
    transition: background 0.3s ease, transform 0.3s ease;
}

/* Gradient underline reveal — same idiom as .nav-links a::after / .footer-navigation a::after */
.next-project-eyebrow::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: linear-gradient(90deg, #0052FF, #00C8A3);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.next-project:hover .next-project-eyebrow::after {
    transform: scaleX(1);
}

.next-project:hover .next-project-eyebrow-dot {
    background: #00C8A3;
    transform: scale(1.4);
}

.next-project-title-wrap {
    position: relative;
    z-index: 2;
    width: 100%;
    padding: 0 6vw;
}

.next-project-title {
    --mx: 50%;
    --my: 50%;
    position: relative;
    z-index: 2;
    font-family: 'Fraunces', Georgia, serif;
    font-style: italic;
    font-weight: 500;
    font-size: clamp(2.5rem, 7vw, 5.5rem);
    line-height: 1.15;
    letter-spacing: -0.02em;
    text-align: center;
    max-width: 100%;
    overflow-wrap: break-word;
    margin: 0;
    will-change: transform;
    background-image: linear-gradient(90deg, #0052FF, #00C8A3, #0052FF, #00C8A3, #0052FF);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    animation: next-project-gradient-shift 10s linear infinite;
    transition: background-image 0.15s ease;
}

/* On hover, freeze the ambient sweep and let the gradient bloom from the cursor instead —
   a spotlight that tracks --mx/--my (set from JS), fading to ink at the edges.
   NOTE: use background-image (not the `background` shorthand) — the shorthand resets
   background-clip to border-box, which paints a solid box instead of clipping to the glyphs. */
.next-project:hover .next-project-title {
    animation-play-state: paused;
    background-image: radial-gradient(circle 320px at var(--mx) var(--my), #00C8A3, #0052FF 45%, var(--ink) 75%);
    background-size: 100% 100%;
}

@keyframes next-project-gradient-shift {
    0%   { background-position: 0% 50%; }
    100% { background-position: -200% 50%; }
}

/* Cursor-follow "View" badge — the magnetic project-link pattern */
.next-project-badge {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 4;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    width: 96px;
    height: 96px;
    border-radius: 50%;
    background: rgba(248, 250, 251, 0.85);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--line-strong);
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink);
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.5);
    transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    pointer-events: none;
    will-change: transform;
}

.next-project-badge-arrow {
    background: linear-gradient(90deg, #0052FF, #00C8A3);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.next-project.is-hovering .next-project-badge {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.next-project.is-hovering .next-project-badge-arrow {
    transform: translateX(3px);
}

@media (max-width: 768px), (hover: none) {
    .next-project { padding: 12vh 0 6vh; cursor: pointer; }
    .next-project-badge { display: none; }
}

/* ── MOBILE: no cursor, so the magnetic badge and the wide ambient glow
   both fall apart. At phone width the 640px glow fills the whole block
   and reads as a hard-edged grey slab instead of a halo. Rebuild the
   block as a self-contained card with a real tap target. ── */
@media (max-width: 768px) {
    .next-project {
        padding: 3rem 1.5rem 3.25rem;
        margin-top: 2.5rem;
        border: 1px solid var(--line);
        border-radius: 24px;
        background: linear-gradient(180deg, var(--bg) 0%, #ffffff 70%);
    }

    .next-project-glow {
        width: 280px;
        height: 280px;
        top: 42%;
        filter: blur(34px);
        opacity: 0.7;
    }

    .next-project-eyebrow { margin-bottom: 1.1rem; }

    .next-project-title-wrap { padding: 0; }

    .next-project-title {
        font-size: clamp(2.1rem, 11vw, 3.2rem);
        line-height: 1.08;
    }

    /* the cursor-follow badge becomes a static pill under the title —
       on touch it was the only affordance and it was hidden outright */
    .next-project-badge {
        display: inline-flex;
        position: static;
        z-index: 2;
        width: auto;
        height: auto;
        margin-top: 2rem;
        padding: 0.7rem 1.4rem;
        border-radius: 999px;
        background: #ffffff;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        opacity: 1;
        transform: none;
        transition: none;
        will-change: auto;
    }
}

@media (prefers-reduced-motion: reduce) {
    .next-project-title { animation: none; }
    .next-project:hover .next-project-title { background-image: linear-gradient(90deg, #0052FF, #00C8A3); }
    .next-project-badge { transition: opacity 0.2s ease; }
}

/* ══════════════════════════════════════════════
   MOBILE / SMALL SCREEN — LANDING PAGE
   ══════════════════════════════════════════════ */
@media (max-width: 768px) {
    /* ── Hero ── */
    .hero { padding: 1.25rem 1.25rem 2rem; }
    .hero-top {
        margin-top: 3.75rem;
        flex-direction: column;
        align-items: center;
        gap: 0.4rem;
        text-align: center;
    }
    .hero-main { gap: 1.1rem; }
    .hero-title { font-size: clamp(2.1rem, 10vw, 3rem); }
    .hero-subtitle { font-size: clamp(1.2rem, 6vw, 2rem); }

    /* ── Process steps (Discover / Design / Build / Launch) ──
       Single column, text anchored to the top of the sticky viewport
       so it doesn't collide with the wireframe illustration, which
       script.js now docks lower on mobile (boxY).

       The tracks are taller than their sticky child so the sticky
       actually has somewhere to travel — at the default 100vh/100vh it
       never pins at all, and the copy just scrolls away from the
       viewport-fixed canvas, leaving the screen half empty. The extra
       60vh gives each step a beat where the copy holds at the top with
       its finished wireframe below, before the next step animates in.
       (The triggers span 'top bottom' → 'top top' = 100vh either way,
       so the animations themselves are unchanged.) */
    .discover-track,
    .design-track,
    .build-track,
    .launch-track { height: 160vh; }

    .discover-sticky,
    .design-sticky,
    .build-sticky,
    .launch-sticky {
        grid-template-columns: 1fr;
        align-items: start;
        padding: 6.5rem 1.5rem 0;
        gap: 0;
    }
    .step-text { max-width: 100%; gap: 0.85rem; }
    .step-title { font-size: clamp(1.7rem, 8vw, 2.4rem); }
    .step-body { font-size: 0.88rem; line-height: 1.5; }

    /* ── Work / Projects cards ── */
    .work-cue { padding-top: 12vh; }
    .work-cue-title { padding: 0 0.5rem; }
    .scroll-cue-projects { top: auto; bottom: 6vh; }
    .proj-inner {
        grid-template-columns: 1fr;
        grid-template-rows: auto 1fr;
        padding: 1.75rem;
        gap: 1.25rem;
    }
    .proj-left { gap: 0.75rem; }
    .proj-title { font-size: clamp(1.4rem, 7vw, 2rem); }
    .proj-body { font-size: 0.85rem; max-width: 100%; }
    .proj-right { min-height: 0; }

    /* Card thumbnails default to a centred crop, but Bloom's and NestUp's
       featured phone doesn't sit centre-frame in the source photo — a
       plain centre crop showed mostly what's around it instead. Anchored
       to the same spot their case-study hero uses (see /assets/transitions.js
       HEROES and their .xx-hero-bg img rules), so the card already shows
       what the hero opens on, tap or no tap. */
    .proj-card:nth-child(3) .proj-img img { object-position: 34% 50%; }
    .proj-card:nth-child(4) .proj-img img { object-position: 52% 50%; }

    /* ── CARD THUMBNAIL ZOOM ──
       RFS's card shows its hero's own phone render (see index.html), which is
       a wide shot with room around the monitor — at the card's own scale it
       reads as mostly empty mint, and the monitor then has to grow a long way
       to become the hero. Zoomed so the card already frames the monitor at
       close to the size the hero opens on, which is what the expand is trying
       to hold still.

       This is the number to tune by eye: raise it to crop in tighter, lower it
       to show more of the shot. 1.18 is the default every other card uses
       (set in script.js); nothing else needs changing when you edit it. If you
       go much past ~1.6 the render starts to soften on a 2x screen. */
    .proj-card:nth-child(2) .proj-img img { --card-zoom: 1.53; }

    /* ── Footer ── */
    .footer { padding: 8vh 1.5rem 0; }
    .footer-top { flex-direction: column; align-items: flex-start; gap: 2.5rem; margin-bottom: 6vh; }
    .footer-hook { width: 100% !important; font-size: clamp(1.4rem, 7vw, 2rem); }
    .footer-actions { width: 100%; align-items: flex-end; }
    .footer-navigation, .footer-contact { width: 100%; flex-wrap: wrap; }
    .footer-navigation { justify-content: flex-end; gap: 1.5rem; }
    .footer-contact { justify-content: flex-end; gap: 1rem; }
    .footer-maeven { margin-bottom: 5vh; }
    .footer-bottom { flex-direction: column; gap: 0.75rem; align-items: flex-start; }
}

@media (max-width: 480px) {
    .polaroids { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    .about-heading { max-width: 100%; }
}

@media (max-width: 900px) {
    .gallery { justify-content: flex-start; padding-top: 13vh; }
}

@media (max-width: 768px) {
    /* The track is twice the gallery's height on desktop, and that extra 100vh
       is pin travel — the gallery holds still while About (margin-top: -100vh)
       slides up over it. With that overlap dropped below, the pin had nothing
       left to cover it and became 100vh of dead scroll where the section just
       sat there. Matching the track to the gallery leaves zero travel, so it
       scrolls like any other section. Kept at the same breakpoint as the
       .about rule below, since that rule is what empties the pin. */
    .gallery-track { height: 100vh; }

    /* The desktop "about slides up over the gallery" pin effect assumes a
       two-column layout short enough to fit one screen. Stacked single-column
       content (photo + full text) is taller than 100vh, so on mobile it drops
       the pin/overflow-clip and flows normally instead of getting cropped.

       Relative rather than static, though: z-index only applies to positioned
       elements, so as static the z-index below goes inert and About paints
       underneath the fixed canvas and project strip — which is what left the
       hi-fi frame and project cards showing through over this section. */
    .about {
        position: relative;
        z-index: 6;
        margin-top: 0;
        min-height: auto;
        overflow: visible;
        /* The rounded top only reads as a curve on desktop, where the negative
           margin slides this up over the gallery. Sitting flush after it here,
           the corners would instead cut a window through to the project strip
           still parked behind. */
        border-radius: 0;
        padding: 8vh 1.5rem 6vh;
    }
    .about-image img { min-height: 320px; height: 320px; }
    .skills-list { grid-template-columns: 1fr; max-width: 100%; gap: 0; }

    /* The copy lane.

       All four steps' copy is lifted out of flow into one fixed lane at the
       top of the screen, and swapped in place by syncStepText(). Previously
       each block scrolled through the viewport with its section, which is what
       opened the empty gap between steps — and what the illustration was then
       moving to cover. With the copy parked, the gap never opens and the
       illustration can hold still. */
    /* Rail and copy sit lower than the nav would require, so the pair reads as
       one group with the illustration below it rather than being stranded at
       the top of the screen. */
    .step-text {
        position: fixed;
        top: 11.5rem;       /* a clear beat below the stage navigator */
        left: 1.5rem;
        right: 1.5rem;
        z-index: 2;
        opacity: 0;
        will-change: opacity, transform;
    }

    /* The stage navigator above says "Build" already — the eyebrow would
       only repeat it. */
    .step-text .step-number { display: none; }

    /* Mobile: a plain row across the top of the copy lane. */
    .stage-nav {
        top: 7rem;
        left: 1.5rem;
        right: 1.5rem;
        gap: 0;
        justify-content: space-between;
        transform: none;
    }

    .hero-bottom { transition: opacity 0.45s ease; }
    .hero-bottom.out-of-view { opacity: 0; }
}
/* ══════════════════════════════════════════════
   MOTION — split-word masks, intro, reveals, strip counter
   ══════════════════════════════════════════════ */

/* Each word sits in its own clipping mask and rises from under its baseline.
   The padding / negative margin pair gives ascenders, descenders and italic
   overhang room inside the mask without changing the line's layout. */
.wm {
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    /* Room inside the mask for Fraunces italic: y / j / g descend well below
       the baseline and the swash J also hooks out to the left. */
    padding: 0.14em 0.14em 0.32em 0.14em;
    margin: -0.14em -0.14em -0.32em -0.14em;
}
.wi { display: inline-block; }
/* Gradient words paint their text through their own background
   (background-clip: text), and a background only covers the element's box —
   so descenders and the italic swash J fell outside it and went unpainted.
   Pad the box out to cover the ink; the negative margin keeps layout as is. */
.wm > em.wi {
    padding: 0.08em 0.12em 0.24em 0.12em;
    margin: -0.08em -0.12em -0.24em -0.12em;
}

/* Hero intro — the headline rises in word by word as the dots ripple out. */
@keyframes word-rise {
    from { transform: translate3d(0, 140%, 0); }
    to   { transform: none; }
}
@keyframes fade-rise {
    from { opacity: 0; transform: translate3d(0, 12px, 0); }
    to   { opacity: 1; transform: none; }
}
.hero .wi {
    animation: word-rise 1.3s cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: calc(0.25s + var(--i) * 0.075s);
}
/* The em keeps its gradient drift alongside the rise. */
.hero-title em.wi {
    animation: word-rise 1.3s cubic-bezier(0.16, 1, 0.3, 1) both,
               gradient-shift 10s linear infinite;
    animation-delay: calc(0.25s + var(--i) * 0.075s), 0s;
}
.hero-top { animation: fade-rise 1s cubic-bezier(0.16, 1, 0.3, 1) 0.9s both; }

/* Desktop step copy: words rise as the step scrolls into view, and drop back
   when it leaves so the story re-plays on the way back up. */
.step-title.is-split .wi {
    transform: translate3d(0, 140%, 0);
    transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
    transition-delay: calc(var(--i) * 0.07s);
}
.step-text.in .step-title.is-split .wi { transform: none; }

/* One-shot reveals (IntersectionObserver adds .in). `translate` rather than
   `transform`, so they never fight the About photo's hover tilt. */
[data-reveal] {
    transition: opacity 1s cubic-bezier(0.16, 1, 0.3, 1),
                translate 1.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.about-image[data-reveal],
.inspiration-text[data-reveal],
.gallery-header[data-reveal] .gallery-sub {
    opacity: 0;
    translate: 0 40px;
}
.about-image[data-reveal] {
    transition: opacity 1s cubic-bezier(0.16, 1, 0.3, 1),
                translate 1.2s cubic-bezier(0.16, 1, 0.3, 1),
                transform 0.2s ease-out;
}
.about-image[data-reveal] img {
    transform: scale(1.22);
    transition: transform 1.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.inspiration-text[data-reveal] { transition-delay: 0.35s; }
.gallery-header[data-reveal] .gallery-sub {
    transition: opacity 1s cubic-bezier(0.16, 1, 0.3, 1) 0.35s,
                translate 1.2s cubic-bezier(0.16, 1, 0.3, 1) 0.35s;
}
.about-image[data-reveal].in,
.inspiration-text[data-reveal].in,
.gallery-header[data-reveal].in .gallery-sub { opacity: 1; translate: 0 0; }
.about-image[data-reveal].in img { transform: none; }

.about-heading.is-split .wi,
.gallery-title.is-split .wi {
    transform: translate3d(0, 140%, 0);
    transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
    transition-delay: calc(var(--i) * 0.035s);
}
.about-heading.in .wi,
.gallery-header.in .gallery-title .wi { transform: none; }

.meta-row[data-reveal] li,
.meta-row[data-reveal] .tools-inline span {
    opacity: 0;
    translate: 0 14px;
    transition: opacity 0.8s ease, translate 0.9s cubic-bezier(0.16, 1, 0.3, 1),
                color 0.2s ease, border-color 0.2s ease;
    transition-delay: calc(0.1s + var(--i) * 0.045s);
}
.meta-row[data-reveal].in li,
.meta-row[data-reveal].in .tools-inline span { opacity: 1; translate: 0 0; }

/* Horizontal strip counter — "01 ——— 04", fills as the cards pass. */
.strip-hud {
    position: fixed;
    left: 50%;
    bottom: 4vh;
    transform: translateX(-50%);
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 0.9rem;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    letter-spacing: 0.18em;
    color: var(--ink);
    opacity: 0;
    pointer-events: none;
    will-change: opacity;
}
.strip-hud-total { color: var(--muted); }
.strip-hud-bar {
    width: 72px;
    height: 1px;
    background: var(--line-strong);
    overflow: hidden;
}
.strip-hud-bar i {
    display: block;
    height: 100%;
    background: var(--ink);
    transform: scaleX(0);
    transform-origin: left center;
}

@media (max-width: 768px) {
    /* The copy lane is scroll-scrubbed by script.js, frame by frame — a CSS
       transition on top would make every word lag behind the finger. */
    .step-title.is-split .wi { transition: none; }
    .step-number, .step-body, .step-title .wi { will-change: opacity, transform; }
    .strip-hud { bottom: calc(env(safe-area-inset-bottom, 0px) + 3.5vh); }
}

@media (prefers-reduced-motion: reduce) {
    .hero .wi, .hero-title em.wi, .hero-top { animation: none; }
    .hero-title em.wi { animation: gradient-shift 10s linear infinite; }
    .wi, [data-reveal], [data-reveal] * { transition: none !important; }
    .step-title.is-split .wi,
    .about-heading.is-split .wi,
    .gallery-title.is-split .wi { transform: none; }
    [data-reveal], .meta-row[data-reveal] li, .meta-row[data-reveal] .tools-inline span,
    .gallery-header[data-reveal] .gallery-sub { opacity: 1 !important; translate: none !important; }
    .about-image[data-reveal] img { transform: none; }
}


/* While the first card grows out of the canvas mock-up, the canvas paints its
   surface; the DOM panel only contributes its content on top. */
.proj-inner.is-morphing { background: transparent; }

/* Desktop: room between the vertical stage navigator and the step copy. */
@media (min-width: 769px) {
    .discover-sticky,
    .design-sticky,
    .build-sticky,
    .launch-sticky { padding-left: 7.5rem; }
}

/* ══════════════════════════════════════════════
   CASE STUDY MOTION — companions to /assets/case-motion.js
   html.case-motion is only set once that script runs (it skips itself for
   prefers-reduced-motion), so every page still reads complete without it.
   ══════════════════════════════════════════════ */

/* Smooth scrolling is Lenis's job on desktop; a CSS scroll-behavior also
   animates ScrollTrigger's own scroll restoration on refresh. */
html.case-motion { scroll-behavior: auto; }

/* Keep body one viewport tall with Lenis on. Every case study's layering
   depends on it: the Brief (and later slide-over sections) are sticky
   children of body, and a one-screen body is what stops them sticking past
   their own slide-over. Lenis's stylesheet sets height: auto, which left the
   Brief pinned over the rest of the page. */
html.case-motion.lenis,
html.case-motion.lenis body { height: 100%; }

.case-progress {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: var(--ink);
    transform: scaleX(0);
    transform-origin: 0 50%;
    z-index: 999;
    pointer-events: none;
    will-change: transform;
}

/* Hero dims as the Brief slides up over it */
.case-hero-shade {
    position: absolute;
    inset: 0;
    z-index: 0;
    background: #0B0F17;
    opacity: 0;
    pointer-events: none;
}

/* Read-along words: opacity is scrubbed per word. Deliberately no
   will-change here — it would promote every word to its own GPU layer. */

/* Brief / role labels count themselves: "01 — OVERVIEW" */
.case-num { color: var(--muted); }

/* ══════════════════════════════════════════════
   PAGE TRANSITIONS — cross-document View Transitions (see /assets/transitions.js)
   Forward: the new page rises over the old, which sinks back and dims.
   Back/forward buttons (type "back"): the same, reversed.
   Landing card → case study (type "expand"): the landing page itself grows
   the card's image into the hero first (see .page-expand below). Browsers
   without support navigate as before.
   ══════════════════════════════════════════════ */

@view-transition { navigation: auto; }

:root {
    --vt-dur: 0.9s;
    --vt-ease: cubic-bezier(0.76, 0, 0.24, 1);
}

::view-transition-group(root) { animation-duration: var(--vt-dur); }

::view-transition-old(root) {
    animation: vt-sink var(--vt-dur) var(--vt-ease) both;
}
::view-transition-new(root) {
    animation: vt-rise var(--vt-dur) var(--vt-ease) both;
}

@keyframes vt-sink {
    to { transform: translateY(-4%) scale(0.94); opacity: 0.35; }
}
@keyframes vt-rise {
    from { transform: translateY(100%); clip-path: inset(0 round 40px 40px 0 0); }
    to   { transform: none;            clip-path: inset(0 round 0); }
}

/* Back / forward: the old page drops away and the previous one comes forward. */
html:active-view-transition-type(back)::view-transition-old(root) {
    z-index: 1;
    animation: vt-drop var(--vt-dur) var(--vt-ease) both;
}
html:active-view-transition-type(back)::view-transition-new(root) {
    animation: vt-surface var(--vt-dur) var(--vt-ease) both;
}
@keyframes vt-drop {
    to { transform: translateY(100%); clip-path: inset(0 round 40px 40px 0 0); }
}
@keyframes vt-surface {
    from { transform: translateY(-4%) scale(0.94); opacity: 0.35; }
}

/* Card → case study: the landing page grows the card's image into exactly
   the hero before navigating (.page-expand, driven by /assets/transitions.js),
   so the swap itself only needs a brief settle, not a slide. */
html:active-view-transition-type(expand)::view-transition-old(root) {
    animation: vt-fade-out 0.3s ease both;
}
html:active-view-transition-type(expand)::view-transition-new(root) { animation: none; }
@keyframes vt-fade-out { to { opacity: 0; } }

.page-expand {
    position: fixed;
    z-index: 995;               /* over the page, under the nav and progress bar */
    overflow: hidden;
    /* Takes the pointer (it's only up for 0.9s) so the nav's tone check,
       which only sees hit-testable elements, reads the growing image. */
    will-change: left, top, width, height;
}
.page-expand img,
.page-expand i {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.page-expand img { object-fit: cover; display: block; }
.page-expand i { opacity: 0; }

/* Case studies, until the hero script takes over (see transitions.js). */
html.hero-pending [class$="-hero-content"],
html.hero-pending:not(.hero-arriving) #hero-bg { visibility: hidden; }

/* The nav deliberately has no view-transition-name of its own: a named nav
   is photographed on each page and the one photo stretched into the other,
   which smeared its glass into a blurry bar whenever the two navs differed in
   size. It's simply part of each page; arriving from a card, the landing page
   hands over its exact state (see nav.js), so the two frames match. */

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) { animation: none !important; }
}

/* ══════════════════════════════════════════════
   CASE STUDY HERO ON PHONES — the photo is landscape, so covering a tall
   screen cut most of it away. Here it shows whole, full width near the top,
   fading into a solid backdrop in the hero's own dark; the copy sits below.
   /assets/transitions.js lands the card's expand on exactly this framing.
   ══════════════════════════════════════════════ */
@media (max-width: 768px) {
    .msc-hero-bg { --hero-solid: rgb(var(--msc-scrim-rgb)); }
    .cs-hero-bg  { --hero-solid: rgb(var(--cs-scrim-rgb)); }
    .bl-hero-bg  { --hero-solid: rgb(var(--bl-scrim-rgb)); }
    .ns-hero-bg  { --hero-solid: rgb(var(--ns-scrim-rgb)); }
    #hero-bg { background: var(--hero-solid); }
    #hero-bg img {
        position: absolute;
        top: 9svh;
        left: 0;
        width: 100%;
        height: auto;
        object-position: 50% 50%;
        background: none;
        -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 62%, transparent);
                mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 62%, transparent);
    }
    /* Bloom: cropped like MSC and RFS rather than shown whole, centred on
       the main "How are you feeling today?" screen. */
    /* Runs on down behind the copy, as on desktop, so the hero keeps
       desktop's light, subtle wash instead of ending in a dark block. */
    #hero-bg.bl-hero-bg img {
        top: -4svh;
        height: 100svh;
        object-fit: cover;
        object-position: 34% 50%;
        -webkit-mask-image: linear-gradient(to bottom, #000 88%, transparent);
                mask-image: linear-gradient(to bottom, #000 88%, transparent);
    }
    /* NestUp: cropped around the phone, centred and shown whole. */
    #hero-bg.ns-hero-bg img {
        top: -4svh;
        height: 74svh;
        object-fit: cover;
        object-position: 52% 50%;
        -webkit-mask-image: linear-gradient(to bottom, #000 80%, transparent);
                mask-image: linear-gradient(to bottom, #000 80%, transparent);
    }
    /* MSC and RFS have their own phone renders: a wider shot with room around the
       monitor, cropped to it and filling the top of the screen. */
    /* Sits a little lower, and its bottom edge dissolves into the mint, so
       the chair's legs never end in a hard cut. */
    #hero-bg.cs-hero-bg img {
        top: -4svh;
        height: 72svh;
        object-fit: cover;
        -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 96%);
                mask-image: linear-gradient(to bottom, #000 70%, transparent 96%);
    }
    #hero-bg.cs-hero-bg::after {
        background: linear-gradient(to bottom,
            rgba(223, 240, 223, 0) 0%, rgba(223, 240, 223, 0) 50%,
            rgba(223, 240, 223, 0.85) 66%, rgba(223, 240, 223, 0.95) 100%);
    }
    #hero-bg.msc-hero-bg img {
        top: -12svh;
        height: 80svh;
        object-fit: cover;
        -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent);
                mask-image: linear-gradient(to bottom, #000 72%, transparent);
    }
}

/* RFS's renders (desktop and phone) sit on a flat mint: the hero takes that
   mint and dark type on every screen, so the photo simply continues into the
   page, with a mint (not navy) fade behind the copy. */
#hero-bg.cs-hero-bg { background: rgb(223, 240, 223); }
#hero-bg.cs-hero-bg img { background: none; }
@media (min-width: 769px) {
    #hero-bg.cs-hero-bg::after {
        background: linear-gradient(to bottom,
            rgba(223, 240, 223, 0) 0%, rgba(223, 240, 223, 0) 50%,
            rgba(223, 240, 223, 0.75) 78%, rgba(223, 240, 223, 0.95) 100%);
    }
}
.cs-hero .cs-hero-title { color: #0D1B2A; }
.cs-hero .cs-hero-sub   { color: rgba(13, 27, 42, 0.68); }
.cs-hero .cs-meta-label { color: rgba(13, 27, 42, 0.5); }
.cs-hero .cs-meta-value { color: rgba(13, 27, 42, 0.9); }

/* NestUp, likewise: its render sits on a pale sky, so the hero fades into
   that sky (not navy) behind dark type, on every screen. */
#hero-bg.ns-hero-bg { background: rgb(200, 217, 234); }
#hero-bg.ns-hero-bg img { background: none; }
#hero-bg.ns-hero-bg::after {
    background: linear-gradient(to bottom,
        rgba(200, 217, 234, 0) 0%, rgba(200, 217, 234, 0) 50%,
        rgba(200, 217, 234, 0.8) 72%, rgba(200, 217, 234, 0.95) 100%);
}
.ns-hero .ns-hero-title  { color: #0D1B2A; }
.ns-hero .ns-hero-sub    { color: rgba(13, 27, 42, 0.7); }
.ns-hero .ns-meta-label  { color: rgba(13, 27, 42, 0.5); }
.ns-hero .ns-meta-value  { color: rgba(13, 27, 42, 0.9); }

/* Text for search engines and screen readers only — not painted. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
