/* ══════════════════════════════════════════════════════════════════════════
   Anjan Athreya — portfolio
   Design language transplanted from meuze.ai: cool near-black ground,
   one electric blue, zero corner radius, hairline rules doing the dividing,
   light-weight display type set tight, and photographs run through a
   dot-matrix screen. Ink → paper → ink → blue.
   ══════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────  TOKENS  ───────────────────────────── */
:root {
    /* ground — measured off meuze.ai, a near-black with a blue-green cast */
    --ink:      #0B1014;
    --ink-2:    #10161B;
    --ink-3:    #171E25;

    /* the one accent — crimson red for agentic aesthetic */
    --blue:     #DC2626;
    --blue-hi:  #EF4444;

    /* paper half */
    --paper:    #FFFFFF;
    --paper-2:  #F6F6F8;
    --paper-3:  #E3E5EC;

    /* live band tokens — every band re-points these three groups */
    --bg:        var(--ink);
    --surface:   var(--ink-2);
    --surface-2: var(--ink-3);
    --fg:        #FFFFFF;
    --fg-dim:    rgba(255, 255, 255, .78);
    --fg-mute:   #9DA2B3;
    --fg-faint:  #55586A;
    --rule:      rgba(255, 255, 255, .14);
    --rule-soft: rgba(255, 255, 255, .07);
    --accent:    var(--blue);

    /* type */
    --sans:  "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
    --mono:  "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
    --serif: "Lora", Georgia, "Times New Roman", serif;

    /* rhythm */
    --wrap: 1200px;
    --gut:  clamp(20px, 5vw, 60px);
    --band: clamp(88px, 12vw, 176px);

    /* motion */
    --ease: cubic-bezier(.22, .61, .36, 1);
    --slow: cubic-bezier(.16, 1, .3, 1);
}

/* the paper half. Hard cut, full bleed, square — the reference never
   rounds a corner or floats a section as an island. */
.paper {
    --bg:        var(--paper);
    --surface:   var(--paper-2);
    --surface-2: var(--paper-3);
    --fg:        #0B1014;
    --fg-dim:    #40424D;
    --fg-mute:   #6E7180;
    --fg-faint:  #9DA2B3;
    --rule:      #E3E5EC;
    --rule-soft: #EFF0F4;
    background: var(--bg);
    color: var(--fg);
    position: relative;
    z-index: 1;
}

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

html {
    -webkit-text-size-adjust: 100%;
    scrollbar-color: #262E36 var(--ink);
    scrollbar-width: thin;
}

body {
    margin: 0;
    background: var(--ink);
    color: var(--fg);
    font-family: var(--sans);
    font-size: 16px;
    font-weight: 400;
    line-height: 1.55;
    letter-spacing: -.01em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

body.is-locked { overflow: hidden; height: 100vh; }

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

h1, h2, h3, h4, p, dl, dd, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

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

::selection { background: var(--blue); color: #FFFFFF; }

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

.has-blob, .has-blob a, .has-blob button { cursor: none; }

/* ─────────────────────────────  PRIMITIVES  ───────────────────────────── */
.wrap {
    width: 100%;
    max-width: var(--wrap);
    margin-inline: auto;
    padding-inline: var(--gut);
}

/* the reference's utility voice: 13px, uppercase, +0.08em, nothing else */
.mono {
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: .08em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
}

/* eyebrow — a flat tracked label over a hairline, not a badge */
.eyebrow {
    display: block;
    margin-bottom: 26px;
    font-size: 13px;
    font-weight: 400;
    letter-spacing: .085em;
    text-transform: uppercase;
    color: var(--fg-mute);
}
.eyebrow--rule {
    padding-top: 16px;
    border-top: 1px solid var(--rule);
}
/* the single live signal on the page — one blue dot, on the availability line */
.eyebrow i {
    display: inline-block;
    width: 6px; height: 6px;
    margin-right: 10px;
    vertical-align: 1px;
    background: var(--blue);
    animation: pulse 2.8s var(--ease) infinite;
}
@keyframes pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .35; }
}

/* buttons — square, 48px, arrow on the primary. Straight off the reference. */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    height: 48px;
    padding: 0 24px;
    border: 1px solid transparent;
    font-size: 15px;
    font-weight: 400;
    letter-spacing: -.01em;
    white-space: nowrap;
    transition: background-color .35s var(--ease), border-color .35s var(--ease),
                color .35s var(--ease);
}
.btn svg {
    width: 15px; height: 15px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform .45s var(--slow);
}
.btn:hover svg { transform: translateX(4px); }

.btn--blue  { background: var(--blue); color: #FFFFFF; }
.btn--blue:hover { background: var(--blue-hi); }

.btn--ghost { border-color: var(--rule); color: var(--fg); }
.btn--ghost:hover { border-color: var(--fg); }

.btn--solid { background: var(--fg); color: var(--bg); }
.btn--solid:hover { background: var(--blue); color: #FFFFFF; }

/* chips + tags — square, hairline, mono */
.tag, .chip {
    display: inline-flex;
    align-items: center;
    height: 30px;
    padding: 0 11px;
    border: 1px solid var(--rule);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .05em;
    color: var(--fg-mute);
    transition: color .3s var(--ease), border-color .3s var(--ease);
}
.chip:hover { color: var(--fg); border-color: var(--fg); }

.tags, .chips { display: flex; flex-wrap: wrap; gap: 7px; }

/* ─────────────────────────────  DOT SCREEN  ─────────────────────────────
   The reference runs every photograph through a fine dot matrix, so the
   image reads as data rather than as a picture. A radial-gradient mask
   punches the image into dots and lets the ground show through the gaps —
   which is why the gaps are the exact colour of the band behind them. */
.screen {
    position: relative;
    overflow: hidden;
    background: var(--ink);
}
.screen img, .dotted {
    -webkit-mask-image: radial-gradient(circle at center, #000 46%, transparent 47%);
            mask-image: radial-gradient(circle at center, #000 46%, transparent 47%);
    -webkit-mask-size: var(--dot, 4px) var(--dot, 4px);
            mask-size: var(--dot, 4px) var(--dot, 4px);
}
@media (max-width: 640px) { .screen, .dotted { --dot: 3px; } }

/* the live version: a canvas grid drawn from the photograph's own tone.
   The CSS mask above stays as the no-JS/failed-decode fallback — once the
   grid is running the source image is only a sampling surface, never seen. */
.halftone {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    z-index: 1;
}
/* a photograph is worth showing if the grid never arrives, so it only hides
   once there is a grid to replace it with */
.is-halftone > img { visibility: hidden; }

/* a frame sheet is a contact sheet, not a picture. There is no state in which
   showing it is right, so it hides on sight rather than after the first paint. */
[data-halftone-sheet] > img { visibility: hidden; }

/* ═════════════════════════════  PRELOADER  ═════════════════════════════ */
.preloader {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: grid;
    place-items: center;
    background: var(--ink);
    transition: opacity .7s var(--ease), visibility .7s;
}
.preloader.is-done { opacity: 0; visibility: hidden; }

.preloader__words {
    position: relative;
    height: 1.2em;
    font-size: clamp(24px, 4.4vw, 42px);
    font-weight: 300;
    letter-spacing: -.025em;
    color: #FFFFFF;
}
.preloader__word {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    white-space: nowrap;
    opacity: 0;
    transform: translateY(.3em);
    transition: opacity .4s var(--ease), transform .4s var(--ease);
}
.preloader__word.is-on { opacity: 1; transform: none; }

.preloader__bar {
    position: absolute;
    left: var(--gut); right: var(--gut);
    bottom: 40px;
    height: 1px;
    background: rgba(255, 255, 255, .12);
    overflow: hidden;
}
.preloader__bar i {
    display: block;
    height: 100%;
    width: 100%;
    background: var(--blue);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 1.7s var(--ease);
}
.preloader.is-loading .preloader__bar i { transform: scaleX(1); }

/* ═════════════════════════════  CURSOR  ═════════════════════════════ */
.blob, .blob-dot {
    position: fixed;
    top: 0; left: 0;
    z-index: 150;
    pointer-events: none;
    mix-blend-mode: difference;
    opacity: 0;
    will-change: transform, width, height;
}
.blob {
    width: 34px; height: 34px;
    background: #FFFFFF;
    transition: opacity .3s var(--ease);
}
.blob-dot {
    width: 6px; height: 6px;
    background: #FFFFFF;
    transition: opacity .3s var(--ease);
}
.blob.is-on, .blob-dot.is-on { opacity: 1; }
.blob-dot.is-hidden { opacity: 0; }

/* Intrinsically sized, NOT stretched to the blob. The blob measures this label
   to decide how wide to be, so if the label were sized by the blob in turn
   (inset: 0) the measurement would feed itself and the chip would grow without
   bound on every frame. width: max-content breaks the loop. */
.blob__label {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: max-content;
    text-align: center;
    padding: 0 13px;
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--ink);
    opacity: 0;
    transition: opacity .2s var(--ease);
}
.blob.is-label .blob__label { opacity: 1; }

@media (hover: none), (pointer: coarse) {
    .blob, .blob-dot { display: none; }
}

/* scroll progress — a blue hairline down the right edge */
.scroll-rail {
    position: fixed;
    top: 0; right: 0;
    z-index: 90;
    width: 2px; height: 100vh;
    background: rgba(255, 255, 255, .06);
}
.scroll-rail i {
    display: block;
    width: 100%; height: 100%;
    background: var(--blue);
    transform: scaleY(0);
    transform-origin: top;
}

/* ═════════════════════════════  NAV  ═════════════════════════════ */
.nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 100;
    border-bottom: 1px solid transparent;
    transition: transform .6s var(--slow), background-color .5s var(--ease),
                border-color .5s var(--ease), backdrop-filter .5s var(--ease);
}
.nav.is-stuck {
    background: rgba(11, 16, 20, .82);
    backdrop-filter: blur(18px) saturate(140%);
    border-bottom-color: rgba(255, 255, 255, .10);
}
.nav.is-hidden { transform: translateY(-100%); }

.nav__inner {
    display: flex;
    align-items: center;
    gap: 44px;
    max-width: var(--wrap);
    margin-inline: auto;
    padding: 18px var(--gut);
    color: #FFFFFF;
}

/* wordmark left, the way the reference sets it */
.nav__mark {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 17px;
    font-weight: 400;
    letter-spacing: -.02em;
    flex: none;
}
.nav__mark svg { width: 17px; height: 17px; fill: var(--blue); }

.nav__links {
    display: flex;
    gap: 30px;
    font-size: 13px;
    letter-spacing: .08em;
    text-transform: uppercase;
}
.nav__links a {
    color: rgba(255, 255, 255, .68);
    transition: color .3s var(--ease);
}
.nav__links a:hover { color: #FFFFFF; }

.nav__actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

.nav__resume {
    font-size: 13px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .68);
    transition: color .3s var(--ease);
}
.nav__resume:hover { color: #FFFFFF; }

.nav__cta { height: 40px; padding: 0 18px; font-size: 14px; }

@media (max-width: 900px) {
    .nav__links, .nav__resume { display: none; }
}

/* ═════════════════════════════  HERO  ═════════════════════════════
   A scroll runway with a pinned stage inside it. The runway's height is the
   only thing setting how much scrolling the clip is worth — the stage itself
   never moves, so the room opens in place while the page stays still. */
.hero {
    position: relative;
    /* the runway grew with the clip: the footage (now door-swing → window →
       chair spin) spends the first 78% of it, the whiteout takes the rest */
    height: 420vh;
}

.hero__pin {
    position: sticky;
    top: 0;
    height: 100svh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.hero__media { position: absolute; inset: 0; z-index: 0; background: var(--ink); }
.hero__media img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: 50% 42%;
}

/* how far through the room you are */
.hero__rail {
    position: absolute;
    left: var(--gut); right: var(--gut);
    bottom: 0;
    z-index: 3;
    height: 1px;
    background: rgba(255, 255, 255, .12);
}
.hero__rail i {
    display: block;
    height: 100%;
    background: var(--blue);
    transform: scaleX(var(--p, 0));
    transform-origin: left;
}

/* The dive finisher. The zoom does the storytelling — the grid plunges into
   the laptop's white screen — but a halftone can never actually reach solid
   white (the blocks stop just short of touching), so this layer closes the
   final gap: nothing until the dive is well underway, blinding just as the
   pin releases and the next section slides in over it. */
.hero__flash {
    position: absolute;
    inset: 0;
    z-index: 5;
    background: #FFFFFF;
    opacity: clamp(0, calc((var(--p, 0) - .88) * 8.4), 1);
    pointer-events: none;
}

/* a phone covers more of its own viewport per swipe, so the same runway in vh
   reads as a much longer walk — shorten it rather than make people work */
@media (max-width: 760px) {
    .hero { height: 300vh; }
}
/* the screen has to fall to solid ink top and bottom or the type floats on it.
   Sits above the halftone canvas, not just above the source image — the canvas
   carries its own stacking position, so an unlayered vignette lands under it
   and the grid runs at full strength straight through the nav and the lede. */
.hero__media::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    /* Two jobs, two gradients. Vertically the veil only anchors the very top
       and the fall to the next band — the middle stays open so the room reads.
       Horizontally a left scrim holds the type column: the headline is white
       and left-aligned, and mid-clip the window fills that band with white-hot
       cells — a drop shadow alone cannot win that fight. The room's subject
       (window, desk, plant) sits right of centre, so the scrim costs little. */
    background:
        linear-gradient(to right,
            rgba(11, 16, 20, .78) 0%,
            rgba(11, 16, 20, .38) 34%,
            rgba(11, 16, 20, 0) 58%),
        linear-gradient(to bottom,
            rgba(11, 16, 20, .72) 0%,
            rgba(11, 16, 20, .12) 24%,
            rgba(11, 16, 20, .16) 62%,
            rgba(11, 16, 20, .78) 88%,
            var(--ink) 100%);
    /* the veil belongs to the room; the dive leaves the room behind. It lifts
       across the zoom so the screen brightens to clean white, not scrimmed white */
    opacity: clamp(0, calc(1 - (var(--p, 0) - .72) * 3.6), 1);
}

/* The copy holds for most of the walk — the room opening is the motion, and a
   landing's primary call to action never earns the right to be invisible. It
   releases over the chair-spin beat, so the frame is clear before the whiteout
   takes the screen. Unitless --p is safe in calc(); no-JS lands at opacity 1. */
.hero__inner {
    /* gone by the time the dive starts at .72 — the zoom takes a clear frame */
    opacity: clamp(0, calc(1 - (var(--p, 0) - .56) * 6.25), 1);
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    flex: 1;
    width: 100%;
    max-width: var(--wrap);
    margin-inline: auto;
    padding: 30vh var(--gut) clamp(40px, 6vh, 64px);
}

.hero__title {
    max-width: 15ch;
    font-size: clamp(40px, 6.6vw, 92px);
    font-weight: 300;
    line-height: 1.06;
    letter-spacing: -.025em;
    /* the room behind is now bright enough to collide with the type — a soft
       drop shadow buys the separation the old full-width veil used to */
    text-shadow: 0 2px 24px rgba(11, 16, 20, .85), 0 1px 6px rgba(11, 16, 20, .9);
}

.hero__sub, .hero__ticker span {
    text-shadow: 0 1px 12px rgba(11, 16, 20, .9);
}

/* bottom rail: lede + button left, portrait + availability ticker right */
.hero__foot {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: clamp(28px, 6vw, 80px);
    margin-top: auto;
    padding-top: clamp(60px, 12vh, 130px);
}

.hero__sub {
    max-width: 44ch;
    font-size: 15px;
    line-height: 1.62;
    color: rgba(255, 255, 255, .74);
    text-wrap: pretty;
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }

.hero__ticker { display: flex; flex-direction: column; align-items: flex-end; gap: 16px; }
.hero__pfp {
    --size: 76px;
    width: var(--size); height: var(--size);
    object-fit: cover;
    filter: grayscale(1) contrast(1.05);
    border: 1px solid rgba(255, 255, 255, .2);
}
.hero__ticker-line { width: clamp(180px, 22vw, 260px); height: 1px; background: rgba(255, 255, 255, .28); }
.hero__ticker span {
    font-size: 13px;
    letter-spacing: .02em;
    color: rgba(255, 255, 255, .74);
}

@media (max-width: 780px) {
    .hero__inner { padding-top: 26vh; }
    .hero__foot { grid-template-columns: 1fr; align-items: start; gap: 36px; }
    .hero__ticker { align-items: flex-start; }
}

/* ═════════════════════════════  AFFILIATIONS  ═════════════════════════════ */
.affil { padding-block: clamp(48px, 7vw, 84px); border-top: 1px solid var(--rule-soft); }
.affil__label {
    margin-bottom: 30px;
    font-size: 13px;
    letter-spacing: .085em;
    text-transform: uppercase;
    color: var(--fg-faint);
    text-align: center;
}

.marquee {
    position: relative;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track {
    display: flex;
    align-items: center;
    width: max-content;
    will-change: transform;
}
.affil .marquee__track span {
    padding: 0 36px;
    font-size: clamp(16px, 1.9vw, 21px);
    font-weight: 300;
    letter-spacing: -.02em;
    color: var(--fg-mute);
    white-space: nowrap;
}
.affil .marquee__track i {
    width: 3px; height: 3px;
    background: var(--fg-faint);
    flex: none;
}

/* ═════════════════════════════  SECTION SHELL  ═════════════════════════════ */
.section { padding-block: var(--band); }
.section--tight { padding-block: clamp(64px, 9vw, 124px); }

/* stacked head — eyebrow, headline, lede. The reference's dominant block. */
.section__head { margin-bottom: clamp(48px, 6vw, 80px); }
.section__title {
    max-width: 20ch;
    font-size: clamp(28px, 3.9vw, 52px);
    font-weight: 400;
    line-height: 1.1;
    letter-spacing: -.025em;
    text-wrap: balance;
}
.section__note {
    max-width: 58ch;
    margin-top: 22px;
    font-size: 15px;
    line-height: 1.65;
    color: var(--fg-mute);
    text-wrap: pretty;
}

/* a head that carries a figure alongside the copy, the way the reference sets
   its scale band — the claim on the left, the thing turning on the right */
.section__head--split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
    align-items: center;
    gap: clamp(32px, 6vw, 80px);
}

.globe__stage { position: relative; width: 100%; aspect-ratio: 1; }
.globe__stage canvas { display: block; width: 100%; height: 100%; }
.globe figcaption {
    margin-top: 18px;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: .07em;
    text-transform: uppercase;
    line-height: 1.7;
    color: var(--fg-faint);
    text-align: center;
    text-wrap: balance;
}

@media (max-width: 860px) {
    .section__head--split { grid-template-columns: 1fr; }
    .globe { width: 100%; max-width: 260px; margin-inline: auto; }
}

/* ═════════════════════════════  ROLES  ═════════════════════════════ */
.roles { border-top: 1px solid var(--rule); }

.role {
    position: relative;
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr) 100px;
    align-items: start;
    gap: clamp(18px, 4vw, 52px);
    padding: 32px 0;
    border-bottom: 1px solid var(--rule);
}
/* a blue rule wipes down the left edge on hover — the reference divides and
   marks with hairlines, never with a filled hover card */
.role::before {
    content: "";
    position: absolute;
    left: calc(var(--gut) * -.5);
    top: 0; bottom: 0;
    width: 1px;
    background: var(--blue);
    transform: scaleY(0);
    transform-origin: top;
    transition: transform .55s var(--slow);
}
.role:hover::before { transform: scaleY(1); }

.role__when { display: flex; flex-direction: column; gap: 9px; padding-top: 3px; }
.role__when .mono { color: var(--fg-mute); }
.role__when em {
    align-self: start;
    font-family: var(--mono);
    font-size: 11px;
    font-style: normal;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fg-faint);
}
.role--next .role__when em { color: var(--blue); }

.role__what h3 {
    font-size: clamp(19px, 2.1vw, 25px);
    font-weight: 400;
    line-height: 1.24;
    letter-spacing: -.022em;
}
.role__org { margin-top: 6px; font-size: 15px; color: var(--fg-mute); }
.role__desc {
    margin-top: 14px;
    max-width: 64ch;
    font-size: 15px;
    line-height: 1.65;
    color: var(--fg-mute);
    text-wrap: pretty;
}

.role__logo {
    width: auto;
    height: 30px;
    max-width: 100%;
    justify-self: end;
    object-fit: contain;
    object-position: right center;
    filter: grayscale(1) brightness(1.2);
    opacity: .45;
    transition: opacity .45s var(--ease), filter .45s var(--ease);
}
.role:hover .role__logo { opacity: 1; filter: none; }

@media (max-width: 760px) {
    .role { grid-template-columns: 1fr auto; gap: 14px; }
    .role__when { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: 14px; }
}

/* the Now rows ride the stack's hairline grid; this is just their text voice */
.now__what {
    padding-top: 4px;
    max-width: 64ch;
    font-size: 15px;
    line-height: 1.65;
    color: var(--fg-dim);
    text-wrap: pretty;
}

/* ═════════════════════════════  PROJECTS  ═════════════════════════════ */
.project { padding-top: 36px; border-top: 1px solid var(--rule); }
.project + .project { margin-top: clamp(60px, 8vw, 104px); }

.project__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 28px;
}
.project__idx { color: var(--blue); }
.project__head h3 {
    font-size: clamp(26px, 3.4vw, 42px);
    font-weight: 300;
    letter-spacing: -.028em;
    line-height: 1;
}
.project__lang { color: var(--fg-faint); }
.project__link {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--fg-mute);
    transition: color .3s var(--ease);
}
.project__link svg {
    width: 13px; height: 13px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform .4s var(--slow);
}
.project__link:hover { color: var(--blue); }
.project__link:hover svg { transform: translate(2px, -2px); }

/* The frame takes its shape from the asset, not the other way round. A fixed
   16/9 box cropped the ultrawide terminal capture to less than half its width
   — --ar carries each asset's native ratio so cover has nothing left to cut. */
.project__media {
    overflow: hidden;
    border: 1px solid var(--rule);
    background: var(--surface);
    aspect-ratio: var(--ar, 16 / 9);
}
.project__media img,
.project__media iframe {
    width: 100%; height: 100%;
    border: 0;
    object-fit: cover;
}

/* the Circular demo is a vertical short — give it an actual device frame
   instead of letterboxing it inside a 16:9 box. The frame is a real
   screenshot of the iOS Simulator's own chrome (Xcode 26, iPhone 17),
   cropped to the device silhouette and cut to two rounded-rect alpha
   holes — the screen and the outer corners. The gif sits underneath,
   inset to the exact pixel bounds of that screen hole. */
.project__media--phone {
    aspect-ratio: 620 / 1294;
    max-width: 300px;
    margin-inline: auto;
    position: relative;
    background: none;
    border: 0;
    overflow: visible;
    filter: drop-shadow(0 32px 60px rgba(0, 0, 0, .35));
}
.project__media--phone .phone__screen {
    position: absolute;
    top: 3.42%;
    left: 4.67%;
    width: 90.78%;
    height: 94.64%;
    object-fit: cover;
    z-index: 1;
}
.project__media--phone .phone__frame {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    z-index: 2;
    pointer-events: none;
    border: 0;
}
.project__media--phone.project__media--link { display: block; }

.project__text {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 220px);
    align-items: start;
    gap: clamp(20px, 4vw, 60px);
    margin-top: 28px;
}
.project__text ul { display: grid; gap: 14px; }
.project__text li {
    position: relative;
    padding-left: 22px;
    font-size: 15px;
    line-height: 1.65;
    color: var(--fg-mute);
    text-wrap: pretty;
}
.project__text li::before {
    content: "";
    position: absolute;
    left: 0; top: .72em;
    width: 8px; height: 1px;
    background: var(--blue);
}
.project__text .tags { align-content: start; }

@media (max-width: 780px) {
    .project__text { grid-template-columns: 1fr; }
    .project__link { margin-left: 0; }
}

/* ═════════════════════════════  STACK  ═════════════════════════════ */
.stack { border-top: 1px solid var(--rule); }
.stack__row {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: clamp(16px, 4vw, 52px);
    padding: 24px 0;
    border-bottom: 1px solid var(--rule);
}
.stack__row h3 { color: var(--fg-faint); padding-top: 7px; }

@media (max-width: 640px) {
    .stack__row { grid-template-columns: 1fr; gap: 14px; }
}

/* ═════════════════════════════  EDUCATION  ═════════════════════════════ */
.edu {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--rule);
    isolation: isolate;
    background: var(--ink);
}
.edu__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    overflow: hidden;
}
.edu__bg {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: 50% 30%;
    filter: brightness(.5) saturate(.35) contrast(1.1);
}
.edu::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(105deg, rgba(11, 16, 20, .93) 16%, rgba(11, 16, 20, .5) 82%);
}
.edu__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: clamp(30px, 5vw, 72px);
    padding: clamp(32px, 5vw, 64px);
    color: #FFFFFF;
}
.edu__lede h2 {
    font-size: clamp(28px, 3.6vw, 44px);
    font-weight: 300;
    line-height: 1.08;
    letter-spacing: -.028em;
}
.edu__deg {
    margin-top: 14px;
    max-width: 32ch;
    font-size: 15px;
    line-height: 1.6;
    color: rgba(255, 255, 255, .7);
}
.edu__facts { display: grid; margin-top: 30px; }
.edu__facts > div {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 13px 0;
    border-top: 1px solid rgba(255, 255, 255, .13);
    font-size: 14px;
}
.edu__facts dt { color: rgba(255, 255, 255, .55); }
.edu__facts dd { color: #FFFFFF; text-align: right; }

/* the 1px gap is the hairline — the container's own background is what shows
   through it, so the grid has to hug its cards. Left stretched by the parent,
   the leftover track paints as a filled slab under the last card. */
.edu__grid {
    display: grid;
    gap: 1px;
    align-self: start;
    background: rgba(255, 255, 255, .13);
}
.edu__card {
    padding: 24px;
    background: rgba(11, 16, 20, .72);
    backdrop-filter: blur(10px);
}
.edu__card h3 { font-size: 15px; font-weight: 400; letter-spacing: -.015em; }
.edu__card p {
    margin-top: 10px;
    font-size: 14px;
    line-height: 1.65;
    color: rgba(255, 255, 255, .64);
    text-wrap: pretty;
}

@media (max-width: 820px) { .edu__inner { grid-template-columns: 1fr; } }

/* ═════════════════════════════  GALLERY  ═════════════════════════════ */
.gallery {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.gallery__track { display: flex; gap: 16px; width: max-content; will-change: transform; }

.shot { width: clamp(240px, 27vw, 340px); flex: none; }
.shot img {
    width: 100%;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    border: 1px solid var(--rule);
    filter: grayscale(1) brightness(.85) contrast(1.05);
    transition: filter .6s var(--ease);
}
.shot:hover img { filter: none; }
.shot figcaption {
    margin-top: 14px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--fg-mute);
    text-wrap: pretty;
}

/* ═════════════════════════════  CTA BAND  ═════════════════════════════
   The accent used once, at full strength, as ground. */
.cta {
    --fg:       #FFFFFF;
    --fg-dim:   rgba(255, 255, 255, .88);
    --fg-mute:  rgba(255, 255, 255, .78);
    --rule:     rgba(255, 255, 255, .3);
    background: var(--blue);
    color: #FFFFFF;
    padding-block: clamp(80px, 11vw, 150px);
}
.cta__inner {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    align-items: end;
    gap: clamp(30px, 5vw, 76px);
}
.cta .eyebrow { color: rgba(255, 255, 255, .72); }
.cta .eyebrow i { background: #FFFFFF; }
.cta .section__title { max-width: 16ch; font-weight: 300; }
.cta__side p {
    font-size: 15px;
    line-height: 1.65;
    color: rgba(255, 255, 255, .82);
    text-wrap: pretty;
}
.cta__links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.cta .btn--solid { background: #FFFFFF; color: var(--blue); }
.cta .btn--solid:hover { background: var(--ink); color: #FFFFFF; }
.cta .btn--ghost { border-color: rgba(255, 255, 255, .4); color: #FFFFFF; }
.cta .btn--ghost:hover { border-color: #FFFFFF; background: rgba(255, 255, 255, .1); }

@media (max-width: 780px) { .cta__inner { grid-template-columns: 1fr; align-items: start; } }

/* ═════════════════════════════  FOOTER  ═════════════════════════════ */
.footer { position: relative; overflow: hidden; background: var(--ink); }

.footer__top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
    gap: clamp(30px, 5vw, 72px);
    padding-block: clamp(48px, 6vw, 80px);
}
.footer__id { display: flex; align-items: center; gap: 16px; }
.footer__pfp {
    width: 52px; height: 52px;
    object-fit: cover;
    filter: grayscale(1);
    border: 1px solid var(--rule);
}
.footer__name { font-size: 17px; font-weight: 400; letter-spacing: -.02em; }
.footer__role { font-size: 14px; color: var(--fg-mute); }

.footer__cols {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 28px;
}
.footer__cols dt {
    margin-bottom: 14px;
    font-size: 12px;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--fg-faint);
}
.footer__cols dd { margin: 0 0 8px; font-size: 14px; color: var(--fg-mute); }
.footer__cols dd a { transition: color .3s var(--ease); }
.footer__cols dd a:hover { color: #FFFFFF; }

/* the wordmark is ground texture, not a headline — it never fully arrives */
.footer__ghost {
    margin: 0 auto;
    padding-inline: var(--gut);
    max-width: var(--wrap);
    font-size: clamp(72px, 21vw, 280px);
    font-weight: 300;
    line-height: .82;
    letter-spacing: -.05em;
    text-align: center;
    color: transparent;
    -webkit-background-clip: text;
            background-clip: text;
    background-image: linear-gradient(to bottom, rgba(255, 255, 255, .09), transparent 78%);
    user-select: none;
}

.footer__base {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 12px;
    padding-block: 26px 34px;
    border-top: 1px solid var(--rule-soft);
    font-size: 13px;
    color: var(--fg-faint);
}

@media (max-width: 780px) { .footer__top { grid-template-columns: 1fr; } }

/* ═════════════════════════════  MOTION PRIMITIVES  ═════════════════════════════ */
.wd { display: inline-block; white-space: nowrap; }
.ch {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    padding-bottom: .14em;
    margin-bottom: -.14em;
}
.ch > i {
    display: inline-block;
    font-style: inherit;
    transform: translateY(105%);
    transition: transform .95s var(--slow);
    transition-delay: var(--d, 0ms);
}
[data-split].is-in .ch > i { transform: none; }

.js [data-rise] {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity .85s var(--ease), transform .85s var(--slow);
    transition-delay: var(--d, 0ms);
}
.js [data-rise].is-in { opacity: 1; transform: none; }

/* ═════════════════════════════  REDUCED MOTION  ═════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    .js [data-rise] { opacity: 1; transform: none; }
    .ch > i { transform: none; }
    .blob, .blob-dot { display: none; }
    .has-blob, .has-blob a, .has-blob button { cursor: auto; }

    /* no runway to walk: collapse the hero to one screen and hold a single
       frame from inside the room, rather than making someone scroll three
       screens for motion they have asked not to see */
    .hero { height: 100svh; }
    .hero__inner { opacity: 1; }
    .hero__rail, .hero__flash { display: none; }
}

/* ═════════════════════════════  THINKING ORBS  ═════════════════════════════
   Canvas orbs from thinking-orbs.js. The script sizes each canvas; these rules
   only place them. */
.orb { display: inline-block; flex: none; }

.preloader__orb {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, calc(-100% - clamp(40px, 5vw, 56px)));
}

.stack__row h3 { display: flex; align-items: center; gap: 12px; align-self: start; }
.stack__row h3 .orb { margin-top: -1px; }

.project__orb { align-self: center; }

.eyebrow .orb { margin-right: 12px; vertical-align: -5px; }
.cta .orb { mix-blend-mode: screen; }

/* ═════════════════════════════  AGENT SWARM  ═════════════════════════════
   Multi-cursor touring system inspired by saai.pro — colorful cursors fly
   around the page inspecting elements while a status bar tracks progress. */

/* Container for all agent cursors */
.agent-cursors {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 9998;
    overflow: hidden;
}

/* Individual cursor arrow */
.agent-cursor {
    position: absolute;
    width: 20px;
    height: 20px;
    opacity: 0;
    transform: translate(-50%, -50%);
    transition: opacity .3s var(--ease);
    will-change: transform;
    filter: drop-shadow(0 2px 4px rgba(0,0,0,.3));
}
.agent-cursor.is-active { opacity: 1; }
.agent-cursor svg {
    width: 100%;
    height: 100%;
    fill: var(--cursor-color, #DC2626);
}

/* Status bar at bottom */
.agent-bar {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(100px);
    display: flex;
    align-items: center;
    gap: 12px;
    height: 44px;
    padding: 0 8px 0 16px;
    background: rgba(16, 22, 27, .92);
    backdrop-filter: blur(12px) saturate(1.4);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 22px;
    font-size: 13px;
    color: rgba(255,255,255,.8);
    z-index: 9999;
    opacity: 0;
    transition: transform .6s var(--slow), opacity .4s var(--ease);
}
.agent-bar.is-visible {
    transform: translateX(-50%) translateY(0);
    opacity: 1;
}

.agent-bar__dots {
    display: flex;
    gap: 2px;
}
.agent-bar__dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--c);
    opacity: .9;
}

.agent-bar__count { font-weight: 500; }

.agent-bar__sep {
    width: 1px;
    height: 16px;
    background: rgba(255,255,255,.2);
}

.agent-bar__layers {
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: .02em;
}

.agent-bar__progress {
    width: 60px;
    height: 4px;
    background: rgba(255,255,255,.15);
    border-radius: 2px;
    overflow: hidden;
}
.agent-bar__progress i {
    display: block;
    height: 100%;
    width: 0%;
    background: var(--blue);
    border-radius: 2px;
    transition: width .3s var(--ease);
}

.agent-bar button {
    height: 28px;
    padding: 0 12px;
    border: 1px solid rgba(255,255,255,.15);
    border-radius: 14px;
    background: transparent;
    color: rgba(255,255,255,.7);
    font-size: 12px;
    font-family: var(--sans);
    cursor: pointer;
    transition: background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.agent-bar button:hover {
    border-color: rgba(255,255,255,.3);
    color: #fff;
}

.agent-bar__touring.is-active {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
}

.agent-bar__speed { min-width: 36px; }

.agent-bar__sound {
    width: 28px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.agent-bar__sound svg {
    width: 14px;
    height: 14px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.agent-bar__close {
    width: 28px;
    padding: 0;
    font-size: 18px;
    line-height: 1;
}

/* Intro overlay - scanning phase */
.agent-intro {
    position: fixed;
    inset: 0;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: var(--ink);
    z-index: 9996;
    transition: opacity .5s var(--ease);
}
.agent-intro.is-hidden {
    opacity: 0;
    pointer-events: none;
}

.agent-intro__logo {
    width: 80px;
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255,255,255,.08);
    border-radius: 16px;
    font-family: var(--sans);
    font-size: 28px;
    font-weight: 500;
    color: #fff;
    margin-bottom: 24px;
}

.agent-intro__status {
    font-family: var(--mono);
    font-size: 13px;
    letter-spacing: .05em;
    color: rgba(255,255,255,.6);
}

/* Build box overlays - wireframe placeholders (no animation for low latency) */
.build-box {
    position: fixed;
    border: 1px solid #3B82F6;
    background: rgba(59, 130, 246, .05);
    pointer-events: none;
    z-index: 9997;
}

/* Corner handles */
.build-box::before,
.build-box::after,
.build-box > span::before,
.build-box > span::after {
    content: '';
    position: absolute;
    width: 8px;
    height: 8px;
    border: 1px solid #3B82F6;
    background: var(--ink);
}
.build-box::before { top: -4px; left: -4px; }
.build-box::after { top: -4px; right: -4px; }
.build-box > span::before { bottom: -4px; left: -4px; }
.build-box > span::after { bottom: -4px; right: -4px; }

/* Dimension label */
.build-label {
    position: absolute;
    bottom: -22px;
    left: 50%;
    transform: translateX(-50%);
    padding: 2px 8px;
    background: #3B82F6;
    color: #fff;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: .02em;
    white-space: nowrap;
    border-radius: 3px;
}

/* Typing text box */
.build-type {
    position: absolute;
    inset: 4px;
    padding: 4px 8px;
    background: rgba(59, 130, 246, .15);
    border: 1px solid rgba(59, 130, 246, .3);
    color: #3B82F6;
    font-family: var(--sans);
    font-size: 12px;
    line-height: 1.4;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.build-type::after {
    content: '|';
    animation: typeCursor .6s steps(1) infinite;
}
@keyframes typeCursor {
    50% { opacity: 0; }
}

/* Plus markers for pending elements */
.build-marker {
    position: fixed;
    width: 12px;
    height: 12px;
    pointer-events: none;
    z-index: 9995;
}
.build-marker::before,
.build-marker::after {
    content: '';
    position: absolute;
    background: rgba(255,255,255,.3);
}
.build-marker::before {
    top: 50%;
    left: 0;
    right: 0;
    height: 1px;
    transform: translateY(-50%);
}
.build-marker::after {
    left: 50%;
    top: 0;
    bottom: 0;
    width: 1px;
    transform: translateX(-50%);
}

/* Hide on mobile / touch devices */
@media (hover: none), (pointer: coarse) {
    .agent-cursors { display: none; }
    .agent-bar__dots { display: none; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
    .agent-cursors { display: none; }
    .agent-bar { display: none; }
}
