/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */
:root {
  /* ---- Surfaces: layered near-black, all below 10% relative luminance ---- */
  --bg-void:    #05060a;
  --bg-base:    #0a0c12;
  --surface-1:  #10131c;
  --surface-2:  #171b27;
  --surface-3:  #1f2432;
  --hairline:   #262c3b;

  /* ---- Accents ---- */
  --cyan:       #38f2ff;
  --magenta:    #ff4bd8;
  --amber:      #ffb03a;
  --steel:      #e8eefc;
  /* Nebula-only hue. Never used for text or borders, so it carries no
     contrast obligation — it exists to give the deep-space layer a third
     temperature between the cyan and magenta accents. */
  --violet:     #9a6cff;

  /* RGB channel triplets for composing translucent variants */
  --cyan-rgb:    56, 242, 255;
  --magenta-rgb: 255, 75, 216;
  --amber-rgb:   255, 176, 58;
  --steel-rgb:   232, 238, 252;
  --violet-rgb:  154, 108, 255;

  /* ---- Text ---- */
  --text-strong: #f2f6ff;
  --text-body:   #c7d0e6;
  --text-muted:  #9aa6c2;

  /* ---- Spacing scale ---- */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;     --sp-7: 3rem;     --sp-8: 4rem;
  --sp-9: 6rem;     --sp-10: 8rem;

  /* ---- Radii ---- */
  --r-xs: 4px;  --r-sm: 8px;  --r-md: 14px;  --r-lg: 22px;  --r-pill: 999px;

  /* ---- Glow ---- */
  --glow-cyan:    0 0 12px rgba(var(--cyan-rgb), .45),    0 0 36px rgba(var(--cyan-rgb), .18);
  --glow-magenta: 0 0 12px rgba(var(--magenta-rgb), .45), 0 0 36px rgba(var(--magenta-rgb), .18);
  --glow-amber:   0 0 12px rgba(var(--amber-rgb), .42),   0 0 34px rgba(var(--amber-rgb), .16);
  --glow-steel:   0 0 10px rgba(var(--steel-rgb), .30),   0 0 30px rgba(var(--steel-rgb), .10);
  --glow-accent:  0 0 14px rgba(var(--accent-rgb), .28),  0 0 40px rgba(var(--accent-rgb), .12);
  --glow-inset:   inset 0 0 30px rgba(var(--accent-rgb), .06);

  /* ---- Type ---- */
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, "Liberation Mono", monospace;

  --fs-100: clamp(0.75rem,  0.72rem + 0.15vw, 0.8125rem);
  --fs-200: clamp(0.8125rem,0.78rem + 0.20vw, 0.875rem);
  --fs-300: clamp(1rem,     0.96rem + 0.25vw, 1.0625rem);  /* floor is 16px */
  --fs-400: clamp(1.125rem, 1.05rem + 0.40vw, 1.375rem);
  --fs-500: clamp(1.5rem,   1.20rem + 1.40vw, 2.25rem);
  --fs-600: clamp(2rem,     1.30rem + 3.00vw, 3.5rem);
  --fs-900: clamp(2.25rem,  1.35rem + 5.00vw, 5.5rem);

  --lh-tight: 1.05;  --lh-snug: 1.25;  --lh-body: 1.65;
  --track-wide: 0.14em;
  --track-mega: 0.02em;

  /* ---- Motion ---- */
  --dur-fast: 120ms;
  --dur-base: 160ms;   /* nav indicator stays inside the 200ms budget */
  --dur-slow: 260ms;
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* ---- Layout ---- */
  --measure: 68ch;
  --shell: 1200px;
  --gutter: var(--sp-5);
  --header-h: 64px;
}

/* ==========================================================================
   2. GLOBAL BASE AND UTILITIES
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg-base);
  color: var(--text-body);
  font: var(--fs-300)/var(--lh-body) var(--font-ui);
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
}

section { position: relative; scroll-margin-top: calc(var(--header-h) + var(--sp-4)); }

.shell { width: min(100% - 2 * var(--gutter), var(--shell)); margin-inline: auto; }

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

/* Zero-size, non-rendering sprite host. display:none is avoided on purpose:
   some engines refuse to paint symbols pulled from a display:none subtree. */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.eyebrow {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-100);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--cyan);
}

.section-title {
  margin: 0 0 var(--sp-6);
  font-size: var(--fs-500);
  font-weight: 800;
  line-height: var(--lh-snug);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-strong);
  text-shadow: 0 0 26px rgba(var(--cyan-rgb), .20);
}
.section-title--sm { font-size: var(--fs-400); margin-bottom: var(--sp-3); }

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

/* ==========================================================================
   3. LOGO MARK — circular frame around bajr_profile_logo.png
   ========================================================================== */
/* The 1px ring is the padding box of the frame showing through beneath a round
   image, so there is no extra element and no second border to keep in sync. */
.logo {
  width: 36px; height: 36px; display: block; flex: none;
  padding: 1px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--cyan), var(--magenta));
  box-shadow: 0 0 10px rgba(var(--cyan-rgb), .45), 0 0 26px rgba(var(--magenta-rgb), .16);
}
.logo img {
  width: 100%; height: 100%; display: block;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-1);
}
.logo--lg { width: 52px; height: 52px; }

/* ==========================================================================
   4. HEADER, NAV, SLIDING INDICATOR, BUTTONS
   ========================================================================== */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(10, 12, 18, .78);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
          backdrop-filter: blur(12px) saturate(1.2);
  border-bottom: 1px solid var(--hairline);
  box-shadow: 0 1px 0 rgba(var(--cyan-rgb), .10), 0 8px 30px rgba(0, 0, 0, .45);
}

.nav {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-3) var(--sp-4);
  min-height: var(--header-h);
  padding-block: var(--sp-2);
}

.nav__brand {
  order: 1;
  display: inline-flex; align-items: center; gap: var(--sp-3);
  text-decoration: none;
}
.nav__brandtext {
  font-size: var(--fs-100);
  font-weight: 800;
  letter-spacing: var(--track-wide);
  line-height: 1.15;
  color: var(--text-strong);
  display: grid;
}
.nav__brandtext span { color: var(--cyan); }

.btn--pill { order: 2; margin-left: auto; }

.nav__links {
  order: 3; flex-basis: 100%;
  display: flex; justify-content: center; position: relative;
}
.nav__list { display: flex; gap: var(--sp-5); list-style: none; margin: 0; padding: 0; }

.nav__link {
  display: block; padding: var(--sp-2) var(--sp-1);
  font-size: var(--fs-100); letter-spacing: var(--track-wide);
  text-transform: uppercase; text-decoration: none;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease), text-shadow var(--dur-fast) var(--ease);
}
.nav__link:hover,
.nav__link[aria-current="true"] {
  color: var(--cyan);
  text-shadow: 0 0 14px rgba(var(--cyan-rgb), .5);
}

/* One absolutely positioned element, so it slides between links instead of
   snapping. The script writes only width, transform and opacity. */
.nav__indicator {
  position: absolute; left: 0; bottom: -2px;
  height: 2px; width: 0;
  background: linear-gradient(90deg, var(--cyan), var(--magenta));
  box-shadow: var(--glow-cyan);
  border-radius: var(--r-pill);
  opacity: 0;
  transform: translateX(0);
  transition: transform var(--dur-base) var(--ease),
              width var(--dur-base) var(--ease),
              opacity var(--dur-fast) linear;
  will-change: transform, width;
}

.btn {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  font-size: var(--fs-100); font-weight: 600;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  text-decoration: none; color: var(--steel);
  background: transparent;
  border: 1px solid rgba(var(--steel-rgb), .35);
  border-radius: var(--r-pill);
  box-shadow: var(--glow-steel);
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease),
              background-color var(--dur-fast) var(--ease);
}
.btn:hover, .btn:focus-visible {
  color: var(--cyan);
  border-color: rgba(var(--cyan-rgb), .75);
  background: rgba(var(--cyan-rgb), .06);
  box-shadow: var(--glow-cyan);
}
.btn__arrow {
  width: 1em; height: 1em; flex: none;
  transition: transform var(--dur-base) var(--ease);
}
.btn:hover .btn__arrow { transform: translateX(4px); }
.btn--cta { padding: var(--sp-4) var(--sp-6); }

/* ==========================================================================
   5. HERO
   ========================================================================== */
/* Less breathing room above the copy; more below so the now-absolute cabinet
   reflection stays inside the section and overflow:hidden does not clip it.
   overflow:hidden stays — it contains horizontal spill from the backdrop glows. */
.hero { padding-block: var(--sp-6) var(--sp-9); overflow: hidden; }
.hero__inner { display: grid; gap: var(--sp-7); position: relative; z-index: 1; }

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

/* Photographic backplate for the hero. Bottom of the stack: .hero__persp and
   everything after it paints on top, which is what knocks the photo back to a
   texture rather than a picture competing with the wordmark.

   The URL resolves against this stylesheet's location, not the HTML's, so
   "images/..." is correct with styles.css sitting at the site root.

   Framed at 38% vertically so the lit stone floor and the stair silhouette stay
   in shot as the section changes height, instead of centring on the dark
   ceiling beams. */
.hero__photo {
  position: absolute; inset: 0;
  background: url("images/backroom-arcade-hero-image.jpg") center 38% / cover no-repeat;
  opacity: .65;
}

/* Perspective: atmospheric depth bands plus a horizon bloom at the vanishing
   point. Lighter toward the horizon, deepest at the floor, which is what sells
   distance without drawing a single line.

   The base linear-gradient was opaque hex stops. Now rgba, because it sits
   directly over .hero__photo and opaque stops would hide the photo completely.
   The alphas are the exposure control for the plate: heavier at the top and
   bottom edges where the copy and the nav sit, lightest through the middle band
   where the room should read. Worst case under the copy works out near 7.5:1
   for --text-muted, so there is headroom, but raising the photo's opacity and
   lowering these together is what would spend it. */
.hero__persp {
  position: absolute; inset: 0;
  background:
    radial-gradient(58% 32% at 50% 58%,
      rgba(var(--cyan-rgb), .28) 0%,
      rgba(var(--cyan-rgb), .09) 42%,
      transparent 74%),
    radial-gradient(44% 34% at 84% 80%,
      rgba(var(--magenta-rgb), .18), transparent 70%),
    linear-gradient(180deg,
      rgba(5, 6, 10, .92) 0%,
      rgba(8, 12, 24, .70) 26%,
      rgba(13, 26, 48, .48) 50%,
      rgba(8, 13, 26, .72) 66%,
      rgba(5, 6, 10, .94) 100%);
}

/* Rays converging on the vanishing point, masked to a ring so they never reach
   the copy on the left or the hard edges of the section.

   Stripe alpha and layer opacity multiply, so the effective value is what
   matters: .18 * .92 lands near .166. That is the ceiling, not an arbitrary
   pick — the hero copy sits on these stripes over the #0d1a30 band of
   .hero__persp, and --text-muted clears 4.5:1 at .166 before .hero__vignette
   even darkens on top. Push either number higher and the sub-copy fails.

   The mask now carries the stripes out to 72% instead of 58%, which is a
   cheaper way to make them read than brightening: more visible ray length, same
   peak alpha. */
.hero__rays {
  position: absolute; left: 50%; top: 58%;
  width: 200%; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: repeating-conic-gradient(from 0deg,
    rgba(var(--cyan-rgb), .18) 0deg 1.15deg,
    transparent 1.15deg 6.5deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 2%, #000 16%,
    rgba(0, 0, 0, .75) 46%, transparent 72%);
          mask-image: radial-gradient(closest-side, transparent 2%, #000 16%,
    rgba(0, 0, 0, .75) 46%, transparent 72%);
  opacity: .52;
}

.hero__glow { position: absolute; border-radius: 50%; filter: blur(70px); }
.hero__glow--cyan {
  width: 60vw; height: 40vw; top: -12vw; left: -10vw;
  background: radial-gradient(circle, rgba(var(--cyan-rgb), .18), transparent 68%);
}
.hero__glow--magenta {
  width: 52vw; height: 38vw; bottom: -14vw; right: -12vw;
  background: radial-gradient(circle, rgba(var(--magenta-rgb), .16), transparent 68%);
}
/* Softened from the original so the horizon bloom survives the overlay while
   copy contrast is still held at the top and bottom edges.

   The radial was pulling in from 46% at .82, which ate the outer half of the
   rays — no point extending their mask if this immediately paints over them.
   Relaxed to 54% / .66. The linear layer is untouched: that is the one holding
   text contrast at the top and bottom, and the copy block sits well inside the
   radial's transparent core either way, so only the corners change. */
.hero__vignette {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(5, 6, 10, .82) 0%, transparent 52%, rgba(5, 6, 10, .55) 98%, rgba(5, 6, 10, .92) 100%),
    radial-gradient(130% 100% at 50% 42%, transparent 54%, rgba(5, 6, 10, .66) 100%);
}
.hero__grain {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: .06; mix-blend-mode: soft-light;
}

.hero__lead { font-size: var(--fs-400); color: var(--text-body); max-width: var(--measure); }
.hero__sub  { color: var(--text-muted); max-width: var(--measure); }

/* background-clip:text kills text-shadow, so the glow is rebuilt from a
   drop-shadow pair (tight halo) plus a blurred attr(data-text) duplicate
   behind the gradient layer (wide bloom). */
.wordmark {
  margin: var(--sp-4) 0 var(--sp-5);
  font-size: var(--fs-900);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-mega);
  font-weight: 800;
  filter: drop-shadow(0 0 18px rgba(var(--cyan-rgb), .35))
          drop-shadow(0 0 42px rgba(var(--magenta-rgb), .22));
}
.wordmark__line {
  display: block;
  position: relative;
  color: var(--cyan);
  background-image: linear-gradient(100deg, var(--cyan) 0%, #9ad8ff 42%, var(--magenta) 100%);
  -webkit-background-clip: text;
          background-clip: text;
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .wordmark__line { color: transparent; -webkit-text-fill-color: transparent; }
}
.wordmark__line::before {
  content: attr(data-text);
  position: absolute; inset: 0;
  color: var(--cyan);
  -webkit-text-fill-color: var(--cyan);
  filter: blur(18px);
  opacity: .45;
  z-index: -1;
}
.wordmark__line:last-child::before {
  color: var(--magenta);
  -webkit-text-fill-color: var(--magenta);
}

/* ---- Arcade cabinet: arcade_cabinet.png ----
   The render ships with its own neon bloom and a transparent background, so no
   drop-shadow filters here — they would double the glow. One soft ambient wash
   sits behind it. The floor reflection is a flipped, masked copy of the same
   file, cropped by aspect-ratio so it does not add a second cabinet's height. */
.hero__cabinet { justify-self: center; width: min(100%, 235px); position: relative; }
.hero__cabinet::before {
  content: ""; position: absolute; inset: 8% -14% 20%;
  background:
    radial-gradient(52% 42% at 50% 30%, rgba(var(--cyan-rgb), .13), transparent 72%),
    radial-gradient(56% 46% at 50% 78%, rgba(var(--magenta-rgb), .14), transparent 74%);
  filter: blur(26px);
  z-index: -1; pointer-events: none;
}
.hero__cab { width: 100%; height: auto; display: block; }

/* The mask is authored in the element's own axes and the flip happens after, so
   "to top" here reads as a downward dissolve once scaleY(-1) is applied.
   Taken out of normal flow so it adds no height to the column: with the grid
   centring on .hero__cabinet, in-flow reflection height would push the visible
   cabinet above the copy's centre line. */
.hero__cabrefl {
  position: absolute; top: 100%; left: 0;
  width: 100%; height: auto; display: block;
  aspect-ratio: 488 / 170;
  object-fit: cover; object-position: bottom;
  opacity: .22;
  transform: scaleY(-1);
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, .45) 38%, transparent 88%);
          mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, .45) 38%, transparent 88%);
}

/* ==========================================================================
   6. GAMES
   ========================================================================== */
.games { padding-block: var(--sp-8); }

.cards { display: grid; gap: var(--sp-5); }

/* Card visuals are entirely accent-driven: every card sets --accent and
   --accent-rgb inline, and no rule below is written per card. */
.card {
  display: flex; flex-direction: column;
  position: relative; isolation: isolate;
  background: var(--surface-2);
  border: 1px solid rgba(var(--accent-rgb), .45);
  border-radius: var(--r-md);
  box-shadow: var(--glow-accent), var(--glow-inset);
  overflow: hidden;
  transition: transform var(--dur-slow) var(--ease),
              box-shadow var(--dur-slow) var(--ease),
              border-color var(--dur-slow) var(--ease);
}

/* Accent light pooling along the bottom edge, clipped by the card's own
   overflow:hidden so it reads as light trapped inside the case rather than a
   drop shadow. isolation:isolate above plus `.card > *` below keep it behind
   the copy.

   Shape is the whole trick: a flat horizontal streak, not a dome. Every ellipse
   is far wider than it is tall and centred at or below the bottom edge, so only
   a shallow upper falloff is ever in frame. Three layers — a bright flat core
   on the edge, a halo blending it into the surface, and a faint wide wash so
   the bottom corners do not go abruptly dark.

   The vertical extents are the contrast control. The core's 11% dies out around
   19px above the bottom edge, inside the meta list's own bottom padding, so it
   never touches a row. Only the halo and the wash reach the PRICE line, at
   roughly .075 effective — that holds --text-muted near 5.6:1 even on the steel
   card, the brightest accent in the set. Core alpha is safe to raise. Core
   extent is not: that is the knob that pushes light up into the rows.

   The mask flattens the streak further and backstops the maths. Not decorative,
   do not remove it. */
.card::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 42%;
  z-index: -1; pointer-events: none;
  background:
    /* bright flat core riding the bottom edge */
    radial-gradient(72% 11% at 50% 100%, rgba(var(--accent-rgb), .62), transparent 72%),
    /* halo blending the core into the card surface */
    radial-gradient(96% 26% at 50% 104%, rgba(var(--accent-rgb), .26), transparent 74%),
    /* wide low wash reaching the bottom corners */
    radial-gradient(120% 52% at 50% 112%, rgba(var(--accent-rgb), .10), transparent 76%);
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, .45) 26%, transparent 62%);
          mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, .45) 26%, transparent 62%);
  opacity: .85;
  transition: opacity var(--dur-slow) var(--ease);
}
/* ---- Whole-card link ----
   The glow above is at z-index:-1 rather than 0 for this to work. -1 combined
   with isolation:isolate on .card paints it over the card's own background but
   under every in-flow child, which is the same result the old
   `.card > * { position: relative; z-index: 1 }` produced — except that rule
   made .card__title a containing block, which would have trapped the stretched
   hit area below inside the title bar instead of covering the card.

   Cards without a .card__link are unaffected: they just have no overlay. */
.card__link {
  color: inherit;
  text-decoration: none;
}
.card__link::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
}
/* The card already lifts and brightens via :hover / :focus-within, so the title
   only needs to pick up the accent to show it is the thing being activated. */
.card__link:hover, .card__link:focus-visible { color: var(--accent); }
/* The visible focus ring belongs on the card, not on a 0-height inline box. */
.card__link:focus-visible { outline: none; }
.card:focus-within { outline: 2px solid var(--cyan); outline-offset: 3px; }

.card:hover, .card:focus-within {
  transform: translateY(-4px);
  border-color: rgba(var(--accent-rgb), .85);
  box-shadow: 0 0 22px rgba(var(--accent-rgb), .38),
              0 0 60px rgba(var(--accent-rgb), .16),
              var(--glow-inset);
}
.card:hover::after, .card:focus-within::after { opacity: 1; }
.card__art { aspect-ratio: 16 / 10; background: var(--bg-void); position: relative; max-width: 100%; overflow: hidden;}
.card__art svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.card__title {
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  border-top: 1px solid rgba(var(--accent-rgb), .35);
  background: linear-gradient(180deg, rgba(var(--accent-rgb), .10), transparent);
}
.card__title h3 {
  margin: 0; font-size: var(--fs-400); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--text-strong);
}
.card__meta {
  margin: 0; padding: 0 var(--sp-4) var(--sp-4);
  display: grid; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-200);
}
.card__meta > div {
  display: flex; justify-content: space-between; gap: var(--sp-3);
  border-bottom: 1px dashed var(--hairline); padding-bottom: var(--sp-2);
}
.card__meta > div:last-child { border-bottom: 0; padding-bottom: 0; }
.card__meta dt { color: var(--text-muted); letter-spacing: .1em; }
.card__meta dd { margin: 0; color: var(--text-body); text-align: right; }
.card__price { color: var(--accent); font-weight: 700; }

/* ==========================================================================
   7. VIDEO SECTION — vertical playlist menu + HUD-framed player
   ========================================================================== */
.videos { padding-block: var(--sp-8); }

/* Base: the menu sits above the player as a wrapping row so it costs almost no
   vertical space. From 900px it becomes a stacked column on the left. */
.vplayer { display: grid; gap: var(--sp-5); }
.vplayer__menu { min-width: 0; }
.playlist { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.ptab {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  position: relative;
  flex: 1 1 auto; min-width: 0;
  padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-5);
  text-align: left;
  font: 600 var(--fs-100)/1.1 var(--font-ui);
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease),
              background-color var(--dur-fast) var(--ease);
}
/* Leading indicator bar: dim hairline until the item is the selected one. */
.ptab::before {
  content: ""; position: absolute; left: 7px; top: 24%; bottom: 24%;
  width: 2px; border-radius: var(--r-pill);
  background: var(--hairline);
  transition: background-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.ptab:hover { color: var(--steel); border-color: rgba(var(--steel-rgb), .4); }
.ptab[aria-selected="true"] {
  color: var(--cyan);
  background: rgba(var(--cyan-rgb), .08);
  border-color: rgba(var(--cyan-rgb), .75);
  box-shadow: var(--glow-cyan);
}
.ptab[aria-selected="true"]::before {
  background: var(--cyan);
  box-shadow: 0 0 10px rgba(var(--cyan-rgb), .85);
}

/* ---- HUD frame ----
   The chamfer lives on .hud__plate, a decorative layer behind the panel, so the
   clip never eats the corner brackets, the label chip, or the focus ring on the
   focusable tabpanel. */
/* The ambient halo lives here, not on the plate: clip-path would trim an outer
   box-shadow along with the corners. */
.hud { position: relative; box-shadow: 0 0 40px rgba(var(--cyan-rgb), .08); }
.hud__plate {
  position: absolute; inset: 0; pointer-events: none;
  background: var(--surface-1);
  border: 1px solid rgba(var(--cyan-rgb), .28);
  box-shadow: inset 0 0 40px rgba(0, 0, 0, .5);
  clip-path: polygon(14px 0, calc(100% - 14px) 0, 100% 14px, 100% calc(100% - 14px),
                     calc(100% - 14px) 100%, 14px 100%, 0 calc(100% - 14px), 0 14px);
}
/* Inner hairline, offset a few px in, so the border reads as a double frame. */
.hud__plate::after {
  content: ""; position: absolute; inset: 6px;
  border: 1px solid rgba(var(--cyan-rgb), .18);
}
.hud__label {
  position: absolute; top: -0.72em; left: 30px; z-index: 2;
  padding-inline: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-100);
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--cyan);
  background: var(--bg-base);
  pointer-events: none;
}
.hud__ticks {
  position: absolute; right: -4px; top: 40px; bottom: 40px; width: 7px;
  background: repeating-linear-gradient(to bottom,
    rgba(var(--cyan-rgb), .55) 0 1px, transparent 1px 9px);
  opacity: .5; pointer-events: none;
}

.panel {
  position: relative; z-index: 1;
  padding: var(--sp-4);
}
.panel__frame {
  display: block; width: 100%; aspect-ratio: 16 / 9; height: auto;
  border: 0; background: var(--bg-void);
}
.panel__fallback {
  color: var(--text-muted); text-align: center;
  padding: var(--sp-7) var(--sp-4); margin: 0;
}

/* ==========================================================================
   8. PROJECT + SHARED PERSPECTIVE GRID FLOOR
   ========================================================================== */
/* #project is a curved grid chamber, not the flat .grid-floor below: its arcs
   and meridians are the inline .chamber SVG. overflow:hidden contains the
   stretched grid and the over-wide horizon band; isolation:isolate keeps the
   negative-z decorative layers above the section box instead of behind the
   page. Layer order is sky (-3) → chamber (-2) → horizon (-1) → copy (1). */
.project {
  position: relative; overflow: hidden; isolation: isolate;
  padding-block: var(--sp-9);
  text-align: center;
}
.project__body {
  max-width: 52ch; margin-inline: auto;
  color: var(--text-body); font-size: var(--fs-400);
}
.project__inner { position: relative; z-index: 1; }

/* Contrast scrim. The sky below is bright enough now that --text-body over the
   raw nebula would drop under 4.5:1, so the copy carries its own pool of
   near-black. z-index:-1 resolves inside .project__inner (position + z-index:1
   makes it a stacking context), which puts the scrim above the chamber and the
   sky but below the text. Feathered to nothing well before the edges so it
   never reads as a panel. */
.project__inner::before {
  content: ""; position: absolute;
  inset: calc(var(--sp-7) * -1) calc(var(--sp-6) * -1);
  z-index: -1; pointer-events: none;
  background: radial-gradient(56% 68% at 50% 50%,
    rgba(5, 6, 10, .88) 0%, rgba(5, 6, 10, .62) 52%, rgba(5, 6, 10, .22) 76%, transparent 92%);
}

/* Horizon glow band, centred on the vanishing point at 50% height, so the
   meridians appear to dissolve into light rather than converge to a dot. The
   core is bright — this is the light source the whole chamber is lit by — and
   the scrim above is what buys back the text contrast. */
.project::before {
  content: ""; position: absolute; left: -14%; right: -14%; top: 50%; height: 58%;
  transform: translateY(-50%);
  background:
    radial-gradient(30% 24% at 50% 50%, rgba(var(--steel-rgb), .22), transparent 68%),
    radial-gradient(58% 46% at 50% 50%, rgba(var(--cyan-rgb),  .26), transparent 70%),
    radial-gradient(84% 34% at 50% 50%, rgba(var(--violet-rgb), .24), transparent 76%);
  z-index: -1; pointer-events: none;
}

/* The chamber stretches to the section box (preserveAspectRatio="none"), which
   is why every path carries vector-effect="non-scaling-stroke" — otherwise the
   horizontal scale would fatten the verticals. The mask dissolves the grid at
   the horizon, where the glow band takes over, and at all four extremes, so no
   line ends on a hard edge. */
.chamber {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: -2; pointer-events: none;
  /* Bloom on the strokes themselves. One drop-shadow on the whole SVG is far
     cheaper than a per-path filter and reads the same at this line weight. */
  filter: drop-shadow(0 0 5px rgba(var(--cyan-rgb), .40));
  -webkit-mask-image: radial-gradient(115% 62% at 50% 50%, transparent 0%,
    rgba(0, 0, 0, .45) 13%, #000 34%, rgba(0, 0, 0, .55) 74%, transparent 100%);
          mask-image: radial-gradient(115% 62% at 50% 50%, transparent 0%,
    rgba(0, 0, 0, .45) 13%, #000 34%, rgba(0, 0, 0, .55) 74%, transparent 100%);
}

@media (min-width: 900px) {
  .project { padding-block: var(--sp-10); }
}

/* overflow:hidden is load-bearing here: the rotated grid layer deliberately
   extends past the section edges and would otherwise cause horizontal scroll. */
.grid-floor { position: relative; overflow: hidden; isolation: isolate; }
.grid-floor::before {
  content: ""; position: absolute; left: -25%; right: -25%; bottom: 0; height: 65%;
  background:
    repeating-linear-gradient(to right,  rgba(var(--cyan-rgb), .18) 0 1px, transparent 1px 72px),
    repeating-linear-gradient(to bottom, rgba(var(--cyan-rgb), .18) 0 1px, transparent 1px 72px);
  transform: perspective(420px) rotateX(70deg);
  transform-origin: bottom center;
  -webkit-mask-image: linear-gradient(to top, #000 8%, rgba(0,0,0,.35) 45%, transparent 88%);
          mask-image: linear-gradient(to top, #000 8%, rgba(0,0,0,.35) 45%, transparent 88%);
  z-index: -1; pointer-events: none;
}
.grid-floor::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 65%; height: 140px;
  background: radial-gradient(60% 100% at 50% 100%, rgba(var(--cyan-rgb), .28), transparent 72%);
  z-index: -1; pointer-events: none;
}
.grid-floor > * { position: relative; z-index: 1; }

/* ==========================================================================
   9. STATS STRIP
   ========================================================================== */
/* No borders on either edge — this strip is bounded by tone, not by rules.

   The background ramp is doing more than decoration. #project's vignette bottoms
   out at rgba(0,0,0,.92) over --bg-void, so its last row of pixels is near pure
   black, while the page surface underneath is --bg-base (#0a0c12). Butting those
   together leaves a visible tonal step that reads as a line even with the border
   gone, so this starts at --bg-void and ramps to --bg-base over the top third to
   meet the section above continuously.

   Painting a background here is safe alongside .grid-floor: element backgrounds
   paint below negative z-index descendants, so the grid pseudo-elements still
   sit on top of the ramp. */
.stats {
  padding-block: var(--sp-8);
  background: linear-gradient(180deg, var(--bg-void) 0%, var(--bg-base) 34%);
}

/* NOTE: deliberate exception to the otherwise single-column mobile base.
   The stats strip starts as a 2-column grid (2x2) and widens to 4 columns at
   640px. Each stat is its own chamfered HUD capsule, so there are no thin
   vertical rules between cells any more: the capsule edges do that job. */
.stats__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }

/* ---- HUD capsule ----
   Same division of labour as .hud / .hud__plate: the chamfer and the visible
   edge live on decorative layers, while the ambient halo stays on the unclipped
   host, because clip-path trims an outer box-shadow along with the corners.
   isolation:isolate keeps the z-index:-1 layers above the section background
   instead of dropping them behind the grid floor. */
.stat {
  position: relative; isolation: isolate;
  padding: var(--sp-5) var(--sp-3);
  text-align: center;
  box-shadow: 0 0 26px rgba(var(--cyan-rgb), .07);
}
/* Layer 1 — the edge: a light sheet clipped to the full chamfer, brightest at
   the top. Deliberately not a border, which clip-path would leave unstroked
   along the four diagonals. */
.stat::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(var(--steel-rgb), .42) 0%,
    rgba(var(--steel-rgb), .16) 45%,
    rgba(var(--steel-rgb), .06) 100%);
  clip-path: polygon(14px 0, calc(100% - 14px) 0, 100% 14px, 100% calc(100% - 14px),
                     calc(100% - 14px) 100%, 14px 100%, 0 calc(100% - 14px), 0 14px);
}
/* Layer 2 — the body, sitting 1px inside the same shape so exactly one pixel of
   layer 1 shows all the way round, chamfers included. The first two background
   layers are the bright hairline and its falloff along the top inside edge. */
.stat::after {
  content: ""; position: absolute; inset: 1px; z-index: -1; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(var(--steel-rgb), .30) 0 1px, transparent 1px),
    linear-gradient(180deg, rgba(var(--steel-rgb), .07), transparent 14px),
    linear-gradient(180deg, var(--surface-2) 0%, var(--surface-1) 100%);
  clip-path: polygon(13px 0, calc(100% - 13px) 0, 100% 13px, 100% calc(100% - 13px),
                     calc(100% - 13px) 100%, 13px 100%, 0 calc(100% - 13px), 0 13px);
}
.stat__label {
  margin: 0 0 var(--sp-2); font-size: var(--fs-100);
  letter-spacing: var(--track-wide); text-transform: uppercase; color: var(--text-muted);
}
.stat__value {
  margin: 0; font-size: var(--fs-600); font-weight: 800; line-height: 1;
  color: var(--text-strong); text-shadow: 0 0 24px rgba(var(--cyan-rgb), .25);
}

/* ==========================================================================
   10. FOOTER
   ========================================================================== */
/* No border-top. Separation from the stats strip is carried by the extra 32px
   of top padding (--sp-9 rather than --sp-8) plus the background ramp, which is
   enough to read the boundary without drawing a rule across it. */
.site-footer {
  padding-block: var(--sp-9) var(--sp-5);
  background: linear-gradient(180deg, var(--bg-base), var(--bg-void));
}
/* The three-part row is now the body of one wide HUD panel. The halo lives here
   on the unclipped host; the chamfered frame is .footer__plate behind it.
   isolation:isolate is what lets that plate use z-index:-1 without falling
   behind the footer's own background. */
.footer__grid {
  display: grid; gap: var(--sp-6); justify-items: center; text-align: center;
  padding: var(--sp-6) var(--sp-5);
  isolation: isolate;
  box-shadow: 0 0 40px rgba(var(--cyan-rgb), .08);
}
/* Decorative frame layer, the same arrangement as .hud__plate on the video
   player: content and focus rings sit outside the clip entirely. The visible
   outer edge is this cyan sheet with the fill inset 1px on top of it, rather
   than a border, so the chamfer diagonals are stroked like the straights. */
.footer__plate {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(var(--cyan-rgb), .34) 0%,
    rgba(var(--cyan-rgb), .16) 55%,
    rgba(var(--cyan-rgb), .10) 100%);
  clip-path: polygon(16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px),
                     calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px);
}
.footer__plate::before {
  content: ""; position: absolute; inset: 1px;
  background: var(--bg-void);
  background: color-mix(in srgb, var(--bg-void) 82%, transparent);
  box-shadow: inset 0 0 60px rgba(0, 0, 0, .5);
  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 15px),
                     calc(100% - 15px) 100%, 15px 100%, 0 calc(100% - 15px), 0 15px);
}
/* Inner hairline, offset a few px in, so the frame reads as a double one —
   the same trick as .hud__plate::after. */
.footer__plate::after {
  content: ""; position: absolute; inset: 6px;
  border: 1px solid rgba(var(--cyan-rgb), .18);
}
.footer__brand { display: inline-block; text-decoration: none; }
.footer__contact p { margin: 0 0 var(--sp-2); }
/* Magenta reply address: the one warm accent in an otherwise cyan frame. */
.footer__contact .link {
  color: var(--magenta);
  text-decoration-color: rgba(var(--magenta-rgb), .45);
}
.footer__phones { color: var(--text-muted); font-family: var(--font-mono); font-size: var(--fs-200); }
.socials { display: flex; gap: var(--sp-3); list-style: none; margin: 0; padding: 0; }
/* Chamfered squares, same bevel language as the stats capsules and at the same
   44px touch target as the circles they replace. Edge and body are layers for
   the usual reason; the hover halo stays on the unclipped anchor. */
.social {
  position: relative; isolation: isolate;
  display: grid; place-items: center; width: 44px; height: 44px;
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.social::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: rgba(var(--steel-rgb), .34);
  clip-path: polygon(10px 0, calc(100% - 10px) 0, 100% 10px, 100% calc(100% - 10px),
                     calc(100% - 10px) 100%, 10px 100%, 0 calc(100% - 10px), 0 10px);
  transition: background-color var(--dur-fast) var(--ease);
}
.social::after {
  content: ""; position: absolute; inset: 1px; z-index: -1; pointer-events: none;
  background:
    linear-gradient(180deg, rgba(var(--steel-rgb), .22) 0 1px, transparent 1px),
    linear-gradient(180deg, var(--surface-2), var(--surface-1));
  clip-path: polygon(9px 0, calc(100% - 9px) 0, 100% 9px, 100% calc(100% - 9px),
                     calc(100% - 9px) 100%, 9px 100%, 0 calc(100% - 9px), 0 9px);
}
.social:hover, .social:focus-visible { color: var(--cyan); box-shadow: var(--glow-cyan); }
.social:hover::before, .social:focus-visible::before { background: rgba(var(--cyan-rgb), .85); }
.social svg { width: 20px; height: 20px; fill: currentColor; }
.link {
  color: var(--cyan);
  text-decoration-color: rgba(var(--cyan-rgb), .45);
  text-underline-offset: 3px;
}
.footer__legal {
  margin: var(--sp-7) 0 0; text-align: center;
  font-size: var(--fs-200); color: var(--text-muted);
}

/* ==========================================================================
   11. RESPONSIVE — mobile first, min-width only
   ========================================================================== */
@media (min-width: 640px) {
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero__cabinet { width: min(100%, 295px); }
  .games, .videos { padding-block: var(--sp-9); }
  .stats { padding-block: var(--sp-9); }

  /* Four capsules across. The gap stays as authored in the base rule now that
     each stat is a discrete object rather than a cell in a ruled strip. */
  .stats__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 900px) {
  .nav__brand { order: 1; }
  .nav__links { order: 2; flex-basis: auto; flex: 1; }
  .btn--pill  { order: 3; }

  .hero__inner { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); align-items: center; }
  .hero__cabinet { justify-self: end; width: min(100%, 380px); }

  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .footer__grid { grid-template-columns: auto 1fr auto; align-items: center; }
  .footer__brand { justify-self: start; }
  .socials { justify-self: end; }
}

/* ==========================================================================
   12. REDUCED MOTION — interpolation removed, state changes still instant
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .card:hover, .card:focus-within { transform: none; }
  .btn:hover .btn__arrow { transform: none; }
}

/* ==========================================================================
   13. ORNAMENTS — corner brackets, circuit traces, deep-space backdrop,
       footer trim, and the widened video layout.
       Loaded last on purpose: .project__sky has to beat `.grid-floor > *`,
       which shares its specificity.
   ========================================================================== */

/* ---- 13.1 Corner brackets: one element, eight background slices ----
   Four L shapes with 22px arms and 2px stroke. Used by the video HUD and, at
   low opacity, by the footer's inner container. */
.brackets {
  position: absolute; inset: -3px;
  pointer-events: none;
  filter: drop-shadow(0 0 6px rgba(var(--cyan-rgb), .5));
  background-repeat: no-repeat;
  background-image:
    linear-gradient(var(--cyan), var(--cyan)), linear-gradient(var(--cyan), var(--cyan)),
    linear-gradient(var(--cyan), var(--cyan)), linear-gradient(var(--cyan), var(--cyan)),
    linear-gradient(var(--cyan), var(--cyan)), linear-gradient(var(--cyan), var(--cyan)),
    linear-gradient(var(--cyan), var(--cyan)), linear-gradient(var(--cyan), var(--cyan));
  background-size: 22px 2px, 2px 22px, 22px 2px, 2px 22px,
                   22px 2px, 2px 22px, 22px 2px, 2px 22px;
  background-position:
    0 0,       0 0,          /* top-left    */
    100% 0,    100% 0,       /* top-right   */
    0 100%,    0 100%,       /* bottom-left */
    100% 100%, 100% 100%;    /* bottom-right */
}
.brackets--soft {
  inset: calc(var(--sp-5) * -1);
  opacity: .26;
  filter: none;
}

/* ---- 13.2 Circuit traces: desktop only, never painted on mobile ---- */
.circuit { display: none; }

/* ---- 13.3 Deep space behind THE ARCADE PROJECT ----
   The atmosphere layer of the chamber: z-index -3 puts it under the .chamber
   SVG at -2 and the horizon band at -1. The nebula is pushed out to the two
   outer edges so the middle of the box stays dark and the grid reads clean over
   it. The vignette is first in the stack, i.e. painted on top of the nebula and
   the stars, which closes the chamber off at the top and bottom. Body copy sits
   on near-black plus a low-alpha glow, so contrast holds. */
.project__sky {
  position: absolute; inset: 0; z-index: -3; pointer-events: none;
  background-color: var(--bg-void);
  background-repeat: no-repeat;
  background-image:
    /* vignette — top of the stack. Softer than a straight crop: the top and
       bottom still close off hard, but the middle band is left almost fully
       open so the nebula below survives instead of being flattened to black. */
    linear-gradient(180deg,
      rgba(0, 0, 0, .92) 0%, rgba(0, 0, 0, .40) 16%, transparent 34%,
      transparent 66%, rgba(0, 0, 0, .40) 84%, rgba(0, 0, 0, .92) 100%),
    /* Bright flare points: the two objects in the field that read as discrete
       light sources rather than haze. */
    radial-gradient(4px 4px at 84% 62%, rgba(var(--magenta-rgb), .95), transparent 100%),
    radial-gradient(46px 46px at 84% 62%, rgba(var(--magenta-rgb), .22), transparent 72%),
    radial-gradient(3px 3px at 17% 27%, rgba(var(--cyan-rgb), .90), transparent 100%),
    radial-gradient(38px 38px at 17% 27%, rgba(var(--cyan-rgb), .18), transparent 72%),
    /* nebula — outer lobes, brightened and pulled further into frame */
    radial-gradient(40% 60% at 6%  30%, rgba(var(--magenta-rgb), .32), transparent 72%),
    radial-gradient(36% 54% at 12% 80%, rgba(var(--violet-rgb),  .26), transparent 74%),
    radial-gradient(40% 60% at 94% 28%, rgba(var(--cyan-rgb),    .28), transparent 72%),
    radial-gradient(36% 56% at 89% 76%, rgba(var(--magenta-rgb), .26), transparent 74%),
    /* nebula — mid-field lobes bridging the outer lobes to the centre, so the
       field reads continuous instead of two glows bolted to the edges */
    radial-gradient(34% 48% at 28% 14%, rgba(var(--violet-rgb),  .22), transparent 74%),
    radial-gradient(32% 44% at 72% 88%, rgba(var(--violet-rgb),  .20), transparent 74%),
    radial-gradient(30% 40% at 66% 12%, rgba(var(--cyan-rgb),    .14), transparent 76%),
    radial-gradient(30% 42% at 34% 90%, rgba(var(--magenta-rgb), .16), transparent 76%),
    /* deep base wash across the whole box: lifts the void off pure black so the
       starfield has something to sit in */
    radial-gradient(96% 78% at 50% 50%, rgba(var(--violet-rgb), .16), transparent 78%),
    /* starfield — infill pass. Deliberately dim and small: these exist to close
       the gaps in the original scatter so the field reads as dust rather than a
       countable set of dots. Kept as a separate batch to stay legible. */
    radial-gradient(1.2px 1.2px at 2%  36%, rgba(var(--steel-rgb), .40), transparent 100%),
    radial-gradient(1.1px 1.1px at 9%  84%, rgba(var(--violet-rgb), .55), transparent 100%),
    radial-gradient(1.3px 1.3px at 13% 51%, rgba(var(--steel-rgb), .38), transparent 100%),
    radial-gradient(1.1px 1.1px at 21% 33%, rgba(var(--steel-rgb), .34), transparent 100%),
    radial-gradient(1.2px 1.2px at 25% 76%, rgba(var(--violet-rgb), .48), transparent 100%),
    radial-gradient(1.1px 1.1px at 33% 22%, rgba(var(--steel-rgb), .32), transparent 100%),
    radial-gradient(1.3px 1.3px at 37% 58%, rgba(var(--steel-rgb), .36), transparent 100%),
    radial-gradient(1.1px 1.1px at 49% 12%, rgba(var(--violet-rgb), .42), transparent 100%),
    radial-gradient(1.2px 1.2px at 53% 88%, rgba(var(--steel-rgb), .34), transparent 100%),
    radial-gradient(1.1px 1.1px at 61% 29%, rgba(var(--steel-rgb), .30), transparent 100%),
    radial-gradient(1.3px 1.3px at 68% 68%, rgba(var(--violet-rgb), .46), transparent 100%),
    radial-gradient(1.1px 1.1px at 76% 24%, rgba(var(--steel-rgb), .34), transparent 100%),
    radial-gradient(1.2px 1.2px at 83% 75%, rgba(var(--steel-rgb), .32), transparent 100%),
    radial-gradient(1.1px 1.1px at 90% 42%, rgba(var(--violet-rgb), .44), transparent 100%),
    radial-gradient(1.2px 1.2px at 96% 15%, rgba(var(--steel-rgb), .36), transparent 100%),
    radial-gradient(1.1px 1.1px at 99% 68%, rgba(var(--steel-rgb), .30), transparent 100%),
    /* starfield */
    radial-gradient(1.6px 1.6px at 4%   9%, rgba(var(--steel-rgb), .80), transparent 100%),
    radial-gradient(1.3px 1.3px at 6%  60%, rgba(var(--steel-rgb), .50), transparent 100%),
    radial-gradient(1.1px 1.1px at 8%  44%, rgba(var(--steel-rgb), .45), transparent 100%),
    radial-gradient(1.7px 1.7px at 11% 72%, rgba(var(--cyan-rgb),  .55), transparent 100%),
    radial-gradient(1.2px 1.2px at 15% 21%, rgba(var(--steel-rgb), .60), transparent 100%),
    radial-gradient(1.4px 1.4px at 19% 88%, rgba(var(--steel-rgb), .50), transparent 100%),
    radial-gradient(1.1px 1.1px at 23% 55%, rgba(var(--magenta-rgb), .55), transparent 100%),
    radial-gradient(1.8px 1.8px at 27% 13%, rgba(var(--steel-rgb), .75), transparent 100%),
    radial-gradient(1.2px 1.2px at 31% 66%, rgba(var(--steel-rgb), .40), transparent 100%),
    radial-gradient(1.5px 1.5px at 35% 34%, rgba(var(--cyan-rgb),  .60), transparent 100%),
    radial-gradient(1.1px 1.1px at 39% 92%, rgba(var(--steel-rgb), .45), transparent 100%),
    radial-gradient(1.4px 1.4px at 43%  7%, rgba(var(--steel-rgb), .65), transparent 100%),
    radial-gradient(1.1px 1.1px at 44% 49%, rgba(var(--steel-rgb), .30), transparent 100%),
    radial-gradient(1.2px 1.2px at 47% 78%, rgba(var(--magenta-rgb), .45), transparent 100%),
    radial-gradient(1.1px 1.1px at 51% 27%, rgba(var(--steel-rgb), .35), transparent 100%),
    radial-gradient(1.6px 1.6px at 55% 61%, rgba(var(--steel-rgb), .55), transparent 100%),
    radial-gradient(1.2px 1.2px at 58% 16%, rgba(var(--cyan-rgb),  .50), transparent 100%),
    radial-gradient(1.7px 1.7px at 62% 84%, rgba(var(--magenta-rgb), .55), transparent 100%),
    radial-gradient(1.1px 1.1px at 66% 41%, rgba(var(--steel-rgb), .40), transparent 100%),
    radial-gradient(1.4px 1.4px at 70% 71%, rgba(var(--steel-rgb), .60), transparent 100%),
    radial-gradient(1.5px 1.5px at 74% 11%, rgba(var(--steel-rgb), .70), transparent 100%),
    radial-gradient(1.1px 1.1px at 78% 52%, rgba(var(--cyan-rgb),  .45), transparent 100%),
    radial-gradient(1.2px 1.2px at 81% 90%, rgba(var(--steel-rgb), .50), transparent 100%),
    radial-gradient(1.6px 1.6px at 85% 31%, rgba(var(--steel-rgb), .65), transparent 100%),
    radial-gradient(1.1px 1.1px at 88% 63%, rgba(var(--magenta-rgb), .50), transparent 100%),
    radial-gradient(1.3px 1.3px at 91% 18%, rgba(var(--steel-rgb), .55), transparent 100%),
    radial-gradient(1.5px 1.5px at 94% 79%, rgba(var(--steel-rgb), .60), transparent 100%),
    radial-gradient(1.1px 1.1px at 97% 47%, rgba(var(--steel-rgb), .40), transparent 100%);
}

.neon-divider {
  display: block; width: 96px; height: 2px;
  margin: 0 auto var(--sp-5);
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--cyan), var(--magenta));
  box-shadow: var(--glow-cyan);
}

/* ---- 13.4 Footer trim ----
   position:relative is load-bearing: .circuit--footer anchors to it. */
.site-footer { position: relative; }
.footer__grid { position: relative; }

/* ---- 13.5 Desktop layout for the ornaments and the player ---- */
@media (min-width: 900px) {
  /* Anchored to the shell's outer edge and running inward, so the trace lives in
     the gutter and the faded outer end is what crosses the viewport edge. */
  .circuit {
    display: block; position: absolute; top: var(--sp-9);
    width: 240px; height: 120px;
    pointer-events: none;
    filter: drop-shadow(0 0 6px rgba(var(--cyan-rgb), .35));
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 55%);
            mask-image: linear-gradient(to right, transparent 0%, #000 55%);
  }
  .circuit--left  { right: calc(50% + min(50% - var(--gutter), var(--shell) / 2)); }
  .circuit--right { left:  calc(50% + min(50% - var(--gutter), var(--shell) / 2));
                    transform: scaleX(-1); }
  .circuit--footer { top: auto; bottom: var(--sp-7); }

  .vplayer {
    grid-template-columns: clamp(200px, 22%, 240px) minmax(0, 1fr);
    gap: var(--sp-6);
    align-items: start;
  }
  .playlist { flex-direction: column; }
  .ptab { flex: 0 0 auto; width: 100%; }
}

/* ==========================================================================
   14. PROJECT PAGE — HERO
       Only used by project-*.html. Nothing above this point depends on it.
   ========================================================================== */
/* Copy left, render right, same as the home hero. overflow:hidden contains the
   over-wide sky glows; isolation:isolate keeps the negative-z backdrop layers
   above the section box instead of behind the page. */
.phero {
  position: relative; overflow: hidden; isolation: isolate;
  padding-block: var(--sp-7) var(--sp-8);
}
.phero__backdrop { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.phero__inner { position: relative; z-index: 1; display: grid; gap: var(--sp-6); }

/* Deep space, built the same way as .project__sky but wider and warmer toward
   the right, where the render sits. The base wash lifts the void off pure black
   so the nebula lobes have something to sit in. */
.phero__sky {
  position: absolute; inset: 0;
  background-color: var(--bg-void);
  background-image:
    radial-gradient(42% 58% at 6%  22%, rgba(var(--violet-rgb),  .30), transparent 74%),
    radial-gradient(38% 52% at 16% 82%, rgba(var(--magenta-rgb), .22), transparent 74%),
    radial-gradient(46% 62% at 88% 30%, rgba(var(--violet-rgb),  .32), transparent 72%),
    radial-gradient(40% 54% at 78% 86%, rgba(var(--cyan-rgb),    .18), transparent 74%),
    radial-gradient(34% 44% at 52% 10%, rgba(var(--cyan-rgb),    .12), transparent 76%),
    radial-gradient(96% 80% at 50% 50%, rgba(var(--violet-rgb),  .14), transparent 78%),
    /* sparse starfield — deliberately dim, it is texture rather than detail */
    radial-gradient(1.6px 1.6px at 8%  16%, rgba(var(--steel-rgb), .70), transparent 100%),
    radial-gradient(1.2px 1.2px at 14% 62%, rgba(var(--steel-rgb), .45), transparent 100%),
    radial-gradient(1.4px 1.4px at 23% 34%, rgba(var(--cyan-rgb),  .50), transparent 100%),
    radial-gradient(1.1px 1.1px at 31% 84%, rgba(var(--steel-rgb), .40), transparent 100%),
    radial-gradient(1.5px 1.5px at 44% 24%, rgba(var(--steel-rgb), .55), transparent 100%),
    radial-gradient(1.2px 1.2px at 57% 70%, rgba(var(--violet-rgb), .55), transparent 100%),
    radial-gradient(1.3px 1.3px at 68% 18%, rgba(var(--steel-rgb), .48), transparent 100%),
    radial-gradient(1.1px 1.1px at 74% 56%, rgba(var(--magenta-rgb), .48), transparent 100%),
    radial-gradient(1.6px 1.6px at 86% 74%, rgba(var(--steel-rgb), .52), transparent 100%),
    radial-gradient(1.2px 1.2px at 94% 40%, rgba(var(--steel-rgb), .42), transparent 100%);
  background-repeat: no-repeat;
}

/* Closes the section off top and bottom so it meets the header and the next
   section without a tonal step. Kept off the middle so the sky survives. */
.phero__vignette {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(5, 6, 10, .88) 0%, rgba(5, 6, 10, .34) 14%, transparent 34%,
    transparent 68%, rgba(5, 6, 10, .40) 86%, rgba(5, 6, 10, .92) 100%);
}
.phero__grain {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: .06; mix-blend-mode: soft-light;
}

/* Same background-clip:text treatment as .wordmark on the home page, but on one
   element rather than a span per word: the gradient is clipped to the glyphs,
   and because that kills text-shadow the glow is rebuilt from a drop-shadow pair
   plus a blurred data-text duplicate in ::before.

   The title wraps naturally, so a long project name just runs onto a second
   line. Nothing here assumes a word count. */
.phero__title {
  position: relative;
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-600);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-mega);
  font-weight: 800;
  text-transform: uppercase;
  color: var(--steel);
  background-image: linear-gradient(100deg, #ffffff 0%, #e4eeff 46%, var(--violet) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  filter: drop-shadow(0 0 16px rgba(var(--cyan-rgb), .28))
          drop-shadow(0 0 40px rgba(var(--violet-rgb), .26));
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .phero__title { color: transparent; -webkit-text-fill-color: transparent; }
}
/* Wide bloom. A duplicate of the same string, blurred, sitting behind the
   clipped gradient layer. data-text on the h1 has to match its text content. */
.phero__title::before {
  content: attr(data-text);
  position: absolute; inset: 0;
  color: var(--violet);
  -webkit-text-fill-color: var(--violet);
  filter: blur(18px);
  opacity: .40;
  z-index: -1;
}

.phero__tag {
  margin: 0 0 var(--sp-6);
  font-family: var(--font-mono); font-size: var(--fs-200);
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--text-muted);
}

/* ---- Description panel ----
   Frosted glass: one warm-white wash over a blurred backdrop, with a lit white
   edge. --glow-steel carries the outer halo, and the inset top highlight is
   what makes the fill read as glass rather than flat translucency. */
.pdesc {
  position: relative;
  max-width: 60ch;
  padding: var(--sp-5);
  background: rgba(255, 246, 240, .22);
  -webkit-backdrop-filter: blur(10px) saturate(1.1);
          backdrop-filter: blur(10px) saturate(1.1);
  border: 1px solid rgba(var(--steel-rgb), .58);
  border-radius: var(--r-sm);
  box-shadow:
    var(--glow-steel),
    inset 0 1px 0 rgba(var(--steel-rgb), .22);
}
.pdesc__title {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-200); font-weight: 700;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--cyan);
}
.pdesc__body { margin: 0; color: var(--text-body); }

/* ---- Project render ----
   The glow lives on a blurred pseudo-element behind the image so it works with
   any transparent PNG and does not double up if the render ships its own bloom. */
.phero__art { position: relative; justify-self: center; width: min(100%, 560px); }
.phero__art::before {
  content: ""; position: absolute; inset: 4% -10% 10%;
  background:
    radial-gradient(54% 46% at 50% 34%, rgba(var(--cyan-rgb), .16), transparent 72%),
    radial-gradient(58% 50% at 50% 74%, rgba(var(--violet-rgb), .20), transparent 74%);
  filter: blur(30px);
  z-index: -1; pointer-events: none;
}
.phero__img {
  width: 100%; height: auto; display: block;
  border-radius: var(--r-md);
  filter: drop-shadow(0 18px 40px rgba(0, 0, 0, .55));
}

/* ==========================================================================
   15. PROJECT PAGE — SECTION HEAD + SEGMENTED CONTROL + VIDEO SHOWCASE
   ========================================================================== */
/* Title left, control right, and they stack below 640px. The title's own
   bottom margin is dropped here because the row owns the spacing. */
.sechead {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--sp-3) var(--sp-5);
  margin-bottom: var(--sp-6);
}
.sechead .section-title { margin-bottom: 0; }

.seg {
  display: inline-flex; gap: 2px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
}
.seg__btn {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  padding: var(--sp-2) var(--sp-4);
  font: 600 var(--fs-100)/1.1 var(--font-ui);
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--text-muted);
  background: transparent;
  border: 0; border-radius: var(--r-pill);
  transition: color var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
.seg__btn:hover { color: var(--steel); }
.seg__btn[aria-selected="true"] {
  color: var(--bg-void);
  background: linear-gradient(100deg, var(--cyan), #8fe6ff);
  box-shadow: 0 0 14px rgba(var(--cyan-rgb), .45);
}

/* Player and side rail. Single column until 900px, where the rail moves right. */
.vshow { display: grid; gap: var(--sp-5); }
.vside { display: grid; gap: var(--sp-4); align-content: start; }

/* ---- Side feature thumbs ----
   A button, not a link: it swaps the player above rather than navigating. The
   whole tile is the hit target, hence the reset on padding and border. */
.vthumb {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  display: block; position: relative; isolation: isolate;
  padding: 0; text-align: left;
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  overflow: hidden;
  transition: transform var(--dur-slow) var(--ease),
              border-color var(--dur-slow) var(--ease),
              box-shadow var(--dur-slow) var(--ease);
}
.vthumb:hover, .vthumb:focus-visible {
  transform: translateY(-3px);
  border-color: rgba(var(--cyan-rgb), .70);
  box-shadow: 0 0 20px rgba(var(--cyan-rgb), .26), 0 0 54px rgba(var(--cyan-rgb), .10);
}
/* Currently playing in the main frame. */
.vthumb[aria-pressed="true"] {
  border-color: rgba(var(--cyan-rgb), .85);
  box-shadow: var(--glow-cyan);
}
.vthumb__art { display: block; position: relative; aspect-ratio: 16 / 9; background: var(--bg-void); }
.vthumb__art svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.vthumb__meta {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--hairline);
}
.vthumb__badge {
  display: grid; place-items: center; flex: none;
  width: 22px; height: 22px;
  color: var(--cyan);
}
.vthumb__badge svg { width: 100%; height: 100%; fill: currentColor; }
.vthumb__label {
  font-size: var(--fs-200); font-weight: 600;
  letter-spacing: .04em; color: var(--text-strong);
}

/* ==========================================================================
   16. PROJECT PAGE — LINK GROUPS
   ========================================================================== */
.pvideos { padding-block: var(--sp-8); }
.plinks  { padding-block: var(--sp-8) var(--sp-9); }

.plink-grid { display: grid; gap: var(--sp-5); }

/* One accent per column, set inline on .plink-col the same way the home page
   cards do it, so nothing below is written per column. */
.plink-col {
  position: relative;
  padding: var(--sp-5) var(--sp-4);
  background: var(--surface-1);
  border: 1px solid rgba(var(--accent-rgb), .32);
  border-radius: var(--r-md);
  box-shadow: inset 0 0 34px rgba(0, 0, 0, .45);
}
.plink-col__title {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-200); font-weight: 700;
  letter-spacing: var(--track-wide); text-transform: uppercase;
  color: var(--accent);
}
.plink-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }

/* Icon, label, then a monospace type tag pinned right. The label is allowed to
   wrap to two lines; the tag never is, hence the flex:none pairing. */
.plink {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--sp-3);
  padding: var(--sp-3);
  text-decoration: none;
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  transition: background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-base) var(--ease),
              transform var(--dur-base) var(--ease);
}
.plink:hover, .plink:focus-visible {
  transform: translateX(2px);
  background: rgba(var(--accent-rgb), .08);
  border-color: rgba(var(--accent-rgb), .60);
  box-shadow: 0 0 16px rgba(var(--accent-rgb), .20);
}
/* fill:currentColor is for the solid symbols (ic-x, ic-twitch), which carry no
   fill attribute of their own. The outlined ones declare fill="none"
   stroke="currentColor" on the <symbol>, and that beats this rule inside their
   own subtree, so one declaration covers both kinds. */
.plink__ic {
  width: 20px; height: 20px;
  color: var(--accent);
  fill: currentColor;
}
.plink__text {
  font-size: var(--fs-200); line-height: var(--lh-snug);
  color: var(--text-body);
}
.plink:hover .plink__text, .plink:focus-visible .plink__text { color: var(--text-strong); }

/* Kept at --text-muted rather than the accent: four of these per column in an
   accent colour reads as four calls to action competing with the labels. */
.plink__ext {
  font-family: var(--font-mono); font-size: var(--fs-100);
  letter-spacing: .08em; color: var(--text-muted);
}

.plinks__back { margin: var(--sp-7) 0 0; text-align: center; }

/* ==========================================================================
   17. PROJECT PAGE — RESPONSIVE
       Breakpoints match the home page so both share the same rhythm.
   ========================================================================== */
@media (min-width: 640px) {
  .plink-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pvideos, .plinks { padding-block: var(--sp-9); }
}

@media (min-width: 900px) {
  .phero { padding-block: var(--sp-8) var(--sp-9); }
  .phero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: var(--sp-7);
    align-items: center;
  }
  .phero__art { justify-self: end; width: 100%; }

  /* Player takes the bulk; the rail is wide enough for a legible 16:9 thumb. */
  .vshow {
    grid-template-columns: minmax(0, 1fr) clamp(220px, 26%, 300px);
    gap: var(--sp-5);
    align-items: start;
  }

  .plink-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
