/* ============================================================================
   home.css — home page sections: hero, index rail, work, about, capabilities,
   craft, play, contact. Built on tokens.css + base.css.
   ========================================================================== */

/* ---------- Hero (editorial: meta rail + giant exact-fit name + section index) ---------- */
.hero {
  position: relative; overflow: hidden;
  min-height: 100vh;                          /* fallback for browsers without svh */
  min-height: calc(100svh - var(--nav-h));    /* fill the screen below the sticky nav */
  display: flex; flex-direction: column;
  padding-block: clamp(1rem, 2.5vw, 1.75rem) clamp(1.1rem, 2.8vw, 1.9rem);
  border-bottom: 1px solid var(--border-strong);
}
.hero__inner { position: relative; z-index: 1; flex: 1 1 auto; align-content: center; display: grid; grid-template-columns: 1fr; gap: clamp(1.1rem, 3vw, 1.8rem); }
@media (min-width: 960px) {
  .hero__inner { grid-template-columns: clamp(128px, 14vw, 190px) 1fr; gap: clamp(1.5rem, 2.5vw, 2.5rem); align-items: end; }
}
.hero__rail { display: flex; flex-direction: column; gap: 0.7rem; }
@media (min-width: 960px) { .hero__rail { border-right: 1px solid var(--border-strong); padding-right: clamp(0.9rem, 1.8vw, 1.4rem); padding-bottom: 0.5rem; } }
@media (max-width: 959px) { .hero__rail { flex-flow: row wrap; gap: 0.5rem 1.4rem; align-items: baseline; } }
.hero__rail-row { display: flex; flex-direction: column; gap: 1px; font-family: var(--font-sans); font-size: var(--fs-sm); color: var(--text-dim); }
.hero__rail-k { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-mute); }
.hero__rail-row a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--border-strong); transition: text-decoration-color var(--t); }
.hero__rail-row a:hover { text-decoration-color: var(--accent); }
.hero__rail .num { color: var(--text); }

.hero__main { min-width: 0; }
.hero__kicker { margin-bottom: clamp(0.7rem, 1.8vw, 1.1rem); }
/* The eyebrow's live dot is the o's partner in the arrival: it emits one expanding accent ring timed
   to peak exactly as the o lands (see hero-o-land), so the line above the name and the o resolve on
   the same beat. The dot keeps its perpetual live-ping (base.css) after; this ::after fires once. */
.hero__kicker .kicker__dot--live { position: relative; }
.hero__kicker .kicker__dot--live::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 100%; height: 100%;
  border-radius: var(--r-pill); border: 1.5px solid var(--live);
  transform: translate(-50%, -50%) scale(0.4); opacity: 0; pointer-events: none;
  animation: hero-dot-land 1s var(--ease-out) 0.78s 1 both;
}
@keyframes hero-dot-land {
  0%   { opacity: 0;    transform: translate(-50%, -50%) scale(0.4); }
  22%  { opacity: 0.85; }                                                  /* ~1.0s — fires as the o lands */
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(4.2); }
}
@media (prefers-reduced-motion: reduce) { .hero__kicker .kicker__dot--live::after { animation: none; opacity: 0; } }
.hero__name {
  margin: 0; color: var(--text); white-space: nowrap;
  font-family: var(--font-display); font-weight: var(--w-display); font-optical-sizing: none;
  font-size: clamp(2.4rem, 13vw, 96px);   /* CLS fallback (under the fitted size so "Samuel Jo" never clips pre-JS); JS fits it to the column */
  line-height: 0.9; letter-spacing: -0.03em;
}
/* The "o" in "Jo" is the second live orb — a glossy TORUS (so it reads as the letter) that shares the
   About SJ orb's whole toy: hover-tilt, press-glow, and the full click-to-pop → gravity → fling →
   drag-back-to-the-cutout physics (initHeroOrb, a self-contained cousin of initOrb so BOTH orbs can be
   loose at once). Lighting is FIXED; a faint sheen layer rotates so the ring reads as spinning without
   the light sliding. Sized in em so it tracks the JS-fitted name; box width ≤ the measured 'o' advance
   (0.551em) → the line never widens (no overflow/CLS). A real (visually-hidden) "o" keeps a11y/SEO. */
.hero__o {
  display: inline-block; position: relative; vertical-align: baseline;
  width: 0.55em; height: 0.52em;
}
/* the drop-back cutout — a small dashed ring nested on the o's spot while it's loose: the SJ orb's
   language (thin dashed, slow spin, soft accent glow) but sized in em so it hugs the orb instead of
   dwarfing it. It doubles as a reset button — the ring is clickable (initHeroOrb → snapHome) and
   labelled "reset"; dragging the orb back onto it also snaps home. ::after = the spinning, clickable
   ring; ::before = the static label (so it doesn't spin). */
.hero__o.is-loose::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 0.62em; height: 0.62em; border-radius: 50%;
  border: 1px dashed color-mix(in srgb, var(--accent) 46%, transparent);
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 10%, transparent) 0%, transparent 70%);
  transform: translate(-50%, -50%); opacity: 0.9;
  animation: hero-cutout-spin 20s linear infinite;
  transition: border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
  pointer-events: auto; cursor: pointer;
}
.hero__o.is-loose::before {
  content: "reset"; position: absolute; left: 50%; top: 50%;
  width: max-content; transform: translate(-50%, -50%); white-space: nowrap; text-align: center; line-height: 1.35;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 74%, var(--text-dim)); opacity: 0.95; pointer-events: none;
  transition: color 0.2s var(--ease-out);
}
.hero__o.is-loose:hover::after,
.hero__o.is-target::after {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.035em color-mix(in srgb, var(--accent) 14%, transparent), inset 0 0 0.14em color-mix(in srgb, var(--accent) 16%, transparent);
}
.hero__o.is-loose:hover::before,
.hero__o.is-target::before { color: var(--accent); }
@keyframes hero-cutout-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
.hero__o-orb {
  position: absolute; inset: 0; perspective: 6em;
  /* On load the o spins in (two decelerating turns), lands on its spot, then hops a couple of times
     ("lifts off the ground") before the perpetual float takes over — the float is delayed to start
     exactly as the landing settles, so the two hand off with no jump (both end/begin at translateY 0,
     rotate 0). The kicker's live dot rings on the same beat (hero-dot-land) so the two read as one
     choreographed arrival. */
  animation:
    hero-o-land 1.7s var(--ease-out) 0.18s both,
    hero-o-float 7s var(--ease-in-out) 2s infinite;
}
.hero__o-orb.is-loose {   /* popped out into the fixed clip-layer; JS sets width/height + transform */
  inset: auto; left: 0; top: 0; margin: 0;
  animation: none; touch-action: none; pointer-events: auto; will-change: transform; z-index: 1;
}
.hero__o-face {
  position: absolute; inset: 0; border-radius: 50%; cursor: pointer;
  -webkit-user-select: none; user-select: none;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--os, 1));
  filter: drop-shadow(0 0 0 transparent);
  transition: transform 0.18s var(--ease-out), filter 0.28s var(--ease-out);
  /* the SJ orb's glossy material, shaped like an actual serif "o": the counter is an UPRIGHT ELLIPSE
     (mask), so the ring is thick on the left/right and thin top/bottom — modulated like real type
     rather than a uniform donut. Body is accent-lit from the upper-left, with a shaded inner wall
     (hugging the elliptical counter) + base occlusion, and a bright accent rim on the top-outer edge. */
  background:
    radial-gradient(36% 44% at 50% 50%, rgba(0, 0, 0, 0.5) 84%, rgba(0, 0, 0, 0) 126%),
    radial-gradient(circle at 50% 120%, rgba(0, 0, 0, 0.48) 0%, rgba(0, 0, 0, 0) 46%),
    radial-gradient(circle at 35% 24%, color-mix(in srgb, var(--accent) 48%, var(--surface)) 0%, var(--surface-2) 46%, color-mix(in srgb, #000 18%, var(--surface)) 100%);
  border: 1px solid var(--border);
  box-shadow:
    inset 0 0.055em 0.085em -0.04em color-mix(in srgb, var(--accent) 62%, #fff),
    inset 0 -0.03em 0.055em -0.04em rgba(0, 0, 0, 0.42),
    0 0.05em 0.11em rgba(0, 0, 0, 0.32);
  -webkit-mask: radial-gradient(36% 44% at 50% 50%, transparent 0 86%, #000 100%);
          mask: radial-gradient(36% 44% at 50% 50%, transparent 0 86%, #000 100%);
}
/* fixed specular glint (the SJ orb's ::before) — the gloss that makes it read polished, not flat;
   the face's mask keeps it on the ring */
.hero__o-face::before {
  content: ""; position: absolute; left: 18%; top: 10%; width: 40%; height: 31%; border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, rgba(255, 255, 255, 0.56), rgba(255, 255, 255, 0) 68%);
  opacity: 0.68; pointer-events: none;
}
/* a faint sheen that slowly turns around the ring → a subtle sense of rotation; the light stays fixed */
.hero__o-spin {
  position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background: conic-gradient(from 0deg at 50% 50%, transparent 0deg, rgba(255, 255, 255, 0.1) 44deg, transparent 96deg, transparent 360deg);
  -webkit-mask: radial-gradient(36% 44% at 50% 50%, transparent 0 86%, #000 100%);
          mask: radial-gradient(36% 44% at 50% 50%, transparent 0 86%, #000 100%);
  animation: hero-o-turn 12s linear infinite;
}
.hero__o-ring {   /* thin accent ring just outside the torus — mirrors .about__shape .ring */
  position: absolute; inset: -1px; border-radius: 50%;
  border: 1px solid var(--accent); opacity: 0.24; pointer-events: none;
}
.hero__o-face:hover { --os: 1.05; }                    /* hover swells it, inviting the grab */
.hero__o-face.is-grabbed { --os: 0.94; filter: drop-shadow(0 0 0.13em color-mix(in srgb, var(--accent) 48%, transparent)); }  /* held: squish + accent glow */
.hero__o-face.is-squish { animation: hero-o-squish 0.32s var(--ease-out); }
@keyframes hero-o-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-0.03em); } }
@keyframes hero-o-turn { to { transform: rotate(360deg); } }
/* Landing entrance: spins in from just above (2 turns, decelerating), impacts its spot (~46% → the
   "beat" the kicker dot syncs to), lifts off in two decaying hops, then settles to rest so the float
   can take over. Impact/hop frames squash-and-stretch on the vertical axis for weight. Ends at
   translateY(0) rotate(0) scale(1) — identical to hero-o-float's 0% — so the handoff is seamless. */
@keyframes hero-o-land {
  0%   { opacity: 0; transform: translateY(-0.55em) rotate(-720deg) scale(0.5); }
  10%  { opacity: 1; }
  46%  { transform: translateY(0.02em)  rotate(0deg) scale(1.08, 0.9); }   /* impact — squash */
  60%  { transform: translateY(-0.26em) rotate(0deg) scale(0.95, 1.06); }  /* lift off — hop up + stretch */
  74%  { transform: translateY(0)       rotate(0deg) scale(1.05, 0.96); }  /* land — small squash */
  87%  { transform: translateY(-0.09em) rotate(0deg) scale(1); }           /* tiny second hop */
  100% { transform: translateY(0)       rotate(0deg) scale(1); }
}
@keyframes hero-o-squish { 0% { transform: scale(1.16, 0.86); } 55% { transform: scale(0.95, 1.05); } 100% { transform: scale(1, 1); } }
/* the hero orb's return button — stacked above the About orb's (double class beats the base
   .orb-reset's later `bottom`), so both orbs can be live with both buttons visible at once */
.orb-reset.orb-reset--hero { bottom: calc(clamp(1rem, 3.5vw, 1.7rem) + 3.15rem + env(safe-area-inset-bottom, 0px)); }
@media (prefers-reduced-motion: reduce) { .hero__o-orb, .hero__o-spin { animation: none; } .hero__o-face { transition: none; } .hero__o.is-loose::after { animation: none; } }
/* Discoverability pill — the shared "poke me" callout BOTH orbs use (JS: makeOrbHint). One base
   component; per-orb modifiers only change the anchoring. JS builds it only when the physics toy
   is live (never under reduced motion) and an actual poke retires it — hover just invites.
   Outer span owns anchoring/centering; inner span owns the reveal + the idle bob, so the two
   transforms never fight. On-accent text on the accent pill mirrors the primary button — legible
   in every theme. */
.orb-hint { position: absolute; z-index: 3; pointer-events: none; font-size: 0; line-height: 0; }   /* collapse the inherited display line-box so the pill centres on its anchor, not on a text baseline */
.orb-hint__inner {
  position: relative; display: inline-flex; align-items: center; white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; line-height: 1;
  color: var(--on-accent); background: var(--accent); padding: 0.42em 0.72em; border-radius: var(--r-pill);
  box-shadow: 0 4px 14px -5px color-mix(in srgb, var(--accent) 60%, transparent);
  opacity: 0; transform: translateX(-6px) scale(0.9); transform-origin: left center;
  transition: opacity 0.4s var(--ease-out), transform 0.5s var(--ease-spring);
}
.orb-hint.is-shown .orb-hint__inner { opacity: 1; transform: none; animation: orb-hint-bob-x 2.4s var(--ease-in-out) 0.6s infinite; }
.orb-hint__tail { position: absolute; width: 0; height: 0; border: 5px solid transparent; }
@keyframes orb-hint-bob-x { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } }
@keyframes orb-hint-bob-y { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(3px); } }
/* hero "o": to the right of the letter (open space), tail pointing back at it */
.orb-hint--o { left: calc(100% + 0.6rem); top: 50%; transform: translateY(-50%); }
.orb-hint--o .orb-hint__tail { right: 100%; top: 50%; border-right-color: var(--accent); transform: translateY(-50%); margin-right: -1px; }
/* phones: the o sits at the right edge → drop the callout just beneath it, right-aligned, tail on top */
@media (max-width: 600px) {
  .orb-hint--o { left: auto; right: -0.15rem; top: calc(100% + 0.5rem); transform: none; }
  .orb-hint--o .orb-hint__inner { transform: translateY(-6px) scale(0.9); transform-origin: top right; }
  .orb-hint--o.is-shown .orb-hint__inner { transform: none; animation: orb-hint-bob-y 2.4s var(--ease-in-out) 0.6s infinite; }
  .orb-hint--o .orb-hint__tail { right: 0.72rem; top: auto; bottom: 100%; border-right-color: transparent; border-bottom-color: var(--accent); transform: none; margin: 0 0 -1px 0; }
}
/* About SJ orb: a badge riding the sphere's lower edge — prose wraps the circle, so anything
   outside the float box would collide with text. No tail; it reads as a label on the ball. */
.orb-hint--sj { left: 50%; top: auto; bottom: 5%; transform: translateX(-50%); }
.orb-hint--sj .orb-hint__inner { transform: translateY(6px) scale(0.9); transform-origin: bottom center; }
.orb-hint--sj.is-shown .orb-hint__inner { transform: none; animation: orb-hint-bob-y 2.4s var(--ease-in-out) 0.6s infinite; }
.orb-hint--sj .orb-hint__tail { display: none; }
@media (prefers-reduced-motion: reduce) { .orb-hint.is-shown .orb-hint__inner { animation: none; } }
/* accent rule under the name — draws in from the centre on load; the accent peaks at the centre and
   fades symmetrically to transparent at both ends. Hover lifts it with a brighter accent + a soft glow. */
.hero__rule {
  height: clamp(2px, 0.3vw, 3px); width: min(100%, 40rem); margin-top: clamp(0.85rem, 2vw, 1.5rem);
  border-radius: 3px; transform-origin: center;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--accent) 40%, transparent) 25%,
    var(--accent) 50%,
    color-mix(in srgb, var(--accent) 40%, transparent) 75%,
    transparent 100%);
  transform: scaleX(0); opacity: 0;
  animation: hero-rule-in 1s var(--ease-out) 0.35s forwards;
  transition: filter 0.5s var(--ease-out);
}
@keyframes hero-rule-in { to { transform: scaleX(1); opacity: 1; } }
.hero__main:hover .hero__rule { filter: brightness(1.32) drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 42%, transparent)); }
@media (prefers-reduced-motion: reduce) { .hero__rule { animation: none; transform: scaleX(1); opacity: 1; transition: none; } }

.hero__statement { font-family: var(--font-display); font-weight: var(--w-display); font-optical-sizing: none; font-size: var(--fs-2xl); line-height: 1.16; letter-spacing: -0.01em; color: var(--text-dim); max-width: 30ch; text-wrap: balance; margin-top: clamp(0.9rem, 2.2vw, 1.4rem); }
.hero__statement em { font-style: italic; color: var(--accent); }
.hero__lead { margin-top: 0.9rem; max-width: 56ch; font-family: var(--font-sans); font-size: var(--fs-lg); line-height: 1.5; color: var(--text-dim); text-wrap: pretty; }
.hero__lead strong { color: var(--text); font-weight: var(--w-strong); }
.hero__actions { margin-top: clamp(1.1rem, 2.6vw, 1.6rem); display: flex; flex-wrap: wrap; gap: 0.8rem; }

/* Entrance: the masthead rises + fades in on load, one element at a time. `both` fill applies the
   hidden `from` state only while each element's delay runs; the base style stays visible, so if
   animations are unavailable nothing is left hidden. A dedicated reduced-motion guard below turns
   it off (the global reduce rule collapses animation duration but NOT the stagger delay). The rule
   under the name keeps its own draw-in (hero-rule-in), timed to land right after the name. */
@keyframes hero-rise { from { opacity: 0; transform: translateY(1.1rem); } to { opacity: 1; transform: none; } }
.hero__kicker, .hero__name, .hero__statement, .hero__lead, .hero__actions { animation: hero-rise 0.72s var(--ease-out) both; }
.hero__kicker    { animation-delay: 0.04s; }
.hero__name      { animation-delay: 0.12s; }
.hero__statement { animation-delay: 0.26s; }
.hero__lead      { animation-delay: 0.34s; }
.hero__actions   { animation-delay: 0.42s; }
/* Reduced-motion: kill the entrance outright. (The global reduce rule only collapses animation
   DURATION, not DELAY — with `both` fill the staggered elements would otherwise sit hidden through
   their delay. Same guard the hero rule uses.) */
@media (prefers-reduced-motion: reduce) {
  .hero__kicker, .hero__name, .hero__statement, .hero__lead, .hero__actions { animation: none; opacity: 1; transform: none; }
}

@media (max-height: 860px) {
  .hero__kicker { margin-bottom: 0.5rem; }
  .hero__statement { margin-top: 0.7rem; }
  .hero__lead { margin-top: 0.55rem; }
  .hero__actions { margin-top: 0.9rem; }
}
@media (max-width: 600px) {
  .hero__rail { display: none; }                        /* role + location already live in the kicker */
  /* Centre the masthead between the nav and the section rail: on today's tall phones a
     top-anchored block pooled a dead band under the CTAs — splitting the slack evenly
     reads composed at any height (on short phones there's little slack, so it still sits
     naturally high). */
  .hero__inner { align-content: center; padding-top: 0; padding-bottom: 0; }
  .hero__kicker { margin-bottom: clamp(0.9rem, 3.2vw, 1.2rem); }
  .hero__statement { margin-top: clamp(1.05rem, 4vw, 1.45rem); }
  .hero__lead { margin-top: clamp(0.85rem, 3vw, 1.1rem); }
  .hero__actions { margin-top: clamp(1.35rem, 5vw, 1.9rem); }
}
/* Very short phones (landscape / SE-class): tighten so the whole pitch still fits one clean screen. */
@media (max-width: 600px) and (max-height: 720px) {
  .hero__kicker { margin-bottom: 0.7rem; }
  .hero__statement { margin-top: 0.8rem; }
  .hero__lead { margin-top: 0.65rem; }
  .hero__actions { margin-top: 1rem; }
}

/* ---------- Section index — the hero's bottom "table of contents" strip ---------- */
.index-rail {
  display: flex; flex-wrap: wrap; gap: 0.2rem 1.6rem;
  margin-top: clamp(1.1rem, 3vw, 1.9rem);
  padding-top: clamp(0.75rem, 1.8vw, 1.05rem);
  border-top: 1px solid var(--border-strong);
}
.index-rail a {
  font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: 500; color: var(--text-dim);
  display: inline-flex; align-items: baseline; gap: 0.5em; padding-block: 0.2rem;
  position: relative; transition: color var(--t);
}
.index-rail__n { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-mute); transition: color var(--t); }
.index-rail a:hover { color: var(--text); }
.index-rail a:hover .index-rail__n, .index-rail a[aria-current="page"] .index-rail__n { color: var(--accent); }
.index-rail a[aria-current="page"] { color: var(--text); }
@media (max-width: 600px) {
  .index-rail {
    flex-wrap: nowrap; overflow-x: auto; gap: 1.3rem; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    --ml: 0px; --mr: 0px;   /* JS fades whichever edge still has items to swipe (initRailFade) */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--ml), #000 calc(100% - var(--mr)), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 var(--ml), #000 calc(100% - var(--mr)), transparent 100%);
  }
  .index-rail::-webkit-scrollbar { display: none; }
  .index-rail a { white-space: nowrap; }
}

/* ---------- Section headers (modern: hairline rule + mono index) ---------- */
.sec-head { margin-bottom: clamp(2rem, 5vw, 3rem); padding-top: clamp(0.9rem, 2vw, 1.3rem); border-top: 1px solid var(--border); }
.sec-head__meta { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-mute); letter-spacing: 0.12em; text-transform: uppercase; display: flex; align-items: center; gap: 0.7em; }
.sec-head__n { color: var(--proj-ink, var(--accent)); font-weight: 600; }
.sec-head__title { font-family: var(--font-display); font-size: var(--fs-3xl); font-weight: var(--w-display); max-width: 20ch; text-wrap: balance; margin-top: 0.55rem; letter-spacing: -0.03em; line-height: 1.04; }
.sec-head--center { text-align: center; }
.sec-head--center .sec-head__meta { justify-content: center; }
.sec-head--center .sec-head__title { margin-inline: auto; max-width: none; }

/* ---------- Subtle per-section backgrounds (full-bleed, CSS-only, behind content) ----------
   Each motif nods to the section's meaning; all kept very low-contrast so text stays clean. */
#work, #capabilities, #play, #contact { position: relative; isolation: isolate; }
#work::before, #capabilities::before, #play::before, #contact::before {
  content: ""; position: absolute; z-index: -1; inset-block: 0; left: 50%; width: 100vw; transform: translateX(-50%);
  pointer-events: none; background-repeat: no-repeat;
}
/* Work — a faint data-point matrix + an accent corner glow */
#work::before {
  background:
    radial-gradient(46% 55% at 90% 4%, color-mix(in srgb, var(--accent) 7%, transparent), transparent 70%),
    radial-gradient(var(--grid-line) 1px, transparent 1.6px) 0 0 / 24px 24px;
}
/* Capabilities — a faint engineering grid + glow */
#capabilities::before {
  background:
    radial-gradient(48% 58% at 86% 0%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 70%),
    repeating-linear-gradient(0deg, var(--grid-line) 0 1px, transparent 1px 30px),
    repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 30px);
}
/* Play — a real felt table; the full treatment lives with the Play section styles below */
/* Contact — a soft centered focus glow */
#contact::before {
  background: radial-gradient(50% 80% at 50% 28%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 72%);
}

/* ---------- Work: alternating feature rows, ruled like an editorial index ---------- */
.work-grid { display: flex; flex-direction: column; gap: clamp(2.5rem, 6vw, 4.5rem); }
.feature { display: grid; grid-template-columns: 1fr; gap: clamp(1.5rem, 4vw, 2.75rem); align-items: center; padding-top: clamp(1.5rem, 4vw, 2.5rem); border-top: 1px solid var(--border-strong); }
@media (min-width: 880px) {
  .feature { grid-template-columns: 1.04fr 0.96fr; gap: clamp(2.5rem, 5vw, 4.5rem); }
  .feature--flip .feature__media { order: 2; }
}
.feature__body { min-width: 0; }
.feature__meta { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.9rem; }
.feature__index { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--proj-ink, var(--accent)); letter-spacing: 0.1em; }
.feature__title { font-family: var(--font-display); font-weight: var(--w-display); font-size: clamp(2.1rem, 1.4rem + 3.4vw, 3.5rem); line-height: 1.0; letter-spacing: -0.035em; color: var(--text); }
.feature__role { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--proj-ink, var(--accent)); margin-top: 0.7rem; }
.feature__desc { margin-top: 1.1rem; font-size: var(--fs-lg); line-height: var(--lh-prose); color: var(--text-dim); max-width: 46ch; }
.feature__desc .count { color: var(--text); font-weight: 600; }
.feature__chips { margin-top: 1.2rem; }
.feature__actions { margin-top: 1.6rem; display: flex; flex-wrap: wrap; align-items: center; gap: 0.8rem 1.3rem; }

/* faux browser chrome — shows the live URL, opens the real site */
.browser { display: block; border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; background: var(--surface-2); box-shadow: var(--shadow-2); transition: transform var(--t) var(--ease-out), box-shadow var(--t), border-color var(--t); }
.browser:hover { transform: translateY(-5px); box-shadow: var(--shadow-3); border-color: var(--border-strong); }
.browser__bar { display: flex; align-items: center; gap: 10px; padding: 9px 12px; background: var(--surface); border-bottom: 1px solid var(--border); }
.browser__dots { display: inline-flex; gap: 6px; flex: none; }
.browser__dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--border-strong); }
.browser__url { flex: 1; min-width: 0; text-align: center; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-dim); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-pill); padding: 4px 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.browser__url .lock { color: var(--up); margin-right: 0.4em; }
.browser__go { flex: none; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--proj-ink, var(--accent)); opacity: 0; transition: opacity var(--t); }
.browser:hover .browser__go { opacity: 1; }
.browser__view { aspect-ratio: 16 / 10; background: var(--surface-2); position: relative; overflow: hidden; }
.browser__view img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.browser__view--fit img { object-fit: contain; object-position: center; }

/* facecard preview sits on its own table-felt dark */
.browser__view--fc { background: #0a140f; }
/* miztips preview adapts to the active theme */
.browser__view--mz { background: #c1b38c; }
.mz-shot--dark { display: none; }
:is([data-theme="forest"], [data-theme="indigo"]) .browser__view--mz { background: #0d1625; }
:is([data-theme="forest"], [data-theme="indigo"]) .mz-shot--luxe { display: none; }
:is([data-theme="forest"], [data-theme="indigo"]) .mz-shot--dark { display: block; }

/* ---------- Also shipped ---------- */
.more { margin-top: clamp(3.5rem, 8vw, 6rem); }
.more__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding-bottom: 0.9rem; border-bottom: 1px solid var(--border-strong); }
.more__title { font-family: var(--font-display); font-weight: var(--w-heading); font-size: var(--fs-xl); letter-spacing: -0.02em; }
.more__head .tlink { color: var(--text-dim); }
.more__list { display: grid; grid-template-columns: 1fr; }
@media (min-width: 760px) { .more__list { grid-template-columns: 1fr 1fr; column-gap: 2.5rem; } }
.more-item a { display: block; padding: 1.05rem 0.35rem; border-bottom: 1px solid var(--border); transition: background var(--t-fast); }
.more-item a:hover { background: var(--surface-2); }
.more-item__top { display: flex; align-items: baseline; gap: 0.7rem; }
.more-item__name { font-family: var(--font-display); font-weight: var(--w-heading); font-size: var(--fs-lg); color: var(--text); letter-spacing: -0.02em; }
.more-item__lang { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--proj-ink, var(--text-mute)); letter-spacing: 0.04em; }
.more-item__go { margin-left: auto; color: var(--text-mute); transition: transform var(--t) var(--ease), color var(--t); }
.more-item a:hover .more-item__go { color: var(--proj-ink, var(--accent)); transform: translate(2px, -2px); }
.more-item__desc { margin-top: 0.3rem; font-family: var(--font-sans); font-size: var(--fs-sm); color: var(--text-dim); line-height: 1.45; max-width: 46ch; }

/* ---------- About — prose wraps the interactive SJ monogram orb, then a fact grid ---------- */
.about__grid { display: block; }
.about__shape {
  float: right; shape-outside: circle(50%);
  width: clamp(150px, 28vw, 250px); aspect-ratio: 1;
  margin: 0.4rem 0 1rem 1.6rem; position: relative; perspective: 820px;
}
.about__orb { position: absolute; inset: 0; transform-style: preserve-3d; animation: about-float 7s ease-in-out infinite; }
@keyframes about-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
.about__orb-face {
  position: absolute; inset: 0; border-radius: 50%; display: grid; place-items: center;
  --lx: 36%; --ly: 26%; --sx: 50%; --sh-x: 0px;   /* light (--lx/--ly) + shadow side (--sx/--sh-x): JS tilts them with gravity while loose */
  /* lit sphere. Everything tilts together: the light rides up + opposite the lean, while the cast (--sx) and
     inset occlusion (--sh-x) follow the heavy SJ side — so highlight, shadow, cast and SJ read as one moving ball. */
  background:
    radial-gradient(circle at var(--sx) 118%, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 47%),
    radial-gradient(circle at var(--lx) var(--ly), color-mix(in srgb, var(--accent) 38%, var(--surface)) 0%, var(--surface-2) 48%, color-mix(in srgb, #000 26%, var(--surface)) 100%);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2), inset var(--sh-x) -15px 26px -12px rgba(0, 0, 0, 0.62), inset calc(-1 * var(--sh-x)) 12px 20px -14px color-mix(in srgb, var(--accent) 55%, #fff);
  transform-style: preserve-3d; transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--os, 1));
  filter: drop-shadow(0 0 0 rgba(0, 0, 0, 0)); transition: transform 0.18s var(--ease-out), filter 0.28s var(--ease-out); cursor: grab; -webkit-user-select: none; user-select: none;
}
.about__orb:not(.is-loose) .about__orb-face:hover { --os: 1.03; }   /* hover invites the grab */
.about__orb-face.is-grabbed { --os: 0.97; filter: drop-shadow(0 0 13px color-mix(in srgb, var(--accent) 48%, transparent)); }  /* held: a soft accent glow (no tilt yet) */
.about__orb-face:active { cursor: grabbing; }
.about__orb-face::before {   /* soft specular glint that tracks the light */
  content: ""; position: absolute; left: calc(var(--lx) - 17%); top: calc(var(--ly) - 15%); width: 42%; height: 34%; border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0) 66%);
  opacity: 0.55; pointer-events: none;
}
.about__shape .ring { position: absolute; inset: -1px; border-radius: 50%; border: 1px solid var(--proj, var(--accent)); opacity: 0.28; transform: translateZ(14px); }
.about__monogram { font-family: var(--font-display); font-weight: 360; font-size: clamp(3.2rem, 10vw, 6rem); color: var(--accent); letter-spacing: -0.04em; line-height: 1; transform: translateZ(30px); }
@media (prefers-reduced-motion: reduce) { .about__orb { animation: none; } .about__orb-face { transition: none; } }
@media (max-width: 600px) { .about__shape { width: clamp(116px, 33vw, 150px); margin: 0.3rem 0 0.7rem 1.2rem; } }
/* Physics toy: click the orb to pop it loose (gravity + wall-bounce), fling it, drag it back onto the dashed cutout to snap home. The cutout keeps the float box so the prose never reflows. */
.about__shape::after {
  content: ""; position: absolute; inset: -2%; border-radius: 50%;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 52%, transparent);
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 9%, transparent) 0%, transparent 72%);
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s var(--ease-out), border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
}
.about__shape.is-loose::after { opacity: 0.8; animation: cutout-spin 18s linear infinite; }
.about__shape.is-target::after { opacity: 1; border-color: var(--accent); box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 14%, transparent), inset 0 0 26px color-mix(in srgb, var(--accent) 16%, transparent); }
@keyframes cutout-spin { to { transform: rotate(360deg); } }
/* hint text centered in the cutout while the orb is loose */
.about__cue {
  position: absolute; inset: 0; display: grid; place-items: center; text-align: center; padding: 0 22%; line-height: 1.45;
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 72%, var(--text-dim));
  opacity: 0; pointer-events: none; transition: opacity 0.3s var(--ease-out), color 0.2s, transform 0.3s var(--ease-spring);
}
.about__shape.is-loose .about__cue { opacity: 0.9; }
.about__shape.is-target .about__cue { opacity: 1; color: var(--accent); transform: scale(1.08); }
.orb-layer { position: fixed; inset: 0; z-index: 400; overflow: hidden; pointer-events: none; }
.about__orb.is-loose {
  position: absolute; inset: auto; left: 0; top: 0; margin: 0;
  animation: none; cursor: grab; touch-action: none; pointer-events: auto; will-change: transform;
}
.about__orb.is-loose:active { cursor: grabbing; }
/* return-home button — appears only while the orb is loose (in case it's flung far or you scroll away) */
.orb-reset {
  position: fixed; left: 50%; bottom: calc(clamp(1rem, 3.5vw, 1.7rem) + env(safe-area-inset-bottom, 0px)); z-index: 401;
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text); background: color-mix(in srgb, var(--surface) 82%, transparent);
  border: 1px solid var(--border-strong); border-radius: var(--r-pill); padding: 0.55rem 0.95rem;
  cursor: pointer; opacity: 0; pointer-events: none; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transform: translateX(-50%) translateY(10px);
  transition: opacity 0.3s var(--ease-out), transform 0.35s var(--ease-spring), border-color 0.2s, background 0.2s;
}
.orb-reset.is-shown { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.orb-reset:hover { border-color: var(--accent); background: color-mix(in srgb, var(--surface) 94%, transparent); }
.orb-reset__i { font-size: 1.15em; line-height: 1; }
.about__orb-face.is-squish { animation: orb-squish 0.28s var(--ease-out); }
@keyframes orb-squish { 0% { transform: scale(1.18, 0.82); } 55% { transform: scale(0.94, 1.06); } 100% { transform: scale(1, 1); } }
.about__body { font-size: var(--fs-lg); line-height: var(--lh-prose); color: var(--text-dim); }
.about__body p + p { margin-top: 1.1rem; }
.about__body strong { color: var(--text); font-weight: var(--w-strong); }
.about__meta { margin-top: clamp(1.6rem, 4vw, 2.4rem); display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.about__fact { background: var(--surface); padding: 1.1rem 1.2rem; }
.about__fact dt { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-mute); }
.about__fact dd { margin-top: 0.35rem; font-family: var(--font-sans); font-size: var(--fs-sm); color: var(--text); font-weight: var(--w-strong); }
.about__fact dd .num { color: var(--accent); }

/* ---------- Capabilities ---------- */
.cap-feature {
  border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--surface);
  padding: clamp(1.6rem, 4vw, 2.6rem); margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
  position: relative; overflow: hidden;
}
/* the left accent line — where scroll-driven animations exist it DRAWS down in step with the
   panel's own progress through the viewport (pure CSS, compositor-driven); elsewhere it's the
   same static gradient as before */
.cap-feature::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: linear-gradient(var(--proj), transparent); transform-origin: top; }
@supports (animation-timeline: view()) {
  .cap-feature { view-timeline: --cap-view; }   /* named timeline on the panel — a view() on the pseudo itself doesn't re-sample reliably */
  .cap-feature::before { animation: cap-line-draw linear both; animation-timeline: --cap-view; animation-range: entry 10% cover 55%; }
}
@keyframes cap-line-draw { from { transform: scaleY(0); } to { transform: scaleY(1); } }
/* laser pulse — a hot core (accent → near-white → accent) that shoots down the line: once when
   the panel scroll-reveals (the touch/mobile moment), and again on every hover. transform +
   opacity only; the panel's overflow:hidden clips the exit. */
.cap-feature::after {
  content: ""; position: absolute; left: 0; top: 0; width: 3px; height: 30%;
  background: linear-gradient(180deg, transparent, var(--proj) 30%, color-mix(in srgb, var(--proj) 25%, #fff) 50%, var(--proj) 70%, transparent);
  box-shadow: 0 0 12px 1px color-mix(in srgb, var(--proj) 55%, transparent);
  opacity: 0; transform: translateY(-100%); pointer-events: none;
}
.cap-feature.is-in::after { animation: cap-laser 0.9s var(--ease-in-out) 0.3s; }
.cap-feature:hover::after { animation: cap-laser-hover 0.5s ease-in; }
/* duplicate keyframes on purpose: hover swaps to a different animation-name so it re-fires
   even though the reveal pulse already ran (same-name animations never restart) */
@keyframes cap-laser       { 0% { opacity: 0; transform: translateY(-100%); } 12% { opacity: 1; } 100% { opacity: 1; transform: translateY(340%); } }
@keyframes cap-laser-hover { 0% { opacity: 0; transform: translateY(-100%); } 12% { opacity: 1; } 100% { opacity: 1; transform: translateY(340%); } }
@media (prefers-reduced-motion: reduce) { .cap-feature::before, .cap-feature::after { animation: none !important; } }
.cap-feature__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.cap-feature__label { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: 0.16em; text-transform: uppercase; color: var(--proj-ink, var(--accent)); display: inline-flex; align-items: center; gap: 0.5em; }
.cap-feature__tag { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-mute); }
.cap-feature__lead { font-family: var(--font-display); font-weight: var(--w-heading); font-size: clamp(1.3rem, 1rem + 1.3vw, 1.85rem); line-height: 1.2; letter-spacing: -0.025em; color: var(--text); max-width: 34ch; margin-top: 0.9rem; text-wrap: balance; }
.cap-feature__lead em { font-style: italic; color: var(--proj-ink, var(--accent)); }
.cap-feature__chips { margin-top: 1.4rem; display: flex; flex-wrap: wrap; gap: 0.55rem; }
.cap-chip { font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: 500; color: var(--text-dim); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-pill); padding: 0.4rem 0.85rem; transition: border-color var(--t), color var(--t), transform var(--t-fast); }
.cap-chip:hover { color: var(--text); border-color: var(--proj, var(--accent)); transform: translateY(-2px); }
.cap-chip b { color: var(--proj-ink, var(--accent)); font-weight: 600; }

.skills-grid { display: grid; grid-template-columns: 1fr; gap: clamp(1.5rem, 4vw, 2.5rem); }
@media (min-width: 640px) { .skills-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .skills-grid { grid-template-columns: repeat(4, 1fr); } }
.skill-group__head { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-mute); padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; display: flex; justify-content: space-between; }
.skill-group__head .n { color: var(--proj-ink, var(--accent)); }
.skill-list li { font-family: var(--font-sans); font-size: var(--fs-sm); color: var(--text-dim); padding-block: 0.35rem; line-height: 1.4; }
.skill-list li b { color: var(--text); font-weight: 600; }

/* ---------- Contact sign-off seal ---------- */
.contact__seal { display: flex; justify-content: center; margin-bottom: clamp(1.6rem, 4vw, 2.4rem); }
.contact__seal .seal { width: clamp(104px, 17vw, 136px); animation: none; }

/* ---------- Spinning seal (core styles in base.css; home adds size + float) ---------- */
.seal { width: clamp(122px, 30vw, 150px); animation: seal-float 9s ease-in-out infinite; }
@keyframes seal-float { 0%, 100% { transform: translate(0, 0); } 25% { transform: translate(3px, -6px); } 50% { transform: translate(0, -9px); } 75% { transform: translate(-3px, -5px); } }
@media (prefers-reduced-motion: reduce) { .seal { animation: none; } }

/* ---------- Play — heads-up Texas Hold'em, dealt on an actual felt table ----------
   The section re-skins itself by scoping the design tokens: every component inside
   (headers, HUD, cards, buttons, links) reads the same variables, so ONE block turns
   the band into a casino table — cream ink, gold accents (chips & card backs), deeper
   shadows to seat the cards on the cloth. Works identically in all three themes via
   the per-theme --felt tokens. */
#play {
  color: var(--text);   /* re-resolve inherited ink in-scope — headings etc. inherit body's computed color otherwise */
  --text: #f4f2e7;
  --text-dim: color-mix(in srgb, #f4f2e7 82%, var(--felt));
  --text-mute: color-mix(in srgb, #f4f2e7 68%, var(--felt));   /* ≥4.5:1 on every theme's felt for the 11px mono labels */
  --border: color-mix(in srgb, #fff 14%, transparent);
  --border-strong: color-mix(in srgb, #fff 28%, transparent);
  --surface: color-mix(in srgb, #fff 7%, var(--felt));
  --surface-2: color-mix(in srgb, #fff 12%, var(--felt));
  --accent: #e0bc8c;          /* the house gold — chips, card backs, the deal button */
  --accent-strong: #eccfa3;
  --on-accent: #171208;
  --proj: var(--accent); --proj-ink: var(--accent-strong);
  --up: #7ddfa8; --down: #f79a89;
  --selection: rgba(224, 188, 140, 0.28);
  --shadow-2: 0 14px 30px rgba(0, 0, 0, 0.38);
  --shadow-3: 0 24px 52px rgba(0, 0, 0, 0.5);
}
/* The cloth itself — real baize, not flat paint. Four material layers (all static, inline SVG):
     1. fibre grain: soft-blurred light + dark speckle (the fuzz) + a faint horizontal brushed
        nap (long low-x-frequency streaks — the direction the cloth was combed)
     2. mottle: a handful of large soft gradient blotches (non-repeating, so no tile seams) —
        the organic large-scale shading real felt has that makes it read as cloth, not color —
        plus a faint gold BETTING LINE ellipse around the play area (the table's signature)
     3. an overhead-light sheen
     4. the felt body, vignetting into the shaded rail; inset cushion shadows seat the band. */
#play::before {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='a'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.16 0'/%3E%3C/filter%3E%3Cfilter id='b'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.6' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3C/filter%3E%3Cfilter id='c'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.00833 0.0875' numOctaves='1' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.06 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23a)'/%3E%3Crect width='240' height='240' filter='url(%23b)'/%3E%3Crect width='240' height='240' filter='url(%23c)'/%3E%3C/svg%3E") repeat left top / 240px 240px,
    radial-gradient(42% 34% at 18% 22%, rgba(0, 0, 0, 0.18), transparent 70%),
    radial-gradient(50% 40% at 82% 68%, rgba(0, 0, 0, 0.16), transparent 72%),
    radial-gradient(36% 30% at 62% 16%, rgba(0, 0, 0, 0.12), transparent 70%),
    radial-gradient(44% 36% at 33% 84%, rgba(0, 0, 0, 0.14), transparent 72%),
    radial-gradient(30% 26% at 93% 28%, rgba(255, 255, 255, 0.06), transparent 70%),
    radial-gradient(34% 28% at 7% 60%, rgba(255, 255, 255, 0.05), transparent 70%),
    radial-gradient(48% 34% at 50% 47%, transparent 96%, rgba(232, 203, 152, 0.16) 97.4%, rgba(232, 203, 152, 0.16) 98.8%, transparent 100%),
    radial-gradient(72% 54% at 50% 32%, rgba(255, 255, 255, 0.13), transparent 70%),
    radial-gradient(150% 130% at 50% 32%, var(--felt) 26%, color-mix(in srgb, var(--felt-deep) 82%, #000) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    inset 0 18px 34px -18px rgba(0, 0, 0, 0.55),
    inset 0 -18px 34px -18px rgba(0, 0, 0, 0.55);
}
.play { text-align: center; }
.play__lead { max-width: 52ch; margin: 0 auto; color: var(--text-dim); }
.play__hud { display: flex; gap: clamp(1.1rem, 4vw, 1.8rem); justify-content: center; align-items: baseline; margin-top: 1.5rem; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-mute); }
.play__stat b { font-family: var(--font-display); font-variant-numeric: tabular-nums; letter-spacing: 0; color: var(--text-dim); }
.play__stat:first-child b { font-size: 1.2rem; color: var(--proj-ink, var(--accent)); transition: color var(--t) var(--ease); }

/* the table: dealer (top) · board (middle) · you (bottom) */
.holdem { display: flex; flex-direction: column; align-items: center; gap: clamp(0.7rem, 2.4vw, 1.25rem); margin: clamp(1.4rem, 4vw, 2.3rem) auto 1.3rem; perspective: 1300px; }
.holdem__row { display: flex; flex-direction: column; align-items: center; gap: 0.45rem; }
.holdem__tag { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--text-mute); }
.holdem__row--board .holdem__tag { color: var(--proj-ink, var(--accent)); }
.holdem__seats { display: flex; justify-content: center; align-items: flex-start; gap: clamp(1.1rem, 6vw, 2.75rem); }
.holdem__seat { display: flex; flex-direction: column; align-items: center; gap: 0.45rem; }
.holdem__seats .pcard { width: clamp(38px, 9vw, 58px); }   /* opponents read as "across the table" */
.hcards { display: flex; justify-content: center; align-items: center; gap: clamp(5px, 1.5vw, 10px); min-height: clamp(67px, 15.4vw, 106px); }   /* center, don't stretch: keeps the smaller opponent cards at 5/7 */

/* live opponent action — "bets 5" / "calls" / "folds" under each seat; a fold mucks the cards */
.holdem__act { min-height: 1.15em; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-mute); transition: color var(--t), opacity var(--t); }
.holdem__act[data-act="in"] { color: var(--proj-ink, var(--accent)); }
.holdem__act[data-act="fold"] { opacity: 0.5; }
.holdem__seat .hcards { transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease), filter var(--t-slow) var(--ease); }
.holdem__seat.is-folded .hcards { opacity: 0.3; filter: grayscale(0.55); transform: translateY(8px) scale(0.94); }
.holdem__seat.is-folded .holdem__tag { opacity: 0.45; }

/* a card: a back that flips to its face when .in is added; .is-best lifts the winning five */
.pcard { width: clamp(48px, 11vw, 76px); aspect-ratio: 5 / 7; position: relative; transform-style: preserve-3d; transform: rotateY(0deg); transition: transform 0.55s var(--ease-spring), box-shadow var(--t); }
.pcard.in { transform: rotateY(180deg); }
.pcard.is-best { transform: rotateY(180deg) translateY(-7px); }
.pcard.is-best .pcard__face { box-shadow: 0 0 0 2px var(--proj, var(--accent)), var(--shadow-3); }
.pcard__side { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; border-radius: var(--r); border: 1px solid var(--border-strong); display: grid; place-items: center; box-shadow: var(--shadow-2); }
/* a REAL card back: woven diagonal lattice over a rich gold, with a thin inset frame line —
   reads as a printed deck instead of a flat swatch. All colors derive from the section tokens. */
.pcard__back {
  background:
    repeating-linear-gradient(45deg, color-mix(in srgb, var(--on-accent) 9%, transparent) 0 1.5px, transparent 1.5px 7px),
    repeating-linear-gradient(-45deg, color-mix(in srgb, var(--on-accent) 9%, transparent) 0 1.5px, transparent 1.5px 7px),
    linear-gradient(135deg, var(--accent-strong), var(--accent) 58%, color-mix(in srgb, var(--accent) 80%, var(--on-accent)));
}
.pcard__back::before { content: ""; position: absolute; inset: 5px; border-radius: calc(var(--r) - 4px); border: 1px solid color-mix(in srgb, var(--on-accent) 30%, transparent); }
.pcard__back::after { content: "◆"; color: var(--on-accent); opacity: 0.55; font-size: 1.3rem; }
.pcard__face { background: #fdfcf9; color: #16140f; transform: rotateY(180deg); flex-direction: column; font-family: var(--font-display); }
.pcard__face .rank { font-size: clamp(1.15rem, 4vw, 1.75rem); font-weight: 500; line-height: 1; }
.pcard__face .suit { font-size: clamp(0.9rem, 3.2vw, 1.35rem); line-height: 1; margin-top: 2px; }
.pcard.red .pcard__face { color: #b23a2e; }

.play__result { font-family: var(--font-display); font-weight: var(--w-heading); font-size: var(--fs-2xl); letter-spacing: -0.02em; min-height: 3rem; color: var(--text); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.15rem; }
.play__result .muted { color: var(--text-mute); font-size: var(--fs-base); }
.play__hands { font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: 500; color: var(--text-mute); letter-spacing: 0; }
.play__hands b { color: var(--text); font-weight: 600; }
.play__win { color: var(--up); font-family: var(--font-display); font-weight: 500; }
.play__lose { color: var(--down); font-family: var(--font-display); font-weight: 500; }
.play__actions { margin-top: 1.5rem; display: flex; justify-content: center; gap: 0.8rem; }
.play__hint { min-height: 1.2em; margin-top: 0.9rem; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-mute); letter-spacing: 0.05em; }
.play__note { margin-top: 1.1rem; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-mute); }
.play__note a { color: var(--text-dim); text-decoration: underline; text-underline-offset: 3px; }

/* ---------- Contact ---------- */
.contact { text-align: center; }
.contact__title { font-family: var(--font-display); font-size: var(--fs-display); font-weight: var(--w-display); line-height: 0.98; letter-spacing: -0.04em; margin-top: 1rem; }
.contact__title em { font-style: normal; color: var(--accent); }
.contact__lead { margin: 1.25rem auto 0; max-width: 42ch; color: var(--text-dim); font-size: var(--fs-lg); }
.contact__actions { margin-top: 2rem; display: flex; flex-wrap: wrap; gap: 0.8rem; justify-content: center; }
.contact__alt { margin-top: 1.75rem; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-mute); display: inline-flex; align-items: center; gap: 0.5em; width: 100%; justify-content: center; }
.contact__alt .kbd-inline { color: var(--text-dim); }
/* The ⌘K glyph hint is keyboard-only; on touch swap it for a tappable "search" affordance. */
.contact__alt--tap { display: none; font: inherit; color: var(--proj-ink, var(--accent)); text-decoration: underline; text-underline-offset: 3px; gap: 0.3em; }
@media (pointer: coarse) { .contact__alt--kbd { display: none; } .contact__alt--tap { display: inline-flex; align-items: center; } }
