// responsive-scenes.jsx — Responsive morph: desktop → tablet → mobile → desktop
// Smoothly interpolates a single layout across viewports with fluid easing.

const R_PALETTE = {
  cream: '#f5f0e8',
  creamDeep: '#ede6d8',
  paper: '#faf6ee',
  moss600: '#3f6b54',
  moss500: '#4d7e65',
  moss400: '#6fa37a',
  moss300: '#93b89a',
  moss200: '#b8cdbb',
  moss100: '#d7e1d4',
  amber: '#cd8a4b',
  amberSoft: '#e2a568',
  ink: '#0f1713',
  ink70: 'rgba(15,23,19,0.72)',
  ink40: 'rgba(15,23,19,0.40)',
  ink15: 'rgba(15,23,19,0.15)',
  ink08: 'rgba(15,23,19,0.08)',
};

const R_FONTS = {
  display: '"Space Grotesk", system-ui, sans-serif',
  serif: '"Instrument Serif", Georgia, serif',
  mono: '"JetBrains Mono", ui-monospace, monospace',
};

// Silky eased smoothstep (matches cubic-bezier(0.2, 0.7, 0.2, 1) feel)
const rEase = (t) => {
  if (t <= 0) return 0;
  if (t >= 1) return 1;
  // Smootherstep for a very silky morph
  return t * t * t * (t * (t * 6 - 15) + 10);
};
const rMix = (a, b, t) => a + (b - a) * t;
const rClamp = (v, a, b) => Math.max(a, Math.min(b, v));

// Continuous viewport width interpolation over 15s loop.
// Keyframes: 0..4s = desktop(1440). 4..6s = desktop→tablet. 6s = tablet(768).
// 6..9s = tablet→mobile. 9..11s = hold mobile(375). 11..14s = mobile→desktop.
// 14..15s = identity hold (already at desktop from 13s).
// Returns { vw, phase: 'desktop'|'tablet'|'mobile', progress within phase }
function viewportAt(t) {
  // Define anchors
  const anchors = [
    { t: 0,  vw: 1440 },
    { t: 4,  vw: 1440 },
    { t: 6,  vw: 768  },
    { t: 9,  vw: 375  },
    { t: 11, vw: 375  },
    { t: 14, vw: 1440 },
    { t: 15, vw: 1440 },
  ];
  let a = anchors[0], b = anchors[anchors.length - 1];
  for (let i = 0; i < anchors.length - 1; i++) {
    if (t >= anchors[i].t && t <= anchors[i + 1].t) {
      a = anchors[i]; b = anchors[i + 1];
      break;
    }
  }
  const span = b.t - a.t;
  const local = span > 0 ? rEase((t - a.t) / span) : 0;
  const vw = a.vw + (b.vw - a.vw) * local;
  return vw;
}

// Smooth 0..1 weights for each viewport tier (continuous, no snap).
// Each weight peaks at its native width and falls off smoothly to neighbors.
function tierWeights(vw) {
  const DESK = 1440, TAB = 768, MOB = 375;
  // Use raw distance-based smoothing so layout morphs are fluid.
  let desk = 0, tab = 0, mob = 0;
  if (vw >= TAB) {
    const u = rEase((vw - TAB) / (DESK - TAB)); // 0 at tab → 1 at desk
    desk = u; tab = 1 - u; mob = 0;
  } else {
    const u = rEase((vw - MOB) / (TAB - MOB));  // 0 at mob → 1 at tab
    tab = u; mob = 1 - u; desk = 0;
  }
  return { desk, tab, mob };
}

// Blend scalar by tier weights
const blendT = (w, vd, vt, vm) => w.desk * vd + w.tab * vt + w.mob * vm;

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

function RCornerChrome({ vw }) {
  const time = useTime();
  const pulse = 0.5 + 0.5 * Math.sin(time * Math.PI * 1.2);

  // Morphing amber orb (corner, faint)
  const w = 3;
  const r1 = 50 + Math.sin(time * w * 0.7) * 14;
  const r2 = 50 + Math.cos(time * w * 0.6 + 1) * 16;
  const r3 = 50 + Math.sin(time * w * 0.9 + 2) * 12;
  const r4 = 50 + Math.cos(time * w * 0.5 + 3) * 18;

  // Viewport label: current vw rounded
  const vwRounded = Math.round(vw / 5) * 5;
  let tierLabel = 'desktop';
  if (vwRounded < 600) tierLabel = 'mobile';
  else if (vwRounded < 1100) tierLabel = 'tablet';

  return (
    <>
      {/* Top-left logo */}
      <img
        src="assets/digital-heroes-logo.png"
        alt=""
        style={{
          position: 'absolute', left: 56, top: 44,
          height: 54, width: 'auto',
          opacity: 0.42,
          pointerEvents: 'none',
        }}
      />

      {/* Top-right section caption + pulse */}
      <div style={{
        position: 'absolute', right: 56, top: 58,
        display: 'flex', alignItems: 'center', gap: 12,
        fontFamily: R_FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.12em',
        color: R_PALETTE.ink70,
        textTransform: 'uppercase',
      }}>
        <div style={{
          width: 8, height: 8, borderRadius: 4,
          background: R_PALETTE.moss500,
          opacity: 0.4 + 0.6 * pulse,
          boxShadow: `0 0 ${8 + 12 * pulse}px ${R_PALETTE.moss400}`,
        }}/>
        <span style={{ opacity: 0.55 }}>§ 06 · responsive</span>
      </div>

      {/* Top-right edition line */}
      <div style={{
        position: 'absolute', right: 56, top: 86,
        fontFamily: R_FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.16em',
        color: R_PALETTE.ink40,
        textTransform: 'uppercase',
      }}>
        vol. 01 — viewport study
      </div>

      {/* Bottom-right viewport label — morphs numerically */}
      <div style={{
        position: 'absolute', right: 56, bottom: 70,
        display: 'flex', alignItems: 'baseline', gap: 14,
        fontFamily: R_FONTS.mono,
        fontSize: 14,
        letterSpacing: '0.1em',
        color: R_PALETTE.moss600,
        textTransform: 'uppercase',
      }}>
        <span style={{
          fontWeight: 500,
          fontVariantNumeric: 'tabular-nums',
          color: R_PALETTE.ink,
          fontSize: 18,
          letterSpacing: '-0.01em',
        }}>
          {vwRounded}
        </span>
        <span style={{ opacity: 0.7 }}>· {tierLabel}</span>
      </div>

      {/* Bottom-left folio */}
      <div style={{
        position: 'absolute', left: 56, bottom: 52,
        fontFamily: R_FONTS.mono,
        fontSize: 12,
        letterSpacing: '0.12em',
        color: R_PALETTE.ink40,
      }}>
        fig.&nbsp;&nbsp;06·i — one layout, three viewports
      </div>

      {/* Bottom-right small amber orb (faint, persistent) */}
      <div style={{
        position: 'absolute', right: 28, bottom: 28,
        width: 22, height: 22,
        background: `radial-gradient(circle at 38% 32%, ${R_PALETTE.amberSoft}, ${R_PALETTE.amber})`,
        borderRadius: `${r1}% ${100-r1}% ${r2}% ${100-r2}% / ${r3}% ${r4}% ${100-r4}% ${100-r3}%`,
        opacity: 0.28,
        filter: 'blur(0.5px)',
      }}/>
    </>
  );
}

// ─── Center-stage section title (always present, fades subtly) ──────────
function RSectionTitle() {
  return (
    <div style={{
      position: 'absolute',
      left: '50%', top: 116,
      transform: 'translateX(-50%)',
      textAlign: 'center',
      whiteSpace: 'nowrap',
    }}>
      <div style={{
        fontFamily: R_FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.28em',
        color: R_PALETTE.moss500,
        textTransform: 'uppercase',
        marginBottom: 8,
      }}>
        responsive ⸺ desktop &nbsp;·&nbsp; tablet &nbsp;·&nbsp; mobile
      </div>
      <div style={{
        fontFamily: R_FONTS.display,
        fontWeight: 700,
        fontSize: 34,
        letterSpacing: '-0.03em',
        color: R_PALETTE.ink,
        lineHeight: 1,
        whiteSpace: 'nowrap',
      }}>
        One layout, <span style={{ fontFamily: R_FONTS.serif, fontStyle: 'italic', fontWeight: 400, color: R_PALETTE.moss600 }}>every</span> viewport.
      </div>
    </div>
  );
}

// ─── The morphing "page" container ─────────────────────────────────────
// The page container renders ONE hero layout whose width scales smoothly;
// its nav, grid, typography all interpolate by tier weights.
function PageContainer() {
  const time = useTime();
  const vw = viewportAt(time);
  const w = tierWeights(vw);

  // Display container: map vw to actual pixel width of the rendered frame.
  // Desktop 1440 → 1360px wide; tablet 768 → 760px; mobile 375 → 420px.
  // Smooth scale based on vw.
  const containerW = rMix(
    420,                       // at mobile end
    rMix(760, 1360, (vw > 768 ? (vw - 768) / (1440 - 768) : 0)),
    (vw >= 768 ? 1 : (vw - 375) / (768 - 375))
  );

  // Height scales with content — generous to prevent clipping on desktop 3-col grid.
  const containerH = blendT(w, 720, 760, 820);

  const containerX = 960; // center
  const containerY = 228 + containerH / 2; // vertical center

  return (
    <>
      {/* Ruler line behind container (moss-tinted) — spans frame width but the container sits within */}
      <div style={{
        position: 'absolute',
        left: 180, right: 180, top: 206,
        height: 1,
        background: R_PALETTE.moss200,
        opacity: 0.7,
      }}/>
      {/* ruler ticks */}
      {[0, 0.25, 0.5, 0.75, 1].map((frac, i) => (
        <div key={i} style={{
          position: 'absolute',
          left: `calc(180px + ${frac} * (100% - 360px))`,
          top: 202, height: 10, width: 1,
          background: R_PALETTE.moss300,
        }}/>
      ))}
      {/* ruler mono labels */}
      <div style={{
        position: 'absolute', left: 180, top: 182,
        fontFamily: R_FONTS.mono, fontSize: 11,
        color: R_PALETTE.moss500, letterSpacing: '0.12em',
        textTransform: 'uppercase',
      }}>
        0px
      </div>
      <div style={{
        position: 'absolute', right: 180, top: 182,
        fontFamily: R_FONTS.mono, fontSize: 11,
        color: R_PALETTE.moss500, letterSpacing: '0.12em',
        textTransform: 'uppercase',
      }}>
        1440px →
      </div>

      {/* Live width indicator — a moss bracket from center out to current container edges */}
      <ContainerBracket cx={containerX} y={202} width={containerW} />

      {/* Container frame */}
      <div style={{
        position: 'absolute',
        left: containerX - containerW / 2,
        top: 230,
        width: containerW,
        height: containerH,
        background: R_PALETTE.paper,
        border: `1px solid ${R_PALETTE.ink15}`,
        boxShadow: `0 30px 80px rgba(40,30,15,0.12), 0 0 0 6px ${R_PALETTE.creamDeep}`,
        overflow: 'hidden',
      }}>
        <PageContent width={containerW} weights={w} />
      </div>

      {/* CWV metrics callout (9–11s on mobile hold) */}
      <CWVCallout cx={containerX} cy={230 + containerH + 40} />
    </>
  );
}

// Bracket indicating current container width, positioned above the container
function ContainerBracket({ cx, y, width }) {
  const left = cx - width / 2;
  const right = cx + width / 2;
  return (
    <>
      {/* left tick */}
      <div style={{ position: 'absolute', left, top: y, width: 1, height: 16, background: R_PALETTE.moss600 }}/>
      {/* right tick */}
      <div style={{ position: 'absolute', left: right, top: y, width: 1, height: 16, background: R_PALETTE.moss600 }}/>
      {/* connecting line */}
      <div style={{ position: 'absolute', left, top: y + 6, width: width, height: 1, background: R_PALETTE.moss500, opacity: 0.7 }}/>
      {/* center label with px value */}
      <div style={{
        position: 'absolute',
        left: cx, top: y - 26,
        transform: 'translateX(-50%)',
        fontFamily: R_FONTS.mono,
        fontSize: 11, letterSpacing: '0.2em',
        color: R_PALETTE.moss600,
        textTransform: 'uppercase',
        fontVariantNumeric: 'tabular-nums',
      }}>
        container
      </div>
    </>
  );
}

// ─── Page content: nav, hero, feature grid — all tier-aware ─────────────
function PageContent({ width, weights }) {
  // Inner padding (scales with viewport)
  const padX = blendT(weights, 56, 40, 22);
  const padY = blendT(weights, 36, 30, 22);

  return (
    <div style={{
      position: 'absolute', inset: 0,
      padding: `${padY}px ${padX}px`,
      display: 'flex', flexDirection: 'column',
      gap: blendT(weights, 44, 36, 28),
    }}>
      <PageNav weights={weights} width={width} />
      <PageHero weights={weights} width={width} />
      <FeatureGrid weights={weights} width={width} />
    </div>
  );
}

// Nav bar
function PageNav({ weights, width }) {
  const w = weights;

  // Logo font size scales
  const logoSize = blendT(w, 18, 16, 15);

  // Nav items: desktop=5 visible, tablet=3 + glyph, mobile=hamburger only
  const allItems = ['work', 'studio', 'journal', 'approach', 'contact'];
  const tabletItems = allItems.slice(0, 3);

  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      width: '100%',
    }}>
      {/* Brand */}
      <div style={{
        fontFamily: R_FONTS.display,
        fontWeight: 700,
        fontSize: logoSize,
        letterSpacing: '-0.03em',
        color: R_PALETTE.ink,
      }}>
        studio<span style={{ fontFamily: R_FONTS.serif, fontStyle: 'italic', fontWeight: 400, color: R_PALETTE.moss600 }}>.seventy</span>
      </div>

      {/* Nav cluster with crossfading variants (avoids layout jumps) */}
      <div style={{ position: 'relative', display: 'flex', alignItems: 'center', minHeight: 28 }}>
        {/* Desktop nav — full set */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 22,
          opacity: w.desk,
          transition: 'none',
        }}>
          {allItems.map(item => (
            <NavPill key={item} label={item} size={13} />
          ))}
        </div>

        {/* Tablet nav — 3 pills + glyph */}
        <div style={{
          position: 'absolute', right: 0, top: '50%',
          transform: 'translateY(-50%)',
          display: 'flex', alignItems: 'center', gap: 14,
          opacity: w.tab,
          pointerEvents: w.tab > 0.5 ? 'auto' : 'none',
        }}>
          {tabletItems.map(item => (
            <NavPill key={item} label={item} size={12} />
          ))}
          <MoreGlyph />
        </div>

        {/* Mobile nav — hamburger only */}
        <div style={{
          position: 'absolute', right: 0, top: '50%',
          transform: 'translateY(-50%)',
          opacity: w.mob,
          pointerEvents: w.mob > 0.5 ? 'auto' : 'none',
        }}>
          <Hamburger />
        </div>
      </div>
    </div>
  );
}

function NavPill({ label, size }) {
  return (
    <div style={{
      padding: '6px 14px',
      border: `1px solid ${R_PALETTE.ink15}`,
      borderRadius: 999,
      fontFamily: R_FONTS.display,
      fontSize: size,
      fontWeight: 500,
      letterSpacing: '0.04em',
      color: R_PALETTE.ink70,
      textTransform: 'uppercase',
      background: 'rgba(255,253,247,0.5)',
      whiteSpace: 'nowrap',
    }}>
      {label}
    </div>
  );
}

function MoreGlyph() {
  return (
    <div style={{
      width: 36, height: 36, borderRadius: 999,
      border: `1px solid ${R_PALETTE.ink15}`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: R_PALETTE.ink70,
    }}>
      <div style={{ display: 'flex', gap: 3 }}>
        <div style={{ width: 3, height: 3, borderRadius: 2, background: R_PALETTE.ink70 }}/>
        <div style={{ width: 3, height: 3, borderRadius: 2, background: R_PALETTE.ink70 }}/>
        <div style={{ width: 3, height: 3, borderRadius: 2, background: R_PALETTE.ink70 }}/>
      </div>
    </div>
  );
}

function Hamburger() {
  return (
    <div style={{
      width: 40, height: 40, borderRadius: 999,
      border: `1px solid ${R_PALETTE.ink15}`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: 'rgba(255,253,247,0.5)',
    }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        <div style={{ width: 16, height: 2, background: R_PALETTE.ink }}/>
        <div style={{ width: 16, height: 2, background: R_PALETTE.ink }}/>
        <div style={{ width: 16, height: 2, background: R_PALETTE.ink }}/>
      </div>
    </div>
  );
}

// Hero section
function PageHero({ weights, width }) {
  const w = weights;
  // Headline size scales with tier
  const h1Size = blendT(w, 62, 46, 34);
  // Subcopy size
  const subSize = blendT(w, 18, 16, 14);

  // CTA: desktop/tablet inline, mobile full-width
  const ctaFull = w.mob;

  return (
    <div style={{
      display: 'flex', flexDirection: 'column',
      gap: blendT(w, 24, 20, 16),
      paddingTop: blendT(w, 24, 18, 12),
    }}>
      <div style={{
        fontFamily: R_FONTS.display,
        fontWeight: 700,
        fontSize: h1Size,
        lineHeight: 1.02,
        letterSpacing: '-0.04em',
        color: R_PALETTE.ink,
        maxWidth: blendT(w, 900, 600, 320),
      }}>
        Sites that ship on a{' '}
        <span style={{
          fontFamily: R_FONTS.serif,
          fontStyle: 'italic',
          fontWeight: 400,
          color: R_PALETTE.moss600,
          letterSpacing: '-0.02em',
        }}>clear</span>{' '}
        schedule.
      </div>

      <div style={{
        fontFamily: R_FONTS.display,
        fontWeight: 400,
        fontSize: subSize,
        lineHeight: 1.5,
        color: R_PALETTE.ink70,
        maxWidth: blendT(w, 600, 480, 320),
        letterSpacing: '-0.01em',
      }}>
        We build editorial websites in 6-week sprints — design, build, measure, ship.
      </div>

      {/* CTA pill — grows to full width on mobile */}
      <div style={{
        display: 'flex',
        marginTop: blendT(w, 10, 8, 6),
      }}>
        <div style={{
          padding: blendT(w, 16, 14, 14) + 'px ' + blendT(w, 32, 28, 24) + 'px',
          background: R_PALETTE.moss600,
          borderRadius: 999,
          color: R_PALETTE.paper,
          fontFamily: R_FONTS.display,
          fontWeight: 600,
          fontSize: blendT(w, 16, 15, 15),
          letterSpacing: '0.02em',
          width: ctaFull > 0.5 ? '100%' : 'auto',
          textAlign: 'center',
          boxShadow: '0 6px 18px rgba(63,107,84,0.24)',
          whiteSpace: 'nowrap',
        }}>
          Start a project →
        </div>
      </div>
    </div>
  );
}

// Feature grid: 3-col desktop → 2-col tablet → 1-col mobile (smooth)
function FeatureGrid({ weights, width }) {
  const w = weights;

  // Compute "effective cols": 3 at desktop, 2 at tablet, 1 at mobile.
  // We'll render 3 cards and let their flex-basis interpolate.
  const gap = blendT(w, 20, 16, 14);

  // Card width as % of row.
  // desktop: 33.33%, tablet: 48%, mobile: 100%
  // But wrapping must happen at mobile (cards stack). Use flexBasis.
  const cardBasis = blendT(w, 33.33, 48, 100);

  const features = [
    { eyebrow: '01', title: 'Strategy', body: 'Positioning, naming, content architecture.' },
    { eyebrow: '02', title: 'Design',   body: 'Editorial layouts, type systems, brand polish.' },
    { eyebrow: '03', title: 'Build',    body: 'Next.js, headless CMS, clean handoff.' },
  ];

  return (
    <div style={{
      display: 'flex', flexWrap: 'wrap',
      gap,
      marginTop: blendT(w, 12, 8, 4),
    }}>
      {features.map((f, i) => {
        // Hide card 03 on mobile (1-col stack) to save height — fade instead
        const cardOpacity = (i === 2) ? (1 - w.mob * 0.0) : 1; // keep all visible
        return (
          <div
            key={f.title}
            style={{
              flex: `0 0 calc(${cardBasis}% - ${gap}px)`,
              minWidth: 0,
              padding: blendT(w, 22, 18, 16),
              background: 'rgba(255,253,247,0.7)',
              border: `1px solid ${R_PALETTE.ink08}`,
              borderRadius: 2,
              display: 'flex', flexDirection: 'column',
              gap: 8,
              opacity: cardOpacity,
            }}
          >
            <div style={{
              fontFamily: R_FONTS.mono,
              fontSize: 11,
              letterSpacing: '0.22em',
              color: R_PALETTE.moss500,
              textTransform: 'uppercase',
            }}>
              § {f.eyebrow}
            </div>
            <div style={{
              fontFamily: R_FONTS.display,
              fontWeight: 700,
              fontSize: blendT(w, 22, 20, 18),
              letterSpacing: '-0.02em',
              color: R_PALETTE.ink,
            }}>
              {f.title}
            </div>
            <div style={{
              fontFamily: R_FONTS.display,
              fontWeight: 400,
              fontSize: blendT(w, 14, 13, 13),
              lineHeight: 1.45,
              color: R_PALETTE.ink70,
              letterSpacing: '-0.005em',
            }}>
              {f.body}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─── CWV callout (appears during 9–11s mobile hold, fades around transitions) ───
function CWVCallout({ cx, cy }) {
  const time = useTime();
  // Appear smoothly starting 8.6s, peak 9.4–10.8, fade by 11.4
  let opacity = 0;
  if (time >= 8.6 && time <= 11.6) {
    if (time < 9.3) opacity = rEase((time - 8.6) / 0.7);
    else if (time > 10.9) opacity = 1 - rEase((time - 10.9) / 0.7);
    else opacity = 1;
  }
  if (opacity < 0.01) return null;

  const metrics = [
    { label: 'LCP', value: '1.2s' },
    { label: 'INP', value: '120ms' },
    { label: 'CLS', value: '0.03' },
  ];

  return (
    <div style={{
      position: 'absolute',
      left: cx, top: cy,
      transform: 'translate(-50%, 0)',
      opacity,
      display: 'flex', alignItems: 'center', gap: 24,
      padding: '14px 26px',
      background: R_PALETTE.paper,
      border: `1px solid ${R_PALETTE.moss300}`,
      boxShadow: '0 10px 30px rgba(63,107,84,0.14)',
      borderRadius: 2,
      position: 'absolute',
    }}>
      {/* Check mark */}
      <div style={{
        width: 28, height: 28, borderRadius: 14,
        background: R_PALETTE.moss500,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
          <path d="M3 7.2l2.8 2.6L11 4.2" stroke={R_PALETTE.paper} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </div>

      <div style={{
        fontFamily: R_FONTS.display,
        fontWeight: 600,
        fontSize: 15,
        letterSpacing: '-0.01em',
        color: R_PALETTE.ink,
      }}>
        Core Web Vitals
      </div>

      <div style={{ width: 1, height: 24, background: R_PALETTE.ink15 }}/>

      {metrics.map((m, i) => (
        <div key={m.label} style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
          <span style={{
            fontFamily: R_FONTS.mono,
            fontSize: 11,
            letterSpacing: '0.18em',
            color: R_PALETTE.moss500,
            textTransform: 'uppercase',
          }}>
            {m.label}
          </span>
          <span style={{
            fontFamily: R_FONTS.mono,
            fontSize: 15,
            color: R_PALETTE.ink,
            fontVariantNumeric: 'tabular-nums',
            fontWeight: 500,
          }}>
            {m.value}
          </span>
        </div>
      ))}
    </div>
  );
}

// ─── Phase caption at bottom (changes with viewport) ─────────────────────
function PhaseCaption({ vw }) {
  const time = useTime();
  let eyebrow = 'desktop', text = 'Editorial sites at full width.';
  if (vw < 500) { eyebrow = 'mobile';  text = 'Single column. Full-bleed CTA.'; }
  else if (vw < 1100) { eyebrow = 'tablet';  text = 'Two-column grid. Compact nav.'; }

  // CWV override from 9.3–10.9s
  if (time >= 9.3 && time <= 10.9) {
    eyebrow = 'measured'; text = 'We ship against the numbers.';
  }

  return (
    <div style={{
      position: 'absolute',
      left: '50%', bottom: 86,
      transform: 'translateX(-50%)',
      textAlign: 'center',
    }}>
      <div style={{
        fontFamily: R_FONTS.mono,
        fontSize: 11,
        letterSpacing: '0.24em',
        color: R_PALETTE.moss500,
        textTransform: 'uppercase',
        marginBottom: 6,
      }}>
        — {eyebrow} —
      </div>
    </div>
  );
}

// ─── Root scene ─────────────────────────────────────────────────────────
function ResponsiveScene() {
  const time = useTime();
  const vw = viewportAt(time);

  return (
    <>
      <RCornerChrome vw={vw} />
      <RSectionTitle />
      <PageContainer />
      <PhaseCaption vw={vw} />
      <RFilmGrain />
    </>
  );
}

Object.assign(window, {
  ResponsiveScene, R_PALETTE, R_FONTS,
  viewportAt, tierWeights, rEase,
});
