/* ==========================================================================
   Yoshi Sakaguchi — site styles
   Hand-written. No framework, no build step.
   Order: tokens → reset → type → layout → components → utilities → motion
   ========================================================================== */

/* --- Tokens --------------------------------------------------------------- */

:root {
    /* Brand green, sampled from the logo mark. Used raw for the mark itself in
       both themes — never for small text on light, where it fails contrast. */
    --brand: #6ee7b7;

    /* Palette — the site is dark-only by design. Saturated illustration reads
       as artwork on near-black, and the brand mint only reaches full strength
       here (12.5:1); on a light ground it would need a substituted green. */
    --ink: #f0ece4;
    --ink-2: #b4ada3; /* 8.0:1 */
    --ink-3: #9a9288; /* 6.3:1 — dates and mono labels stay readable */
    --paper: #100f0e;
    --paper-2: #1b1917;
    --line: #302c28;
    --accent: var(--brand);
    --accent-ink: #12100e;

    /* Type
       Display — Bricolage Grotesque: a variable grotesk with genuine quirk in
       its terminals and optical sizing. Reads as a design studio, not a bank.
       Body    — Instrument Sans: clean UI sans, slightly humanist, no drag.
       Mono    — DM Mono: lighter and more drawn than the usual dev monos.

       To try an alternate pairing, swap these three lines only — nothing else
       in the stylesheet references a font by name:
         Editorial : "Instrument Serif" display + "Instrument Sans" body
         Techno    : "Space Grotesk" display + "Inter Tight" body
         Brutal    : "Anton" display + "Archivo" body                        */
    --font-display: "Bricolage Grotesque", "Helvetica Neue", Arial, sans-serif;
    --font-body: "Instrument Sans", "Helvetica Neue", Arial, sans-serif;
    --font-mono: "DM Mono", ui-monospace, "SF Mono", Menlo, monospace;

    /* Fluid type scale — clamp(min, preferred, max) */
    --step--1: clamp(0.78rem, 0.75rem + 0.15vw, 0.86rem);
    --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
    --step-1: clamp(1.25rem, 1.15rem + 0.5vw, 1.6rem);
    --step-2: clamp(1.6rem, 1.4rem + 1vw, 2.4rem);
    --step-3: clamp(2.1rem, 1.6rem + 2.4vw, 3.8rem);
    --step-4: clamp(2.8rem, 1.6rem + 5.6vw, 7rem);
    --step-5: clamp(3.4rem, 0.9rem + 11vw, 12rem);

    /* Space */
    --gutter: clamp(1.25rem, 0.8rem + 2.2vw, 3.5rem);
    --section: clamp(4.5rem, 3rem + 7vw, 11rem);
    --measure: 62ch;

    --radius: 2px;
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* --- Reset ---------------------------------------------------------------- */

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

* {
    margin: 0;
}

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

body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.6;
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
    transition: background-color 0.4s var(--ease), color 0.4s var(--ease);
}

img,
picture,
video,
canvas,
svg {
    display: block;
    max-width: 100%;
    height: auto;
}

input,
button,
textarea,
select {
    font: inherit;
    color: inherit;
}

button {
    background: none;
    border: none;
    cursor: pointer;
}

a {
    color: inherit;
    text-decoration: none;
}

ul,
ol {
    list-style: none;
    padding: 0;
}

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

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

/* --- Type ----------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 0.95;
    letter-spacing: -0.03em;
    text-wrap: balance;
}

/* Widow control.
   `pretty` keeps a lone word from dropping to its own last line in running
   text; `balance` evens the line lengths of short, few-line blocks. Applied
   broadly on purpose — no manual &nbsp; patching anywhere in the markup. */
p,
li,
blockquote,
figcaption,
dd {
    text-wrap: pretty;
}

.label,
.lede,
.stat__label,
.section-head h2,
.work-card__title,
.exp-item__co,
.quote__name,
.quote__role,
.btn,
.arrow-link {
    text-wrap: balance;
}

.display {
    font-size: var(--step-5);
    font-weight: 800;
    line-height: 0.84;
    letter-spacing: -0.045em;
    text-transform: uppercase;
}

.h-xl {
    font-size: var(--step-4);
}
.h-lg {
    font-size: var(--step-3);
}
.h-md {
    font-size: var(--step-2);
}
.h-sm {
    font-size: var(--step-1);
}

.lede {
    font-size: var(--step-1);
    line-height: 1.4;
    font-weight: 400;
    letter-spacing: -0.015em;
    max-width: 34ch;
}

.body {
    max-width: var(--measure);
    color: var(--ink-2);
}

.body + .body {
    margin-top: 1.1em;
}

/* Mono eyebrow label — the recurring "CATEGORY · CLIENT" tag */
.label {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-3);
}

.label--accent {
    color: var(--accent);
}

/* --- Layout --------------------------------------------------------------- */

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

.section {
    padding-block: var(--section);
}

.section--tight {
    padding-block: calc(var(--section) * 0.55);
}

/* Section heading: rule + mono index + title */
.section-head {
    display: flex;
    align-items: baseline;
    gap: 1.5rem;
    padding-bottom: 1.75rem;
    margin-bottom: clamp(2.5rem, 1rem + 4vw, 5rem);
    border-bottom: 1px solid var(--line);
}

.section-head h2 {
    font-size: var(--step-2);
    text-transform: uppercase;
    letter-spacing: -0.02em;
}

.section-head .label {
    margin-left: auto;
    white-space: nowrap;
}

/* --- Header --------------------------------------------------------------- */

.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: color-mix(in srgb, var(--paper) 82%, transparent);
    backdrop-filter: saturate(1.6) blur(14px);
    -webkit-backdrop-filter: saturate(1.6) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color 0.3s var(--ease);
}

.site-header.is-stuck {
    border-bottom-color: var(--line);
}

.site-header .wrap {
    display: flex;
    align-items: center;
    gap: 1rem;
    height: clamp(64px, 8vh, 84px);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/* The mark is drawn inline as SVG — the circle IS the shape, so no clipping
   or border is needed (the old raster was a square being masked round). */
.brand__mark {
    width: 34px;
    height: 34px;
    flex: none;
    display: block;
}

.nav {
    display: flex;
    align-items: center;
    gap: clamp(1rem, 2.5vw, 2.5rem);
    margin-left: auto;
}

.nav a {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-2);
    position: relative;
    padding-block: 0.4em;
    transition: color 0.2s var(--ease);
}

.nav a::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform 0.35s var(--ease);
}

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

.nav a:hover::after,
.nav a[aria-current="page"]::after {
    transform: scaleX(1);
    transform-origin: left;
}

/* Mobile nav */
.nav-toggle {
    display: none;
}

@media (max-width: 760px) {
    /* backdrop-filter makes an element the containing block for fixed-position
       descendants — which would trap the full-screen nav panel inside the 64px
       header strip. Dropping it here is what lets `inset: 0` mean the viewport. */
    .site-header {
        background: var(--paper);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }

    .nav-toggle {
        display: grid;
        place-items: center;
        width: 38px;
        height: 38px;
        margin-left: auto;
        color: var(--ink);
        /* Sits above the panel so it can always close it */
        position: relative;
        z-index: 2;
    }

    .nav-toggle .icon-close {
        display: none;
    }

    .nav-toggle[aria-expanded="true"] .icon-open {
        display: none;
    }

    .nav-toggle[aria-expanded="true"] .icon-close {
        display: block;
    }

    .nav {
        position: fixed;
        inset: 0;
        z-index: 1;
        flex-direction: column;
        justify-content: center;
        gap: 2rem;
        /* Opaque, and clear of the header bar so the brand stays legible */
        background: var(--paper);
        padding-top: clamp(64px, 8vh, 84px);
        margin: 0;
        opacity: 0;
        pointer-events: none;
        transform: translateY(-8px);
        transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
    }

    .nav.is-open {
        opacity: 1;
        pointer-events: auto;
        transform: none;
    }

    .nav a {
        font-size: var(--step-1);
        font-family: var(--font-display);
        font-weight: 800;
    }
}

/* --- Hero ----------------------------------------------------------------- */

.hero {
    position: relative;
    overflow: hidden;
    padding-block: clamp(3rem, 2rem + 6vw, 8rem) var(--section);
}

/* Content sits above the backdrop */
.hero > .wrap {
    position: relative;
    z-index: 2;
}

/* --- Hero backdrop --------------------------------------------------------
   Three parallax layers behind the name. The motif is the bouncing-ball arc
   with onion-skinned frames — the first exercise every animator does — so it
   reads as craft rather than generic decoration. Kept low-contrast on purpose:
   it must never compete with the name.                                      */

.hero__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}

.hero__layer {
    position: absolute;
    inset: -10% 0 -20%;
    will-change: transform;
}

/* Soft green bloom */
.hero__layer--glow {
    background:
        radial-gradient(
            48% 55% at 22% 42%,
            color-mix(in srgb, var(--brand) 13%, transparent) 0%,
            transparent 68%
        ),
        radial-gradient(
            42% 48% at 82% 62%,
            color-mix(in srgb, var(--brand) 8%, transparent) 0%,
            transparent 70%
        );
}

/* Dot grid, faded out at the edges */
.hero__layer--grid {
    background-image: radial-gradient(
        circle,
        color-mix(in srgb, var(--ink) 13%, transparent) 1px,
        transparent 1px
    );
    background-size: 44px 44px;
    -webkit-mask-image: radial-gradient(75% 75% at 50% 45%, #000 20%, transparent 78%);
    mask-image: radial-gradient(75% 75% at 50% 45%, #000 20%, transparent 78%);
}

.hero__layer--art {
    width: 100%;
    height: 100%;
}

/* The arc the ball travels */
.hero__path {
    fill: none;
    stroke: color-mix(in srgb, var(--brand) 34%, transparent);
    stroke-width: 1.5;
    stroke-dasharray: 5 9;
}

/* Onion-skin frames — each pulses in turn, so the eye reads a ball moving
   along the arc without anything actually translating. */
.hero__frame {
    fill: var(--brand);
    opacity: 0.07;
    animation: onion 3.4s var(--ease) infinite;
}

@keyframes onion {
    0%,
    62%,
    100% {
        opacity: 0.07;
    }
    16% {
        opacity: 0.46;
    }
}

/* Squash marker at the point of impact */
.hero__impact {
    fill: none;
    stroke: color-mix(in srgb, var(--brand) 55%, transparent);
    stroke-width: 1.5;
    transform-origin: center;
    animation: impact 3.4s var(--ease) infinite;
}

@keyframes impact {
    0%,
    100% {
        opacity: 0;
        transform: scale(0.6);
    }
    6% {
        opacity: 0.75;
        transform: scale(1);
    }
    22% {
        opacity: 0;
        transform: scale(1.7);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero__frame,
    .hero__impact {
        animation: none !important;
    }

    .hero__frame {
        opacity: 0.16;
    }
}

.hero__eyebrow {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin-bottom: clamp(1.5rem, 1rem + 2vw, 3rem);
}

.hero__name {
    /* Two lines of oversized type, optically flush to the container edge */
    margin-left: -0.055em;
}

.hero__meta {
    display: flex;
    flex-wrap: wrap;
    gap: clamp(1.5rem, 4vw, 5rem);
    align-items: end;
    justify-content: space-between;
    margin-top: clamp(2rem, 1rem + 4vw, 4.5rem);
    padding-top: 1.75rem;
    border-top: 1px solid var(--line);
}

/* Small pulsing "available" dot */
.dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    flex: none;
    position: relative;
}

.dot::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: inherit;
    animation: pulse 2.4s var(--ease) infinite;
}

@keyframes pulse {
    0% {
        transform: scale(1);
        opacity: 0.7;
    }
    70%,
    100% {
        transform: scale(3);
        opacity: 0;
    }
}

/* --- Work cards ----------------------------------------------------------- */

.work-list {
    display: grid;
    gap: clamp(3rem, 1.5rem + 5vw, 7rem);
}

.work-card {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(1.25rem, 1rem + 2vw, 3rem);
    align-items: center;
}

@media (min-width: 900px) {
    .work-card {
        grid-template-columns: 1.35fr 1fr;
    }

    /* Alternate image side down the list */
    .work-card:nth-child(even) .work-card__media {
        order: 2;
    }
}

.work-card__media {
    position: relative;
    overflow: hidden;
    background: var(--paper-2);
    aspect-ratio: 16 / 10;
    border-radius: var(--radius);
}

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

.work-card:hover .work-card__media img {
    transform: scale(1.035);
}

.work-card__index {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
    margin-bottom: 0.9rem;
    display: block;
}

.work-card__title {
    font-size: var(--step-3);
    margin-block: 0.5rem 1rem;
    transition: color 0.25s var(--ease);
}

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

.work-card__body {
    color: var(--ink-2);
    max-width: 46ch;
    margin-bottom: 1.75rem;
}

/* Arrow link */
.arrow-link {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--line);
    transition: border-color 0.3s var(--ease), gap 0.3s var(--ease),
        color 0.3s var(--ease);
}

.arrow-link:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
    gap: 1.1rem;
}

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

.arrow-link:hover svg {
    transform: translateX(2px);
}

/* --- Experience ----------------------------------------------------------- */

.exp-list {
    display: grid;
    gap: 0;
}

.exp-item {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem 3rem;
    padding-block: clamp(1.75rem, 1rem + 2vw, 2.75rem);
    border-top: 1px solid var(--line);
    transition: background-color 0.3s var(--ease);
}

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

@media (min-width: 800px) {
    .exp-item {
        grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.4fr);
        align-items: start;
    }
}

.exp-item__co {
    font-size: var(--step-2);
    letter-spacing: -0.02em;
}

.exp-item__role {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--accent);
    margin-top: 0.5rem;
}

.exp-item__years {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
    margin-top: 0.35rem;
}

.exp-item ul {
    display: grid;
    gap: 0.6rem;
    color: var(--ink-2);
    font-size: var(--step-0);
}

.exp-item li {
    padding-left: 1.4rem;
    position: relative;
}

.exp-item li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.62em;
    width: 6px;
    height: 1px;
    background: var(--ink-3);
}

/* --- Earlier roles (disclosure) ------------------------------------------- */

/* Native <details> on purpose: keyboard and screen-reader support come free,
   it works with JS disabled, and it survives hand-editing the HTML. */
.exp-more {
    border-top: 1px solid var(--line);
}

.exp-more > summary {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding-block: clamp(1.25rem, 1rem + 1vw, 1.75rem);
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    list-style: none;
    transition: color 0.25s var(--ease);
}

/* Hide the default disclosure triangle in every engine */
.exp-more > summary::-webkit-details-marker {
    display: none;
}
.exp-more > summary::marker {
    content: "";
}

.exp-more > summary:hover,
.exp-more > summary:focus-visible {
    color: var(--accent);
}

.exp-more__icon {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border: 1px solid var(--line);
    border-radius: 50%;
    flex: none;
    transition: border-color 0.25s var(--ease);
}

.exp-more > summary:hover .exp-more__icon {
    border-color: var(--accent);
}

/* The vertical stroke collapses on open, turning the + into a − */
.exp-more__icon .v {
    transform-origin: center;
    transition: transform 0.35s var(--ease);
}

.exp-more[open] .exp-more__icon .v {
    transform: scaleY(0);
}

.exp-more > summary .when {
    margin-left: auto;
    white-space: nowrap;
}

.exp-more[open] > summary .label-more {
    display: none;
}

.exp-more:not([open]) > summary .label-less {
    display: none;
}

/* --- Testimonials --------------------------------------------------------- */

.quote-grid {
    display: grid;
    gap: clamp(1rem, 0.5rem + 1.5vw, 2rem);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
}

.quote {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
    background: var(--paper-2);
    border-radius: var(--radius);
    border: 1px solid transparent;
    transition: border-color 0.3s var(--ease), transform 0.4s var(--ease);
}

.quote:hover {
    border-color: var(--line);
    transform: translateY(-3px);
}

.quote blockquote {
    font-size: var(--step-0);
    line-height: 1.55;
    color: var(--ink-2);
    flex: 1;
}

.quote blockquote::before {
    content: "\201C";
    font-family: var(--font-display);
    font-size: 3rem;
    line-height: 0;
    color: var(--accent);
    vertical-align: -0.35em;
    margin-right: 0.1em;
}

.quote figcaption {
    display: flex;
    align-items: center;
    gap: 0.85rem;
}

.quote figcaption img {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
    flex: none;
}

.quote__name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-0);
    line-height: 1.2;
}

.quote__role {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
}

/* --- Footer / CTA --------------------------------------------------------- */

.cta {
    border-top: 1px solid var(--line);
    padding-block: var(--section);
}

.cta__mail {
    display: inline-block;
    font-family: var(--font-display);
    font-weight: 800;
    /* The address is 25 unbreakable characters. This curve is solved so it
       lands ~10% under the container width at 375px (≈24px vs a 26.5px
       ceiling) instead of hitting it exactly and dropping the last letter.
       word-break stays only as a last resort below ~320px. */
    font-size: clamp(1.3rem, 0.27rem + 5.26vw, 5rem);
    letter-spacing: -0.04em;
    line-height: 1.05;
    word-break: break-word;
    background-image: linear-gradient(var(--accent), var(--accent));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 2px;
    transition: background-size 0.45s var(--ease), color 0.3s var(--ease);
}

.cta__mail:hover {
    color: var(--accent);
    background-size: 100% 2px;
}

.site-footer {
    border-top: 1px solid var(--line);
    padding-block: 2.5rem;
}

.site-footer .wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem 2rem;
    align-items: center;
    justify-content: space-between;
}

.social {
    display: flex;
    gap: 1.5rem;
}

.social a {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-2);
    transition: color 0.25s var(--ease);
}

.social a:hover {
    color: var(--accent);
}

/* --- Buttons -------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.95em 1.6em;
    background: var(--ink);
    color: var(--paper);
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-radius: var(--radius);
    transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
        transform 0.25s var(--ease);
}

.btn:hover {
    background: var(--accent);
    color: var(--accent-ink);
    transform: translateY(-2px);
}

.btn--ghost {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--line);
}

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

/* --- Page hero (inner pages) ---------------------------------------------- */

.page-hero {
    padding-block: clamp(2.5rem, 1.5rem + 4vw, 6rem) clamp(2rem, 1rem + 3vw, 4rem);
}

/* The eyebrow label is an inline span everywhere else, but here it must clear
   the back-link above it. */
.page-hero .label {
    display: block;
}

.page-hero h1 {
    font-size: var(--step-4);
    text-transform: uppercase;
    margin-block: 1rem 1.5rem;
    margin-left: -0.04em;
}

.page-hero .lede {
    max-width: 46ch;
    color: var(--ink-2);
}

/* Breadcrumb back-link */
.back-link {
    display: flex;
    width: fit-content;
    align-items: center;
    gap: 0.55rem;
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 2rem;
    transition: color 0.25s var(--ease), gap 0.25s var(--ease);
}

.back-link:hover {
    color: var(--accent);
    gap: 1rem;
}

/* --- Meta bar ------------------------------------------------------------- */

.meta-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr));
    gap: clamp(1.25rem, 2vw, 2.5rem);
    padding-block: clamp(1.5rem, 1rem + 2vw, 2.5rem);
    border-block: 1px solid var(--line);
}

.meta-bar dt {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 0.6rem;
}

.meta-bar dd {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-0);
    line-height: 1.35;
}

/* --- Full-bleed figure ---------------------------------------------------- */

.figure-full {
    margin-block: clamp(2.5rem, 1.5rem + 4vw, 5rem);
}

.figure-full img {
    width: 100%;
    border-radius: var(--radius);
}

.figure-full figcaption {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
    margin-top: 1rem;
}

/* --- Two column prose ----------------------------------------------------- */

.two-col {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(1.5rem, 1rem + 3vw, 4rem);
    padding-block: clamp(2rem, 1rem + 3vw, 4rem);
}

@media (min-width: 860px) {
    .two-col {
        grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr);
    }
}

.two-col h2 {
    font-size: var(--step-2);
    text-transform: uppercase;
}

.two-col__sub {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent);
    margin-top: 0.75rem;
}

/* --- Delivered / services ------------------------------------------------- */

.pill-group {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    gap: clamp(2rem, 1rem + 3vw, 4rem);
    padding-block: clamp(2rem, 1rem + 3vw, 4rem);
    border-top: 1px solid var(--line);
}

.pill-group h3 {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 1.5rem;
}

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

.pills li {
    padding: 0.55em 1.1em;
    border: 1px solid var(--line);
    border-radius: 100px;
    font-size: var(--step--1);
    color: var(--ink-2);
    transition: border-color 0.25s var(--ease), color 0.25s var(--ease),
        transform 0.25s var(--ease);
}

.pills li:hover {
    border-color: var(--accent);
    color: var(--accent);
    transform: translateY(-2px);
}

/* --- Galleries ------------------------------------------------------------ */

.gallery {
    display: grid;
    gap: clamp(0.5rem, 1vw, 1rem);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
}

.gallery--wide {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
}

.gallery img {
    width: 100%;
    border-radius: var(--radius);
    background: var(--paper-2);
    transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}

.gallery img:hover {
    transform: scale(1.03);
    box-shadow: 0 16px 34px -14px rgb(0 0 0 / 0.4);
    position: relative;
    z-index: 2;
}

/* Dense icon grid — the 200 Devils vectors */
.gallery--icons {
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 0.5rem;
}

.gallery--icons img {
    aspect-ratio: 1;
    object-fit: contain;
    padding: 0.75rem;
    background: var(--paper-2);
}

/* --- Video grid ----------------------------------------------------------- */

.video-grid {
    display: grid;
    gap: clamp(1rem, 2vw, 2rem);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
}

.video {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.video__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    background: var(--paper-2);
    border-radius: var(--radius);
    overflow: hidden;
}

.video__frame iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.video__title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-0);
}

.video__note {
    font-size: var(--step--1);
    color: var(--ink-3);
}

.video--feature {
    grid-column: 1 / -1;
}

/* --- Pull quote ----------------------------------------------------------- */

.pull-quote {
    padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem);
    border-top: 1px solid var(--line);
}

.pull-quote blockquote {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-2);
    line-height: 1.25;
    letter-spacing: -0.02em;
    max-width: 24ch;
    text-wrap: balance;
}

.pull-quote blockquote::before {
    content: "\201C";
    color: var(--accent);
}

.pull-quote figcaption {
    margin-top: 1.75rem;
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
}

.pull-quote figcaption strong {
    color: var(--ink);
    font-weight: 500;
}

/* --- Next project --------------------------------------------------------- */

.next-project {
    display: block;
    border-top: 1px solid var(--line);
    padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem);
}

.next-project__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: var(--step-3);
    text-transform: uppercase;
    letter-spacing: -0.03em;
    margin-top: 0.9rem;
    transition: color 0.25s var(--ease), transform 0.35s var(--ease);
}

.next-project:hover .next-project__title {
    color: var(--accent);
    transform: translateX(10px);
}

/* --- About ---------------------------------------------------------------- */

.about-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(2rem, 1rem + 4vw, 5rem);
    align-items: start;
}

@media (min-width: 900px) {
    .about-grid {
        grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    }
}

.portrait {
    border-radius: var(--radius);
    width: 100%;
    background: var(--paper-2);
}

.tool-group + .tool-group {
    margin-top: 2.5rem;
}

/* --- Résumé viewer --------------------------------------------------------
   Two presentations of the same document. Wide screens get the browser's real
   PDF viewer (selectable text, zoom, print). Narrow screens get rendered page
   images, because mobile browsers overwhelmingly refuse to display an inline
   PDF — they show a blank box or silently offer a download instead.          */

.resume {
    margin-inline: auto;
    max-width: 900px;
}

/* Real text rather than an embedded PDF or page images: it reflows on a phone,
   is searchable and selectable, works with screen readers, and carries no
   contact details the author didn't choose to publish. */

.resume__contact {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
    padding-bottom: 1.75rem;
    border-bottom: 1px solid var(--line);
}

.resume__contact a:hover {
    color: var(--accent);
}

.resume__section {
    padding-block: clamp(1.75rem, 1rem + 2vw, 2.75rem);
    border-bottom: 1px solid var(--line);
}

.resume__section > h2 {
    font-family: var(--font-mono);
    font-weight: 500;
    font-size: var(--step--1);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1.5rem;
}

.resume__role {
    display: grid;
    gap: 0.35rem;
}

.resume__role + .resume__role {
    margin-top: 1.75rem;
    padding-top: 1.75rem;
    border-top: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
}

.resume__role h3 {
    font-size: var(--step-1);
    letter-spacing: -0.02em;
}

.resume__where {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    color: var(--ink-3);
}

.resume__role p {
    color: var(--ink-2);
    max-width: 78ch;
}

.resume__list {
    display: grid;
    gap: 0.65rem;
    color: var(--ink-2);
    max-width: 82ch;
}

.resume__list li {
    padding-left: 1.4rem;
    position: relative;
}

.resume__list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.62em;
    width: 6px;
    height: 1px;
    background: var(--accent);
}

.resume__list strong {
    color: var(--ink);
    font-weight: 600;
}

/* --- Print ----------------------------------------------------------------
   Printing (or "Save as PDF") should produce a clean document: ink on paper,
   no site chrome, no decoration, nothing split awkwardly across a page break. */

@media print {
    .site-header,
    .site-footer,
    .grain,
    .resume__actions,
    .skip-link,
    .back-link {
        display: none !important;
    }

    :root {
        --ink: #000;
        --ink-2: #1a1a1a;
        --ink-3: #555;
        --paper: #fff;
        --paper-2: #fff;
        --line: #bbb;
        --accent: #0a7d5c;
    }

    body {
        background: #fff;
        color: #000;
        font-size: 10.5pt;
    }

    .wrap {
        max-width: none;
        padding-inline: 0;
    }

    .page-hero {
        padding-block: 0 0.5rem;
    }

    .page-hero h1 {
        font-size: 26pt;
    }

    .page-hero .lede {
        font-size: 10.5pt;
    }

    .resume__role,
    .resume__section {
        break-inside: avoid;
    }

    [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
    }

    a {
        text-decoration: none;
    }
}

.resume__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: clamp(1.5rem, 3vw, 2.5rem);
}

/* --- Form ----------------------------------------------------------------- */

.form {
    display: grid;
    gap: 1.5rem;
    max-width: 640px;
}

.form__row {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
}

.field {
    display: grid;
    gap: 0.6rem;
}

.field label {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-3);
}

.field input,
.field select,
.field textarea {
    width: 100%;
    padding: 0.85em 1em;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: var(--step-0);
    transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
    border-color: var(--accent);
    background: var(--paper-2);
    outline: none;
}

.field textarea {
    resize: vertical;
    min-height: 150px;
    font-family: inherit;
}

.form__note {
    font-size: var(--step--1);
    color: var(--ink-3);
}

/* --- Contact rows --------------------------------------------------------- */

.contact-list {
    display: grid;
    gap: 0;
}

.contact-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 2rem;
    align-items: baseline;
    justify-content: space-between;
    padding-block: 1.5rem;
    border-bottom: 1px solid var(--line);
    transition: padding-left 0.3s var(--ease), color 0.3s var(--ease);
}

.contact-row:first-child {
    border-top: 1px solid var(--line);
}

.contact-row:hover {
    padding-left: 0.75rem;
    color: var(--accent);
}

.contact-row__value {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--step-1);
    letter-spacing: -0.02em;
}

/* --- Grain ---------------------------------------------------------------- */

/* Fixed film-grain overlay. Purely decorative, never intercepts pointer events. */
.grain {
    position: fixed;
    inset: -50%;
    z-index: 1;
    pointer-events: none;
    opacity: 0.14;
    mix-blend-mode: screen;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
    animation: grain-shift 8s steps(6) infinite;
}

@keyframes grain-shift {
    0%, 100% { transform: translate(0, 0); }
    16% { transform: translate(-3%, -4%); }
    33% { transform: translate(2%, -2%); }
    50% { transform: translate(-2%, 3%); }
    66% { transform: translate(3%, 1%); }
    83% { transform: translate(-1%, -3%); }
}

/* --- Marquee -------------------------------------------------------------- */

.marquee {
    --marquee-duration: 38s;
    position: relative;
    display: flex;
    overflow: hidden;
    user-select: none;
    gap: 0;
    padding-block: clamp(1rem, 2vw, 2rem);
    border-block: 1px solid var(--line);
    background: var(--paper);
}

.marquee__track {
    display: flex;
    flex: none;
    align-items: center;
    gap: clamp(1.5rem, 3vw, 3.5rem);
    padding-right: clamp(1.5rem, 3vw, 3.5rem);
    min-width: max-content;
    animation: marquee-scroll var(--marquee-duration) linear infinite;
}

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

.marquee--reverse .marquee__track {
    animation-direction: reverse;
}

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

/* Word marquee — oversized outlined type */
.marquee__word {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(2.2rem, 1rem + 5vw, 6rem);
    line-height: 1;
    letter-spacing: -0.03em;
    text-transform: uppercase;
    white-space: nowrap;
}

.marquee__word--outline {
    color: transparent;
    -webkit-text-stroke: 1.5px var(--ink-3);
}

.marquee__star {
    color: var(--accent);
    font-size: 0.5em;
    flex: none;
}

/* Image marquee — the strip of actual artwork.
   Three rows at different durations: the speed difference reads as depth, and
   three rows show all 47 cards instead of the ten a single row could. */
.marquee-stack {
    display: grid;
    gap: clamp(0.4rem, 0.8vw, 0.75rem);
}

.marquee--media {
    padding-block: 0;
    border-block: none;
}

.marquee--media .marquee__track {
    gap: clamp(0.4rem, 0.8vw, 0.75rem);
    padding-right: clamp(0.4rem, 0.8vw, 0.75rem);
    align-items: stretch;
}

/* Each card is a button so it's keyboard reachable, not just clickable */
.marquee__item {
    display: block;
    padding: 0;
    border: 0;
    background: none;
    flex: none;
    cursor: zoom-in;
    border-radius: var(--radius);
    transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease);
}

.marquee__item img {
    height: clamp(88px, 10.5vw, 150px);
    width: auto;
    max-width: none;
    object-fit: cover;
    border-radius: var(--radius);
    display: block;
}

/* Full colour by default — the artwork is the loudest thing on the page and
   shouldn't be muted. Hover just lifts it. */
.marquee__item:hover,
.marquee__item:focus-visible {
    transform: scale(1.06) rotate(-1deg);
    box-shadow: 0 18px 40px -12px rgb(0 0 0 / 0.55);
    z-index: 2;
    position: relative;
}

/* --- Lightbox ------------------------------------------------------------- */

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: grid;
    grid-template-rows: 1fr auto;
    place-items: center;
    padding: clamp(1rem, 3vw, 3rem);
    background: color-mix(in srgb, var(--paper) 94%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    animation: lb-in 0.25s var(--ease);
}

.lightbox[hidden] {
    display: none;
}

@keyframes lb-in {
    from {
        opacity: 0;
    }
}

.lightbox__stage {
    display: grid;
    place-items: center;
    gap: 1.25rem;
    min-height: 0;
}

.lightbox__stage img {
    max-width: min(1200px, 92vw);
    max-height: 76vh;
    width: auto;
    height: auto;
    border-radius: var(--radius);
    box-shadow: 0 30px 80px -20px rgb(0 0 0 / 0.7);
}

.lightbox__meta {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    text-align: center;
}

.lightbox__btn {
    position: absolute;
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: var(--paper-2);
    color: var(--ink-2);
    transition: color 0.2s var(--ease), border-color 0.2s var(--ease),
        transform 0.2s var(--ease);
}

.lightbox__btn:hover {
    color: var(--accent);
    border-color: var(--accent);
}

.lightbox__close {
    top: clamp(1rem, 3vw, 2rem);
    right: clamp(1rem, 3vw, 2rem);
}

.lightbox__prev {
    left: clamp(0.5rem, 2vw, 2rem);
    top: 50%;
    margin-top: -23px;
}

.lightbox__next {
    right: clamp(0.5rem, 2vw, 2rem);
    top: 50%;
    margin-top: -23px;
}

.lightbox__prev:hover {
    transform: translateX(-3px);
}

.lightbox__next:hover {
    transform: translateX(3px);
}

/* Freeze the strips while the lightbox is open */
body.is-locked {
    overflow: hidden;
}

body.is-locked .marquee__track {
    animation-play-state: paused;
}

/* --- Stats ---------------------------------------------------------------- */

.stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
    gap: 1px;
    background: var(--line);
    border-block: 1px solid var(--line);
}

.stat {
    background: var(--paper);
    padding: clamp(1.75rem, 1rem + 3vw, 3.5rem) clamp(1rem, 2vw, 2rem);
    transition: background-color 0.35s var(--ease);
}

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

.stat__num {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(2.4rem, 1rem + 4.5vw, 4.75rem);
    line-height: 0.9;
    letter-spacing: -0.045em;
    color: var(--accent);
    display: block;
    font-variant-numeric: tabular-nums;
}

.stat__label {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-top: 0.9rem;
    display: block;
}

/* --- Color band ----------------------------------------------------------- */

/* Full-bleed section used to break the page rhythm. On a dark-only palette a
   true inversion would flip to cream, so this is an *elevated* dark surface
   instead — the shift in ground is what separates the section, not a flip. */
.band {
    background: var(--paper-2);
    border-block: 1px solid var(--line);
}

/* Cards need to stay distinct from the raised ground they now sit on */
.band .quote {
    background: color-mix(in srgb, var(--ink) 6%, transparent);
}

.band .quote:hover {
    border-color: color-mix(in srgb, var(--ink) 18%, transparent);
}

/* --- Cursor badge --------------------------------------------------------- */

/* "VIEW" disc that tracks the pointer across a work card's image. */
.cursor-badge {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 3;
    display: grid;
    place-items: center;
    width: 108px;
    height: 108px;
    margin: -54px 0 0 -54px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-ink);
    font-family: var(--font-mono);
    font-size: var(--step--1);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    pointer-events: none;
    opacity: 0;
    transform: scale(0.4);
    transition: opacity 0.28s var(--ease), transform 0.28s var(--ease);
}

.work-card__media:hover .cursor-badge {
    opacity: 1;
    transform: scale(1);
}

@media (hover: none) {
    .cursor-badge {
        display: none;
    }
}

/* Oversized ghost index numeral behind each work card's text */
.work-card__text {
    position: relative;
}

.work-card__ghost {
    position: absolute;
    top: -0.35em;
    right: 0;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(5rem, 2rem + 9vw, 11rem);
    line-height: 1;
    letter-spacing: -0.05em;
    color: transparent;
    /* --line is for borders only. Text greys are always --ink-3 so every muted
       label, date and numeral on the site sits at the same value. */
    -webkit-text-stroke: 1.5px var(--ink-3);
    opacity: 0.55;
    pointer-events: none;
    z-index: -1;
}

/* --- Utilities ------------------------------------------------------------ */

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

.skip-link {
    position: absolute;
    top: -100%;
    left: var(--gutter);
    z-index: 200;
    padding: 0.75em 1.25em;
    background: var(--ink);
    color: var(--paper);
    font-family: var(--font-mono);
    font-size: var(--step--1);
}

.skip-link:focus {
    top: 0.5rem;
}

/* --- Motion --------------------------------------------------------------- */

/* Elements tagged [data-reveal] fade up once scrolled into view (see site.js) */
[data-reveal] {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

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

@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;
    }

    [data-reveal] {
        opacity: 1;
        transform: none;
    }

    /* The blanket rule above would freeze the marquee mid-translate and hide
       the first track — kill the animation outright and let it sit still. */
    .marquee__track {
        animation: none !important;
    }

    .marquee {
        overflow-x: auto;
    }

    .grain {
        animation: none !important;
    }
}
