// ═══════════════════════════════════════════════════════════════════════════
// FOUR ROOM ARCHETYPES
//
//   A · Band       full-bleed espresso, one enormous gold number
//   B · Split      40% statement on paper / 60% product UI bleeding off-frame
//   C · Field      a dense glyph field that carries the argument without prose
//   D · Statement  centred serif and air — used twice only, as punctuation
//
// Adjacent rooms never share an archetype. That alternation is the point:
// ten rooms in one composition is ten rooms nobody remembers.
// ═══════════════════════════════════════════════════════════════════════════

const { useState: useAS, useEffect: useAE, useRef: useAR } = React;

// ?static=1 freezes every animation so a headless render can settle. Without
// it the rAF loops keep Chrome's virtual clock from ever going idle and the
// PDF captures a blank first paint.
const isStatic = (function () {
  try { return new URLSearchParams(location.search).get('static') === '1'; }
  catch (e) { return false; }
})();
window.__STATIC = isStatic;

const reduceMotion = () => {
  if (isStatic) return true;
  try { return window.matchMedia('(prefers-reduced-motion: reduce)').matches; }
  catch (e) { return false; }
};

// ── Hero numbers arrive rather than appear. Nothing sells a number like
//    watching it count. Parses whatever numeric part a string contains and
//    preserves the prefix/suffix around it ($1.7 trillion, $300 000, 1%).
function useHeroCount(text, ms) {
  const [out, setOut] = useAS(text);
  useAE(() => {
    const s = String(text == null ? '' : text);
    const m = s.match(/([^\d]*)([\d]+(?:[.,][\d]+)?)(.*)$/s);
    if (!m || reduceMotion()) { setOut(s); return; }
    const pre = m[1], raw = m[2], post = m[3];
    const dec = (raw.split(/[.,]/)[1] || '').length;
    const sep = raw.indexOf(',') > -1 ? ',' : '.';
    const target = parseFloat(raw.replace(',', '.'));
    if (!isFinite(target)) { setOut(s); return; }

    let frame = 0, done = false;
    const t0 = performance.now();
    const step = (now) => {
      const p = Math.min(1, (now - t0) / (ms || 700));
      const eased = 1 - Math.pow(1 - p, 3);            // ease-out cubic
      const v = (target * eased).toFixed(dec).replace('.', sep);
      setOut(pre + v + post);
      if (p < 1) frame = requestAnimationFrame(step);
      else done = true;
    };
    frame = requestAnimationFrame(step);
    // Never leave a partial number on screen if the animation is interrupted.
    const safety = setTimeout(() => { if (!done) setOut(s); }, (ms || 700) + 400);
    return () => { cancelAnimationFrame(frame); clearTimeout(safety); };
  }, [text, ms]);
  return out;
}
window.__useCountUp = useHeroCount;

// ───────────────────────── A · THE BAND
// The product's KPI strip at full-screen scale. Edge to edge, no margins.
function Band({ value, line, label, figId, room }) {
  const shown = useHeroCount(value, 700);
  const Fig = window.Fig;
  const num = (
    <div className="band-hero" style={{
      fontFamily: 'var(--serif)', fontWeight: 600,
      fontSize: 'var(--t-hero)', lineHeight: 0.86,
      letterSpacing: '-0.03em', color: 'var(--gold)',
      // Long strings ("$1.7 trillion") must still fill the frame without
      // wrapping; the container scales them down rather than breaking them.
      whiteSpace: 'nowrap', maxWidth: '100%',
    }}>{shown}</div>
  );
  return (
    <div className="room room-band" style={{
      position: 'absolute', inset: 0,
      background: 'var(--espresso)',
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center',
      paddingTop: 56, paddingInline: 'var(--s4)',
      textAlign: 'center', overflow: 'hidden',
    }}>
      {label && (
        <div style={{
          fontFamily: 'var(--sans)', fontSize: 'var(--t-label)', fontWeight: 600,
          letterSpacing: '0.08em', textTransform: 'uppercase',
          color: 'var(--on-esp-30)', marginBottom: 'var(--s3)',
        }}>{label}</div>
      )}

      <div style={{ maxWidth: '100%' }}>
        {figId ? <Fig id={figId} tone="var(--gold)">{num}</Fig> : num}
      </div>

      {/* The gold rule draws in under the number. */}
      <div className="band-rule" style={{
        height: 3, background: 'var(--gold)', marginTop: 'var(--s3)',
        width: 'min(420px, 60%)', transformOrigin: 'left center',
      }} />

      {line && (
        <div style={{
          marginTop: 'var(--s4)', maxWidth: '30ch',
          fontFamily: 'var(--serif)', fontWeight: 500,
          fontSize: 'var(--t-headline)', lineHeight: 1.15,
          color: 'var(--paper)',
        }}>{line}</div>
      )}

      {room && <window.Objections room={room} onDark />}
    </div>
  );
}

// ───────────────────────── B · THE SPLIT
// Statement left on paper, real product UI right, bleeding off the frame edge.
// The screenshot is the argument that the thing exists.
function Split({ label, headline, body, img, imgAlt, imgW, room, foot, dense }) {
  return (
    <div className="room room-split" data-dense={dense ? '1' : undefined} style={{
      position: 'absolute', inset: 0, paddingTop: 56,
      display: 'grid', gridTemplateColumns: '40fr 60fr',
      alignItems: 'center', overflow: 'hidden',
    }}>
      <div style={{
        paddingLeft: 'var(--margin)', paddingRight: 'var(--s4)',
        paddingBlock: 'var(--s3)',
        textAlign: 'left', zIndex: 1,
        maxHeight: '100%', overflow: 'hidden',
        display: 'flex', flexDirection: 'column', justifyContent: 'center',
      }}>
        {label && (
          <div style={{
            fontFamily: 'var(--sans)', fontSize: 'var(--t-label)', fontWeight: 600,
            letterSpacing: '0.08em', textTransform: 'uppercase',
            color: 'var(--gold)', marginBottom: 'var(--s2)',
          }}>{label}</div>
        )}
        <h2 style={{
          margin: 0, fontFamily: 'var(--serif)', fontWeight: 500,
          fontSize: 'var(--t-headline)', lineHeight: 1.1,
          letterSpacing: '-0.015em', color: 'var(--espresso)',
        }}>{headline}</h2>
        {body && (
          <div style={{
            marginTop: 'var(--s2)', fontFamily: 'var(--sans)',
            fontSize: 'var(--t-body)', lineHeight: 1.45, color: 'var(--ink-70)',
            minHeight: 0,
          }}>{body}</div>
        )}
        {foot}
        {room && <window.Objections room={room} align="left" />}
      </div>

      {/* Bleeds off the right edge — never a floating mockup. */}
      <div className="split-shot" style={{
        position: 'relative', height: '100%',
        display: 'flex', alignItems: 'center', overflow: 'hidden',
      }}>
        <img src={img} alt={imgAlt || ''} style={{
          position: 'absolute', left: 0, top: '50%',
          transform: 'translateY(-50%)',
          width: imgW || '150%', height: 'auto',
          maxWidth: 'none', maxHeight: 'none',
          borderRadius: '14px 0 0 14px',
          boxShadow: '0 40px 90px -40px rgba(57,54,48,0.45)',
        }} />
      </div>
    </div>
  );
}

// ───────────────────────── C · THE FIELD
// The viewer sees the proportion instead of reading it. The mark is the
// product's own level-bar glyph from the Nivå column, not a new chart style.
function Field({ label, headline, total, filled, unit, note, room, figId, cap, foot }) {
  const [on, setOn] = useAS(reduceMotion());
  useAE(() => {
    if (reduceMotion()) return;
    const t = setTimeout(() => setOn(true), 120);
    return () => clearTimeout(t);
  }, []);
  const Fig = window.Fig;

  // One mark per unit up to `cap`, then each mark stands for several. Keeps
  // 125 000 legible without pretending to draw 125 000 elements.
  const marks = Math.min(total, cap || 600);
  const scale = total / marks;
  const goldMarks = Math.max(1, Math.round(filled / scale));

  const headEl = (
    <h2 style={{
      margin: 0, fontFamily: 'var(--serif)', fontWeight: 500,
      fontSize: 'var(--t-headline)', lineHeight: 1.1,
      letterSpacing: '-0.015em', color: 'var(--espresso)',
    }}>{headline}</h2>
  );

  return (
    <div className="room room-field" style={{
      position: 'absolute', inset: 0,
      paddingTop: 'calc(56px + var(--s3))', paddingBottom: 'var(--s3)',
      paddingInline: 'var(--margin)',
      display: 'flex', flexDirection: 'column', justifyContent: 'center',
      alignItems: 'center', textAlign: 'center', overflow: 'hidden',
    }}>
      {label && (
        <div style={{
          fontFamily: 'var(--sans)', fontSize: 'var(--t-label)', fontWeight: 600,
          letterSpacing: '0.08em', textTransform: 'uppercase',
          color: 'var(--ink-50)', marginBottom: 'var(--s2)', flex: '0 0 auto',
        }}>{label}</div>
      )}
      {figId ? <Fig id={figId}>{headEl}</Fig> : headEl}

      <div className="field-grid" style={{
        marginTop: 'var(--s4)', width: '100%', maxWidth: 'var(--measure)',
        display: 'flex', flexWrap: 'wrap', gap: 4,
        justifyContent: 'center', alignContent: 'center', flex: '1 1 auto',
        minHeight: 0, maxHeight: '46vh', overflow: 'hidden',
      }}>
        {Array.from({ length: marks }).map((_, i) => (
          <span key={i} style={{
            width: 9, height: 20, borderRadius: 2,
            background: i < goldMarks ? 'var(--gold)' : 'var(--ink-12)',
            opacity: on ? 1 : 0,
            transition: reduceMotion() ? 'none'
              : `opacity 500ms ease ${Math.min(700, i * (700 / marks))}ms`,
          }} />
        ))}
      </div>

      {note && (
        <div style={{
          marginTop: 'var(--s3)', fontFamily: 'var(--sans)',
          fontSize: 'var(--t-body)', color: 'var(--ink-70)',
        }}>{note}</div>
      )}
      {unit}
      {foot}
      {room && <window.Objections room={room} />}
    </div>
  );
}

// ───────────────────────── D · THE STATEMENT
// Punctuation. Used twice in the whole deck, which is where its force comes
// from — it was the default for all ten rooms, and defaults are invisible.
function Statement({ children, sub, room }) {
  return (
    <div className="room room-statement" style={{
      position: 'absolute', inset: 0,
      paddingTop: 56, paddingInline: 'var(--margin)',
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center',
      textAlign: 'center', overflow: 'hidden',
    }}>
      <div style={{
        fontFamily: 'var(--serif)', fontWeight: 500,
        fontSize: 'var(--t-headline)', lineHeight: 1.1,
        letterSpacing: '-0.02em', color: 'var(--espresso)', maxWidth: '22ch',
      }}>{children}</div>
      {sub && (
        <div style={{
          marginTop: 'var(--s4)', maxWidth: '46ch',
          fontFamily: 'var(--sans)', fontSize: 'var(--t-sub)',
          lineHeight: 1.45, color: 'var(--ink-70)',
        }}>{sub}</div>
      )}
      {room && <window.Objections room={room} />}
    </div>
  );
}

window.Band = Band;
window.Split = Split;
window.Field = Field;
window.Statement = Statement;
