/* ============================================================
   PORTFOLIO v2 — TWO WORLDS
   Surface: editorial/professional · Hidden: cyberpunk/playful
   ============================================================ */

/* ---------- TOKENS ---------- */
:root {
  /* Surface — Anthropic-leaning warm */
  --surface-bg: #F5F1EB;
  --surface-bg-2: #EDE7DC;
  --surface-ink: #1A1A1A;
  --surface-ink-dim: #5C5A55;
  --surface-ink-faint: #9A968D;
  --surface-line: rgba(26, 26, 26, 0.12);
  --surface-accent: #6d9078;
  --surface-display: 'Source Serif 4', 'Newsreader', Georgia, serif;
  --surface-sans: 'IBM Plex Sans', 'Söhne', -apple-system, sans-serif;
  --surface-mono: 'IBM Plex Mono', monospace;

  /* Hidden — Edgerunners cyberpunk */
  --hidden-bg: #0a0a0f;
  --hidden-bg-2: #11111a;
  --hidden-ink: #ece9ff;
  --hidden-ink-dim: #8a87a8;
  --hidden-ink-faint: #4a4860;
  --hidden-line: rgba(236, 233, 255, 0.08);
  --hidden-accent: #ff2e88;
  --hidden-accent2: #00f0ff;
  --hidden-mono: 'JetBrains Mono', 'IBM Plex Mono', monospace;
  --hidden-display: 'Space Grotesk', sans-serif;

  --bubble-r: 280px;
  --cx: 50vw;
  --cy: 50vh;

  --ease: cubic-bezier(.22, 1, .36, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { background: var(--surface-bg); overflow-x: hidden; }
body {
  font-family: var(--surface-sans);
  color: var(--surface-ink);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
body[data-fun="true"] { cursor: none; }
@media (max-width: 900px) { body[data-fun="true"] { cursor: auto; } }

a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
::selection { background: var(--surface-accent); color: var(--surface-bg); }

/* Spacers in the hidden layer that line up flip-band heights so mirrored
   sections (About, Contact) sit at the same Y as their surface peers. */
.bubble-spacer { width: 100%; }

/* ---------- LAYER STACK ---------- */
.world {
  position: absolute;
  inset: 0;
  width: 100%;
}

/* Surface is in normal flow so it provides scroll height */
.surface { position: relative; z-index: 1; }

/* Hidden is positioned over surface, height matched by JS, clipped to a circle around cursor */
.hidden {
  position: absolute;
  top: 0; left: 0; right: 0;
  overflow: hidden;
  z-index: 2;
  pointer-events: none;
  background: var(--hidden-bg);
  color: var(--hidden-ink);
  font-family: var(--hidden-mono);
  -webkit-clip-path: circle(var(--bubble-r) at var(--cx) var(--cy));
          clip-path: circle(var(--bubble-r) at var(--cx) var(--cy));
  transition: -webkit-clip-path 0.05s linear, clip-path 0.05s linear;
}

/* When user touches a hover-triggering element, bubble can grow */
.hidden.is-expanded {
  --bubble-r: 320px;
}

/* Collapse to nothing while over a flip-band so the lens doesn't block
   the section's own surface→hidden flip animation. */
.hidden.is-collapsed {
  -webkit-clip-path: circle(0 at var(--cx) var(--cy));
          clip-path: circle(0 at var(--cx) var(--cy));
  transition: -webkit-clip-path 0.25s var(--ease), clip-path 0.25s var(--ease);
}

/* Static cyberpunk grain + scanlines INSIDE the bubble only */
.hidden::before {
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom, transparent 0, transparent 2px, rgba(0,0,0,0.22) 2px, rgba(0,0,0,0.22) 3px);
  pointer-events: none;
  mix-blend-mode: multiply;
}
.hidden::after {
  content: "";
  position: absolute; inset: -50%;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.5 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.4'/></svg>");
  opacity: 0.08;
  pointer-events: none;
  mix-blend-mode: overlay;
  animation: bubble-grain 1s steps(4) infinite;
}
@keyframes bubble-grain {
  0% { transform: translate(0,0); }
  25% { transform: translate(-2%, 3%); }
  50% { transform: translate(2%, -2%); }
  75% { transform: translate(-1%, 1%); }
  100% { transform: translate(0,0); }
}

/* ---------- BUBBLE CURSOR (the lens itself) ---------- */
.bubble-cursor {
  position: fixed;
  top: 0; left: 0;
  width: calc(var(--bubble-r) * 2);
  height: calc(var(--bubble-r) * 2);
  margin-left: calc(var(--bubble-r) * -1);
  margin-top: calc(var(--bubble-r) * -1);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9998;
  transform: translate(var(--cx), var(--cy));
  border: 1px solid var(--hidden-accent);
  box-shadow:
    0 0 0 1px rgba(255, 46, 136, 0.12),
    0 0 40px rgba(255, 46, 136, 0.18),
    inset 0 0 30px rgba(0, 240, 255, 0.06);
  transition: width 0.35s var(--ease), height 0.35s var(--ease), margin 0.35s var(--ease), opacity 0.3s;
}
.bubble-cursor::before {
  /* crosshair tick */
  content: "";
  position: absolute;
  top: -8px; left: 50%; width: 1px; height: 8px;
  background: var(--hidden-accent);
}
.bubble-cursor::after {
  content: "";
  position: absolute;
  top: 50%; left: -8px; width: 8px; height: 1px;
  background: var(--hidden-accent);
}
.bubble-cursor[data-hidden="true"] { opacity: 0; }

/* Small fallback dot — visible while the bubble cursor is hidden so the
   user can still track where they are on flip-band sections. */
.bubble-dot {
  position: fixed;
  top: 0; left: 0;
  width: 8px; height: 8px;
  margin-left: -4px;
  margin-top: -4px;
  background: var(--hidden-accent);
  border-radius: 50%;
  box-shadow: 0 0 12px rgba(255, 46, 136, 0.7);
  pointer-events: none;
  z-index: 9999;
  transform: translate(var(--cx), var(--cy));
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}
.bubble-dot[data-shown="true"] { opacity: 1; }

/* HUD label that floats with the bubble */
.bubble-hud {
  position: fixed;
  top: 0; left: 0;
  transform: translate(calc(var(--cx) + var(--bubble-r) * 0.78), calc(var(--cy) - var(--bubble-r) * 0.78));
  pointer-events: none;
  z-index: 9999;
  font-family: var(--hidden-mono);
  font-size: 10px;
  letter-spacing: 0.15em;
  color: var(--hidden-accent);
  text-shadow: 0 0 8px rgba(255, 46, 136, 0.6);
  white-space: nowrap;
  transition: opacity 0.2s;
}
.bubble-hud .bubble-hud-line { display: block; }
.bubble-hud .bubble-hud-line--dim { color: var(--hidden-accent2); opacity: 0.7; font-size: 9px; }
.bubble-hud[data-hidden="true"] { opacity: 0; }

/* First-load hint */
.peek-hint {
  position: fixed;
  bottom: 32px; left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  display: flex; gap: 10px; align-items: center;
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--surface-ink-dim);
  background: var(--surface-bg);
  padding: 10px 16px;
  border: 1px solid var(--surface-line);
  border-radius: 999px;
  animation: hint-bob 2.4s ease-in-out infinite;
  transition: opacity 0.5s;
}
.peek-hint.is-faded { opacity: 0; pointer-events: none; }
.peek-hint .peek-dot {
  display: inline-block; width: 6px; height: 6px;
  background: var(--surface-accent); border-radius: 50%;
}
@keyframes hint-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50% { transform: translate(-50%, -4px); }
}

/* ============================================================
   SURFACE — editorial / professional
   ============================================================ */
.surface { padding-top: 80px; padding-bottom: 80px; }

/* Sticky nav band — lives ABOVE both worlds, has its own mini bubble */
/* Both navs share an identical 3-column grid — mark | links | cta — so
   their child link slots line up exactly under the bubble. */
.s-nav,
.h-nav-fixed {
  position: fixed; top: 0; left: 0; right: 0;
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr) 140px;
  align-items: center;
  padding: 18px 48px;
  height: 64px;
  z-index: 60;
}
.s-nav {
  background: rgba(245, 241, 235, 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--surface-line);
  font-family: var(--surface-sans);
  font-size: 14px;
  color: var(--surface-ink);
}
.h-nav-fixed {
  background: var(--hidden-bg);
  border-bottom: 1px solid var(--hidden-accent);
  z-index: 61;
  font-family: var(--hidden-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hidden-ink-dim);
  pointer-events: none;
  /* Mini bubble inside the nav only */
  -webkit-clip-path: circle(80px at var(--cx) 32px);
          clip-path: circle(80px at var(--cx) 32px);
}
@media (max-width: 800px) {
  .h-nav-fixed { padding: 14px 20px; }
}
.s-nav-mark {
  font-family: var(--surface-display);
  font-size: 18px; font-weight: 500; letter-spacing: -0.01em;
}
.s-nav-mark span { color: var(--surface-accent); }
.h-nav-fixed .h-nav-mark {
  color: var(--hidden-accent);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.08em;
  font-family: var(--hidden-mono);
}
/* Identical link-slot geometry: 6 equal columns, justified across the centre
   region of the nav grid. Both surface and hidden use the same template so
   each link sits at the same x-coordinate. Children fill their cell so the
   text-center is the cell-center regardless of label width. */
.s-nav-links,
.h-nav-fixed .h-nav-links {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0;
  align-items: center;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
}
.s-nav-links > *,
.h-nav-fixed .h-nav-links > * {
  width: 100%;
  text-align: center;
  white-space: nowrap;
}
/* Hidden nav labels are longer (Cool_Stuff, Brain_Dumps, etc) — shrink text
   so each fits within its 1fr grid cell without colliding with neighbours.
   Surface labels (Work, About) are short enough at 14px to fit. */
.h-nav-fixed .h-nav-links > * {
  font-size: 9px;
  letter-spacing: 0.04em;
}
.h-nav-fixed .h-nav-cta {
  justify-self: end;
  border: 1px solid var(--hidden-accent);
  color: var(--hidden-accent);
  padding: 7px 14px;
  font-size: 11px;
}
@media (max-width: 800px) {
  .h-nav-fixed .h-nav-links { display: none; }
}
.s-nav-links a { color: var(--surface-ink-dim); transition: color .2s; }
.s-nav-links a:hover { color: var(--surface-ink); }
.s-nav-cta {
  justify-self: end;
  border: 1px solid var(--surface-ink);
  padding: 8px 16px;
  border-radius: 999px;
  font-size: 13px;
  transition: background .2s, color .2s;
}
.s-nav-cta:hover { background: var(--surface-ink); color: var(--surface-bg); }

@media (max-width: 800px) {
  .s-nav { padding: 16px 20px; }
  .s-nav-links { display: none; }
}

.s-section {
  max-width: 1200px;
  margin: 0 auto;
  padding: 100px 48px;
}
@media (max-width: 800px) { .s-section { padding: 60px 24px; } }

/* ---------- HERO ---------- */
.s-hero {
  min-height: 92vh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 120px 48px 80px;
  max-width: 1200px;
  margin: 0 auto;
  position: relative;
}
.s-hero-eyebrow {
  font-family: var(--surface-mono);
  font-size: 13px; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--surface-accent);
  margin-bottom: 32px;
  display: flex; gap: 10px; align-items: center;
}
.s-hero-eyebrow::before { content: ""; width: 24px; height: 1px; background: var(--surface-accent); }

/* ── Tooltip ─────────────────────────────────────────────── */
.tooltip-wrap {
  cursor: help;
  border-bottom: 1px dotted currentColor;
}

/* Portal tooltip — rendered on document.body, above all stacking contexts */
.portal-tip {
  position: fixed;
  transform: translateX(-50%) translateY(calc(-100% - 12px));
  width: 260px;
  padding: 10px 14px;
  border-radius: 4px;
  z-index: 9995;
  pointer-events: none;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0.01em;
  text-transform: none;
  white-space: normal;
  text-align: left;
  background: var(--surface-ink);
  color: var(--surface-bg);
  font-family: var(--surface-sans);
  box-shadow: 0 4px 16px rgba(0,0,0,0.18);
}
.portal-tip--fun {
  background: var(--hidden-bg);
  color: #ffffff;
  font-family: var(--hidden-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  border: 1px solid var(--hidden-accent);
  box-shadow: 0 0 20px rgba(255,46,136,0.3), 0 0 40px rgba(0,240,255,0.15);
}

.s-hero-h1 {
  font-family: var(--surface-display);
  font-size: clamp(40px, 6.4vw, 88px);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--surface-ink);
  text-wrap: pretty;
  max-width: 1100px;
  margin-bottom: 40px;
}
.s-hero-h1 em {
  font-style: italic;
  color: var(--surface-accent);
  font-weight: 400;
}

.s-hero-tagline {
  font-family: var(--surface-display);
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.5;
  color: var(--surface-ink-dim);
  max-width: 640px;
  margin-bottom: 48px;
}

.s-hero-meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  padding-top: 32px;
  border-top: 1px solid var(--surface-line);
  font-family: var(--surface-mono);
  font-size: 13px;
}
@media (max-width: 800px) { .s-hero-meta { grid-template-columns: repeat(2, 1fr); } }
.s-hero-meta-label {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--surface-ink-faint);
  margin-bottom: 6px;
}
.s-hero-meta strong {
  font-family: var(--surface-display);
  font-weight: 500;
  font-size: 18px;
  color: var(--surface-ink);
  display: block;
}

/* ---------- SECTION HEADER ---------- */
.s-section-head {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 24px;
  align-items: baseline;
  margin-bottom: 60px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--surface-line);
}
.s-section-num {
  font-family: var(--surface-mono);
  font-size: 13px;
  color: var(--surface-accent);
  letter-spacing: 0.1em;
}
.s-section-title {
  font-family: var(--surface-display);
  font-size: clamp(32px, 4vw, 48px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.s-section-title em { font-style: italic; color: var(--surface-accent); }
.s-section-caption {
  grid-column: 2;
  color: var(--surface-ink-dim);
  font-size: 16px;
  margin-top: 8px;
  font-family: var(--surface-display);
  font-style: italic;
}

/* ---------- WORK ---------- */
.s-work-list { border-top: 1px solid var(--surface-line); }
.s-work-row {
  display: grid;
  grid-template-columns: 60px 1fr 200px 100px;
  gap: 24px;
  padding: 28px 0;
  border-bottom: 1px solid var(--surface-line);
  align-items: baseline;
}
.s-work-id {
  font-family: var(--surface-mono);
  font-size: 13px;
  color: var(--surface-accent);
}
.s-work-title {
  font-family: var(--surface-display);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.s-work-stack {
  margin-top: 8px;
  font-family: var(--surface-mono);
  font-size: 12px;
  color: var(--surface-ink-faint);
}
.s-work-kind {
  font-family: var(--surface-mono);
  font-size: 13px;
  color: var(--surface-ink-dim);
}
.s-work-year {
  font-family: var(--surface-mono);
  font-size: 13px;
  color: var(--surface-ink-dim);
  text-align: right;
}
@media (max-width: 800px) {
  .s-work-row { grid-template-columns: 40px 1fr; }
  .s-work-kind, .s-work-year { display: none; }
  .s-work-title { font-size: 22px; }
}

/* ---------- ABOUT ---------- */
.s-about-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 80px;
  align-items: start;
}
@media (max-width: 800px) { .s-about-grid { grid-template-columns: 1fr; gap: 32px; } }
.s-about-lead {
  font-family: var(--surface-display);
  font-size: 24px;
  line-height: 1.45;
  color: var(--surface-ink);
  margin-bottom: 24px;
}
.s-about-text p {
  margin-bottom: 18px;
  color: var(--surface-ink-dim);
  line-height: 1.7;
  max-width: 580px;
}
.s-about-card {
  border-top: 1px solid var(--surface-ink);
  padding-top: 16px;
}
.s-about-card h3 {
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--surface-ink-faint);
  margin-bottom: 16px;
}
.s-about-card dl {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 12px 16px;
  font-size: 14px;
}
.s-about-card dt {
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--surface-ink-faint);
  padding-top: 2px;
}
.s-about-card dd { color: var(--surface-ink); }
.s-about-card a { border-bottom: 1px solid var(--surface-line); transition: border-color .2s; }
.s-about-card a:hover { border-color: var(--surface-accent); color: var(--surface-accent); }
.s-about-photo {
  display: block;
  width: 100%;
  margin-top: 28px;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center top;
  border-radius: 52% 48% 44% 56% / 48% 52% 56% 44%;
  border: 1px solid var(--surface-line);
}

/* ---------- EXPERIENCE ---------- */
.s-exp-item {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 32px;
  padding: 28px 0;
  border-bottom: 1px solid var(--surface-line);
}
.s-exp-year {
  font-family: var(--surface-mono);
  font-size: 13px;
  color: var(--surface-accent);
}
.s-exp-role {
  font-family: var(--surface-display);
  font-size: 22px;
  font-weight: 400;
  margin-bottom: 4px;
}
.s-exp-org {
  font-family: var(--surface-display);
  font-style: italic;
  color: var(--surface-ink-dim);
  font-size: 16px;
  margin-bottom: 12px;
}
.s-exp-bullets li {
  color: var(--surface-ink-dim);
  font-size: 15px;
  padding-left: 20px;
  position: relative;
  line-height: 1.6;
  margin-bottom: 4px;
}
.s-exp-bullets li::before {
  content: "—";
  position: absolute; left: 0;
  color: var(--surface-accent);
}
@media (max-width: 700px) {
  .s-exp-item { grid-template-columns: 1fr; gap: 8px; }
}

.s-edu-list { margin-top: 24px; }
.s-edu-item {
  display: grid;
  grid-template-columns: 140px 1.2fr 1.6fr;
  gap: 24px;
  padding: 14px 0;
  border-bottom: 1px solid var(--surface-line);
  font-size: 14px;
  align-items: baseline;
}
.s-edu-year { font-family: var(--surface-mono); color: var(--surface-accent); font-size: 12px; }
.s-edu-deg { font-family: var(--surface-display); font-size: 18px; }
.s-edu-org { color: var(--surface-ink-dim); font-style: italic; font-family: var(--surface-display); }
@media (max-width: 800px) { .s-edu-item { grid-template-columns: 1fr; gap: 4px; } }

.s-sub-title {
  font-family: var(--surface-mono);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--surface-ink-dim);
  margin-top: 60px;
  margin-bottom: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--surface-line);
}

/* ---------- SKILLS ---------- */
.s-skills-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}
@media (max-width: 800px) { .s-skills-grid { grid-template-columns: 1fr 1fr; } }
.s-skill-block { border-top: 1px solid var(--surface-line); padding-top: 16px; }
.s-skill-group {
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--surface-accent);
  margin-bottom: 12px;
}
.s-skill-block ul { display: flex; flex-direction: column; gap: 4px; }
.s-skill-block li {
  font-family: var(--surface-display);
  font-size: 16px;
  color: var(--surface-ink);
}

/* ---------- PUBS ---------- */
.s-pub-item {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 24px;
  padding: 24px 0;
  border-bottom: 1px solid var(--surface-line);
}
.s-pub-year { font-family: var(--surface-mono); color: var(--surface-accent); font-size: 13px; }
.s-pub-authors { font-family: var(--surface-mono); font-size: 12px; color: var(--surface-ink-faint); margin-bottom: 6px; }
.s-pub-title {
  font-family: var(--surface-display);
  font-size: 20px;
  line-height: 1.35;
  margin-bottom: 4px;
}
a.s-pub-title--link {
  display: block;
  color: inherit;
  text-decoration: none;
}
a.s-pub-title--link:hover { color: var(--surface-accent); text-decoration: underline; }
.s-pub-venue { font-family: var(--surface-display); font-style: italic; color: var(--surface-ink-dim); font-size: 14px; }

/* ---------- CONTACT ---------- */
.s-contact {
  text-align: left;
  padding: 120px 48px;
  max-width: 1200px;
  margin: 0 auto;
}
.s-contact h2 {
  font-family: var(--surface-display);
  font-size: clamp(48px, 8vw, 112px);
  font-weight: 400;
  letter-spacing: -0.025em;
  line-height: 1.05;
  margin-bottom: 40px;
}
.s-contact h2 em { font-style: italic; color: var(--surface-accent); }
.s-contact-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px;
  border-top: 1px solid var(--surface-ink);
  padding-top: 32px;
}
@media (max-width: 700px) { .s-contact-grid { grid-template-columns: 1fr; } }
.s-contact-link .label {
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--surface-ink-faint);
  margin-bottom: 8px;
}
.s-contact-link .value {
  font-family: var(--surface-display);
  font-size: 22px;
  white-space: nowrap;
}
.s-contact-link a { border-bottom: 1px solid var(--surface-line); transition: border-color .2s; }
.s-contact-link a:hover { border-color: var(--surface-accent); color: var(--surface-accent); }

.s-footer {
  padding: 32px 48px;
  display: flex; justify-content: space-between;
  border-top: 1px solid var(--surface-line);
  max-width: 1200px;
  margin: 0 auto;
  font-family: var(--surface-mono);
  font-size: 12px;
  color: var(--surface-ink-faint);
  flex-wrap: wrap; gap: 12px;
}

/* ============================================================
   FLIP TILES — sections that aren't part of the portal bubble.
   Each tile has a surface face and a glimpsed (cyberpunk) face.
   Hover flips horizontally.
   These sit ABOVE the hidden layer (z-index higher) so the
   bubble doesn't reveal them — they have their own reveal.
   ============================================================ */

.flip-band {
  position: relative;
  z-index: 5; /* above .hidden (z=2) */
  background: var(--surface-bg);
}

.flip-tile {
  perspective: 1600px;
  position: relative;
  transform-style: preserve-3d;
  display: block;
  width: 100%;
}
.flip-tile-inner {
  position: relative;
  transition: transform 0.7s var(--ease);
  transform-style: preserve-3d;
  width: 100% !important;
  display: block;
}
.flip-tile:hover .flip-tile-inner,
.flip-tile:focus-within .flip-tile-inner {
  transform: rotateX(180deg);
}
.flip-face {
  width: 100% !important;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform-style: preserve-3d;
  transition: opacity 0.25s var(--ease), visibility 0s linear 0.35s;
}
.flip-face--front {
  position: relative;
  transform: rotateX(0deg) translateZ(1px);
  opacity: 1;
  visibility: visible;
}
.flip-face--back {
  position: absolute;
  inset: 0;
  transform: rotateX(180deg) translateZ(1px);
  background: var(--hidden-bg);
  color: var(--hidden-ink);
  padding: 28px 0;
  display: flex;
  align-items: center;
  opacity: 0;
  visibility: hidden;
}
.flip-tile:hover .flip-face--front,
.flip-tile:focus-within .flip-face--front {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s var(--ease) 0.35s, visibility 0s linear 0.35s;
}
.flip-tile:hover .flip-face--back,
.flip-tile:focus-within .flip-face--back {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.25s var(--ease) 0.35s, visibility 0s;
}
/* Inner padding wrapper inside back face for visual breathing */
.flip-face--back-inner {
  width: 100%;
  padding: 0 24px;
  position: relative;
}
.flip-face--back-inner::before {
  content: "";
  position: absolute;
  inset: 8px 12px;
  border: 1px solid var(--hidden-accent);
  pointer-events: none;
  opacity: 0.4;
}

/* Tile-back styles reuse hidden tokens but compact */
.tile-back-id { font-family: var(--hidden-mono); font-size: 13px; color: var(--hidden-accent2); }
.tile-back-title {
  font-family: var(--hidden-display);
  font-size: 26px;
  font-weight: 700;
  color: var(--hidden-accent);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  text-shadow: 0 0 14px rgba(255,46,136,0.4);
}
.tile-back-meta {
  font-family: var(--hidden-mono);
  font-size: 12px;
  color: var(--hidden-ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.tile-back-stack {
  font-family: var(--hidden-mono);
  font-size: 12px;
  color: var(--hidden-ink-faint);
  margin-top: 6px;
}
.tile-back-year { font-family: var(--hidden-mono); color: var(--hidden-ink-dim); font-size: 13px; text-align: right; }

/* Work flip-row */
.s-work-row.flip-tile { padding: 0; border-bottom: 1px solid var(--surface-line); cursor: pointer; }
.s-work-row.flip-tile .flip-face--front {
  display: grid;
  grid-template-columns: 60px 1fr 200px 100px 36px;
  gap: 24px;
  padding: 28px 0;
  align-items: baseline;
}
.s-work-row.flip-tile .flip-face--back .flip-face--back-inner {
  display: grid;
  grid-template-columns: 60px 1fr 200px 100px 36px;
  gap: 24px;
  align-items: baseline;
}
@media (max-width: 800px) {
  .s-work-row.flip-tile .flip-face--front,
  .s-work-row.flip-tile .flip-face--back .flip-face--back-inner {
    grid-template-columns: 40px 1fr 36px;
  }
  .s-work-row.flip-tile .flip-face--front .s-work-kind,
  .s-work-row.flip-tile .flip-face--front .s-work-year,
  .s-work-row.flip-tile .flip-face--back .tile-back-meta,
  .s-work-row.flip-tile .flip-face--back .tile-back-year { display: none; }
}

/* ---------- WORK EXPAND CUE ---------- */
.s-work-cue {
  font-family: var(--surface-mono);
  font-size: 20px;
  font-weight: 300;
  color: var(--surface-accent);
  align-self: center;
  text-align: center;
  line-height: 1;
  transition: transform 0.35s var(--ease);
  user-select: none;
}
.s-work-cue.is-open { transform: rotate(45deg); }

.tile-back-cue {
  font-family: var(--hidden-mono);
  font-size: 20px;
  font-weight: 300;
  color: var(--hidden-accent);
  align-self: center;
  text-align: center;
  line-height: 1;
  user-select: none;
  transition: transform 0.35s var(--ease);
}
.tile-back-cue.is-open { transform: rotate(45deg); }

/* ---------- WORK EXPAND PANEL ---------- */
.work-expand {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--ease);
}
.work-expand--open { grid-template-rows: 1fr; }

.work-expand-inner { overflow: hidden; min-height: 0; }

/* Surface expand content */
.work-expand-surface {
  display: flex;
  gap: 40px;
  align-items: flex-start;
  padding: 32px 0 40px;
  border-top: 1px solid var(--surface-line);
}
/* Hidden expand content — shown in fun mode when tile is hovered */
.work-expand-hidden { display: none; }

body[data-fun="true"] .s-work-row.flip-tile:hover .work-expand-hidden,
body[data-fun="true"] .s-work-row.flip-tile:focus-within .work-expand-hidden {
  display: flex;
  gap: 40px;
  align-items: flex-start;
  padding: 32px 0 40px;
  border-top: 1px solid var(--hidden-line);
}
body[data-fun="true"] .s-work-row.flip-tile:hover .work-expand-surface,
body[data-fun="true"] .s-work-row.flip-tile:focus-within .work-expand-surface { display: none; }

.work-expand-desc {
  flex: 1;
  min-width: 0;
  font-family: var(--surface-display);
  font-size: 17px;
  line-height: 1.65;
  color: var(--surface-ink-dim);
}
.work-expand-hidden .work-expand-desc {
  font-family: var(--hidden-mono);
  font-size: 13px;
  line-height: 1.7;
  color: var(--hidden-ink-dim);
}

/* Outbound "Visit live site" link inside the expand panel */
.work-expand-text { flex: 1; min-width: 0; }

.work-expand-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 20px;
  font-family: var(--surface-sans);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--surface-accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease), gap .25s var(--ease);
}
.work-expand-link:hover { border-bottom-color: var(--surface-accent); gap: 10px; }

.work-expand-hidden .work-expand-link {
  font-family: var(--hidden-mono);
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--hidden-accent2);
  padding: 7px 14px;
  border: 1px solid var(--hidden-accent2);
  border-radius: 3px;
  box-shadow: 0 0 14px rgba(0, 240, 255, 0.18);
  transition: background .2s var(--ease), color .2s var(--ease), gap .2s var(--ease);
}
.work-expand-hidden .work-expand-link:hover {
  gap: 10px;
  background: var(--hidden-accent2);
  color: var(--hidden-bg);
}

.work-expand-visual {
  flex: 0 0 340px;
  width: 340px;
}
.work-expand-visual img {
  width: 100%;
  height: 220px;
  object-fit: cover;
  border-radius: 3px;
  display: block;
}
.work-expand-surface .work-expand-visual img {
  border: 1px solid var(--surface-line);
}
.work-expand-hidden .work-expand-visual img {
  border: 1px solid var(--hidden-accent);
  box-shadow: 0 0 20px rgba(255, 46, 136, 0.25);
}
.work-expand-image-note {
  margin-top: 8px;
  font-family: var(--hidden-mono);
  font-size: 11px;
  color: var(--hidden-ink-dim);
  line-height: 1.4;
}

/* Experience flip-item */
.s-exp-item.flip-tile { padding: 0; border-bottom: 1px solid var(--surface-line); }
.s-exp-item.flip-tile .flip-face--front {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 32px;
  padding: 28px 0;
}
.s-exp-item.flip-tile .flip-face--back { padding: 22px 0; }
.s-exp-item.flip-tile .flip-face--back .flip-face--back-inner {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 32px;
}
.tile-back-role {
  font-family: var(--hidden-display);
  font-size: 22px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--hidden-accent);
  margin-bottom: 4px;
}
.tile-back-org {
  font-family: var(--hidden-mono);
  font-size: 13px;
  color: var(--hidden-accent2);
  margin-bottom: 10px;
}
.tile-back-bullets li {
  color: var(--hidden-ink-dim);
  font-size: 13px;
  font-family: var(--hidden-mono);
  padding-left: 18px;
  position: relative;
  line-height: 1.55;
  margin-bottom: 3px;
}
.tile-back-bullets li::before {
  content: "▸"; position: absolute; left: 0; color: var(--hidden-accent);
}
@media (max-width: 700px) {
  .s-exp-item.flip-tile .flip-face--front,
  .s-exp-item.flip-tile .flip-face--back .flip-face--back-inner {
    grid-template-columns: 1fr; gap: 8px;
  }
}

/* Experience — redaction wipe (fun mode only, replaces the 3D flip).
   A censor bar sweeps across the row, holds while fully covering the
   surface text, then continues off the right edge — the hidden dossier
   line is left revealed behind it instead of a rotated back face. */
.s-exp-item.flip-tile { overflow: hidden; }
.s-exp-item.flip-tile .flip-face--front { z-index: 1; }
.s-exp-item.flip-tile .flip-face--back { transform: none; z-index: 2; }
.s-exp-item.flip-tile .flip-tile-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: #050506;
  box-shadow: 4px 0 14px rgba(255, 46, 136, 0.45);
  transform: translateX(-100%);
  transition: transform 0.4s var(--ease);
  pointer-events: none;
}
body[data-fun="true"] .s-exp-item.flip-tile:hover .flip-tile-inner,
body[data-fun="true"] .s-exp-item.flip-tile:focus-within .flip-tile-inner {
  transform: none;
}
body[data-fun="true"] .s-exp-item.flip-tile:hover .flip-tile-inner::before,
body[data-fun="true"] .s-exp-item.flip-tile:focus-within .flip-tile-inner::before {
  animation: exp-redact-sweep 1.05s var(--ease) forwards;
}
body[data-fun="true"] .s-exp-item.flip-tile:hover .flip-face--front,
body[data-fun="true"] .s-exp-item.flip-tile:focus-within .flip-face--front {
  animation: exp-redact-front-out 1.05s var(--ease) forwards;
}
body[data-fun="true"] .s-exp-item.flip-tile:hover .flip-face--back,
body[data-fun="true"] .s-exp-item.flip-tile:focus-within .flip-face--back {
  animation: exp-redact-back-in 1.05s var(--ease) forwards;
}
@keyframes exp-redact-sweep {
  0%   { transform: translateX(-100%); }
  40%  { transform: translateX(0%); }
  60%  { transform: translateX(0%); }
  100% { transform: translateX(100%); }
}
@keyframes exp-redact-front-out {
  0%, 35%   { opacity: 1; visibility: visible; }
  45%, 100% { opacity: 0; visibility: hidden; }
}
@keyframes exp-redact-back-in {
  0%, 55%   { opacity: 0; visibility: hidden; }
  70%, 100% { opacity: 1; visibility: visible; }
}

/* Skills — decrypt scramble (fun mode only). JS (SkillBlock in
   portfolio-v3-app.jsx) scrambles each label's characters in place and
   locks them into the hidden text; this block only carries the
   colour/panel wash that syncs with the JS timing via .is-decrypted.
   Negative margin + matching padding keeps text position identical
   between states — only the panel fill grows in, nothing reflows. */
.s-skill-block {
  min-height: 200px;
  margin: 0 -14px;
  padding: 16px 14px 20px;
  border-top-color: var(--surface-line);
  transition: background-color 0.4s var(--ease), border-color 0.4s var(--ease);
}
.s-skill-block .s-skill-group,
.s-skill-block li {
  transition: color 0.35s var(--ease);
}
.s-skill-block.is-decrypted {
  background-color: var(--hidden-bg);
  border-top-color: var(--hidden-accent2);
}
.s-skill-block.is-decrypted .s-skill-group { color: var(--hidden-accent); }
.s-skill-block.is-decrypted li { color: var(--hidden-ink); }

/* Pub flip-item */
.s-pub-item.flip-tile { padding: 0; border-bottom: 1px solid var(--surface-line); cursor: pointer; }
.s-pub-item.flip-tile .flip-face--front {
  display: grid;
  grid-template-columns: 100px 1fr 36px;
  gap: 24px;
  padding: 24px 0;
}
.s-pub-item.flip-tile .flip-face--back { padding: 22px 0; }
.s-pub-item.flip-tile .flip-face--back .flip-face--back-inner {
  display: grid;
  grid-template-columns: 100px 1fr 36px;
  gap: 24px;
}

/* Publications — scanline declassify (fun mode only, replaces the 3D
   flip). A glowing scanner line sweeps top-to-bottom; the surface row
   is clipped away just behind it while the hidden annotated row is
   clipped in — like a photocopier declassifying the row as it passes.
   Linear timing (not var(--ease)) for a constant mechanical scan speed,
   distinct from Experience's eased wipe and Skills' staggered decrypt. */
.s-pub-item.flip-tile .flip-face--front {
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.35s var(--ease);
  z-index: 1;
}
.s-pub-item.flip-tile .flip-face--back {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.35s var(--ease);
  transform: none;
  z-index: 2;
}
.s-pub-item.flip-tile .flip-tile-inner::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0%;
  height: 2px;
  transform: translateY(-50%);
  background: var(--hidden-accent2);
  box-shadow: 0 0 10px 2px var(--hidden-accent2), 0 0 22px 6px rgba(0, 240, 255, 0.35);
  opacity: 0;
  transition: top 0.35s var(--ease), opacity 0.35s var(--ease);
  z-index: 3;
  pointer-events: none;
}
body[data-fun="true"] .s-pub-item.flip-tile:hover .flip-tile-inner,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .flip-tile-inner {
  transform: none;
}
body[data-fun="true"] .s-pub-item.flip-tile:hover .flip-tile-inner::before,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .flip-tile-inner::before {
  animation: pub-scan-bar 0.95s linear forwards;
}
body[data-fun="true"] .s-pub-item.flip-tile:hover .flip-face--front,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .flip-face--front {
  opacity: 1;
  visibility: visible;
  animation: pub-scan-front-out 0.95s linear forwards;
}
body[data-fun="true"] .s-pub-item.flip-tile:hover .flip-face--back,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .flip-face--back {
  animation: pub-scan-back-in 0.95s linear forwards;
}
@keyframes pub-scan-bar {
  0%   { top: 0%; opacity: 0; }
  6%   { opacity: 1; }
  94%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}
@keyframes pub-scan-front-out {
  0%   { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(100% 0 0 0); }
}
@keyframes pub-scan-back-in {
  0%   { clip-path: inset(0 0 100% 0); }
  100% { clip-path: inset(0 0 0 0); }
}

/* ---------- PUB EXPAND CUE ---------- */
.s-pub-cue {
  font-family: var(--surface-mono);
  font-size: 20px;
  font-weight: 300;
  color: var(--surface-accent);
  align-self: center;
  text-align: center;
  line-height: 1;
  transition: transform 0.35s var(--ease);
  user-select: none;
}
.s-pub-cue.is-open { transform: rotate(45deg); }

.tile-back-pub-cue {
  font-family: var(--hidden-mono);
  font-size: 20px;
  font-weight: 300;
  color: var(--hidden-accent);
  align-self: center;
  text-align: center;
  line-height: 1;
  user-select: none;
  transition: transform 0.35s var(--ease);
}
.tile-back-pub-cue.is-open { transform: rotate(45deg); }

/* ---------- PUB EXPAND PANEL ---------- */
.pub-expand {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--ease);
}
.pub-expand--open { grid-template-rows: 1fr; }
.pub-expand-inner { overflow: hidden; min-height: 0; }

.pub-expand-surface {
  padding: 20px 0 28px;
  border-top: 1px solid var(--surface-line);
}
.pub-expand-hidden { display: none; }

body[data-fun="true"] .s-pub-item.flip-tile:hover .pub-expand-hidden,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .pub-expand-hidden {
  display: block;
  padding: 20px 0 28px;
  border-top: 1px solid var(--hidden-line);
}
body[data-fun="true"] .s-pub-item.flip-tile:hover .pub-expand-surface,
body[data-fun="true"] .s-pub-item.flip-tile:focus-within .pub-expand-surface { display: none; }

.pub-expand-desc {
  font-family: var(--surface-display);
  font-size: 16px;
  line-height: 1.65;
  color: var(--surface-ink-dim);
  max-width: 780px;
}
.pub-expand-hidden .pub-expand-desc {
  font-family: var(--hidden-mono);
  font-size: 13px;
  line-height: 1.7;
  color: var(--hidden-ink-dim);
  max-width: 780px;
}
.tile-back-year-tall { font-family: var(--hidden-mono); color: var(--hidden-accent2); font-size: 13px; padding-top: 4px; }
.tile-back-pub-authors { font-family: var(--hidden-mono); font-size: 11px; color: var(--hidden-ink-faint); margin-bottom: 4px; }
.tile-back-pub-title {
  font-family: var(--hidden-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--hidden-accent);
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin-bottom: 4px;
  line-height: 1.3;
}
a.tile-back-pub-title--link {
  display: block;
  color: var(--hidden-accent);
  text-decoration: none;
  font-family: var(--hidden-display);
  font-size: 18px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin-bottom: 4px;
  line-height: 1.3;
}
a.tile-back-pub-title--link:hover { color: var(--hidden-accent2); text-decoration: underline; }
.tile-back-pub-venue { font-family: var(--hidden-mono); font-size: 11px; color: var(--hidden-ink-dim); }

/* ============================================================
   HIDDEN — cyberpunk, mono, heavy chrome
   Mirrors surface layout dimensions so positions match
   ============================================================ */
.h-nav {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; justify-content: space-between; align-items: center;
  padding: 20px 48px;
  border-bottom: 1px solid var(--hidden-line);
  height: 65px;
  font-family: var(--hidden-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hidden-ink-dim);
}
.h-nav-mark {
  color: var(--hidden-accent);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.08em;
}
.h-nav-links { display: flex; gap: 22px; }
.h-nav-cta {
  border: 1px solid var(--hidden-accent);
  color: var(--hidden-accent);
  padding: 7px 14px;
  font-size: 11px;
  border-radius: 0;
}

@media (max-width: 800px) {
  .h-nav { padding: 16px 20px; }
  .h-nav-links { display: none; }
}

.h-section {
  max-width: 1200px;
  margin: 0 auto;
  padding: 100px 48px;
}
@media (max-width: 800px) { .h-section { padding: 60px 24px; } }

.h-hero {
  min-height: 92vh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 120px 48px 80px;
  max-width: 1200px;
  margin: 0 auto;
  position: relative;
}
.h-hero-eyebrow {
  font-family: var(--hidden-mono);
  font-size: 13px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--hidden-accent);
  margin-bottom: 32px;
  display: flex; gap: 10px; align-items: center;
  text-shadow: 0 0 12px rgba(255, 46, 136, 0.6);
}
.h-hero-eyebrow::before { content: ""; width: 24px; height: 1px; background: var(--hidden-accent); }

.h-hero-h1 {
  font-family: var(--hidden-display);
  font-size: clamp(40px, 6.4vw, 88px);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: var(--hidden-ink);
  text-wrap: pretty;
  max-width: 1100px;
  margin-bottom: 40px;
}
.h-hero-h1 em {
  font-style: normal;
  color: var(--hidden-accent);
  text-shadow: 0 0 24px rgba(255, 46, 136, 0.6);
}
.h-hero-h1 .glitch-cyan {
  color: var(--hidden-accent2);
  text-shadow: 0 0 18px rgba(0, 240, 255, 0.5);
}

.h-hero-tagline {
  font-family: var(--hidden-mono);
  font-size: clamp(15px, 1.4vw, 18px);
  line-height: 1.55;
  color: var(--hidden-ink);
  max-width: 640px;
  margin-bottom: 48px;
}
.h-hero-tagline span.dim { color: var(--hidden-ink-faint); }
.h-hero-tagline span.cyan { color: var(--hidden-accent2); }

.h-hero-meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  padding-top: 32px;
  border-top: 1px solid var(--hidden-accent);
  font-family: var(--hidden-mono);
  font-size: 13px;
}
@media (max-width: 800px) { .h-hero-meta { grid-template-columns: repeat(2, 1fr); } }
.h-hero-meta-label {
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--hidden-accent2);
  margin-bottom: 6px;
}
.h-hero-meta strong {
  font-family: var(--hidden-display);
  font-weight: 600;
  font-size: 18px;
  color: var(--hidden-ink);
  display: block;
  letter-spacing: -0.01em;
}

.h-section-head {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 24px;
  align-items: baseline;
  margin-bottom: 60px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--hidden-line);
}
.h-section-num {
  font-family: var(--hidden-mono);
  font-size: 13px;
  color: var(--hidden-accent2);
  letter-spacing: 0.12em;
}
.h-section-title {
  font-family: var(--hidden-display);
  font-size: clamp(32px, 4vw, 48px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  text-transform: uppercase;
}
.h-section-title em { font-style: normal; color: var(--hidden-accent); text-shadow: 0 0 18px rgba(255, 46, 136, 0.5); }
.h-section-caption {
  grid-column: 2;
  color: var(--hidden-ink-dim);
  font-size: 14px;
  margin-top: 8px;
  font-family: var(--hidden-mono);
}

.h-work-list { border-top: 1px solid var(--hidden-line); }
.h-work-row {
  display: grid;
  grid-template-columns: 60px 1fr 200px 100px;
  gap: 24px;
  padding: 28px 0;
  border-bottom: 1px solid var(--hidden-line);
  align-items: baseline;
}
.h-work-id { font-family: var(--hidden-mono); font-size: 13px; color: var(--hidden-accent2); }
.h-work-title {
  font-family: var(--hidden-display);
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--hidden-accent);
  text-transform: uppercase;
}
.h-work-stack {
  margin-top: 8px;
  font-family: var(--hidden-mono);
  font-size: 12px;
  color: var(--hidden-ink-faint);
}
.h-work-kind {
  font-family: var(--hidden-mono);
  font-size: 13px;
  color: var(--hidden-ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.h-work-year {
  font-family: var(--hidden-mono);
  font-size: 13px;
  color: var(--hidden-ink-dim);
  text-align: right;
}
@media (max-width: 800px) {
  .h-work-row { grid-template-columns: 40px 1fr; }
  .h-work-kind, .h-work-year { display: none; }
  .h-work-title { font-size: 22px; }
}

.h-about-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 80px;
  align-items: start;
}
@media (max-width: 800px) { .h-about-grid { grid-template-columns: 1fr; gap: 32px; } }
.h-about-lead {
  font-family: var(--hidden-display);
  font-size: 24px;
  line-height: 1.45;
  color: var(--hidden-ink);
  margin-bottom: 24px;
  letter-spacing: -0.01em;
}
.h-about-lead em { font-style: normal; color: var(--hidden-accent); }
.h-about-text p {
  margin-bottom: 18px;
  color: var(--hidden-ink-dim);
  line-height: 1.7;
  max-width: 580px;
  font-family: var(--hidden-mono);
  font-size: 14px;
}
.h-about-card {
  border-top: 1px solid var(--hidden-accent);
  padding-top: 16px;
}
.h-about-card h3 {
  font-family: var(--hidden-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--hidden-accent2);
  margin-bottom: 16px;
}
.h-about-card dl {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 12px 16px;
  font-size: 14px;
  font-family: var(--hidden-mono);
}
.h-about-card dt {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hidden-ink-faint);
  padding-top: 2px;
}
.h-about-card dd { color: var(--hidden-ink); }
.h-about-card dd.accent { color: var(--hidden-accent); }

/* ============================================================
   GLITCH PORTRAIT — hidden layer only
   ============================================================ */
.h-portrait-wrap {
  margin-top: 28px;
  user-select: none;
}

.h-portrait-layers {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  border-radius: 52% 48% 44% 56% / 48% 52% 56% 44%;
  background: var(--hidden-bg);
  isolation: isolate;
  cursor: crosshair;
}

.h-portrait-layer {
  position: absolute;
  inset: 0;
}
.h-portrait-layer img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}

/* Base — no filter, no blend mode */
.h-portrait-layer--base { z-index: 1; }

/* Cyan channel — offset left by default */
.h-portrait-layer--b {
  z-index: 2;
  transform: translateX(-4px);
  mix-blend-mode: screen;
}
.h-portrait-layer--b img {
  filter: sepia(1) saturate(6) hue-rotate(158deg) brightness(0.6);
}

/* Magenta channel — offset right by default */
.h-portrait-layer--r {
  z-index: 3;
  transform: translateX(4px);
  mix-blend-mode: screen;
}
.h-portrait-layer--r img {
  filter: sepia(1) saturate(6) hue-rotate(298deg) brightness(0.6);
}

/* ---- Glitch burst keyframes ---- */
@keyframes h-portrait-glitch-r {
  0%   { transform: translateX(4px);                       }
  9%   { transform: translateX(30px)  skewX(-5deg);        }
  18%  { transform: translateX(-14px);                     }
  27%  { transform: translateX(26px)  skewX(4deg);         }
  36%  { transform: translateX(-10px);                     }
  45%  { transform: translateX(22px);                      }
  54%  { transform: translateX(-18px) skewX(-3deg);        }
  63%  { transform: translateX(16px);                      }
  72%  { transform: translateX(-6px)  skewX(2deg);         }
  81%  { transform: translateX(12px);                      }
  90%  { transform: translateX(-4px);                      }
  100% { transform: translateX(4px);                       }
}
@keyframes h-portrait-glitch-b {
  0%   { transform: translateX(-4px);                      }
  9%   { transform: translateX(-30px) skewX(5deg);         }
  18%  { transform: translateX(14px);                      }
  27%  { transform: translateX(-26px) skewX(-4deg);        }
  36%  { transform: translateX(10px);                      }
  45%  { transform: translateX(-22px);                     }
  54%  { transform: translateX(18px)  skewX(3deg);         }
  63%  { transform: translateX(-16px);                     }
  72%  { transform: translateX(6px)   skewX(-2deg);        }
  81%  { transform: translateX(-12px);                     }
  90%  { transform: translateX(4px);                       }
  100% { transform: translateX(-4px);                      }
}
@keyframes h-portrait-glitch-wrap {
  0%,100% { filter: none; }
  20%     { filter: brightness(2.5) saturate(0); }
  40%     { filter: hue-rotate(90deg) saturate(4) brightness(1.2); }
  60%     { filter: brightness(0.2); }
  80%     { filter: hue-rotate(-90deg) saturate(6) brightness(1.4); }
}

.h-portrait-layers.is-glitching {
  animation: h-portrait-glitch-wrap 0.08s steps(1) infinite;
}
.h-portrait-layers.is-glitching .h-portrait-layer--r {
  animation: h-portrait-glitch-r 0.11s steps(1) infinite;
}
.h-portrait-layers.is-glitching .h-portrait-layer--b {
  animation: h-portrait-glitch-b 0.11s steps(1) infinite;
}

/* Caption */
.h-portrait-caption {
  font-family: var(--hidden-mono);
  font-size: 11px;
  color: var(--hidden-accent2);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.45);
  letter-spacing: 0.1em;
  text-align: center;
  margin-top: 10px;
}

.h-exp-item {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 32px;
  padding: 28px 0;
  border-bottom: 1px solid var(--hidden-line);
}
.h-exp-year { font-family: var(--hidden-mono); font-size: 13px; color: var(--hidden-accent2); }
.h-exp-role {
  font-family: var(--hidden-display);
  font-size: 22px;
  font-weight: 600;
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: -0.01em;
}
.h-exp-org {
  font-family: var(--hidden-mono);
  color: var(--hidden-accent);
  font-size: 13px;
  margin-bottom: 12px;
}
.h-exp-bullets li {
  color: var(--hidden-ink-dim);
  font-size: 14px;
  padding-left: 20px;
  position: relative;
  line-height: 1.6;
  margin-bottom: 4px;
  font-family: var(--hidden-mono);
}
.h-exp-bullets li::before {
  content: "▸";
  position: absolute; left: 0;
  color: var(--hidden-accent);
}
@media (max-width: 700px) {
  .h-exp-item { grid-template-columns: 1fr; gap: 8px; }
}

.h-edu-list { margin-top: 24px; }
.h-edu-item {
  display: grid;
  grid-template-columns: 140px 1.2fr 1.6fr;
  gap: 24px;
  padding: 14px 0;
  border-bottom: 1px solid var(--hidden-line);
  font-size: 14px;
  font-family: var(--hidden-mono);
  align-items: baseline;
}
.h-edu-year { color: var(--hidden-accent2); font-size: 12px; }
.h-edu-deg { font-family: var(--hidden-display); font-size: 16px; font-weight: 600; text-transform: uppercase; letter-spacing: -0.01em; }
.h-edu-org { color: var(--hidden-ink-dim); }
@media (max-width: 800px) { .h-edu-item { grid-template-columns: 1fr; gap: 4px; } }

.h-sub-title {
  font-family: var(--hidden-mono);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--hidden-accent2);
  margin-top: 60px;
  margin-bottom: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--hidden-line);
}

.h-skills-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}
@media (max-width: 800px) { .h-skills-grid { grid-template-columns: 1fr 1fr; } }
.h-skill-block { border-top: 1px solid var(--hidden-accent); padding-top: 16px; }
.h-skill-group {
  font-family: var(--hidden-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--hidden-accent);
  margin-bottom: 12px;
}
.h-skill-block ul { display: flex; flex-direction: column; gap: 4px; font-family: var(--hidden-mono); }
.h-skill-block li { font-size: 14px; color: var(--hidden-ink); }

.h-pub-item {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 24px;
  padding: 24px 0;
  border-bottom: 1px solid var(--hidden-line);
  font-family: var(--hidden-mono);
}
.h-pub-year { font-size: 13px; color: var(--hidden-accent2); }
.h-pub-authors { font-size: 12px; color: var(--hidden-ink-faint); margin-bottom: 6px; }
.h-pub-title {
  font-family: var(--hidden-display);
  font-size: 18px;
  line-height: 1.35;
  margin-bottom: 4px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}
.h-pub-venue { font-size: 12px; color: var(--hidden-ink-dim); }

/* ============================================================
   CLASSIFIED EDU BLOCK — fun mode only
   ============================================================ */

/* Mode switching: surface mode shows plain list, fun mode shows classified block */
body:not([data-fun="true"]) .edu-fun-block { display: none; }
body[data-fun="true"] .edu-surface-heading,
body[data-fun="true"] .edu-surface-list { display: none; }

/* Wrapper */
.edu-classified-wrap {
  position: relative;
  cursor: default;
}

/* CLASSIFIED stamp — absolute overlay, centred and rotated */
.edu-classified-stamp {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--hidden-mono);
  font-size: clamp(26px, 4vw, 44px);
  font-weight: 700;
  letter-spacing: 0.35em;
  color: transparent;
  -webkit-text-stroke: 2px var(--hidden-accent);
  text-shadow: 0 0 24px rgba(255, 46, 136, 0.6);
  border: 3px solid var(--hidden-accent);
  box-shadow: 0 0 28px rgba(255, 46, 136, 0.2), inset 0 0 28px rgba(255, 46, 136, 0.05);
  transform: rotate(-6deg);
  z-index: 3;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.2s ease;
}

/* Redaction bars — cover each row */
.edu-redactable { position: relative; }
.edu-redact-bar {
  position: absolute;
  inset: 6px 0;
  background: #0d0d12;
  z-index: 2;
  opacity: 1;
  transition: opacity 0.35s ease 0.1s;
}

/* Bonus entry — hidden until revealed */
.edu-bonus-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 18px 0;
  border-bottom: 1px solid var(--hidden-line);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s ease 0.28s;
}
.edu-bonus-line {
  font-family: var(--hidden-mono);
  font-size: 13px;
  font-style: italic;
  color: var(--hidden-accent2);
  text-shadow: 0 0 14px rgba(0, 240, 255, 0.45);
  letter-spacing: 0.02em;
}

/* ---- Glitch keyframes ---- */
@keyframes edu-glitch-container {
  0%, 100% { transform: none; filter: none; }
  7%  { transform: translateX(-3px) skewX(-1deg); filter: hue-rotate(90deg) saturate(5) brightness(1.2); }
  8%  { transform: translateX(3px);               filter: hue-rotate(-90deg) saturate(7); }
  9%  { transform: none;                           filter: none; }
  31% { transform: translateX(2px) skewX(2deg);   filter: hue-rotate(180deg) brightness(1.4); }
  32% { transform: none;                           filter: none; }
  62% { transform: translateX(-3px);              filter: hue-rotate(-180deg) saturate(8); }
  63% { transform: none;                           filter: none; }
  86% { transform: translateX(2px) skewX(-2deg);  filter: saturate(6) brightness(1.3); }
  87% { transform: none;                           filter: none; }
}

/* ---- Revealed (hovered) state ---- */
.edu-classified-wrap.is-hovered {
  animation: edu-glitch-container 0.7s steps(1) infinite;
}
.edu-classified-wrap.is-hovered .edu-classified-stamp {
  opacity: 0;
  transition: opacity 0.15s ease;
}
.edu-classified-wrap.is-hovered .edu-redact-bar {
  opacity: 0;
  transition: opacity 0.35s ease 0.1s;
}
.edu-classified-wrap.is-hovered .edu-bonus-item {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.45s ease 0.28s;
}

.h-contact {
  text-align: left;
  padding: 120px 48px;
  max-width: 1200px;
  margin: 0 auto;
}
.h-contact h2 {
  font-family: var(--hidden-display);
  font-size: clamp(48px, 8vw, 112px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 40px;
  text-transform: uppercase;
}
.h-contact h2 em { font-style: normal; color: var(--hidden-accent); text-shadow: 0 0 24px rgba(255, 46, 136, 0.6); }
/* Sits between the h2 and grid; pads the hidden contact block so its grid
   divider lines up with the surface contact divider. */
/* Subtitle is removed from flow (height: 0) so the hidden contact grid
   divider lines up exactly with the surface contact divider. The visible
   text overflows upward into the h2's margin-bottom gap. */
.h-contact-subtitle {
  font-family: var(--hidden-mono);
  font-size: 14px;
  line-height: 24px;
  height: 0;
  overflow: visible;
  margin: 0;
  transform: translateY(-32px);
  color: var(--hidden-accent2);
  letter-spacing: 0.04em;
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.4);
}
.h-contact-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px;
  border-top: 1px solid var(--hidden-accent);
  padding-top: 32px;
  font-family: var(--hidden-mono);
}
@media (max-width: 700px) { .h-contact-grid { grid-template-columns: 1fr; } }
.h-contact-link .label {
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hidden-accent2);
  margin-bottom: 8px;
}
.h-contact-link .value {
  font-family: var(--hidden-display);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.h-footer {
  padding: 32px 48px;
  display: flex; justify-content: space-between;
  border-top: 1px solid var(--hidden-line);
  max-width: 1200px;
  margin: 0 auto;
  font-family: var(--hidden-mono);
  font-size: 11px;
  color: var(--hidden-ink-faint);
  flex-wrap: wrap; gap: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.h-footer .live { color: var(--hidden-accent); }
.dot-live {
  display: inline-block; width: 6px; height: 6px;
  background: var(--hidden-accent); border-radius: 50%;
  margin-right: 6px;
  box-shadow: 0 0 6px var(--hidden-accent);
  animation: blink 1.6s infinite;
}
@keyframes blink {
  0%, 60% { opacity: 1; }
  80% { opacity: 0.2; }
  100% { opacity: 1; }
}

/* ============================================================
   FUN-MODE TOGGLE
   ============================================================ */

.s-nav-left {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.h-nav-left {
  display: flex;
  align-items: center;
  gap: 14px;
}
.h-nav-spacer {
  display: inline-block;
  width: 88px;
  flex-shrink: 0;
}

.fun-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 88px;
  padding: 5px 11px 5px 8px;
  border-radius: 999px;
  border: 1px solid var(--surface-line);
  background: transparent;
  color: var(--surface-ink-dim);
  font-family: var(--surface-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  transition: border-color 0.3s, color 0.3s, background 0.3s, box-shadow 0.3s;
}
.fun-toggle:hover {
  border-color: var(--surface-ink);
  color: var(--surface-ink);
}
.fun-toggle--fun {
  background: var(--hidden-bg);
  border-color: var(--hidden-accent);
  color: var(--hidden-accent);
  font-family: var(--hidden-mono);
  box-shadow: 0 0 14px rgba(255, 46, 136, 0.35);
}
.fun-toggle--fun:hover {
  box-shadow: 0 0 22px rgba(255, 46, 136, 0.55);
}
@media (max-width: 1024px) {
  .fun-toggle { display: none; }
}

/* Glitch effect on nav links — fun mode only */
@keyframes glitch-text {
  0%   { transform: none; text-shadow: none; opacity: 1; }
  15%  { transform: translateX(-3px) skewX(-5deg); text-shadow: 3px 0 var(--hidden-accent), -3px 0 var(--hidden-accent2); opacity: 0.9; }
  30%  { transform: translateX(2px) skewX(1deg); text-shadow: -2px 0 var(--hidden-accent); opacity: 1; }
  50%  { transform: translateX(-2px) skewX(-3deg); text-shadow: 2px 0 var(--hidden-accent2), -1px 0 var(--hidden-accent); opacity: 0.85; }
  70%  { transform: translateX(3px); text-shadow: -3px 0 var(--hidden-accent); opacity: 1; }
  85%  { transform: translateX(-1px) skewX(2deg); text-shadow: 1px 0 var(--hidden-accent2); opacity: 0.95; }
  100% { transform: none; text-shadow: none; opacity: 1; }
}

body[data-fun="true"] .s-nav-links a:hover,
body[data-fun="true"] .s-nav-mark:hover {
  color: var(--surface-ink);
  animation: glitch-text 0.4s steps(1) infinite;
}

/* ============================================================
   SERIOUS MODE — lock out all fun-layer elements
   ============================================================ */

/* Hidden layer stays collapsed */
body:not([data-fun="true"]) .hidden {
  -webkit-clip-path: circle(0 at var(--cx) var(--cy)) !important;
          clip-path: circle(0 at var(--cx) var(--cy)) !important;
  transition: -webkit-clip-path 0.45s var(--ease), clip-path 0.45s var(--ease) !important;
}
/* Mini nav bubble also collapsed */
body:not([data-fun="true"]) .h-nav-fixed {
  -webkit-clip-path: circle(0) !important;
          clip-path: circle(0) !important;
}
/* Flip tiles stay locked on their front face */
body:not([data-fun="true"]) .flip-tile:hover .flip-tile-inner,
body:not([data-fun="true"]) .flip-tile:focus-within .flip-tile-inner {
  transform: none !important;
  transition: none !important;
}
body:not([data-fun="true"]) .flip-tile:hover .flip-face--front,
body:not([data-fun="true"]) .flip-tile:focus-within .flip-face--front {
  opacity: 1 !important;
  visibility: visible !important;
  transition: none !important;
}
body:not([data-fun="true"]) .flip-tile:hover .flip-face--back,
body:not([data-fun="true"]) .flip-tile:focus-within .flip-face--back {
  opacity: 0 !important;
  visibility: hidden !important;
  transition: none !important;
}
/* When fun mode is enabled, restore the nice reveal transition */
body[data-fun="true"] .hidden {
  transition: -webkit-clip-path 0.5s var(--ease), clip-path 0.5s var(--ease);
}

/* Mobile nav elements — hidden by default on desktop */
.s-nav-mobile  { display: none; }
.s-nav-overlay { display: none; }

/* Touch hint bubble — hidden on desktop, shown on mobile via media query */
.touch-hint { display: none; }

/* ============================================================
   SERIOUS-MODE MOTION & POLISH
   Entrance choreography, scroll reveals, hover feedback,
   scrollspy, band backgrounds. All entrance/reveal motion is
   gated behind prefers-reduced-motion: no-preference — users
   with reduced motion get the static page.
   ============================================================ */

/* --- Band backgrounds: About + Skills sit on the deeper cream.
   Sections are centered 1200px boxes, so the band is made
   full-bleed with the spread-shadow + clip trick. --- */
#about, #skills {
  background: var(--surface-bg-2);
  box-shadow: 0 0 0 100vmax var(--surface-bg-2);
  clip-path: inset(0 -100vmax);
}

/* --- Row hover feedback (work + pubs are clickable/expandable) --- */
.s-work-title, .s-pub-title, .s-work-cue, .s-pub-cue { transition: color .25s var(--ease); }
.s-work-row:hover .s-work-title,
.s-pub-item:hover .s-pub-title,
.s-work-row:hover .s-work-cue,
.s-pub-item:hover .s-pub-cue { color: var(--surface-accent); }

/* --- Nav CTA arrow nudge --- */
.s-nav-cta-arrow { display: inline-block; transition: transform .25s var(--ease); }
.s-nav-cta:hover .s-nav-cta-arrow { transform: translateX(3px); }

/* --- Scrollspy: sage underline slides in under the active link --- */
.s-nav-links a { position: relative; }
.s-nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%; bottom: -4px;
  height: 1px;
  background: var(--surface-accent);
  transition: right .3s var(--ease);
}
.s-nav-links a.is-active { color: var(--surface-ink); }
.s-nav-links a.is-active::after { right: 0; }
body[data-fun="true"] .s-nav-links a.is-active::after { background: var(--hidden-accent); }

/* --- Hero scroll cue --- */
.s-hero-scrollcue {
  position: absolute;
  left: 48px; bottom: 26px;
  display: flex; align-items: center; gap: 12px;
  color: var(--surface-ink-faint);
  font-family: var(--surface-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  pointer-events: none;
  transition: opacity .45s var(--ease);
}
.s-hero-scrollcue::before {
  content: "";
  width: 1px; height: 36px;
  background: var(--surface-ink-faint);
}
.s-hero-scrollcue.is-hidden { opacity: 0; }

/* --- Work hover image preview (desktop pointer + serious mode only) --- */
.work-hover-preview {
  position: fixed;
  left: 0; top: 0;
  z-index: 70;
  width: 300px; height: 200px;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 18px 50px rgba(26, 26, 26, .18);
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--ease), transform .2s ease-out;
}
.work-hover-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.work-hover-preview.is-visible { opacity: 1; }
body[data-fun="true"] .work-hover-preview { display: none; }
@media (hover: none) { .work-hover-preview { display: none; } }

/* --- Motion: only for users who haven't asked for reduced motion --- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* Hero entrance — one-time, on load */
  @keyframes rise-in {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
  }
  .s-hero-eyebrow   { animation: rise-in .6s var(--ease) .05s both; }
  .s-hero-h1        { animation: rise-in .7s var(--ease) .15s both; }
  .s-hero-tagline   { animation: rise-in .7s var(--ease) .30s both; }
  .s-hero-meta      { animation: rise-in .7s var(--ease) .45s both; }
  .s-hero-scrollcue { animation: rise-in .7s var(--ease) .65s both; }

  /* Scroll cue pulse — the line drifts down and fades, loops */
  @keyframes cue-drift {
    0%, 100% { transform: translateY(0); opacity: 1; }
    70%      { transform: translateY(6px); opacity: .25; }
  }
  .s-hero-scrollcue::before { animation: cue-drift 2.4s var(--ease) 1.6s infinite; }

  /* Scroll reveals — JS adds .reveal-item + .is-visible; without JS
     the class never exists so nothing is ever hidden */
  .reveal-item {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity .55s var(--ease), transform .55s var(--ease);
    transition-delay: var(--reveal-delay, 0s);
  }
  .reveal-item.is-visible { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ============================================================
   PROJECTOR PULL-CORD — fun mode only
   The page is the projector screen. A void strip hangs off the
   very end of the document with a weighted slat and a pull cord;
   pulling it rolls #root up off the viewport while /Creative/
   (pre-loaded in .screen-wall, z-index -1) shows through beneath.
   --pull (px) is set from JS while dragging.
   ============================================================ */
.screen-pull-zone {
  --pull: 0px;
  position: relative;
  z-index: 6; /* above .hidden (2) and flip bands (5) */
  height: 200px;
  background: var(--hidden-bg);
}
.screen-pull-slat {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 7px;
  background: linear-gradient(#1c1c26, #06060c);
  border-bottom: 1px solid rgba(0, 240, 255, 0.55);
  box-shadow: 0 2px 14px rgba(0, 240, 255, 0.22), 0 8px 28px rgba(0, 0, 0, 0.65);
  transform: translateY(calc(var(--pull) * 0.18));
  transition: transform 0.45s cubic-bezier(0.16, 1.4, 0.4, 1);
}
.screen-pull-cord {
  position: absolute;
  top: 7px;
  right: 18%;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: none;
  border: 0;
  padding: 0 16px; /* fat hit target around a thin string */
  cursor: grab;
  touch-action: none;
  transform-origin: 50% 0;
  animation: cord-sway 3.6s ease-in-out infinite alternate;
}
.screen-pull-cord.is-grabbing { cursor: grabbing; }
.screen-pull-cord.is-grabbing,
.screen-pull-cord.is-autopull,
.screen-pull-cord.is-spent { animation: none; }
.screen-pull-cord:focus-visible {
  outline: 1px dashed var(--hidden-accent2);
  outline-offset: 8px;
}
.screen-pull-string {
  width: 2px;
  height: calc(50px + var(--pull));
  background: linear-gradient(180deg, rgba(236, 233, 255, 0.95), rgba(236, 233, 255, 0.55));
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.35);
}
.screen-pull-ring {
  width: 22px;
  height: 22px;
  margin-top: -1px;
  border-radius: 50%;
  border: 2px solid var(--hidden-accent);
  box-shadow: 0 0 10px rgba(255, 46, 136, 0.55), inset 0 0 6px rgba(255, 46, 136, 0.35);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.screen-pull-cord:hover .screen-pull-ring {
  transform: scale(1.08);
  box-shadow: 0 0 16px rgba(255, 46, 136, 0.8), inset 0 0 8px rgba(255, 46, 136, 0.5);
}
.screen-pull-cord.is-snapping .screen-pull-string {
  transition: height 0.5s cubic-bezier(0.16, 1.6, 0.4, 1);
}
.screen-pull-hint {
  position: absolute;
  top: 44px;
  right: calc(18% + 44px);
  font-family: var(--hidden-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--hidden-accent2);
  opacity: 0.6;
  white-space: nowrap;
  pointer-events: none;
}
@keyframes cord-sway {
  from { transform: rotate(2.4deg); }
  to   { transform: rotate(-2.4deg); }
}
@media (prefers-reduced-motion: reduce) {
  .screen-pull-cord { animation: none; }
  .screen-pull-slat { transition: none; }
}

/* The wall behind the screen: paints above the body background but
   below everything in #root (negative stacking level). */
.screen-wall {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  z-index: -1;
  background: #fafafa;
  pointer-events: none;
}

/* The roll itself: the whole app slides up and off like a released
   projector screen. Fixed elements are pinned to absolute by JS first.
   html/body backgrounds go transparent because an opaque body background
   would paint OVER the negative-z .screen-wall and hide the reveal. */
html.is-screen-rolling,
html.is-screen-rolling body { background: transparent !important; }
html.is-screen-rolling #root {
  transition: transform 1.05s cubic-bezier(0.65, -0.02, 0.85, 0.45);
  transform: translateY(calc(-100vh - 240px));
  pointer-events: none;
}

/* ============================================================
   BOARDING PASS — fun mode only
   A pass stub tucked into the page's right edge under the Skills
   band, styled in the Elsewhere palette as a teaser of where it
   leads. Dragging left tears it off along the perforation; the
   passport stamp (below) slams down; you board.
   --tear (px) is set from JS while dragging.
   ============================================================ */
.pass-zone {
  --tear: 0px;
  position: absolute;
  top: 0; /* set from JS: bottom of #skills */
  right: 0;
  z-index: 7; /* above .hidden (2) and flip bands (5) */
  height: 0;
  overflow: visible;
}
.boarding-pass {
  position: absolute;
  top: 0;
  right: -38px; /* tucked into the edge like a bookmark */
  width: 196px;
  display: block;
  padding: 12px 14px 10px;
  background: #f9cba3;
  border: 0;
  border-left: 1px solid rgba(37, 60, 66, 0.35);
  text-align: left;
  cursor: grab;
  touch-action: none;
  transform: translate(calc(var(--tear) * -1), calc(var(--tear) * 0.12)) rotate(-6deg);
  transform-origin: 100% 40%;
  box-shadow: -6px 8px 22px rgba(26, 44, 49, 0.28);
  animation: pass-sway 5.2s ease-in-out infinite alternate;
}
.boarding-pass.is-grabbing { cursor: grabbing; }
.boarding-pass.is-grabbing,
.boarding-pass.is-autotear,
.boarding-pass.is-snapping,
.boarding-pass.is-torn { animation: none; }
.boarding-pass:focus-visible {
  outline: 1px dashed #e81e30;
  outline-offset: 6px;
}
.pass-carrier {
  display: block;
  font-family: var(--hidden-mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  color: #253c42;
  opacity: 0.75;
}
.pass-route {
  display: block;
  margin-top: 5px;
  font-family: var(--hidden-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: #e81e30;
  white-space: nowrap;
}
.pass-meta {
  display: block;
  margin-top: 5px;
  font-family: var(--hidden-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  color: #253c42;
  opacity: 0.6;
  white-space: nowrap;
}
.pass-barcode {
  display: block;
  margin-top: 8px;
  height: 16px;
  background: repeating-linear-gradient(
    90deg,
    #253c42 0 2px, transparent 2px 5px,
    #253c42 5px 6px, transparent 6px 11px,
    #253c42 11px 14px, transparent 14px 17px
  );
  opacity: 0.85;
}
.pass-perf {
  position: absolute;
  top: 4px;
  bottom: 4px;
  right: 34px; /* the perforation sits roughly at the viewport edge */
  width: 0;
  border-left: 2px dashed rgba(37, 60, 66, 0.5);
}
/* the sliver left behind in the "book" after the tear */
.pass-remnant {
  position: absolute;
  top: 6px;
  right: 0;
  width: 7px;
  height: 74px;
  background: #f9cba3;
  border-left: 2px dashed rgba(37, 60, 66, 0.5);
  opacity: 0;
  transform: rotate(-6deg);
}
.pass-zone.is-torn .pass-remnant { opacity: 1; transition: opacity 0.2s 0.15s; }
.boarding-pass.is-snapping {
  transition: transform 0.5s cubic-bezier(0.16, 1.6, 0.4, 1);
}
.boarding-pass.is-torn {
  transition: transform 0.7s cubic-bezier(0.5, -0.15, 0.9, 0.6), opacity 0.55s 0.15s;
  transform: translate(-200px, 55vh) rotate(-38deg);
  opacity: 0;
  pointer-events: none;
}
.pass-hint {
  position: absolute;
  top: 96px;
  right: 218px;
  font-family: var(--hidden-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: #e81e30;
  opacity: 0.65;
  white-space: nowrap;
  pointer-events: none;
  transform: rotate(-6deg);
}
.pass-zone.is-torn .pass-hint { opacity: 0; }
@keyframes pass-sway {
  from { transform: translate(0, 0) rotate(-5deg); }
  to   { transform: translate(0, 2px) rotate(-7.2deg); }
}

/* ============================================================
   PASSPORT STAMP — the transition into /Elsewhere/
   Mounted imperatively by stampAndGo(); .is-stamped plays the
   slam. Reduced motion never mounts this (direct navigation).
   ============================================================ */
.stamp-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000; /* above the bubble cursor (9999) */
  display: grid;
  place-items: center;
  background: rgba(10, 10, 15, 0);
  transition: background 0.2s ease;
  pointer-events: all;
}
.stamp-overlay.is-stamped {
  background: rgba(10, 10, 15, 0.34);
  animation: stamp-shake 0.22s 0.24s;
}
.stamp {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: min(72vw, 350px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 4px solid #e81e30;
  position: relative;
  color: #e81e30;
  font-family: var(--hidden-mono);
  text-transform: uppercase;
  transform: scale(2.5) rotate(-3deg);
  opacity: 0;
}
.stamp::before {
  content: "";
  position: absolute;
  inset: 7px;
  border: 1.5px solid #e81e30;
  border-radius: 50%;
}
.stamp-overlay.is-stamped .stamp {
  transform: scale(1) rotate(-12deg);
  opacity: 0.95;
  transition: transform 0.24s cubic-bezier(0.2, 1.5, 0.4, 1), opacity 0.16s ease;
}
.stamp-word {
  font-size: clamp(26px, 7vw, 42px);
  font-weight: 700;
  letter-spacing: 0.12em;
}
.stamp-rule { width: 56%; height: 2px; background: currentColor; opacity: 0.85; }
.stamp-sub { font-size: clamp(14px, 3.4vw, 19px); letter-spacing: 0.34em; text-indent: 0.34em; }
.stamp-date { font-size: clamp(11px, 2.4vw, 14px); letter-spacing: 0.18em; opacity: 0.8; }
@keyframes stamp-shake {
  0% { transform: translate(0, 0); }
  30% { transform: translate(2px, -2px); }
  60% { transform: translate(-2px, 1px); }
  100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .boarding-pass { animation: none; }
}

/* ============================================================
   MOBILE — max-width: 768px
   Overrides only. All desktop styles are untouched.
   ============================================================ */
@media (max-width: 768px) {
  /* Boarding pass: smaller, tucked further in so it reads as a stub */
  .boarding-pass { width: 158px; right: -46px; padding: 10px 12px 8px; }
  .pass-perf { right: 40px; }
  .pass-hint { top: 80px; right: 150px; }


  /* --- Hide desktop nav entirely on mobile --- */
  .s-nav { display: none; }

  /* ---- Mobile sticky banner ---- */
  .s-nav-mobile {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 56px;
    padding: 0 20px;
    z-index: 60;
    background: rgba(245, 241, 235, 0.95);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--surface-line);
  }
  body[data-fun="true"] .s-nav-mobile {
    background: rgba(10, 10, 15, 0.95);
    border-bottom: 1px solid var(--hidden-accent);
  }

  .s-nav-mobile-mark {
    font-family: var(--surface-display);
    font-size: 15px;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--surface-ink);
    white-space: nowrap;
    justify-self: start;
  }
  body[data-fun="true"] .s-nav-mobile-mark {
    font-family: var(--hidden-mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--hidden-accent);
    text-shadow: 0 0 8px rgba(255, 46, 136, 0.35);
  }

  /* FunToggle sits in the centre column automatically */

  /* Burger button */
  .s-nav-burger {
    justify-self: end;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 40px;
    height: 40px;
    padding: 9px 9px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--surface-ink);
  }
  body[data-fun="true"] .s-nav-burger { color: var(--hidden-ink); }

  .s-nav-burger span {
    display: block;
    width: 22px;
    height: 2px;
    background: currentColor;
    border-radius: 1px;
    transition: transform 0.25s var(--ease), opacity 0.2s var(--ease);
    transform-origin: center;
  }
  .s-nav-burger.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .s-nav-burger.is-open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
  .s-nav-burger.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* ---- Full-screen overlay ---- */
  .s-nav-overlay {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 56px; left: 0; right: 0; bottom: 0;
    z-index: 59;
    background: rgba(245, 241, 235, 0.97);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-8px);
    transition: opacity 0.22s var(--ease),
                visibility 0s linear 0.22s,
                transform 0.22s var(--ease);
  }
  .s-nav-overlay.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    transition: opacity 0.22s var(--ease),
                visibility 0s,
                transform 0.22s var(--ease);
  }
  body[data-fun="true"] .s-nav-overlay {
    background: rgba(10, 10, 15, 0.97);
  }

  .s-nav-overlay-links {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
  }
  .s-nav-overlay-links a {
    display: block;
    font-family: var(--surface-display);
    font-size: 30px;
    font-weight: 400;
    letter-spacing: -0.01em;
    color: var(--surface-ink);
    padding: 12px 0;
    transition: color 0.18s;
  }
  .s-nav-overlay-links a:hover,
  .s-nav-overlay-links a:active { color: var(--surface-accent); }

  body[data-fun="true"] .s-nav-overlay-links a {
    font-family: var(--hidden-mono);
    font-size: 20px;
    font-weight: 400;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--hidden-ink-dim);
  }
  body[data-fun="true"] .s-nav-overlay-links a:hover,
  body[data-fun="true"] .s-nav-overlay-links a:active {
    color: var(--hidden-accent);
    text-shadow: 0 0 12px rgba(255, 46, 136, 0.5);
  }

  /* --- Surface container --- */
  .surface { padding-top: 56px; padding-bottom: 48px; }

  /* --- Hero: reduce tall desktop padding --- */
  .s-hero {
    padding: 80px 20px 48px;
    min-height: 75vh;
  }
  .s-hero-scrollcue { left: 20px; bottom: 18px; }
  .h-hero {
    padding: 80px 20px 48px;
    min-height: 75vh;
  }

  /* --- Generic sections --- */
  .s-section { padding: 60px 20px; }
  .h-section  { padding: 60px 20px; }

  /* --- Work rows: !important needed to beat the inline style in JSX --- */
  .s-work-row.flip-tile .flip-face--front,
  .s-work-row.flip-tile .flip-face--back .flip-face--back-inner {
    grid-template-columns: 40px 1fr 36px !important;
    gap: 16px !important;
  }
  .s-work-row.flip-tile .flip-face--front .s-work-kind,
  .s-work-row.flip-tile .flip-face--front .s-work-year,
  .s-work-row.flip-tile .flip-face--back .tile-back-meta,
  .s-work-row.flip-tile .flip-face--back .tile-back-year { display: none; }

  /* --- Work expand panel: stack on mobile --- */
  .work-expand-surface,
  body[data-fun="true"] .s-work-row.flip-tile:hover .work-expand-hidden,
  body[data-fun="true"] .s-work-row.flip-tile:focus-within .work-expand-hidden {
    flex-direction: column;
    gap: 20px;
  }
  .work-expand-visual { flex: unset; width: 100%; }
  .work-expand-visual img { height: 200px; }

  /* --- Experience items: !important to beat the inline style in JSX --- */
  .s-exp-item.flip-tile .flip-face--front,
  .s-exp-item.flip-tile .flip-face--back .flip-face--back-inner {
    grid-template-columns: 1fr !important;
    gap: 8px !important;
  }

  /* --- Publication items: stack year above content, beat inline style --- */
  .s-pub-item.flip-tile .flip-face--front,
  .s-pub-item.flip-tile .flip-face--back .flip-face--back-inner {
    grid-template-columns: 1fr 36px !important;
    gap: 6px !important;
  }
  .s-pub-item.flip-tile .flip-face--front .s-pub-year,
  .s-pub-item.flip-tile .flip-face--back .tile-back-year-tall {
    display: none;
  }

  /* --- Skills: single column so blocks breathe on a phone --- */
  .s-skills-grid,
  .h-skills-grid { grid-template-columns: 1fr; }

  /* --- Contact: reduce large desktop padding --- */
  .s-contact { padding: 80px 20px; }
  .h-contact  { padding: 80px 20px; }

  /* --- Contact grids (already 1fr at 700px, kept for 768px explicitness) --- */
  .s-contact-grid { grid-template-columns: 1fr; }
  .h-contact-grid { grid-template-columns: 1fr; }

  /* --- Contact values: allow long emails/URLs to wrap --- */
  .s-contact-link .value { white-space: normal; font-size: 18px; }
  .h-contact-link .value { font-size: 16px; }

  /* --- Contact headings: clamp down so they don't overflow on phones --- */
  .s-contact h2 { font-size: clamp(34px, 9vw, 60px); }
  .h-contact h2 { font-size: clamp(34px, 9vw, 60px); }

  /* --- Footers --- */
  .s-footer {
    padding: 24px 20px;
    flex-direction: column;
    gap: 8px;
  }
  .h-footer {
    padding: 24px 20px;
    flex-direction: column;
    gap: 8px;
  }

  /* ---- Touch hint bubble ---- */
  .touch-hint {
    display: flex;
    align-items: center;
    gap: 12px;
    position: fixed;
    bottom: 28px;
    left: 50%;
    z-index: 100;
    transform: translateX(-50%) translateY(10px);
    padding: 10px 22px;
    border-radius: 999px;
    background: rgba(10, 10, 15, 0.88);
    border: 1px solid var(--hidden-accent2);
    box-shadow:
      0 0 18px rgba(0, 240, 255, 0.14),
      inset 0 0 10px rgba(0, 240, 255, 0.04);
    font-family: var(--hidden-mono);
    font-size: 11px;
    letter-spacing: 0.12em;
    white-space: nowrap;
    color: var(--hidden-ink-dim);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  }
  .touch-hint.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }

  .touch-hint-text {
    color: var(--hidden-accent2);
  }

  .touch-hint-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--hidden-accent2);
    box-shadow: 0 0 8px rgba(0, 240, 255, 0.7);
    flex-shrink: 0;
    animation: touch-hint-pulse 1.8s ease-in-out infinite;
  }
  @keyframes touch-hint-pulse {
    0%, 100% { transform: scale(1);   opacity: 1; }
    50%       { transform: scale(1.5); opacity: 0.6; }
  }
}

/* ============================================================
   EASTER EGG — wordle trigger (fun mode only)
   ============================================================ */
.wordle-egg {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 48px;
  text-decoration: none;
  opacity: 0.18;
  transition: opacity 0.2s, width 0.2s;
}
.wordle-egg:hover {
  opacity: 1;
  width: 36px;
  animation: glitch-text 0.4s steps(1) infinite;
}
.wordle-egg-icon {
  font-size: 16px;
  color: var(--hidden-accent);
  line-height: 1;
  filter: drop-shadow(0 0 4px var(--hidden-accent));
}

/* The wordle shred: the page is consumed by a radial wave of flipping
   letter tiles spreading from the click point (wordleShred in the JSX
   builds the grid + per-tile animation-delay). Colours mirror
   /wordle.html so the landing feels continuous. */
.wordle-shred {
  position: fixed;
  inset: 0;
  z-index: 10001; /* same shelf as the fox portal — they can't co-occur */
  display: grid;
  grid-template-columns: repeat(var(--cols), var(--tile));
  grid-auto-rows: var(--tile);
  overflow: hidden;
  perspective: 900px;
  pointer-events: all;
}
.wordle-shred span {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #d6e7ce;                    /* wordle.html --bg-2 */
  border: 1px solid rgba(42, 61, 46, 0.15);
  color: #5a7a5e;                          /* wordle.html --ink-dim */
  font-family: var(--surface-mono);
  font-weight: 700;
  font-size: 26px;
  text-transform: uppercase;
  opacity: 0;
  transform: rotateX(90deg);
  backface-visibility: hidden;
  animation: shred-flip 0.34s cubic-bezier(0.2, 0.9, 0.3, 1.2) forwards;
}
.wordle-shred .is-green  { background: #4a7c59; border-color: #4a7c59; color: #fff; }
.wordle-shred .is-yellow { background: #c9a227; border-color: #c9a227; color: #fff; }
.wordle-shred .is-grey   { background: #a8b8aa; border-color: #a8b8aa; color: #fff; }
@keyframes shred-flip {
  from { opacity: 0; transform: rotateX(90deg); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: rotateX(0deg); }
}

/* ============================================================
   EASTER EGG — the RPG fox patrols the projector-slat seam
   (fun mode only; lives inside .screen-pull-zone, feet on the
   slat line). JS drives translate3d runs + sprite frames.
   Hover: front-facing hop. Click: portal bloom (below).
   ============================================================ */
.fox-runner {
  position: absolute;
  top: -58px; /* feet on the slat line at the zone's top edge */
  left: 0;
  z-index: 2;
  width: 48px;
  height: 64px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform: translate3d(-96px, 0, 0); /* parked off-stage until a run */
  will-change: transform;
}
.fox-runner:focus-visible {
  outline: 1px dashed var(--hidden-accent2);
  outline-offset: 6px;
}
.fox-runner-sprite {
  display: block;
  width: 48px;
  height: 64px;
  background: url("/RPG/fox-sprite.png?v=2") no-repeat -48px 0;
  image-rendering: pixelated;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.5));
}
.fox-runner.is-waiting .fox-runner-sprite {
  animation: fox-hop 0.55s ease-in-out infinite;
}
@keyframes fox-hop {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* The bubble becomes the door: the destination iframe is clipped to a
   circle that blooms from the fox and swallows the viewport, with a pink
   ring racing along the clip edge (echoes the peek-bubble cursor). */
.fox-portal-wall {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  z-index: 10001; /* above the bubble cursor (9999) and the stamp (10000) */
  background: #1c2b1a; /* the RPG's ground green while it boots */
  clip-path: circle(0px at var(--px, 50%) var(--py, 50%));
  filter: drop-shadow(0 0 30px rgba(255, 46, 136, 0.7));
}
.fox-portal-wall.is-open {
  clip-path: circle(150vmax at var(--px, 50%) var(--py, 50%));
  transition: clip-path 0.95s cubic-bezier(0.3, 0, 0.15, 1);
}
.fox-portal-ring {
  position: fixed;
  left: var(--px, 50%);
  top: var(--py, 50%);
  z-index: 10002;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--hidden-accent);
  box-shadow: 0 0 22px rgba(255, 46, 136, 0.8), inset 0 0 10px rgba(0, 240, 255, 0.4);
  transform: translate(-50%, -50%);
  opacity: 0.95;
  pointer-events: none;
}
.fox-portal-ring.is-open {
  width: 320vmax;
  height: 320vmax;
  opacity: 0;
  transition: width 0.95s cubic-bezier(0.3, 0, 0.15, 1),
              height 0.95s cubic-bezier(0.3, 0, 0.15, 1),
              opacity 0.8s ease 0.2s;
}
@media (prefers-reduced-motion: reduce) {
  .fox-runner.is-waiting .fox-runner-sprite { animation: none; }
}
