/* ==========================================================================
   ChakraBit design system
   Engineering-editorial. Type and hairlines carry the page; the only imagery
   is real product screenshots. The hero is an interactive canvas field.

   Radius rule (no exceptions):
     containers / media  14px   (--r-lg)
     inner elements      8px    (--r-md)
     small labels        4px    (--r-sm)
   ========================================================================== */

/* ── Fonts ───────────────────────────────────────────────────────────────── */

@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('/fonts/geist-sans.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Geist Mono';
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url('/fonts/geist-mono.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root {
    --paper:        #fafaf8;
    --paper-sunk:   #f1f0ec;
    --paper-raised: #ffffff;
    --ink:          #171614;
    --ink-2:        #55524d;
    --ink-3:        #6e6a63;
    --line:         #e3e1dc;
    --line-strong:  #cdcac3;

    /* One accent. Burnt vermillion. Used for every emphasis on the page. */
    --accent:       #c2461e;
    --accent-ink:   #a13b19;
    --accent-wash:  rgba(194, 70, 30, 0.10);
    --on-accent:    #ffffff;

    /* Canvas field, read by site.js. */
    --field-dot:    23, 22, 20;
    --field-hot:    194, 70, 30;

    --shadow-sm: 0 1px 2px rgba(38, 30, 24, 0.05);
    --shadow-md: 0 10px 30px -10px rgba(38, 30, 24, 0.16);
    --shadow-lg: 0 34px 70px -28px rgba(38, 30, 24, 0.3);

    --r-sm: 4px;
    --r-md: 8px;
    --r-lg: 14px;

    --gutter: clamp(1.25rem, 4vw, 2.75rem);
    --page: 1320px;
    --bay: clamp(5rem, 10vw, 9rem);

    --sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

    --ease: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-io: cubic-bezier(0.65, 0, 0.35, 1);

    /* z-index ladder. Nothing lives outside it. */
    --z-base: 1;
    --z-raised: 2;
    --z-nav: 50;
    --z-grain: 60;

    /* Extra stage tint in dark mode, where a wash reads weaker. */
    --stage-boost: 0%;
}

@media (prefers-color-scheme: dark) {
    :root {
        --paper:        #111010;
        --paper-sunk:   #0a0a09;
        --paper-raised: #191817;
        --ink:          #f2f0ec;
        --ink-2:        #aea9a1;
        --ink-3:        #8a857d;
        --line:         #2a2825;
        --line-strong:  #3b3835;

        --accent:       #e8683c;
        --accent-ink:   #f08055;
        --accent-wash:  rgba(232, 104, 60, 0.14);
        --on-accent:    #190f07;

        --field-dot:    242, 240, 236;
        --field-hot:    232, 104, 60;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
        --shadow-md: 0 10px 30px -10px rgba(0, 0, 0, 0.6);
        --shadow-lg: 0 34px 70px -28px rgba(0, 0, 0, 0.75);

        --stage-boost: 6%;
    }
}

/* ── Reset & base ────────────────────────────────────────────────────────── */

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

html {
    scroll-behavior: smooth;
    scroll-padding-top: 6rem;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.6;
    color: var(--ink);
    background: var(--paper);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

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

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: var(--r-sm);
}

.skip-link {
    position: absolute;
    left: 1rem;
    top: 1rem;
    z-index: 100;
    padding: 0.7rem 1.1rem;
    background: var(--ink);
    color: var(--paper);
    font-size: 0.85rem;
    font-weight: 600;
    border-radius: var(--r-md);
    text-decoration: none;
    /* transform, not top: animating top runs layout on every frame. */
    transform: translateY(-200%);
    transition: transform 0.2s var(--ease);
}

.skip-link:focus { transform: none; }

.grain {
    position: fixed;
    inset: 0;
    z-index: var(--z-grain);
    pointer-events: none;
    opacity: 0.5;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.13'/%3E%3C/svg%3E");
}

/* Pre-inverted noise rather than filter: invert(1). A CSS filter on a fixed,
   viewport-sized layer costs a full-screen pass on every composite. */
@media (prefers-color-scheme: dark) {
    .grain {
        opacity: 0.3;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='-1' intercept='1'/%3E%3CfeFuncG type='linear' slope='-1' intercept='1'/%3E%3CfeFuncB type='linear' slope='-1' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.13'/%3E%3C/svg%3E");
    }
}

/* ── Type ────────────────────────────────────────────────────────────────── */

.display {
    font-size: clamp(2.3rem, 6.2vw, 5.4rem);
    font-weight: 600;
    letter-spacing: -0.045em;
    line-height: 0.98;
    text-wrap: balance;
}

.h2 {
    font-size: clamp(1.9rem, 4.4vw, 3.4rem);
    font-weight: 600;
    letter-spacing: -0.04em;
    line-height: 1.02;
    text-wrap: balance;
}

.h3 {
    font-size: clamp(1.1rem, 1.7vw, 1.35rem);
    font-weight: 600;
    letter-spacing: -0.022em;
    line-height: 1.25;
}

.lede {
    font-size: clamp(1rem, 1.4vw, 1.15rem);
    line-height: 1.6;
    color: var(--ink-2);
    max-width: 46ch;
    text-wrap: pretty;
}

.prose p {
    color: var(--ink-2);
    line-height: 1.75;
    max-width: 62ch;
    text-wrap: pretty;
}

.prose p + p { margin-top: 1.1rem; }

.meta {
    font-family: var(--mono);
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-3);
    font-variant-numeric: tabular-nums;
}

/* ── Layout ──────────────────────────────────────────────────────────────── */

.wrap {
    width: 100%;
    max-width: var(--page);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

/* Optically balanced: bottom carries slightly more than top. */
.bay {
    padding-top: var(--bay);
    padding-bottom: calc(var(--bay) * 1.15);
}

.edge { border-top: 1px solid var(--line); }

/* ── Line-mask reveal ────────────────────────────────────────────────────
   Authored one span per line. The clip box is grown with padding and pulled
   back with a matching negative margin, so descenders and italics never clip
   while the layout box stays exactly where it was. */

.ln {
    display: block;
    overflow: hidden;
    padding-bottom: 0.14em;
    margin-bottom: -0.14em;
}

/* Every hidden start state is scoped to .js, which an inline snippet in the
   head sets before first paint. Without scripting, or if site.js fails to
   run, the page renders fully visible instead of blank. */
.ln-i { display: block; }

.js .ln-i {
    transform: translateY(108%);
    transition: transform 0.95s var(--ease);
    transition-delay: calc(var(--l, 0) * 90ms);
}

.js [data-reveal='in'] .ln-i,
.js [data-reveal='done'] .ln-i,
.js.is-ready .hero .ln-i { transform: none; }

/* Everything else fades up on entry.
   The transition lives on the 'in' state alone, never on the base selector.
   Left on the base, it outranks each component's own transition for the whole
   session: a .work card would inherit the 800ms reveal timing and its 80ms
   stagger delay for its hover lift too. site.js flips the state to 'done' once
   the entry has played, which hands the transition property back. */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(20px);
}

.js [data-reveal='in'] {
    opacity: 1;
    transform: none;
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
    transition-delay: calc(var(--i, 0) * 80ms);
}

.js [data-reveal='done'] { opacity: 1; transform: none; }
.js [data-reveal].has-lines { opacity: 1; transform: none; }

/* ── Navigation ──────────────────────────────────────────────────────────── */

.nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: var(--z-nav);
    background: color-mix(in srgb, var(--paper) 72%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid transparent;
    transition: border-color 0.3s var(--ease), background 0.3s var(--ease);
}

.nav[data-scrolled='true'] {
    border-bottom-color: var(--line);
    background: color-mix(in srgb, var(--paper) 92%, transparent);
}

/* Reading progress. Pure CSS scroll timeline: no scroll listener anywhere. */
.progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: 0 50%;
}

@supports (animation-timeline: scroll()) {
    .progress {
        animation: progress-grow linear both;
        animation-timeline: scroll(root block);
    }
}

@keyframes progress-grow { to { transform: scaleX(1); } }

.nav-inner {
    max-width: var(--page);
    margin-inline: auto;
    padding-inline: var(--gutter);
    height: 70px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    color: var(--ink);
    text-decoration: none;
    flex-shrink: 0;
}

.brand svg { flex-shrink: 0; transition: transform 0.6s var(--ease); }
.brand:hover svg { transform: rotate(-90deg); }

/* Brand mark, geometry unchanged. Only the palette follows the theme. */
.mark-bg { fill: var(--ink); }
.mark-fg { fill: var(--paper); }
.mark-ac { fill: var(--accent); }

.nav-links {
    display: flex;
    align-items: center;
    gap: clamp(1rem, 2.2vw, 2.1rem);
    list-style: none;
}

.nav-links a {
    display: block;
    font-size: 0.875rem;
    font-weight: 450;
    color: var(--ink-2);
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.25s var(--ease);
}

.nav-links a:hover, .nav-links a[aria-current='true'] { color: var(--ink); }

/* Label rolls up, a duplicate rolls in behind it. */
.roll {
    display: block;
    position: relative;
    overflow: hidden;
    padding-block: 0.3rem;
}

.roll span {
    display: block;
    transition: transform 0.45s var(--ease);
}

.roll span::after {
    content: attr(data-label);
    position: absolute;
    left: 0;
    top: 100%;
    width: 100%;
    color: var(--accent);
}

.nav-links a:hover .roll span,
.nav-links a:focus-visible .roll span { transform: translateY(-100%); }

.nav-toggle {
    display: none;
    width: 42px;
    height: 42px;
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 4px;
}

.nav-toggle span {
    display: block;
    width: 16px;
    height: 1.5px;
    background: currentColor;
    transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}

.nav-toggle[aria-expanded='true'] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav-toggle[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded='true'] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    padding: 0.85rem 1.5rem;
    font-size: 0.9rem;
    font-weight: 550;
    letter-spacing: -0.012em;
    line-height: 1.2;
    white-space: nowrap;
    border-radius: var(--r-md);
    border: 1px solid transparent;
    text-decoration: none;
    overflow: hidden;
    isolation: isolate;
    transition: color 0.3s var(--ease), border-color 0.3s var(--ease),
                box-shadow 0.3s var(--ease), transform 0.25s var(--ease);
}

/* Fill wipes up from the bottom instead of a flat colour swap. */
.btn::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    transform: translateY(101%);
    transition: transform 0.45s var(--ease);
}

.btn:hover::before { transform: translateY(0); }
.btn .arw { transition: transform 0.35s var(--ease); }
.btn:hover .arw { transform: translateX(4px); }

/* Lift on hover, press back down on click. The button never leaves its
   place in the layout. */
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-primary {
    background: var(--ink);
    color: var(--paper);
    box-shadow: var(--shadow-sm);
}

.btn-primary::before { background: var(--accent); }
.btn-primary:hover { color: var(--on-accent); box-shadow: var(--shadow-md); }

.btn-primary:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    transform: none;
    color: var(--paper);
}

.btn-primary:disabled::before { transform: translateY(101%); }

.btn-ghost {
    color: var(--ink);
    border-color: var(--line-strong);
}

.btn-ghost::before { background: var(--ink); }
.btn-ghost:hover { color: var(--paper); border-color: var(--ink); }

.link {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    font-size: 0.9rem;
    font-weight: 550;
    color: var(--accent-ink);
    text-decoration: none;
    text-underline-offset: 4px;
    text-decoration-thickness: 1px;
}

.link:hover { text-decoration: underline; }
.link .arw { transition: transform 0.35s var(--ease); }
.link:hover .arw { transform: translate(3px, -3px); }

/* ── Hero ────────────────────────────────────────────────────────────────── */

.hero {
    position: relative;
    /* The whole hero is a click target for the field pulse. Without this a
       double-click selects the headline and the highlight sits on top of the
       animation. */
    user-select: none;
    -webkit-user-select: none;

    /* Says "interactive surface" the moment the pointer enters, which is
       exactly when it is useful. Native keyword, so the OS renders it and
       pointer accessibility settings still apply. */
    cursor: crosshair;
    display: flex;
    align-items: center;
    min-height: 100svh;
    padding-top: 6rem;
    padding-bottom: clamp(3rem, 8vh, 6rem);
    overflow: hidden;
}

/* The interactive field. Drawn by site.js; pointer events land on the hero. */
.hero-canvas {
    position: absolute;
    inset: 0;
    z-index: var(--z-base);
    width: 100%;
    height: 100%;
    pointer-events: none;
}

/* Scrim only where the type sits, so the headline keeps its contrast while
   the field stays fully visible across the rest of the hero. */
.hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: var(--z-base);
    pointer-events: none;
    background: linear-gradient(100deg,
        var(--paper) 8%,
        color-mix(in srgb, var(--paper) 72%, transparent) 38%,
        transparent 62%);
}

.hero .wrap { position: relative; z-index: var(--z-raised); }

/* Real controls override it: a crosshair over a button would be misleading. */
.hero a, .hero button { cursor: pointer; }

.hero .display { max-width: 13ch; }

.hero .display em {
    font-style: italic;
    font-weight: 600;
    color: var(--accent);
}

.hero-sub {
    margin-top: clamp(1.5rem, 3vw, 2.25rem);
    max-width: 42ch;
    font-size: clamp(1rem, 1.35vw, 1.15rem);
    line-height: 1.6;
    color: var(--ink-2);
    text-wrap: pretty;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: clamp(1.75rem, 3vw, 2.5rem);
}

/* ── Capability strip ────────────────────────────────────────────────────
   One row, one direction, slow. The edge mask is what keeps it calm: terms
   dissolve at both ends instead of being chopped off at the viewport, so the
   eye is never snagged by a hard cut. Practice terms sit a shade darker than
   the platform ones, which is the only hierarchy the row needs. */

.strip {
    display: flex;
    overflow: hidden;
    padding-block: 1.15rem;
    border-block: 1px solid var(--line);
    user-select: none;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

.strip-track {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 2.25rem;
    padding-right: 2.25rem;
    list-style: none;
    animation: strip 68s linear infinite;
}

.strip:hover .strip-track { animation-play-state: paused; }

.strip-track li {
    display: inline-flex;
    align-items: center;
    gap: 2.25rem;
    white-space: nowrap;
}

/* The brand motif as the separator. Every item carries a trailing mark, so
   the join where the track repeats is spaced exactly like the rest. */
.strip-track li::after {
    content: '';
    width: 3px;
    height: 3px;
    flex-shrink: 0;
    background: var(--line-strong);
}

.strip-track .t {
    font-family: var(--mono);
    font-size: 0.78rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ink-3);
    transition: color 0.3s var(--ease);
}

.strip-track li[data-k='practice'] .t { color: var(--ink); font-size: 0.82rem; }
.strip-track li:hover .t { color: var(--accent); }

@keyframes strip { to { transform: translateX(-100%); } }

/* ── Statement band ──────────────────────────────────────────────────────── */

.band { background: var(--paper-sunk); border-bottom: 1px solid var(--line); }

.band-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: clamp(2rem, 6vw, 5rem);
    align-items: end;
    padding-block: clamp(3rem, 6vw, 4.5rem);
}

.band-statement {
    font-size: clamp(1.25rem, 2.4vw, 1.85rem);
    font-weight: 500;
    letter-spacing: -0.028em;
    line-height: 1.32;
    max-width: 24ch;
    text-wrap: pretty;
}

.band-facts { display: grid; gap: 0.6rem; }

.band-facts div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--line);
}

.band-facts div:last-child { border-bottom: 0; padding-bottom: 0; }

.band-facts dd {
    font-family: var(--mono);
    font-size: 0.85rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    text-align: right;
}

/* ── Services ────────────────────────────────────────────────────────────── */

.svc-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.7fr) minmax(0, 1.3fr);
    gap: clamp(2rem, 6vw, 5rem);
    align-items: start;
}

.svc-aside { position: sticky; top: 7.5rem; }
.svc-aside .lede { margin-top: 1rem; }
.svc-list { list-style: none; }

.svc-item {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: clamp(1.25rem, 3vw, 2.5rem);
    padding-block: clamp(1.75rem, 3vw, 2.5rem);
    border-top: 1px solid var(--line);
}

.svc-item:last-child { border-bottom: 1px solid var(--line); }

/* The rule above each item redraws in the accent, left to right, on hover. */
.svc-item::before {
    content: '';
    position: absolute;
    top: -1px;
    left: 0;
    width: 100%;
    height: 1px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform 0.6s var(--ease);
}

.svc-item:hover::before { transform: scaleX(1); }

.svc-num {
    font-family: var(--mono);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
    color: var(--ink-3);
    padding-top: 0.4rem;
    transition: color 0.3s var(--ease);
}

.svc-item:hover .svc-num { color: var(--accent); }
.svc-item h3 { margin-bottom: 0.6rem; }
.svc-item p { color: var(--ink-2); line-height: 1.7; max-width: 56ch; text-wrap: pretty; }

/* ── Work: one feature row, a pair, then a reversed feature row ──────────── */

.work-list { display: grid; gap: clamp(1.25rem, 2.5vw, 1.75rem); }

.pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(1.25rem, 2.5vw, 1.75rem);
}

.work {
    display: flex;
    flex-direction: column;
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    /* transform and border-colour only. box-shadow is painted, not composited,
       so transitioning it repaints the card and its shadow every frame. */
    transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}

.work:hover, .work:focus-within {
    border-color: var(--line-strong);
    transform: translateY(-4px);
}

/* Feature variant: copy beside the shot. Column order comes from the DOM, so
   the reversed row just swaps its two children and widens the image side. */
/* The copy needs less room than the screenshot does, so the media side takes
   the larger share on both feature rows. */
.work-feature {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.3fr);
    align-items: stretch;
}

.work-feature.flip { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.9fr); }

/* The media area is a stage, not a crop window. These screenshots are 16:9
   full-page captures whose composition runs the full width (Speechmark and
   FridgeWorthy put their product visual on the right, Edgemetry is edge-to-edge
   UI), so any cover-crop throws away the half that carries the meaning. The
   image keeps its native ratio and is inset instead, which also makes the
   framing read as deliberate rather than clipped. */

/* Each stage is tinted from its own screenshot's dominant hue, sampled from
   the image itself: Speechmark 205 (blue), InboundKit 213 (blue, but a dark
   capture so it needs a deeper stage to sit on), Edgemetry 251 (indigo),
   FridgeWorthy 10 (warm). Set per card via --sh/--ss/--sm.

   Note these are backdrops, not UI accents. Vermillion is still the only
   colour the interface itself uses: links, status, hover, focus. */
.work-shot {
    --sh: 30;
    --ss: 45%;
    --sm: 10%;

    position: relative;
    display: grid;
    place-items: center;
    padding: clamp(1.1rem, 2.4vw, 2rem);
    background:
        radial-gradient(125% 95% at 100% 0%,
            hsl(var(--sh) var(--ss) 55% / 0.17), transparent 62%),
        color-mix(in srgb,
            hsl(var(--sh) var(--ss) 50%) calc(var(--sm) + var(--stage-boost)),
            var(--paper-sunk));
}

.work-feature .work-shot { min-height: 100%; }

.work-shot img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
    box-shadow:
        0 1px 1px color-mix(in srgb, var(--ink) 6%, transparent),
        0 12px 28px -12px color-mix(in srgb, var(--ink) 26%, transparent);
    transition: transform 0.8s var(--ease);
}

.work:hover .work-shot img,
.work:focus-within .work-shot img { transform: translateY(-5px); }

.work-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: clamp(1.5rem, 3vw, 2.5rem);
}

.work-top {
    display: grid;
    grid-template-columns: 2.25rem minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 0.75rem;
    margin-bottom: 0.9rem;
}

.work-n {
    font-family: var(--mono);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--ink-3);
    transition: color 0.35s var(--ease);
}

.work:hover .work-n { color: var(--accent); }

.work-top h3 {
    font-size: clamp(1.3rem, 2.2vw, 1.7rem);
    font-weight: 600;
    letter-spacing: -0.035em;
    line-height: 1.05;
}

/* Plain typographic status label. No pill, no dot, no colour coding. */
.work-state {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink-3);
    white-space: nowrap;
}

.work-state[data-live='true'] { color: var(--accent); }

.work-body > p {
    color: var(--ink-2);
    font-size: 0.94rem;
    line-height: 1.7;
    max-width: 54ch;
    text-wrap: pretty;
}

.work-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.25rem;
    list-style: none;
    margin-top: 1.35rem;
}

.work-tags li {
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-3);
}

/* Pinned to the bottom so links line up across cards of unequal height. */
.work-body .link { margin-top: auto; padding-top: 1.6rem; align-self: flex-start; }

.work-note {
    margin-top: clamp(2rem, 4vw, 3rem);
    color: var(--ink-3);
    font-size: 0.9rem;
    line-height: 1.7;
    max-width: 66ch;
    text-wrap: pretty;
}

/* ── About ───────────────────────────────────────────────────────────────── */

.about-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.85fr);
    gap: clamp(2rem, 6vw, 5rem);
    align-items: start;
}

.facts { display: grid; border-top: 1px solid var(--ink); }

.facts div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.9rem;
    border-bottom: 1px solid var(--line);
}

.facts dt { font-size: 0.85rem; color: var(--ink-3); }

.facts dd {
    font-family: var(--mono);
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--ink);
    text-align: right;
}

.facts dd a { color: var(--accent-ink); text-decoration: none; text-underline-offset: 3px; }
.facts dd a:hover { text-decoration: underline; }

/* ── Process: cards that stick and stack ─────────────────────────────────── */

.stack { display: grid; gap: 1.25rem; }

.stack-card {
    position: sticky;
    top: calc(7rem + var(--s, 0) * 1.15rem);
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
    padding: clamp(1.75rem, 3.5vw, 2.75rem);
    background: var(--paper-raised);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}

.stack-n {
    font-family: var(--mono);
    font-size: clamp(1.6rem, 3vw, 2.4rem);
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.05em;
    line-height: 1;
    color: var(--accent);
}

.stack-card h3 { font-size: clamp(1.15rem, 2vw, 1.5rem); font-weight: 600; letter-spacing: -0.028em; margin-bottom: 0.5rem; }
.stack-card p { color: var(--ink-2); line-height: 1.7; max-width: 58ch; text-wrap: pretty; }

.commitments {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.5rem 2.5rem;
    margin-top: clamp(3rem, 6vw, 4.5rem);
    padding-top: 1.75rem;
    border-top: 1px solid var(--line);
    list-style: none;
}

.commitments li { font-size: 0.9rem; color: var(--ink-2); text-wrap: pretty; }
.commitments strong { display: block; color: var(--ink); font-weight: 600; margin-bottom: 0.2rem; }

/* ── Contact ─────────────────────────────────────────────────────────────── */

.contact-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    gap: clamp(2.5rem, 6vw, 5rem);
    align-items: start;
}

.contact-mail {
    display: inline-block;
    margin-top: 2rem;
    font-size: clamp(1.15rem, 2.6vw, 1.9rem);
    font-weight: 600;
    letter-spacing: -0.035em;
    color: var(--ink);
    text-decoration: none;
    background-image: linear-gradient(var(--accent), var(--accent));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 100% 1.5px;
    padding-bottom: 4px;
    transition: color 0.3s var(--ease), background-size 0.45s var(--ease);
}

.contact-mail:hover { color: var(--accent); background-size: 100% 2.5px; }

.form { display: grid; gap: 1.75rem; }
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem; }
.field { display: grid; gap: 0.45rem; }

.field label { font-size: 0.82rem; font-weight: 550; color: var(--ink-2); }

.field input, .field textarea {
    width: 100%;
    padding: 0.7rem 0;
    font-family: inherit;
    font-size: 0.98rem;
    color: var(--ink);
    background: transparent;
    border: 0;
    border-bottom: 1.5px solid var(--line-strong);
    border-radius: 0;
    transition: border-color 0.3s var(--ease);
}

.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); opacity: 1; }
.field input:focus, .field textarea:focus { outline: none; border-bottom-color: var(--accent); }
.field input:focus-visible, .field textarea:focus-visible { outline: none; outline-offset: 0; }
.field textarea { resize: vertical; min-height: 96px; line-height: 1.6; }

.field[data-invalid='true'] input,
.field[data-invalid='true'] textarea { border-bottom-color: var(--accent); }

.field-error { font-size: 0.8rem; color: var(--accent-ink); }
.field:not([data-invalid='true']) .field-error { display: none; }

.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-actions { display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; }

.form-status { font-size: 0.88rem; line-height: 1.55; color: var(--ink-2); max-width: 38ch; }
.form-status:empty { display: none; }
.form-status[data-state='error'] { color: var(--accent-ink); }

/* ── Footer ──────────────────────────────────────────────────────────────── */

/* The deepest neutral in the same family as the page text, not a theme flip:
   ink is already the dominant colour of every section above. */
.footer {
    background: var(--ink);
    color: #a8a39a;
    padding-top: clamp(3.5rem, 7vw, 5rem);
    overflow: hidden;
}

@media (prefers-color-scheme: dark) {
    .footer { background: var(--paper-sunk); border-top: 1px solid var(--line); }
}

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

.footer-brand h2 {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -0.03em;
    color: #f4f2ee;
    margin-bottom: 0.9rem;
}

.footer .mark-bg { fill: #2b2926; }
.footer .mark-fg { fill: #f4f2ee; }
.footer .mark-ac { fill: #e8683c; }

.footer-brand p { font-size: 0.88rem; line-height: 1.7; max-width: 44ch; text-wrap: pretty; }

.footer-legal { display: grid; gap: 0.55rem; align-content: start; }

.footer-legal div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.8rem;
}

.footer-legal dt { color: #7c766d; }
.footer-legal dd { font-family: var(--mono); font-size: 0.76rem; color: #cfc9bf; text-align: right; }

.footer-bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-top: 1.5rem;
    border-top: 1px solid rgba(255, 255, 255, 0.09);
    font-size: 0.79rem;
    color: #7c766d;
}

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

.footer-links a {
    color: #7c766d;
    text-decoration: none;
    text-underline-offset: 3px;
    transition: color 0.25s var(--ease);
}

.footer-links a:hover { color: #f4f2ee; text-decoration: underline; }

/* Oversized wordmark, clipped at the baseline. */
.wordmark {
    margin-top: clamp(2.5rem, 6vw, 4.5rem);
    font-size: clamp(4rem, 17.2vw, 16rem);
    font-weight: 700;
    letter-spacing: -0.055em;
    line-height: 0.8;
    color: transparent;
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.16);
    user-select: none;
    white-space: nowrap;
    transform: translateY(0.14em);
    transition: -webkit-text-stroke-color 0.6s var(--ease), color 0.6s var(--ease);
}

.footer:hover .wordmark { -webkit-text-stroke-color: rgba(232, 104, 60, 0.5); }

/* ── Legal & error pages ─────────────────────────────────────────────────── */

.doc { padding-top: clamp(8rem, 15vh, 11rem); padding-bottom: clamp(4rem, 8vw, 6rem); }
.doc-inner { max-width: 72ch; }
.doc-inner .display { margin-bottom: 1rem; }
.doc-inner > .meta { display: block; margin-bottom: 3rem; }

.doc-inner h2 {
    font-size: 1.3rem;
    font-weight: 600;
    letter-spacing: -0.028em;
    margin-top: 3rem;
    margin-bottom: 0.9rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.doc-inner h3 { font-size: 1rem; font-weight: 600; margin-top: 1.75rem; margin-bottom: 0.5rem; }
.doc-inner p, .doc-inner li { color: var(--ink-2); line-height: 1.75; text-wrap: pretty; }
.doc-inner p { margin-bottom: 1rem; }
.doc-inner ul, .doc-inner ol { margin: 0 0 1rem 1.15rem; display: grid; gap: 0.45rem; }

/* Buttons carry their own colour: excluding them keeps a CTA inside prose
   from picking up the accent link colour on an ink background. */
.doc-inner a:not(.btn):not(.link) { color: var(--accent-ink); text-underline-offset: 3px; }
.doc-inner strong { color: var(--ink); font-weight: 600; }

.doc-inner table { width: 100%; border-collapse: collapse; margin-bottom: 1.5rem; font-size: 0.9rem; }

.doc-inner th, .doc-inner td {
    text-align: left;
    padding: 0.75rem 1rem 0.75rem 0;
    border-bottom: 1px solid var(--line);
    color: var(--ink-2);
    vertical-align: top;
}

.doc-inner th { color: var(--ink); font-weight: 600; }

/* ── Responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 1000px) {
    .band-inner { grid-template-columns: 1fr; align-items: start; }
    .svc-grid, .about-grid, .contact-grid { grid-template-columns: 1fr; }
    .svc-aside { position: static; }
    .work-feature, .work-feature.flip { grid-template-columns: 1fr; }
    .work-feature .work-shot { min-height: 0; }
    .commitments { grid-template-columns: 1fr; gap: 1.25rem; }
    .stack-card { grid-template-columns: 1fr; gap: 1rem; }
    .footer-top { grid-template-columns: 1fr; }
    .footer-legal div { display: grid; gap: 0.1rem; }
    .footer-legal dd { text-align: left; }
}

@media (max-width: 720px) {
    .nav-inner { height: 64px; }
    .nav-toggle { display: flex; }

    .nav-links {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 0.5rem var(--gutter) 1.25rem;
        background: var(--paper);
        border-bottom: 1px solid var(--line);
        box-shadow: var(--shadow-md);
        display: none;
    }

    .nav-links[data-open='true'] { display: flex; }
    .nav-links li { border-bottom: 1px solid var(--line); }
    .nav-links li:last-child { border-bottom: 0; }
    .nav-links a { font-size: 1rem; }
    .roll { padding-block: 0.9rem; }
    .roll span::after { display: none; }

    .hero { min-height: 92svh; padding-top: 5.5rem; }
    .hero .display { max-width: none; }
    .hero::after { background: linear-gradient(180deg,
        color-mix(in srgb, var(--paper) 82%, transparent) 55%, transparent); }
    .hero-actions .btn { flex: 1 1 auto; }

    .pair { grid-template-columns: 1fr; }
    .work-top { grid-template-columns: 1.75rem minmax(0, 1fr); row-gap: 0.35rem; }
    .work-state { grid-column: 2; }

    .stack-card { position: static; }
    .form-row { grid-template-columns: 1fr; }
    .footer-bottom { justify-content: flex-start; }
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        transition-delay: 0ms !important;
    }

    .js [data-reveal] { opacity: 1; transform: none; transition: none; }
    .js .ln-i { transform: none; }
    .strip-track { animation: none; }
    .progress { animation: none; }
}
