/* ==========================================================================
   ARISTIDES LAB — design tokens
   ========================================================================== */
:root {
    --bg:            #f3f2ee;
    --bg-sunk:       #eae8e2;
    --card:          rgba(255,255,255,.66);
    --card-hover:    rgba(255,255,255,.9);
    /* Every text token resolves to the same ink. Hierarchy is carried by size
       and weight alone, so nothing on the page is set in a lighter grey. Only
       the two rule tokens stay lighter — they draw hairlines, not words. */
    --text-primary:  #000000;
    --text-secondary:#000000;
    --text-muted:    #000000;
    --text-subtle:   #000000;
    --rule:          #b9b7ad;
    --rule-strong:   #94918a;

    /* Accent is re-rolled per section by app.js. Three tokens because one
       hue can't do every job legibly on both grounds:
         --accent      vivid — graphics only (points, borders, rules)
         --accent-ink  contrast-safe — any text, and solid fills
         --accent-on   foreground that sits on --accent-ink
       Defaults here are the light-mode red; JS overwrites all three. */
    --accent:        rgb(228 62 30);
    --accent-ink:    rgb(186 34 8);
    --accent-on:     #ffffff;
    --accent-t:      440ms;
    --frame-shell:   #17171a;
    /* every frosted surface reads from this, so the panes, the app cards, the
       hire box and the animation toggle cannot drift to different blurs */
    --glass:         blur(16px) saturate(1.15);

    /* per-app hover outlines. "White" for Vision Emoji becomes ink on a light
       ground — a white outline on bone would be invisible — so the intent (a
       neutral, hueless edge) survives both themes. */
    --app-tdlidar:   rgb(0 114 218);
    --app-zpth:      rgb(140 74 200);
    --app-vision:    rgb(17 17 17);
    --app-splat:     rgb(0 141 41);

    --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
    --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Roboto Mono", monospace;

    --ease: cubic-bezier(.22,.61,.36,1);
    --dur: 540ms;
}

body.dark {
    --bg:            #0b0b0c;
    --bg-sunk:       #131315;
    --card:          rgba(255,255,255,.075);
    --card-hover:    rgba(255,255,255,.09);
    --text-primary:  #ffffff;
    --text-secondary:#ffffff;
    --text-muted:    #ffffff;
    --text-subtle:   #ffffff;
    --rule:          #55555f;
    --rule-strong:   #74747f;
    --accent:        rgb(255 122 92);
    --accent-ink:    rgb(255 138 110);
    --accent-on:     #0b0b0c;
    --frame-shell:   #0f0f11;
    --app-tdlidar:   rgb(76 188 255);
    --app-zpth:      rgb(210 150 255);
    --app-vision:    rgb(255 255 255);
    --app-splat:     rgb(76 214 118);
}

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

html, body {
    height: 100%;
    background-color: var(--bg);
    color: var(--text-primary);
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overscroll-behavior: none;
}

body { transition: background-color 400ms var(--ease), color 400ms var(--ease); }

@media (min-width: 861px) {
    html, body { height: 100dvh; overflow: hidden; }
}

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

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

/* The accent is re-rolled on every section change; ease the swap on the
   elements that carry it so the hue crossfades with the content. */
.title__eyebrow,
.flag,
.grp h3 em,
.panel__cta,
.dot,
.viewer__ticks button,
.submit,
.success__mark {
    transition: color var(--accent-t) var(--ease),
                background-color var(--accent-t) var(--ease),
                border-color var(--accent-t) var(--ease),
                width 380ms var(--ease);
}

.skip-link {
    position: fixed; top: -100px; left: 50%; transform: translateX(-50%);
    z-index: 500; background: var(--text-primary); color: var(--bg);
    padding: .7rem 1.2rem; font-size: .75rem; letter-spacing: .06em;
    text-transform: uppercase; font-family: var(--font-mono);
}
.skip-link:focus { top: 12px; }

/* ==========================================================================
   LIDAR FIELD — the page background
   ========================================================================== */
#field {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    /* the canvas paints its own opaque ground in the same colour as the page,
       so dropping opacity only recedes the flock, never the background */
    opacity: .55;
    transition: opacity 260ms var(--ease);
}
/* the sweep briefly brings the whole field forward, so the pulse is obvious
   without the resting background being any busier */
body.is-wiping #field { opacity: .95; }

/* ==========================================================================
   TOP BAR
   ========================================================================== */
.topbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 120;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 26px 34px 0 34px;
    pointer-events: none;
}
.topbar > * { pointer-events: auto; }

.theme-toggle {
    display: flex; align-items: center; gap: 8px;
    font-family: var(--font-mono);
    font-size: .62rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 6px 2px;
}
.theme-toggle__dot {
    width: 11px; height: 11px;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}
.theme-toggle:hover { color: var(--text-primary); }

/* ==========================================================================
   CUSTOM CURSOR — a hard dot with a ring that lags behind it
   ========================================================================== */
.cursor { display: none; }
@media (hover: hover) and (pointer: fine) {
    html.has-cursor, html.has-cursor * { cursor: none !important; }
    .cursor {
        display: block;
        position: fixed;
        top: 0; left: 0;
        z-index: 9999;
        pointer-events: none;
        mix-blend-mode: difference;
    }
    .cursor i { position: absolute; display: block; border-radius: 50%; }
    .cursor__ring {
        width: 20px; height: 20px;
        margin: -10px 0 0 -10px;
        border: 1.5px solid #fff;
        transition: width 220ms var(--ease), height 220ms var(--ease),
                    margin 220ms var(--ease), border-radius 220ms var(--ease),
                    opacity 220ms var(--ease), background-color 220ms var(--ease);
    }
    .cursor__dot {
        width: 2.5px; height: 2.5px;
        margin: -1.25px 0 0 -1.25px;
        background: #fff;
        transition: opacity 200ms var(--ease), transform 200ms var(--ease);
    }
    /* over something clickable */
    .cursor.is-target .cursor__ring {
        width: 31px; height: 31px; margin: -15.5px 0 0 -15.5px;
        background: rgba(255,255,255,.85);
        border-color: transparent;
    }
    .cursor.is-target .cursor__dot { opacity: 0; }
    /* over a text field */
    .cursor.is-text .cursor__ring {
        width: 1.5px; height: 16px;
        margin: -8px 0 0 -.75px;
        border-radius: 1px;
        background: #fff;
        border-color: transparent;
    }
    .cursor.is-text .cursor__dot { opacity: 0; }
    .cursor__ring::after {
        content: "";
        position: absolute;
        inset: -1.5px;
        border-radius: 50%;
        border: 1.5px solid #fff;
        opacity: 0;
    }
    .cursor.is-down .cursor__ring::after { animation: cursorPulse 520ms var(--ease); }
    /* pointer is off the page, on another tab, or has not moved yet */
    /* held: the ring stays open to show the flock is still being gathered */
    .cursor.is-holding .cursor__ring {
        width: 34px; height: 34px; margin: -17px 0 0 -17px;
        border-color: #fff;
        background: transparent;
    }
    .cursor.is-away { opacity: 0; }
    .cursor { transition: opacity 160ms var(--ease); }
}
@keyframes cursorPulse {
    0%   { transform: scale(1);   opacity: .9; }
    100% { transform: scale(2.6); opacity: 0; }
}

/* ==========================================================================
   TRAIL SLIDER — index section only
   ========================================================================== */
.trailer {
    display: flex;
    align-items: center;
    gap: 10px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 360ms var(--ease);
}
body[data-section="0"] .trailer { opacity: 1; pointer-events: auto; }
.trailer__label {
    font-family: var(--font-mono);
    font-size: .52rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.trailer input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: 92px;
    height: 14px;
    background: transparent;
    cursor: pointer;
}
.trailer input[type="range"]::-webkit-slider-runnable-track {
    height: 2px; border-radius: 2px; background: var(--rule-strong);
}
.trailer input[type="range"]::-moz-range-track {
    height: 2px; border-radius: 2px; background: var(--rule-strong);
}
.trailer input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 11px; height: 11px;
    margin-top: -4.5px;
    border-radius: 50%;
    background: var(--accent-ink);
    border: 0;
    transition: background-color var(--accent-t) var(--ease);
}
.trailer input[type="range"]::-moz-range-thumb {
    width: 11px; height: 11px;
    border-radius: 50%;
    background: var(--accent-ink);
    border: 0;
}

/* ==========================================================================
   STAGE GRID
   ========================================================================== */
.stage {
    position: relative;
    z-index: 2;
    height: 100dvh;
    display: grid;
    grid-template-columns: 20% 56% 24%;
    align-items: stretch;
    padding: 96px 40px 46px 40px;
}

.col { min-width: 0; min-height: 0; }

.col--left {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding-right: 24px;
}

/* --- cross-faded section titles --- */
.titles { position: relative; flex: 1; }

.title {
    position: absolute;
    top: 50%; left: 0; right: 0;
    transform: translateY(calc(-50% + 14px));
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.title.is-active { opacity: 1; transform: translateY(-50%); pointer-events: auto; }
.title__eyebrow {
    font-family: var(--font-mono);
    font-size: .58rem;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--accent-ink);
    margin-bottom: 14px;
}
.title__main {
    font-size: clamp(1.6rem, 2.2vw, 2.2rem);
    font-weight: 600;
    line-height: 1.04;
    letter-spacing: -.028em;
    color: var(--text-primary);
}
.title__main span { display: block; }
.title__sub {
    font-size: clamp(1.6rem, 2.2vw, 2.2rem);
    font-weight: 600;
    line-height: 1.04;
    letter-spacing: -.028em;
    color: var(--text-subtle);
}

/* --- dots + credit --- */
.col__foot { display: flex; flex-direction: column; gap: 20px; }

.dots { display: flex; align-items: center; gap: 7px; }
.dot {
    width: 7px; height: 2px;
    border-radius: 2px;
    background: var(--text-subtle);
    padding: 0;
    transition: width 380ms var(--ease), background-color 380ms var(--ease);
}
.dot:hover { background: var(--text-muted); }
.dot[aria-current="true"] { width: 24px; background: var(--accent); }

.credit {
    font-family: var(--font-mono);
    font-size: .68rem;
    letter-spacing: .06em;
    color: var(--text-subtle);
    line-height: 1.8;
}
.credit__sep { margin: 0 .5em; }

/* lets anyone who finds the moving background hard to read against switch it off */
.motion-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    padding: 6px 12px 6px 9px;
    border-radius: 99px;
    border: 1px solid var(--rule);
    background: var(--card);
    backdrop-filter: var(--glass);
    -webkit-backdrop-filter: var(--glass);
    font-family: var(--font-mono);
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-primary);
    align-self: flex-start;
    transition: border-color 200ms var(--ease), background-color 200ms var(--ease);
}
.motion-toggle:hover { border-color: var(--rule-strong); }
.motion-toggle__dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--accent-ink);
    transition: background-color var(--accent-t) var(--ease), opacity 200ms var(--ease);
}
.motion-toggle[aria-pressed="false"] .motion-toggle__dot { opacity: .28; background: currentColor; }
/* with the field off the trail control has nothing to act on */
body.no-motion .trailer { display: none; }
.credit kbd {
    font: inherit;
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 0 .32em;
    color: var(--text-muted);
}

/* ==========================================================================
   CENTER — cross-faded content frames
   ========================================================================== */
.col--main { display: flex; align-items: center; justify-content: center; }

.frames { position: relative; width: 100%; height: 100%; }

.frame {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, calc(-50% + 18px));
    width: 100%;
    max-height: 100%;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
    opacity: 0;
    pointer-events: none;
    /* Opacity is deliberately much faster than the slide. An ancestor with
       opacity between 0 and 1 isolates its subtree, and backdrop-filter on a
       descendant does not render while that is true — so the glass panes came
       in unblurred and only frosted once the fade finished. Reaching opacity 1
       quickly means the blur is there essentially from the start, while the
       transform keeps the sense of movement. */
    transition: opacity 150ms var(--ease), transform var(--dur) var(--ease);
}
.frame::-webkit-scrollbar { display: none; }
.frame.is-active { opacity: 1; transform: translate(-50%, -50%); pointer-events: auto; }

/* ==========================================================================
   FRAME 0 — index
   ========================================================================== */
.frame--index { max-width: 620px; }

.statement {
    font-size: clamp(2.6rem, 5.2vw, 4.6rem);
    font-weight: 600;
    line-height: .96;
    letter-spacing: -.045em;
    color: var(--text-primary);
}
.statement em { font-style: normal; color: var(--accent-ink); }

/* emoji tracks the headline's height instead of its 32px attributes, and .nb
   keeps it welded to the final word so it can never wrap to its own line */
.nb { white-space: nowrap; }
.alien img {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-left: .1em;
    vertical-align: -.17em;
}

.statement__sub {
    margin-top: 26px;
    max-width: 30rem;
    font-size: .95rem;
    line-height: 1.6;
    color: var(--text-secondary);
}

/* "New" announcement — its own frosted box on its own line, sitting below the
   subtitle rather than trailing off the end of it. inline-flex so the box hugs
   the sentence instead of stretching the column width. */
.flag {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    margin-top: 20px;
    padding: 13px 18px;
    border-radius: 16px;
    border: 1px solid var(--rule);
    background: var(--card);
    backdrop-filter: var(--glass);
    -webkit-backdrop-filter: var(--glass);
    color: var(--accent-ink);
    font-size: .9rem;
    line-height: 1.4;
    transition: border-color 240ms var(--ease), background-color 240ms var(--ease),
                color var(--accent-t) var(--ease);
}
.flag b { font-weight: 700; flex: 0 0 auto; }
.flag em { font-style: normal; display: inline-block; transition: transform 240ms var(--ease); }
.flag:hover { border-color: var(--accent-ink); background: var(--card-hover); }
.flag:hover em { transform: translate(2px,-2px); }

.toc {
    list-style: none;
    margin-top: 44px;
    border-top: 1px solid var(--rule);
    max-width: 30rem;
}
.toc button {
    display: flex;
    align-items: baseline;
    gap: 16px;
    width: 100%;
    padding: 13px 4px;
    border-bottom: 1px solid var(--rule);
    text-align: left;
    transition: padding-left 260ms var(--ease), border-color 260ms var(--ease);
}
.toc i {
    font-style: normal;
    font-family: var(--font-mono);
    font-size: .58rem;
    letter-spacing: .1em;
    color: var(--text-subtle);
    flex: 0 0 auto;
    transition: color 220ms var(--ease);
}
.toc b {
    font-size: .95rem;
    font-weight: 500;
    letter-spacing: -.015em;
    flex: 0 0 auto;
}
.toc span {
    font-size: .75rem;
    color: var(--text-muted);
    flex: 1;
}
.toc em {
    font-style: normal;
    color: var(--text-subtle);
    font-size: .85rem;
    transition: transform 260ms var(--ease), color 260ms var(--ease);
}
.toc button:hover { padding-left: 12px; border-color: var(--rule-strong); }
.toc button:hover i,
.toc button:hover em { color: var(--accent-ink); }
.toc button:hover em { transform: translateX(4px); }

/* ==========================================================================
   FRAME 1 — reel viewer
   ========================================================================== */
.frame--reels {
    max-width: 330px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

/* The phone viewport. `container-type: size` lets each slide and its iframe be
   sized from the screen's height in cqh, so the embed's media box always
   exactly fills a slide with no letterboxing and no JS measurement. */
/* iPhone 17 silhouette. Every hardware detail is sized in container units off
   the screen, so the whole device scales as one when the viewport changes. */
.phone {
    position: relative;
    padding: 9px;
    border-radius: 46px;
    background:
        linear-gradient(150deg,
            color-mix(in srgb, var(--frame-shell) 74%, #ffffff) 0%,
            var(--frame-shell) 22%,
            var(--frame-shell) 78%,
            color-mix(in srgb, var(--frame-shell) 82%, #ffffff) 100%);
    box-shadow: 0 34px 70px -30px rgba(20,18,14,.5),
                inset 0 0 0 1px rgba(255,255,255,.16),
                inset 0 0 0 3px rgba(0,0,0,.35);
}

/* side hardware — percentages of device height, matching iPhone 17 placement */
.phone__btn {
    position: absolute;
    width: 3px;
    background: var(--frame-shell);
    filter: brightness(1.65);
    z-index: 1;
}
.phone__btn--action { left: -2px;  top: 14.5%; height: 3.6%; border-radius: 2px 0 0 2px; }
.phone__btn--volup  { left: -2px;  top: 21.5%; height: 6.4%; border-radius: 2px 0 0 2px; }
.phone__btn--voldn  { left: -2px;  top: 29.5%; height: 6.4%; border-radius: 2px 0 0 2px; }
.phone__btn--power  { right: -2px; top: 23.5%; height: 9.8%; border-radius: 0 2px 2px 0; }
/* iPhone 17's real screen is 402x874pt, i.e. 1:2.174 — far taller than 16:9,
   which is what made the earlier frame look squat. A 9:16 reel on a screen this
   tall has to be cropped at the sides to fill, which is exactly what Instagram
   does on the device itself. Height leads the sizing so the phone shrinks on
   short viewports rather than overflowing. */
.phone__screen {
    position: relative;
    height: min(62vh, 620px);
    aspect-ratio: 402 / 874;
    container-type: size;
    border-radius: 33px;
    overflow: hidden;
    background: #0b0b0d;
    cursor: grab;
    touch-action: none;          /* the momentum scroller owns the gesture */
    user-select: none;
    -webkit-user-select: none;
}
.phone__screen:active { cursor: grabbing; }

.feed { position: absolute; top: 0; left: 0; width: 100%; will-change: transform; }

.slide {
    position: relative;
    width: 100%;
    height: 100cqh;
    overflow: hidden;
    background: #0b0b0d;
    --ig-head: 56px;
    --ig-foot: 128px;
}
/* width is derived from height so the embed's 100:124 media box covers the
   slide exactly; the cropped chrome sits outside the overflow */
.slide iframe {
    position: absolute;
    top: calc(-1 * var(--ig-head));
    left: 50%;
    transform: translateX(-50%);
    width: calc(100cqh / 1.24);
    height: calc(100cqh + var(--ig-head) + var(--ig-foot));
    border: 0;
    display: block;
    pointer-events: none;        /* drags belong to the feed, not the embed */
}
.slide::after {
    content: "";
    position: absolute; top: 50%; left: 50%;
    width: 24px; height: 24px; margin: -12px 0 0 -12px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,.18);
    border-top-color: rgba(255,255,255,.85);
    animation: spin 900ms linear infinite;
    transition: opacity 300ms var(--ease);
}
.slide.is-loaded::after { opacity: 0; }
@keyframes spin { to { transform: rotate(360deg); } }

/* --- status bar, Dynamic Island, home indicator --- */
.statusbar {
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 7cqh;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1.6cqh 7cqw 0;
    font-size: 2.15cqh;
    font-weight: 600;
    letter-spacing: -.01em;
    color: #fff;
    fill: #fff;
    pointer-events: none;
    text-shadow: 0 1px 3px rgba(0,0,0,.45);
}
.statusbar__icons { display: flex; align-items: center; gap: 1.1cqw; }
.statusbar__icons svg {
    display: block;
    height: 1.55cqh;
    width: auto;
    filter: drop-shadow(0 1px 2px rgba(0,0,0,.45));
}

.island {
    position: absolute;
    top: 1.35cqh; left: 50%;
    transform: translateX(-50%);
    width: 31cqw; height: 4.6cqh;
    background: #000;
    border-radius: 99px;
    z-index: 7;
    pointer-events: none;
    box-shadow: inset 0 0 0 .5px rgba(255,255,255,.06);
}

.homebar {
    position: absolute;
    bottom: 1.05cqh; left: 50%;
    transform: translateX(-50%);
    width: 35cqw; height: .62cqh;
    min-height: 3px;
    border-radius: 99px;
    background: rgba(255,255,255,.92);
    z-index: 6;
    pointer-events: none;
    box-shadow: 0 0 6px rgba(0,0,0,.35);
}

/* iOS only shows the indicator while the finger is moving, so it fades in on
   interaction and back out once the feed settles */
.phone__rail {
    position: absolute;
    top: 9cqh; bottom: 4.5cqh; right: 4px;
    width: 2px;
    border-radius: 2px;
    background: rgba(255,255,255,.10);
    overflow: hidden;
    z-index: 3;
    opacity: 0;
    transition: opacity 420ms var(--ease);
}
.phone__screen.is-scrolling .phone__rail { opacity: 1; transition-duration: 120ms; }
.phone__rail i {
    display: block;
    width: 100%;
    border-radius: 2px;
    background: color-mix(in srgb, var(--accent) 80%, transparent);
    transition: background-color var(--accent-t) var(--ease);
}

.phone__hint {
    margin: -4px 0 0;
    text-align: center;
    font-family: var(--font-mono);
    font-size: .64rem;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.viewer__nav { display: flex; align-items: center; gap: 16px; }
.viewer__btn {
    width: 30px; height: 30px;
    border-radius: 50%;
    border: 1px solid var(--rule);
    color: var(--text-muted);
    font-size: .8rem;
    display: flex; align-items: center; justify-content: center;
    transition: color 200ms var(--ease), border-color 200ms var(--ease);
}
.viewer__btn:hover { color: var(--text-primary); border-color: var(--rule-strong); }

.viewer__count {
    font-family: var(--font-mono);
    font-size: .7rem;
    letter-spacing: .1em;
    color: var(--text-muted);
    min-width: 42px;
    text-align: center;
}
.viewer__count b { color: var(--text-primary); font-weight: 500; }
.viewer__count i { font-style: normal; margin: 0 2px; }

.viewer__out {
    font-family: var(--font-mono);
    font-size: .72rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
    transition: color 200ms var(--ease);
}
.viewer__out:hover { color: var(--accent-ink); }

/* ==========================================================================
   FRAME 2 — app cards
   ========================================================================== */
.frame--apps { max-width: 640px; }

.cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}
.card {
    display: flex;
    gap: 14px;
    padding: 18px;
    border-radius: 16px;
    border: 1px solid var(--rule);
    background: var(--card);
    backdrop-filter: var(--glass);
    -webkit-backdrop-filter: var(--glass);
    transition: background-color 260ms var(--ease), border-color 260ms var(--ease),
                box-shadow 260ms var(--ease);
}
/* No translate on hover: the frame is a scroll box, so lifting the top row by
   2px pushed it above the content box and clipped it. An outline reads just as
   clearly and cannot shift layout. */
.card:hover {
    background: var(--card-hover);
    border-color: var(--app, var(--rule-strong));
    box-shadow: inset 0 0 0 1px var(--app, transparent);
}
.card[data-app="0"] { --app: var(--app-tdlidar); }
.card[data-app="1"] { --app: var(--app-zpth); }
.card[data-app="2"] { --app: var(--app-vision); }
.card[data-app="3"] { --app: var(--app-splat); }
.card:hover .card__cta { color: var(--app, var(--accent-ink)); }
.card img {
    width: 46px; height: 46px;
    flex: 0 0 auto;
    border-radius: 11px;
    box-shadow: 0 3px 10px -3px rgba(0,0,0,.35);
}
.card__body { min-width: 0; }
.card__body b {
    display: block;
    font-size: .88rem;
    font-weight: 600;
    letter-spacing: -.015em;
    margin-bottom: 5px;
}
.card__body p {
    font-size: .72rem;
    line-height: 1.5;
    color: var(--text-secondary);
    margin-bottom: 9px;
}
.card__cta {
    font-family: var(--font-mono);
    font-size: .55rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
    transition: color 220ms var(--ease);
}

.subrow {
    display: flex;
    flex-wrap: wrap;
    gap: 22px;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--rule);
}
.subrow a {
    font-family: var(--font-mono);
    font-size: .58rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
    transition: color 200ms var(--ease);
}
.subrow a:hover { color: var(--accent-ink); }

/* ==========================================================================
   FRAME 3 — link rows
   ========================================================================== */
.frame--links { max-width: 540px; }

.rows { border-top: 1px solid var(--rule); }
.row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 15px 6px;
    border-bottom: 1px solid var(--rule);
    transition: padding-left 260ms var(--ease), border-color 260ms var(--ease);
}
.row:hover { padding-left: 14px; border-color: var(--rule-strong); }
.row__tile {
    flex: 0 0 auto;
    width: 30px; height: 30px;
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: .66rem; font-weight: 600;
    color: #fff;
    background: #8e8e93;
}
.row__tile--yt  { background: #ff0033; }
.row__tile--pa  { background: #141414; }
.row__tile--ig  { background: linear-gradient(45deg,#f9ce34,#ee2a7b,#6228d7); }
.row__tile--gh  { background: #24292f; font-size: .52rem; }
.row__tile--bmc { background: #ffdd00; color: #141414; }
.row__tile--doc { background: #0a66ff; }
.row__tile--hf { background: #ffd21e; color: #141414; font-size: .8rem; }
.row__tile--mail { background: var(--text-primary); color: var(--bg); font-size: .8rem; }
.row__tile--img { background: none; padding: 0; overflow: hidden; }
.row__tile--img img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; }
.row__name {
    font-size: .92rem;
    font-weight: 500;
    letter-spacing: -.015em;
    flex: 0 0 auto;
}
.row__sub {
    font-size: .74rem;
    color: var(--text-muted);
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.row__go {
    color: var(--text-subtle);
    font-size: .82rem;
    transition: color 240ms var(--ease), transform 240ms var(--ease);
}
.row:hover .row__go { color: var(--accent-ink); transform: translate(3px,-3px); }

/* ==========================================================================
   FRAME 4 — skills spec sheet
   ========================================================================== */
.frame--skills { max-width: 620px; }

.spec { border-top: 1px solid var(--rule); }

.grp { padding: 16px 0 18px; border-bottom: 1px solid var(--rule); }
.grp h3 {
    font-family: var(--font-mono);
    font-size: .58rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-primary);
}
.grp h3 em { font-style: normal; font-weight: 400; color: var(--accent-ink); }
/* opt out of the uppercase run so "iOS" keeps its real casing */
.grp h3 .kase { text-transform: none; letter-spacing: .1em; }
.grp p {
    margin-top: 7px;
    font-size: .76rem;
    line-height: 1.6;
    color: var(--text-secondary);
    max-width: 34rem;
}
.grp ul {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}
.grp li {
    font-size: .78rem;
    letter-spacing: -.01em;
    padding: 4px 11px;
    border-radius: 99px;
    border: 1px solid var(--rule);
    background: var(--card);
    transition: border-color 240ms var(--ease), color 240ms var(--ease);
}
.grp li:hover { border-color: var(--accent-ink); color: var(--accent-ink); }

/* ==========================================================================
   HIRE CTA — apps frame
   ========================================================================== */
.hire {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    margin-top: 14px;
    padding: 15px 18px;
    border-radius: 14px;
    border: 1px solid var(--rule);
    background: var(--card);
    backdrop-filter: var(--glass);
    -webkit-backdrop-filter: var(--glass);
    text-align: left;
    transition: background-color 260ms var(--ease), border-color 260ms var(--ease);
}
.hire:hover { background: var(--card-hover); border-color: var(--accent); }
.hire b {
    flex: 0 0 auto;
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: -.015em;
}
.hire span {
    flex: 1;
    font-size: .72rem;
    line-height: 1.5;
    color: var(--text-secondary);
}
.hire em {
    font-style: normal;
    color: var(--text-subtle);
    transition: color 240ms var(--ease), transform 240ms var(--ease);
}
.hire:hover em { color: var(--accent-ink); transform: translateX(4px); }

/* ==========================================================================
   FRAME 5 — contact form
   ========================================================================== */
.frame--contact { max-width: 620px; }

.form__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 22px; }
.f { grid-column: 1 / -1; }
.f--half { grid-column: span 1; }

.f label {
    display: block;
    font-family: var(--font-mono);
    font-size: .53rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-primary);
    margin-bottom: 5px;
}
.f input,
.f select,
.f textarea {
    width: 100%;
    font-family: var(--font-sans);
    font-size: .85rem;
    color: var(--text-primary);
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--rule);
    padding: 7px 0 9px;
    outline: none;
    border-radius: 0;
    -webkit-appearance: none;
    appearance: none;
    transition: border-color 220ms var(--ease);
}
.f select { cursor: pointer; }
.f textarea { resize: none; line-height: 1.55; }
/* Placeholders sit one step below the ink so a filled field still reads as
   filled, but at full 7:1 contrast rather than the old hairline grey. */
.f input::placeholder,
.f textarea::placeholder { color: var(--text-secondary); opacity: 1; }
.f select:invalid { color: var(--text-secondary); }
/* Optional selects are never :invalid — match on the unchosen option instead
   so every select's resting state looks the same. */
.f select:has(option[value=""]:checked) { color: var(--text-secondary); }
.f option { color: var(--text-primary); background: var(--bg); }
.f input:focus,
.f select:focus,
.f textarea:focus { border-color: var(--accent); }

/* native select arrow */
.f select {
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 9px) calc(50% + 1px), calc(100% - 5px) calc(50% + 1px);
    background-size: 4px 4px, 4px 4px;
    background-repeat: no-repeat;
    padding-right: 20px;
}

.form__foot {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-top: 26px;
}
.submit {
    padding: 11px 26px;
    border-radius: 99px;
    background: var(--accent-ink);
    color: var(--accent-on);
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: -.01em;
    transition: filter 180ms var(--ease), transform 180ms var(--ease);
}
.submit:hover { filter: brightness(1.08); }
.submit:active { transform: scale(.985); }
.form__note { font-size: .7rem; color: var(--text-primary); }

.success { text-align: center; padding: 40px 20px; }
.success__mark {
    width: 50px; height: 50px;
    margin: 0 auto 18px;
    border-radius: 50%;
    background: var(--accent-ink);
    color: var(--accent-on);
    font-size: 1.4rem;
    display: flex; align-items: center; justify-content: center;
}
.success__title { font-size: 1.2rem; font-weight: 600; margin-bottom: 8px; letter-spacing: -.02em; }
.success__body { font-size: .85rem; color: var(--text-primary); }


/* ==========================================================================
   GLASS PANELS

   Links, Skills and Contact each sit on one rounded pane that blurs the flock
   behind it, the same treatment the app cards already use. The blur is what
   buys the legibility — a flat fill at this opacity would still let the moving
   dots read through as texture under the text.
   ========================================================================== */
.frame--links .rows,
.frame--skills .spec,
.frame--contact .form,
.frame--contact .success {
    padding: 24px 26px;
    border-radius: 22px;
    border: 1px solid var(--rule);
    background: var(--card);
    backdrop-filter: var(--glass);
    -webkit-backdrop-filter: var(--glass);
}
/* the pane's own edge replaces the leading hairline */
.frame--links .rows,
.frame--skills .spec { border-top: 1px solid var(--rule); }
.frame--links .row:last-child,
.frame--skills .grp:last-child { border-bottom: 0; padding-bottom: 0; }
.frame--links .row:first-child { padding-top: 0; }
.frame--skills .grp:first-child { padding-top: 0; }

/* ==========================================================================
   RIGHT PANEL
   ========================================================================== */
.col--panel { display: flex; align-items: center; position: relative; }
.panels { position: relative; width: 100%; height: 100%; }

.panel {
    position: absolute;
    top: 50%; left: 0; right: 0;
    transform: translateY(calc(-50% + 16px));
    padding-left: 38px;
    max-height: 100%;
    overflow-y: auto;
    scrollbar-width: none;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.panel::-webkit-scrollbar { display: none; }
.panel.is-active { opacity: 1; transform: translateY(-50%); pointer-events: auto; }

.panel__lede {
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -.015em;
    margin-bottom: 12px;
}
.panel__body {
    font-size: .88rem;
    line-height: 1.6;
    color: var(--text-secondary);
    margin-bottom: 12px;
    max-width: 270px;
}
.panel__cta {
    display: inline-block;
    font-size: .74rem;
    font-weight: 500;
    color: var(--accent-ink);
    border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    padding-bottom: 2px;
    transition: border-color 200ms var(--ease);
}
.panel__cta:hover { border-color: var(--accent); }

.meta {
    margin-top: 22px;
    border-top: 1px solid var(--rule);
    max-width: 270px;
}
.meta dt {
    font-family: var(--font-mono);
    font-size: .62rem;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding-top: 11px;
}
.meta dd {
    font-size: .84rem;
    color: var(--text-secondary);
    padding-bottom: 11px;
    border-bottom: 1px solid var(--rule);
}
.meta dd:last-child { border-bottom: 0; }
.meta dd a {
    border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    transition: color 200ms var(--ease), border-color 200ms var(--ease);
}
.meta dd a:hover { color: var(--accent-ink); border-color: var(--accent-ink); }

/* ==========================================================================
   MOBILE PAGER
   ========================================================================== */
.pager { display: none; }

/* ==========================================================================
   RESPONSIVE — tablet
   ========================================================================== */
@media (max-width: 1240px) and (min-width: 861px) {
    .stage { grid-template-columns: 22% 54% 24%; padding: 90px 26px 40px 26px; }
    .panel { padding-left: 24px; }
    .cards { gap: 10px; }
    .card { padding: 14px; gap: 11px; }
}

@media (max-width: 1000px) and (min-width: 861px) {
    .stage { grid-template-columns: 24% 76%; padding: 90px 30px 40px 30px; }
    .col--panel { display: none; }
}

/* ==========================================================================
   RESPONSIVE — mobile
   ========================================================================== */
@media (max-width: 860px) {
    html, body { height: 100dvh; overflow: hidden; }

    .topbar { padding: 14px 16px 0; }
    .trailer { display: none; }

    .stage {
        grid-template-columns: 1fr;
        grid-template-rows: auto minmax(0, 1fr);
        padding: 46px 20px calc(52px + env(safe-area-inset-bottom));
        gap: 14px;
    }

    .col--left { padding-right: 0; display: contents; }
    .col__head { display: none; }

    .titles { grid-row: 1; position: relative; height: 52px; flex: none; }
    .title { top: 0; transform: translateY(10px); }
    .title.is-active { transform: none; }
    .title__eyebrow { margin-bottom: 4px; font-size: .5rem; }
    .title__main { font-size: 1.3rem; display: inline; }
    .title__main span { display: inline; }
    .title__sub  { font-size: 1.3rem; display: inline; margin-left: .4em; }

    .col--main { grid-row: 2; min-height: 0; align-items: flex-start; }
    .frames { height: 100%; }
    .frame {
        top: 0; left: 0;
        transform: translateY(14px);
        max-width: none;
        height: 100%;
        padding-bottom: 20px;
    }
    .frame.is-active { transform: none; }

    .statement { font-size: clamp(2rem, 11vw, 3rem); }
    .nb { white-space: normal; }          /* let the emoji wrap on narrow screens */
    .statement__sub { margin-top: 18px; font-size: .85rem; }
    .toc { margin-top: 26px; }
    .toc button { gap: 12px; padding: 11px 2px; flex-wrap: wrap; }
    .toc em { order: 2; margin-left: auto; }
    .toc span { flex-basis: 100%; order: 3; font-size: .68rem; margin-top: 3px; }

    .frame--reels { max-width: 300px; margin: 0 auto; }
    .phone__hint { display: none; }

    .cards { grid-template-columns: 1fr; }
    .card { padding: 14px; }
    .hire { flex-wrap: wrap; gap: 6px 12px; }
    .hire b { flex-basis: 100%; }
    .grp p { font-size: .72rem; }

    .form__grid { grid-template-columns: 1fr; gap: 4px; }
    .f--half { grid-column: 1 / -1; }
    .form__foot { flex-direction: column; align-items: stretch; gap: 12px; text-align: center; }
    .submit { width: 100%; }

    .col--panel { display: none; }

    .col__foot {
        position: fixed;
        left: 20px;
        bottom: calc(16px + env(safe-area-inset-bottom));
        z-index: 60;
    }
    .credit { display: none; }

    .pager {
        display: flex;
        position: fixed;
        right: 14px;
        bottom: calc(12px + env(safe-area-inset-bottom));
        z-index: 60;
        gap: 6px;
    }
    .pager__btn {
        width: 30px; height: 30px;
        border-radius: 50%;
        border: 1px solid var(--rule);
        color: var(--text-muted);
        font-size: .72rem;
        display: flex; align-items: center; justify-content: center;
        background: color-mix(in srgb, var(--bg) 85%, transparent);
        backdrop-filter: var(--glass);
        -webkit-backdrop-filter: var(--glass);
    }
}

/* ==========================================================================
   REDUCED MOTION
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

/* ==========================================================================
   SNAKE EASTER EGG
   ========================================================================== */
#snake-warning {
    position: fixed;
    top: 10px; left: 0;
    width: 100%;
    z-index: 9998;
    text-align: center;
    font-family: var(--font-mono);
    font-size: .58rem;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--accent-ink);
    pointer-events: none;
}

#snake-canvas { position: fixed; top: 0; left: 0; z-index: 10000; pointer-events: none; }

#snake-hud {
    position: fixed;
    top: 10px; left: 0;
    width: 100%;
    display: flex;
    justify-content: space-between;
    padding: 0 1rem;
    font-family: var(--font-mono);
    font-size: .6rem;
    letter-spacing: .2em;
    color: var(--text-primary);
    z-index: 10001;
    pointer-events: none;
}

#snake-gameover {
    position: fixed;
    inset: 0;
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .55rem;
    z-index: 10002;
    font-family: var(--font-mono);
    color: var(--text-primary);
    text-align: center;
}
#snake-go-text { font-size: 1.1rem; font-weight: 600; letter-spacing: .3em; }
#snake-go-score { font-size: .78rem; letter-spacing: .16em; color: var(--accent-ink); }
#snake-go-hint { font-size: .56rem; letter-spacing: .12em; color: var(--text-muted); }
