/* Poise onboarding - Act 4 (Commitment) + Act 5 (Conversion): S17, S18, S21-S24 */

const { useState, useEffect, useLayoutEffect, useRef } = React;
const { Button: CButton, Badge: CBadge } = window.PoiseDesignSystem_eee0d2;

/* Extra Lucide-style icons for the showcase */
const S45 = ({ children, size = 24, sw = 2, style }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" style={style} aria-hidden="true">{children}</svg>
);
const IconWalk = (p) => <S45 {...p}><circle cx="13" cy="4.5" r="2"></circle><path d="M12.5 8.5 10 13l-2.5 7"></path><path d="M12.5 8.5 15 12l3 1.5"></path><path d="M10 13l3 2.5 1 6"></path><path d="M10 8.8 7 10.5 6 14"></path></S45>;
const IconDesk = (p) => <S45 {...p}><path d="M3 10h18"></path><path d="M5 10v9"></path><path d="M19 10v9"></path><path d="M9 10V7a3 3 0 0 1 6 0v3"></path></S45>;
const IconChores = (p) => <S45 {...p}><path d="M12 3c1 3 4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-2.5C9 10 10 8 12 3z"></path><path d="M8 14a4 4 0 0 0 8 0"></path></S45>;
const IconCar = (p) => <S45 {...p}><path d="M5 16l1.5-5.5A2 2 0 0 1 8.4 9h7.2a2 2 0 0 1 1.9 1.5L19 16"></path><path d="M3 16h18v3h-2.5"></path><path d="M3 16v3h2.5"></path><circle cx="7.5" cy="19" r="1.5"></circle><circle cx="16.5" cy="19" r="1.5"></circle></S45>;
const IconPhoneTilt = (p) => <S45 {...p}><rect x="7" y="3" width="10" height="18" rx="2.5"></rect><line x1="11" y1="18" x2="13" y2="18"></line></S45>;
const IconFlag = (p) => <S45 {...p}><path d="M6 21V4"></path><path d="M6 4.5h11l-2.8 4.2L17 13H6"></path></S45>;
const IconLockOpen = (p) => <S45 {...p}><rect x="3" y="11" width="18" height="11" rx="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></S45>;
const IconStar = (p) => <S45 {...p}><polygon points="12 2 15.1 8.3 22 9.3 17 14.1 18.2 21 12 17.8 5.8 21 7 14.1 2 9.3 8.9 8.3 12 2"></polygon></S45>;
const IconBolt = (p) => <S45 {...p}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></S45>;
const IconBars = (p) => <S45 {...p}><line x1="6" y1="20" x2="6" y2="15"></line><line x1="12" y1="20" x2="12" y2="9"></line><line x1="18" y1="20" x2="18" y2="4"></line></S45>;
const IconInfinity = (p) => <S45 {...p}><path d="M6 8c2.5 0 3.5 4 6 4s3.5-4 6-4a4 4 0 0 1 0 8c-2.5 0-3.5-4-6-4s-3.5 4-6 4a4 4 0 0 1 0-8z"></path></S45>;

/* ============ S21 · Hold to commit - signature moment 3 ============ */
const HOLD_MS = 1687.5; // matches reference iOS hold duration (1.6875s)

function CommitScreen() {
  const flow = useFlow();
  const [prog, setProg] = useState(0);        // 0..1
  const [committed, setCommitted] = useState(false);
  const holding = useRef(false);
  const raf = useRef(null);
  const doneTimer = useRef(null);

  useEffect(() => () => { cancelAnimationFrame(raf.current); clearTimeout(doneTimer.current); }, []);

  const loop = (dir) => {
    cancelAnimationFrame(raf.current);
    let last = performance.now();
    const step = (now) => {
      const dt = now - last; last = now;
      setProg((p) => {
        const np = Math.max(0, Math.min(1, p + (dir * dt) / (flow.t.motion ? HOLD_MS : 240)));
        if (np >= 1 && !committed) finish();
        else if ((dir > 0 && np < 1) || (dir < 0 && np > 0)) raf.current = requestAnimationFrame(step);
        return np;
      });
    };
    raf.current = requestAnimationFrame(step);
  };

  const finish = () => {
    setCommitted(true);
    PoiseAudio.success();
    track('commit_completed', {});
    doneTimer.current = setTimeout(() => flow.go('commit-day1'), flow.t.motion ? 260 : 60);
  };

  const down = (e) => { e.preventDefault(); if (committed) return; holding.current = true; loop(1); };
  const up = () => { if (committed || !holding.current) return; holding.current = false; loop(-1); };

  const amp = `${(0.2 + prog * 1.3).toFixed(2)}px`; // escalating haptic
  const ringStyle = (sz) => ({
    width: sz, height: sz, borderRadius: '50%',
    background: prog <= 0.001
      ? 'var(--surface-elevated)'
      : prog >= 0.999
      ? 'var(--gradient-cta)'
      : `conic-gradient(from -90deg, #C3D6B3 0%, #BDEECD ${prog * 55}%, #B0E7E4 ${prog * 100}%, var(--surface-elevated) ${prog * 100}%)`,
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    boxShadow: prog > 0.05 ? 'var(--glow-mint)' : 'none',
  });

  return (
    <Screen id="commit" label="S21 · Hold to commit" topBar={<TopBar onBack={() => flow.back()} />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 18, textAlign: 'center' }}>
        <H style={{ fontSize: 29 }}>One small commitment.</H>
        <P style={{ fontSize: 16, marginBottom: 26 }}>5 days to build the habit. You in?</P>

        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 28, marginTop: 36 }}>
          <div style={{ transform: `scale(${1 + prog * 0.14})`, transition: holding.current ? 'none' : 'transform 300ms var(--ease-out)' }}>
            <button
              onPointerDown={down} onPointerUp={up} onPointerLeave={up}
              className={prog > 0.02 && flow.t.motion ? 'hold-shake' : ''}
              style={{ '--amp': amp, ...ringStyle(132), border: 'none', cursor: 'pointer', padding: 0, touchAction: 'none', WebkitUserSelect: 'none', userSelect: 'none' }}>
              <span style={{ width: 116, height: 116, borderRadius: '50%', background: 'var(--bg-canvas)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <img src={window.__resources ? window.__resources.imgChevron : "/onboarding-demo/_ds/PoiseDesignSystem_eee0d2/assets/poise-chevron.svg"} alt="" style={{ width: 38, opacity: 0.65 + prog * 0.35, transform: `scale(${1 + prog * 0.12})`, transition: 'transform 100ms linear' }} />
              </span>
            </button>
          </div>
          <span className="poise-footnote">Hold to commit</span>
        </div>
      </div>
    </Screen>
  );
}

const STREAK_GROUP_DELAY = 850;    // ms before the dots start appearing, one by one
const STREAK_DOT_STAGGER = 150;    // gap between each dot's appearance
const STREAK_LIGHT_UP_DELAY = 2000; // day-1 dot sits unlit like the rest, then pulses mint
const STREAK_TEXT_DELAY = 2450;     // "Day 1 of a 5-day streak" appears slightly after light-up
const STREAK_LINGER_MS = 4950;      // total time this screen holds before auto-advancing (STREAK_TEXT_DELAY + 2.5s pause)

function Day1Screen() {
  const flow = useFlow();
  const doneTimer = useRef(null);
  const [lit, setLit] = useState(!flow.t.motion);
  
  // Get current day of week (0 = Sun, 1 = Mon, etc.) and map to next 5 days starting from today
  const today = new Date().getDay();
  const dayLabels = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
  const streakDays = Array.from({ length: 4 }, (_, i) => dayLabels[(today + i) % 7]);
  
  useEffect(() => {
    doneTimer.current = setTimeout(() => flow.next(), flow.t.motion ? STREAK_LINGER_MS : 350);
    return () => clearTimeout(doneTimer.current);
  }, []);
  useEffect(() => {
    if (!flow.t.motion) return;
    const t = setTimeout(() => setLit(true), STREAK_LIGHT_UP_DELAY);
    return () => clearTimeout(t);
  }, []);
  useEffect(() => {
    // Let the progress bar finish here, fully lit, then fade it out before
    // this screen advances to S22 (rather than snapping away on screen change).
    const fadeDelay = flow.t.motion ? Math.max(0, STREAK_LINGER_MS - 3800) : 50;
    const t = setTimeout(() => flow.setProgressFading(true), fadeDelay);
    return () => { clearTimeout(t); flow.setProgressFading(false); };
  }, []);

  return (
    <Screen id="commit-day1" label="S21 · Day 1 committed" topBar={<TopBar />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 10, textAlign: 'center' }}>
        <div style={{ position: 'relative', width: 120, height: 120, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 16 }}>
          {flow.t.motion && <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', border: '2px solid var(--mint)', animation: 'successBurst 900ms var(--ease-out) both' }}></span>}
          <div style={{ width: 110, height: 110, borderRadius: '50%', background: 'var(--gradient-cta)', boxShadow: 'var(--glow-mint)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <span style={{ width: 96, height: 96, borderRadius: '50%', background: 'var(--bg-canvas)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--mint)' }}>
              <window.IconCheck size={40} sw={2.2} />
            </span>
          </div>
        </div>
        {/* LOCKED: plan-agnostic - never "Day 1 of N" */}
        <span className="poise-display-lg onb-screen-enter" style={{ fontSize: 76 }}>Day 1</span>
        <span className="poise-caption" style={{ marginTop: 12 }}>starts now</span>

        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 22, marginTop: 44 }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 22 }}>
            {streakDays.map((day, i) => (
              <div
                key={i}
                className={flow.t.motion ? 'rise' : ''}
                style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, ...(flow.t.motion ? { animationDelay: `${STREAK_GROUP_DELAY + i * STREAK_DOT_STAGGER}ms` } : {}) }}
              >
                <span className={`streak-dot ${i === 0 && lit ? 'streak-dot-active streak-pop' : ''}`} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  {i === 0 && lit && <window.IconCheck size={14} sw={3.6} style={{ color: '#000' }} />}
                </span>
                <span className="streak-num" style={{ color: i === 0 && lit ? 'var(--text-accent)' : 'var(--text-secondary)' }}>{day}</span>
              </div>
            ))}
            <div
              className={flow.t.motion ? 'rise' : ''}
              style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, ...(flow.t.motion ? { animationDelay: `${STREAK_GROUP_DELAY + 4 * STREAK_DOT_STAGGER}ms` } : {}) }}
            >
              <span className="streak-goal"><window.IconFlag size={14} sw={2} /></span>
              <span className="streak-num" style={{ color: 'var(--text-accent)' }}>{dayLabels[(today + 4) % 7]}</span>
            </div>
          </div>
          <span className={`poise-footnote ${flow.t.motion ? (lit ? 'onb-screen-enter' : '') : ''}`} style={flow.t.motion && !lit ? { opacity: 0 } : (flow.t.motion ? { animationDelay: `${STREAK_TEXT_DELAY - 850}ms` } : {})}>Day 1 of a 5-day streak</span>
        </div>
      </div>
    </Screen>
  );
}

/* ============ S22 · Preparing your profile ============ */
function PreparingScreen() {
  const flow = useFlow();
  const [line, setLine] = useState(0);
  useEffect(() => {
    const base = flow.t.motion ? 1 : 0.1;
    const t1 = setTimeout(() => setLine(1), 1000 * base);
    const t2 = setTimeout(() => setLine(2), 2000 * base);
    const t3 = setTimeout(() => flow.next(), 3400 * base);
    return () => { clearTimeout(t1); clearTimeout(t2); clearTimeout(t3); };
  }, []);

  const styleName = (COACH_STYLES.find((c) => c.k === (flow.coachStyle || 'balanced')) || {}).name || 'Balanced';
  return (
    <Screen id="preparing" label="S22 · Preparing your profile" topBar={<TopBar />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 28 }}>
        <div style={{ position: 'relative', width: 96, height: 96, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          {flow.t.motion && <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', border: '2px solid var(--mint)', animation: 'pulseRing 1.5s var(--ease-out) infinite' }}></span>}
          <img src={window.__resources ? window.__resources.imgChevron : "/onboarding-demo/_ds/PoiseDesignSystem_eee0d2/assets/poise-chevron.svg"} alt="" className={flow.t.motion ? 'logo-breathe' : ''} style={{ width: 40 }} />
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, textAlign: 'center' }}>
          <span className="poise-title">Preparing your profile</span>
          <span key={line} className="poise-footnote onb-screen-enter">{[
            'Applying your baseline',
            `Setting ${styleName} coaching`,
            'Finalizing your profile',
          ][line]}</span>
        </div>
      </div>
    </Screen>
  );
}

/* ============ S17 · Feature showcase - "a day with Poise" horizontal walkthrough ============ */
function SensitivityBars({ level }) { /* 3 = stricter, 1 = lighter, 0 = silent */
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 4, height: 22 }}>
      {[0, 1, 2].map((i) => (
        <span key={i} style={{ width: 6, height: 8 + i * 6, borderRadius: 3, background: i < level ? 'var(--mint)' : 'var(--gray-700)', transition: 'background 400ms var(--ease-out)' }}></span>
      ))}
    </div>
  );
}

function CardActivity({ live }) {
  const MODES = [
    { Icon: IconWalk, name: 'On a walk', level: 3, word: 'Stricter' },
    { Icon: IconDesk, name: 'At your desk', level: 2, word: 'Lighter' },
    { Icon: IconCar, name: 'Driving or cycling', level: 0, word: 'Silent' },
    { Icon: IconChores, name: 'standing tasks', level: 0, word: 'Silent' },
  ];
  const [m, setM] = useState(0);
  useEffect(() => {
    if (!live) return;
    const iv = setInterval(() => setM((x) => (x + 1) % MODES.length), 1800);
    return () => clearInterval(iv);
  }, [live]);
  const mode = MODES[m];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
      <div style={{ display: 'flex', gap: 18, alignItems: 'center' }}>
        {MODES.map(({ Icon }, i) => (
          <span key={i} style={{ color: i === m ? 'var(--mint)' : 'var(--gray-700)', transform: i === m ? 'scale(1.18)' : 'scale(1)', transition: 'all 450ms var(--ease-out)' }}><Icon size={28} sw={1.8} /></span>
        ))}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, height: 26 }}>
        <SensitivityBars level={mode.level} />
        <span key={m} className="poise-caption onb-screen-enter" style={{ color: mode.level ? 'var(--text-accent)' : 'var(--text-secondary)' }}>{mode.word} · {mode.name}</span>
      </div>
    </div>
  );
}

function CardPhone({ live }) {
  const [quiet, setQuiet] = useState(false);
  useEffect(() => {
    if (!live) return;
    const iv = setInterval(() => setQuiet((q) => !q), 2200);
    return () => clearInterval(iv);
  }, [live]);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 22 }}>
        <span style={{ color: 'var(--text-primary)', transform: quiet ? 'rotate(-24deg)' : 'rotate(0deg)', transition: 'transform 600ms var(--ease-out)' }}><IconPhoneTilt size={34} sw={1.7} /></span>
        <span style={{ color: quiet ? 'var(--gray-700)' : 'var(--mint)', transition: 'color 400ms var(--ease-out)', position: 'relative' }}>
          <window.IconBell size={30} sw={1.7} />
          <span style={{ position: 'absolute', left: -3, top: '48%', width: quiet ? 38 : 0, height: 2, background: 'var(--gray-400)', borderRadius: 1, transform: 'rotate(-38deg)', transition: 'width 350ms var(--ease-out)' }}></span>
        </span>
      </div>
      <span className="poise-caption" style={{ color: quiet ? 'var(--text-accent)' : 'var(--text-secondary)', transition: 'color 400ms var(--ease-out)', height: 14 }}>{quiet ? 'On your phone: staying quiet' : 'Heads up: coaching on'}</span>
    </div>
  );
}

function CardAutostart({ live }) {
  const [on, setOn] = useState(false);
  useEffect(() => {
    if (!live) { setOn(true); return; }
    const iv = setInterval(() => setOn((q) => !q), 2600);
    return () => clearInterval(iv);
  }, [live]);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
      <div style={{ position: 'relative', width: 64, height: 64, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        {on && live && <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', border: '1.5px solid var(--mint)', animation: 'pulseRing 1.8s var(--ease-out) infinite' }}></span>}
        <img src={window.__resources ? window.__resources.imgAirpodsPro : "/onboarding-demo/app/airpods-pro.svg"} alt="" style={{ width: 40, height: 'auto', opacity: on ? 1 : 0.5, transition: 'opacity 500ms var(--ease-out)' }} />
      </div>
      <span className="poise-caption" style={{ display: 'flex', alignItems: 'center', gap: 6, height: 14 }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: on ? 'var(--mint)' : 'var(--gray-700)', animation: on && live ? 'monitorDot 1.6s ease-in-out infinite' : 'none' }}></span>
        {on ? 'Monitoring' : 'AirPods out'}
      </span>
    </div>
  );
}


const DAY_CARDS = [
  { id: 'phone', title: 'Pauses when you check your phone.', body: 'Poise only nudges you when you’re not looking at your phone, so it won’t bother you mid-scroll.', Demo: CardPhone },
  { id: 'activity', title: 'Adjusts to what you’re doing.', body: 'Stricter on a walk, easier at your desk, silent behind the wheel.', note: 'Poise also uses smart motion detection to pause nudges for standing tasks where looking down is required, like cooking or doing the dishes.', Demo: CardActivity },
  { id: 'autostart', title: 'Starts monitoring automatically.', body: 'Pop your AirPods in. Poise picks right up, working quietly in the background.', Demo: CardAutostart },
];

function ShowcaseScreen() {
  const flow = useFlow();
  const [idx, setIdx] = useState(0);
  const trackRef = useRef(null);
  const paneRefs = useRef([]);
  const live = flow.t.motion;
  const n = DAY_CARDS.length;
  const lastIdx = n - 1;
  const isLast = idx === lastIdx;
  // Once the visitor has reached the last pane, Continue stays lit and
  // clickable even if they scroll back to an earlier one - reaching the end
  // is the unlock, not currently being on it. Lives on flow (not local
  // state) because this screen unmounts/remounts on navigation - going to
  // S18 and back to S17 would otherwise lose the unlock.
  const reachedEnd = flow.showcaseReachedEnd;
  useEffect(() => { if (isLast) flow.setShowcaseReachedEnd(true); }, [isLast]); // eslint-disable-line react-hooks/exhaustive-deps

  const scrollToIdx = (i) => {
    const track = trackRef.current, pane = paneRefs.current[i];
    if (!track || !pane) return;
    track.scrollTo({ left: pane.offsetLeft, behavior: 'smooth' });
  };

  useEffect(() => {
    const track = trackRef.current;
    if (!track || !('IntersectionObserver' in window)) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((en) => {
        if (en.isIntersecting && en.intersectionRatio > 0.6) setIdx(Number(en.target.dataset.i));
      });
    }, { root: track, threshold: [0.6] });
    paneRefs.current.forEach((p) => p && obs.observe(p));
    return () => obs.disconnect();
  }, []);

  const [peek, setPeek] = useState(false);
  useEffect(() => {
    /* one-time nudge so the sideways scroll is discoverable; never repeats.
       Purely a CSS affordance on the next button, no programmatic scrolling:
       scrollBy() fights mandatory scroll-snap and can misfire onto pane 2. */
    const t = setTimeout(() => setPeek(true), 900);
    return () => clearTimeout(t);
  }, []);

  const onContinue = () => {
    if (!reachedEnd) {
      const track = trackRef.current;
      if (track) {
        track.scrollBy({ left: 60, behavior: 'smooth' });
        setTimeout(() => track.scrollBy({ left: -60, behavior: 'smooth' }), 420);
      }
      return;
    }
    flow.next();
  };

  return (
    <Screen
      id="showcase" label="S17 · Feature showcase"
      topBar={<TopBar onBack={() => flow.back()} />}
      cta={
        <React.Fragment>
          <span className="poise-footnote" style={{ marginBottom: 10, textAlign: 'center' }}>Every mode is yours. Switch any of it on or off.</span>
          <CButton variant="primary" size="lg" fullWidth onClick={onContinue} style={{ opacity: reachedEnd ? 1 : 0.4, transition: 'opacity 250ms var(--ease-out)' }}>Continue</CButton>
        </React.Fragment>
      }
    >
      <div style={{ display: 'flex', flexDirection: 'column', paddingTop: 18, flex: 1, minHeight: 0 }}>
        <div style={{ position: 'relative', flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
          <div ref={trackRef} className="day-track" style={{ margin: '0 calc(-1 * var(--screen-margin))' }}>
            {DAY_CARDS.map(({ id, title, body, note, Demo }, i) => (
              <div key={id} ref={(el) => (paneRefs.current[i] = el)} data-i={i} className="day-pane" style={{ padding: '8px var(--screen-margin)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 20, textAlign: 'center' }}>
                <div style={{ minHeight: 120, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                  <Demo live={live && i === idx} />
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                  <span className="poise-title" style={{ fontSize: 20 }}>{title}</span>
                  <P style={{ fontSize: 15 }}>{body}</P>
                  {note && <P style={{ fontSize: 15 }}>{note}</P>}
                </div>
              </div>
            ))}
          </div>
          <button type="button" className={`day-prev ${idx > 0 ? 'shown' : ''}`} aria-label="Previous moment" onClick={() => scrollToIdx(Math.max(0, idx - 1))}>
            <window.IconChevron size={16} sw={2.2} style={{ transform: 'rotate(180deg)' }} />
          </button>
          <button type="button" className={`day-next ${isLast ? 'done' : ''} ${peek && idx === 0 ? 'peek' : ''}`} aria-label="Next moment" onAnimationEnd={() => setPeek(false)} onClick={() => scrollToIdx(Math.min(lastIdx, idx + 1))}>
            <window.IconChevron size={16} sw={2.2} />
          </button>
        </div>
        <div style={{ display: 'flex', justifyContent: 'center', gap: 7, padding: '16px 0 4px' }}>
          {DAY_CARDS.map((c, i) => <button key={c.id} className={`car-dot ${i === idx ? 'on' : ''}`} style={{ border: 'none', padding: 0, cursor: 'pointer' }} onClick={() => scrollToIdx(i)} aria-label={`Moment ${i + 1}`}></button>)}
        </div>
      </div>
    </Screen>
  );
}

/* ============ S18 · Price anchor ============ */
const ANCHOR_ROWS = [
  { old: 'Another gadget to buy and charge', neu: 'AirPods you already own' },
  { old: 'Visible and unflattering wearable', neu: 'Nothing to see, nothing to explain' },
  { old: 'Remember it every single morning', neu: 'Automatic, in the background' },
];

function AnchorScreen() {
  const flow = useFlow();
  const [stage, setStage] = useState(0);
  const [ctaReady, setCtaReady] = useState(false);

  // Title @ 0ms (CSS rise, immediate) -> price card @ +1000ms -> the whole
  // comparison table (column headers + all rows together, no per-row
  // stagger) @ +1000ms after the price card. stage 0 = nothing but the
  // title, 1 = price card, 2 = table.
  useEffect(() => {
    const base = flow.t.motion ? 1 : 0.05;
    const stageTimes = [1000, 2000];
    const ts = stageTimes.map((t, i) => setTimeout(() => setStage(i + 1), t * base));
    const ctaTimer = setTimeout(() => setCtaReady(true), (stageTimes[stageTimes.length - 1] + 500) * base);
    return () => { ts.forEach(clearTimeout); clearTimeout(ctaTimer); };
  }, []);

  return (
    <Screen
      id="anchor" label="S18 · Price anchor"
      topBar={<TopBar onBack={() => flow.back()} />}
      cta={<CButton variant="primary" size="lg" fullWidth disabled={!ctaReady} onClick={() => flow.next()}>Continue</CButton>}
    >
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', paddingTop: 18, gap: 28 }}>
        <H style={{ fontSize: 28 }}>
          <span className="rise" style={{ display: 'block' }}>Other solutions are costly, and you have to wear them.</span>
        </H>
        <div style={{
          padding: '20px 20px 22px', borderRadius: 'var(--radius-card)', background: 'var(--surface-card)', border: '1px solid var(--border-hairline)', display: 'flex', flexDirection: 'column', gap: 6,
          opacity: stage > 0 ? 1 : 0,
          transform: stage > 0 ? 'none' : 'translateY(8px)',
          transition: 'opacity 450ms var(--ease-out), transform 450ms var(--ease-out)',
        }}>
          <span className="poise-caption" style={{ color: 'var(--text-secondary)' }}>Smart posture wearables</span>
          <span className="poise-display-lg" style={{ fontSize: 46 }}>$100–140</span>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column' }}>
          <div style={{
            display: 'grid', gridTemplateColumns: '1fr 1fr', columnGap: 18, paddingBottom: 10,
            opacity: stage > 1 ? 1 : 0,
            transform: stage > 1 ? 'none' : 'translateY(8px)',
            transition: 'opacity 450ms var(--ease-out), transform 450ms var(--ease-out)',
          }}>
            <span className="poise-caption" style={{ color: 'var(--text-secondary)' }}>Other solutions</span>
            <span className="poise-caption" style={{ color: 'var(--mint)', paddingLeft: 18 }}>Poise</span>
          </div>
          {ANCHOR_ROWS.map((r, i) => {
            const visible = stage > 1;
            return (
              <div key={i} style={{
                display: 'grid', gridTemplateColumns: '1fr 1fr', columnGap: 18, alignItems: 'start',
                padding: '14px 0', borderTop: '1px solid var(--border-hairline)',
                opacity: visible ? 1 : 0,
                transform: visible ? 'none' : 'translateY(8px)',
                transition: 'opacity 450ms var(--ease-out), transform 450ms var(--ease-out)',
              }}>
                <span className="poise-body" style={{ color: 'var(--text-secondary)', fontSize: 14.5, lineHeight: 1.3, display: 'flex', alignItems: 'flex-start', gap: 6 }}>
                  <span style={{ color: 'var(--text-secondary)', opacity: 0.7, display: 'flex', marginTop: 2, flexShrink: 0 }}><window.IconClose size={12} sw={2.4} /></span>{r.old}
                </span>
                <span className="poise-body" style={{ fontSize: 14.5, fontWeight: 500, lineHeight: 1.3, paddingLeft: 18, display: 'flex', alignItems: 'flex-start', gap: 6 }}>
                  <span style={{ color: 'var(--mint)', display: 'flex', marginTop: 2, flexShrink: 0 }}><window.IconCheck size={12} sw={2.6} /></span>{r.neu}
                </span>
              </div>
            );
          })}
        </div>
      </div>
    </Screen>
  );
}

/* ============ S20 · Paywall (port of PoisePaywallView.swift) + exit sheet ============
   Faithful port of the SwiftUI paywall: back chevron (top-left), ambient mint
   glow, staggered reveal, the "how your free trial works" timeline, annual/
   monthly plan cards, and the pinned footer. Onboarding is always trial-eligible,
   so only the trial-framing variant is ported.

   Exit-intent behaviour (from PoisePaywallView.sandboxBackBar + PoiseTrialExitView):
   the FIRST back tap intercepts with the free-trial exit sheet (shown once ever).
   Once that sheet has been offered and dismissed, a SECOND back tap steps back to
   S21 (hold to commit), the user's chosen destination. */

/* Launch control arm: 7-day trial on annual, no trial on monthly. Trial length
   and eligibility are the A/B variable — prices are the fixed default. */
const PW_PLANS_TRIAL = [
  { id: 'annual', title: 'Annual', perPeriod: '$5.83/mo', subline: '7 days free · then $69.99/yr', trialDays: 7, savePercent: 42, featured: true },
  { id: 'monthly', title: 'Monthly', perPeriod: '$9.99/mo', subline: 'Billed monthly', trialDays: 0, savePercent: null, featured: false },
];
/* No-trial variant (user has already used their free trial): bills immediately,
   so no "X days free" sublines, no trial timeline, CTA reads "Subscribe". */
const PW_PLANS_EXPIRED = [
  { id: 'annual', title: 'Annual', perPeriod: '$5.83/mo', subline: '$69.99 / year', trialDays: 0, savePercent: 42, featured: true },
  { id: 'monthly', title: 'Monthly', perPeriod: '$9.99/mo', subline: 'Billed monthly', trialDays: 0, savePercent: null, featured: false },
];

function PwTimelineRow({ Icon, title, body, isEnd }) {
  return (
    <div style={{ display: 'flex', gap: 14, alignItems: 'stretch' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 36, flexShrink: 0 }}>
        <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--mint)', color: 'var(--text-on-accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          <Icon size={17} sw={2} />
        </div>
        {isEnd ? (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
            <div style={{ width: 3, height: 18, borderRadius: 2, marginTop: 2, background: 'linear-gradient(180deg, rgba(189,238,205,0.45), var(--mint))' }}></div>
            <span style={{ color: 'var(--mint)', marginTop: -4, display: 'flex' }}><window.IconChevronDown size={13} sw={2.6} /></span>
          </div>
        ) : (
          <div style={{ flex: 1, width: 3, minHeight: 20, borderRadius: 2, marginTop: 2, background: 'linear-gradient(180deg, rgba(189,238,205,0.45), var(--mint))' }}></div>
        )}
      </div>
      <div style={{ paddingBottom: isEnd ? 4 : 20 }}>
        <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--text-primary)' }}>{title}</div>
        <div style={{ fontSize: 13, color: 'var(--text-secondary)', marginTop: 2, lineHeight: 1.4 }}>{body}</div>
      </div>
    </div>
  );
}

/* Benefit row for the no-trial variant — mint icon, no connector (no sequence). */
function PwBenefitRow({ Icon, title, body }) {
  return (
    <div style={{ display: 'flex', gap: 14, alignItems: 'flex-start' }}>
      <div style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--mint)', color: 'var(--text-on-accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Icon size={17} sw={2} />
      </div>
      <div>
        <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--text-primary)' }}>{title}</div>
        <div style={{ fontSize: 13, color: 'var(--text-secondary)', marginTop: 2, lineHeight: 1.4 }}>{body}</div>
      </div>
    </div>
  );
}

/* Full-screen exit-intent offer (port of ExitOfferScaffold). Two flavours below. */
function ExitSheet({ eyebrow, title, subtitle, ctaTitle, dismissTitle, chargeNote, onClaim, onDismiss, children }) {
  return (
    <React.Fragment>
      <div className="sheet-dim" onClick={onDismiss}></div>
      <div className="pw-exit-sheet" data-screen-label="S20x · Exit offer">
        <div className="pw-exit-glow"></div>
        <div style={{ position: 'relative', zIndex: 1, flex: 1, minHeight: 0, boxSizing: 'border-box', display: 'flex', flexDirection: 'column', padding: '46px 22px 34px', overflowY: 'auto' }}>
          <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
            <button onClick={onDismiss} aria-label="Close" className="pw-back" style={{ background: 'var(--surface-card)' }}><window.IconClose size={15} sw={2} /></button>
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', marginTop: 4 }}>
            <span style={{ font: '700 12px var(--font-sans)', letterSpacing: '1.4px', color: 'var(--mint)', marginBottom: 8 }}>{eyebrow}</span>
            <H style={{ fontSize: 29 }}>{title}</H>
            <P style={{ fontSize: 15, marginTop: 6 }}>{subtitle}</P>
          </div>

          <div style={{ marginTop: 12 }}>
            <div className="pw-offer-card">{children}</div>
          </div>

          <div style={{ flex: '1 1 12px', minHeight: 12 }}></div>

          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0 }}>
            <CButton variant="primary" size="lg" fullWidth onClick={onClaim}>{ctaTitle}</CButton>
            <button className="ghost-link" style={{ fontSize: 14, marginTop: 8 }} onClick={onDismiss}>{dismissTitle}</button>
            <span className="poise-footnote" style={{ textAlign: 'center', marginTop: 10, lineHeight: 1.45 }}>{chargeNote}</span>
          </div>
        </div>
      </div>
    </React.Fragment>
  );
}

/* Trial-eligible exit (port of PoiseTrialExitView): re-emphasise the free trial. */
function TrialExitSheet({ onClaim, onDismiss }) {
  return (
    <ExitSheet
      eyebrow="ARE YOU SURE?"
      title={<React.Fragment>Your free trial<br />is still here</React.Fragment>}
      subtitle="Try everything free for 7 days. Nothing to pay today, cancel anytime."
      ctaTitle="Start free trial"
      dismissTitle="No thanks"
      chargeNote="7 days free, then $69.99/yr. Cancel anytime up to 24 hours before your trial ends."
      onClaim={onClaim}
      onDismiss={onDismiss}
    >
      <div className="pw-offer-badge" style={{ marginBottom: 8 }}>7 DAYS FREE</div>
      <span style={{ fontSize: 34, fontWeight: 800, letterSpacing: '-1px', color: 'var(--text-primary)' }}>$0.00</span>
      <span style={{ fontSize: 14, color: 'var(--text-secondary)', marginTop: 6 }}>due today · then $69.99/yr, cancel anytime</span>
    </ExitSheet>
  );
}

/* Trial-expired win-back (port of PoiseWinbackView): 50% off the first month. */
function WinbackSheet({ onClaim, onDismiss }) {
  return (
    <ExitSheet
      eyebrow="SPECIAL OFFER"
      title={<React.Fragment>50% off your<br />first month</React.Fragment>}
      subtitle="Pick up where you left off, at half the price."
      ctaTitle="Claim discount"
      dismissTitle="No thanks"
      chargeNote="First month $4.99, then $9.99/mo. Cancel anytime. Auto-renews until canceled."
      onClaim={onClaim}
      onDismiss={onDismiss}
    >
      <div className="pw-offer-badge" style={{ marginBottom: 8 }}>SAVE 50%</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontSize: 20, fontWeight: 600, color: 'var(--text-secondary)', textDecoration: 'line-through' }}>$9.99</span>
        <span style={{ fontSize: 34, fontWeight: 800, letterSpacing: '-1px', color: 'var(--text-primary)' }}>$4.99</span>
      </div>
      <span style={{ fontSize: 14, color: 'var(--text-secondary)', marginTop: 6 }}>for your first month, then $9.99/mo</span>
    </ExitSheet>
  );
}

function PaywallScreen() {
  const flow = useFlow();
  const trialFraming = flow.t.variantPaywall !== 'Trial used';
  const plans = trialFraming ? PW_PLANS_TRIAL : PW_PLANS_EXPIRED;
  const [plan, setPlan] = useState('annual');
  const [sheet, setSheet] = useState(false);
  const [pumped, setPumped] = useState(null);
  const [phase, setPhase] = useState(flow.t.motion ? 0 : 4);
  const [glowOn, setGlowOn] = useState(!flow.t.motion);

  useEffect(() => { track('paywall_shown', { variant: trialFraming ? 'trial' : 'expired' }); }, [trialFraming]);

  useEffect(() => {
    if (!flow.t.motion) return;
    const t = setTimeout(() => setGlowOn(true), 20);
    return () => clearTimeout(t);
  }, [flow.t.motion]);

  /* Staggered reveal: ~0.5s blank, then sections fade+rise in order (matches the
     Swift appearPhase sequence). */
  useEffect(() => {
    if (!flow.t.motion) { setPhase(4); return; }
    const timers = [];
    for (let step = 1; step <= 4; step++) {
      timers.push(setTimeout(() => setPhase(step), 500 + (step - 1) * 120));
    }
    return () => timers.forEach(clearTimeout);
  }, [flow.t.motion]);

  const selected = plans.find((p) => p.id === plan) || plans[0];
  /* Trial framing is per-plan, not per-screen: under the control arm a
     trial-eligible user picking Monthly gets no trial, so the timeline, the
     "no payment now" reassurance and the purchase event all have to follow the
     selected plan rather than the variant. */
  const hasTrial = trialFraming && selected.trialDays > 0;
  const lead = selected.trialDays >= 14 ? 4 : 2;
  const remindDay = Math.max(selected.trialDays - lead, 1);

  const reveal = (p) => ({
    opacity: phase >= p ? 1 : 0,
    transform: phase >= p ? 'none' : 'translateY(12px)',
    transition: 'opacity 350ms var(--ease-out), transform 350ms var(--ease-out)',
  });

  const select = (id) => {
    if (id === plan) return;
    setPlan(id);
    setPumped(id);
    setTimeout(() => setPumped(null), 340);
  };

  /* Back chevron (matches PoisePaywallView build-65 E-back-loop): exitOffered is
     per-paywall-instance state, re-armed on entry and when the variant changes.
     First tap offers the exit sheet; after it has been offered and dismissed, a
     second tap steps back to S21 (hold to commit). The flow-level flag is kept in
     sync so the "Re-arm exit sheet" tweak still works. */
  const [exitOffered, setExitOffered] = useState(false);
  useEffect(() => { setExitOffered(false); }, [trialFraming]);
  useEffect(() => { if (!flow.exitSheetShown) setExitOffered(false); }, [flow.exitSheetShown]);
  const onBack = () => {
    if (!exitOffered) {
      setExitOffered(true);
      flow.setExitSheetShown(true);
      setSheet(true);
      track('exit_sheet_shown', {});
    } else {
      track('paywall_back', { to: 'commit' });
      flow.go('commit');
    }
  };

  const purchase = () => { track(hasTrial ? 'trial_started' : 'subscribed', { plan }); flow.go('success'); };

  return (
    <div data-screen-label="S20 · Paywall" style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', paddingTop: 'var(--status-bar-inset)', overflow: 'hidden' }}>
      <div className="pw-glow" style={{ opacity: glowOn ? 1 : 0, transition: 'opacity 3000ms linear' }}></div>

      {/* back bar */}
      <div style={{ height: 48, display: 'flex', alignItems: 'center', gap: 4, padding: '0 10px', flexShrink: 0, position: 'relative', zIndex: 2, ...reveal(1) }}>
        <div style={{ width: 60, flexShrink: 0 }}>
          <button onClick={onBack} aria-label="Back" className="ghost-link" style={{ display: 'flex', alignItems: 'center', padding: '8px 10px' }}><window.IconChevron size={20} sw={2} style={{ transform: 'rotate(180deg)' }} /></button>
        </div>
      </div>

      {/* content — tuned to fit one view; scrolls (scrollbar hidden) on a
          shorter real viewport instead of clipping */}
      <div className="onb-scroll-y" style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '0 var(--screen-margin)', position: 'relative', zIndex: 1 }}>
        <div style={{ textAlign: 'center', marginTop: hasTrial ? 0 : -20, ...reveal(1) }}>
          {hasTrial ? (
            <H style={{ fontSize: 34, letterSpacing: '-0.6px' }}>How your free<br />trial works</H>
          ) : (
            <React.Fragment>
              <H style={{ fontSize: 30, letterSpacing: '-0.6px' }}>Keep your<br />posture on track</H>
              {!trialFraming && <P style={{ fontSize: 14, marginTop: 6 }}>Your free trial has ended. Subscribe to continue.</P>}
            </React.Fragment>
          )}
        </div>

        {hasTrial ? (
          <div style={{ marginTop: 32, ...reveal(2) }}>
            <PwTimelineRow Icon={IconLockOpen} title="Today" body="Unlock real-time slouch nudges, posture insights, and your daily Poise score." />
            <PwTimelineRow Icon={window.IconBell} title={`In ${remindDay} days`} body={`We'll remind you ${lead} days before your trial ends. No surprises.`} />
            <PwTimelineRow Icon={IconStar} title={`In ${selected.trialDays} days`} body="Your subscription begins. Cancel anytime before then and you won't be charged." isEnd />
          </div>
        ) : (
          <div style={{ marginTop: 20, display: 'flex', flexDirection: 'column', gap: 14, ...reveal(2) }}>
            <PwBenefitRow Icon={IconBolt} title="Real-time slouch nudges" body="A gentle audio cue through your AirPods the moment you start to slouch." />
            <PwBenefitRow Icon={IconBars} title="Your daily Poise score" body="Track your posture over time and watch your streak grow." />
            <PwBenefitRow Icon={IconInfinity} title="Always sensing, in the background" body="Poise keeps working while you do. No need to keep the app open." />
          </div>
        )}

        <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginTop: hasTrial ? 8 : 20, paddingBottom: 8, ...reveal(3) }}>
          {plans.map((p) => {
            const sel = plan === p.id;
            return (
              <button key={p.id} className={`pw-plan ${sel ? 'sel' : ''} ${pumped === p.id ? 'pump' : ''}`} onClick={() => select(p.id)}>
                {p.featured && <div className="pw-band">MOST POPULAR</div>}
                <div className="pw-plan-row">
                  <span style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
                    <span style={{ fontWeight: 700, fontSize: 18 }}>{p.title}</span>
                    <span style={{ fontSize: 13, color: 'var(--text-secondary)' }}>{p.subline}</span>
                  </span>
                  <span style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
                    <span style={{ fontWeight: 700, fontSize: 17 }}>{p.perPeriod}</span>
                    {p.savePercent != null && <span className="pw-save">Save {p.savePercent}%</span>}
                  </span>
                </div>
              </button>
            );
          })}
        </div>
      </div>

      {/* pinned footer */}
      <div style={{ flexShrink: 0, padding: '12px var(--screen-margin) 34px', display: 'flex', flexDirection: 'column', alignItems: 'center', position: 'relative', zIndex: 2, ...reveal(4) }}>
        {hasTrial && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 10 }}>
            <span style={{ color: 'var(--mint)', display: 'flex' }}><window.IconCheck size={13} sw={3} /></span>
            <span style={{ fontSize: 12.5, color: 'var(--text-secondary)' }}>No payment required now</span>
          </div>
        )}
        <CButton variant="primary" size="lg" fullWidth onClick={purchase}>Continue</CButton>
        <span className="poise-footnote" style={{ textAlign: 'center', marginTop: 18, lineHeight: 1.5, padding: '0 6px', fontSize: 11 }}>
          By continuing, you agree to our <a href="https://poise-app.com/terms" target="_blank" rel="noopener noreferrer" style={{ color: 'var(--text-secondary)', textDecoration: 'underline' }}>Terms</a> and <a href="https://poise-app.com/privacy" target="_blank" rel="noopener noreferrer" style={{ color: 'var(--text-secondary)', textDecoration: 'underline' }}>Privacy Policy</a>.
        </span>
        <button
          onClick={() => track('restore_purchases_tapped', {})}
          className="poise-footnote"
          style={{ marginTop: 12, background: 'none', border: 'none', padding: 0, cursor: 'pointer', color: 'var(--text-secondary)', fontSize: 11, textDecoration: 'underline' }}
        >
          Restore purchases
        </button>
      </div>

      {sheet && (
        trialFraming ? (
          <TrialExitSheet
            onClaim={purchase}
            onDismiss={() => { track('exit_offer_denied', {}); setSheet(false); }}
          />
        ) : (
          <WinbackSheet
            onClaim={purchase}
            onDismiss={() => { track('exit_offer_denied', {}); setSheet(false); }}
          />
        )
      )}
    </div>
  );
}

/* ============ S21 · Success ============ */
function SuccessScreen() {
  const flow = useFlow();
  useEffect(() => {
    track('onboarding_completed', {});
    PoiseAudio.success();
    const t = setTimeout(() => flow.go('end'), flow.t.motion ? 3100 : 400);
    return () => clearTimeout(t);
  }, []);
  return (
    <Screen id="success" label="S21 · Success" enter="from-black" topBar={<TopBar />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 14, textAlign: 'center' }}>
        <div style={{ position: 'relative', width: 84, height: 84, marginBottom: 14 }}>
          <span style={{ position: 'absolute', inset: 0, borderRadius: '50%', border: '2px solid var(--mint)', animation: 'pulseRingStay 2.2s var(--ease-out) 1 forwards' }}></span>
          <span className="onb-screen-enter" style={{ width: 84, height: 84, borderRadius: '50%', background: 'var(--accent-muted)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--mint)', boxShadow: 'var(--glow-mint)' }}>
            <window.IconCheck size={36} sw={2.2} />
          </span>
        </div>
        <H style={{ fontSize: 30 }}>You’re set.</H>
        <P>Better posture starts today.</P>
      </div>
    </Screen>
  );
}

/* ============ End of flow (prototype affordance, not a product screen) ============ */
function EndScreen() {
  const flow = useFlow();
  return (
    <Screen id="end" label="End of flow (prototype)" topBar={<TopBar />}>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 18, textAlign: 'center' }}>
        <span className="poise-caption">End of onboarding</span>
        <P style={{ fontSize: 15 }}>The user lands in the app here: home screen, monitoring live.</P>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'stretch', gap: 10, alignSelf: 'stretch' }}>
          {/* The only exit mobile visitors get - the desktop chrome link isn't
              rendered there - so it ships on both layouts. */}
          <CButton variant="primary" size="md" fullWidth onClick={() => { window.location.href = '/'; }}>Back to the Poise home page</CButton>
          <CButton variant="secondary" size="md" fullWidth onClick={() => flow.restart()}>Restart the flow</CButton>
        </div>
      </div>
    </Screen>
  );
}

Object.assign(window, { CommitScreen, Day1Screen, PreparingScreen, ShowcaseScreen, AnchorScreen, PaywallScreen, SuccessScreen, EndScreen });
