// atelier-screens.jsx — All six screens for the Atelier prototype.

const { useState: useS, useEffect: useE, useMemo: useM } = React;

// === Shared atoms ============================================================

function Pill({ palette, children, tone = 'default' }) {
  const C = palette;
  const tones = {
    default: { bg: C.cream, fg: C.umberSoft, br: C.umberHair },
    sienna:  { bg: 'rgba(201,123,95,0.12)', fg: C.terracotta, br: 'rgba(201,123,95,0.35)' },
    celadon: { bg: 'rgba(143,163,145,0.14)', fg: C.sage, br: 'rgba(143,163,145,0.4)' },
    brass:   { bg: C.brassLight, fg: C.brassDeep, br: C.brassDeep },
  }[tone];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '5px 10px', borderRadius: 99,
      background: tones.bg, color: tones.fg,
      border: `0.6px solid ${tones.br}`,
      fontFamily: window.ATELIER_TYPE.ui,
      fontSize: 10, letterSpacing: 2, textTransform: 'uppercase',
    }}>{children}</span>
  );
}

function Card({ palette, children, padding = 20, style }) {
  const C = palette;
  return (
    <div style={{
      background: C.cream,
      borderRadius: 14,
      padding,
      border: `0.6px solid ${C.umberHair}`,
      boxShadow: '0 14px 28px -22px rgba(42,34,27,0.35)',
      ...style,
    }}>{children}</div>
  );
}

function LayerToggle({ palette, layers, setLayers }) {
  const C = palette;
  const L = window.COPY.layers;
  const items = [
    { key: 'heatmap',    label: L.heatmap    },
    { key: 'hero',       label: L.hero       },
    { key: 'trajectory', label: L.trajectory },
    { key: 'tension',    label: L.tension    },
  ];
  return (
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
      {items.map((it) => {
        const on = layers[it.key];
        return (
          <button key={it.key}
            onClick={() => setLayers({ ...layers, [it.key]: !on })}
            style={{
              appearance: 'none', cursor: 'pointer',
              padding: '7px 12px', borderRadius: 99,
              border: `0.6px solid ${on ? C.umber : C.umberHair}`,
              background: on ? C.umber : C.cream,
              color: on ? C.cream : C.umberSoft,
              fontFamily: window.ATELIER_TYPE.ui,
              fontSize: 10, letterSpacing: 2, textTransform: 'uppercase',
              transition: 'all 180ms ' + window.ATELIER_EASE,
              display: 'inline-flex', alignItems: 'center', gap: 7,
            }}>
            <span style={{
              width: 6, height: 6, borderRadius: 99,
              background: on ? C.brassLight : 'transparent',
              border: `0.6px solid ${on ? C.brassLight : C.umberFaint}`,
            }} />
            {it.label}
          </button>
        );
      })}
    </div>
  );
}

// === 1. ONBOARDING ===========================================================
function OnboardingScreen({ palette, setRoute }) {
  const C = palette;
  const { isMobile, isTablet } = window.useBreakpoint();
  const [step, setStep] = useS(0);
  const steps = window.COPY.onboarding.steps;
  const cur = steps[step];

  return (
    <div style={{
      flex: 1, height: '100%', overflow: 'auto',
      background: C.boneSoft,
      position: 'relative',
    }}>
      {/* soft top illumination */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(120% 70% at 50% -20%, ${withAlpha(C.brassLight, 0.5)}, transparent 60%)`,
        pointerEvents: 'none',
      }} />
      <div style={{
        maxWidth: 880, margin: '0 auto',
        padding: isMobile ? '40px 20px 40px' : '90px 64px 64px',
        display: 'grid',
        gridTemplateColumns: isTablet ? '1fr' : '1fr 280px',
        gap: isTablet ? 32 : 64,
        alignItems: 'center',
        position: 'relative',
      }}>
        <div>
          <div style={{
            fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 3.5,
            textTransform: 'uppercase', opacity: 0.6, color: C.umberSoft, marginBottom: 16,
          }}>{cur.kicker}</div>
          <h1 style={{
            margin: 0,
            fontFamily: window.ATELIER_TYPE.display,
            fontWeight: 300, fontStyle: 'italic',
            fontSize: isMobile ? 42 : 68, lineHeight: 1.02,
            color: C.umber, letterSpacing: -0.8,
          }}>{cur.title}</h1>
          <p style={{
            marginTop: 28,
            fontFamily: window.ATELIER_TYPE.display,
            fontSize: 19, lineHeight: 1.55,
            color: C.umberSoft, maxWidth: 540,
          }}>{cur.body}</p>

          <div style={{ marginTop: 40, display: 'flex', alignItems: 'center', gap: 18 }}>
            {step > 0 && (
              <button
                onClick={() => setStep(step - 1)}
                style={ghostBtn(C)}>{window.COPY.onboarding.buttons.back}</button>
            )}
            {step < steps.length - 1 ? (
              <button
                onClick={() => setStep(step + 1)}
                style={primaryBtn(C)}>{window.COPY.onboarding.buttons.continue}</button>
            ) : (
              <button
                onClick={() => { localStorage.setItem('chesswarp_onboarding_seen', '1'); setRoute('home'); }}
                style={primaryBtn(C)}>{window.COPY.onboarding.buttons.enter}</button>
            )}
            <div style={{ display: 'flex', gap: 6, marginLeft: 8 }}>
              {steps.map((_, i) => (
                <div key={i} style={{
                  width: i === step ? 28 : 8, height: 4, borderRadius: 99,
                  background: i === step ? C.brass : C.umberHair,
                  transition: 'all 280ms ' + window.ATELIER_EASE,
                }} />
              ))}
            </div>
          </div>
        </div>

        {/* Small ceremonial visual — a single knight on a plinth */}
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <PlinthVignette palette={C} />
        </div>
      </div>
    </div>
  );
}

function PlinthVignette({ palette }) {
  const C = palette;
  return (
    <svg width="240" height="320" viewBox="0 0 240 320">
      <defs>
        <linearGradient id="pv-spot" x1="50%" y1="0%" x2="50%" y2="100%">
          <stop offset="0%" stopColor="#fff5d7" stopOpacity="0.95" />
          <stop offset="60%" stopColor={C.brassLight} stopOpacity="0.45" />
          <stop offset="100%" stopColor={C.brass} stopOpacity="0" />
        </linearGradient>
        <radialGradient id="pv-shadow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="rgba(42,34,27,0.4)" />
          <stop offset="100%" stopColor="rgba(42,34,27,0)" />
        </radialGradient>
      </defs>
      <path d="M 78 0 L 162 0 L 200 240 L 40 240 Z" fill="url(#pv-spot)" opacity="0.85" />
      {/* Plinth */}
      <rect x="56" y="220" width="128" height="80" rx="2" fill={C.boneDeep} />
      <rect x="56" y="220" width="128" height="6" fill={C.umberHair} />
      <ellipse cx="120" cy="218" rx="50" ry="6" fill="url(#pv-shadow)" />
      {/* Knight glyph */}
      <text
        x="120" y="218"
        fontFamily={'"Noto Sans Symbols 2","Segoe UI Symbol","Apple Symbols","DejaVu Sans",sans-serif'}
        fontSize="120"
        fill={C.umber}
        textAnchor="middle"
        style={{ filter: `drop-shadow(0 4px 4px rgba(42,34,27,0.25))` }}
      >♞</text>
      <text x="120" y="284"
        fontFamily={window.ATELIER_TYPE.ui}
        fontSize="9" letterSpacing="3"
        fill={C.umberFaint} textAnchor="middle" style={{ textTransform: 'uppercase' }}>
        {window.COPY.onboarding.knightLabel}
      </text>
    </svg>
  );
}

function primaryBtn(C) {
  return {
    appearance: 'none', border: 'none', cursor: 'pointer',
    padding: '14px 24px', borderRadius: 99,
    background: C.umber, color: C.cream,
    fontFamily: window.ATELIER_TYPE.ui, fontSize: 13, fontWeight: 500,
    letterSpacing: 0.3,
    boxShadow: '0 10px 22px -12px rgba(42,34,27,0.6)',
    transition: 'transform 180ms ' + window.ATELIER_EASE,
  };
}
function ghostBtn(C) {
  return {
    appearance: 'none', cursor: 'pointer',
    padding: '13px 18px', borderRadius: 99,
    background: 'transparent', color: C.umberSoft,
    border: `0.6px solid ${C.umberHair}`,
    fontFamily: window.ATELIER_TYPE.ui, fontSize: 13, fontWeight: 500,
  };
}

function withAlpha(hex, a) {
  if (!hex || !hex.startsWith('#')) return hex;
  const [r,g,b] = hex.match(/[0-9a-f]{2}/gi).map((h) => parseInt(h,16));
  return `rgba(${r},${g},${b},${a})`;
}

// === 2. HOME / DASHBOARD =====================================================

// A pool of evocative, atelier-style names. Each lesson is mapped to one
// deterministically via its id — no spoiler about which piece is the hero.
const ATELIER_NAMES = [
  'Quiet thunder', 'Slow weight', 'The fourth rank', 'Aftermath', 'Threshold',
  'Tremor', 'A patient knife', 'The bind', 'Crossroads', 'Slow tide',
  'Distant horn', 'The watchman', 'Half-light', 'Folded silk', 'A held breath',
  'The narrow stair', 'Late November', 'Twin shadows', 'The locked door', 'Soft iron',
  'Vespers', 'The window seat', 'Smoke', 'A clean line', 'The cipher',
  'Glasswork', 'Two ravens', 'The long room', 'Silver thread', 'A second wind',
  'Northern light', 'The pivot', 'Echoes', 'Brass and ash', 'The slow burn',
  'A standing wave', 'The hinge', 'Tin and rose', 'After the rain', 'The cartographer',
  'Dovetail', 'The honest move', 'Vellum', 'The quiet hour', 'Three rivers',
  'The visitor', 'A study in restraint', 'Plumbline', 'The watchtower', 'Saltwater',
  'The fold', 'A patient ear', 'Inkwell', 'The reading room', 'Coalsmoke',
  'A small bell', 'The promenade', 'Marrow', 'The third letter', 'Antlers',
  'The trespass', 'Snow on slate', 'The thin wire', 'Hush', 'The corridor',
  'Foxglove', 'The reckoning', 'A loose thread', 'The chapel', 'Wintering',
  'The almanac', 'A folded map', 'Tallow', 'The orchard', 'Compass rose',
  'The tide returns', 'Lantern', 'The lacquer box', 'Vesper bells', 'The drift',
  'A grave finding', 'The fulcrum', 'Slate', 'The good question', 'Embers',
];

// Hash a lesson id to a stable index. Different ids land on different names.
function hashLessonId(id) {
  if (!id) return 0;
  let h = 0;
  for (let i = 0; i < id.length; i++) {
    h = ((h << 5) - h + id.charCodeAt(i)) | 0;
  }
  return Math.abs(h);
}

// Creative, non-spoiler title for a lesson. Stable across renders.
function creativeTitle(lessonId) {
  if (!lessonId) return 'Position study';
  const h = hashLessonId(lessonId);
  const name = ATELIER_NAMES[h % ATELIER_NAMES.length];
  const num = (h % 199) + 1; // 1..199
  return `${name}, no. ${num}`;
}

// Theme-based, non-spoiler subtitle.
const THEME_BLURBS = {
  'fork':              'Two pieces threatened at once.',
  'pin':               "A piece can't move without paying.",
  'discovered-attack': 'Move one piece, unleash another.',
  'skewer':            'The front yields, the back falls.',
  'knight-endgame':    'A quiet finish, with knights.',
  'outpost':           'A square held deep in enemy ground.',
};
function creativeSubtitle(theme) {
  return THEME_BLURBS[theme] || 'A position worth sitting with.';
}

// Back-compat shims (older callers).
function displayTitle(title) {
  if (!title) return title;
  const idx = title.indexOf(' — ');
  return idx !== -1 ? title.slice(idx + 3) : title;
}
function displaySubtitle(subtitle) {
  if (!subtitle) return subtitle;
  const marker = ' — SHAP score ';
  const idx = subtitle.indexOf(marker);
  if (idx === -1) return subtitle;
  const afterShap = subtitle.slice(idx + marker.length);
  const period = afterShap.indexOf('. ');
  return period !== -1 ? afterShap.slice(period + 2) : subtitle.slice(0, idx);
}

// Maps difficulty strings to Pill tone variants.
function difficultyTone(difficulty) {
  return { beginner: 'celadon', intermediate: 'brass', advanced: 'sienna' }[difficulty] || 'default';
}

const THEME_FILTERS = [
  { value: 'all',               label: 'All' },
  { value: 'fork',              label: 'Fork' },
  { value: 'pin',               label: 'Pin' },
  { value: 'discovered-attack', label: 'Discovered Attack' },
  { value: 'skewer',            label: 'Skewer' },
  { value: 'knight-endgame',    label: 'Knight Endgame' },
  { value: 'outpost',           label: 'Outpost' },
];

const DIFFICULTY_FILTERS = [
  { value: 'all',         label: 'All' },
  { value: 'beginner',    label: 'Beginner' },
  { value: 'intermediate',label: 'Intermediate' },
  { value: 'advanced',    label: 'Advanced' },
];

const PIECE_FILTERS = [
  { value: 'all',    label: 'Any piece' },
  { value: 'pawn',   label: 'Pawn' },
  { value: 'knight', label: 'Knight' },
  { value: 'bishop', label: 'Bishop' },
  { value: 'rook',   label: 'Rook' },
  { value: 'queen',  label: 'Queen' },
  { value: 'king',   label: 'King' },
];

const PHASE_FILTERS = [
  { value: 'all',        label: 'Any phase' },
  { value: 'opening',    label: 'Opening' },
  { value: 'middlegame', label: 'Middlegame' },
  { value: 'endgame',    label: 'Endgame' },
];

const PAGE_SIZE = 48;

function FilterBar({ palette, filters, active, onSelect }) {
  const C = palette;
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
      {filters.map((f) => {
        const isActive = f.value === active;
        return (
          <button key={f.value} onClick={() => onSelect(f.value)}
            style={{
              appearance: 'none', cursor: 'pointer',
              padding: '7px 14px', borderRadius: 99,
              border: `0.6px solid ${isActive ? C.umber : C.umberHair}`,
              background: isActive ? C.cream : 'transparent',
              color: isActive ? C.umber : C.umberSoft,
              fontFamily: window.ATELIER_TYPE.ui,
              fontSize: 10, letterSpacing: 1.5, textTransform: 'uppercase',
              transition: 'all 180ms ' + window.ATELIER_EASE,
              position: 'relative',
            }}>
            {isActive && (
              <span style={{
                position: 'absolute', bottom: -1, left: '50%',
                transform: 'translateX(-50%)',
                width: 16, height: 2, borderRadius: 99,
                background: C.brass,
              }} />
            )}
            {f.label}
          </button>
        );
      })}
    </div>
  );
}

function HomeScreen({ palette, setRoute }) {
  const C = palette;
  const H = window.COPY.home;
  const today = new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' });
  const hour = new Date().getHours();
  const timeOfDay = hour < 12 ? 'morning' : hour < 17 ? 'afternoon' : 'evening';
  const greeting = `A quiet ${timeOfDay}\nin the studio.`;

  const [lessonIndex, setLessonIndex] = useS(window.LESSON_INDEX || null);
  useE(() => {
    const handler = (e) => setLessonIndex(e.detail);
    window.addEventListener('lessonIndexLoaded', handler);
    if (window.LESSON_INDEX) setLessonIndex(window.LESSON_INDEX);
    return () => window.removeEventListener('lessonIndexLoaded', handler);
  }, []);

  const [themeFilter, setThemeFilter] = useS('all');
  const [diffFilter, setDiffFilter] = useS('all');
  const [pieceFilter, setPieceFilter] = useS('all');
  const [phaseFilter, setPhaseFilter] = useS('all');
  const [visibleCount, setVisibleCount] = useS(PAGE_SIZE);

  // Reset pagination when filters change.
  useE(() => { setVisibleCount(PAGE_SIZE); }, [themeFilter, diffFilter, pieceFilter, phaseFilter]);

  const catalogCount = lessonIndex && lessonIndex.lessons ? lessonIndex.lessons.length : null;

  // Progress state for the lower cards.
  const progress = useM(() => (window.getProgress && window.getProgress()) || {}, []);
  const progressKeys = Object.keys(progress);
  const incompleteKeys = progressKeys.filter(k => !progress[k].complete);
  const resumeKey = incompleteKeys.length > 0
    ? incompleteKeys[incompleteKeys.length - 1]
    : progressKeys.length > 0 ? progressKeys[progressKeys.length - 1] : null;
  const resumeLessonMeta = useM(() => {
    if (!resumeKey || !lessonIndex || !lessonIndex.lessons) return null;
    return lessonIndex.lessons.find(l => l.id === resumeKey) || null;
  }, [resumeKey, lessonIndex]);
  const completedCount = progressKeys.filter(k => progress[k].complete).length;

  const filteredLessons = useM(() => {
    if (!lessonIndex || !lessonIndex.lessons) return null;
    return lessonIndex.lessons
      .filter((l) => themeFilter === 'all' || l.theme === themeFilter)
      .filter((l) => diffFilter === 'all' || l.difficulty === diffFilter)
      .filter((l) => pieceFilter === 'all' || l.heroPiece === pieceFilter)
      .filter((l) => phaseFilter === 'all' || l.gamePhase === phaseFilter);
  }, [lessonIndex, themeFilter, diffFilter, pieceFilter, phaseFilter]);

  return (
    <div style={{ flex: 1, height: '100%', overflow: 'auto', background: C.bone }}>
      {/* Full-bleed hero */}
      <section className="atelier-hero-section" style={{
        position: 'relative',
        height: 360,
        background: C.boneDeep,
        overflow: 'hidden',
      }}>
        {/* Decorative hero background */}
        <div style={{
          position: 'absolute', inset: 0,
          background: `linear-gradient(160deg, ${C.boneSoft} 0%, ${C.boneDeep} 55%, ${withAlpha(C.squareLight, 0.8)} 100%)`,
        }} />
        <div style={{
          position: 'absolute', right: 0, top: 0, bottom: 0,
          display: 'flex', alignItems: 'center', paddingRight: 60,
          pointerEvents: 'none', userSelect: 'none',
        }}>
          <span style={{
            fontFamily: '"Noto Sans Symbols 2","Segoe UI Symbol",sans-serif',
            fontSize: 300, color: C.umber, lineHeight: 1, opacity: 0.06,
          }}>♛</span>
        </div>
        {/* Gradient overlay to keep text readable */}
        <div style={{
          position: 'absolute', inset: 0,
          background: `linear-gradient(180deg, ${withAlpha(C.bone, 0.0)} 0%, ${withAlpha(C.bone, 0.0)} 55%, ${withAlpha(C.bone, 0.95)} 100%),
                       linear-gradient(90deg, ${withAlpha(C.bone, 0.65)} 0%, ${withAlpha(C.bone, 0.15)} 45%, transparent 70%)`,
          pointerEvents: 'none',
        }} />
        <div className="atelier-hero-text" style={{
          position: 'absolute', left: 48, top: 56, maxWidth: 520,
        }}>
          <div style={{
            fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 4,
            textTransform: 'uppercase', opacity: 0.7, color: C.umberSoft, marginBottom: 14,
          }}>{today} · {H.heroCopy.kicker}</div>
          <h2 style={{
            margin: 0,
            fontFamily: window.ATELIER_TYPE.display,
            fontWeight: 300, fontStyle: 'italic',
            fontSize: 54, lineHeight: 1.05,
            color: C.umber, letterSpacing: -0.5,
            whiteSpace: 'pre-line',
          }}>
            {greeting}
          </h2>
          <p style={{
            marginTop: 18,
            fontFamily: window.ATELIER_TYPE.display,
            fontSize: 17, lineHeight: 1.5,
            color: C.umberSoft, maxWidth: 460,
          }}>
            {H.heroCopy.subhead}
          </p>
        </div>
      </section>

      {/* Today's exhibits */}
      <section className="atelier-section-pad" style={{ padding: '36px 48px 24px' }}>
        <div style={{ marginBottom: 20 }}>
          <SectionHeading palette={C} kicker={H.todaySection.kicker}
            title={catalogCount !== null ? `${catalogCount} positions` : 'Today\'s positions'} />
        </div>

        {/* Dynamic catalog from lesson index */}
        {lessonIndex && lessonIndex.lessons && lessonIndex.lessons.length > 0 ? (
          <>
            {/* Filter controls */}
            <div style={{ marginBottom: 16, display: 'flex', flexDirection: 'column', gap: 10 }}>
              <FilterBar palette={C} filters={THEME_FILTERS} active={themeFilter} onSelect={setThemeFilter} />
              <FilterBar palette={C} filters={PIECE_FILTERS} active={pieceFilter} onSelect={setPieceFilter} />
              <FilterBar palette={C} filters={PHASE_FILTERS} active={phaseFilter} onSelect={setPhaseFilter} />
              <FilterBar palette={C} filters={DIFFICULTY_FILTERS} active={diffFilter} onSelect={setDiffFilter} />
              <div style={{
                fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 1.5,
                textTransform: 'uppercase', color: C.umberSoft, opacity: 0.65,
              }}>
                Showing {Math.min(visibleCount, filteredLessons ? filteredLessons.length : 0)} of {filteredLessons ? filteredLessons.length : 0}
              </div>
            </div>
            <div className="atelier-exhibit-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
              {(filteredLessons || []).slice(0, visibleCount).map((ls, i) => (
                <ExhibitCard key={ls.id} palette={C}
                  num={String(i + 1).padStart(2, '0')}
                  room={ls.theme}
                  title={creativeTitle(ls.id)}
                  body={creativeSubtitle(ls.theme)}
                  tag={ls.difficulty}
                  tone={difficultyTone(ls.difficulty)}
                  footer={ls.estimatedMinutes ? `About ${ls.estimatedMinutes} minutes` : null}
                  onOpen={() => setRoute('lesson:' + ls.id)} />
              ))}
            </div>
            {filteredLessons && visibleCount < filteredLessons.length && (
              <div style={{ marginTop: 24, display: 'flex', justifyContent: 'center' }}>
                <button
                  onClick={() => setVisibleCount((c) => c + PAGE_SIZE)}
                  style={{
                    appearance: 'none', cursor: 'pointer',
                    padding: '11px 28px', borderRadius: 99,
                    border: `0.6px solid ${C.umberHair}`,
                    background: 'transparent', color: C.umberSoft,
                    fontFamily: window.ATELIER_TYPE.ui, fontSize: 11,
                    letterSpacing: 1.5, textTransform: 'uppercase',
                    transition: 'all 180ms ' + window.ATELIER_EASE,
                  }}
                  onMouseEnter={(e) => { e.currentTarget.style.borderColor = C.umber; e.currentTarget.style.color = C.umber; }}
                  onMouseLeave={(e) => { e.currentTarget.style.borderColor = C.umberHair; e.currentTarget.style.color = C.umberSoft; }}>
                  Load more
                </button>
              </div>
            )}
          </>
        ) : (
          /* Hardcoded fallback when no index is available */
          <div className="atelier-exhibit-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
            {H.exhibits.map((ex) => (
              <ExhibitCard key={ex.num} palette={C}
                num={ex.num}
                room={ex.room}
                title={ex.title}
                body={ex.body}
                tag={ex.tag}
                tone={ex.tone}
                onOpen={() => setRoute(ex.route)} />
            ))}
          </div>
        )}
      </section>

      {/* Two-column lower */}
      <section className="atelier-home-lower atelier-section-pad" style={{
        padding: '12px 48px 56px',
        display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 24,
      }}>
        <Card palette={C} padding={24}>
          <SectionHeading palette={C} kicker={H.resumeSection.kicker}
            title={resumeLessonMeta ? H.resumeSection.resumeTitle : H.resumeSection.noProgressTitle} small />
          <div style={{ marginTop: 16 }}>
            {resumeLessonMeta ? (
              <div style={{ display: 'flex', gap: 18 }}>
                <div style={{
                  width: 100, height: 100, borderRadius: 8, flexShrink: 0,
                  background: `linear-gradient(135deg, ${C.boneDeep} 0%, ${C.squareLight} 100%)`,
                  border: `0.6px solid ${C.umberHair}`,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontFamily: '"Noto Sans Symbols 2","Segoe UI Symbol",sans-serif',
                  fontSize: 64, color: C.umber,
                }}>♞</div>
                <div>
                  <div style={{ fontFamily: window.ATELIER_TYPE.display, fontStyle: 'italic', fontSize: 20, color: C.umber, lineHeight: 1.2 }}>
                    {creativeTitle(resumeLessonMeta.id || resumeKey)}
                  </div>
                  <p style={{ margin: '6px 0 12px', fontFamily: window.ATELIER_TYPE.ui, fontSize: 12, color: C.umberSoft, letterSpacing: 0.3 }}>
                    {resumeLessonMeta.theme} · Step {(progress[resumeKey] ? progress[resumeKey].lastStep + 1 : 1)} of 6
                  </p>
                  <button style={primaryBtn(C)} onClick={() => setRoute('lesson:' + resumeKey)}>
                    {H.resumeSection.resumeButton}
                  </button>
                </div>
              </div>
            ) : (
              <p style={{ margin: '12px 0 0', fontFamily: window.ATELIER_TYPE.display, fontSize: 15, lineHeight: 1.5, color: C.umberSoft }}>
                {H.resumeSection.noProgressNote}
              </p>
            )}
          </div>
        </Card>
        <Card palette={C} padding={24}>
          <SectionHeading palette={C} kicker={H.collectionSection.kicker} title={H.collectionSection.title} small />
          {completedCount > 0 ? (
            <>
              <div style={{
                marginTop: 16,
                display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)', gap: 8,
                fontFamily: '"Noto Sans Symbols 2","Segoe UI Symbol",sans-serif',
              }}>
                {['♞','♝','♜','♛','♚','♟','♘','♗','♖','♕','♙','♔'].map((g, i) => (
                  <div key={i} style={{
                    aspectRatio: '1 / 1',
                    background: i % 2 ? C.squareLight : C.boneDeep,
                    borderRadius: 6,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontSize: 30, color: i < 6 ? C.umber : C.umberSoft,
                    opacity: i < completedCount ? 1 : 0.25,
                  }}>{g}</div>
                ))}
              </div>
              <div style={{
                marginTop: 14, fontFamily: window.ATELIER_TYPE.ui, fontSize: 11, letterSpacing: 2,
                textTransform: 'uppercase', opacity: 0.55, color: C.umberSoft,
              }}>
                {completedCount} of {catalogCount !== null ? catalogCount : '521'} completed
              </div>
            </>
          ) : (
            <p style={{ margin: '16px 0 0', fontFamily: window.ATELIER_TYPE.display, fontSize: 15, lineHeight: 1.5, color: C.umberSoft }}>
              {H.collectionSection.noProgressNote}
            </p>
          )}
        </Card>
      </section>
    </div>
  );
}

function SectionHeading({ palette, kicker, title, small }) {
  const C = palette;
  return (
    <div>
      <div style={{
        fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 3.5,
        textTransform: 'uppercase', opacity: 0.55, color: C.umberSoft, marginBottom: 6,
      }}>{kicker}</div>
      <h3 style={{
        margin: 0,
        fontFamily: window.ATELIER_TYPE.display,
        fontWeight: 300, fontStyle: 'italic',
        fontSize: small ? 22 : 30, lineHeight: 1, color: C.umber,
      }}>{title}</h3>
    </div>
  );
}

function ExhibitCard({ palette, num, room, title, body, tag, tone, footer, onOpen }) {
  const C = palette;
  return (
    <button onClick={onOpen} style={{
      appearance: 'none', textAlign: 'left', cursor: 'pointer',
      border: `0.6px solid ${C.umberHair}`,
      background: C.cream,
      borderRadius: 14,
      padding: 22,
      display: 'flex', flexDirection: 'column', gap: 14,
      minHeight: 200,
      transition: 'transform 220ms ' + window.ATELIER_EASE + ', box-shadow 220ms',
      boxShadow: '0 14px 28px -22px rgba(42,34,27,0.35)',
    }}
    onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 24px 36px -22px rgba(42,34,27,0.45)'; }}
    onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 14px 28px -22px rgba(42,34,27,0.35)'; }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{
          fontFamily: window.ATELIER_TYPE.ui, fontSize: 9, letterSpacing: 3,
          textTransform: 'uppercase', opacity: 0.55, color: C.umberSoft,
        }}>Room {num} · {room}</div>
        <Pill palette={C} tone={tone}>{tag}</Pill>
      </div>
      <div style={{
        fontFamily: window.ATELIER_TYPE.display, fontStyle: 'italic', fontWeight: 300,
        fontSize: 24, lineHeight: 1.15, color: C.umber,
      }}>{title}</div>
      <p style={{
        margin: 0,
        fontFamily: window.ATELIER_TYPE.display, fontSize: 14, lineHeight: 1.55, color: C.umberSoft,
      }}>{body}</p>
      <div style={{
        marginTop: 'auto', fontFamily: window.ATELIER_TYPE.ui, fontSize: 11,
        color: C.umber, letterSpacing: 0.5,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <span>{window.COPY.home.enterRoom}</span>
        {footer && (
          <span style={{ opacity: 0.5, fontFamily: window.ATELIER_TYPE.ui, fontSize: 10, letterSpacing: 1 }}>
            {footer}
          </span>
        )}
      </div>
    </button>
  );
}

Object.assign(window, {
  OnboardingScreen, HomeScreen,
  Pill, Card, LayerToggle, SectionHeading, primaryBtn, ghostBtn, withAlpha,
  creativeTitle, creativeSubtitle,
});
