// Kairós — vistas del prototipo: Monumentos, Tablero, Cronómetro, Cartas
// (Sin destructurar hooks de React aquí: cada .jsx se inyecta como <script>
//  clásico y comparten el ámbito global, así que declarar `useState`/`useEffect`
//  de nuevo chocaría con kairos-app.jsx. Estas vistas no usan hooks.)

const K = {
  ent: '#1d4f91',
  dec: '#76953a',
  vor: '#e8930c',
  exp: '#5b7e9e',
  res: '#a9c6cd',
  nuc: '#c8175d',
  yellow: '#f3d100',
  ink: '#243038',
};

const NODE_TYPES = [
  { id: 'VOR', name: 'VÓRTICE',  color: K.vor },
  { id: 'DEC', name: 'DECIDE',   color: K.dec },
  { id: 'EXP', name: 'EXPLORA',  color: K.exp },
  { id: 'RES', name: 'RESPIRO',  color: K.res, darkText: true },
  { id: 'NUC', name: 'NÚCLEO',   color: K.nuc, label: 'NÚCLEO' },
];

const MONUMENTS = [
  { id: 'coliseo',    name: 'El Coliseo',   place: 'Roma',       accent: K.nuc },
  { id: 'stonehenge', name: 'Stonehenge',   place: 'Inglaterra', accent: K.dec },
  { id: 'chichen',    name: 'Chichén Itzá', place: 'México',     accent: K.vor },
  { id: 'tajmahal',   name: 'Taj Mahal',    place: 'India',      accent: K.ent },
];

const LOREM_1 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Donec ullamcorper nulla non metus auctor fringilla, sed posuere consectetur est at lobortis.';
const LOREM_2 = 'Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.';

function fmtTime(s) {
  const m = Math.floor(Math.max(0, s) / 60);
  const ss = Math.max(0, s) % 60;
  return String(m).padStart(2, '0') + ':' + String(ss).padStart(2, '0');
}

/* ---------- Vista 1 · Monumentos ---------- */

const ROMAN = ['I', 'II', 'III', 'IV'];
const CARD_ROT = ['-2.4deg', '1.6deg', '-1.2deg', '2.3deg'];
const CARD_DY = ['8px', '24px', '0px', '18px'];

function Silhouette({ id }) {
  if (id === 'coliseo') {
    return (
      <div className="silo silo-coliseo">
        <div className="col-body">
          <div className="col-row upper">
            <span></span><span></span><span></span><span></span><span></span>
          </div>
          <div className="col-row">
            <span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>
          </div>
        </div>
      </div>
    );
  }
  if (id === 'stonehenge') {
    return (
      <div className="silo silo-stonehenge">
        <div className="sh-tri a"><span className="sh-lintel"></span><span className="sh-legs"><i></i><i></i></span></div>
        <div className="sh-tri b"><span className="sh-lintel"></span><span className="sh-legs"><i></i><i></i></span></div>
        <div className="sh-tri c"><span className="sh-lintel"></span><span className="sh-legs"><i></i><i></i></span></div>
        <span className="sh-fallen"></span>
      </div>
    );
  }
  if (id === 'chichen') {
    return (
      <div className="silo silo-chichen">
        <span className="ch-step s1"></span>
        <span className="ch-step s2"></span>
        <span className="ch-step s3"></span>
        <span className="ch-step s4"></span>
        <span className="ch-temple"></span>
        <span className="ch-roof"></span>
        <span className="ch-stair"></span>
      </div>
    );
  }
  return (
    <div className="silo silo-taj">
      <span className="tj-min l"></span>
      <span className="tj-min r"></span>
      <span className="tj-base"></span>
      <span className="tj-body"></span>
      <span className="tj-dome"></span>
      <span className="tj-finial"></span>
      <span className="tj-arch"></span>
    </div>
  );
}

function MonumentsView({ onPick }) {
  return (
    <div className="screen" data-screen-label="Monumentos">
      <header className="brand-header">
        <div className="brand-mark">KAIRÓS</div>
        <div className="brand-tag">Decide. Lidera. Deja huella.</div>
      </header>
      <p className="screen-hint">Elige tu monumento para comenzar la partida</p>
      <div className="monument-row">
        {MONUMENTS.map((m, i) => (
          <button
            key={m.id}
            className="tarot-card"
            style={{ '--accent': m.accent, '--rot': CARD_ROT[i], '--dy': CARD_DY[i] }}
            onClick={() => onPick(m)}
          >
            <span className="tarot-numeral">· {ROMAN[i]} ·</span>
            <div className="tarot-scene">
              <Silhouette id={m.id} />
              <span className="tarot-ground"></span>
            </div>
            <div className="tarot-name">{m.name}</div>
            <div className="tarot-place">{m.place}</div>
          </button>
        ))}
      </div>
      <footer className="proto-footer">© 3 WEEKS + MARINVA · prototipo</footer>
    </div>
  );
}

/* ---------- Vista 2 · Tablero / dashboard ---------- */

const STAT_DEFS = [
  { id: 'MAT', label: 'Materia',        max: 10 },
  { id: 'ENE', label: 'Energía',        max: 10 },
  { id: 'SIS', label: 'Sistema',        max: 10 },
  { id: 'TC',  label: 'Tiempo cósmico', max: 30 },
];

// posiciones (%) de las casillas dentro del panel, con sus conexiones.
// El descenso va de la superficie (EXP/VOR arriba) al NÚCLEO, que es SIEMPRE lo
// más profundo (mayor y): nada queda por debajo de él.
const NODE_POS = {
  EXP: { x: 20, y: 22 },
  VOR: { x: 72, y: 18 },
  DEC: { x: 46, y: 44 },
  RES: { x: 26, y: 64 },
  NUC: { x: 58, y: 84 },
};
const NODE_LINKS = [['EXP', 'DEC'], ['DEC', 'VOR'], ['DEC', 'RES'], ['DEC', 'NUC'], ['VOR', 'NUC'], ['RES', 'NUC']];

function StatSquare({ def, value, onAdjust }) {
  const pct = Math.round((value / def.max) * 100);
  return (
    <div className="stat-square">
      <div className="stat-head">
        <div className="stat-id">{def.label}</div>
        {onAdjust && (
          <div className="stat-steppers">
            <button type="button" className="stat-step" onClick={() => onAdjust(def.id, -1)}
              disabled={value <= 0} aria-label={'Restar ' + def.label}>−</button>
            <button type="button" className="stat-step" onClick={() => onAdjust(def.id, 1)}
              disabled={value >= def.max} aria-label={'Sumar ' + def.label}>+</button>
          </div>
        )}
      </div>
      <div className="stat-value">{value}<span className="stat-max">/{def.max}</span></div>
      <div className="stat-track"><div className="stat-fill" style={{ width: pct + '%' }}></div></div>
    </div>
  );
}

function BoardView({ monument, stats, sprint, onSprint, timeLeft, timerRunning, onOpenTimer, onPickNode, onAdjustStat, onBack, showLinks }) {
  return (
    <div className="screen board-screen" data-screen-label="Tablero">
      <div className="board-topbar">
        <button className="ghost-btn" onClick={onBack}>← Monumentos</button>
        <button className={'time-pill' + (timerRunning ? ' running' : '')} onClick={onOpenTimer} title="Abrir cronómetro">
          <span className="time-pill-label">Tiempo</span>
          <span className="time-pill-value">{fmtTime(timeLeft)}</span>
        </button>
        <div className="board-monument">{monument ? monument.name : '—'}</div>
      </div>

      <div className="stat-row">
        {STAT_DEFS.map((d) => <StatSquare key={d.id} def={d} value={stats[d.id]} onAdjust={onAdjustStat} />)}
      </div>

      <div className="board-main">
        <div className="node-panel">
          <div className="zone-bands" aria-hidden="true">
            <div className="zone z1"><span>superficie</span></div>
            <div className="zone z2"><span>umbral</span></div>
            <div className="zone z3"><span>profunda</span></div>
          </div>
          {showLinks && (
            <svg className="node-links" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
              {NODE_LINKS.map(([a, b], i) => (
                <line key={i} x1={NODE_POS[a].x} y1={NODE_POS[a].y} x2={NODE_POS[b].x} y2={NODE_POS[b].y}></line>
              ))}
            </svg>
          )}
          {NODE_TYPES.map((n) => (
            <button
              key={n.id}
              className={'node-circle' + (n.darkText ? ' dark-text' : '')}
              style={{ left: NODE_POS[n.id].x + '%', top: NODE_POS[n.id].y + '%', background: n.color }}
              onClick={() => onPickNode(n)}
            >
              {n.label || n.id}
            </button>
          ))}
          <div className="sprint-box">
            <div className="sprint-label">Sprint</div>
            <div className="sprint-controls">
              <button className="sprint-btn" onClick={() => onSprint(-1)} aria-label="Sprint anterior">−</button>
              <div className="sprint-num">{sprint}</div>
              <button className="sprint-btn" onClick={() => onSprint(1)} aria-label="Sprint siguiente">+</button>
            </div>
          </div>
          <aside className="legend">
            <div className="legend-title">Leyenda</div>
            {NODE_TYPES.map((n) => (
              <div key={n.id} className="legend-row">
                <span className="legend-dot" style={{ background: n.color }}></span>
                <span>{n.name}</span>
              </div>
            ))}
          </aside>
        </div>
      </div>
      <footer className="proto-footer">Pincha una casilla para elegir carta · pincha el tiempo para el cronómetro · usa +/− para ajustar tus marcadores a mano</footer>
    </div>
  );
}

/* ---------- Cronómetro grande ---------- */

function TimerOverlay({ open, seconds, duration, running, onToggle, onReset, onSetMinutes, onClose }) {
  if (!open) return null;
  const presets = [5, 10, 15, 20];
  const r = 130;
  const circ = 2 * Math.PI * r;
  const frac = duration > 0 ? seconds / duration : 0;
  return (
    <div className="timer-overlay" data-screen-label="Cronómetro" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="timer-card">
        <button className="ghost-btn timer-close" onClick={onClose}>✕ Cerrar</button>
        <div className="timer-ring-wrap">
          <svg viewBox="0 0 300 300" className="timer-ring">
            <circle cx="150" cy="150" r={r} className="ring-bg"></circle>
            <circle
              cx="150" cy="150" r={r} className="ring-fg"
              strokeDasharray={circ}
              strokeDashoffset={circ * (1 - frac)}
            ></circle>
          </svg>
          <div className="timer-readout">{fmtTime(seconds)}</div>
        </div>
        <div className="timer-presets">
          {presets.map((p) => (
            <button
              key={p}
              className={'preset-btn' + (duration === p * 60 ? ' active' : '')}
              onClick={() => onSetMinutes(p)}
            >{p}′</button>
          ))}
          <button className="preset-btn" onClick={() => onSetMinutes(Math.min(60, Math.round(duration / 60) + 1))}>+1′</button>
          <button className="preset-btn" onClick={() => onSetMinutes(Math.max(1, Math.round(duration / 60) - 1))}>−1′</button>
        </div>
        <div className="timer-actions">
          <button className="primary-btn" onClick={onToggle}>{running ? 'Pausar' : 'Iniciar'}</button>
          <button className="ghost-btn" onClick={onReset}>Reiniciar</button>
        </div>
      </div>
    </div>
  );
}

/* ---------- Vista 3 · Cartas ---------- */
// Mazos reales servidos por la BBDD (api/cards.php). El fetch y el barajado
// viven en kairos-app.jsx; aquí solo se PINTA (sin hooks, ámbito global).
// DEC = DECIDE (por monumento y sprint), VOR = VÓRTICE, EXP = EXPLORA
// (estos dos compartidos por sprint). RESPIRO y NÚCLEO aún no tienen mazo.

const DECK_NODES = ['DEC', 'VOR', 'EXP'];

function fmtDelta(v) {
  if (v === null || v === undefined) return '·';
  return (v > 0 ? '+' : '') + v;
}
function deltaCls(v) {
  if (v === null || v === undefined || v === 0) return 'zero';
  return v > 0 ? 'pos' : 'neg';
}

// chips Mat/Ene/Sis/TC + Score de una opción DECIDE (se revelan al elegir)
function OptStats({ o }) {
  const items = [['MAT', o.mat], ['ENE', o.ene], ['SIS', o.sis], ['TC', o.tc]];
  return (
    <div className="opt-stats">
      {items.map(([k, v]) => (
        <span key={k} className={'opt-chip ' + deltaCls(v)}>
          <b>{k}</b><span>{fmtDelta(v)}</span>
        </span>
      ))}
      {(o.score !== null && o.score !== undefined) && (
        <span className={'opt-score ' + deltaCls(o.score)}>Score {fmtDelta(o.score)}</span>
      )}
    </div>
  );
}

// Opción DECIDE: botón clicable mientras no se ha decidido; al elegir, revela
// los puntos que suma/resta (no aparecen antes).
function OptionButton({ letter, o, resolved, onChoose }) {
  const decided = !!resolved;
  const chosen = decided && resolved.choice === letter;
  const cls = 'opt-block' + (decided ? (chosen ? ' chosen' : ' passed') : ' opt-clickable');
  const inner = (
    <React.Fragment>
      <div className="opt-head">
        <span className="opt-letter">{letter}</span>
        <span className="opt-text">{o.text}</span>
        {chosen && <span className="opt-chosen-badge">✓ elegida</span>}
      </div>
      {o.tipo && <span className="opt-tag">{o.tipo}</span>}
      {decided
        ? <OptStats o={o} />
        : <span className="opt-hint">Pincha para elegir esta opción</span>}
    </React.Fragment>
  );
  if (decided) return <div className={cls}>{inner}</div>;
  return <button type="button" className={cls} onClick={() => onChoose(letter)}>{inner}</button>;
}

// banner de "qué se aplicó a los trackers" (Vórtice/Explora aceptadas)
function AppliedBanner({ resolved }) {
  if (!resolved) return null;
  const applied = resolved.applied || {};
  const items = ['MAT', 'ENE', 'SIS', 'TC'].filter((k) => applied[k]).map((k) => k + ' ' + fmtDelta(applied[k]));
  return (
    <div className="applied-banner">
      <span className="applied-check">✓</span>
      {items.length
        ? <span>Aplicado a tus trackers: <b>{items.join(' · ')}</b>{resolved.note ? <span className="applied-note"> · {resolved.note}</span> : null}</span>
        : <span>{resolved.note || 'Carta aceptada'}</span>}
    </div>
  );
}

function DecideBody({ card, monument, sprint, resolved, onChoose }) {
  return (
    <div className="deck-card-inner deck-body">
      <div className="card-meta">
        {card.competencia && <span className="meta-pill">{card.competencia}</span>}
        {card.bloque && <span className="meta-dim">{card.bloque}</span>}
        <span className="card-id">{card.id}</span>
      </div>
      <p className="deck-card-body pre situacion">{card.situacion}</p>
      <div className="deck-card-divider"></div>
      <OptionButton letter="A" o={card.a} resolved={resolved} onChoose={onChoose} />
      <OptionButton letter="B" o={card.b} resolved={resolved} onChoose={onChoose} />
      {!resolved && <p className="decide-hint">Elige A o B para ver lo que suma o resta</p>}
      <DeckFoot monument={monument} sprint={sprint} label="DECIDE" />
    </div>
  );
}

function VortexBody({ card, sprint, resolved }) {
  const sinc = (card.tipo || '').toUpperCase().indexOf('SINCRON') === 0;
  return (
    <div className="deck-card-inner deck-body">
      <div className="card-meta">
        <span className={'tipo-pill ' + (sinc ? 'sinc' : 'entr')}>{card.tipo}</span>
        <span className="card-id">{card.id}</span>
      </div>
      <h2 className="deck-card-title">{card.titulo}</h2>
      {card.subtitulo && <p className="deck-sub">{card.subtitulo}</p>}
      {card.efectoFrase && <p className="deck-card-body pre">{card.efectoFrase}</p>}
      {card.efectoCompleto && (
        <div className="efecto-box">
          {card.mov && <span className="mov-flag">🚶 acción</span>}
          <span className="pre">{card.efectoCompleto}</span>
        </div>
      )}
      <AppliedBanner resolved={resolved} />
      <DeckFoot sprint={sprint} label="VÓRTICE" />
    </div>
  );
}

function ExploraBody({ card, sprint, resolved }) {
  const hasAccion = card.accion && card.accion.trim() !== '' && card.accion.trim() !== '—';
  return (
    <div className="deck-card-inner deck-body">
      <div className="card-meta">
        <span className="meta-pill">{card.categoria}</span>
        <span className="card-id">{card.id}</span>
      </div>
      <h2 className="deck-card-title">{card.nombre}</h2>
      {card.profecia && <p className="deck-card-body pre">{card.profecia}</p>}
      {hasAccion && <div className="efecto-box accion"><span className="pre">{card.accion}</span></div>}
      {card.fraseFinal && <p className="deck-sub closing pre">{card.fraseFinal}</p>}
      <AppliedBanner resolved={resolved} />
      <DeckFoot sprint={sprint} label="EXPLORA" />
    </div>
  );
}

function DeckFoot({ monument, sprint, label }) {
  return (
    <div className="deck-card-foot">
      <span>KAIRÓS</span>
      <span className="dot">·</span>
      {monument && <React.Fragment><span>{monument.name}</span><span className="dot">·</span></React.Fragment>}
      <span>MAZO {label}</span>
      {sprint ? <React.Fragment><span className="dot">·</span><span>Sprint {sprint}</span></React.Fragment> : null}
    </div>
  );
}

function CardBody({ node, monument, sprint, card, loading, error, exhausted, resolved, onChoose }) {
  // RESPIRO: propuesta a la Voz del Continuum (negociación con el facilitador)
  if (node.id === 'RES') {
    const opts = ['Tiempo cósmico', 'Energía', 'Materia', 'Sistema'];
    return (
      <div className="deck-card-inner deck-special respiro">
        <span className="special-glyph" aria-hidden="true">⟳</span>
        <p className="special-kicker">RESPIRO</p>
        <p className="special-lead">Proponed a la Voz del Continuum qué indicador os gustaría mejorar</p>
        <div className="propose-grid">
          {opts.map((o) => (
            <span key={o} className="propose-chip"><b>+</b> {o}<span className="q">?</span></span>
          ))}
        </div>
        <p className="special-note">La Voz del Continuum decidirá si acepta vuestra propuesta.</p>
      </div>
    );
  }
  // NÚCLEO: cierre de la partida
  if (node.id === 'NUC') {
    return (
      <div className="deck-card-inner deck-special nucleo">
        <span className="special-glyph" aria-hidden="true">◉</span>
        <p className="special-kicker">NÚCLEO</p>
        <p className="special-body">Habéis conseguido llegar al Núcleo. Preguntad a la Voz del Continuum el coste de su reparación y emprended la vuelta a la superficie.</p>
      </div>
    );
  }
  if (!DECK_NODES.includes(node.id)) {
    return (
      <div className="deck-card-inner deck-empty">
        <div className="empty-glyph" aria-hidden="true"></div>
        <p className="empty-title">{node.name}</p>
        <p className="empty-note">Este mazo aún no tiene cartas.</p>
      </div>
    );
  }
  if (loading) {
    return <div className="deck-card-inner deck-msg"><p>Eligiendo carta…</p></div>;
  }
  if (error) {
    return <div className="deck-card-inner deck-msg error"><p>No se pudieron cargar las cartas.</p><p className="empty-note">{error}</p></div>;
  }
  if (exhausted) {
    return (
      <div className="deck-card-inner deck-msg">
        <p>Habéis usado todas las cartas de {node.name} en este sprint.</p>
        <p className="empty-note">Cambiad de sprint en el tablero para tener cartas nuevas.</p>
      </div>
    );
  }
  if (!card) {
    return <div className="deck-card-inner deck-msg"><p className="empty-note">No hay cartas para este sprint.</p></div>;
  }
  if (node.id === 'DEC') return <DecideBody card={card} monument={monument} sprint={sprint} resolved={resolved} onChoose={onChoose} />;
  if (node.id === 'VOR') return <VortexBody card={card} sprint={sprint} resolved={resolved} />;
  return <ExploraBody card={card} sprint={sprint} resolved={resolved} />;
}

function CardActions({ node, resolved, loading, deckSize, onAccept, onContinue }) {
  const isDec = node.id === 'DEC';
  const busy = loading || !deckSize;
  // Una vez resuelta la carta (DECIDE elegida A/B · VÓRTICE/EXPLORA aceptada), el
  // efecto ya se aplicó a los trackers: solo se ofrece «Continuar». No hay «elegir
  // otra» — la carta que sale es la que hay que aceptar (no se re-baraja).
  if (resolved) {
    return (
      <div className="cards-actions">
        <button className="primary-btn" onClick={onContinue}>Continuar al tablero →</button>
      </div>
    );
  }
  // DECIDE sin resolver: no hay botón; se resuelve pinchando la opción A o B.
  if (isDec) return null;
  // VÓRTICE/EXPLORA sin resolver: única acción, aceptar la carta que ha salido.
  return (
    <div className="cards-actions">
      <button className="primary-btn" onClick={onAccept} disabled={busy}>Aceptar carta</button>
    </div>
  );
}

function CardsView({ node, monument, sprint, card, loading, error, deckSize, exhausted, resolved, onChoose, onAccept, onContinue, onBack }) {
  const n = node || NODE_TYPES[1];
  const hasDeck = DECK_NODES.includes(n.id);
  return (
    <div className="screen cards-screen" data-screen-label="Cartas">
      <div className="cards-topbar">
        <button className="ghost-btn light" onClick={onBack}>← Volver al tablero</button>
        <div className="cards-context">
          Casilla&nbsp;·&nbsp;<strong>{n.name}</strong>
          {hasDeck && <React.Fragment>&nbsp;·&nbsp;Sprint {sprint}</React.Fragment>}
        </div>
      </div>
      <div className="deck-stack" style={{ '--accent': n.color }}>
        <div className="deck-under u3"></div>
        <div className="deck-under u2"></div>
        <div className="deck-under u1"></div>
        <div className="deck-card">
          <div className="deck-card-head">
            <span className="deck-card-badge">{n.label || n.id}</span>
            <span className="deck-card-type">{n.name}</span>
            <span className="deck-card-glyph" aria-hidden="true"></span>
          </div>
          <CardBody
            node={n} monument={monument} sprint={sprint}
            card={card} loading={loading} error={error} exhausted={exhausted}
            resolved={resolved} onChoose={onChoose} />
        </div>
      </div>
      {hasDeck && !error && (card || resolved) && (
        <CardActions node={n} resolved={resolved} loading={loading} deckSize={deckSize} onAccept={onAccept} onContinue={onContinue} />
      )}
      <footer className="proto-footer light">
        {!hasDeck
          ? (n.id === 'RES'
            ? 'Negociad vuestra propuesta con la Voz del Continuum'
            : n.id === 'NUC'
              ? 'Pactad el coste con la Voz del Continuum y volved a la superficie'
              : 'Las cartas de esta casilla se definirán más adelante')
          : n.id === 'DEC'
            ? (resolved
              ? 'Lee lo que suma o resta y pulsa «Continuar» para volver al tablero'
              : 'Pincha la opción que elegirías para ver lo que suma o resta')
            : (resolved
              ? 'Efecto aplicado · pulsa «Continuar» para volver al tablero'
              : 'Acepta la carta para aplicar su efecto a tus trackers')}
      </footer>
    </div>
  );
}

/* ---------- Vista 0 · Sala (lobby): crear o entrar ---------- */
// Presentacional (sin hooks). El estado del código y la sincronización viven en
// kairos-app.jsx; aquí solo se pinta. Modelo «espejo total»: todas las sesiones
// que entren con el mismo código comparten y cambian el mismo estado en vivo.

function LobbyView({ onCreate, codeInput, onCodeInput, onJoin, busy, error }) {
  return (
    <div className="screen lobby-screen" data-screen-label="Sala">
      <header className="brand-header">
        <div className="brand-mark">KAIRÓS</div>
        <div className="brand-tag">Decide. Lidera. Deja huella.</div>
      </header>
      <p className="screen-hint">Crea una sala o entra con un código para jugar en grupo, en directo</p>
      <div className="lobby-grid">
        <section className="lobby-card create">
          <div className="lobby-card-icon" aria-hidden="true">✦</div>
          <h2 className="lobby-card-title">Crear sala</h2>
          <p className="lobby-card-desc">Genera un código nuevo y compártelo. Cada pantalla que entre verá y cambiará lo mismo, al instante.</p>
          <button className="primary-btn lobby-btn" onClick={onCreate} disabled={busy}>
            {busy ? 'Creando…' : 'Crear sala nueva'}
          </button>
        </section>
        <section className="lobby-card join">
          <div className="lobby-card-icon" aria-hidden="true">⮕</div>
          <h2 className="lobby-card-title">Entrar a una sala</h2>
          <p className="lobby-card-desc">Escribe el código que te han pasado para unirte a una partida ya creada.</p>
          <form className="lobby-join" onSubmit={(e) => { e.preventDefault(); onJoin(); }}>
            <input
              className="lobby-input"
              type="text"
              inputMode="text"
              autoCapitalize="characters"
              autoComplete="off"
              spellCheck="false"
              maxLength={8}
              placeholder="CÓDIGO"
              aria-label="Código de sala"
              value={codeInput}
              onChange={(e) => onCodeInput(e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, ''))} />
            <button type="submit" className="ghost-btn lobby-btn" disabled={busy}>
              {busy ? 'Entrando…' : 'Entrar'}
            </button>
          </form>
        </section>
      </div>
      {error ? <p className="lobby-error" role="alert">{error}</p> : null}
      <footer className="proto-footer">© 3 WEEKS + MARINVA · prototipo · salas en vivo</footer>
    </div>
  );
}

/* ---------- Barra de sala (siempre visible dentro de la partida) ---------- */

function RoomBar({ code, online, onLeave }) {
  return (
    <div className="room-bar">
      <div className="room-bar-info">
        <span className="room-bar-label">Sala</span>
        <span className="room-bar-code">{code}</span>
        <span className={'room-bar-live ' + (online ? 'on' : 'off')}>
          <span className="room-bar-dot" aria-hidden="true"></span>
          {online ? 'en vivo' : 'sin conexión'}
        </span>
      </div>
      <button className="ghost-btn room-bar-leave" onClick={onLeave}>Salir de la sala</button>
    </div>
  );
}

Object.assign(window, { K, NODE_TYPES, MONUMENTS, fmtTime, LobbyView, RoomBar, MonumentsView, BoardView, TimerOverlay, CardsView });
