/* ===== TOKENS ===== */
:root {
    --bg: #ffffff;
    --text: #1a1a1a;
    --accent: #ff4800;
    --vw-center: calc((100vw - 1440px) / 2);
    --type-base: 18px;
    --type-chrome: 13px;
    --letter-spacing-base: 0.02em;
    --gap-sm: 12px;
    --gap-md: 24px;
    --gap-lg: 48px;
    --ease-fade: cubic-bezier(0.25, 0, 0, 1);
    --ease-modal: cubic-bezier(0.65, 0, 0.35, 1);
    --ease-transform: cubic-bezier(0.4, 0, 0.2, 1);
    --dur-short: 0.5s;
    --dur-base: 1s;
    /* Body copy stays on Inter Display (loaded from Google Fonts). Display
       and chrome elements use Neue Haas Grotesk Display via Adobe Typekit
       (kit byk5ift, see <head>), matching the branch.studio typography.
       If the Typekit kit doesn't authorise this domain, Inter Display
       takes over silently. */
    --font-display: 'neue-haas-grotesk-display', 'Inter Display', -apple-system, BlinkMacSystemFont, sans-serif;

    /* Flowchart hero (in-canvas interactive graph). All flowcharts on the
       site read these; tweak here to restyle every chart at once. */
    --flow-bg: #f4f4f4;
    --flow-border: rgba(26, 26, 26, 0.15);
    --flow-node-bg: #ffffff;
    --flow-node-fg: #1a1a1a;
    --flow-node-border: rgba(26, 26, 26, 0.4);
    --flow-node-radius: 4px;
    --flow-node-pad: 0 12px;
    --flow-node-w: 140px;
    --flow-node-h: 44px;
    --flow-node-font-size: 12px;
    --flow-edge: rgba(26, 26, 26, 0.55);
    --flow-edge-w: 1.5px;
}

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

/* ===== PAGE ENTRY =====
   After the loading screen finishes its exit (letters fade, then bg
   fades), body gets .entered, which triggers transitions on the canvas
   viewport and chrome from their hidden initial states to visible.
   Transitions over @keyframes here: more reliable on mobile Safari, where
   keyframe animations on opacity sometimes failed to fire. */
body.entered .canvas-viewport {
    opacity: 1;
    transform: none;
}
.nav, .bottom-bar, .project-nav {
    transition: opacity 1s cubic-bezier(0.4, 0, 0.6, 1);
}
body.entered .nav { opacity: 1; transition-delay: 0.2s; }
body.entered .bottom-bar { opacity: 1; transition-delay: 0.3s; }
body.entered .project-nav { opacity: 1; transition-delay: 0.4s; }

/* ===== LOADING SCREEN =====
   Letters appear over 0.21s (random delays), hold while media decodes,
   then exit: letters fade out (0-0.28s, staggered), then the background
   fades to transparent (0.28-0.56s). At 0.35s, body.entered fires so the
   page fade-in overlaps with the loader's last moments. */
.loading-screen {
    position: fixed;
    inset: 0;
    z-index: 99999;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-family: 'Inter Display', sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    font-size: calc(var(--type-base) * 3);
    line-height: 1;
    letter-spacing: -0.02em;
    /* Bg fade is delayed until after per-letter fade-outs finish. */
    transition: background 0.28s ease 0.28s;
}
.loading-screen.exiting {
    background: transparent;
}
@media (max-width: 768px) {
    .loading-screen { font-size: 7vw; }
    .loading-text {
        white-space: nowrap;
        flex-shrink: 0;
    }
}

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

/* ===== BODY + GLOBAL ===== */
body {
    font-family: 'Inter Display', sans-serif;
    background-color: var(--bg);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='85' height='85'><g stroke='%23ccc' stroke-width='1' opacity='0.25'><line x1='42.5' y1='38.5' x2='42.5' y2='46.5'/><line x1='38.5' y1='42.5' x2='46.5' y2='42.5'/></g></svg>");
    color: var(--text);
    overflow: hidden;
    cursor: none;
}
body.modal-open { overflow: hidden; }

.canvas-viewport {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    position: relative;
    cursor: none;
    user-select: none;
    -webkit-user-select: none;
    /* Hidden + slightly zoomed-out by default. The loader covers visually;
       body.entered transitions opacity:0 → 1 and transform:scale(0.92) →
       none for the page-entry zoom+fade. */
    opacity: 0;
    transform: scale(0.92);
    transition: opacity 1.8s cubic-bezier(0.4, 0, 0.6, 1),
                transform 1.8s cubic-bezier(0.4, 0, 0.6, 1);
}

.canvas-text-inner,
.testimonials-inner,
.testimonial,
.modal-content,
.hover-label,
.nav,
.bottom-bar {
    user-select: text;
    -webkit-user-select: text;
}

/* ===== CURSOR + LABELS ===== */
.custom-cursor {
    position: fixed;
    top: 0;
    left: 0;
    width: 12px;
    height: 12px;
    background: white;
    border-radius: 50%;
    pointer-events: none;
    z-index: 100000;
    transform: translate(-50%, -50%);
    transition: transform 0.15s ease;
    mix-blend-mode: difference;
}
body.dragging .custom-cursor { transform: translate(-50%, -50%) scale(0.6); }

.hover-label {
    position: fixed;
    pointer-events: none;
    z-index: 9998;
    mix-blend-mode: difference;
    color: white;
    font-family: 'Inter Display', sans-serif;
    white-space: nowrap;
    overflow: hidden;
    text-transform: lowercase;
}
.hover-label .label-id {
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: 0.02em;
    margin-bottom: 4px;
}
.hover-label .label-desc {
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: 0.02em;
}

/* ===== NAV ===== */
.nav {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 100;
    padding: 20px 32px;
    pointer-events: none;
    color: var(--text);
    opacity: 0;
}
.nav-links {
    display: flex;
    flex-direction: column;
    gap: 6px;
    list-style: none;
    pointer-events: auto;
}
.nav-links a {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    color: var(--text);
    text-decoration: none;
    letter-spacing: 0.02em;
    text-transform: lowercase;
}
.nav-links a.active::after { content: ' ←'; color: var(--accent); }
.nav-links a:focus-visible {
    outline: 2px solid var(--text);
    outline-offset: 4px;
}

/* ===== PROJECT NAV (bottom-right) =====
   Mirrors .nav but anchored to the bottom-right above the bottom-bar.
   z-index sits below the modal (200) so an open project covers it. */
.project-nav {
    position: fixed;
    right: 32px;
    bottom: 60px;
    z-index: 100;
    pointer-events: none;
    color: var(--text);
    opacity: 0;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
    scrollbar-width: none;
}
.project-nav::-webkit-scrollbar { display: none; }
.project-nav-links {
    display: flex;
    flex-direction: column;
    gap: 6px;
    list-style: none;
    pointer-events: auto;
    align-items: flex-end;
}
.project-nav-links a {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    color: var(--text);
    text-decoration: none;
    letter-spacing: 0.02em;
    text-transform: lowercase;
    cursor: pointer;
    transition: color 0.2s;
    /* Kill the default Chrome focus square on click. */
    outline: none;
    -webkit-tap-highlight-color: transparent;
}
.project-nav-links a:hover { color: var(--accent); }
.project-nav-links a.active { color: var(--accent); }
.project-nav-links a.active::before { content: '→ '; color: var(--accent); }
@media (max-width: 768px) {
    .project-nav { display: none; }
}

/* ===== BOTTOM BAR ===== */
.bottom-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 100;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 32px;
    font-size: var(--type-chrome);
    font-family: 'Inter Display', sans-serif;
    font-weight: 400;
    color: var(--text);
    pointer-events: none;
    letter-spacing: 0.02em;
    opacity: 0;
    text-transform: lowercase;
}
.bottom-bar span { pointer-events: auto; }
.bottom-bar a { color: var(--text); text-decoration: none; pointer-events: auto; }
.bottom-bar-mid { position: absolute; left: 50%; transform: translateX(-50%); }

/* ===== EDGE BLUR =====
   Soft rectangular frame of blur around the screen perimeter. The mask
   is an inline SVG data URI (avoids file:// fetch issues): an opaque
   rectangle with a feathered rounded-rect hole punched out via
   gaussian blur. preserveAspectRatio='none' stretches the SVG to fill
   the viewport. Black in the mask = no blur, white = full blur. */
.edge-blur {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 50;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'><defs><filter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'><feGaussianBlur stdDeviation='3'/></filter></defs><mask id='h'><rect width='100' height='100' fill='white'/><rect x='4' y='4' width='92' height='92' fill='black' filter='url(%23b)'/></mask><rect width='100' height='100' fill='black' mask='url(%23h)'/></svg>");
    mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'><defs><filter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'><feGaussianBlur stdDeviation='3'/></filter></defs><mask id='h'><rect width='100' height='100' fill='white'/><rect x='4' y='4' width='92' height='92' fill='black' filter='url(%23b)'/></mask><rect width='100' height='100' fill='black' mask='url(%23h)'/></svg>");
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    /* Hidden during the entry transition so backdrop-filter compositing
       doesn't compete with the canvas-viewport's transform/opacity tween.
       Fades back in once body.entered fires. */
    visibility: hidden;
    opacity: 0;
}
/* Mobile: only top and bottom blur bands. The inner rect of the mask
   extends well beyond the horizontal edges (x=-20 to x=120) so there's
   no side feather, and the rect is shorter vertically (y=9 to y=91)
   so the top and bottom feathers reach further inward. Stronger blur
   strength (18px vs 12px desktop) makes the bands more pronounced. */
@media (max-width: 768px) {
    .edge-blur {
        backdrop-filter: blur(18px);
        -webkit-backdrop-filter: blur(18px);
        -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'><defs><filter id='b' x='-100%25' y='-100%25' width='300%25' height='300%25'><feGaussianBlur stdDeviation='6'/></filter></defs><mask id='h'><rect width='100' height='100' fill='white'/><rect x='-20' y='9' width='140' height='82' fill='black' filter='url(%23b)'/></mask><rect width='100' height='100' fill='black' mask='url(%23h)'/></svg>");
        mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'><defs><filter id='b' x='-100%25' y='-100%25' width='300%25' height='300%25'><feGaussianBlur stdDeviation='6'/></filter></defs><mask id='h'><rect width='100' height='100' fill='white'/><rect x='-20' y='9' width='140' height='82' fill='black' filter='url(%23b)'/></mask><rect width='100' height='100' fill='black' mask='url(%23h)'/></svg>");
    }
}
body.entered .edge-blur {
    visibility: visible;
    opacity: 1;
    transition: opacity 1s ease, visibility 0s;
}

/* ===== CANVAS ===== */
.canvas { position: absolute; top: 0; left: 0; }

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* ===== CANVAS ITEMS ===== */

/* ===== LETTER POP =====
   Each letter holds invisible until its random delay elapses, then
   appears instantly. Used by the loading screen and the hover label
   tooltip. */
.pop-letter { display: inline-block; opacity: 0; }
.loading-screen .pop-letter,
.hover-label .pop-letter {
    animation: popLetterIn 0s linear forwards;
    animation-delay: var(--pop-delay, 0s);
}
@keyframes popLetterIn {
    to { opacity: 1; }
}
/* Reverse of the appear: each letter fades out at its own random delay. */
.loading-screen.exiting .pop-letter {
    animation: popLetterOut 0.07s ease forwards;
    animation-delay: var(--pop-out-delay, 0s);
}
@keyframes popLetterOut {
    to { opacity: 0; }
}
.canvas-item {
    position: absolute;
    transition: transform 0.56s var(--ease-transform), opacity 0.6s ease-in-out, filter 0.6s ease-in-out;
    pointer-events: none;
}
.testimonials-row { transition: opacity 0.6s ease-in-out; }
@media (min-width: 769px) {
    .canvas-item[data-label-id] { margin-left: var(--vw-center); }
}
.canvas-image img:not(.lqip), .canvas-image video { pointer-events: auto; }
.canvas-image {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    /* Containing block for the absolutely-positioned .lqip child. */
    position: relative;
}
.canvas-image img:not(.lqip), .canvas-image video {
    display: block;
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    opacity: 0;
    transition: opacity var(--dur-short) ease;
    /* Sit above the absolute-positioned LQIP so the cross-fade works. */
    position: relative;
    z-index: 1;
}
.canvas-image img:not(.lqip).loaded, .canvas-image video.loaded { opacity: 1; }
/* LQIP placeholder: blurred, aspect-preserved, baked-in. Fills the wrapper
   and uses the same object-fit as the hero so its image content lands in
   exactly the same letterbox rectangle. The wrapper's letterbox region
   stays transparent (showing the body pattern), matching the look the site
   had before placeholders were introduced. */
.canvas-image img.lqip {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    pointer-events: none;
    z-index: 0;
}

/* Image items default to dim + grayscale; clear up to full color on hover.
   Only image items (data-label-id) participate. Text sections and
   testimonials never change. */
.canvas-item[data-label-id] {
    opacity: 0.5;
    filter: grayscale(100%);
}
.canvas-item[data-label-id].is-hovered,
.canvas-item[data-label-id].is-centered {
    opacity: 1;
    filter: none;
}

/* ===== CANVAS TEXT ===== */
.canvas-text {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 40px 20px;
    pointer-events: none;
}
.canvas-text-inner {
    max-width: min(480px, 90vw);
    pointer-events: auto;
}
.canvas-text h2,
.canvas-text p,
.canvas-text .label,
.canvas-text .intro-subtitle {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-base);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: 0;
    margin: 0 0 var(--gap-md);
    color: var(--text);
    text-align: justify;
}
/* All section headlines + intro subtitle: big bold uppercase, matching */
.canvas-text h2,
.canvas-text .intro-subtitle,
.testimonials-row h2 {
    text-transform: uppercase;
    letter-spacing: -0.02em;
    font-size: calc(var(--type-base) * 3);
    font-weight: 700;
    line-height: 1.0;
    margin: 0 0 var(--gap-md);
}
.canvas-text a {
    color: var(--text);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}
.canvas-text strong { font-weight: 700; }
.canvas-text .intro-subtitle a { text-decoration: none; }
.canvas-text .label { text-transform: lowercase; }
.section-number {
    display: block;
    margin-left: -132px;
    margin-bottom: 8px;
    font-family: 'Inter Display', sans-serif;
    font-size: calc(var(--type-base) * 3);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    text-transform: uppercase;
    color: var(--accent);
}

/* Intro: title and body share the same column width. */
.intro-title .canvas-text-inner {
    max-width: min(480px, 90vw);
}

/* Mobile-only project tile grid inside the work section. Hidden on
   desktop; on mobile it appears below the body copy and lets you tap
   into a project (the canvas itself is not free-pan on mobile). */
.work-tiles { display: none; }
@media (max-width: 768px) {
    .work-tiles {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
        margin-top: var(--gap-lg);
    }
    .work-tile {
        display: block;
        aspect-ratio: 1 / 1;
        overflow: hidden;
        background: #f0f0f0;
        outline: none;
        -webkit-tap-highlight-color: transparent;
    }
    .work-tile img,
    .work-tile video {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
        pointer-events: none;
    }
}

/* ===== TESTIMONIALS ===== */
.testimonials-row {
    position: absolute;
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 40px 20px;
    overflow-y: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    pointer-events: none;
}
.testimonials-inner {
    width: 100%;
    max-width: 75vw;
    pointer-events: auto;
}
.testimonials-row::-webkit-scrollbar { display: none; }
.testimonials-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 40px;
    width: 100%;
}
.testimonial { flex-shrink: 0; }
.testimonial .attribution {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-base);
    font-weight: 500;
    color: var(--text);
    margin-bottom: var(--gap-sm);
    line-height: 1.3;
}
.testimonial .attribution span {
    font-weight: 400;
    display: block;
    margin-top: 2px;
}
.testimonial blockquote {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-base);
    font-weight: 400;
    font-style: normal;
    line-height: 1.2;
    color: var(--text);
    border: none;
    padding: 0;
    text-align: justify;
}

/* ===== MOBILE LABELS ===== */
.mobile-label {
    display: none;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 12px 16px;
    background: rgba(0,0,0,0.7);
    color: white;
    font-family: 'Inter Display', sans-serif;
    z-index: 10;
    opacity: 0;
    transition: opacity 0.3s;
    pointer-events: none;
}
.mobile-label.visible { opacity: 1; }
.mobile-label .label-id {
    font-size: var(--type-chrome);
    font-weight: 500;
    letter-spacing: 0.05em;
    margin-bottom: 3px;
}
.mobile-label .label-desc {
    font-size: var(--type-chrome);
    font-weight: 400;
    line-height: 1.5;
}
@media (max-width: 768px) { .mobile-label { display: block; } }

/* ===== MODAL ===== */
.modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    background: var(--bg);
    transform: translateY(100%);
    transition: transform 1s var(--ease-modal);
    overflow-y: auto;
    overscroll-behavior: contain;
}
.modal[hidden] { display: none; }
.modal.open { transform: translateY(0); }

.modal-close, .modal-next {
    position: fixed;
    top: 20px;
    z-index: 210;
    background: transparent;
    border: none;
    outline: none;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: 0.02em;
    color: var(--text);
    cursor: pointer;
    padding: 8px 12px;
    line-height: 1;
}
.modal-close { left: 32px; }
.modal-next { right: 32px; }
/* Symbols are decorative; aria-labels on the buttons carry the meaning. */
.modal-close::after { content: ' [×]'; }
.modal-next::after { content: ' [→]'; }
.modal-close:focus, .modal-next:focus,
.modal-close:focus-visible, .modal-next:focus-visible { outline: none; }
.modal-close:hover, .modal-next:hover { opacity: 0.6; }

.modal-content {
    max-width: 1550px;
    margin: 0 auto;
    padding: 100px 20px 120px;
    transition: opacity 0.4s ease;
}
.modal-content.fading { opacity: 0; }
.modal-content .modal-hero {
    width: 100%;
    margin-bottom: var(--gap-lg);
}
.modal-content .modal-hero img,
.modal-content .modal-hero video {
    width: 100%;
    height: auto;
    display: block;
}
.modal-content h2.modal-title {
    font-family: 'Inter Display', sans-serif;
    text-transform: uppercase;
    letter-spacing: -0.02em;
    font-size: calc(var(--type-base) * 3);
    font-weight: 700;
    line-height: 1.0;
    margin: 0 0 var(--gap-md);
    color: var(--text);
}
/* Tagline: one-line "what is this" lead, sits between the title and the
   small year chrome. Body-size + Inter Display so it reads as natural
   prose, not as another structural label. mb matches .modal-section so
   the gap above the first section label is the same as the gaps between
   later sections. */
.modal-content .modal-tagline {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-base);
    font-weight: 400;
    line-height: 1.4;
    color: var(--text);
    margin: 0 0 var(--gap-lg);
}
.modal-content .modal-meta {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.4;
    color: var(--text);
    margin: 0 0 var(--gap-lg);
}
.modal-content .modal-description p {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.45;
    color: var(--text);
    text-align: justify;
    margin: 0 0 var(--gap-md);
}
/* Case-study sections (Brief / Approach / Outcome). Labels match the rest
   of the type system: uppercase, black, weight 700 like h2s. Sections sit
   var(--gap-lg) apart, matching the tagline's mb so the spacing above
   each numbered title is consistent. */
.modal-content .modal-section {
    margin: 0 0 var(--gap-lg);
}
.modal-content .modal-section-label {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 700;
    letter-spacing: var(--letter-spacing-base);
    text-transform: uppercase;
    color: var(--text);
    margin-bottom: 6px;
}
.modal-content .modal-section-body p {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.45;
    color: var(--text);
    text-align: justify;
    margin: 0 0 var(--gap-md);
}
.modal-content .modal-section-body p:last-child { margin-bottom: 0; }
/* Sub-section heading inside a section body (used by Nodes for category
   headers like "Generators (AI)"). Smaller and lighter than the main
   section label, but uses the same uppercase chrome treatment. */
.modal-content .modal-section-body h3 {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 700;
    letter-spacing: var(--letter-spacing-base);
    text-transform: uppercase;
    color: var(--text);
    margin: 24px 0 8px;
}
.modal-content .modal-section-body h3:first-child { margin-top: 0; }
.modal-content .modal-section-body ul {
    list-style: none;
    padding: 0;
    margin: 0 0 10px;
}
.modal-content .modal-section-body li {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.5;
    color: var(--text);
    margin-bottom: 6px;
}
.modal-content .modal-section-body dl {
    margin: 0;
}
.modal-content .modal-section-body dt {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 700;
    letter-spacing: var(--letter-spacing-base);
    color: var(--text);
    margin-top: 12px;
}
.modal-content .modal-section-body dt:first-child { margin-top: 0; }
.modal-content .modal-section-body dd {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.5;
    color: var(--text);
    margin: 4px 0 0 0;
}
/* Footer: client / role / stack as a definition list. dt | dd in a 2-col
   grid keeps labels vertically aligned and values wrapping below them. */
.modal-content .modal-footer {
    margin-top: var(--gap-lg);
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: 16px;
    row-gap: 6px;
}
.modal-content .modal-footer dt {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 700;
    letter-spacing: var(--letter-spacing-base);
    text-transform: uppercase;
    color: var(--text);
}
.modal-content .modal-footer dd {
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: var(--letter-spacing-base);
    line-height: 1.4;
    color: var(--text);
}
.modal-content .modal-media {
    margin-top: 64px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.modal-content .modal-media-block img,
.modal-content .modal-media-block video {
    width: 100%;
    height: auto;
    display: block;
}
.modal-content .modal-media-block .caption {
    font-size: var(--type-base);
    font-weight: 400;
    line-height: 1.5;
    color: var(--text);
    margin-top: 12px;
}
@media (min-width: 769px) {
    .modal-content {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(288px, 384px);
        grid-template-areas:
            "hero text"
            "media text"
            "details details";
        column-gap: 64px;
        row-gap: 10px;
        align-items: start;
        padding: 100px 32px 120px;
    }
    .modal-content .modal-hero { grid-area: hero; margin-bottom: 0; }
    .modal-content .modal-text { grid-area: text; }
    .modal-content .modal-media { grid-area: media; margin-top: 0; }
    .modal-content .modal-details { grid-area: details; }
}
/* Full-width depth block under the main two-column layout. Carries Stack /
   Nodes / APIs at a comfortable reading width. */
.modal-content .modal-details {
    margin-top: 80px;
    padding-top: var(--gap-lg);
    max-width: 720px;
}
.modal-content .modal-details .modal-section { margin-bottom: var(--gap-lg); }
.modal-content .modal-details .modal-section:last-child { margin-bottom: 0; }

/* ===== FIRST HINT ===== */
.first-hint {
    position: fixed;
    bottom: 60px;
    right: 32px;
    z-index: 99;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    font-weight: 400;
    letter-spacing: 0.02em;
    color: white;
    mix-blend-mode: difference;
    opacity: 0;
    transition: opacity 0.6s ease;
    pointer-events: none;
}
.first-hint.visible { opacity: 0.7; }
.first-hint[hidden] { display: none; }

/* ===== EDIT MODE ===== */
.edit-banner {
    position: fixed;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 10000;
    background: #000;
    color: #fff;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    padding: 8px 20px;
    border-radius: 6px;
    display: none;
    pointer-events: none;
    letter-spacing: 0.02em;
}
.edit-banner.active { display: block; }
body.edit-mode .canvas-item[data-label-id] { pointer-events: auto !important; cursor: grab; }
body.edit-mode .canvas-item[data-label-id]:active { cursor: grabbing; }
body.edit-mode .canvas-item[data-label-id]:not(.tile-clone)::after {
    content: attr(data-label-id);
    position: absolute;
    top: 4px;
    left: 4px;
    background: rgba(0,0,0,0.75);
    color: #fff;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    padding: 2px 6px;
    border-radius: 3px;
    z-index: 1;
    pointer-events: none;
}
body.edit-mode .tile-clone { pointer-events: auto !important; cursor: grab; }
body.edit-mode .canvas-text-inner,
body.edit-mode .testimonials-grid,
body.edit-mode .testimonials-row h2 {
    cursor: grab;
    outline: 2px dashed rgba(0,0,0,0.3);
    outline-offset: 8px;
    position: relative;
}
body.edit-mode .canvas-text-inner:active,
body.edit-mode .testimonials-grid:active { cursor: grabbing; }
body.edit-mode .canvas-text-inner::before,
body.edit-mode .testimonials-row h2::before {
    content: attr(data-edit-label);
    position: absolute;
    top: -28px;
    left: 0;
    background: rgba(0,0,0,0.75);
    color: #fff;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    padding: 2px 6px;
    border-radius: 3px;
    pointer-events: none;
    white-space: nowrap;
}
.edit-toast {
    position: fixed;
    bottom: 60px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 10000;
    background: #000;
    color: #0f0;
    font-family: 'Inter Display', sans-serif;
    font-size: var(--type-chrome);
    padding: 8px 20px;
    border-radius: 6px;
    display: none;
    pointer-events: none;
}

/* ===== RESPONSIVE ===== */
@media (max-width: 1200px) {
    .testimonials-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
    /* Mobile typography: scale body content 20% smaller. Headings, body
       paragraphs, and section numbers all derive from --type-base, so this
       single var cuts cascade through. --type-chrome (used by .nav-links,
       .project-nav-links, .bottom-bar, captions, modal labels) stays at
       13px so the nav stays legible. */
    :root { --type-base: 14.4px; }

    .nav { padding: 20px 5vw; }
    .nav-links { gap: 4px; }
    .bottom-bar { padding: 16px 5vw; }
    .custom-cursor { display: none; }
    .testimonials-row {
        justify-content: flex-start;
        padding: 140px 5vw 60px;
        height: auto;
        min-height: 100vh;
        overflow-y: visible;
    }
    .modal-close { left: 5vw; }
    .modal-next { right: 5vw; }
    .modal-content { padding: 80px 5vw 80px; }
    .first-hint { right: 5vw; bottom: 80px; }
    /* (01) etc. flow above the title instead of hanging in the left margin. */
    .section-number { margin-left: 0; }
    /* Sections grow to fit their content (no inner scroll-box that would
       clip text/tiles). The touch handler scrolls the camera through tall
       sections instead. */
    .canvas-text {
        justify-content: flex-start;
        padding: 140px 5vw 60px;
        height: auto;
        min-height: 100vh;
    }
    .canvas-text-inner,
    .intro-title .canvas-text-inner,
    .testimonials-inner {
        width: 100%;
        max-width: 100%;
    }
    /* On mobile we don't free-pan the canvas; the tile grid in the work
       section is the only entry point to projects. Hide the floating
       canvas-items so the canvas only shows the section text. */
    .canvas-item[data-label-id] { display: none; }

    /* ===== MOBILE: native body scroll =====
       Flatten the absolutely-positioned canvas stack so sections flow in
       document order and the body scrolls natively (with iOS momentum).
       Desktop keeps the free-pan camera; this only kicks in below 768px. */
    html, body {
        height: auto;
        overflow: auto;
        -webkit-overflow-scrolling: touch;
    }
    body { overscroll-behavior-y: auto; }
    .canvas-viewport {
        height: auto;
        overflow: visible;
        position: static;
    }
    .canvas {
        position: static;
        transform: none !important; /* override JS-set inline transform */
    }
    .canvas-item.canvas-text,
    .testimonials-row {
        position: static !important;
        left: auto !important;
        top: auto !important;
        transform: none !important;
    }
    /* Modal stays as a fixed overlay; just enable iOS momentum and drop the
       contain that was blocking it. */
    .modal {
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: auto;
    }
}
@media (max-width: 600px) {
    .testimonials-grid { grid-template-columns: 1fr; }
}

/* ===== FLOWCHART =====
   Interactive flow-chart hero. Lives inside .canvas-image like an <img>
   would, but with its own pan/zoom isolated from the page canvas. The
   frame is the clipping viewport; the stage carries a translate+scale
   transform driven by --flow-tx / --flow-ty / --flow-zoom. Visuals are
   token-driven (see :root) so changing a single var restyles every
   flowchart on the site at once. */
.canvas-item--flowchart {
    /* Override the default greyscale-and-dim treatment. Flowcharts are
       interactive surfaces; they read better at full opacity / colour
       all the time. */
    opacity: 1 !important;
    filter: none !important;
}
.flowchart-frame {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: var(--flow-bg);
    border: 1px solid var(--flow-border);
    pointer-events: auto;
    cursor: grab;
    touch-action: none;
}
.flowchart-frame.is-panning { cursor: grabbing; }
.flowchart-stage {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    transform-origin: 0 0;
    transform: translate(var(--flow-tx, 0px), var(--flow-ty, 0px)) scale(var(--flow-zoom, 1));
}
.flowchart-edges {
    position: absolute;
    top: 0;
    left: 0;
    overflow: visible;
    pointer-events: none;
}
.flow-edge {
    fill: none;
    stroke: var(--flow-edge);
    stroke-width: var(--flow-edge-w);
}
.flow-node {
    position: absolute;
    width: var(--flow-node-w);
    height: var(--flow-node-h);
    background: var(--flow-node-bg);
    color: var(--flow-node-fg);
    border: 1px solid var(--flow-node-border);
    border-radius: var(--flow-node-radius);
    padding: var(--flow-node-pad);
    font-size: var(--flow-node-font-size);
    font-family: var(--font-display);
    line-height: 1.2;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    user-select: none;
    letter-spacing: var(--letter-spacing-base);
}
/* Type modifiers — accent variants by node category. Add new ones here
   without touching JS. */
.flow-node--input { background: #1a1a1a; color: #ffffff; border-color: #1a1a1a; }
.flow-node--ai { background: var(--accent); color: #ffffff; border-color: var(--accent); }
.flow-node--output { background: #ffffff; color: #1a1a1a; border-color: #1a1a1a; }

/* ===== TYPOGRAPHY: DISPLAY FONT =====
   Apply Neue Haas Grotesk Display (Adobe Typekit) to display + chrome
   elements, matching the branch.studio split. Body paragraphs — intro,
   work, contact, modal description, modal section bodies, testimonials,
   captions — keep Inter Display via the body rule. This rule sits at
   the end of the file so it wins source order over the per-element
   font-family declarations earlier. */
.loading-screen,
.hover-label,
.nav-links a,
.project-nav-links a,
.bottom-bar,
.section-number,
.canvas-text h2,
.canvas-text .intro-subtitle,
.testimonials-row h2,
.modal-close,
.modal-next,
.modal-content h2.modal-title,
.modal-content .modal-meta,
.modal-content .modal-section-label,
.modal-content .modal-description p,
.modal-content .modal-section-body p,
.modal-content .modal-section-body strong,
.modal-content .modal-section-body h3,
.modal-content .modal-section-body li,
.modal-content .modal-section-body dt,
.modal-content .modal-section-body dd,
.modal-content .modal-footer dt,
.modal-content .modal-footer dd,
.first-hint,
.mobile-label {
    font-family: var(--font-display);
}
/* Tagline is the one modal element that stays on Inter Display per the
   "text under it" exclusion. Listed AFTER the override block above so
   source order wins, even at matching specificity. */
.modal-content .modal-tagline {
    font-family: 'Inter Display', sans-serif;
}
