// system-scenes.jsx — "§ 03 · design system" pyramid animation
// 15s loop: 4 tiers build up bottom→top:
//   tier 1 (bottom, widest): 8 tokens (color, type, spacing, easing, radius, shadow, border, breakpoint)
//   tier 2: 5 components (Button, Card, Nav, Input, Modal)
//   tier 3: 3 patterns (Hero, Feature grid, FAQ)
//   tier 4 (top, narrowest): 1 page with amber bloom
// Thin moss connecting lines draw between tiers. Final beat: pyramid + "tokens build pages" caption.

const S_PALETTE = {
  cream:    '#f5f0e8',
  creamDk:  '#ebe4d6',
  creamLt:  '#faf6ed',
  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)',
  ink08:    'rgba(15,23,19,0.08)',
  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)',
};
const S_FONTS = {
  display: '"Space Grotesk", system-ui, sans-serif',
  serif:   '"Instrument Serif", Georgia, serif',
  mono:    '"JetBrains Mono", ui-monospace, monospace',
};

const sClamp = (v, a = 0, b = 1) => Math.max(a, Math.min(b, v));
const sEase  = (t) => 1 - Math.pow(1 - t, 3);
const sEaseInOut = (t) => t < 0.5 ? 4*t*t*t : 1 - Math.pow(-2*t+2,3)/2;
const sSmooth = (t) => t * t * (3 - 2 * t);

// ── Timing ─────────────────────────────────────────────────────────────
const TIER1_START = 0.6, TIER1_END = 3.0;
const TIER2_START = 3.0, TIER2_END = 6.0;
const TIER3_START = 6.0, TIER3_END = 9.0;
const TIER4_START = 9.0, TIER4_END = 13.0;
const SETTLE_START = 13.0, SETTLE_END = 14.0;
const REVERSE_START_S = 14.0;

const sReverseAlpha = (t) => t < REVERSE_START_S ? 0 : (t - REVERSE_START_S) / (15 - REVERSE_START_S);

// ── Layout ─────────────────────────────────────────────────────────────
// Canvas 1920x1080. Pyramid centered horizontally.
// Tier bands (y-center and widths):
// Stacking top→bottom with real spacing between bands:
//   tier 4 center y ≈ 370  (page, h=180) → bottom 460
//   tier 3 center y ≈ 600  (patterns, h=150) → top 525
//   tier 2 center y ≈ 770  (components, h=120) → top 710
//   tier 1 center y ≈ 920  (tokens, h=110) → top 865
const TIERS = {
  1: { y: 920, tileW: 104, tileH: 108, count: 8, gap: 26 },   // tokens (bottom)
  2: { y: 770, tileW: 156, tileH: 118, count: 5, gap: 32 },   // components
  3: { y: 600, tileW: 240, tileH: 140, count: 3, gap: 44 },   // patterns
  4: { y: 370, tileW: 640, tileH: 170, count: 1, gap: 0 },    // pages (top)
};

function tileXPositions(tier) {
  const t = TIERS[tier];
  const totalW = t.count * t.tileW + (t.count - 1) * t.gap;
  const left = 960 - totalW / 2;
  const xs = [];
  for (let i = 0; i < t.count; i++) {
    xs.push(left + i * (t.tileW + t.gap) + t.tileW / 2);
  }
  return xs;
}

// ── Film grain ─────────────────────────────────────────────────────────
function SFilmGrain({ 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 SCornerChrome() {
  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',
        }}
      />
      <div style={{
        position: 'absolute', right: 56, top: 58,
        fontFamily: S_FONTS.mono,
        fontSize: 12, letterSpacing: '0.16em',
        color: S_PALETTE.ink40,
        textTransform: 'uppercase',
      }}>
        vol. 01 — craft
      </div>
      <div style={{
        position: 'absolute', right: 56, bottom: 56,
        display: 'flex', alignItems: 'center', gap: 12,
        fontFamily: S_FONTS.mono,
        fontSize: 12, letterSpacing: '0.14em',
        color: S_PALETTE.ink70,
        textTransform: 'uppercase',
        opacity: 0.75,
      }}>
        <span>§ 03 · design system</span>
        <div style={{
          width: 8, height: 8, borderRadius: 4,
          background: S_PALETTE.moss500,
          opacity: 0.45 + 0.55 * pulse,
          boxShadow: `0 0 ${6 + 10*pulse}px ${S_PALETTE.moss400}`,
        }}/>
      </div>
      <div style={{
        position: 'absolute', left: 56, bottom: 56,
        fontFamily: S_FONTS.mono,
        fontSize: 12, letterSpacing: '0.14em',
        color: S_PALETTE.ink40,
      }}>
        fig.&nbsp;&nbsp;03·ii — hierarchy of craft
      </div>
    </>
  );
}

// ── Token tile (tier 1) ────────────────────────────────────────────────
// Each token has a symbol + mono label.
const TOKENS = [
  { kind: 'color',      label: 'color' },
  { kind: 'type',       label: 'type' },
  { kind: 'spacing',    label: 'space' },
  { kind: 'easing',     label: 'ease' },
  { kind: 'radius',     label: 'radius' },
  { kind: 'shadow',     label: 'shadow' },
  { kind: 'border',     label: 'border' },
  { kind: 'breakpoint', label: 'break' },
];

function TokenGlyph({ kind }) {
  const s = 52;
  if (kind === 'color') {
    return (
      <div style={{ width: s, height: s, background: S_PALETTE.moss500, borderRadius: 2 }}/>
    );
  }
  if (kind === 'type') {
    return (
      <div style={{
        fontFamily: S_FONTS.display, fontWeight: 700,
        fontSize: 28, letterSpacing: '-0.02em',
        color: S_PALETTE.moss700, lineHeight: 1,
      }}>
        20<span style={{ fontFamily: S_FONTS.mono, fontWeight: 400, fontSize: 14, color: S_PALETTE.ink55 }}>/28</span>
      </div>
    );
  }
  if (kind === 'spacing') {
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        {[0.4, 0.7, 1.0].map((sc, i) => (
          <div key={i} style={{
            width: 10 * sc, height: 10 * sc, borderRadius: '50%',
            background: S_PALETTE.moss600,
          }}/>
        ))}
      </div>
    );
  }
  if (kind === 'easing') {
    // SVG ease-out-cubic curve
    return (
      <svg width="44" height="44" viewBox="0 0 44 44">
        <path d="M 2 42 C 2 42, 10 4, 42 2" fill="none" stroke={S_PALETTE.moss600} strokeWidth="2"/>
        <circle cx="2" cy="42" r="2" fill={S_PALETTE.moss700}/>
        <circle cx="42" cy="2" r="2" fill={S_PALETTE.moss700}/>
      </svg>
    );
  }
  if (kind === 'radius') {
    return (
      <div style={{
        width: 44, height: 44,
        border: `2px solid ${S_PALETTE.moss600}`,
        borderRadius: 12,
      }}/>
    );
  }
  if (kind === 'shadow') {
    return (
      <div style={{
        width: 40, height: 40, background: S_PALETTE.moss600, borderRadius: 2,
        boxShadow: `6px 8px 0 ${S_PALETTE.moss200}`,
      }}/>
    );
  }
  if (kind === 'border') {
    return (
      <svg width="44" height="44" viewBox="0 0 44 44">
        <line x1="4" y1="22" x2="40" y2="22" stroke={S_PALETTE.moss600} strokeWidth="2" strokeDasharray="6 4"/>
        <line x1="4" y1="8"  x2="40" y2="8"  stroke={S_PALETTE.moss600} strokeWidth="1"/>
        <line x1="4" y1="36" x2="40" y2="36" stroke={S_PALETTE.moss600} strokeWidth="3"/>
      </svg>
    );
  }
  if (kind === 'breakpoint') {
    return (
      <svg width="44" height="44" viewBox="0 0 44 44">
        <rect x="2"  y="10" width="12" height="24" rx="1.5" fill="none" stroke={S_PALETTE.moss600} strokeWidth="1.5"/>
        <rect x="16" y="6"  width="14" height="32" rx="1.5" fill="none" stroke={S_PALETTE.moss600} strokeWidth="1.5"/>
        <rect x="32" y="2"  width="10" height="40" rx="1.5" fill="none" stroke={S_PALETTE.moss600} strokeWidth="1.5"/>
      </svg>
    );
  }
  return null;
}

// ── Tile frame (with entry animation) ──────────────────────────────────
function Tile({ cx, cy, w, h, alpha, scale, accent = false, children }) {
  if (alpha < 0.01) return null;
  return (
    <div style={{
      position: 'absolute',
      left: cx - w / 2, top: cy - h / 2,
      width: w, height: h,
      background: S_PALETTE.cream,
      border: `1px solid ${accent ? S_PALETTE.moss500 : S_PALETTE.moss300}`,
      boxShadow: `0 4px 14px rgba(50,85,63,0.08)`,
      borderRadius: 2,
      opacity: alpha,
      transform: `scale(${scale})`,
      transformOrigin: 'center',
      transition: 'none',
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center',
      overflow: 'hidden',
    }}>
      {children}
    </div>
  );
}

// ── Tier-entry helper: compute (alpha, scale) per-tile with stagger ────
function tierEntry(time, tierStart, tierEnd, i, count) {
  const span = tierEnd - tierStart;
  const perTileStagger = Math.min(0.18, (span * 0.55) / Math.max(1, count));
  const tileStart = tierStart + i * perTileStagger;
  const k = sClamp((time - tileStart) / 0.45);
  const alpha = sEase(k);
  const scale = 0.82 + 0.18 * sEase(k);
  return { alpha, scale };
}

// ── Tier 1: Tokens ─────────────────────────────────────────────────────
function Tier1Tokens() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const xs = tileXPositions(1);
  const cy = TIERS[1].y;
  const { tileW, tileH } = TIERS[1];

  return (
    <>
      {TOKENS.map((tok, i) => {
        const { alpha, scale } = tierEntry(time, TIER1_START, TIER1_END, i, TOKENS.length);
        const a = alpha * (1 - rev);
        return (
          <React.Fragment key={tok.kind}>
            <Tile cx={xs[i]} cy={cy} w={tileW} h={tileH} alpha={a} scale={scale}>
              <div style={{ marginBottom: 14 }}>
                <TokenGlyph kind={tok.kind}/>
              </div>
              <div style={{
                fontFamily: S_FONTS.mono,
                fontSize: 10, letterSpacing: '0.2em',
                color: S_PALETTE.ink55, textTransform: 'uppercase',
              }}>
                {tok.label}
              </div>
            </Tile>
          </React.Fragment>
        );
      })}
    </>
  );
}

// ── Tier 2: Components ─────────────────────────────────────────────────
const COMPONENTS = [
  { key: 'button', label: 'Button' },
  { key: 'card',   label: 'Card' },
  { key: 'nav',    label: 'Nav' },
  { key: 'input',  label: 'Input' },
  { key: 'modal',  label: 'Modal' },
];

function ComponentGlyph({ kind }) {
  if (kind === 'button') {
    return (
      <div style={{
        padding: '8px 20px', background: S_PALETTE.moss600,
        color: S_PALETTE.cream, fontFamily: S_FONTS.display,
        fontWeight: 600, fontSize: 12, letterSpacing: '0.04em',
        borderRadius: 999,
      }}>
        Continue
      </div>
    );
  }
  if (kind === 'card') {
    return (
      <div style={{
        width: 90, height: 48,
        border: `1px solid ${S_PALETTE.moss500}`, borderRadius: 4,
        background: S_PALETTE.creamLt, padding: 6,
      }}>
        <div style={{ width: 32, height: 4, background: S_PALETTE.moss600, marginBottom: 4 }}/>
        <div style={{ width: 60, height: 2, background: S_PALETTE.moss300, marginBottom: 3 }}/>
        <div style={{ width: 50, height: 2, background: S_PALETTE.moss300 }}/>
      </div>
    );
  }
  if (kind === 'nav') {
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 14, height: 14, borderRadius: '50%', background: S_PALETTE.moss600 }}/>
        {[0, 1, 2].map(i => (
          <div key={i} style={{
            width: 18, height: 3, background: S_PALETTE.moss500, borderRadius: 1,
          }}/>
        ))}
      </div>
    );
  }
  if (kind === 'input') {
    return (
      <div style={{
        width: 110, height: 26,
        border: `1px solid ${S_PALETTE.moss500}`, borderRadius: 2,
        display: 'flex', alignItems: 'center', padding: '0 8px',
        fontFamily: S_FONTS.mono, fontSize: 11,
        color: S_PALETTE.ink40, letterSpacing: '0.05em',
      }}>
        email.tld<span style={{ marginLeft: 1, color: S_PALETTE.moss600 }}>|</span>
      </div>
    );
  }
  if (kind === 'modal') {
    return (
      <div style={{
        position: 'relative', width: 90, height: 60,
      }}>
        <div style={{
          position: 'absolute', inset: 0,
          background: S_PALETTE.moss200, opacity: 0.5, borderRadius: 2,
        }}/>
        <div style={{
          position: 'absolute', left: 14, top: 10, right: 14, bottom: 10,
          background: S_PALETTE.cream, border: `1px solid ${S_PALETTE.moss500}`,
          borderRadius: 2, padding: 6,
        }}>
          <div style={{ width: 36, height: 3, background: S_PALETTE.moss600, marginBottom: 4 }}/>
          <div style={{ width: 58, height: 2, background: S_PALETTE.moss300 }}/>
        </div>
      </div>
    );
  }
  return null;
}

function Tier2Components() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const xs = tileXPositions(2);
  const cy = TIERS[2].y;
  const { tileW, tileH } = TIERS[2];

  return (
    <>
      {COMPONENTS.map((c, i) => {
        const { alpha, scale } = tierEntry(time, TIER2_START, TIER2_END, i, COMPONENTS.length);
        const a = alpha * (1 - rev);
        return (
          <Tile key={c.key} cx={xs[i]} cy={cy} w={tileW} h={tileH} alpha={a} scale={scale}>
            <div style={{ marginBottom: 14 }}>
              <ComponentGlyph kind={c.key}/>
            </div>
            <div style={{
              fontFamily: S_FONTS.mono,
              fontSize: 10, letterSpacing: '0.2em',
              color: S_PALETTE.ink55, textTransform: 'uppercase',
            }}>
              {c.label}
            </div>
          </Tile>
        );
      })}
    </>
  );
}

// ── Tier 3: Patterns ───────────────────────────────────────────────────
const PATTERNS = [
  { key: 'hero',    label: 'Hero' },
  { key: 'grid',    label: 'Feature grid' },
  { key: 'faq',     label: 'FAQ' },
];

function PatternGlyph({ kind }) {
  if (kind === 'hero') {
    return (
      <div style={{ width: 200, height: 80, display: 'flex', gap: 10 }}>
        <div style={{ flex: 1.2, padding: 10, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 5 }}>
          <div style={{ width: '85%', height: 6, background: S_PALETTE.ink, borderRadius: 1 }}/>
          <div style={{ width: '65%', height: 6, background: S_PALETTE.moss600, borderRadius: 1 }}/>
          <div style={{ width: '48%', height: 4, background: S_PALETTE.ink40, borderRadius: 1, marginTop: 4 }}/>
          <div style={{ width: 44, height: 10, background: S_PALETTE.moss600, borderRadius: 999, marginTop: 6 }}/>
        </div>
        <div style={{ flex: 1, background: S_PALETTE.moss200, borderRadius: 2 }}/>
      </div>
    );
  }
  if (kind === 'grid') {
    return (
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8, width: 200, height: 80 }}>
        {[0,1,2,3,4,5].map(i => (
          <div key={i} style={{
            background: S_PALETTE.creamLt, border: `1px solid ${S_PALETTE.moss300}`,
            borderRadius: 2, padding: 5,
            display: 'flex', flexDirection: 'column', gap: 3,
          }}>
            <div style={{ width: 10, height: 10, background: S_PALETTE.moss500, borderRadius: '50%' }}/>
            <div style={{ width: '80%', height: 3, background: S_PALETTE.moss400, borderRadius: 1 }}/>
            <div style={{ width: '60%', height: 2, background: S_PALETTE.ink25 }}/>
          </div>
        ))}
      </div>
    );
  }
  if (kind === 'faq') {
    return (
      <div style={{ width: 200, height: 80, display: 'flex', flexDirection: 'column', gap: 6 }}>
        {[0, 1, 2, 3].map(i => (
          <div key={i} style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            background: i === 1 ? S_PALETTE.moss100 : 'transparent',
            border: `1px solid ${S_PALETTE.moss300}`,
            borderRadius: 2, padding: '4px 8px',
            height: i === 1 ? 22 : 14,
          }}>
            <div style={{ width: '70%', height: 3, background: S_PALETTE.moss600, borderRadius: 1 }}/>
            <div style={{ fontFamily: S_FONTS.mono, fontSize: 10, color: S_PALETTE.moss600 }}>
              {i === 1 ? '−' : '+'}
            </div>
          </div>
        ))}
      </div>
    );
  }
  return null;
}

function Tier3Patterns() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const xs = tileXPositions(3);
  const cy = TIERS[3].y;
  const { tileW, tileH } = TIERS[3];

  return (
    <>
      {PATTERNS.map((p, i) => {
        const { alpha, scale } = tierEntry(time, TIER3_START, TIER3_END, i, PATTERNS.length);
        const a = alpha * (1 - rev);
        return (
          <Tile key={p.key} cx={xs[i]} cy={cy} w={tileW} h={tileH} alpha={a} scale={scale}>
            <div style={{ marginBottom: 10 }}>
              <PatternGlyph kind={p.key}/>
            </div>
            <div style={{
              fontFamily: S_FONTS.mono,
              fontSize: 10, letterSpacing: '0.2em',
              color: S_PALETTE.ink55, textTransform: 'uppercase',
            }}>
              {p.label}
            </div>
          </Tile>
        );
      })}
    </>
  );
}

// ── Tier 4: Page ───────────────────────────────────────────────────────
function Tier4Page() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const cy = TIERS[4].y;
  const { tileW, tileH } = TIERS[4];
  const cx = 960;

  const { alpha, scale } = tierEntry(time, TIER4_START, TIER4_END, 0, 1);
  const a = alpha * (1 - rev);
  if (a < 0.01) return null;

  return (
    <div style={{
      position: 'absolute',
      left: cx - tileW / 2, top: cy - tileH / 2,
      width: tileW, height: tileH,
      background: S_PALETTE.cream,
      border: `1px solid ${S_PALETTE.moss500}`,
      boxShadow: `0 14px 40px rgba(50,85,63,0.15)`,
      borderRadius: 2,
      opacity: a,
      transform: `scale(${scale})`,
      transformOrigin: 'center',
      transition: 'none',
      padding: 16,
      display: 'grid',
      gridTemplateColumns: '1fr 0.9fr',
      gap: 14,
    }}>
      {/* Left column: hero copy + stats */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {/* Top nav */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 2 }}>
          <div style={{ width: 28, height: 10, background: S_PALETTE.ink, borderRadius: 1 }}/>
          <div style={{ display: 'flex', gap: 6 }}>
            {[0,1,2].map(i => <div key={i} style={{ width: 16, height: 3, background: S_PALETTE.moss500, borderRadius: 1 }}/>)}
          </div>
        </div>
        {/* Hero text */}
        <div style={{ width: '95%', height: 10, background: S_PALETTE.ink, borderRadius: 1 }}/>
        <div style={{ width: '75%', height: 10, background: S_PALETTE.moss600, borderRadius: 1 }}/>
        <div style={{ width: '90%', height: 4, background: S_PALETTE.ink25, borderRadius: 1, marginTop: 2 }}/>
        <div style={{ width: '80%', height: 4, background: S_PALETTE.ink25, borderRadius: 1 }}/>
        <div style={{ display: 'flex', gap: 6, marginTop: 4 }}>
          <div style={{ width: 48, height: 14, background: S_PALETTE.moss600, borderRadius: 999 }}/>
          <div style={{ width: 40, height: 14, border: `1px solid ${S_PALETTE.moss500}`, borderRadius: 999 }}/>
        </div>
        {/* Stats row */}
        <div style={{ display: 'flex', gap: 14, marginTop: 8 }}>
          {['15k', '72h', '4.9'].map((v, i) => (
            <div key={i}>
              <div style={{
                fontFamily: S_FONTS.display, fontWeight: 700, fontSize: 18, lineHeight: 1,
                color: S_PALETTE.moss700,
              }}>
                {v}
              </div>
              <div style={{ width: 28, height: 2, background: S_PALETTE.ink25, marginTop: 2 }}/>
            </div>
          ))}
        </div>
      </div>
      {/* Right: image block + cards below */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <div style={{
          flex: 1,
          background: `radial-gradient(ellipse at 40% 35%, ${S_PALETTE.moss300}, ${S_PALETTE.moss500})`,
          borderRadius: 2,
        }}/>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4, height: 40 }}>
          {[0,1,2].map(i => (
            <div key={i} style={{
              background: S_PALETTE.creamLt, border: `1px solid ${S_PALETTE.moss200}`,
              borderRadius: 2, padding: 4,
            }}>
              <div style={{ width: '80%', height: 3, background: S_PALETTE.moss500, marginBottom: 2 }}/>
              <div style={{ width: '60%', height: 2, background: S_PALETTE.ink25 }}/>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── Connecting lines between tiers ─────────────────────────────────────
// Each line goes from a higher-tier tile DOWN to a lower-tier tile's top edge.
// Draw progressively as the higher tier assembles.
function ConnectingLines() {
  const time = useTime();
  const rev = sReverseAlpha(time);

  // Each pair of tiers: map each UPPER tile's x to a small set of LOWER tile x's.
  // The lines appear shortly after the upper tile appears, drawing downward to the lower tier.
  //
  // Pairings (upper.i → lower indices):
  //   tier2.Button(0)  → tier1 color, radius        (color/shape tokens)
  //   tier2.Card(1)    → tier1 spacing, shadow, radius
  //   tier2.Nav(2)     → tier1 type, color
  //   tier2.Input(3)   → tier1 border, type
  //   tier2.Modal(4)   → tier1 shadow, radius, spacing
  //   tier3.Hero(0)    → tier2 Button(0), Card(1)
  //   tier3.Grid(1)    → tier2 Card(1), Nav(2), Input(3)
  //   tier3.FAQ(2)     → tier2 Card(1), Input(3), Modal(4)
  //   tier4.Page(0)    → tier3 Hero(0), Grid(1), FAQ(2)

  const mappings = [
    // tier upper, upperIdx, tier lower, lowerIdxs, appearTime
    { up: 2, uI: 0, lo: 1, lIs: [0, 4], at: TIER2_START + 0.1 },
    { up: 2, uI: 1, lo: 1, lIs: [2, 4, 5], at: TIER2_START + 0.3 },
    { up: 2, uI: 2, lo: 1, lIs: [1, 0], at: TIER2_START + 0.5 },
    { up: 2, uI: 3, lo: 1, lIs: [6, 1], at: TIER2_START + 0.7 },
    { up: 2, uI: 4, lo: 1, lIs: [5, 4, 2], at: TIER2_START + 0.9 },

    { up: 3, uI: 0, lo: 2, lIs: [0, 1], at: TIER3_START + 0.2 },
    { up: 3, uI: 1, lo: 2, lIs: [1, 2, 3], at: TIER3_START + 0.7 },
    { up: 3, uI: 2, lo: 2, lIs: [1, 3, 4], at: TIER3_START + 1.2 },

    { up: 4, uI: 0, lo: 3, lIs: [0, 1, 2], at: TIER4_START + 0.3 },
  ];

  const upperXs = { 2: tileXPositions(2), 3: tileXPositions(3), 4: tileXPositions(4) };
  const lowerXs = { 1: tileXPositions(1), 2: tileXPositions(2), 3: tileXPositions(3) };

  return (
    <svg
      width="1920" height="1080" viewBox="0 0 1920 1080"
      style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
    >
      {mappings.map((m, idx) => {
        // Line exits the UPPER tile from its bottom edge + small outset,
        // and enters the LOWER tile at its top edge + small outset.
        // This prevents the line from visibly crossing into either tile.
        const upperY = TIERS[m.up].y + TIERS[m.up].tileH / 2 + 2;
        const lowerY = TIERS[m.lo].y - TIERS[m.lo].tileH / 2 - 2;
        const upperX = upperXs[m.up][m.uI];

        return m.lIs.map((lI, j) => {
          const lowerX = lowerXs[m.lo][lI];
          const drawT = sClamp((time - (m.at + j * 0.05)) / 0.5) * (1 - rev);
          if (drawT < 0.02) return null;

          // Draw line from upper down to lower, with a gentle curve bend.
          const midY = (upperY + lowerY) / 2;
          const d = `M ${upperX} ${upperY} C ${upperX} ${midY}, ${lowerX} ${midY}, ${lowerX} ${lowerY}`;

          // Use strokeDasharray to progressively draw
          const len = Math.hypot(lowerX - upperX, lowerY - upperY) + 40;
          const dashOffset = len * (1 - drawT);

          return (
            <path
              key={`${idx}-${j}`}
              d={d}
              stroke={S_PALETTE.moss400}
              strokeWidth="1"
              fill="none"
              strokeDasharray={len}
              strokeDashoffset={dashOffset}
              opacity={0.45 * drawT}
            />
          );
        });
      })}
    </svg>
  );
}

// ── Tier caption (appears near the active tier) ────────────────────────
function TierCaption() {
  const time = useTime();
  const rev = sReverseAlpha(time);

  // Determine which tier is active
  let idx = 0;
  let label = '§ 01 · tokens';
  if (time >= TIER1_START && time < TIER2_START) { idx = 0; label = '§ 01 · tokens'; }
  else if (time >= TIER2_START && time < TIER3_START) { idx = 1; label = '§ 02 · components'; }
  else if (time >= TIER3_START && time < TIER4_START) { idx = 2; label = '§ 03 · patterns'; }
  else if (time >= TIER4_START && time < SETTLE_START) { idx = 3; label = '§ 04 · pages'; }
  else if (time >= SETTLE_START) { idx = 3; label = '§ 04 · pages'; }
  else { idx = 0; label = '§ 01 · tokens'; }

  const tierStarts = [TIER1_START, TIER2_START, TIER3_START, TIER4_START];
  const since = time - tierStarts[idx];
  let alpha = sClamp(since / 0.4);

  // Fade out 0.3s before the next tier starts (except last)
  const nextStart = idx < 3 ? tierStarts[idx + 1] : SETTLE_START;
  if (time > nextStart - 0.3 && idx < 3) {
    alpha *= sClamp((nextStart - time) / 0.3);
  }
  // Tier 4 stays through settle then fades during reverse
  alpha *= (1 - rev);
  if (alpha < 0.01) return null;

  // Position: to the RIGHT of each tier band, in a consistent slot
  const tierY = TIERS[idx + 1].y;
  return (
    <div style={{
      position: 'absolute',
      left: 72, top: tierY,
      transform: 'translateY(-50%)',
      opacity: alpha,
      transition: 'none',
    }}>
      <div style={{
        fontFamily: S_FONTS.mono,
        fontSize: 11, letterSpacing: '0.2em',
        color: S_PALETTE.moss600, textTransform: 'uppercase',
        marginBottom: 6,
      }}>
        {label.split('·')[0].trim()}
      </div>
      <div style={{
        fontFamily: S_FONTS.display,
        fontWeight: 600, fontSize: 28,
        letterSpacing: '-0.02em',
        color: S_PALETTE.ink,
        lineHeight: 1,
      }}>
        {label.split('·')[1].trim()}
      </div>
    </div>
  );
}

// ── Settle caption "tokens build pages" ────────────────────────────────
function SettleCaption() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const k = sClamp((time - (SETTLE_START + 0.1)) / 0.6) * (1 - rev);
  if (k < 0.01) return null;

  return (
    <div style={{
      position: 'absolute',
      left: 0, right: 0, top: 140,
      textAlign: 'center',
      opacity: k,
      transition: 'none',
    }}>
      <div style={{
        fontFamily: S_FONTS.mono,
        fontSize: 11, letterSpacing: '0.2em',
        color: S_PALETTE.moss600, textTransform: 'uppercase',
        marginBottom: 14,
      }}>
        § 03 · the design system
      </div>
      <div style={{
        fontFamily: S_FONTS.display, fontWeight: 400,
        fontSize: 42, letterSpacing: '-0.02em',
        color: S_PALETTE.ink,
        lineHeight: 1,
      }}>
        tokens{' '}
        <span style={{
          fontFamily: S_FONTS.serif, fontStyle: 'italic',
          color: S_PALETTE.moss600, fontSize: 48,
        }}>
          build
        </span>
        {' '}pages.
      </div>
    </div>
  );
}

// ── Amber bloom behind tier 4 ──────────────────────────────────────────
function AmberPageBloom() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  if (time < TIER4_START - 0.1) return null;

  const k = sClamp((time - TIER4_START) / 1.2);
  const alpha = sEase(k) * (1 - rev);
  const breathe = 0.85 + 0.15 * Math.sin(time * Math.PI * 1.3);

  const cy = TIERS[4].y;

  return (
    <div style={{
      position: 'absolute',
      left: 960 - 520, top: cy - 240,
      width: 1040, height: 480, borderRadius: '50%',
      background: `radial-gradient(ellipse, ${S_PALETTE.amberGlow}, transparent 65%)`,
      opacity: alpha * breathe * 0.5,
      pointerEvents: 'none',
      transition: 'none',
    }}/>
  );
}

// ── Section title ──────────────────────────────────────────────────────
function SystemSectionTitle() {
  const time = useTime();
  const rev = sReverseAlpha(time);
  const alpha = sClamp(time / 0.8);

  // Fade out BEFORE tier 4 arrives, so the page tile has clean air above it
  let out = 1;
  if (time >= TIER4_START - 0.6) out = sClamp((TIER4_START - 0.2 - 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: 120,
      textAlign: 'center',
      opacity: a,
      transition: 'none',
    }}>
      <div style={{
        fontFamily: S_FONTS.mono,
        fontSize: 12, letterSpacing: '0.2em',
        color: S_PALETTE.moss600, textTransform: 'uppercase',
        marginBottom: 12,
      }}>
        § 03 · the design system
      </div>
      <div style={{
        fontFamily: S_FONTS.display,
        fontWeight: 600, fontSize: 48,
        letterSpacing: '-0.035em',
        color: S_PALETTE.ink, lineHeight: 1,
      }}>
        built up,{' '}
        <span style={{
          fontFamily: S_FONTS.serif, fontStyle: 'italic',
          fontWeight: 400, color: S_PALETTE.moss600,
          letterSpacing: '-0.02em',
        }}>
          atom by atom
        </span>
        .
      </div>
    </div>
  );
}

// ── Main scene ─────────────────────────────────────────────────────────
function SystemScene() {
  return (
    <>
      {/* Background tint */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(ellipse at 50% 50%, ${S_PALETTE.cream} 0%, ${S_PALETTE.creamDk} 100%)`,
      }}/>

      <SystemSectionTitle />
      <SettleCaption />
      <AmberPageBloom />

      {/* Connecting lines render FIRST so tiles draw on top of them */}
      <ConnectingLines />

      {/* Tiles bottom→top (later tiles paint on top of lines) */}
      <Tier1Tokens />
      <Tier2Components />
      <Tier3Patterns />
      <Tier4Page />

      <TierCaption />

      <SFilmGrain opacity={0.06} />
      <SCornerChrome />
    </>
  );
}

Object.assign(window, {
  SystemScene,
  S_PALETTE,
  S_FONTS,
});
