/* home.css — the hero page only (bubble menu, brain intro, ambient layer).
   Loaded exclusively by home.html. Tokens come from base.css.
   Current behavior: see prototypes/home-brain-v4.html header comment
   (v4.11 = reference implementation; this file is its production form). */

body.page-home { overflow: hidden; }

/* ---------- layers ---------- */
#view-home { position: fixed; inset: var(--header-h) 0 0 0; }
#backLayer   { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
/* mouse-still: text layer pops above the bubbles (z-swap is instant;
   the .welcome socket animation below sells the "puzzle piece"
   sliding up-and-out / back down-and-in). pointer-events stays none so
   bubbles remain draggable underneath.
   DESKTOP ONLY — on mobile the welcome always stays behind the bubbles. */
@media (min-width: 769px) {
  #view-home.mouse-still #backLayer { z-index: 4; }
}

/* Film grain overlay — breaks up pure white with subtle noise.
   Multiply blend on light background = gentle darkened grain specks. */
#grainOverlay {
  position: fixed; inset: 0; z-index: 999;
  pointer-events: none;
  filter: url(#grain-noise);
  opacity: 0.055;
  mix-blend-mode: multiply;
}
/* Mobile: disable grain — feTurbulence is a perf killer on phone GPUs */
@media (max-width: 768px) {
  #grainOverlay { display: none; }
}
#fieldLayer  { position: absolute; inset: 0; z-index: 3; touch-action: none; display: none; }

/* morph canvas — sits on top of field layer, renders SVG outlines */
#morphCanvas {
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
  width: 100%; height: 100%;
}

/* ---------- glass layer: frosted discs under the morph canvas ----------
   Bubbles that drift over the welcome card frost the text behind them,
   so the overlap reads as deliberate glass instead of clashing layers.
   Desktop only — backdrop-filter on 6 moving discs is a GPU cost on
   mobile, and mobile keeps the card behind the bubbles at all times. */
@media (hover: hover) and (pointer: fine) {
  #glassLayer {
    position: absolute; inset: 0; z-index: 2;
    pointer-events: none;
  }
  .glass-disc {
    position: absolute; left: 0; top: 0;
    border-radius: 50%;
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

/* ---------- back layer: welcome + quotes ---------- */
.welcome {
  position: absolute; left: 50%; top: 42%; transform: translate(-50%, -50%);
  text-align: center; max-width: 40rem;
  /* white card so the text stays readable under drifting bubbles.
     opacity gated until revealWelcome — an empty card pre-burst would
     show behind the brain otherwise. */
  background: var(--surface);
  /* border only exists when popped out of the socket — base state is a
     flush, borderless card sitting in the page (v4.11) */
  border: 1px solid transparent;
  border-radius: 22px;
  padding: 28px 36px;
  opacity: 0;
  box-shadow: 0 0 0 rgba(32, 38, 58, 0);
  transition: opacity 400ms ease, box-shadow 550ms ease, border-color 550ms ease;
}
/* Desktop: socket pop animation */
@media (min-width: 769px) {
  .welcome { animation: socket-in 480ms cubic-bezier(0.55, 0, 0.55, 0.2) both; }
}
#view-home.mouse-still .welcome {
  animation: socket-out 550ms cubic-bezier(0.22, 1, 0.36, 1) both;
  border-color: var(--border);
  box-shadow: 0 16px 44px rgba(32, 38, 58, 0.16);
}
/* socket twist: the card wrenches slightly clockwise as it pops out of
   its socket, then settles level; counter-twist on the way back in.
   Transform lives in keyframes (not a transition) so rotation only
   exists mid-motion, never as a static tilt. */
@keyframes socket-out {
  0%   { transform: translate(-50%, -50%) translateY(0) rotate(0deg) scale(1); }
  45%  { transform: translate(-50%, -50%) translateY(-13px) rotate(2.4deg) scale(1.032); }
  100% { transform: translate(-50%, -50%) translateY(-10px) rotate(0deg) scale(1.025); }
}
@keyframes socket-in {
  0%   { transform: translate(-50%, -50%) translateY(-10px) rotate(0deg) scale(1.025); }
  50%  { transform: translate(-50%, -50%) translateY(-3px) rotate(-1.6deg) scale(1.008); }
  100% { transform: translate(-50%, -50%) translateY(0) rotate(0deg) scale(1); }
}
.wl-line { opacity: 0; }
.wl-row { display: block; }
.wl-hi { font-size: clamp(1.05rem, 2.4vw, 1.5rem); color: var(--muted); font-weight: 500; letter-spacing: 0.04em; }
.wl-name { white-space: nowrap; font-size: clamp(1.7rem, 5.2vw, 3.1rem); }
.wl-word { display: inline-block; white-space: nowrap; }
.wl-ch { display: inline-block; will-change: transform, opacity; }
/* rainbow text must NOT get per-character compositor layers —
   Chrome's background-clip:text can't composite through them */
.rainbow .wl-ch { will-change: auto; }
.welcome h1 { font-size: clamp(1.9rem, 4.6vw, 3.2rem); margin-bottom: 18px; }
.rainbow {
  background: linear-gradient(90deg, #2a3a92, #2f9be8, #6a67ac, #d485b5, #f2945a, #2a3a92);
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: rainbow-slide 9s linear infinite;
}
@keyframes rainbow-slide { to { background-position: 300% 0; } }
.welcome .wl-lede { font-size: 1.15rem; color: var(--text); }
.welcome .wl-tag { font-family: var(--font-display); font-weight: 500; color: var(--muted); margin-top: 12px; }
.welcome .wl-explore { color: var(--muted); margin-top: 12px; font-size: 0.95rem; }
.welcome .wl-explore strong { color: var(--orange); letter-spacing: 0.1em; }

.quote {
  position: absolute; max-width: 320px;
  color: var(--muted); font-style: italic; font-size: 0.95rem; line-height: 1.5;
  opacity: 0; transform: scale(0.85);
  /* same white-card treatment as the showcase images (v4.11) */
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 14px 18px;
  box-shadow: 0 6px 18px rgba(32, 38, 58, 0.10);
}
.quote .q-who {
  display: block; margin-top: 6px; font-style: normal;
  font-size: 0.78rem; color: color-mix(in srgb, var(--muted) 75%, var(--bg));
}

/* ambient showcase images — same fade cycle as quotes, in a small
   white polaroid-ish card with a slight random tilt (set via --tilt) */
.showcase-img {
  position: absolute; width: 150px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 10px;
  opacity: 0; transform: scale(0.85) rotate(var(--tilt, 0deg));
  box-shadow: 0 6px 18px rgba(32, 38, 58, 0.10);
}
.showcase-img img { display: block; width: 100%; image-rendering: pixelated; }
.showcase-img.photo img { image-rendering: auto; } /* rendered art, not sprites */
.showcase-img .s-cap {
  display: block; margin-top: 6px; text-align: center;
  font-family: var(--font-display); font-size: 0.72rem; color: var(--muted);
}

/* ---------- intro layer: the brain ---------- */
#introLayer {
  position: absolute; inset: 0; z-index: 4;
  display: flex; align-items: center; justify-content: center;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  pointer-events: none; /* trigger zone is the brain only, not the viewport */
}
#introLayer:focus-visible { outline: none; }
#brainPulse {
  animation: brain-breathe 3.2s ease-in-out infinite;
  pointer-events: auto; cursor: pointer;
  outline: none; /* Chrome rings tabindex'd buttons on click — the brain
                    has breathe/hover/wobble affordance, no ring needed */
}
@keyframes brain-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.035); } }
#brainHover { transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1); }
#brainPulse:hover #brainHover { transform: scale(1.08); }
#brainSvg { display: block; overflow: visible !important; }
#brainSvg .brain-base { fill: #ffffff; stroke: #20263a; stroke-width: 6; }
/* dark mode: transparent brain with brighter stroke — wireframe look */
:root[data-theme="dark"] #brainSvg .brain-base { fill: transparent; stroke: #4a5580; }
#brainSvg .conduit-g {
  opacity: 0.25;
  transform-box: fill-box; transform-origin: center;
}

/* ---------- bubbles ---------- */
.phys-bubble {
  position: absolute; left: 0; top: 0;
  cursor: grab; user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* DOM shell is invisible — canvas renders the morphing outline */
}
/* Desktop: will-change for smooth dragging. Mobile: kill (GPU layer overhead). */
@media (min-width: 769px) {
  .phys-bubble { will-change: transform; }
}
.phys-bubble.dragging { cursor: grabbing; }
.phys-bubble .b-inner {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; border-radius: 50%;
}
.phys-bubble .b-text {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center; padding: 22px; will-change: transform;
  text-shadow: 0 0 12px var(--bg), 0 0 8px var(--bg);
  pointer-events: none;
}
/* collision state: collide-ripple owns border-radius + box-shadow for
   0.7s (listed last so it wins box-shadow over glow-pulse). fill-mode
   "both" holds the 100% circle frame until the class flips back —
   closes the one-frame square-flash gap at animation end. */
.b-inner.rippling {
  animation: glow-pulse 4s ease-in-out infinite, collide-ripple 0.7s ease-out 1 both;
}
@keyframes glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c) 25%, transparent); }
  50%      { box-shadow: 0 0 18px 4px color-mix(in srgb, var(--c) 14%, transparent); }
}
@keyframes morph {
  0%, 100% { border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%; }
  33%      { border-radius: 52% 48% 51% 49% / 49% 51% 49% 51%; }
  66%      { border-radius: 48% 52% 49% 51% / 51% 49% 52% 48%; }
}
/* quick contour wobble + glow flash on real hits. Transform-free so it
   never fights the JS sway rotation owning this element's transform. */
@keyframes collide-ripple {
  0%   { border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%;
         box-shadow: 0 0 0 0 color-mix(in srgb, var(--c) 45%, transparent); }
  30%  { border-radius: 42% 58% 61% 39% / 56% 44% 60% 40%;
         box-shadow: 0 0 0 10px color-mix(in srgb, var(--c) 22%, transparent); }
  60%  { border-radius: 57% 43% 40% 60% / 44% 58% 42% 56%;
         box-shadow: 0 0 0 5px color-mix(in srgb, var(--c) 12%, transparent); }
  100% { border-radius: 50% 50% 50% 50% / 50% 50% 50% 50%;
         box-shadow: 0 0 0 0 color-mix(in srgb, var(--c) 0%, transparent); }
}
.b-text {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center; padding: 22px; will-change: transform;
}
.b-title { font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; }
.b-sub { font-size: 0.82rem; color: var(--muted); max-width: 20ch;
         opacity: 0; transition: opacity 0.3s ease; }
/* subtext reveals on hover/focus — desktop only (mobile hides .b-sub below) */
.phys-bubble:hover .b-sub,
.phys-bubble:focus-visible .b-sub { opacity: 1; }
.b-ext { font-size: 0.72rem; font-weight: 600; color: var(--c); }

#replayIntro {
  position: absolute; right: 16px; bottom: 14px; z-index: 60;
  background: none; border: 1px solid var(--border); border-radius: 999px;
  color: var(--muted); font-size: 0.95rem; line-height: 32px;
  width: 34px; height: 34px; padding: 0; text-align: center;
  cursor: pointer; display: none;
}
#replayIntro:hover { color: var(--text); border-color: var(--muted); }

/* dark mode: welcome card background goes translucent — text floats.
   subtle glow replaces the solid card shadow when popped. */
:root[data-theme="dark"] .welcome {
  background: transparent;
  box-shadow: none;
  border-color: transparent;
}
/* dark mode glass: the welcome card is transparent, so a pure blur has
   nothing structured behind it to frost — the disc reads as invisible.
   A light-source gradient + rim give the frost body on dark. */
:root[data-theme="dark"] .glass-disc {
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--surface) 72%, transparent) 0%,
    color-mix(in srgb, var(--surface) 38%, transparent) 100%);
  border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
:root[data-theme="dark"] #view-home.mouse-still .welcome {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 0 50px rgba(100, 130, 200, 0.08);
}
@media (max-width: 768px) {
  /* ---- welcome: always popped out over bubbles ---- */
  #backLayer { z-index: 4; }
  .welcome {
    max-width: 88vw;
    padding: 14px 16px;
    border-radius: 16px;
    top: 36%;
    border-color: var(--border);
    box-shadow: 0 16px 44px rgba(32, 38, 58, 0.16);
    animation: none;
  }
  /* dark mode: keep the surface fill + glow — the card is always
     popped out on mobile, so it must block the bubbles behind it */
  :root[data-theme="dark"] .welcome {
    background: var(--surface);
    border-color: var(--border);
    box-shadow: 0 0 50px rgba(100, 130, 200, 0.08);
  }
  .welcome h1 { margin-bottom: 6px; }
  .wl-hi { font-size: clamp(0.78rem, 2vw, 1rem); }
  .wl-name { font-size: clamp(1.15rem, 4.2vw, 2rem); }
  .welcome .wl-lede { font-size: 0.76rem; line-height: 1.3; }
  .welcome .wl-tag { margin-top: 4px; font-size: 0.7rem; }
  .welcome .wl-explore { margin-top: 4px; font-size: 0.68rem; }
  .showcase-img { width: 90px; padding: 6px; border-radius: 10px; }
  .showcase-img .s-cap { font-size: 0.6rem; }

  /* ---- quotes: smaller ---- */
  .quote { font-size: 0.76rem; padding: 10px 14px; border-radius: 10px; }
  .quote .q-who { font-size: 0.66rem; }

  /* ---- bubble text: smaller, no subtitle ---- */
  .phys-bubble .b-text {
    padding: 8px;
    gap: 1px;
    text-shadow: 0 0 14px var(--bg), 0 0 10px var(--bg), 0 0 6px var(--bg);
  }
  .b-title { font-size: 0.8rem; }
  .b-sub { display: none; }
  .b-ext { font-size: 0.6rem; }

  /* ---- perf: kill glow-pulse animation (runs continuously) ---- */
  .b-inner.rippling {
    animation: collide-ripple 0.7s ease-out 1 both;
  }

  /* ---- brain: smaller on mobile ---- */
  #brainSvg { width: 200px; height: 200px; }

  /* ---- replay button: smaller ---- */
  #replayIntro { width: 30px; height: 30px; line-height: 28px; right: 10px; bottom: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .b-inner, .b-inner.rippling { animation: none; border-radius: 50%; }
  .welcome { animation: none !important; }
  #brainPulse { animation: none; }
  .rainbow { animation: none; }
  *, *::before, *::after { transition-duration: 0.01ms !important; }
}

/* ── dark mode: shadows become glows ── */
:root[data-theme="dark"] .quote,
:root[data-theme="dark"] .showcase-img {
  box-shadow: 0 0 18px rgba(100, 130, 200, 0.06);
}

/* ── playfulness rebalance: intro ring, skip, hint, footer tab, mobile menu ── */

/* countdown ring around the full viewport border during intro */
.intro-ring {
  position: fixed; inset: 0; z-index: 4;
  pointer-events: none;
}
.intro-ring rect { stroke: var(--indigo); }

/* first-visit hint: pulsing ripple on one bubble */
.phys-bubble.attn::after {
  content: ''; position: absolute; inset: -14px; border-radius: 50%;
  border: 2px solid var(--c, var(--indigo)); opacity: 0;
  animation: attn-ring 1.6s ease-out infinite; pointer-events: none;
}
@keyframes attn-ring {
  0% { transform: scale(0.82); opacity: 0.8; }
  100% { transform: scale(1.35); opacity: 0; }
}

/* scroll-reveal footer tab */
.foot-tab {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 30;
  background: var(--surface); border-top: 1px solid var(--border);
  border-radius: 22px 22px 0 0;
  padding: 14px 20px 28px;
  transform: translateY(105%); opacity: 0;
  transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1), opacity 700ms ease;
  box-shadow: 0 -10px 30px rgba(0,0,0,0.12);
}
.foot-tab.open { transform: translateY(0); opacity: 1; }
.ft-handle { width: 40px; height: 4px; border-radius: 2px; background: var(--border); margin: 0 auto 12px; }
.ft-nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 18px; }
.ft-nav a {
  color: var(--text); text-decoration: none;
  font-family: var(--font-display); font-weight: 700; font-size: 0.9rem;
}
.ft-nav a:hover { color: var(--warm); }
.ft-copy { text-align: center; color: var(--muted); font-size: 0.75rem; margin-top: 10px; }

/* mobile menu */
.mobile-menu-btn {
  display: none; position: absolute; right: 16px; bottom: 16px; z-index: 40;
  width: 54px; height: 54px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--indigo); color: #fff; font-size: 1.2rem;
  box-shadow: 0 8px 24px rgba(42,58,146,0.35);
}
@media (max-width: 768px) { .mobile-menu-btn.show { display: block; } }
.mobile-menu-sheet {
  display: none; position: absolute; left: 0; right: 0; bottom: 0; z-index: 45;
  background: var(--surface); border-top: 1px solid var(--border);
  border-radius: 20px 20px 0 0; padding: 16px 20px 28px;
  box-shadow: 0 -8px 30px rgba(0,0,0,0.15);
}
.mobile-menu-sheet.open { display: block; animation: sheet-rise 280ms ease-out both; }
@keyframes sheet-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.mm-pill {
  display: block; width: 100%; text-align: left;
  font-family: var(--font-display); font-weight: 700;
  color: var(--text); background: var(--bg);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 11px 18px; margin-bottom: 9px; cursor: pointer; font-size: 0.95rem;
}

