/* ==========================================================================
   MOON LAMP — Design System
   Layout language modelled on botvfx.com, palette from the Moon Lamp brand.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
    /* Brand palette */
    --color-black: #0d0d0d;
    --color-dark-ash: #1a1a1a;
    /* Primary — moonlight white falling to lamp-warm cream.
       Containers (buttons, circular controls) use a RADIAL gradient so the
       light reads as coming from a point, like a lit lamp. Thin bars, rules
       and gradient text use the LINEAR form, where a radial has nothing to
       resolve across. --color-primary is the solid stand-in for small text,
       icons and 1px borders; it is the warm stop, so the accent stays
       distinguishable from plain white body copy. */
    /* THE THREE SOURCE VALUES. Everything below derives from these. */
    --primary-light: #fffef7;
    --primary-warm: #ffe8cf;
    --primary-rgb: 255, 232, 207;
    /* ^ the warm stop again, as channels, so the translucent washes and glows
         further down can be built from it with rgba(). */

    --gradient-primary: linear-gradient(135deg, var(--primary-light) 0%, var(--primary-warm) 100%);

    /* Radial fills for containers */
    --gradient-primary-pill: radial-gradient(ellipse at 26% 0%, var(--primary-light) 0%, var(--primary-warm) 78%);
    --gradient-primary-pill-lit: radial-gradient(ellipse at 26% 0%, var(--primary-light) 0%, var(--primary-light) 24%, var(--primary-warm) 94%);
    --gradient-primary-orb: radial-gradient(circle at 32% 26%, var(--primary-light) 0%, var(--primary-warm) 74%);

    --color-primary: var(--primary-warm);
    --color-primary-hover: var(--primary-light);
    --color-on-primary: var(--color-black);
    --color-white: #ffffff;
    --color-gray-light: #cccccc;
    --color-gray-dark: #333333;

    /* Surfaces derived from the brand blacks, for depth layering */
    --surface-0: var(--color-black);
    --surface-1: #121212;
    /* The band surface again as channels, so the CTA moon-veil can be built
       from it with rgba() and stay invisible against the band itself.
       Same convention as --primary-rgb above. */
    --surface-1-rgb: 18, 18, 18;
    --surface-2: var(--color-dark-ash);
    --surface-3: #202020;

    /* Lines & text */
    --line: rgba(255, 255, 255, 0.08);
    --line-strong: rgba(255, 255, 255, 0.18);
    --line-primary: rgba(var(--primary-rgb), 0.35);
    --text: var(--color-white);
    --text-dim: var(--color-gray-light);
    --text-muted: #8b8b8b;

    /* Primary washes */
    --primary-05: rgba(var(--primary-rgb), 0.05);
    --primary-10: rgba(var(--primary-rgb), 0.10);
    --primary-20: rgba(var(--primary-rgb), 0.20);

    /* Type */
    --font-display: 'Anton', 'Poppins', sans-serif;
    --font-primary: 'Poppins', sans-serif;

    /* Motion */
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
    --transition-smooth: all 0.35s cubic-bezier(0.22, 1, 0.36, 1);
    --transition-fast: all 0.2s ease;

    /* Shadow */
    --shadow-subtle: 0 4px 20px rgba(0, 0, 0, 0.45);
    --shadow-deep: 0 24px 60px rgba(0, 0, 0, 0.6);
    --shadow-glow: 0 0 24px rgba(var(--primary-rgb), 0.35);

    /* Lamp glows — layered so the falloff reads as light, not a flat halo.
       EMPHASIS LADDER: a glow has to mean "this is a light source", so it is
       spent sparingly. --glow-sm was removed rather than retired: it sat on six
       purely decorative things (the eyebrow rule, the nav underline, the scroll
       cue, the marquee dot, the rail progress bar and the loading spinner), and
       when every hairline glows, none of them read as lit. */
    --glow-md: 0 0 18px rgba(var(--primary-rgb), 0.4), 0 0 40px rgba(var(--primary-rgb), 0.16);
    --glow-lamp: 0 0 16px rgba(var(--primary-rgb), 0.38), 0 0 44px rgba(var(--primary-rgb), 0.16);
    --glow-lamp-lit: 0 0 22px rgba(var(--primary-rgb), 0.62), 0 0 60px rgba(var(--primary-rgb), 0.28);
    --glow-text: drop-shadow(0 0 14px rgba(var(--primary-rgb), 0.28));
    --glow-icon: drop-shadow(0 0 9px rgba(var(--primary-rgb), 0.55));
    --glow-icon-lit: drop-shadow(0 0 15px rgba(var(--primary-rgb), 0.85));

    /* Layout */
    --nav-h: 84px;
    --gutter: clamp(1.25rem, 4vw, 4.5rem);
    --max-w: 1440px;
    --radius: 14px;
    --radius-lg: 22px;
}

/* --------------------------------------------------------------------------
   2. RESET & BASE
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--font-primary);
    background-color: var(--surface-0);
    color: var(--text);
    line-height: 1.65;
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ---- film grain ----------------------------------------------------------
   The one thing separating this from the Awwwards Film & TV winners was never
   layout — Palomino is an ordinary Next.js site — it was surface. This is that
   surface, in 289 bytes and no requests.

   It is not only decoration: #121212 under the big cream radial gradients bands
   into visible concentric rings on 8-bit panels, and grain dithers them away.

   Load-bearing details, each one deliberate:
     background-size 50px on a 600px source — downscaling coarse turbulence is
       what makes grain read as fine and filmic instead of blotchy
     fractalNoise, not turbulence — `turbulence` is veiny and reads digital
     stitchTiles — kills the seams where the tile repeats
     position: fixed — grain belongs to the screen, like grain on a print, so it
       must not scroll with the page
     STATIC — none of the winners animate theirs. A full-viewport blended layer
       repainting every frame is a real battery and thermal cost on the phones
       most of this audience uses, and animated grain is the amateur tell.
     z-index 1100 — above the nav (1000), below .modal-shell (1200), so it never
       textures the video player.
   Hold --grain-opacity at or below 0.12: past ~0.14 it starts eating the
   0.62-0.72rem tracked micro-labels. */
:root {
    --grain-opacity: 0.11;
}

body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 1100;
    pointer-events: none;
    opacity: var(--grain-opacity);
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='600' height='600'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.1' numOctaves='3' stitchTiles='stitch'/></filter><rect width='600' height='600' filter='url(%23n)'/></svg>");
    background-size: 50px 50px;
    background-repeat: repeat;
}

img,
video {
    max-width: 100%;
    display: block;
}

a {
    text-decoration: none;
    color: inherit;
    transition: var(--transition-fast);
}

ul {
    list-style: none;
}

button {
    font-family: inherit;
    cursor: pointer;
}

::selection {
    background: var(--color-primary);
    color: var(--color-on-primary);
}

/* Scrollbar */
::-webkit-scrollbar {
    width: 10px;
}

::-webkit-scrollbar-track {
    background: var(--surface-0);
}

::-webkit-scrollbar-thumb {
    background: var(--color-gray-dark);
    border-radius: 10px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--color-primary);
}

/* --------------------------------------------------------------------------
   3. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.shell {
    width: 100%;
    max-width: var(--max-w);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.shell--wide {
    max-width: 1720px;
}

.section {
    padding-block: clamp(4.5rem, 10vw, 8.5rem);
    position: relative;
}

.section--tight {
    padding-block: clamp(3.5rem, 7vw, 6rem);
}

.section--ash {
    background: var(--surface-2);
}

.section--panel {
    background: var(--surface-1);
}

/* For a page that opens straight into a section with no page-hero above it.
   The nav is position: fixed, so without this the first section slides under
   the bar. Pages that start with .page-hero get this offset from that instead. */
.section--below-nav {
    padding-top: calc(var(--nav-h) + clamp(3rem, 7vw, 6rem));
}

/* --------------------------------------------------------------------------
   4. TYPOGRAPHY
   -------------------------------------------------------------------------- */
h1,
h2,
h3,
h4,
h5,
h6 {
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.01em;
}

p {
    font-weight: 400;
}

.display {
    font-family: var(--font-display);
    font-weight: 400;
    text-transform: uppercase;
    line-height: 0.92;
    letter-spacing: 0.005em;
}

.display--xl {
    font-size: clamp(3rem, 9.5vw, 8.5rem);
}

.display--lg {
    font-size: clamp(2.5rem, 6.5vw, 5.5rem);
}

.display--md {
    font-size: clamp(2rem, 4.5vw, 3.75rem);
}

/* Gradient-filled text. The solid colour is declared first so the text stays
   visible if background-clip: text is unsupported. */
.hero__title em,
.statement__title mark,
.stat__value,
.hero__meta-value,
.capability__num {
    color: var(--color-primary);
    background-image: var(--gradient-primary);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    /* drop-shadow glows the composited (gradient-clipped) glyphs; text-shadow
       would bleed through the transparent fill instead. */
    filter: var(--glow-text);
}

@supports not ((-webkit-background-clip: text) or (background-clip: text)) {

    .hero__title em,
    .statement__title mark,
    .stat__value,
    .hero__meta-value,
    .capability__num {
        background-image: none;
        -webkit-text-fill-color: currentColor;
    }
}

.text-dim {
    color: var(--text-dim);
}

.text-muted {
    color: var(--text-muted);
}

/* Eyebrow — the small tracked label above every section, as on the reference */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--color-primary);
    margin-bottom: 1.25rem;
}

.eyebrow::before {
    content: '';
    width: 30px;
    height: 2px;
    background: var(--gradient-primary);
    flex: 0 0 auto;
}

.eyebrow--center {
    justify-content: center;
}

/* Section headers */
.section-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 2rem;
    flex-wrap: wrap;
    margin-bottom: clamp(2.5rem, 5vw, 4rem);
}

.section-head__title {
    max-width: 46rem;
}

.section-head__lede {
    color: var(--text-dim);
    font-size: 1.02rem;
    max-width: 34rem;
    margin-top: 1.1rem;
}

.section-head--center {
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.section-head--center .section-head__lede {
    margin-inline: auto;
}

/* --------------------------------------------------------------------------
   5. BUTTONS
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.65rem;
    padding: 0.95rem 2rem;
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    border-radius: 999px;
    border: 2px solid transparent;
    position: relative;
    overflow: hidden;
    transition: var(--transition-smooth);
    white-space: nowrap;
}

.btn i {
    font-size: 0.95em;
}

/* Solid primary gradient fill */
.btn--primary {
    background: var(--gradient-primary-pill);
    color: var(--color-on-primary);
    border-color: var(--color-primary);
    box-shadow: var(--glow-lamp);
}

.btn--primary:hover {
    background: var(--gradient-primary-pill-lit);
    border-color: var(--color-primary-hover);
    color: var(--color-on-primary);
    box-shadow: var(--glow-lamp-lit);
    transform: translateY(-2px);
}

/* Outline with sweep fill — carried over from the brand's button style */
.btn--outline {
    background: transparent;
    color: var(--color-white);
    border-color: var(--color-primary);
    z-index: 0;
}

.btn--outline::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--gradient-primary-pill);
    transform: translateX(-101%);
    transition: transform 0.4s var(--ease);
    z-index: -1;
}

.btn--outline:hover {
    color: var(--color-on-primary);
    box-shadow: var(--glow-lamp);
}

.btn--outline:hover::before {
    transform: translateX(0);
}

/* Glass */
.btn--ghost {
    background: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-color: var(--line-strong);
    color: var(--color-white);
}

.btn--ghost:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: var(--color-white);
    transform: translateY(-2px);
}

.btn--sm {
    padding: 0.65rem 1.4rem;
    font-size: 0.72rem;
}

.btn--lg {
    padding: 1.15rem 2.6rem;
    font-size: 0.88rem;
}

.btn--block {
    width: 100%;
}

/* Text link with animated arrow */
.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-white);
}

.link-arrow i {
    color: var(--color-primary);
    transition: transform 0.3s var(--ease);
}

.link-arrow:hover {
    color: var(--color-primary);
}

.link-arrow:hover i {
    transform: translateX(6px);
}

/* --------------------------------------------------------------------------
   6. NAVIGATION
   -------------------------------------------------------------------------- */
.site-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    height: var(--nav-h);
    display: flex;
    align-items: center;
    background: transparent;
    transition: background 0.4s var(--ease), height 0.4s var(--ease),
        border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
    border-bottom: 1px solid transparent;
}

.site-nav.is-scrolled {
    height: 70px;
    background: rgba(13, 13, 13, 0.88);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom-color: var(--line);
    box-shadow: var(--shadow-subtle);
}

/* Solid nav for interior pages so the logo never sits on white content */
.site-nav.site-nav--solid {
    background: rgba(13, 13, 13, 0.9);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom-color: var(--line);
}

.site-nav__inner {
    width: 100%;
    max-width: 1720px;
    margin-inline: auto;
    padding-inline: var(--gutter);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-white);
    flex: 0 0 auto;
}

.brand i {
    color: var(--color-primary);
    font-size: 1.5rem;
    filter: var(--glow-icon);
    transition: transform 0.5s var(--ease), filter 0.4s ease;
}

.brand:hover {
    color: var(--color-white);
}

.brand:hover i {
    transform: rotate(-20deg);
    filter: var(--glow-icon-lit);
}

.brand__mark {
    line-height: 1;
}

.nav-menu {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: auto;
}

.nav-menu__link {
    position: relative;
    display: block;
    padding: 0.5rem 1.05rem;
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text-dim);
}

.nav-menu__link::after {
    content: '';
    position: absolute;
    left: 1.05rem;
    right: 1.05rem;
    bottom: 0.1rem;
    height: 2px;
    background: var(--gradient-primary);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.35s var(--ease);
}

.nav-menu__link:hover,
.nav-menu__link.is-active {
    color: var(--color-white);
}

.nav-menu__link:hover::after,
.nav-menu__link.is-active::after {
    transform: scaleX(1);
}

.nav-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex: 0 0 auto;
}

/* Hamburger */
.nav-toggle {
    display: none;
    width: 46px;
    height: 46px;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    background: transparent;
    position: relative;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    transition: var(--transition-fast);
}

.nav-toggle:hover {
    border-color: var(--color-primary);
}

.nav-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--color-white);
    transition: transform 0.35s var(--ease), opacity 0.2s ease;
}

.nav-toggle.is-open span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
}

.nav-toggle.is-open span:nth-child(2) {
    opacity: 0;
}

.nav-toggle.is-open span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
}

/* Mobile drawer */
.nav-drawer {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: var(--surface-0);
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--nav-h) var(--gutter) 3rem;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-12px);
    transition: opacity 0.4s var(--ease), transform 0.4s var(--ease), visibility 0.4s;
}

.nav-drawer.is-open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.nav-drawer__list {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 2.5rem;
}

.nav-drawer__link {
    font-family: var(--font-display);
    font-size: clamp(2rem, 11vw, 3.5rem);
    text-transform: uppercase;
    line-height: 1.15;
    color: var(--color-white);
    border-bottom: 1px solid var(--line);
    padding-block: 0.55rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.nav-drawer__link span {
    font-family: var(--font-primary);
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    color: var(--text-muted);
}

.nav-drawer__link:hover,
.nav-drawer__link.is-active {
    color: var(--color-primary);
}

.nav-drawer__foot {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    font-size: 0.9rem;
    color: var(--text-dim);
}

.nav-drawer__foot a {
    display: flex;
    align-items: center;
    gap: 0.7rem;
}

.nav-drawer__foot a:hover {
    color: var(--color-primary);
}

.nav-drawer__foot i {
    color: var(--color-primary);
    width: 18px;
}

body.is-locked {
    overflow: hidden;
}

/* --------------------------------------------------------------------------
   7. HERO (home)
   -------------------------------------------------------------------------- */
.hero {
    position: relative;
    min-height: 100svh;
    display: flex;
    align-items: flex-end;
    overflow: hidden;
    padding-bottom: clamp(3.5rem, 8vh, 6rem);
    padding-top: calc(var(--nav-h) + 2rem);
}

.hero__media {
    position: absolute;
    inset: 0;
    z-index: 0;
    /* The hero video carries no poster attribute on purpose. Its src arrives
       only after the Firebase SDK loads and Firestore resolves, so a poster
       would make a third-party image the LCP element for the first seconds of
       every visit. This paints the opening frame from CSS instead — already
       loaded, zero extra requests, and on-brand rather than stock. */
    background:
        radial-gradient(ellipse 65% 55% at 28% 62%, rgba(var(--primary-rgb), 0.10) 0%, transparent 70%),
        var(--surface-0);
}

.hero__media video,
.hero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Anamorphic falloff over the plate — a soft frame and a lens vignette rather
   than hard black bars, so the reel still fills the screen but stops fighting
   the nav at the top and the stat and scroll cue at the bottom.

   It sits ABOVE the video and BELOW .hero__scrim (z-index 1), so the scrim's
   carefully-padded regions still do the legibility work; this only shapes the
   frame. Kept off .hero__media itself because that element paints the
   gradient fallback for when no reel has loaded. */
.hero__media::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        linear-gradient(180deg, transparent 84%, rgba(0, 0, 0, 0.6) 100%),
        linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, transparent 19%);
}

.hero__scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    /* These layers COMPOSITE, so their alphas multiply: two 0.9 washes read as
       0.99, not 0.9. The previous version stacked two full-frame gradients that
       reached ~0.996 behind the headline — effectively solid black — which is
       why the showreel was invisible exactly where it mattered.

       Each layer below instead pads ONE region and clears to transparent
       elsewhere. The copy pad is an ellipse rather than a band because the copy
       sits bottom-left; a band would dim the right half of the frame for
       nothing. Net result: ~0.65-0.85 behind text, ~0.14-0.34 over open frame. */

    /* Base veil — ties the frame together and takes the harshness off raw
       video. Sits under every layer below. */
    background-color: rgba(13, 13, 13, 0.14);

    background-image:
        /* warm lamp bloom behind the copy */
        radial-gradient(ellipse 70% 55% at 22% 76%, rgba(var(--primary-rgb), 0.12) 0%, transparent 72%),
        /* nav band — keeps the top-bar links legible without dimming the frame */
        linear-gradient(to bottom,
            rgba(13, 13, 13, 0.78) 0%,
            rgba(13, 13, 13, 0.28) 22%,
            transparent 38%),
        /* copy pad — centred on the headline / lede / buttons block */
        radial-gradient(ellipse 62% 58% at 24% 74%,
            rgba(13, 13, 13, 0.76) 0%,
            rgba(13, 13, 13, 0.50) 45%,
            transparent 78%),
        /* bottom fade — grounds the scroll cue and the stat in the corner */
        linear-gradient(to top,
            rgba(13, 13, 13, 0.70) 0%,
            rgba(13, 13, 13, 0.25) 25%,
            transparent 45%);
}

/* Now that the scrim is light enough to show the showreel, the copy can no
   longer assume a dark plate — the reel is swappable from the admin panel and
   could be a bright clip. A soft shadow holds legibility either way: invisible
   over a dark frame, load-bearing over a bright one. */
.hero__title,
.hero__lede,
.hero .eyebrow,
.hero__meta-label,
.scroll-cue {
    text-shadow: 0 2px 18px rgba(13, 13, 13, 0.6);
}

/* text-shadow is inherited, and these are gradient-clipped with a transparent
   fill — an inherited shadow would show straight through the glyphs. They
   carry --glow-text instead. */
.hero__title em,
.hero__meta-value {
    text-shadow: none;
}

/* --------------------------------------------------------------------------
   HERO AMBIENT SKY — night breathing

   A single infinite CSS keyframe on opacity — a compositor property — paused
   via a class rather than torn down, so no JS runs for it at all. main.js adds
   .is-live only while the hero is on screen and the tab is visible.

   It sits BELOW .hero__scrim in tree order so the blurred backdrops above it
   never re-sample moving pixels.
   -------------------------------------------------------------------------- */
.hero__sky {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}

/* "The page is breathing" — a slow warm swell over the plate. Deliberately
   below the threshold of conscious notice. */
.hero__breath {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 72% 58% at 24% 74%,
            rgba(var(--primary-rgb), 0.11) 0%,
            transparent 72%);
    opacity: 0.3;
}

@media (prefers-reduced-motion: no-preference) {
    .hero__breath {
        animation: hero-breathe 11s ease-in-out infinite;
    }

    /* main.js adds .is-live only while the hero is on screen and the tab is
       visible, so this is genuinely idle otherwise rather than merely throttled
       by the browser. The scroll cue rides the same gate — it is inside the
       hero and was previously animating forever.
       (Still unpaused elsewhere: .marquee__track. .spinner is fine, it only
       exists while something is loading.) */
    .hero:not(.is-live) .hero__breath,
    .hero:not(.is-live) .scroll-cue__line::after {
        animation-play-state: paused;
    }
}

@keyframes hero-breathe {

    0%,
    100% {
        opacity: 0.22;
    }

    50% {
        opacity: 1;
    }
}

/* Faint grid overlay — echoes the reference's technical texture */
.hero__grid {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background-image:
        linear-gradient(to right, rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 90px 90px;
    mask-image: radial-gradient(ellipse at center, #000 30%, transparent 80%);
    -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 80%);
}

.hero__inner {
    position: relative;
    z-index: 2;
    width: 100%;
}

.hero__title {
    max-width: 18ch;
    margin-bottom: 1.6rem;
}

.hero__title em {
    font-style: normal;
    color: var(--color-primary);
    display: block;
}

.hero__lede {
    max-width: 46ch;
    font-size: clamp(0.98rem, 1.3vw, 1.13rem);
    color: var(--text-dim);
    margin-bottom: 2.4rem;
}

.hero__actions {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    align-items: center;
}

.hero__meta {
    position: absolute;
    right: var(--gutter);
    bottom: clamp(3.5rem, 8vh, 6rem);
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.4rem;
    text-align: right;
}

.hero__meta-value {
    font-family: var(--font-display);
    font-size: clamp(2rem, 3.4vw, 3.2rem);
    color: var(--color-primary);
    line-height: 1;
}

.hero__meta-label {
    font-size: 0.68rem;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.scroll-cue {
    position: absolute;
    left: 50%;
    bottom: 1.6rem;
    z-index: 2;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.55rem;
    font-size: 0.62rem;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.scroll-cue__line {
    width: 1px;
    height: 46px;
    background: linear-gradient(to bottom, var(--color-primary), transparent);
    position: relative;
    overflow: hidden;
}

.scroll-cue__line::after {
    content: '';
    position: absolute;
    top: -46px;
    left: 0;
    width: 100%;
    height: 46px;
    background: var(--gradient-primary);
    animation: cue-slide 2.2s infinite;
}

@keyframes cue-slide {
    0% {
        transform: translateY(0);
    }

    100% {
        transform: translateY(92px);
    }
}

/* --------------------------------------------------------------------------
   8. PAGE HERO (interior pages)
   -------------------------------------------------------------------------- */
.page-hero {
    position: relative;
    padding-top: calc(var(--nav-h) + clamp(3.5rem, 9vw, 7rem));
    padding-bottom: clamp(3rem, 7vw, 5.5rem);
    overflow: hidden;
    border-bottom: 1px solid var(--line);
    background: var(--surface-0);
}

.page-hero__glow {
    position: absolute;
    top: -40%;
    left: 50%;
    transform: translateX(-50%);
    width: min(1100px, 130vw);
    aspect-ratio: 1;
    background: radial-gradient(circle,
            rgba(var(--primary-rgb), 0.14) 0%,
            rgba(var(--primary-rgb), 0.05) 34%,
            transparent 64%);
    pointer-events: none;
}

.page-hero__inner {
    position: relative;
    z-index: 1;
}

.page-hero__title {
    margin-bottom: 1rem;
}

.page-hero__lede {
    max-width: 52ch;
    color: var(--text-dim);
    font-size: 1.05rem;
}

.crumbs {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-top: 2rem;
}

.crumbs a:hover {
    color: var(--color-primary);
}

.crumbs span {
    color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   9. STATEMENT BAND ("WE ARE")
   -------------------------------------------------------------------------- */
.statement {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: clamp(2rem, 6vw, 6rem);
    align-items: start;
}

.statement__title {
    letter-spacing: -0.015em;
}

.statement__title mark {
    /* Only the UA's yellow highlight is cleared here — the gradient text fill
       comes from the rule set this selector shares with .hero__title em and
       must not be reset. */
    background-color: transparent;
    color: var(--color-primary);
}

.statement__body p {
    color: var(--text-dim);
    margin-bottom: 1.2rem;
    font-size: 1.02rem;
}

.statement__body p:last-of-type {
    margin-bottom: 2rem;
}

/* Stat row */
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    margin-top: clamp(2.5rem, 5vw, 4rem);
}

.stat {
    background: var(--surface-1);
    padding: 1.9rem 1.6rem;
    transition: var(--transition-smooth);
}

.stat:hover {
    background: var(--surface-2);
}

.stat__value {
    font-family: var(--font-display);
    font-size: clamp(2.2rem, 4vw, 3.2rem);
    color: var(--color-primary);
    line-height: 1;
    margin-bottom: 0.45rem;
}

.stat__label {
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   10. MARQUEE
   -------------------------------------------------------------------------- */
.marquee {
    overflow: hidden;
    border-block: 1px solid var(--line);
    background: var(--surface-1);
    padding-block: 1.4rem;
    user-select: none;
}

.marquee__track {
    display: flex;
    width: max-content;
    animation: marquee 38s linear infinite;
}

.marquee:hover .marquee__track {
    animation-play-state: paused;
}

.marquee__group {
    display: flex;
    align-items: center;
    gap: 3.5rem;
    padding-right: 3.5rem;
    flex: 0 0 auto;
}

.marquee__item {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 2.6vw, 2.2rem);
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
    transition: color 0.3s ease;
}

.marquee__item:nth-child(even) {
    color: var(--color-primary);
}

.marquee__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--gradient-primary-orb);
    flex: 0 0 auto;
}

@keyframes marquee {
    to {
        transform: translateX(-50%);
    }
}

/* --------------------------------------------------------------------------
   11. RAIL (horizontal carousel)
   -------------------------------------------------------------------------- */
.rail {
    position: relative;
}

.rail__track {
    display: flex;
    gap: clamp(1rem, 2vw, 1.75rem);
    overflow-x: auto;
    scroll-behavior: smooth;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
    /* overflow-x: auto makes this a scroll container, which clips vertically
       too. Cards lift 6-8px on hover and cast a 24px glow, so the track needs
       internal headroom; the negative margins cancel it out again, leaving the
       surrounding layout exactly as it was. */
    padding-block: 2rem;
    margin-block: -1.5rem -1rem;
}

.rail__track::-webkit-scrollbar {
    display: none;
}

.rail__track>* {
    scroll-snap-align: start;
    flex: 0 0 auto;
}

.rail__nav {
    display: flex;
    gap: 0.6rem;
}

.rail__btn {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 1px solid var(--line-strong);
    background: transparent;
    color: var(--color-white);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.95rem;
    transition: var(--transition-smooth);
}

.rail__btn:hover:not(:disabled) {
    background: var(--gradient-primary-orb);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    box-shadow: var(--glow-lamp);
}

.rail__btn:disabled {
    opacity: 0.28;
    cursor: not-allowed;
}

/* Progress bar under a rail */
.rail__progress {
    height: 2px;
    background: var(--line);
    margin-top: 1.5rem;
    position: relative;
    overflow: hidden;
    border-radius: 2px;
}

.rail__progress-bar {
    position: absolute;
    inset-block: 0;
    left: 0;
    width: 20%;
    background: var(--gradient-primary);
    border-radius: 2px;
    transition: width 0.2s ease, transform 0.2s ease;
}

/* --------------------------------------------------------------------------
   12. REEL CARD
   -------------------------------------------------------------------------- */
.reel-card {
    width: clamp(280px, 33vw, 460px);
    cursor: pointer;
    background: none;
    border: 0;
    padding: 0;
    text-align: left;
    color: inherit;
    display: block;
}

.reel-card__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-2);
    border: 1px solid var(--line);
    transition: var(--transition-smooth);
}

.reel-card__frame img,
.reel-card__frame video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.7s var(--ease);
}

.reel-card__veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(13, 13, 13, 0.9) 0%, rgba(13, 13, 13, 0.1) 55%, transparent 100%);
    display: flex;
    align-items: flex-end;
    padding: 1.25rem;
    transition: var(--transition-smooth);
}

.reel-card__play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.8);
    width: 68px;
    height: 68px;
    border-radius: 50%;
    background: var(--primary-20);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1.5px solid var(--color-primary);
    box-shadow: var(--glow-md);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-white);
    font-size: 1.15rem;
    opacity: 0;
    transition: var(--transition-smooth);
}

.reel-card__play i {
    margin-left: 3px;
}

.reel-card__tag {
    position: absolute;
    top: 1rem;
    left: 1rem;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    padding: 0.35rem 0.8rem;
    border-radius: 999px;
    background: rgba(13, 13, 13, 0.7);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--line-primary);
    color: var(--color-primary);
}

.reel-card__cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--color-white);
    transform: translateY(10px);
    opacity: 0;
    transition: var(--transition-smooth);
}

.reel-card__cta i {
    color: var(--color-primary);
}

.reel-card:hover .reel-card__frame,
.reel-card:focus-visible .reel-card__frame {
    border-color: var(--line-primary);
    box-shadow: var(--shadow-glow);
    transform: translateY(-6px);
}

.reel-card:hover .reel-card__frame img,
.reel-card:focus-visible .reel-card__frame img {
    transform: scale(1.07);
}

.reel-card:hover .reel-card__play,
.reel-card:focus-visible .reel-card__play {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.reel-card:hover .reel-card__cta,
.reel-card:focus-visible .reel-card__cta {
    opacity: 1;
    transform: translateY(0);
}

.reel-card__info {
    padding-top: 1.1rem;
}

.reel-card__title {
    font-size: 1.12rem;
    font-weight: 600;
    margin-bottom: 0.2rem;
}

.reel-card__meta {
    font-size: 0.78rem;
    color: var(--text-muted);
    letter-spacing: 0.06em;
}

/* Reel grid (reels page) */
.reel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
    gap: clamp(1.25rem, 2.5vw, 2.25rem);
}

.reel-grid .reel-card {
    width: 100%;
}

/* --------------------------------------------------------------------------
   13. WORK CARD (2:3 poster)
   -------------------------------------------------------------------------- */
.work-card {
    width: clamp(200px, 22vw, 280px);
    cursor: pointer;
    display: block;
    background: none;
    border: 0;
    padding: 0;
    text-align: left;
    color: inherit;
}

.work-card__frame {
    position: relative;
    aspect-ratio: 2 / 3;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--surface-2);
    border: 1px solid var(--line);
    transition: var(--transition-smooth);
}

.work-card__frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.7s var(--ease);
}

.work-card__veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(13, 13, 13, 0.94) 0%, rgba(13, 13, 13, 0.15) 50%, transparent 100%);
    opacity: 0;
    transition: var(--transition-smooth);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 1.25rem;
}

.work-card__index {
    position: absolute;
    top: 1rem;
    right: 1rem;
    font-family: var(--font-display);
    font-size: 1.6rem;
    color: rgba(255, 255, 255, 0.28);
    line-height: 1;
    transition: var(--transition-smooth);
}

.work-card:hover .work-card__frame,
.work-card:focus-visible .work-card__frame {
    border-color: var(--line-primary);
    box-shadow: var(--shadow-glow);
    transform: translateY(-8px);
}

.work-card:hover .work-card__frame img,
.work-card:focus-visible .work-card__frame img {
    transform: scale(1.08);
}

.work-card:hover .work-card__veil,
.work-card:focus-visible .work-card__veil {
    opacity: 1;
}

.work-card:hover .work-card__index,
.work-card:focus-visible .work-card__index {
    color: var(--color-primary);
}

.work-card__info {
    padding-top: 1rem;
}

.work-card__title {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.15rem;
}

.work-card__meta {
    font-size: 0.74rem;
    color: var(--text-muted);
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

/* What we actually did on the project — the line a producer is looking for. */
.work-card__role {
    margin-top: 0.35rem;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--text-dim);
}

.work-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr));
    gap: clamp(1.25rem, 2.5vw, 2.25rem);
}

.work-grid .work-card {
    width: 100%;
}

/* On phones the grid becomes a sideways rail — two columns of 2:3 posters is
   too cramped to read at this width. The negative inline margin bleeds the
   track to the screen edges so cards visibly run off the side, which is what
   signals "swipe me"; the matching padding keeps the first and last card
   aligned to the page gutter. */
@media (max-width: 640px) {
    .work-grid {
        display: flex;
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-behavior: smooth;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        -ms-overflow-style: none;
        gap: 1rem;
        margin-inline: calc(var(--gutter) * -1);
        padding-inline: var(--gutter);
        /* overflow-x: auto clips vertically too — headroom for the tap/hover
           lift and its glow, cancelled again by the negative block margins. */
        padding-block: 1.75rem;
        margin-block: -1.5rem -1.25rem;
    }

    .work-grid::-webkit-scrollbar {
        display: none;
    }

    .work-grid .work-card {
        flex: 0 0 auto;
        width: 58vw;
        max-width: 240px;
        scroll-snap-align: start;
    }
}

/* Load more — paged grids */
.load-more {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.1rem;
    margin-top: clamp(2.5rem, 5vw, 4rem);
}

/* .load-more and .btn both set display, which outranks the UA stylesheet's
   [hidden] { display: none }. Without these the hidden state does nothing. */
.load-more[hidden],
.btn[hidden] {
    display: none;
}

.load-more__count {
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.load-more__count b {
    font-weight: 600;
    color: var(--color-primary);
}

/* The chevron nudges down on hover, echoing the direction of travel */
.load-more .btn i {
    transition: transform 0.3s var(--ease);
}

.load-more .btn:hover i {
    transform: translateY(3px);
}

/* --------------------------------------------------------------------------
   14. TEAM CARD
   -------------------------------------------------------------------------- */
.team-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: clamp(1.25rem, 2.5vw, 2rem);
}

.team-card {
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    transition: var(--transition-smooth);
}

.team-card__photo {
    position: relative;
    aspect-ratio: 1;
    overflow: hidden;
    background: var(--surface-2);
}

.team-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: grayscale(100%) contrast(1.05);
    transition: filter 0.5s ease, transform 0.7s var(--ease);
}

.team-card__photo::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(var(--primary-rgb), 0.24), transparent 60%);
    opacity: 0;
    transition: opacity 0.4s ease;
}

.team-card__info {
    padding: 1.25rem;
    text-align: center;
}

.team-card__name {
    font-size: 1.05rem;
    font-weight: 600;
    margin-bottom: 0.2rem;
}

.team-card__role {
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-primary);
}

.team-card:hover {
    transform: translateY(-8px);
    border-color: var(--line-primary);
    box-shadow: var(--shadow-glow);
}

.team-card:hover .team-card__photo img {
    filter: grayscale(0%);
    transform: scale(1.06);
}

.team-card:hover .team-card__photo::after {
    opacity: 1;
}

/* --------------------------------------------------------------------------
   15. CAPABILITY LIST (About)
   -------------------------------------------------------------------------- */
.capability-list {
    border-top: 1px solid var(--line);
}

.capability {
    display: grid;
    grid-template-columns: 90px minmax(0, 1fr) minmax(0, 1.15fr);
    gap: clamp(1rem, 3vw, 3rem);
    align-items: start;
    padding-block: clamp(1.5rem, 3vw, 2.4rem);
    border-bottom: 1px solid var(--line);
    transition: var(--transition-smooth);
}

.capability:hover {
    background: linear-gradient(to right, var(--primary-05), transparent);
    padding-inline: 1rem;
}

.capability__num {
    font-family: var(--font-display);
    font-size: 1.4rem;
    color: var(--color-primary);
    line-height: 1.2;
}

.capability__name {
    font-size: clamp(1.2rem, 2.2vw, 1.7rem);
    font-weight: 600;
}

.capability__desc {
    color: var(--text-dim);
    font-size: 0.96rem;
}

/* --------------------------------------------------------------------------
   16. CTA BAND ("GO AHEAD") — MOONSET

   The band is a night scene: a warm horizon, a ridge, a moon that rises into
   the sky as you scroll, and a cabin lamp on a saddle below it. MOON + LAMP, at
   the bottom of every page — the brand name, spelled out where the visitor
   decides whether to get in touch. The scene is also a toy; see 16a-ii.

   Three mechanisms, ordered by how little they can fail:
     1. The still frame — plain CSS. Moon 85% behind the ridge, lamp lit. This
        is what JS-off, reduced-motion, print and old engines get, and it is
        the composed frame anyway, so there is no separate fallback artwork.
     2. The moonrise — a named view-progress timeline. Scroll IS the clock, so
        there is no rAF, no timer, no infinite animation, nothing to pause.
     3. The ignition — a one-way class latch from main.js (.is-lamplit), which
        also hands the light to the primary CTA through --lit.

   Paint order is tree order (every layer is z-index:auto): sky, moon, veil,
   ridge, lamp. isolation:isolate keeps that local stack from ever racing the
   nav (1000) or the modal shell (1200).
   -------------------------------------------------------------------------- */
.cta-band {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    background: var(--surface-1);
    border-block: 1px solid var(--line);
    text-align: center;
    padding-block: clamp(4.5rem, 10vw, 8rem);
    /* Floors the button row above the ridge at every width, no media query. */
    padding-bottom: calc(clamp(4.5rem, 10vw, 8rem) + var(--ridge-h) * 0.55);

    /* ---- scene ---- */
    --moon-size: clamp(120px, 16vw, 230px);
    /* Well left of centre: it keeps the moon clear of the centred headline at
       narrow widths, and away from .btn--ghost, whose backdrop-filter would
       otherwise re-sample every frame the moon spent behind it. */
    --moon-x: 19%;
    --ridge-h: clamp(78px, 11vw, 140px);
    /* Where it enters from: below the ridge, so it rises into place. */
    --moon-start: calc(var(--moon-size) * 0.55);
    /* Where the moon comes to rest: high in the sky and fully clear of the
       ridge, rather than set behind it. The scroll animation now reads as the
       moon RISING into the section as you reach it. Negative moves it up; the
       moon's bottom starts at --ridge-h, so -1.15 lifts it just over its own
       height above the ridge line. */
    --moon-rest: calc(var(--moon-size) * -1.15);
    --lamp-x: 70%;
    /* 0.44 * --ridge-h == the flat saddle in --ridge-shape. Move the saddle
       and this must move with it. */
    --lamp-y: calc(var(--ridge-h) * 0.44);

    /* Light handoff. 0 == --glow-lamp, 1 == --glow-lamp-lit, byte for byte.
       FAIL-LIT: the default is 1 and only the latch below sets it to 0, so the
       CTA can never render dimmer than it does today. */
    --lit: 1;

    /* Western Ghats: rounded humps, one massif left of centre for the moon to
       set behind, and a deliberate FLAT SADDLE at 66%-74% so the lamp sits on
       a ledge. Held once so the ridge and its rim-light stay congruent. */
    --ridge-shape: polygon(0% 66%, 4% 62%, 9% 55%, 14% 46%, 19% 37%,
            24% 26%, 28% 18%, 31% 15%, 35% 19%, 39% 28%,
            44% 38%, 49% 45%, 54% 49%, 59% 52%, 63% 55%,
            66% 56%, 74% 56%,
            78% 51%, 82% 45%, 86% 41%, 90% 44%, 94% 50%, 97% 56%, 100% 61%,
            100% 101%, 0% 101%);
}

/* ---- 16a. the scene ---- */
.cta-sky {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

/* The warm horizon. Static. Without it a near-black ridge on --surface-1 is
   only a few levels apart and reads as nothing — this is what it bites. */
.cta-sky::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
            transparent 0%,
            rgba(var(--primary-rgb), 0.03) 58%,
            rgba(var(--primary-rgb), 0.07) 100%);
}

.cta-sky__moon {
    position: absolute;
    left: var(--moon-x);
    bottom: var(--ridge-h);
    width: var(--moon-size);
    aspect-ratio: 1;
    border-radius: 50%;
    /* Two near-invisible maria over the brand orb, so it reads as a moon. */
    background:
        radial-gradient(circle at 63% 37%, rgba(0, 0, 0, 0.05) 0 13%, transparent 14%),
        radial-gradient(circle at 39% 64%, rgba(0, 0, 0, 0.04) 0 8%, transparent 9%),
        var(--gradient-primary-orb);
    /* The second shadow is the band's old centred ambient wash, re-attached to
       the moon so the light travels instead of sitting in the middle. */
    box-shadow:
        var(--glow-lamp),
        0 0 clamp(90px, 14vw, 190px) clamp(20px, 5vw, 60px) rgba(var(--primary-rgb), 0.10);
    /* Still frame == the END of cta-moonrise, so there are not two states to
       keep in sync. */
    transform: translate(-50%, var(--moon-rest));
    opacity: 1;
}

/* Legibility veil. Sits between the moon and the ridge in TREE order, so it
   dims the moon behind the copy and can never touch the silhouette or the lamp,
   which paint after it. Built from --surface-1's own channels, so it is
   invisible against the band and shows only where the moon passes under the
   headline. White display type over the cream moon is ~1.19:1 — a hard
   contrast failure; this takes it to ~5.8:1. Raise the 0.88 if a check ever
   fails at some width; do not move the copy. */
.cta-sky__veil {
    position: absolute;
    inset: 0;
    /* Load-bearing. pointer-events is INHERITED, and this covers the whole sky
       and paints after the moon — so once .cta-sky takes pointer-events:auto
       for star placement, the veil silently swallows every press: the moon
       stops dragging and no press ever reaches the sky itself. */
    pointer-events: none;
    background: radial-gradient(ellipse 62% 46% at 50% 46%,
            rgba(var(--surface-1-rgb), 0.88) 0%,
            rgba(var(--surface-1-rgb), 0.58) 42%,
            rgba(var(--surface-1-rgb), 0) 76%);
}

/* The rim-light trick: filter applies BEFORE clip-path, so a drop-shadow on a
   clipped box gets clipped away. Instead, two congruent boxes — a warm fill
   with its ::before in near-black shifted down 1.5px. What survives is a
   1.5px moonlit sliver following the exact diagonal of the silhouette. */
.cta-sky__ridge {
    position: absolute;
    inset: auto 0 0 0;
    height: var(--ridge-h);
    background: rgba(var(--primary-rgb), 0.28);
    clip-path: var(--ridge-shape);
}

.cta-sky__ridge::before {
    content: '';
    position: absolute;
    inset: 1.5px 0 -1.5px;
    background: var(--color-black);
    clip-path: var(--ridge-shape);
}

/* The lamp. Default state is LIT — see the FAIL-LIT note on --lit. */
.cta-sky__lamp {
    position: absolute;
    left: var(--lamp-x);
    bottom: var(--lamp-y);
    width: 6px;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--gradient-primary-orb);
    box-shadow: var(--glow-lamp-lit);
    /* The ::before pool below is up to a 300px circle and hit-tests as this
       element, so without this the lamp punches an invisible dead zone that
       size into the sky and presses inside it place no star. */
    pointer-events: none;
    /* Centres the disc ON the saddle line, half over the silhouette — a lit
       window at the ridge edge. The transform also makes this a stacking
       context, which is what keeps the pool's z-index:-1 inside it. */
    transform: translate(-50%, 50%);
    opacity: 1;
}

/* The pool the lamp throws. No animation of its own: as a child of the lamp it
   inherits the whole strike — flicker and bloom — for free. */
.cta-sky__lamp::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: -1;
    width: clamp(150px, 24vw, 300px);
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle,
            rgba(var(--primary-rgb), 0.17) 0%,
            rgba(var(--primary-rgb), 0.07) 34%,
            transparent 68%);
    transform: translate(-50%, -50%);
}

/* ---- 16a-ii. the scene is a toy ----
   Drag the moon; tap the hills to light a window. Both persist per visitor.

   The drag uses the independent `translate` property rather than `transform`,
   because the scroll-driven moonrise animation owns `transform`. They compose
   instead of fighting, so nothing here has to reach into that animation. */
.cta-band {
    --moon-drag-x: 0px;
    --moon-drag-y: 0px;
}

.cta-sky__moon {
    /* Explicit rather than inherited from .cta-sky below, so that reordering
       these two rules can never silently switch the moon off. */
    pointer-events: auto;
    cursor: grab;
    /* pan-y keeps vertical page scrolling working when a thumb lands on the
       moon; the horizontal axis is ours. A mouse is unaffected and gets both. */
    touch-action: pan-y;
    translate: var(--moon-drag-x) var(--moon-drag-y);
}

.cta-band.is-moon-held .cta-sky__moon {
    cursor: grabbing;
}

/* Once the visitor moves it, it is theirs — the scroll animation lets go so
   the moon stays where it was left. */
.cta-band.is-moon-moved .cta-sky__moon {
    animation: none;
}

/* Settle after release. Not while held: the moon must track the finger 1:1. */
@media (prefers-reduced-motion: no-preference) {
    .cta-band:not(.is-moon-held) .cta-sky__moon {
        transition: translate 0.45s var(--ease);
    }
}

/* The sky itself takes presses so stars can be placed. Overrides the
   pointer-events:none in 16a, which was written when the scene was purely
   decorative. Everything drawn over the sky opts back OUT so it cannot swallow
   a press: the veil (covers all of it), the lamp (300px pool), placed stars,
   and .cta-band__inner over the middle of the band — see 17. The ridge is the
   deliberate exception: clipped to its silhouette, it absorbs presses on the
   hills, where a star would be invisible anyway. */
.cta-sky {
    pointer-events: auto;
}

/* A star someone put in the sky. Deliberately tiny — --star-max caps how far
   holding can grow one, so the sky can never fill up with blobs. */
.cta-band {
    --star-min: 1px;
    --star-max: 3px;
}

.cta-star {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: var(--size, var(--star-min));
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--primary-light);
    box-shadow: 0 0 6px 1px rgba(var(--primary-rgb), 0.55);
    transform: translate(-50%, -50%);
    pointer-events: none;
}

/* Holding grows the star. The growth is a plain CSS transition, so there is no
   rAF loop for it: JS starts it, then freezes the interpolated width on
   release by reading the computed value. */
.cta-star.is-growing {
    transition: width 1.4s linear;
}

@media (prefers-reduced-motion: reduce) {
    .cta-star.is-growing {
        transition: none;
    }
}

/* The invitation, and the count. Real text in .cta-band__inner, NOT inside the
   aria-hidden scene, so screen readers announce it like any other copy. (It is
   not mouse-selectable — see the pointer-events note on .cta-band__inner.) */
.cta-play {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    margin-top: 2.2rem;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.cta-play__reset {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    letter-spacing: inherit;
    color: var(--text-muted);
    border-bottom: 1px solid var(--line-strong);
    transition: var(--transition-fast);
}

.cta-play__reset:hover {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.cta-play__reset[hidden] {
    display: none;
}

/* Touch has no hover, so the crosshair hint never lands. Say it plainly. */
@media (pointer: coarse) {
    .cta-sky__moon {
        cursor: default;
    }
}

/* ---- 16b. the moonrise — scroll is the clock ----
   Motion is opted INTO, so there is nothing to override and no !important
   fight with the global reduced-motion block. That block only zeroes
   animation-duration, which a scroll-driven animation ignores entirely —
   negative-gating this would have failed silently.

   `animation: cta-moonrise linear both` looks like it is missing a duration. It
   is not: the shorthand resets animation-duration to `auto`, which on a
   progress timeline means the full range. Declaration order is load-bearing —
   the shorthand also resets animation-timeline and animation-range, so both
   longhands MUST come after it. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .cta-band {
            view-timeline: --cta-moonrise block;
        }

        .cta-sky__moon {
            animation: cta-moonrise linear both;
            animation-timeline: --cta-moonrise;
            animation-range: entry 4% entry 86%;
        }
    }
}

/* ---- 16c. the ignition — one-way latch ----
   FAIL-LIT, inverted here and only here. The unlit state is armed in CSS at
   first paint rather than from JS, which is what stops the lamp flashing
   lit -> dark -> lit when someone reloads while scrolled to the bottom (scroll
   restoration paints the band before main.js runs).

   Gated on html:not(.no-js) rather than @media (scripting: enabled): .no-js is
   re-added by the boot watchdog when main.js fails to report in, so a broken
   or blocked main.js settles to the lit still frame instead of leaving the
   lamp dark forever. */
@media (prefers-reduced-motion: no-preference) {
    html:not(.no-js) .cta-band:not(.is-lamplit) {
        --lit: 0;
    }

    html:not(.no-js) .cta-band:not(.is-lamplit) .cta-sky__lamp {
        opacity: 0;
    }

    .cta-band.is-lamplit .cta-sky__lamp {
        animation: cta-lamp-strike 1150ms linear both;
    }
}

/* ---- 16d. keyframes ----
   transform + opacity only. Both are compositor properties, so the moon's
   large box-shadow rasterises into its layer once and is merely composited as
   it travels. Do not add a colour, blur, filter or box-shadow keyframe here
   without re-running a paint-flashing check. */
@keyframes cta-moonrise {
    from {
        transform: translate(-50%, var(--moon-start));
        opacity: 0.55;
    }

    to {
        transform: translate(-50%, var(--moon-rest));
        opacity: 1;
    }
}

/* Filament catch: over-bright, dip, settle. `linear` on purpose, so the three
   beats land crisply instead of being eased into mush. */
@keyframes cta-lamp-strike {
    0% {
        opacity: 0;
        transform: translate(-50%, 50%) scale(0.35);
    }

    18% {
        opacity: 1;
        transform: translate(-50%, 50%) scale(1.15);
    }

    32% {
        opacity: 0.45;
        transform: translate(-50%, 50%) scale(0.95);
    }

    48% {
        opacity: 1;
        transform: translate(-50%, 50%) scale(1.05);
    }

    100% {
        opacity: 1;
        transform: translate(-50%, 50%) scale(1);
    }
}

/* ---- 16e. the handoff — the lamp is what lights the CTA ----
   The point of the whole scene. At --lit 0 this box-shadow is byte-identical
   to --glow-lamp, i.e. exactly what the button renders today; at --lit 1 it is
   --glow-lamp-lit. No new colour, and the button only ever gets brighter.

   The :hover rule below is mandatory, not decorative: this selector is (0,2,0),
   the same as .btn--primary:hover, and it comes later in the file — without it,
   hover would stop changing the glow. */
.cta-band__actions .btn--primary {
    box-shadow:
        0 0 calc(16px + 6px * var(--lit)) rgba(var(--primary-rgb), calc(0.38 + 0.24 * var(--lit))),
        0 0 calc(44px + 16px * var(--lit)) rgba(var(--primary-rgb), calc(0.16 + 0.12 * var(--lit)));
    transition: var(--transition-smooth), box-shadow 820ms var(--ease) 260ms;
}

.cta-band__actions .btn--primary:hover,
.cta-band__actions .btn--primary:focus-visible {
    box-shadow: var(--glow-lamp-lit);
    transition: var(--transition-smooth);
}

/* ---- 16f. print ---- */
@media print {
    .cta-sky {
        display: none;
    }

    .cta-band {
        padding-bottom: clamp(4.5rem, 10vw, 8rem);
    }
}

.cta-band__inner {
    position: relative;
    z-index: 1;
    /* Load-bearing, with 16a-ii. This block spans the middle of the band and
       the moon rests directly behind it (at 1920px, ~200px of the moon's 230px
       height is under this box), so leaving it opaque to pointers kills most of
       the drag target and the whole centre of the sky. z-index 1 stays — the
       copy must still PAINT above the scene; only hit-testing falls through.
       The trade is that the headline is no longer text-selectable. */
    pointer-events: none;
}

/* ...and the things that are actually controls take their events back. Not the
   whole rows: the gaps between the buttons stay transparent, so a press there
   still lands a star. Keyboard focus is untouched by pointer-events. */
.cta-band__actions .btn,
.cta-play__reset {
    pointer-events: auto;
}

.cta-band__title {
    margin-bottom: 1.2rem;
}

.cta-band__lede {
    color: var(--text-dim);
    max-width: 48ch;
    margin: 0 auto 2.6rem;
    font-size: 1.05rem;
}

.cta-band__actions {
    display: flex;
    gap: 1rem;
    justify-content: center;
    flex-wrap: wrap;
}

/* Contact tiles */
.contact-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
}

.contact-tile {
    background: var(--surface-1);
    padding: clamp(1.75rem, 3vw, 2.5rem);
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    transition: var(--transition-smooth);
}

.contact-tile:hover {
    background: var(--surface-2);
}

.contact-tile__icon {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--primary-10);
    border: 1px solid var(--line-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary);
    font-size: 1.1rem;
    transition: var(--transition-smooth);
}

.contact-tile:hover .contact-tile__icon {
    background: var(--gradient-primary-orb);
    color: var(--color-on-primary);
    box-shadow: var(--glow-lamp);
}

.contact-tile__label {
    font-size: 0.68rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.contact-tile__value {
    font-size: 1.02rem;
    font-weight: 500;
    word-break: break-word;
}

.contact-tile a.contact-tile__value:hover {
    color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   17. FORMS
   -------------------------------------------------------------------------- */
.form-panel {
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: clamp(1.75rem, 4vw, 3.25rem);
}

.field {
    margin-bottom: 1.4rem;
}

.field__label {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 0.6rem;
}

.field__label i {
    color: var(--color-primary);
}

/* Wrapper for an input with an inline control (e.g. show-password) */
.field__control {
    position: relative;
}

.field__control .field__input {
    padding-right: 3.1rem;
}

.field__toggle {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.95rem;
    transition: var(--transition-fast);
}

.field__toggle:hover {
    color: var(--color-primary);
    background: var(--primary-10);
}

.field__toggle.is-on {
    color: var(--color-primary);
}

.field__input,
.field__select,
.field__textarea {
    width: 100%;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--color-white);
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 400;
    padding: 0.9rem 1.1rem;
    transition: var(--transition-fast);
}

.field__textarea {
    resize: vertical;
    min-height: 150px;
}

.field__select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffe8cf'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 16px;
    padding-right: 2.6rem;
    cursor: pointer;
}

.field__select option {
    background: var(--surface-2);
    color: var(--color-white);
}

.field__input::placeholder,
.field__textarea::placeholder {
    color: rgba(255, 255, 255, 0.28);
}

.field__input:focus,
.field__select:focus,
.field__textarea:focus {
    outline: none;
    /* background-color, not the background shorthand — the shorthand would
       reset background-image and erase .field__select's caret while focused. */
    background-color: rgba(255, 255, 255, 0.07);
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--primary-10);
}

.field__error {
    display: none;
    color: #ff5c5c;
    font-size: 0.8rem;
    margin-top: 0.45rem;
}

.field.is-invalid .field__input,
.field.is-invalid .field__select,
.field.is-invalid .field__textarea {
    border-color: #ff5c5c;
}

.field.is-invalid .field__error {
    display: block;
}

.form-note {
    margin-top: 1.25rem;
    font-size: 0.85rem;
    text-align: center;
}

/* Inline alerts */
.alert {
    padding: 0.9rem 1.15rem;
    border-radius: 10px;
    font-size: 0.9rem;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    border: 1px solid transparent;
    text-align: left;
}

.alert i {
    margin-top: 0.2rem;
}

.alert--success {
    background: rgba(46, 204, 113, 0.1);
    border-color: rgba(46, 204, 113, 0.35);
    color: #7ee2a8;
}

.alert--danger {
    background: rgba(255, 76, 76, 0.1);
    border-color: rgba(255, 76, 76, 0.35);
    color: #ff8c8c;
}

.alert--warning {
    background: var(--primary-10);
    border-color: var(--line-primary);
    color: #ffb277;
}

.alert--info {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--line);
    color: var(--text-dim);
}

.is-hidden {
    display: none !important;
}

/* --------------------------------------------------------------------------
   18. MODAL (video player + contact)
   -------------------------------------------------------------------------- */
.modal-shell {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: clamp(1rem, 4vw, 2.5rem);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.35s var(--ease), visibility 0.35s;
}

.modal-shell.is-open {
    opacity: 1;
    visibility: visible;
}

.modal-shell__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(5, 5, 5, 0.88);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

.modal-shell__panel {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 1100px;
    max-height: 90svh;
    overflow-y: auto;
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-deep);
    transform: translateY(20px) scale(0.98);
    transition: transform 0.4s var(--ease);
}

.modal-shell.is-open .modal-shell__panel {
    transform: translateY(0) scale(1);
}

.modal-shell__panel--sm {
    max-width: 620px;
}

.modal-shell__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.15rem clamp(1.1rem, 3vw, 1.9rem);
    border-bottom: 1px solid var(--line);
}

.modal-shell__title {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    text-transform: uppercase;
}

.modal-shell__title i {
    color: var(--color-primary);
}

.modal-shell__close {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1px solid var(--line-strong);
    background: transparent;
    color: var(--color-white);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition-fast);
}

.modal-shell__close:hover {
    background: var(--gradient-primary-orb);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    box-shadow: var(--glow-lamp);
    transform: rotate(90deg);
}

.modal-shell__body {
    padding: clamp(1.1rem, 3vw, 1.9rem);
}

.modal-shell__body--flush {
    padding: 0;
}

.video-frame {
    aspect-ratio: 16 / 9;
    background: #000;
    width: 100%;
}

.video-frame video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #000;
}

/* Lightbox for work posters */
.lightbox-figure {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
}

.lightbox-figure img {
    max-height: 68svh;
    width: auto;
    border-radius: var(--radius);
    border: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   19. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
    background: var(--surface-1);
    border-top: 1px solid var(--line);
    padding-top: clamp(3.5rem, 7vw, 5.5rem);
}

.footer-top {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
    gap: clamp(2rem, 5vw, 4rem);
    padding-bottom: clamp(2.5rem, 5vw, 4rem);
}

.footer-brand__mark {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    margin-bottom: 1.1rem;
}

.footer-brand__mark i {
    color: var(--color-primary);
    font-size: 1.7rem;
    filter: var(--glow-icon);
}

.footer-brand__blurb {
    color: var(--text-dim);
    max-width: 40ch;
    font-size: 0.95rem;
    margin-bottom: 1.75rem;
}

.footer-social {
    display: flex;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.footer-social a {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: rgba(255, 255, 255, 0.03);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    color: var(--text-dim);
    transition: var(--transition-smooth);
}

.footer-social a:hover {
    background: var(--gradient-primary-orb);
    border-color: var(--color-primary);
    color: var(--color-on-primary);
    transform: translateY(-3px);
    box-shadow: var(--glow-lamp);
}

.footer-col__title {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--color-primary);
    margin-bottom: 1.3rem;
}

.footer-col__list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.footer-col__list a,
.footer-col__list li {
    color: var(--text-dim);
    font-size: 0.93rem;
    display: flex;
    align-items: center;
    gap: 0.65rem;
}

.footer-col__list a:hover {
    color: var(--color-primary);
    transform: translateX(4px);
}

.footer-col__list i {
    color: var(--color-primary);
    width: 16px;
    font-size: 0.85rem;
    flex: 0 0 auto;
}

.footer-bottom {
    border-top: 1px solid var(--line);
    padding-block: 1.6rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    font-size: 0.78rem;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.footer-bottom__links {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.footer-bottom__links a:hover {
    color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   19b. THE LAMP SWITCH

   Pull the cord and the studio turns its lamp off: the whole site drops from
   warm lamp-light to cold moonlight. It is the one thing on the site a visitor
   plays with, and the one they show someone else.

   It is this cheap ONLY because the palette is single-sourced. Everything —
   every gradient, glow, border, wash and button — derives from three tokens,
   so re-pointing those three repaints the entire site's mood. There is no
   second theme to maintain.
   -------------------------------------------------------------------------- */
.lamp-switch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.9rem;
    margin: 0 auto;
    padding: 0 1rem 2.4rem;
    background: none;
    border: 0;
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    transition: color 0.3s var(--ease);
}

.lamp-switch:hover {
    color: var(--color-primary);
}

/* The cord: a hairline that fades in from the top, with a bead on the end. */
.lamp-switch__cord {
    position: relative;
    display: block;
    width: 1px;
    height: 46px;
    background: linear-gradient(to bottom, transparent, var(--color-primary));
    transform-origin: 50% 0;
    transition: transform 0.35s var(--ease);
}

.lamp-switch__cord::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -5px;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    transform: translateX(-50%);
    background: var(--gradient-primary-orb);
    box-shadow: var(--glow-lamp);
    transition: box-shadow 0.3s var(--ease);
}

/* Pull it down a little on hover, further on the actual click. */
.lamp-switch:hover .lamp-switch__cord {
    transform: scaleY(1.14);
}

.lamp-switch:active .lamp-switch__cord {
    transform: scaleY(1.3);
    transition-duration: 0.08s;
}

.lamp-switch:focus-visible .lamp-switch__cord::after {
    box-shadow: var(--glow-lamp-lit);
}

/* ---- lamp OFF: the whole site goes cold ----
   Only the three source tokens and the surfaces change. Nothing else in the
   stylesheet knows this state exists. */
html.lamp-off {
    --primary-light: #e6edff;
    --primary-warm: #9fb4d8;
    --primary-rgb: 159, 180, 216;

    --surface-0: #04050a;
    --surface-1: #070911;
    --surface-2: #0a0d17;
    --surface-3: #10141f;

    --text: #dbe3f3;
    --text-dim: #93a1bd;
    --text-muted: #64708a;
}

/* A lamp that is off should not still be glowing. */
html.lamp-off .cta-sky__lamp {
    opacity: 0.12;
    box-shadow: none;
}

html.lamp-off .hero__breath {
    opacity: 0.08;
}

/* Ease the change rather than snapping it, so it reads as a light going out.
   Kept to the few large surfaces — animating every element would be a
   full-page repaint for no extra legibility. */
body,
.site-nav,
.site-footer,
.cta-band,
.section--ash,
.section--panel {
    transition: background-color 0.7s var(--ease), color 0.7s var(--ease);
}

@media (prefers-reduced-motion: reduce) {

    body,
    .site-nav,
    .site-footer,
    .cta-band,
    .section--ash,
    .section--panel {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   20. STATES: loading / empty / error
   -------------------------------------------------------------------------- */
.state {
    width: 100%;
    padding: clamp(2.5rem, 6vw, 4.5rem) 1rem;
    text-align: center;
    color: var(--text-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    grid-column: 1 / -1;
}

.state i {
    font-size: 1.6rem;
    color: var(--color-primary);
    opacity: 0.6;
}

.state--error {
    color: #ff8c8c;
}

.spinner {
    width: 34px;
    height: 34px;
    border: 2px solid var(--line-strong);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

.spinner--sm {
    width: 16px;
    height: 16px;
    border-width: 2px;
}

/* The default spinner is cream-on-dark. contact.js and admin.js inject it into
   primary-filled submit buttons, where cream-on-cream would paint nothing — so
   invert it there. Without this the only motion cue during a multi-second
   upload or send disappears. */
.btn--primary .spinner,
.btn--outline:hover .spinner {
    border-color: rgba(13, 13, 13, 0.22);
    border-top-color: var(--color-on-primary);
    box-shadow: none;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

/* --------------------------------------------------------------------------
   21. SCROLL REVEAL
   -------------------------------------------------------------------------- */
.reveal {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

/* Without this the site renders BLANK when scripting is unavailable: .reveal is
   the initial state and the ONLY thing that adds .is-visible is the observer in
   main.js — which would hide every heading, lede and BOTH CTA buttons on all
   five pages. .no-js restores the settled state directly (not via a transition,
   which the reduced-motion block below neutralises anyway). */
html.no-js .reveal {
    opacity: 1;
    transform: none;
}

.reveal.is-visible {
    opacity: 1;
    transform: none;
}

.reveal[data-delay="1"] {
    transition-delay: 0.1s;
}

.reveal[data-delay="2"] {
    transition-delay: 0.2s;
}

.reveal[data-delay="3"] {
    transition-delay: 0.3s;
}

.reveal[data-delay="4"] {
    transition-delay: 0.4s;
}

@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .reveal {
        opacity: 1;
        transform: none;
    }
}

/* --------------------------------------------------------------------------
   22. RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
    .statement {
        grid-template-columns: 1fr;
    }

    .footer-top {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .footer-brand {
        grid-column: 1 / -1;
    }
}

@media (max-width: 991px) {

    .nav-menu,
    .nav-actions .btn {
        display: none;
    }

    .nav-toggle {
        display: flex;
    }

    .hero__meta {
        display: none;
    }

    .capability {
        grid-template-columns: 50px minmax(0, 1fr);
    }

    .capability__desc {
        grid-column: 2;
    }
}

@media (max-width: 640px) {
    :root {
        --nav-h: 70px;
    }

    .section-head {
        align-items: flex-start;
    }

    .hero__actions {
        width: 100%;
    }

    .hero__actions .btn {
        flex: 1 1 auto;
    }

    .footer-top {
        grid-template-columns: 1fr;
    }

    .footer-bottom {
        justify-content: center;
        text-align: center;
    }

    .scroll-cue {
        display: none;
    }

    .reel-card {
        width: 82vw;
    }

    .work-card {
        width: 46vw;
    }
}

/* Utilities */
.u-mt-lg {
    margin-top: clamp(2rem, 4vw, 3.5rem);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 3px;
}
