// a11y-scenes.jsx — "§ 04 · accessibility" focus-ring tour (15s loop)
// Emani-inspired Shopify Plus storefront. Amber focus ring jumps through
// interactive elements in correct tab order, labeled with WCAG success criteria.
// Focus-ring positions use DOM refs so they're pixel-aligned to the real elements.

const A_PALETTE = {
  cream:    '#f5f0e8',
  creamDk:  '#ebe4d6',
  creamLt:  '#faf6ed',
  paper:    '#f7f2ea',
  ink:      '#0f1713',
  ink70:    'rgba(15,23,19,0.70)',
  ink55:    'rgba(15,23,19,0.55)',
  ink40:    'rgba(15,23,19,0.40)',
  ink25:    'rgba(15,23,19,0.25)',
  ink12:    'rgba(15,23,19,0.12)',
  moss700:  '#32553f',
  moss600:  '#3f6b54',
  moss500:  '#4d7e65',
  moss400:  '#6fa37a',
  moss300:  '#93b89a',
  moss200:  '#b8cdbb',
  moss100:  '#d7e1d4',
  moss050:  '#e8efe6',
  amber:    '#cd8a4b',
  amberSoft:'#e2a568',
  amberGlow:'rgba(205,138,75,0.32)',
  // Emani-specific accents (inspired by screenshot)
  bar:      '#5d6b54', // announcement bar olive
  sage:     '#f0efe8', // product image background sage
};
const A_FONTS = {
  display: '"Space Grotesk", system-ui, sans-serif',
  serif:   '"Instrument Serif", Georgia, serif',
  mono:    '"JetBrains Mono", ui-monospace, monospace',
};

const aClamp = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v));
const aEase  = (t) => 1 - Math.pow(1 - t, 3);

// ── Timing ─────────────────────────────────────────────────────────────
// 7 focus stops, each ~1.3s visible. Brief: nav→hero CTA→cards→form→submit.
// We map 7 stops across the Emani layout:
//   1. SHOP nav dropdown          (1.2-2.6s)   §2.4.7 Focus Visible · AA
//   2. 3-STEP SYSTEM nav link     (2.6-4.0s)   §2.4.11 Focus Not Obscured · AA
//   3. SKIN QUIZ pill (hero CTA)  (4.0-5.4s)   §2.5.8 Target Size · AA
//   4. Discover button (hero)     (5.4-6.8s)   §2.4.3 Focus Order · A
//   5. Product card (serum)       (6.8-8.4s)   §1.3.1 Info & Relationships · A
//   6. Email input (form)         (8.4-10.2s)  §4.1.2 Name Role Value · A
//   7. Subscribe submit           (10.2-11.6s) §3.3.2 Labels or Instructions · A
const FOCUS_STOP_DEFS = [
  { id: 'nav-shop',     tEnter: 1.2,  tExit: 2.6,  wcag: '2.4.7 Focus Visible',            level: 'AA', tags: ['focusable', 'visible'] },
  { id: 'nav-step',     tEnter: 2.6,  tExit: 4.0,  wcag: '2.4.11 Focus Not Obscured',      level: 'AA', tags: ['current page'] },
  { id: 'skin-quiz',    tEnter: 4.0,  tExit: 5.4,  wcag: '2.5.8 Target Size Minimum',      level: 'AA', tags: ['44 × 44 px'] },
  { id: 'discover',     tEnter: 5.4,  tExit: 6.8,  wcag: '2.4.3 Focus Order',              level: 'A',  tags: ['order matches visual'] },
  { id: 'product-card', tEnter: 6.8,  tExit: 8.4,  wcag: '1.3.1 Info & Relationships',     level: 'A',  tags: ['semantic · role=link'] },
  { id: 'email',        tEnter: 8.4,  tExit: 10.2, wcag: '4.1.2 Name, Role, Value',        level: 'A',  tags: ['label associated'] },
  { id: 'subscribe',    tEnter: 10.2, tExit: 11.6, wcag: '3.3.2 Labels or Instructions',   level: 'A',  tags: ['visible label'] },
];

const TRAIL_START = 11.6;
const TRAIL_END   = 13.8;
const REVERSE_START_A = 14.0;
const aReverseAlpha = (t) => t < REVERSE_START_A ? 0 : (t - REVERSE_START_A) / (15 - REVERSE_START_A);

// ── Refs registry (shared across components) ───────────────────────────
// Each focusable element registers via data-focus-id="<id>".
// FocusRing + BreadcrumbTrail read getBoundingClientRect from the DOM.

function useFocusRects() {
  // Returns a function that reads the current rects for all focus IDs,
  // relative to the stage's 1920x1080 canvas.
  const [rects, setRects] = React.useState({});
  const scan = React.useCallback(() => {
    const stage = document.querySelector('[data-a11y-stage]');
    if (!stage) return;
    const stageRect = stage.getBoundingClientRect();
    const scale = stageRect.width / 1920;
    if (scale < 0.01) return;
    const next = {};
    for (const def of FOCUS_STOP_DEFS) {
      const el = stage.querySelector(`[data-focus-id="${def.id}"]`);
      if (!el) continue;
      const r = el.getBoundingClientRect();
      next[def.id] = {
        x: (r.left - stageRect.left) / scale,
        y: (r.top  - stageRect.top)  / scale,
        w: r.width  / scale,
        h: r.height / scale,
      };
    }
    setRects(next);
  }, []);
  React.useLayoutEffect(() => {
    scan();
    const id = setInterval(scan, 500);
    window.addEventListener('resize', scan);
    return () => { clearInterval(id); window.removeEventListener('resize', scan); };
  }, [scan]);
  return rects;
}

// ── Film grain ─────────────────────────────────────────────────────────
function AFilmGrain({ opacity = 0.07 }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, pointerEvents: 'none',
      opacity, mixBlendMode: 'multiply',
      backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.14  0 0 0 0 0.12  0 0 0 0 0.08  0 0 0 1 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>")`,
      backgroundSize: '220px 220px',
    }} />
  );
}

// ── Corner chrome ──────────────────────────────────────────────────────
function ACornerChrome() {
  const time = useTime();
  const pulse = 0.5 + 0.5 * Math.sin(time * Math.PI * 1.1);

  return (
    <>
      <img
        src="assets/digital-heroes-logo.png"
        alt=""
        style={{
          position: 'absolute', left: 56, top: 44,
          height: 52, width: 'auto',
          opacity: 0.42,
          pointerEvents: 'none',
          zIndex: 20,
        }}
      />
      <div style={{
        position: 'absolute', right: 56, top: 58,
        display: 'flex', alignItems: 'center', gap: 10,
        fontFamily: A_FONTS.mono,
        fontSize: 12, letterSpacing: '0.16em',
        color: A_PALETTE.ink70,
        textTransform: 'uppercase',
        zIndex: 20,
      }}>
        <span>§ tab key · live</span>
        <span style={{
          display: 'inline-block', width: 6, height: 6, borderRadius: 3,
          background: A_PALETTE.amber, opacity: 0.4 + 0.6 * pulse,
          boxShadow: `0 0 ${5+8*pulse}px ${A_PALETTE.amberSoft}`,
        }}/>
      </div>
      <div style={{
        position: 'absolute', right: 56, bottom: 56,
        fontFamily: A_FONTS.mono,
        fontSize: 12, letterSpacing: '0.14em',
        color: A_PALETTE.ink70,
        textTransform: 'uppercase',
        opacity: 0.75,
        zIndex: 20,
      }}>
        § 04 · accessibility
      </div>
      <div style={{
        position: 'absolute', left: 56, bottom: 56,
        fontFamily: A_FONTS.mono,
        fontSize: 12, letterSpacing: '0.14em',
        color: A_PALETTE.ink40,
        zIndex: 20,
      }}>
        fig.&nbsp;&nbsp;04·i — emani.com · keyboard tour
      </div>
    </>
  );
}

// ── Section title ──────────────────────────────────────────────────────
function ASectionTitle() {
  const time = useTime();
  const rev = aReverseAlpha(time);
  const alpha = aClamp(time / 0.6);
  let out = 1;
  if (time >= TRAIL_START - 0.4) out = aClamp((TRAIL_START - 0.1 - time) / 0.4);
  const a = alpha * out * (1 - rev);
  if (a < 0.01) return null;

  return (
    <div style={{
      position: 'absolute',
      left: 0, right: 0, top: 102,
      textAlign: 'center',
      opacity: a,
      transition: 'none',
      zIndex: 20,
      pointerEvents: 'none',
    }}>
      <div style={{
        fontFamily: A_FONTS.mono,
        fontSize: 11, letterSpacing: '0.22em',
        color: A_PALETTE.moss600, textTransform: 'uppercase',
        marginBottom: 8,
      }}>
        § 04 · accessibility · emani.com
      </div>
      <div style={{
        fontFamily: A_FONTS.display,
        fontWeight: 600, fontSize: 40,
        letterSpacing: '-0.035em',
        color: A_PALETTE.ink, lineHeight: 1,
      }}>
        keyboard first,{' '}
        <span style={{
          fontFamily: A_FONTS.serif, fontStyle: 'italic',
          fontWeight: 400, color: A_PALETTE.moss600,
          letterSpacing: '-0.02em',
        }}>
          always
        </span>
        .
      </div>
    </div>
  );
}

// ── EMANI landing page (static) ────────────────────────────────────────
// Built to match the Emani screenshot: olive announcement bar → white header
// with logo + nav + icons → hero "Foundation Reimagined" with sage product shot.
// All focusable targets have data-focus-id so FocusRing can align via DOM refs.

function EmaniLogoSVG() {
  // Simple flower-like glyph approximating the emani mark + wordmark "EMANI"
  return (
    <svg width="130" height="30" viewBox="0 0 130 30" style={{ display: 'block' }}>
      {/* flower/petal mark */}
      <g transform="translate(4, 5)">
        <circle cx="10" cy="10" r="2" fill={A_PALETTE.ink}/>
        {[0, 45, 90, 135, 180, 225, 270, 315].map((deg, i) => (
          <line
            key={i} x1="10" y1="10"
            x2={10 + 8*Math.cos(deg * Math.PI / 180)}
            y2={10 + 8*Math.sin(deg * Math.PI / 180)}
            stroke={A_PALETTE.ink} strokeWidth="1.2" strokeLinecap="round"
          />
        ))}
      </g>
      <text x="30" y="22"
        fontFamily={A_FONTS.display}
        fontSize="22" fontWeight="700"
        letterSpacing="0.08em"
        fill={A_PALETTE.ink}>
        EMANI
      </text>
    </svg>
  );
}

function EmaniPage() {
  const time = useTime();
  const rev = aReverseAlpha(time);
  const appear = aClamp(time / 0.8) * (1 - rev * 0.5);
  if (appear < 0.01) return null;

  return (
    <div style={{
      position: 'absolute',
      left: 120, top: 186,
      width: 1680,
      background: '#ffffff',
      borderRadius: 8,
      boxShadow: `0 10px 40px rgba(15,23,19,0.08), 0 1px 2px rgba(15,23,19,0.05)`,
      overflow: 'hidden',
      border: `1px solid ${A_PALETTE.ink12}`,
      opacity: appear,
      transition: 'none',
      transformOrigin: 'top center',
    }}>
      {/* Announcement bar */}
      <div style={{
        background: A_PALETTE.bar,
        color: '#ffffff',
        fontFamily: A_FONTS.display, fontWeight: 500,
        fontSize: 13, letterSpacing: '0.02em',
        padding: '8px 32px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <div style={{ fontSize: 14, opacity: 0.85 }}>‹</div>
        <div>Free USA shipping $75+</div>
        <div style={{ display: 'flex', gap: 14, alignItems: 'center', fontSize: 13, opacity: 0.9 }}>
          <span>›</span>
          <span>X</span>
          <span>f</span>
          <span>i</span>
          <span>p</span>
          <span>♪</span>
          <span>▶</span>
        </div>
      </div>

      {/* Header / nav */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '14px 36px',
        borderBottom: `1px solid ${A_PALETTE.ink12}`,
        background: '#ffffff',
      }}>
        <EmaniLogoSVG />
        <div style={{ display: 'flex', gap: 36, alignItems: 'center' }}>
          <div
            data-focus-id="nav-shop"
            style={{
              fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 14,
              letterSpacing: '0.08em', color: A_PALETTE.ink,
              textTransform: 'uppercase',
              padding: '6px 4px',
              display: 'flex', alignItems: 'center', gap: 4,
            }}>
            SHOP <span style={{ fontSize: 10, opacity: 0.6 }}>∨</span>
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 14,
            letterSpacing: '0.08em', color: A_PALETTE.ink,
            textTransform: 'uppercase',
            padding: '6px 4px',
            display: 'flex', alignItems: 'center', gap: 4,
          }}>
            BEST SELLERS <span style={{ fontSize: 10, opacity: 0.6 }}>∨</span>
          </div>
          <div
            data-focus-id="nav-step"
            style={{
              fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 14,
              letterSpacing: '0.08em', color: A_PALETTE.moss600,
              textTransform: 'uppercase',
              padding: '6px 4px',
              borderBottom: `2px solid ${A_PALETTE.moss600}`,
            }}>
            3-STEP SYSTEM
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 14,
            letterSpacing: '0.08em', color: A_PALETTE.ink,
            textTransform: 'uppercase',
            padding: '6px 4px',
            display: 'flex', alignItems: 'center', gap: 4,
          }}>
            SHOP BY CONCERN <span style={{ fontSize: 10, opacity: 0.6 }}>∨</span>
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 14,
            letterSpacing: '0.08em', color: A_PALETTE.ink,
            textTransform: 'uppercase',
            padding: '6px 4px',
            display: 'flex', alignItems: 'center', gap: 4,
          }}>
            LEARN <span style={{ fontSize: 10, opacity: 0.6 }}>∨</span>
          </div>
          {/* Skin Quiz pill */}
          <div
            data-focus-id="skin-quiz"
            style={{
              background: A_PALETTE.ink,
              color: '#ffffff',
              fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 13,
              letterSpacing: '0.1em',
              padding: '10px 22px',
              borderRadius: 999,
              textTransform: 'uppercase',
            }}>
            SKIN QUIZ
          </div>
        </div>
        <div style={{ display: 'flex', gap: 18, color: A_PALETTE.ink, fontSize: 18 }}>
          <span>⌕</span>
          <span>◉</span>
          <span>⊡</span>
        </div>
      </div>

      {/* Hero section */}
      <div style={{
        background: A_PALETTE.sage,
        display: 'grid',
        gridTemplateColumns: '1fr 1fr 1fr',
        padding: '32px 40px 40px',
        gap: 28,
        alignItems: 'center',
      }}>
        {/* Left: product shot / card */}
        <div
          data-focus-id="product-card"
          style={{
            aspectRatio: '1 / 0.85',
            background: `radial-gradient(circle at 60% 45%, #e8dccd 0%, #d4c3a8 70%)`,
            borderRadius: 4,
            position: 'relative',
            overflow: 'hidden',
          }}
        >
          {/* Abstract "flowers + jar" composition */}
          <svg viewBox="0 0 400 400" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
            {/* scattered leaves */}
            <g fill={A_PALETTE.moss500} opacity="0.55">
              <ellipse cx="80"  cy="110" rx="26" ry="10" transform="rotate(-30 80 110)"/>
              <ellipse cx="140" cy="80"  rx="22" ry="8"  transform="rotate(20 140 80)"/>
              <ellipse cx="320" cy="320" rx="28" ry="11" transform="rotate(-15 320 320)"/>
            </g>
            {/* flowers */}
            <g>
              {[{ cx: 70, cy: 250 }, { cx: 330, cy: 140 }, { cx: 120, cy: 340 }].map((f, i) => (
                <g key={i} transform={`translate(${f.cx} ${f.cy})`}>
                  {[0, 72, 144, 216, 288].map((deg, j) => (
                    <ellipse
                      key={j} cx="0" cy="-14" rx="8" ry="16"
                      fill={i === 1 ? '#c89b86' : '#b57a9b'}
                      opacity="0.7"
                      transform={`rotate(${deg})`}
                    />
                  ))}
                  <circle r="5" fill="#6b4f2a"/>
                </g>
              ))}
            </g>
            {/* jar */}
            <g transform="translate(200 215)">
              <ellipse cx="0" cy="30" rx="105" ry="28" fill="#aaa7a0" opacity="0.4"/>
              <ellipse cx="0" cy="0" rx="105" ry="32" fill="#e8eef0" stroke={A_PALETTE.ink25} strokeWidth="1.5"/>
              <ellipse cx="0" cy="0" rx="105" ry="32" fill="none" stroke="#ffffff" strokeWidth="2" opacity="0.6"/>
              {/* ridges */}
              {[-70, -50, -30, -10, 10, 30, 50, 70].map((dx, i) => (
                <line key={i} x1={dx} y1={-24} x2={dx} y2={24} stroke="#ffffff" strokeWidth="0.8" opacity="0.5"/>
              ))}
              <text x="0" y="-3" fontFamily={A_FONTS.display} fontSize="11" fontWeight="700"
                textAnchor="middle" fill={A_PALETTE.ink} letterSpacing="2">EMANI</text>
              <text x="0" y="12" fontFamily={A_FONTS.display} fontSize="5" fontWeight="500"
                textAnchor="middle" fill={A_PALETTE.ink70} letterSpacing="1.2">GLOW BIOME</text>
              <text x="0" y="22" fontFamily={A_FONTS.display} fontSize="4" fontWeight="400"
                textAnchor="middle" fill={A_PALETTE.ink55} letterSpacing="1.5">NAD · CERAMIDE SERUM FOUNDATION</text>
            </g>
          </svg>
        </div>

        {/* Center: hero copy */}
        <div style={{ textAlign: 'center', padding: '0 12px' }}>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 500,
            fontSize: 13, letterSpacing: '0.18em',
            color: A_PALETTE.ink55, textTransform: 'uppercase',
            marginBottom: 12,
          }}>
            NAD+ SERUM FOUNDATION
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 500,
            fontSize: 52, letterSpacing: '-0.01em',
            color: A_PALETTE.ink, lineHeight: 1,
            marginBottom: 4,
          }}>
            Foundation
          </div>
          <div style={{
            fontFamily: A_FONTS.serif, fontStyle: 'italic',
            fontWeight: 400, fontSize: 60, lineHeight: 1,
            color: A_PALETTE.moss600, letterSpacing: '-0.015em',
            marginBottom: 14,
          }}>
            Reimagined
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontSize: 15, fontWeight: 400,
            color: A_PALETTE.ink70, lineHeight: 1.4,
            marginBottom: 20,
          }}>
            Your perfect no-makeup look
          </div>
          <div
            data-focus-id="discover"
            style={{
              display: 'inline-block',
              background: A_PALETTE.ink,
              color: '#ffffff',
              padding: '12px 34px',
              borderRadius: 999,
              fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 13,
              letterSpacing: '0.08em',
            }}>
            Discover
          </div>
        </div>

        {/* Right: model shot placeholder */}
        <div style={{
          aspectRatio: '1 / 0.85',
          background: `linear-gradient(135deg, #dfcdb8 0%, #c4a98b 60%, #9a7d5b 100%)`,
          borderRadius: 4,
          position: 'relative',
          overflow: 'hidden',
        }}>
          {/* abstract portrait silhouette */}
          <svg viewBox="0 0 400 400" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
            <defs>
              <radialGradient id="skin" cx="50%" cy="35%" r="60%">
                <stop offset="0%" stopColor="#e9c9aa"/>
                <stop offset="100%" stopColor="#a67f5b"/>
              </radialGradient>
            </defs>
            {/* hair */}
            <path d="M 120 60 Q 200 20, 290 70 Q 330 140, 320 240 L 310 330 Q 200 380, 90 320 L 90 180 Q 90 100, 120 60 Z" fill="#3a2e22"/>
            {/* face */}
            <ellipse cx="200" cy="180" rx="78" ry="95" fill="url(#skin)"/>
            {/* neck + shoulders */}
            <path d="M 160 260 L 160 300 Q 200 320, 240 300 L 240 260 Q 220 275, 200 275 Q 180 275, 160 260 Z" fill="url(#skin)"/>
            <path d="M 80 340 Q 200 310, 320 340 L 340 400 L 60 400 Z" fill="#d4c3a5"/>
            {/* soft highlight */}
            <ellipse cx="160" cy="150" rx="20" ry="28" fill="#ffffff" opacity="0.15"/>
          </svg>
        </div>
      </div>

      {/* Form section */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: '1fr 1fr',
        gap: 40,
        padding: '28px 40px 32px',
        borderTop: `1px solid ${A_PALETTE.ink12}`,
        background: '#ffffff',
      }}>
        <div>
          <div style={{
            fontFamily: A_FONTS.mono, fontSize: 11,
            letterSpacing: '0.22em', color: A_PALETTE.moss600,
            textTransform: 'uppercase', marginBottom: 12,
          }}>
            § members
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontWeight: 500,
            fontSize: 28, letterSpacing: '-0.02em', lineHeight: 1.1,
            color: A_PALETTE.ink, marginBottom: 8,
          }}>
            Get first access.{' '}
            <span style={{
              fontFamily: A_FONTS.serif, fontStyle: 'italic',
              fontWeight: 400, color: A_PALETTE.moss600,
            }}>
              quietly.
            </span>
          </div>
          <div style={{
            fontFamily: A_FONTS.display, fontSize: 13,
            color: A_PALETTE.ink55, maxWidth: 460,
          }}>
            Twice a month. No tracking. Opt-out in one click.
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, maxWidth: 520 }}>
          <label style={{
            fontFamily: A_FONTS.mono, fontSize: 10,
            letterSpacing: '0.2em', color: A_PALETTE.ink70,
            textTransform: 'uppercase',
          }}>
            Email address
          </label>
          <div
            data-focus-id="email"
            style={{
              height: 48,
              background: '#ffffff',
              border: `1px solid ${A_PALETTE.ink25}`,
              borderRadius: 4,
              padding: '0 18px',
              display: 'flex', alignItems: 'center',
              fontFamily: A_FONTS.display, fontSize: 14,
              color: A_PALETTE.ink40,
            }}>
            your@email.com
          </div>
          <div
            data-focus-id="subscribe"
            style={{
              marginTop: 2,
              height: 48,
              width: 200,
              background: A_PALETTE.ink,
              color: '#ffffff',
              borderRadius: 999,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              fontFamily: A_FONTS.display, fontWeight: 600, fontSize: 13,
              letterSpacing: '0.08em', textTransform: 'uppercase',
            }}>
            Subscribe
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Focus ring (driven by DOM-measured rects) ──────────────────────────
function FocusRing({ rects }) {
  const time = useTime();
  const rev = aReverseAlpha(time);

  let active = null;
  for (const def of FOCUS_STOP_DEFS) {
    if (time >= def.tEnter && time < def.tExit) { active = def; break; }
  }
  if (!active || rev > 0.01) return null;
  const rect = rects[active.id];
  if (!rect) return null;

  const sinceEnter = time - active.tEnter;
  const breathe = 0.5 + 0.5 * Math.sin(sinceEnter * Math.PI * 2.2);
  const offset = 6 + breathe * 2;
  const thickness = 2.5;
  const flash = aClamp(sinceEnter / 0.18);
  const flashAlpha = 0.92 + 0.08 * flash;

  const { x, y, w, h } = rect;

  return (
    <>
      <div style={{
        position: 'absolute',
        left: x - offset - 14, top: y - offset - 14,
        width: w + 2*offset + 28, height: h + 2*offset + 28,
        borderRadius: 8,
        background: `radial-gradient(ellipse, ${A_PALETTE.amberGlow}, transparent 70%)`,
        opacity: 0.6 * flashAlpha,
        pointerEvents: 'none',
        transition: 'none',
        zIndex: 15,
      }}/>
      <div style={{
        position: 'absolute',
        left: x - offset, top: y - offset,
        width: w + 2*offset, height: h + 2*offset,
        border: `${thickness}px solid ${A_PALETTE.amber}`,
        borderRadius: 4,
        opacity: flashAlpha,
        pointerEvents: 'none',
        transition: 'none',
        zIndex: 16,
      }}/>
    </>
  );
}

// ── Focus caption ──────────────────────────────────────────────────────
function FocusCaption({ rects }) {
  const time = useTime();
  const rev = aReverseAlpha(time);
  if (rev > 0.01) return null;

  let active = null;
  let idx = 0;
  for (let i = 0; i < FOCUS_STOP_DEFS.length; i++) {
    const def = FOCUS_STOP_DEFS[i];
    if (time >= def.tEnter && time < def.tExit) { active = def; idx = i; break; }
  }
  if (!active) return null;
  const rect = rects[active.id];
  if (!rect) return null;

  const sinceEnter = time - active.tEnter;
  const fade = aClamp((sinceEnter - 0.15) / 0.22);
  if (fade < 0.01) return null;

  const { x, y, w, h } = rect;
  const capW = 320;
  const capH = 110;
  // Prefer below, but flip above if it would clip past y=1000
  let capY = y + h + 24;
  if (capY + capH > 1040) capY = y - capH - 18;
  // Horizontal: left-align with target, but clamp to canvas
  let capX = x;
  if (capX + capW > 1860) capX = 1860 - capW;
  if (capX < 60) capX = 60;

  return (
    <div style={{
      position: 'absolute',
      left: capX, top: capY,
      width: capW,
      opacity: fade,
      transition: 'none',
      pointerEvents: 'none',
      zIndex: 17,
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8,
      }}>
        <div style={{
          width: 6, height: 6, borderRadius: 3,
          background: A_PALETTE.amber,
        }}/>
        <div style={{
          fontFamily: A_FONTS.mono, fontSize: 10, letterSpacing: '0.22em',
          color: A_PALETTE.amber, textTransform: 'uppercase',
        }}>
          focused · tab {idx + 1}/{FOCUS_STOP_DEFS.length}
        </div>
      </div>
      <div style={{
        display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10,
      }}>
        {active.tags.map((t, i) => (
          <div key={i} style={{
            fontFamily: A_FONTS.mono, fontSize: 10,
            letterSpacing: '0.14em', color: A_PALETTE.ink70,
            textTransform: 'uppercase',
            padding: '3px 8px',
            background: '#ffffff',
            border: `1px solid ${A_PALETTE.ink25}`,
            borderRadius: 2,
          }}>
            {t}
          </div>
        ))}
      </div>
      <div style={{
        display: 'flex', alignItems: 'baseline', gap: 8,
        fontFamily: A_FONTS.display, fontWeight: 600,
        fontSize: 17, letterSpacing: '-0.01em',
        color: A_PALETTE.ink,
      }}>
        <span>§ {active.wcag}</span>
        <span style={{
          fontFamily: A_FONTS.mono, fontSize: 10,
          letterSpacing: '0.18em', color: A_PALETTE.moss600,
          textTransform: 'uppercase',
          padding: '2px 6px',
          background: A_PALETTE.moss050,
          border: `1px solid ${A_PALETTE.moss300}`,
          borderRadius: 2,
        }}>
          {active.level}
        </span>
      </div>
    </div>
  );
}

// ── Breadcrumb trail + summary ─────────────────────────────────────────
function BreadcrumbTrail({ rects }) {
  const time = useTime();
  const rev = aReverseAlpha(time);
  if (time < TRAIL_START - 0.2) return null;

  const since = time - TRAIL_START;
  const k = aClamp(since / 1.2) * (1 - rev);
  if (k < 0.01) return null;

  const pts = FOCUS_STOP_DEFS.map(def => {
    const r = rects[def.id];
    if (!r) return null;
    return { x: r.x + r.w / 2, y: r.y + r.h / 2 };
  }).filter(Boolean);
  if (pts.length < 2) return null;

  const segLens = [];
  let total = 0;
  for (let i = 1; i < pts.length; i++) {
    const L = Math.hypot(pts[i].x - pts[i-1].x, pts[i].y - pts[i-1].y);
    segLens.push(L);
    total += L;
  }
  const drawLen = total * k;

  return (
    <svg
      width="1920" height="1080" viewBox="0 0 1920 1080"
      style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 18 }}
    >
      {pts.slice(0, -1).map((p, i) => {
        const q = pts[i+1];
        const consumedBefore = segLens.slice(0, i).reduce((s, l) => s + l, 0);
        const localDraw = aClamp((drawLen - consumedBefore) / segLens[i]);
        if (localDraw < 0.01) return null;
        const ex = p.x + (q.x - p.x) * localDraw;
        const ey = p.y + (q.y - p.y) * localDraw;
        return (
          <line
            key={i}
            x1={p.x} y1={p.y} x2={ex} y2={ey}
            stroke={A_PALETTE.moss500}
            strokeWidth="1.5"
            strokeDasharray="2 6"
            opacity={0.7}
          />
        );
      })}
      {pts.map((p, i) => {
        const segBefore = i === 0 ? 0 : segLens.slice(0, i).reduce((s, l) => s + l, 0);
        const visible = drawLen >= segBefore || i === 0;
        if (!visible) return null;
        return (
          <g key={i}>
            <circle cx={p.x} cy={p.y} r="14" fill="#ffffff" stroke={A_PALETTE.moss500} strokeWidth="1.5"/>
            <text
              x={p.x} y={p.y + 4}
              fontFamily={A_FONTS.mono}
              fontSize="12"
              fontWeight="600"
              fill={A_PALETTE.moss700}
              textAnchor="middle"
            >
              {i + 1}
            </text>
          </g>
        );
      })}
    </svg>
  );
}

function SummaryCaption() {
  const time = useTime();
  const rev = aReverseAlpha(time);
  if (time < TRAIL_START + 0.6) return null;

  const since = time - (TRAIL_START + 0.6);
  const fade = aClamp(since / 0.6) * (1 - rev);
  if (fade < 0.01) return null;

  return (
    <>
      {/* Cream wash to dim the page so summary pops */}
      <div style={{
        position: 'absolute', inset: 0,
        background: A_PALETTE.cream,
        opacity: fade * 0.82,
        pointerEvents: 'none',
        zIndex: 17,
        transition: 'none',
      }}/>
      {/* amber halo behind */}
      <div style={{
        position: 'absolute',
        left: 960 - 500, top: 400,
        width: 1000, height: 280, borderRadius: '50%',
        background: `radial-gradient(ellipse, ${A_PALETTE.amberGlow}, transparent 70%)`,
        opacity: fade * 0.85,
        pointerEvents: 'none',
        zIndex: 18,
      }}/>
      <div style={{
        position: 'absolute',
        left: 0, right: 0, top: 440,
        textAlign: 'center',
        opacity: fade,
        transition: 'none',
        zIndex: 19,
        pointerEvents: 'none',
      }}>
        <div style={{
          fontFamily: A_FONTS.mono, fontSize: 13,
          letterSpacing: '0.24em', color: A_PALETTE.moss600,
          textTransform: 'uppercase', marginBottom: 14,
        }}>
          § summary · keyboard tour
        </div>
        <div style={{
          fontFamily: A_FONTS.display, fontWeight: 600,
          fontSize: 62, letterSpacing: '-0.03em', lineHeight: 1,
          color: A_PALETTE.ink,
        }}>
          7 stops · 0 traps ·{' '}
          <span style={{
            fontFamily: A_FONTS.serif, fontStyle: 'italic',
            fontWeight: 400, color: A_PALETTE.moss600,
            fontSize: 74,
          }}>
            passed
          </span>
        </div>
        <div style={{
          fontFamily: A_FONTS.mono, fontSize: 12,
          letterSpacing: '0.2em', color: A_PALETTE.ink55,
          textTransform: 'uppercase', marginTop: 16,
        }}>
          WCAG 2.2 · level AA · across 7 success criteria
        </div>
      </div>
    </>
  );
}

// ── Scene root ─────────────────────────────────────────────────────────
function A11yScene() {
  const rects = useFocusRects();
  return (
    <div data-a11y-stage style={{ position: 'absolute', inset: 0 }}>
      {/* Background */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(ellipse at 50% 60%, ${A_PALETTE.cream} 0%, ${A_PALETTE.creamDk} 100%)`,
      }}/>

      <ASectionTitle />
      <EmaniPage />
      <FocusRing rects={rects} />
      <FocusCaption rects={rects} />
      <BreadcrumbTrail rects={rects} />
      <SummaryCaption />

      <AFilmGrain opacity={0.05} />
      <ACornerChrome />
    </div>
  );
}

Object.assign(window, {
  A11yScene,
  A_PALETTE,
  A_FONTS,
});
