/* ───────────────────────────────────────────────────────────────────────────
   Vincent Allen — vincentallen.pro
   TWO design languages, deliberately, with a hard seam between them:

     · The HERO is the SPLINE language (spline.design) — pure black, alpha
       surfaces, weight 500, draggable soft-3D objects.  DESIGN_BRIEF §3.
     · EVERYTHING BELOW is the PITCH language (pitch.com) — white, weight 700
       headlines, Space Mono eyebrows, violet #5318EB, rounded 20/24px panels.
       DESIGN_BRIEF §3A.

   Both token sets were SAMPLED from the live sites (CSS custom properties and
   computed styles read back over CDP), not eyeballed. The seam is the rounded
   white shoulder at `.light` — pitch.com's own page does the same thing, going
   from a saturated hero into a white body.

   THE RULES, per language:
     SPLINE   1. field is pure black; surfaces are white at low alpha
              2. --blue #0062ff is a FILL (white on it 5.01:1); as text it is
                 4.19:1 and FAILS — accent text is --blue-hi #5797ff (7.28:1)
              3. nothing heavier than 500, tracking normal
     PITCH    4. headlines are 700. This is the exact opposite of rule 3, and
                 the two must never meet inside one section.
              5. --violet #5318EB works BOTH ways — 7.78:1 as text on white AND
                 7.78:1 as a fill under white. It is the only accent on this
                 page that is safe in both roles; do not assume the same of the
                 Spline blue above.
   ─────────────────────────────────────────────────────────────────────────── */

/* Spline Sans — the hero's typeface, and the body face throughout. SIL OFL,
   self-hosted. One variable file, real wght axis 300–700 (verified: rendered
   widths rise monotonically 446px → 477px at 60px, so 700 is drawn, not
   synthesised — which is what lets it carry the Pitch headline weight too). */
@font-face {
  font-family: 'Spline Sans';
  src: url('splinesans-latin.woff2') format('woff2');
  font-weight: 300 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Spline Sans';
  src: url('splinesans-latin-ext.woff2') format('woff2');
  font-weight: 300 700; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Space Mono — pitch.com's eyebrow face, SIL OFL, self-hosted. 16 KB. It is
   used ONLY for the uppercase section labels; it is not a body face. */
@font-face {
  font-family: 'Space Mono';
  src: url('spacemono-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

:root {
  /* ── Spline tokens (hero) ─────────────────────────────────────────────── */
  --bg:        #000;                      /* --color-bg */
  --panel:     rgba(255,255,255,.05);     /* --color-btn-bg */
  --panel-hi:  rgba(255,255,255,.08);     /* --color-panel-bg */
  --line:      rgba(255,255,255,.10);     /* --color-white-010 */
  --line-soft: rgba(255,255,255,.06);
  --blue:      #0062ff;                   /* --color-blue — fill only */
  --blue-hi:   #5797ff;                   /* --color-blue-lighter — accent text */
  --blue-dk:   #217ce5;
  --teal:      #38e2b3;                   /* --color-super-lighter */
  --ink:       #fff;
  --ink-70:    rgba(255,255,255,.7);
  --ink-60:    rgba(255,255,255,.6);       /* 7.37:1 */
  --ink-40:    rgba(255,255,255,.4);

  /* ── Pitch tokens (everything below the hero) ─────────────────────────── */
  --p-ink:     #0C021C;   /* rgb(12,2,28)    — 105 text uses, the primary ink   */
  --p-body:    #363636;   /* rgb(54,54,54)   — body copy, 12.08:1 on white      */
  --p-mute:    #666;      /* rgb(102,102,102)— meta, 5.74:1 on white            */
  --p-violet:  #5318EB;   /* rgb(83,24,235)  — THE accent. 7.78:1 both ways     */
  --p-lilac:   #C6A5FF;   /* rgb(198,165,255)                                   */
  --p-lav:     #EBE3FE;   /* rgb(235,227,254)— panel wash                       */
  --p-deep:    #280F62;   /* rgb(40,15,98)   — the dark panel, 13 uses          */
  --p-lime:    #C4EE87;   /* rgb(196,238,135)— the one non-violet action colour */
  --p-off:     #F6F6F6;   /* rgb(246,246,246)                                   */
  --p-line:    #E8E4F0;

  --sans: 'Spline Sans', system-ui, -apple-system, BlinkMacSystemFont,
          'Helvetica Neue', Helvetica, Arial, sans-serif;
  --mono: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --ease: cubic-bezier(.22, 1, .36, 1);
  --pad:  clamp(4.5rem, 9vw, 8rem);
  --r16:  16px;
  --r12:  12px;
  --pill: 50px;
  /* Pitch radii, by frequency on the source: 20px (35 uses), 24px (17), 70px */
  --p-r:    20px;
  --p-r-lg: 24px;
  --p-pill: 70px;
}

/* ── reset ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; background: var(--bg); }
body {
  margin: 0; font-family: var(--sans); font-size: 1rem; line-height: 1.6;
  color: var(--ink-60); background: var(--bg);
  -webkit-font-smoothing: antialiased; overflow-x: hidden;
}
img { max-width: 100%; display: block; }
figure { margin: 0; }
h1, h2, h3 { margin: 0; line-height: 1.22; font-weight: 500; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--p-violet); outline-offset: 3px; border-radius: 4px; }
.hero :focus-visible { outline-color: var(--blue-hi); }
::selection { background: rgba(83,24,235,.25); color: var(--p-ink); }
.hero ::selection { background: rgba(0,98,255,.45); color: #fff; }

.wrap { width: min(1160px, 90vw); margin-inline: auto; }
.ico {
  width: 1em; height: 1em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ═══ HERO — the Spline language ═══════════════════════════════════════════ */

.hero {
  position: relative; overflow: hidden;
  min-height: 100svh; display: grid; place-items: center;
  padding: 7rem 0 5rem;
  letter-spacing: normal;                 /* Spline rule 3 */
}
.hero__glow {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(58% 40% at 50% 34%, rgba(0,98,255,.16), transparent 70%),
    radial-gradient(40% 30% at 82% 22%, rgba(167,112,255,.10), transparent 72%),
    radial-gradient(38% 28% at 16% 70%, rgba(255,92,171,.08), transparent 74%);
}
/* The floor plane. `bottom` MUST stay 0 — transform-origin sits on this
   element's bottom edge, so rotateX folds the plane up toward that line and the
   visible band is only height×cos(72°) ≈ 31% of its box, measured up from the
   origin. Pushing the origin below the hero puts the whole band outside the
   overflow clip, and it renders as nothing at all. */
.hero__floor {
  position: absolute; z-index: 0; pointer-events: none;
  left: -50%; right: -50%; bottom: 0; height: 95vh;
  background-image:
    linear-gradient(rgba(255,255,255,.22) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.22) 1px, transparent 1px);
  background-size: 66px 66px;
  transform: perspective(700px) rotateX(72deg);
  transform-origin: 50% 100%;
  -webkit-mask-image: linear-gradient(to bottom, transparent 4%, rgba(0,0,0,.45) 34%, #000 72%, #000);
  mask-image: linear-gradient(to bottom, transparent 4%, rgba(0,0,0,.45) 34%, #000 72%, #000);
  opacity: .8;
}
.stage { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

.hero__copy {
  position: relative; z-index: 2; text-align: center;
  width: min(880px, 92vw); margin-inline: auto;
  display: flex; flex-direction: column; align-items: center; gap: 1.35rem;
}
/* Pointer-transparent so the objects underneath stay grabbable; the controls
   opt back in. Without this the drag has dead zones over the type, and the
   whole illusion of picking things up collapses. */
.hero__copy h1, .hero__copy .lead { pointer-events: none; }
.hero__copy .chip, .hero__copy .btn, .hero__copy a { pointer-events: auto; }

.hero h1 { font-size: clamp(2rem, 7.2vw, 3.625rem); color: var(--ink); font-weight: 500; }
/* The source's two-tone headline. The role line steps down to .72em purely so
   name and role each hold one line — at parity the role wraps and the pair
   stops reading as a single lockup. */
.hero h1 span { display: block; font-size: .72em; color: rgba(255,255,255,.5); margin-top: .15em; }
.lead { font-size: clamp(1rem, 1.5vw, 1.125rem); color: var(--ink-60); max-width: 56ch; }
.lead a { color: var(--blue-hi); text-decoration: none; border-bottom: 1px solid rgba(87,151,255,.35); }
.lead a:hover { border-bottom-color: var(--blue-hi); }
.hero__cta { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; margin-top: .35rem; }

.chip {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8125rem; font-weight: 400; color: var(--ink-70);
  padding: .5rem 1rem; border-radius: var(--pill);
  border: 1px solid var(--line-soft); background: var(--panel);
  backdrop-filter: blur(12px);
}
.chip__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--blue-hi); flex: none; }
.chip__dot--live {
  background: var(--teal); box-shadow: 0 0 0 3px rgba(56,226,179,.14);
  animation: pulse 2.6s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .4 } }

/* Hero actions: solid --blue, WHITE label, 12px radius, 16/24 padding — all
   measured off the source's own CTA. 12px, NOT a pill: Spline pills its nav and
   squares its actions. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  padding: 1rem 1.5rem; border-radius: var(--r12);
  font-family: inherit; font-size: 1rem; font-weight: 400; line-height: 1.25;
  text-decoration: none; cursor: pointer;
  color: #fff; background: var(--blue); border: 1px solid var(--blue);
  transition: background-color .2s ease, border-color .2s ease, transform .2s var(--ease);
}
.btn:hover { background: var(--blue-dk); border-color: var(--blue-dk); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 15px; height: 15px; }
.btn--ghost {
  background: var(--panel); border-color: var(--line);
  color: var(--ink); backdrop-filter: blur(12px);
}
.btn--ghost:hover { background: rgba(255,255,255,.11); }

.hint {
  /* clears the light region's rounded shoulder, which overlaps the hero by 40px */
  position: absolute; z-index: 3; left: 50%; bottom: 4.75rem; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: .5rem; white-space: nowrap;
  font-size: .8125rem; color: var(--ink-40);
  padding: .5rem 1rem; border-radius: var(--pill);
  border: 1px solid var(--line-soft); background: rgba(255,255,255,.04);
  backdrop-filter: blur(12px);
  transition: opacity .5s ease, transform .5s var(--ease);
}
.hint.is-gone { opacity: 0; transform: translate(-50%, 8px); }
.hint svg { width: 14px; height: 14px; }

/* ── the draggable objects ─────────────────────────────────────────────────
   Soft-3D without WebGL: a 145° gradient body, a bright inset rim at the top, a
   dark inset pool at the bottom, one long drop shadow and one coloured bloom.
   Depth is a blur on the far ones and nothing else. */
.obj {
  position: absolute; top: 0; left: 0; pointer-events: auto;
  cursor: grab; touch-action: none;
  will-change: transform;
  background-image: var(--g);
  border-radius: var(--br, 30%);
  box-shadow:
    inset 0 2px 10px rgba(255,255,255,.34),
    inset 0 -14px 26px rgba(0,0,0,.36),
    0 26px 54px -18px rgba(0,0,0,.95),
    0 0 46px -12px var(--bloom, transparent);
}
.obj::after {                       /* the specular kiss, top-left */
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: radial-gradient(52% 42% at 30% 22%, rgba(255,255,255,.42), transparent 62%);
  opacity: .85; pointer-events: none;
}
.obj.is-held { cursor: grabbing; }
/* Radius is what sells each body as a distinct object rather than a recolour of
   the last one; --br is set per shape from site.js. */
.obj--blob { border-radius: 58% 42% 47% 53% / 46% 51% 49% 54%; }
.obj--pill { border-radius: 50%; }
/* Near-black pebbles. They read as depth, so they must not catch a highlight. */
.obj--dark { box-shadow: inset 0 1px 6px rgba(255,255,255,.10), 0 18px 40px -16px #000; }
.obj--dark::after { opacity: .18; }

/* Project cards. These replaced the portrait as the hero's physical objects:
   a face being knocked around by geometry read badly, and the work is a better
   thing to hand someone anyway. */
.obj--card {
  border-radius: 16px; overflow: hidden; background-image: none; background: #0b0d10;
  /* The bloom is per-card and matches nothing in the image — it is what keeps
     the field reading as spline.design's colour composition now that the
     coloured slabs are gone. */
  box-shadow:
    0 0 0 1px rgba(255,255,255,.16),
    0 32px 64px -20px rgba(0,0,0,.95),
    0 0 60px -12px var(--bloom, transparent);
}
.obj--card picture { display: block; width: 100%; height: 100%; }
.obj--card img { width: 100%; height: 100%; object-fit: cover; }
.obj--card::after {
  border-radius: inherit; opacity: 1;
  background:
    linear-gradient(160deg, rgba(255,255,255,.20), transparent 42%),
    linear-gradient(0deg, rgba(0,0,0,.35), transparent 55%);
}

/* ═══ THE SEAM ═════════════════════════════════════════════════════════════
   Black hero → white body. The shoulder is a rounded top on the light region
   pulled up over the hero, so the transition is a deliberate edge rather than a
   muddy gradient between two saturated fields. */
.light {
  position: relative; z-index: 5;
  background: #fff; color: var(--p-body);
  border-radius: 40px 40px 0 0;
  margin-top: -40px;
  letter-spacing: -0.01em;
}
.light h2, .light h3 { color: var(--p-ink); letter-spacing: -0.02em; }

/* ═══ BELOW THE HERO — the Pitch language ══════════════════════════════════ */

.sec { padding-block: var(--pad); scroll-margin-top: 5rem; }
.sec--off  { background: var(--p-off); }

/* The eyebrow. Space Mono, uppercase, violet — pitch.com's single most
   identifiable component, and the reason a mono face is loaded at all. */
.eyebrow {
  display: block; font-family: var(--mono); font-size: .75rem; font-weight: 400;
  letter-spacing: .1em; text-transform: uppercase; color: var(--p-violet);
  margin-bottom: 1.1rem;
}
.sec__head { max-width: 46rem; margin-bottom: clamp(2.5rem, 5vw, 3.5rem); }
.sec__head h2 {
  font-size: clamp(1.9rem, 4.2vw, 3rem); font-weight: 700; line-height: 1.1;
}
.sec__head h2 em { font-style: normal; color: var(--p-violet); }
.sec__head .sub {
  margin-top: 1.25rem; font-size: clamp(1rem, 1.3vw, 1.125rem);
  color: var(--p-body); max-width: 40rem;
}
.sec--center .sec__head { margin-inline: auto; text-align: center; }
.sec--center .sec__head .sub { margin-inline: auto; }

.prose { color: var(--p-body); max-width: 40rem; font-size: 1.0625rem; }
.prose p + p { margin-top: 1.1rem; }
.prose strong { color: var(--p-ink); font-weight: 700; }

/* ── about: copy left, stat rail right ─────────────────────────────────── */
.about { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.stats { display: grid; gap: .75rem; }
.stat {
  padding: 1.5rem 1.6rem; border-radius: var(--p-r);
  background: var(--p-off); border: 1px solid var(--p-line);
}
.stat b {
  display: block; font-size: clamp(1.75rem, 3vw, 2.25rem); font-weight: 700;
  color: var(--p-violet); line-height: 1.05; letter-spacing: -0.02em;
}
.stat span { display: block; margin-top: .4rem; font-size: .9375rem; color: var(--p-mute); }

/* ── capability rows ───────────────────────────────────────────────────────
   pitch.com's feature block: icon + violet bold heading + grey paragraph, in a
   quiet card. Two up, because four across turns the headings into labels. */
.caps { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.cap {
  padding: clamp(1.6rem, 2.5vw, 2.1rem); border-radius: var(--p-r);
  background: #fff; border: 1px solid var(--p-line);
  transition: border-color .25s ease, transform .25s var(--ease), box-shadow .25s ease;
}
.cap:hover {
  border-color: var(--p-lilac); transform: translateY(-3px);
  box-shadow: 0 18px 40px -24px rgba(83,24,235,.55);
}
.cap__h { display: flex; align-items: center; gap: .7rem; margin-bottom: .85rem; }
.cap__h svg { width: 22px; height: 22px; color: var(--p-violet); }
.cap h3 { font-size: 1.25rem; font-weight: 700; color: var(--p-violet); }
.cap p { font-size: 1rem; color: var(--p-body); }
.cap ul { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.1rem; }
.cap li {
  font-family: var(--mono); font-size: .75rem; color: var(--p-mute);
  padding: .3rem .7rem; border-radius: var(--p-pill); background: var(--p-off);
}

/* ── work gallery ──────────────────────────────────────────────────────────
   The thumbnail sits INSIDE a lilac gradient frame — pitch.com never shows a
   product shot flush; it always floats it on a tinted panel. */
.work { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem 1.5rem; }
.wcard { display: flex; flex-direction: column; }
.wcard__frame {
  border-radius: var(--p-r-lg); padding: 12px; margin-bottom: 1.1rem;
  background: linear-gradient(155deg, var(--p-lav), var(--p-lilac));
  transition: transform .35s var(--ease), box-shadow .35s ease;
}
.wcard:hover .wcard__frame {
  transform: translateY(-4px);
  box-shadow: 0 24px 44px -26px rgba(83,24,235,.7);
}
.wcard__frame figure { border-radius: 12px; overflow: hidden; aspect-ratio: 16 / 10; background: #14161a; }
.wcard__frame img { width: 100%; height: 100%; object-fit: cover; }
.wcard__team {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--p-mute); margin-bottom: .5rem;
}
.wcard h3 { font-size: 1.1875rem; font-weight: 700; margin-bottom: .45rem; }
.wcard p { font-size: .9688rem; color: var(--p-body); }
.wcard__meta {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: .8rem;
  font-size: .8125rem; font-weight: 700; color: var(--p-violet);
  padding: .3rem .7rem; border-radius: var(--p-pill); background: var(--p-lav);
}
.wcard__meta svg { width: 13px; height: 13px; }
.wcard__tags { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .9rem; }
.wcard__tags li {
  font-family: var(--mono); font-size: .6875rem; color: var(--p-mute);
  padding: .25rem .6rem; border-radius: var(--p-pill);
  background: #fff; border: 1px solid var(--p-line);
}

/* ── stack ─────────────────────────────────────────────────────────────── */
.stack { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.stack__g { padding: 1.6rem 1.5rem; border-radius: var(--p-r); background: #fff; border: 1px solid var(--p-line); }
.stack__g h3 {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--p-violet); margin-bottom: 1.1rem; font-weight: 400;
}
.stack__g ul { display: flex; flex-wrap: wrap; gap: .4rem; }
.stack__g li {
  font-size: .875rem; color: var(--p-ink);
  padding: .35rem .8rem; border-radius: var(--p-pill);
  background: var(--p-off); border: 1px solid transparent;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.stack__g li:hover { background: var(--p-lav); border-color: var(--p-lilac); color: var(--p-violet); }

/* ── contact ───────────────────────────────────────────────────────────── */
.contact__panel {
  position: relative; overflow: hidden; text-align: center;
  padding: clamp(3rem, 7vw, 5.5rem) clamp(1.5rem, 5vw, 4rem);
  border-radius: 32px; background: var(--p-deep); color: #fff;
}
.contact__panel::after {          /* one soft violet bloom, upper-right */
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 90% at 78% 0%, rgba(198,165,255,.30), transparent 66%);
}
.contact__panel > * { position: relative; z-index: 1; }
.contact__panel .eyebrow { color: var(--p-lilac); }
.contact__panel h2 {
  color: #fff; font-size: clamp(1.9rem, 4vw, 2.75rem); font-weight: 700; line-height: 1.12;
}
.contact__panel .prose { color: rgba(255,255,255,.82); margin: 1.25rem auto 2rem; text-align: center; }
.contact__panel .prose strong { color: #fff; }

/* The action pair, both measured off pitch.com: violet fill with a white label
   (7.78:1), and the lime chip with the ink label (15.30:1). The lime is the
   only non-violet action colour on the source and it is used exactly once. */
.pbtn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  padding: 1rem 1.75rem; border-radius: var(--p-pill);
  font-family: inherit; font-size: 1rem; font-weight: 700; line-height: 1.2;
  text-decoration: none; cursor: pointer; border: 1px solid transparent;
  transition: transform .2s var(--ease), background-color .2s ease, box-shadow .2s ease;
}
.pbtn svg { width: 15px; height: 15px; }
.pbtn--lime { background: var(--p-lime); color: var(--p-ink); }
.pbtn--lime:hover { background: #d3f5a2; transform: translateY(-2px); }
.pbtn--violet { background: var(--p-violet); color: #fff; }
.pbtn--violet:hover { background: #4512c9; transform: translateY(-2px); }
.pbtn--ghost { background: rgba(255,255,255,.10); color: #fff; border-color: rgba(255,255,255,.22); }
.pbtn--ghost:hover { background: rgba(255,255,255,.18); transform: translateY(-2px); }
.actions { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }

.socials { display: flex; gap: .5rem; justify-content: center; margin-top: 2.25rem; }
.socials a {
  width: 42px; height: 42px; border-radius: var(--p-pill); display: grid; place-items: center;
  border: 1px solid rgba(255,255,255,.2); background: rgba(255,255,255,.08); color: #fff;
  transition: background-color .2s ease, transform .2s var(--ease);
}
.socials a:hover { background: rgba(255,255,255,.2); transform: translateY(-2px); }
.socials svg { width: 16px; height: 16px; }

.foot {
  border-top: 1px solid var(--p-line); margin-top: var(--pad);
  padding-block: 2rem 2.5rem;
  font-family: var(--mono); font-size: .75rem; color: var(--p-mute);
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; justify-content: space-between;
}

/* ── top bar ───────────────────────────────────────────────────────────────
   One floating pill, dark over the hero. Past the hero it inverts to the Pitch
   palette — a dark glass pill on a white page reads as a leftover. */
.topbar {
  position: fixed; z-index: 40; top: 1rem; left: 50%; transform: translateX(-50%);
  width: min(1080px, 94vw);
  display: flex; align-items: center; gap: 1rem;
  padding: .5rem .5rem .5rem .75rem; border-radius: var(--pill);
  border: 1px solid var(--line-soft); background: rgba(12,12,14,.55);
  backdrop-filter: blur(16px) saturate(140%);
  transition: background-color .3s ease, border-color .3s ease, box-shadow .3s ease;
}
.topbar.is-stuck { background: rgba(12,12,14,.86); border-color: var(--line); }
.brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; margin-right: auto; }
.brand img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; border: 1px solid var(--line); }
.brand b { font-weight: 500; font-size: .9375rem; color: var(--ink); }
.brand span { font-size: .9375rem; color: var(--ink-40); }
.topnav { display: none; gap: .25rem; }
.topnav a {
  padding: .5rem .8rem; border-radius: var(--pill); text-decoration: none;
  font-size: .9375rem; color: var(--ink-70);
  transition: color .2s ease, background-color .2s ease;
}
.topnav a:hover, .topnav a.is-active { color: var(--ink); background: var(--panel); }
.topbar .btn {
  padding: .625rem 1rem; font-size: .9375rem; border-radius: var(--pill);
  background: rgba(255,255,255,.2); border-color: transparent; color: #fff;
}
.topbar .btn:hover { background: rgba(255,255,255,.28); border-color: transparent; }

/* inverted state, over the white body */
.topbar.on-light {
  background: rgba(255,255,255,.9); border-color: var(--p-line);
  box-shadow: 0 10px 34px -18px rgba(12,2,28,.4);
}
.topbar.on-light .brand b { color: var(--p-ink); }
.topbar.on-light .brand span { color: var(--p-mute); }
.topbar.on-light .brand img { border-color: var(--p-line); }
.topbar.on-light .topnav a { color: var(--p-body); }
.topbar.on-light .topnav a:hover, .topbar.on-light .topnav a.is-active { color: var(--p-ink); background: var(--p-off); }
.topbar.on-light .btn { background: var(--p-violet); color: #fff; }
.topbar.on-light .btn:hover { background: #4512c9; }

/* ── reveal ────────────────────────────────────────────────────────────────
   Scoped to .js (set inline in <head>). If the script never runs nothing is
   hidden — a reveal must never be able to blank the page. */
.js .reveal { opacity: 0; transform: translateY(16px); }
.js .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}

/* ── responsive ────────────────────────────────────────────────────────── */
@media (min-width: 900px) { .topnav { display: flex; } }
@media (max-width: 1080px) {
  .work  { grid-template-columns: repeat(2, 1fr); }
  .stack { grid-template-columns: repeat(2, 1fr); }
  .about { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .caps, .work, .stack { grid-template-columns: 1fr; }
  .brand span { display: none; }
  .hero { min-height: 92svh; padding-top: 6rem; }
  .hero__cta { width: 100%; }
  .hero__cta .btn { flex: 1 1 auto; }
  .hint { bottom: 3.25rem; }
  .light { border-radius: 28px 28px 0 0; }
  .actions .pbtn { flex: 1 1 auto; }
  .foot { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
  .hint { display: none; }
  .obj { cursor: default; }
}
