// Pre-login marketing page. Routes:
//   "/"      (logged out)  → LandingScreen
//   "/login" (logged out)  → LoginScreen
//
// Hero is a single full-bleed cinematic loop with these acts:
//   1. Claude.ai chat UI — long real-world brief typed out
//   2. Absorption — pulsing orb absorbs the workspace knowledge
//   3. Workspace · phases kanban — 6 phases land Pendiente; each self-describes
//   4. Workspace · tasks list — 12 tasks materialise with short descriptions
//   5. Workspace · kanban view — brief look at the same tasks distributed
//   6. Claude.ai again — second prompt asking Claude to delegate to Claude Code
//   7. Workspace split — terminal LEFT, kanban RIGHT; tasks flow progress→review
//   8. Workspace full — terminal closes
//   9. Right-sidebar drawer — for each completed task: highlight, slide in,
//      auto-scroll, comment typewriter, slide out
//  10. Tasks closed, fade & restart
//
// Speed knob: every typewriter ticks at `_MS_PER_CHAR` (40ms by default).

const WISTIA_VIDEOS = {
  all:        '7j0riygyvq', // ← media ID del video "Workspace para todos"
  developers: 'zqc53iwnla', // ← media ID del video "Workspace para developers"
};

// ── Speed knobs (ms) ────────────────────────────────────────────────────────
const _MS_PER_CHAR = 40; // single source of truth for every typewriter
const _FADE_MS     = 350;

const _C = {
  bg0: '#0F1115', bg1: '#161922', bg2: '#1C2030', bg3: '#232839',
  border: '#2A2F3D', borderStrong: '#353B4D',
  t0: '#E6E8EE', t1: '#A8AEBE', t2: '#6B7185', t3: '#4A5066',
  accent: '#4F8EFF', claude: '#F97316',
  ok: '#10B981', warn: '#F59E0B', danger: '#EF4444',
};

// ────────────────────────────────────────────────────────────────────────────
// State, reducer, script
// ────────────────────────────────────────────────────────────────────────────

const _initialState = {
  phase: 'prompt',
  // focused:true on first paint so the input shows the orange ring before
  // the typewriter even fires — the demo feels instant on mount.
  prompt: { focused: true, text: '', target: '', sent: false },
  absorbStatus: '',
  ws: {
    layout: 'normal',
    view: 'phases-board',
    project: null,
    phases: [],
    activePhase: null,
    tasks: [],
    toast: null,
    terminal: { open: false, lines: [] },
    claudeCode: false,
    docs: [],
    highlightTaskId: null,
    rdrawer: null, // { id, title, status, assignee, desc, commentTarget, commentTyped, scrolled, typingStarted, closing }
  },
};

function _reducer(state, action) {
  switch (action.type) {
    case 'RESET': return _initialState;
    case 'SET_PHASE': return { ...state, phase: action.phase };

    // PROMPT (used twice)
    case 'PROMPT_RESET':  return { ...state, prompt: { focused: true, text: '', target: '', sent: false } };
    case 'PROMPT_FOCUS':  return { ...state, prompt: { ...state.prompt, focused: true } };
    case 'PROMPT_TARGET': return { ...state, prompt: { ...state.prompt, target: action.text, text: '', sent: false } };
    case 'PROMPT_TICK': {
      const p = state.prompt;
      if (!p.target || p.text.length >= p.target.length) return state;
      return { ...state, prompt: { ...p, text: p.target.slice(0, p.text.length + 1) } };
    }
    case 'PROMPT_SEND': return { ...state, prompt: { ...state.prompt, sent: true } };

    // ABSORB
    case 'STATUS': return { ...state, absorbStatus: action.text };

    // WORKSPACE
    case 'WS_PROJECT':       return { ...state, ws: { ...state.ws, project: action.payload } };
    case 'WS_VIEW':          return { ...state, ws: { ...state.ws, view: action.view } };
    case 'WS_LAYOUT':        return { ...state, ws: { ...state.ws, layout: action.layout } };
    case 'WS_TOAST':         return { ...state, ws: { ...state.ws, toast: { id: Math.random(), text: action.text } } };
    case 'WS_CLEAR_TOAST':   return { ...state, ws: { ...state.ws, toast: null } };
    case 'WS_PHASE':         return { ...state, ws: { ...state.ws, phases: [...state.ws.phases, action.payload] } };
    case 'WS_ACTIVATE_PHASE': return { ...state, ws: { ...state.ws, activePhase: { id: action.id, text: action.text, typed: '' } } };
    case 'WS_PHASE_DESC_TICK': {
      const ap = state.ws.activePhase;
      if (!ap) return state;
      if (ap.typed.length >= ap.text.length) return state;
      return { ...state, ws: { ...state.ws, activePhase: { ...ap, typed: ap.text.slice(0, ap.typed.length + 1) } } };
    }
    case 'WS_DEACTIVATE_PHASE': return { ...state, ws: { ...state.ws, activePhase: null } };
    case 'WS_TASK': return { ...state, ws: { ...state.ws, tasks: [...state.ws.tasks, action.payload] } };
    case 'WS_MOVE': {
      const { id, to } = action.payload;
      return {
        ...state,
        ws: {
          ...state.ws,
          tasks: state.ws.tasks.map(t => t.id === id ? { ...t, status: to } : t),
          highlightTaskId: id,
        },
      };
    }
    case 'WS_SET_HIGHLIGHT':   return { ...state, ws: { ...state.ws, highlightTaskId: action.id } };
    case 'WS_CLEAR_HIGHLIGHT': return { ...state, ws: { ...state.ws, highlightTaskId: null } };

    case 'WS_CC_ACTIVE':  return { ...state, ws: { ...state.ws, claudeCode: true, terminal: { open: true, lines: [] } } };
    case 'WS_CC_OFF':     return { ...state, ws: { ...state.ws, claudeCode: false } };
    case 'WS_TERM_LINE':  return { ...state, ws: { ...state.ws, terminal: { ...state.ws.terminal, lines: [...state.ws.terminal.lines, action.line] } } };
    case 'WS_TERM_CLEAR': return { ...state, ws: { ...state.ws, terminal: { ...state.ws.terminal, lines: [] } } };
    case 'WS_TERM_CLOSE': return { ...state, ws: { ...state.ws, terminal: { open: false, lines: [] } } };
    case 'WS_DOC':        return { ...state, ws: { ...state.ws, docs: [...state.ws.docs, action.path] } };

    // RIGHT-SIDEBAR DRAWER (after Claude Code phase)
    case 'WS_RDRAWER_OPEN': return { ...state, ws: { ...state.ws, rdrawer: {
      id: action.id, title: action.title, status: action.status, assignee: action.assignee,
      desc: action.desc, commentTarget: action.commentTarget,
      commentTyped: '', scrolled: false, typingStarted: false, closing: false,
    } } };
    case 'WS_RDRAWER_SCROLL': {
      const r = state.ws.rdrawer;
      if (!r) return state;
      return { ...state, ws: { ...state.ws, rdrawer: { ...r, scrolled: true } } };
    }
    case 'WS_RDRAWER_TYPE_START': {
      const r = state.ws.rdrawer;
      if (!r) return state;
      return { ...state, ws: { ...state.ws, rdrawer: { ...r, typingStarted: true } } };
    }
    case 'WS_RDRAWER_COMMENT_TICK': {
      const r = state.ws.rdrawer;
      if (!r || !r.typingStarted || !r.commentTarget) return state;
      if (r.commentTyped.length >= r.commentTarget.length) return state;
      return { ...state, ws: { ...state.ws, rdrawer: { ...r, commentTyped: r.commentTarget.slice(0, r.commentTyped.length + 1) } } };
    }
    case 'WS_RDRAWER_CLOSING': {
      const r = state.ws.rdrawer;
      if (!r) return state;
      return { ...state, ws: { ...state.ws, rdrawer: { ...r, closing: true } } };
    }
    case 'WS_RDRAWER_CLOSE': return { ...state, ws: { ...state.ws, rdrawer: null } };

    default: return state;
  }
}

// ── Story content ───────────────────────────────────────────────────────────

const _PROMPT_TEXT_1 =
  'Hola Claude tenemos nuevo proyecto! Lee todo el contexto del proyecto en el vault del workspace, pero básicamente es un agente IA en WhatsApp para Aura Spa con landing premium. Crea las fases y las tareas del proyecto.';

const _PROMPT_TEXT_2 =
  'Ahora pasa las tareas técnicas a Claude Code. Que vaya resolviendo las tasks asignadas y deje un comment con el resumen de cada una.';

// When the prompt typewriter finishes, the script clock is rebased to these
// values so SEND/scene-change fire 50ms/200ms after the actual last char,
// regardless of React render drift. Each value is "50ms before the script's
// PROMPT_SEND for that prompt". Without this, slow renders push typing past
// the script's expected end and the next scene either cuts off the prompt or
// fires seconds after typing finishes.
const _TYPING_END_BY_TARGET = new Map([
  [_PROMPT_TEXT_1, 10250], // script SEND at 10300
  [_PROMPT_TEXT_2, 42180], // script SEND at 42230
]);

const _PHASE_DESCS = {
  p1: 'Entrevistas con cliente y mapeo de procesos actuales del spa.',
  p2: 'Agente IA con Twilio Conversations y deploy en VPS dedicado.',
  p3: 'Integraciones de pagos, calendario y handoff a operadores humanos.',
  p4: 'Landing del agente y checkout para los paquetes premium del spa.',
  p5: 'Webinar pre-lanzamiento y secuencia de 7 emails de nurturing.',
  p6: 'Tracking, dashboards en tiempo real y reportes semanales.',
};

const _ALL_TASKS = [
  { id: 'T-001', title: 'Discovery con cliente',           descShort: 'Entrevistas con el equipo de Aura Spa y mapeo de procesos.', status: 'closed',   assignee: 'human'  },
  { id: 'T-002', title: 'Definir tono del agente',         descShort: 'Voz cálida, profesional y cercana, alineada con la marca.',  status: 'closed',   assignee: 'claude' },
  { id: 'T-003', title: 'Mapear flujos de WhatsApp',       descShort: 'Diagrama de flujos: agendamiento, reprogramación y FAQ.',     status: 'review',   assignee: 'claude' },
  { id: 'T-004', title: 'Conectar agente con CRM',         descShort: 'Integración con HubSpot para registro automático de leads.',  status: 'progress', assignee: 'human'  },
  { id: 'T-005', title: 'Webhook WhatsApp Business',       descShort: 'Webhook con verificación HMAC-SHA256 y persistencia.',         status: 'backlog',  assignee: 'claude' },
  { id: 'T-006', title: 'Copy del hero de la landing',     descShort: 'Headline, beneficios y testimonios de las sucursales.',         status: 'progress', assignee: 'human'  },
  { id: 'T-007', title: 'Diseño de checkout',              descShort: 'Checkout con Stripe para los paquetes premium del spa.',       status: 'backlog',  assignee: 'human'  },
  { id: 'T-008', title: 'Calendario de emails',            descShort: 'Secuencia de 7 emails de nurturing y lanzamiento.',             status: 'backlog',  assignee: 'human'  },
  { id: 'T-009', title: 'Tracking de conversiones',        descShort: 'GTM + UTMs para atribución end-to-end del funnel.',             status: 'backlog',  assignee: 'human'  },
  { id: 'T-010', title: 'Plantillas de respuesta',         descShort: '12 plantillas para los flujos más comunes del agente.',         status: 'backlog',  assignee: 'claude' },
  { id: 'T-011', title: 'Webinar pre-lanzamiento',         descShort: 'Streaming en vivo con preguntas y demo del agente.',            status: 'backlog',  assignee: 'human'  },
  { id: 'T-012', title: 'Métricas del agente',             descShort: 'Dashboard live de tasa de resolución y tiempo de respuesta.',   status: 'backlog',  assignee: 'claude' },
];

const _RDRAWER_PAYLOADS = {
  'T-005': {
    title: 'Webhook WhatsApp Business',
    desc: 'Implementar el webhook de WhatsApp Business con verificación HMAC-SHA256 y persistencia de eventos en Postgres. Manejar reintentos idempotentes y rate limiting según la cuota de Meta.',
    comment: 'PR listo. Documenté la decisión técnica en /decisiones/canal-whatsapp.md. Tests pasaron al primer intento.',
  },
  'T-010': {
    title: 'Plantillas de respuesta',
    desc: 'Generar 12 plantillas de respuesta para los flujos más comunes del agente: agendamiento, reprogramación, cancelación, confirmación, FAQ y handoff.',
    comment: '12 plantillas listas con tono cálido y profesional. Tests de QA verificaron consistencia con la marca.',
  },
  'T-012': {
    title: 'Métricas del agente',
    desc: 'Dashboard en tiempo real con las métricas clave: tasa de resolución sin handoff, tiempo de respuesta promedio y conversión a cita por sucursal.',
    comment: 'Dashboard live conectado al pipeline de eventos. Wired también a Slack para alertas cuando la resolución cae.',
  },
};

// Story script. ~75s loop. Typewriter wall-clock rate is ~47ms/char (40ms
// setTimeout + React render overhead), so the script timing accounts for that
// drift. 218 chars → real typing-end ≈ 10250ms.
const _SCRIPT = [
  // ── 1. PROMPT 1 (0 – 10.45s)
  { at: 0,    type: 'RESET' },
  { at: 0,    type: 'SET_PHASE', phase: 'prompt' },
  { at: 0,    type: 'PROMPT_TARGET', text: _PROMPT_TEXT_1 },
  // typewriter (~218 chars × 47ms real = ~10250ms)
  { at: 10300, type: 'PROMPT_SEND' },

  // ── 2. ABSORB (compressed to ~2.1s, ends right at 12580 like before)
  { at: 10450, type: 'SET_PHASE', phase: 'absorb' },
  { at: 10520, type: 'STATUS', text: 'Conectando al workspace…' },
  { at: 10820, type: 'STATUS', text: 'Leyendo /decisiones · 18 docs' },
  { at: 11120, type: 'STATUS', text: 'Leyendo /briefs · 12 docs' },
  { at: 11420, type: 'STATUS', text: 'Leyendo /contratos · 6 docs' },
  { at: 11720, type: 'STATUS', text: 'Indexando 64 documentos · 18,200 tokens' },
  { at: 12020, type: 'STATUS', text: 'Estructurando proyecto…' },
  { at: 12200, type: 'SET_PHASE', phase: 'absorb-burst' },

  // ── 3. WORKSPACE — phases (12.6 – 30.1s) — snappy gap into descriptions
  { at: 12580, type: 'SET_PHASE', phase: 'workspace' },
  { at: 12580, type: 'WS_PROJECT', payload: { id: 'aura-spa', name: 'Aura Spa', client: 'Agente IA + Lanzamiento' } },
  { at: 12680, type: 'WS_VIEW', view: 'phases-board' },
  { at: 12880, type: 'WS_TOAST', text: 'Claude planificó 6 fases' },
  { at: 13180, type: 'WS_PHASE', payload: { id: 'p1', name: 'Discovery & estrategia',    status: 'pending' } },
  { at: 13300, type: 'WS_PHASE', payload: { id: 'p2', name: 'Construcción del agente',   status: 'pending' } },
  { at: 13420, type: 'WS_PHASE', payload: { id: 'p3', name: 'Integraciones',              status: 'pending' } },
  { at: 13540, type: 'WS_PHASE', payload: { id: 'p4', name: 'Landing + Funnel',           status: 'pending' } },
  { at: 13660, type: 'WS_PHASE', payload: { id: 'p5', name: 'Email & Webinar',            status: 'pending' } },
  { at: 13780, type: 'WS_PHASE', payload: { id: 'p6', name: 'Lanzamiento + analytics',    status: 'pending' } },
  { at: 13980, type: 'WS_CLEAR_TOAST' },
  { at: 14080, type: 'WS_ACTIVATE_PHASE', id: 'p1', text: _PHASE_DESCS.p1 },
  { at: 16780, type: 'WS_ACTIVATE_PHASE', id: 'p2', text: _PHASE_DESCS.p2 },
  { at: 19480, type: 'WS_ACTIVATE_PHASE', id: 'p3', text: _PHASE_DESCS.p3 },
  { at: 22180, type: 'WS_ACTIVATE_PHASE', id: 'p4', text: _PHASE_DESCS.p4 },
  { at: 24880, type: 'WS_ACTIVATE_PHASE', id: 'p5', text: _PHASE_DESCS.p5 },
  { at: 27580, type: 'WS_ACTIVATE_PHASE', id: 'p6', text: _PHASE_DESCS.p6 },
  { at: 30280, type: 'WS_DEACTIVATE_PHASE' },

  // ── 4. TASKS LIST (30.6 – 33.7s)
  { at: 30580, type: 'WS_TOAST', text: 'Claude generó 12 tareas' },
  { at: 30880, type: 'WS_VIEW', view: 'tasks-list' },
  ..._ALL_TASKS.map((t, i) => ({ at: 31080 + i * 200, type: 'WS_TASK', payload: t })),
  { at: 33680, type: 'WS_CLEAR_TOAST' },

  // ── 5. KANBAN VIEW BRIEF (34.6 – 36.6s)
  { at: 34580, type: 'WS_VIEW', view: 'kanban' },

  // ── 6. PROMPT 2 (36.78 – 42.2s)
  { at: 36780, type: 'SET_PHASE', phase: 'prompt' },
  { at: 36780, type: 'PROMPT_RESET' },
  { at: 36780, type: 'PROMPT_TARGET', text: _PROMPT_TEXT_2 },
  // ~135 chars × 40ms = 5400ms → done at 42180
  { at: 42230, type: 'PROMPT_SEND' },

  // ── 7. CLAUDE CODE — split, terminal LEFT, kanban RIGHT (42.4 – 49.3s)
  { at: 42380, type: 'SET_PHASE', phase: 'workspace' },
  { at: 42380, type: 'WS_VIEW', view: 'kanban' },
  { at: 42480, type: 'WS_LAYOUT', layout: 'split' },
  { at: 42680, type: 'WS_CC_ACTIVE' },

  // T-005 (~2.4s)
  { at: 42830, type: 'WS_MOVE', payload: { id: 'T-005', to: 'progress' } },
  { at: 43030, type: 'WS_TERM_LINE', line: { kind: 'cmd',  text: '$ claude --resume T-005' } },
  { at: 43330, type: 'WS_TERM_LINE', line: { kind: 'info', text: 'leyendo /decisiones/canal-whatsapp.md' } },
  { at: 43630, type: 'WS_TERM_LINE', line: { kind: 'edit', text: 'editando src/whatsapp/webhook.ts (+72 −0)' } },
  { at: 43930, type: 'WS_TERM_LINE', line: { kind: 'edit', text: 'editando __tests__/webhook.test.ts (+48 −0)' } },
  { at: 44230, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'tests: 8 passed' } },
  { at: 44530, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'commit a3f9d12' } },
  { at: 44830, type: 'WS_MOVE', payload: { id: 'T-005', to: 'review' } },
  { at: 44980, type: 'WS_DOC', path: '/decisiones/canal-whatsapp.md' },
  { at: 45130, type: 'WS_TERM_CLEAR' },

  // T-010 (~2.1s)
  { at: 45280, type: 'WS_MOVE', payload: { id: 'T-010', to: 'progress' } },
  { at: 45480, type: 'WS_TERM_LINE', line: { kind: 'cmd',  text: '$ claude --resume T-010' } },
  { at: 45780, type: 'WS_TERM_LINE', line: { kind: 'info', text: 'analizando flujos de conversación' } },
  { at: 46080, type: 'WS_TERM_LINE', line: { kind: 'edit', text: 'creando templates/whatsapp/*.md (12 archivos)' } },
  { at: 46380, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'tests de tono: 12 passed' } },
  { at: 46680, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'commit b1c2d34' } },
  { at: 46980, type: 'WS_MOVE', payload: { id: 'T-010', to: 'review' } },
  { at: 47130, type: 'WS_TERM_CLEAR' },

  // T-012 (~2.1s)
  { at: 47280, type: 'WS_MOVE', payload: { id: 'T-012', to: 'progress' } },
  { at: 47480, type: 'WS_TERM_LINE', line: { kind: 'cmd',  text: '$ claude --resume T-012' } },
  { at: 47780, type: 'WS_TERM_LINE', line: { kind: 'info', text: 'creando dashboards/agent-metrics.tsx' } },
  { at: 48080, type: 'WS_TERM_LINE', line: { kind: 'edit', text: 'wiring al pipeline /events' } },
  { at: 48380, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'tests de integración: 15 passed' } },
  { at: 48680, type: 'WS_TERM_LINE', line: { kind: 'ok',   text: 'commit c2d3e45' } },
  { at: 48980, type: 'WS_MOVE', payload: { id: 'T-012', to: 'review' } },

  // ── 8. TERMINAL CLOSES (49.3 – 49.5s)
  { at: 49380, type: 'WS_LAYOUT', layout: 'normal' },
  { at: 49430, type: 'WS_CC_OFF' },
  { at: 49480, type: 'WS_TERM_CLOSE' },
  { at: 49530, type: 'WS_CLEAR_HIGHLIGHT' },

  // ── 9. RIGHT-SIDEBAR DRAWER — highlight → open → scroll → typewriter → close
  // T-005
  { at: 49780, type: 'WS_SET_HIGHLIGHT', id: 'T-005' },
  { at: 50280, type: 'WS_RDRAWER_OPEN', id: 'T-005',
    title: _RDRAWER_PAYLOADS['T-005'].title, status: 'review', assignee: 'claude-code',
    desc: _RDRAWER_PAYLOADS['T-005'].desc, commentTarget: _RDRAWER_PAYLOADS['T-005'].comment },
  { at: 51480, type: 'WS_RDRAWER_SCROLL' },
  { at: 52180, type: 'WS_RDRAWER_TYPE_START' },
  // ~108 chars × 40 = 4320ms → done ≈ 56500
  { at: 56780, type: 'WS_RDRAWER_CLOSING' },
  { at: 57130, type: 'WS_RDRAWER_CLOSE' },
  { at: 57230, type: 'WS_CLEAR_HIGHLIGHT' },

  // T-010
  { at: 57380, type: 'WS_SET_HIGHLIGHT', id: 'T-010' },
  { at: 57880, type: 'WS_RDRAWER_OPEN', id: 'T-010',
    title: _RDRAWER_PAYLOADS['T-010'].title, status: 'review', assignee: 'claude-code',
    desc: _RDRAWER_PAYLOADS['T-010'].desc, commentTarget: _RDRAWER_PAYLOADS['T-010'].comment },
  { at: 59080, type: 'WS_RDRAWER_SCROLL' },
  { at: 59780, type: 'WS_RDRAWER_TYPE_START' },
  // ~102 chars × 40 = 4080ms → done ≈ 63860
  { at: 64180, type: 'WS_RDRAWER_CLOSING' },
  { at: 64530, type: 'WS_RDRAWER_CLOSE' },
  { at: 64630, type: 'WS_CLEAR_HIGHLIGHT' },

  // T-012
  { at: 64780, type: 'WS_SET_HIGHLIGHT', id: 'T-012' },
  { at: 65280, type: 'WS_RDRAWER_OPEN', id: 'T-012',
    title: _RDRAWER_PAYLOADS['T-012'].title, status: 'review', assignee: 'claude-code',
    desc: _RDRAWER_PAYLOADS['T-012'].desc, commentTarget: _RDRAWER_PAYLOADS['T-012'].comment },
  { at: 66480, type: 'WS_RDRAWER_SCROLL' },
  { at: 67180, type: 'WS_RDRAWER_TYPE_START' },
  // ~108 chars × 40 = 4320ms → done ≈ 71500
  { at: 71780, type: 'WS_RDRAWER_CLOSING' },
  { at: 72130, type: 'WS_RDRAWER_CLOSE' },
  { at: 72230, type: 'WS_CLEAR_HIGHLIGHT' },

  // ── 10. CLOSING (72.4 – 73.9s)
  { at: 72480, type: 'WS_MOVE', payload: { id: 'T-005', to: 'closed' } },
  { at: 72630, type: 'WS_MOVE', payload: { id: 'T-010', to: 'closed' } },
  { at: 72780, type: 'WS_MOVE', payload: { id: 'T-012', to: 'closed' } },
  { at: 72980, type: 'WS_TOAST', text: '3 tareas mergeadas por Claude' },
  { at: 73980, type: 'WS_CLEAR_TOAST' },

  // ── 11. FADE & RESTART
  { at: 74280, type: 'SET_PHASE', phase: 'fade' },
];
const _SCRIPT_TOTAL_MS = 74900;

// ────────────────────────────────────────────────────────────────────────────
// Styles
// ────────────────────────────────────────────────────────────────────────────

const _LANDING_CSS = `
  /* PAGE & GLOBAL BG */
  .lp-page { position: relative; min-height: 100vh; background: ${_C.bg0}; color: ${_C.t0}; overflow-x: hidden; }
  .lp-page-bg {
    position: absolute; inset: 0; pointer-events: none; z-index: 0;
    background-image:
      radial-gradient(circle at 50% -200px, rgba(79,142,255,0.16), transparent 50%),
      radial-gradient(circle at 110% 30%, rgba(249,115,22,0.10), transparent 50%),
      radial-gradient(circle at -10% 70%, rgba(79,142,255,0.08), transparent 50%),
      linear-gradient(rgba(42,47,61,0.45) 1px, transparent 1px),
      linear-gradient(90deg, rgba(42,47,61,0.45) 1px, transparent 1px);
    background-size: auto, auto, auto, 56px 56px, 56px 56px;
    background-attachment: fixed, fixed, fixed, scroll, scroll;
    mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, #000 40%, transparent 100%);
  }
  .lp-content { position: relative; z-index: 1; }

  /* NAV */
  .lp-nav { position: absolute; top: 0; left: 0; right: 0; z-index: 50; padding: 18px 28px; display: flex; align-items: center; gap: 12px; }
  /* Brand mark — must match the production app's TopBar logo:
     white square with a dark inset, scaled proportionally from the 18px source. */
  .lp-logo { width: 26px; height: 26px; border-radius: 6px; background: ${_C.t0}; position: relative; }
  .lp-logo::before { content: ''; position: absolute; inset: 6px; background: ${_C.bg0}; border-radius: 1.5px; }
  .lp-logo-text { font-weight: 700; font-size: 14px; letter-spacing: -0.2px; }
  .lp-nav-link { background: transparent; border: 1px solid transparent; color: ${_C.t1}; font-size: 13px; font-weight: 500; padding: 8px 14px; border-radius: 8px; cursor: pointer; transition: color 160ms; }
  .lp-nav-link:hover { color: ${_C.t0}; }
  .lp-nav-cta { background: ${_C.t0}; color: ${_C.bg0}; border: 1px solid ${_C.t0}; font-size: 13px; font-weight: 600; padding: 8px 16px; border-radius: 8px; cursor: pointer; transition: transform 160ms, box-shadow 200ms; }
  .lp-nav-cta:hover { transform: translateY(-1px); box-shadow: 0 10px 24px rgba(255,255,255,.10); }

  /* HERO */
  .lp-hero { position: relative; min-height: 100vh; padding: 96px 28px 40px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 36px; }
  .lp-hero-headline { text-align: center; max-width: 880px; margin: 0 auto; }
  .lp-hero-title {
    margin: 0 0 14px; font-weight: 500; letter-spacing: -0.03em;
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-size: clamp(36px, 5.6vw, 76px); line-height: 1.05; color: ${_C.t0};
    background: linear-gradient(180deg, ${_C.t0} 0%, ${_C.t0} 55%, rgba(249,115,22,.85) 130%);
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  }
  .lp-hero-subtitle {
    margin: 0; display: inline-flex; align-items: center; gap: 10px;
    font-size: clamp(14px, 1.5vw, 17px); font-weight: 600; letter-spacing: 0.02em;
    color: ${_C.t1}; padding: 8px 16px; border-radius: 999px;
    background: rgba(249,115,22,.08); border: 1px solid rgba(249,115,22,.28);
  }
  .lp-hero-pulse { width: 8px; height: 8px; border-radius: 50%; background: ${_C.claude}; box-shadow: 0 0 0 0 rgba(249,115,22,.6); animation: lp-pulse 1.6s ease-in-out infinite; }
  .lp-stage {
    position: relative; width: 100%; max-width: 1280px;
    aspect-ratio: 16 / 9.4; max-height: calc(100vh - 280px);
    border-radius: 18px; overflow: hidden;
    background: ${_C.bg0}; border: 1px solid ${_C.border};
    box-shadow: 0 60px 140px -30px rgba(0,0,0,.7), 0 0 0 1px rgba(255,255,255,.02) inset;
    isolation: isolate;
    /* Limit invalidation scope: animations inside the stage don't trigger
       layout/paint of the rest of the document. */
    contain: layout paint style;
    transform: translateZ(0);
  }
  .lp-stage::after {
    content: ""; position: absolute; inset: -1px; border-radius: 18px;
    padding: 1px; pointer-events: none;
    background: linear-gradient(135deg, rgba(79,142,255,.55), transparent 35%, transparent 65%, rgba(249,115,22,.55));
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude; opacity: .65;
  }
  .lp-scene { position: absolute; inset: 0; }

  /* helpers */
  .lp-fadein { animation: lp-fadein 320ms cubic-bezier(.16,1,.3,1) both; }
  @keyframes lp-fadein { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
  @keyframes lp-pop {
    0% { opacity: 0; transform: scale(.94) translateY(4px); }
    100% { opacity: 1; transform: scale(1) translateY(0); }
  }
  @keyframes lp-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(249,115,22,.55); }
    50%      { box-shadow: 0 0 0 8px rgba(249,115,22,0); }
  }
  @keyframes lp-cursor-blink { 50% { opacity: 0; } }

  /* CLAUDE PROMPT UI */
  .lp-claude-ui {
    position: absolute; inset: 0;
    background: radial-gradient(ellipse 60% 50% at 50% 40%, rgba(249,115,22,.05), transparent 70%), ${_C.bg0};
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 40px;
    animation: lp-fadein ${_FADE_MS}ms ease-out;
  }
  .lp-claude-logo { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; opacity: .92; }
  .lp-claude-mark { width: 32px; height: 32px; border-radius: 8px; background: ${_C.claude}; display: grid; place-items: center; color: white; font-weight: 700; box-shadow: 0 4px 18px rgba(249,115,22,.4); }
  .lp-claude-mark svg { width: 18px; height: 18px; }
  .lp-claude-name { font-size: 17px; font-weight: 600; letter-spacing: -0.2px; color: ${_C.t0}; }
  .lp-claude-input-wrap { width: 100%; max-width: 760px; background: ${_C.bg1}; border: 1px solid ${_C.border}; border-radius: 18px; padding: 18px 20px; transition: border-color 240ms, box-shadow 240ms; box-shadow: 0 12px 40px rgba(0,0,0,.3); }
  .lp-claude-input-wrap.is-focused { border-color: ${_C.claude}66; box-shadow: 0 0 0 4px rgba(249,115,22,.10), 0 12px 40px rgba(0,0,0,.4); }
  .lp-claude-input { min-height: 52px; font-size: 16px; line-height: 1.55; color: ${_C.t0}; white-space: pre-wrap; word-break: break-word; }
  .lp-claude-input.is-empty { color: ${_C.t3}; }
  .lp-claude-typing::after { content: "▋"; color: ${_C.claude}; margin-left: 1px; animation: lp-cursor-blink 1s steps(2,end) infinite; }
  .lp-claude-actions { display: flex; align-items: center; justify-content: space-between; margin-top: 12px; }
  .lp-claude-hint { font-size: 11.5px; color: ${_C.t3}; display: flex; align-items: center; gap: 7px; }
  .lp-claude-kbd { padding: 1px 6px; border-radius: 4px; background: ${_C.bg2}; border: 1px solid ${_C.border}; color: ${_C.t1}; font: 11px var(--font-mono, monospace); }
  .lp-claude-send { width: 34px; height: 34px; border-radius: 10px; background: ${_C.t0}; color: ${_C.bg0}; display: grid; place-items: center; transition: transform 200ms, background 200ms; }
  .lp-claude-send.is-active { background: ${_C.claude}; color: white; transform: scale(1.06); box-shadow: 0 0 0 6px rgba(249,115,22,.16); }
  .lp-claude-send.is-pressed { animation: lp-press 220ms ease-out; }
  @keyframes lp-press {
    0%   { transform: scale(1.06); }
    50%  { transform: scale(.92); box-shadow: 0 0 0 14px rgba(249,115,22,.05); }
    100% { transform: scale(1.06); }
  }

  /* ABSORB */
  .lp-absorb { position: absolute; inset: 0; background: radial-gradient(circle at 50% 50%, #1A1410 0%, ${_C.bg0} 70%); display: flex; flex-direction: column; align-items: center; justify-content: center; animation: lp-fadein ${_FADE_MS}ms ease-out; }
  .lp-absorb-stage { position: relative; width: min(640px, 80vw); height: min(440px, 50vh); display: flex; align-items: center; justify-content: center; }
  .lp-orb { width: 110px; height: 110px; border-radius: 50%; background: radial-gradient(circle at 32% 30%, #FFD0A8, #FF8E3C 36%, #C2410C 78%, #7C2D12 100%); box-shadow: 0 0 60px rgba(249,115,22,.55), 0 0 140px rgba(249,115,22,.32), 0 0 240px rgba(249,115,22,.18), inset -8px -10px 24px rgba(0,0,0,.35); animation: lp-orb-pulse 2.4s ease-in-out infinite; position: relative; z-index: 3; display: grid; place-items: center; will-change: transform; }
  .lp-orb-mark { width: 44px; height: 44px; color: white; filter: drop-shadow(0 3px 12px rgba(0,0,0,.45)); z-index: 4; }
  /* Pulse only transforms — the box-shadow stays static so we don't repaint
     a 240px halo every frame. The visual difference is imperceptible vs the
     scale change, but the cost drops by ~80%. */
  @keyframes lp-orb-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.07); }
  }
  .lp-orb.is-bursting { animation: lp-orb-burst 800ms cubic-bezier(.55,0,.7,.4) forwards; }
  @keyframes lp-orb-burst {
    0% { transform: scale(1.08); opacity: 1; }
    60% { transform: scale(14); opacity: 0.7; }
    100% { transform: scale(40); opacity: 0; }
  }
  /* Rings: use transform: scale instead of width/height so the animation runs
     on the compositor (GPU) rather than triggering layout every frame. */
  .lp-ring { position: absolute; top: 50%; left: 50%; width: 110px; height: 110px; border-radius: 50%; border: 1px solid rgba(249,115,22,.45); transform: translate(-50%, -50%); animation: lp-ring-expand 2.6s ease-out infinite; will-change: transform, opacity; }
  .lp-ring-2 { animation-delay: 0.87s; }
  .lp-ring-3 { animation-delay: 1.73s; }
  @keyframes lp-ring-expand {
    0%   { transform: translate(-50%, -50%) scale(1);   opacity: 0.7; }
    100% { transform: translate(-50%, -50%) scale(4.9); opacity: 0; }
  }
  .lp-particle { position: absolute; top: 50%; left: 50%; padding: 5px 9px; background: rgba(28,32,48,.92); border: 1px solid rgba(249,115,22,.32); border-radius: 6px; font: 11px var(--font-mono, monospace); color: ${_C.t0}; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; box-shadow: 0 8px 24px rgba(0,0,0,.4); animation: lp-particle-flow 2.2s cubic-bezier(.55,.05,.7,.4) infinite; will-change: transform, opacity; }
  .lp-particle-icon { width: 4px; height: 4px; border-radius: 50%; background: ${_C.claude}; box-shadow: 0 0 6px ${_C.claude}; }
  @keyframes lp-particle-flow {
    0% { opacity: 0; transform: translate(calc(var(--sx) * 1px), calc(var(--sy) * 1px)) scale(.6); }
    18% { opacity: 1; transform: translate(calc(var(--sx) * 0.95px), calc(var(--sy) * 0.95px)) scale(1); }
    78% { opacity: 1; transform: translate(calc(var(--sx) * 0.18px), calc(var(--sy) * 0.18px)) scale(.65); }
    100% { opacity: 0; transform: translate(0, 0) scale(.1); }
  }
  .lp-absorb-status { margin-top: 28px; font: 13px var(--font-mono, monospace); color: ${_C.t1}; display: flex; align-items: center; gap: 10px; min-height: 22px; transition: opacity 160ms; }
  .lp-absorb-status-dot { width: 6px; height: 6px; border-radius: 50%; background: ${_C.claude}; animation: lp-pulse 1.4s ease-in-out infinite; }

  /* WORKSPACE FRAME */
  .lp-ws { position: absolute; inset: 0; display: flex; flex-direction: column; animation: lp-fadein ${_FADE_MS}ms ease-out; }
  .lp-ws-windowbar { flex-shrink: 0; height: 32px; background: ${_C.bg1}; border-bottom: 1px solid ${_C.border}; display: flex; align-items: center; gap: 6px; padding: 0 14px; }
  .lp-dot { width: 10px; height: 10px; border-radius: 50%; }
  .lp-urlbar { flex: 1; margin: 0 12px; height: 20px; border-radius: 5px; background: ${_C.bg2}; border: 1px solid ${_C.border}; font: 11px var(--font-mono, monospace); color: ${_C.t2}; display: flex; align-items: center; padding: 0 10px; }
  .lp-ws-topbar { flex-shrink: 0; height: 44px; padding: 0 16px; background: ${_C.bg1}; border-bottom: 1px solid ${_C.border}; display: flex; align-items: center; gap: 12px; }
  .lp-ws-body { flex: 1; min-height: 0; display: flex; position: relative; }

  /* SIDEBAR — full structure mimicking the real app */
  .lp-sb {
    width: 220px; flex-shrink: 0;
    background: ${_C.bg0}; border-right: 1px solid ${_C.border};
    display: flex; flex-direction: column; overflow: hidden;
  }
  .lp-sb-scroll { flex: 1; overflow-y: auto; padding: 8px 0; }
  .lp-sb-section { padding: 10px 14px 4px; font-size: 10px; font-weight: 600; color: ${_C.t3}; text-transform: uppercase; letter-spacing: 0.7px; }
  .lp-sb-row {
    display: flex; align-items: center; gap: 8px;
    padding: 5px 14px; margin: 0 6px;
    border-radius: 6px;
    font-size: 12.5px; color: ${_C.t1};
    transition: all 200ms;
  }
  .lp-sb-row.is-active { background: ${_C.bg2}; color: ${_C.t0}; }
  .lp-sb-row-icon { width: 14px; height: 14px; flex-shrink: 0; opacity: 0.85; }
  .lp-sb-folder-children { padding-left: 22px; }
  .lp-sb-doc-row {
    display: flex; align-items: center; gap: 6px;
    padding: 4px 14px 4px 30px;
    font-size: 11px;
    font-family: var(--font-mono, monospace);
    color: ${_C.t0};
    border-left: 2px solid ${_C.claude};
    background: rgba(249,115,22,.06);
    margin: 1px 12px 1px 18px;
    border-radius: 0 4px 4px 0;
  }
  .lp-sb-divider { border-top: 1px solid ${_C.border}; margin: 10px 12px 6px; }
  .lp-sb-footer {
    padding: 10px 14px;
    border-top: 1px solid ${_C.border};
    display: flex; justify-content: space-between;
    font-size: 10.5px; color: ${_C.t2};
  }
  .lp-sb-footer-num { color: ${_C.t1}; font-family: var(--font-mono, monospace); font-weight: 500; }
  .lp-sb-project-active {
    margin: 0 6px; padding: 6px 9px; border-radius: 6px;
    background: rgba(79,142,255,.10); border: 1px solid ${_C.accent}40;
    color: ${_C.t0}; display: flex; align-items: center; gap: 7px;
    font-size: 12.5px;
  }

  .lp-ws-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; position: relative; overflow: hidden; }

  /* Split layout (terminal LEFT, kanban RIGHT) */
  .lp-ws-content { flex: 1; display: flex; min-height: 0; position: relative; }
  .lp-kanban-area { flex: 1; min-width: 0; position: relative; display: flex; flex-direction: column; min-height: 0; }
  .lp-ws-content.is-split .lp-kanban-area { border-left: 1px solid ${_C.border}; }
  .lp-terminal-side {
    flex: 1; min-width: 0;
    background: #0A0C12;
    overflow: auto;
    padding: 14px 16px;
    font: 11.5px var(--font-mono, monospace); color: ${_C.t1};
    animation: lp-ts-in 380ms cubic-bezier(.16,1,.3,1) both;
    display: flex; flex-direction: column; gap: 4px;
  }
  @keyframes lp-ts-in {
    from { opacity: 0; transform: translateX(-20px); }
    to { opacity: 1; transform: none; }
  }
  .lp-terminal-side-head { display: flex; align-items: center; gap: 8px; font-size: 10px; color: ${_C.t3}; text-transform: uppercase; letter-spacing: 0.7px; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid ${_C.border}; }
  .lp-term-line { animation: lp-fadein 220ms ease-out both; padding: 2px 0; }

  /* PHASES KANBAN */
  .lp-phase-card { background: ${_C.bg2}; border: 1px solid ${_C.border}; border-radius: 8px; padding: 11px 13px; animation: lp-pop 320ms cubic-bezier(.16,1,.3,1) both; transition: border-color 240ms, box-shadow 240ms; }
  .lp-phase-card.is-active { border-color: ${_C.claude}; box-shadow: 0 0 0 2px rgba(249,115,22,.16), 0 8px 24px rgba(249,115,22,.10); }
  .lp-phase-card-desc-inline {
    max-height: 0; opacity: 0; overflow: hidden;
    font-size: 12px; line-height: 1.5; color: ${_C.t1};
    margin-top: 0; padding-top: 0;
    border-top: 0 solid transparent;
    transition: max-height 320ms cubic-bezier(.16,1,.3,1), opacity 220ms ease, margin-top 280ms ease, padding-top 280ms ease, border-top-width 280ms ease;
  }
  .lp-phase-card.is-active .lp-phase-card-desc-inline {
    max-height: 220px; opacity: 1;
    margin-top: 10px; padding-top: 10px;
    border-top-width: 1px; border-top-color: ${_C.borderStrong};
  }

  /* TASKS LIST VIEW */
  .lp-tasks-list { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 18px; display: flex; flex-direction: column; gap: 8px; }
  .lp-task-row { background: ${_C.bg2}; border: 1px solid ${_C.border}; border-radius: 8px; padding: 11px 14px; animation: lp-row-in 380ms cubic-bezier(.16,1,.3,1) both; }
  @keyframes lp-row-in {
    from { opacity: 0; transform: translateX(-12px); }
    to { opacity: 1; transform: none; }
  }
  .lp-task-row-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; font-size: 11px; }
  .lp-task-row-id { font-family: var(--font-mono, monospace); color: ${_C.t3}; }
  .lp-task-row-status { margin-left: auto; font-size: 10px; padding: 2px 7px; border-radius: 999px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.4px; }
  .lp-task-row-title { font-size: 13px; font-weight: 500; margin-bottom: 4px; color: ${_C.t0}; }
  .lp-task-row-desc { font-size: 12px; color: ${_C.t1}; line-height: 1.4; }

  /* KANBAN */
  .lp-task-card { background: ${_C.bg2}; border: 1px solid ${_C.border}; border-radius: 6px; padding: 9px 11px; font-size: 12px; color: ${_C.t0}; animation: lp-pop 280ms cubic-bezier(.16,1,.3,1) both; transition: border-color 240ms, box-shadow 240ms; position: relative; }
  .lp-task-card.is-highlight { border-color: ${_C.claude}; box-shadow: 0 0 0 2px rgba(249,115,22,.22), 0 0 22px rgba(249,115,22,.18); }

  .lp-toast { background: ${_C.bg3}; border: 1px solid ${_C.borderStrong}; color: ${_C.t0}; padding: 8px 14px; border-radius: 999px; font-size: 12px; display: inline-flex; align-items: center; gap: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.5); animation: lp-fadein 240ms ease-out; }
  .lp-pulse-dot { width: 7px; height: 7px; border-radius: 50%; background: ${_C.claude}; animation: lp-pulse 1.6s ease-in-out infinite; }
  .lp-cc-chip { display: inline-flex; align-items: center; gap: 7px; background: rgba(249,115,22,.12); border: 1px solid rgba(249,115,22,.35); color: ${_C.claude}; padding: 5px 11px; border-radius: 999px; font-size: 11.5px; font-weight: 500; animation: lp-fadein 280ms ease-out; }
  .lp-typewriter::after { content: "▋"; color: ${_C.claude}; margin-left: 1px; animation: lp-cursor-blink 1s steps(2,end) infinite; }

  /* RIGHT-SIDEBAR DRAWER */
  .lp-rdrawer {
    position: absolute; top: 0; right: 0; bottom: 0;
    width: 50%;
    background: ${_C.bg1};
    border-left: 1px solid ${_C.borderStrong};
    box-shadow: -24px 0 60px rgba(0,0,0,.55);
    z-index: 14;
    display: flex; flex-direction: column;
    animation: lp-rdrawer-in 380ms cubic-bezier(.16,1,.3,1) both;
  }
  .lp-rdrawer.is-closing { animation: lp-rdrawer-out 320ms cubic-bezier(.4,0,.7,.4) forwards; }
  @keyframes lp-rdrawer-in {
    from { transform: translateX(100%); }
    to { transform: none; }
  }
  @keyframes lp-rdrawer-out {
    from { transform: none; }
    to { transform: translateX(100%); }
  }
  .lp-rdrawer-header { display: flex; align-items: center; gap: 10px; padding: 14px 18px; background: ${_C.bg2}; border-bottom: 1px solid ${_C.border}; flex-shrink: 0; }
  .lp-rdrawer-id { font: 11px var(--font-mono, monospace); color: ${_C.t3}; background: ${_C.bg3}; padding: 3px 8px; border-radius: 4px; border: 1px solid ${_C.border}; }
  .lp-rdrawer-title { font-size: 14px; font-weight: 600; color: ${_C.t0}; }
  .lp-rdrawer-status-pill { margin-left: auto; font-size: 10px; padding: 3px 9px; border-radius: 999px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.4px; color: ${_C.warn}; background: rgba(245,158,11,.12); border: 1px solid rgba(245,158,11,.3); }
  .lp-rdrawer-close-btn { width: 26px; height: 26px; display: grid; place-items: center; border-radius: 6px; color: ${_C.t2}; opacity: .7; }
  .lp-rdrawer-content { flex: 1; min-height: 0; overflow-y: auto; scroll-behavior: smooth; padding: 18px 22px; display: flex; flex-direction: column; gap: 22px; }
  .lp-rdrawer-section-label { font-size: 11px; color: ${_C.t3}; font-weight: 600; text-transform: uppercase; letter-spacing: 0.7px; margin-bottom: 8px; }
  .lp-rdrawer-desc { font-size: 13.5px; line-height: 1.65; color: ${_C.t0}; }
  .lp-rdrawer-meta-row { display: flex; gap: 18px; font-size: 12px; padding-bottom: 14px; border-bottom: 1px solid ${_C.border}; }
  .lp-rdrawer-meta-key { color: ${_C.t3}; margin-bottom: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.4px; }
  .lp-rdrawer-spacer { height: 220px; flex-shrink: 0; }
  .lp-rdrawer-comment-block { background: ${_C.bg2}; border: 1px solid ${_C.border}; border-radius: 10px; padding: 14px 16px; min-height: 80px; }
  .lp-rdrawer-comment-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
  .lp-rdrawer-comment-avatar { width: 22px; height: 22px; border-radius: 50%; background: ${_C.claude}; color: white; display: grid; place-items: center; font-size: 11px; font-weight: 700; }
  .lp-rdrawer-comment-text { font-size: 13px; line-height: 1.55; color: ${_C.t0}; min-height: 36px; }

  /* BUTTONS / VIDEO TABS / BENTO */
  .lp-btn { display: inline-flex; align-items: center; gap: 8px; padding: 12px 18px; border-radius: 9px; font-size: 14px; font-weight: 600; cursor: pointer; border: 1px solid transparent; transition: transform 120ms, box-shadow 200ms; text-decoration: none; }
  .lp-btn-primary { background: ${_C.t0}; color: ${_C.bg0}; border-color: ${_C.t0}; }
  .lp-btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 32px rgba(255,255,255,.1); }
  .lp-vtab { padding: 10px 18px; border-radius: 999px; font-size: 13px; font-weight: 500; border: 1px solid ${_C.border}; background: rgba(22,25,34,.6); color: ${_C.t1}; cursor: pointer; transition: all 200ms; backdrop-filter: blur(8px); }
  .lp-vtab.is-active { background: ${_C.t0}; color: ${_C.bg0}; border-color: ${_C.t0}; }
  .lp-video-empty { width: 100%; aspect-ratio: 16/9; background: linear-gradient(135deg, rgba(22,25,34,.7), rgba(28,32,48,.5)); border: 1px dashed ${_C.borderStrong}; border-radius: 12px; display: grid; place-items: center; color: ${_C.t2}; font-size: 13px; padding: 24px; text-align: center; }
  .lp-bento { display: grid; gap: 14px; grid-template-columns: repeat(6, 1fr); grid-auto-rows: minmax(160px, auto); }
  .lp-bento-card { background: linear-gradient(180deg, rgba(22,25,34,.8), rgba(15,17,21,.6)); border: 1px solid ${_C.border}; border-radius: 14px; padding: 22px; position: relative; overflow: hidden; transition: transform 200ms, border-color 200ms; backdrop-filter: blur(8px); }
  .lp-bento-card:hover { border-color: ${_C.borderStrong}; transform: translateY(-2px); }

  @media (prefers-reduced-motion: reduce) {
    .lp-fadein, .lp-task-card, .lp-phase-card, .lp-pulse-dot, .lp-typewriter::after,
    .lp-term-line, .lp-orb, .lp-ring, .lp-particle, .lp-claude-typing::after,
    .lp-absorb-status-dot, .lp-toast, .lp-cc-chip, .lp-rdrawer, .lp-task-row,
    .lp-terminal-side {
      animation: none !important;
    }
  }

  /* VIDEO SECTION + TITLES (responsive) */
  .lp-vid-section { padding: 60px 28px 40px; }
  .lp-vid-eyebrow { text-align: center; margin-bottom: 18px; font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: ${_C.claude}; }
  .lp-vid-title { text-align: center; margin: 0 auto 12px; font-size: clamp(20px, 3.4vw, 40px); line-height: 1.1; font-weight: 700; letter-spacing: -0.02em; color: ${_C.t0}; white-space: nowrap; }
  .lp-vid-title.is-solo { margin-bottom: 24px; }
  .lp-vid-subtitle { text-align: center; margin: 0 auto 28px; font-size: clamp(18px, 2.13vw, 24px); line-height: 1.5; font-weight: 500; letter-spacing: -0.01em; color: ${_C.t1}; max-width: 820px; }
  .lp-vid-subtitle.is-nowrap { white-space: nowrap; max-width: none; }

  @media (max-width: 900px) {
    .lp-bento { grid-template-columns: repeat(2, 1fr); }
    .lp-bento-card { grid-column: span 2 !important; }
    .lp-stage { aspect-ratio: 4 / 5; max-height: none; }
    .lp-claude-input { font-size: 14px; }
    .lp-sb { display: none; }
    .lp-rdrawer { width: 86%; }
  }

  /* MOBILE (phones) */
  @media (max-width: 600px) {
    .lp-nav { padding: 12px 14px; gap: 6px; }
    .lp-logo-text { font-size: 13px; }
    .lp-nav-link { padding: 6px 10px; font-size: 12px; }
    .lp-nav-cta { padding: 6px 12px; font-size: 12px; }
    .lp-hero { min-height: auto; padding: 72px 12px 24px; gap: 22px; }
    .lp-hero-title { font-size: clamp(30px, 8vw, 46px); letter-spacing: -0.025em; margin-bottom: 10px; }
    .lp-hero-subtitle { font-size: 13px; padding: 6px 12px; gap: 8px; }
    .lp-hero-pulse { width: 7px; height: 7px; }
    .lp-stage { aspect-ratio: 9 / 14; border-radius: 14px; }
    .lp-claude-ui { padding: 24px 16px; }
    .lp-claude-input-wrap { padding: 14px 14px; border-radius: 14px; }
    .lp-claude-input { font-size: 13px; line-height: 1.5; min-height: 40px; }
    .lp-claude-hint { display: none; }
    .lp-vid-title { white-space: normal; font-size: clamp(22px, 6.5vw, 32px); line-height: 1.18; }
    .lp-vid-eyebrow { font-size: 11px; letter-spacing: 0.16em; margin-bottom: 12px; }
    .lp-vid-subtitle { font-size: clamp(17px, 4.6vw, 21px); margin-bottom: 22px; }
    .lp-vid-subtitle.is-nowrap { white-space: normal; max-width: 760px; }
    .lp-vid-section { padding: 32px 14px 24px; }
    .lp-rdrawer { width: 92%; }
    .lp-particle { font-size: 10px; padding: 4px 7px; }
  }
`;

function _StyleInject() {
  React.useEffect(() => {
    if (document.getElementById('ws-landing-styles')) return;
    const s = document.createElement('style');
    s.id = 'ws-landing-styles';
    s.textContent = _LANDING_CSS;
    document.head.appendChild(s);
  }, []);
  return null;
}

function _ClaudeMarkSvg() {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M12 2 L13.4 9 Q13.6 10 14.6 10.2 L21 11.5 L14.6 12.8 Q13.6 13 13.4 14 L12 21 L10.6 14 Q10.4 13 9.4 12.8 L3 11.5 L9.4 10.2 Q10.4 10 10.6 9 Z" />
    </svg>
  );
}

// ── Tiny inline icons for the sidebar ───────────────────────────────────────
function _Icon({ name }) {
  const props = { width: 14, height: 14, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', className: 'lp-sb-row-icon' };
  switch (name) {
    case 'library':     return <svg {...props}><path d="M3 4v16M7 4v16M11 4h10v16H11z"/></svg>;
    case 'folder':      return <svg {...props}><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>;
    case 'kanban':      return <svg {...props}><rect x="3" y="3" width="6" height="14"/><rect x="11" y="3" width="6" height="10"/><rect x="19" y="3" width="2" height="6"/></svg>;
    case 'layers':      return <svg {...props}><path d="M12 2 2 7l10 5 10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>;
    case 'trello':      return <svg {...props}><rect x="3" y="3" width="18" height="18" rx="2"/><rect x="7" y="7" width="3" height="9"/><rect x="14" y="7" width="3" height="5"/></svg>;
    case 'gantt-chart': return <svg {...props}><line x1="3" y1="6" x2="13" y2="6"/><line x1="7" y1="12" x2="17" y2="12"/><line x1="11" y1="18" x2="21" y2="18"/></svg>;
    case 'user-circle': return <svg {...props}><circle cx="12" cy="12" r="9"/><circle cx="12" cy="10" r="3"/><path d="M6 19a6 6 0 0 1 12 0"/></svg>;
    case 'banknote':    return <svg {...props}><rect x="2" y="6" width="20" height="12" rx="2"/><circle cx="12" cy="12" r="3"/></svg>;
    case 'book-open':   return <svg {...props}><path d="M2 4h7a3 3 0 0 1 3 3v13"/><path d="M22 4h-7a3 3 0 0 0-3 3v13"/></svg>;
    case 'terminal':    return <svg {...props}><path d="M4 17l6-6-6-6"/><line x1="12" y1="19" x2="20" y2="19"/></svg>;
    case 'users':       return <svg {...props}><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>;
    case 'file-text':   return <svg {...props}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>;
    case 'chevron-down': return <svg {...props}><polyline points="6 9 12 15 18 9"/></svg>;
    default: return null;
  }
}

// ── PHASE 1 / 5: Claude prompt UI ───────────────────────────────────────────

const _ClaudePromptScene = React.memo(function _ClaudePromptScene({ prompt }) {
  const isTyping = prompt.target && prompt.text.length < prompt.target.length;
  const isFull = prompt.target && prompt.text.length >= prompt.target.length;
  return (
    <div className="lp-claude-ui">
      <div className="lp-claude-logo">
        <div className="lp-claude-mark"><_ClaudeMarkSvg /></div>
        <div className="lp-claude-name">Claude</div>
      </div>
      <div className={`lp-claude-input-wrap${prompt.focused ? ' is-focused' : ''}`}>
        <div className={`lp-claude-input${prompt.text ? '' : ' is-empty'}${isTyping ? ' lp-claude-typing' : ''}`}>
          {prompt.text || (prompt.focused ? '' : 'Pregúntale algo a Claude…')}
        </div>
        <div className="lp-claude-actions">
          <div className="lp-claude-hint">
            <span className="lp-claude-kbd">⌘</span>
            <span className="lp-claude-kbd">↵</span>
            <span>para enviar</span>
          </div>
          <div className={`lp-claude-send${isFull ? ' is-active' : ''}${prompt.sent ? ' is-pressed' : ''}`}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M12 19V5M5 12l7-7 7 7"/>
            </svg>
          </div>
        </div>
      </div>
    </div>
  );
});

// ── PHASE 2: Absorption ─────────────────────────────────────────────────────

const _PARTICLES = [
  { sx: -260, sy: -160, label: '/decisiones/onboarding.md', delay: 0    },
  { sx:  240, sy: -180, label: '/briefs/aura-spa.md',       delay: 240  },
  { sx: -310, sy:   60, label: '/contratos/mensual.pdf',     delay: 460  },
  { sx:  290, sy:   80, label: '/tasks/T-007 · checkout',    delay: 660  },
  { sx: -190, sy:  170, label: '/decisiones/canal.md',       delay: 860  },
  { sx:  210, sy:  -40, label: '/phases/II-7',                delay: 1040 },
  { sx:    0, sy: -200, label: '/log/2026-05-08',            delay: 1220 },
  { sx:    0, sy:  220, label: '/uploads/audio.m4a',         delay: 1400 },
];

const _AbsorbScene = React.memo(function _AbsorbScene({ status, bursting }) {
  return (
    <div className="lp-absorb">
      <div className="lp-absorb-stage">
        <div className="lp-ring lp-ring-1" />
        <div className="lp-ring lp-ring-2" />
        <div className="lp-ring lp-ring-3" />
        {!bursting && _PARTICLES.map(p => (
          <div key={p.label} className="lp-particle"
               style={{ '--sx': p.sx, '--sy': p.sy, animationDelay: `${p.delay}ms` }}>
            <span className="lp-particle-icon" />
            {p.label}
          </div>
        ))}
        <div className={`lp-orb${bursting ? ' is-bursting' : ''}`}>
          {!bursting && <span className="lp-orb-mark"><_ClaudeMarkSvg /></span>}
        </div>
      </div>
      {!bursting && (
        <div className="lp-absorb-status" key={status}>
          <span className="lp-absorb-status-dot" />
          {status || 'Conectando…'}
        </div>
      )}
    </div>
  );
});

// ── Workspace pieces ────────────────────────────────────────────────────────

function _WsWindowBar({ project }) {
  const sub = project ? `${project.id}.workspace.sebasai.com` : 'workspace.sebasai.com';
  return (
    <div className="lp-ws-windowbar">
      <span className="lp-dot" style={{ background: '#FF5F57' }} />
      <span className="lp-dot" style={{ background: '#FEBC2E' }} />
      <span className="lp-dot" style={{ background: '#28C840' }} />
      <div className="lp-urlbar">
        <span style={{ color: _C.t3, marginRight: 6 }}>⌂</span>
        <span>{sub}</span>
        {project && <span style={{ color: _C.t3 }}>/tracker</span>}
      </div>
    </div>
  );
}

function _WsTopBar({ project, view, claudeCode }) {
  const viewLabel =
    view === 'kanban'       ? 'Tablero' :
    view === 'tasks-list'   ? 'Tareas'  :
    view === 'phases-board' ? 'Fases tablero' : 'Fases';
  return (
    <div className="lp-ws-topbar">
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <div style={{ width: 20, height: 20, borderRadius: 5, background: _C.t0, position: 'relative' }}>
          <div style={{ position: 'absolute', inset: 4, background: _C.bg0, borderRadius: 1 }} />
        </div>
        <span style={{ fontWeight: 600, fontSize: 13 }}>workspace</span>
      </div>
      <div style={{ width: 1, height: 14, background: _C.border }} />
      <div style={{ fontSize: 12, color: _C.t1, display: 'flex', gap: 6, alignItems: 'center' }}>
        {project && (
          <>
            <span>{project.name}</span>
            <span style={{ color: _C.t3 }}>›</span>
            <span style={{ color: _C.t0 }}>{viewLabel}</span>
          </>
        )}
      </div>
      <div style={{ flex: 1 }} />
      {claudeCode && (
        <div className="lp-cc-chip">
          <span className="lp-pulse-dot" />
          Claude Code activo
        </div>
      )}
      <div style={{ width: 24, height: 24, borderRadius: '50%', background: _C.accent, fontSize: 11, color: 'white', display: 'grid', placeItems: 'center', fontWeight: 700 }}>S</div>
    </div>
  );
}

// Sidebar — full structure mirroring the real app (layout.jsx).
function _WsSidebar({ project, view, docs, taskCount, docCount }) {
  const SbRow = ({ icon, label, active }) => (
    <div className={`lp-sb-row${active ? ' is-active' : ''}`}>
      <_Icon name={icon} />
      <span>{label}</span>
    </div>
  );
  const FolderRow = ({ name, open, hasDocs }) => (
    <div className="lp-sb-row">
      <_Icon name="chevron-down" />
      <_Icon name="folder" />
      <span>{name}</span>
    </div>
  );
  return (
    <div className="lp-sb">
      <div className="lp-sb-scroll">
        {/* PROYECTO ACTIVO */}
        <div className="lp-sb-section">Proyecto</div>
        {project ? (
          <div className="lp-sb-project-active">
            <div style={{ width: 6, height: 6, borderRadius: '50%', background: _C.accent }} />
            {project.name}
          </div>
        ) : (
          <div style={{ height: 28, background: _C.bg2, borderRadius: 6, opacity: .35, margin: '0 6px' }} />
        )}

        <div className="lp-sb-divider" />

        {/* VAULT */}
        <div className="lp-sb-section">Vault</div>
        <SbRow icon="library" label="Inicio del Vault" />
        <FolderRow name="decisiones" open={true} hasDocs={docs.length > 0} />
        {docs.map(d => (
          <div key={d} className="lp-sb-doc-row lp-fadein">
            {d.replace('/decisiones/', '')}
          </div>
        ))}
        <FolderRow name="briefs" />
        <FolderRow name="contratos" />
        <FolderRow name="uploads" />

        <div className="lp-sb-divider" />

        {/* TRACKER */}
        <div className="lp-sb-section">Tracker</div>
        <SbRow icon="kanban"      label="Tablero"       active={view === 'kanban'} />
        <SbRow icon="layers"      label="Fases"         active={view === 'phases'} />
        <SbRow icon="trello"      label="Fases tablero" active={view === 'phases-board'} />
        <SbRow icon="gantt-chart" label="Timeline" />
        <SbRow icon="user-circle" label="Mis tareas"    active={view === 'tasks-list'} />

        <div className="lp-sb-divider" />

        {/* NEGOCIO */}
        <div className="lp-sb-section">Negocio</div>
        <SbRow icon="banknote" label="Pagos" />

        <div className="lp-sb-divider" />

        {/* BITÁCORA */}
        <div className="lp-sb-section">Bitácora</div>
        <SbRow icon="book-open" label="Diario / Retros" />

        <div className="lp-sb-divider" />

        {/* AGENTE */}
        <div className="lp-sb-section">Agente</div>
        <SbRow icon="terminal" label="Claude Code" />

        <div className="lp-sb-divider" />

        {/* WORKSPACE */}
        <div className="lp-sb-section">Workspace</div>
        <SbRow icon="users" label="Colaboradores" />
      </div>

      {/* Footer counts */}
      <div className="lp-sb-footer">
        <span><span className="lp-sb-footer-num">{docCount}</span> docs</span>
        <span><span className="lp-sb-footer-num">{taskCount}</span> tareas abiertas</span>
      </div>
    </div>
  );
}

// Phases board (3 cols)
const _PHASE_COLS = [
  { id: 'pending',  label: 'Pendiente', match: 'pending'  },
  { id: 'progress', label: 'En curso',  match: 'progress' },
  { id: 'closed',   label: 'Cerrada',   match: 'closed'   },
];

function _WsPhasesBoard({ phases, activePhase }) {
  return (
    <div style={{
      flex: 1, padding: '14px',
      display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12,
      minHeight: 0, overflow: 'auto', alignContent: 'start',
    }}>
      {_PHASE_COLS.map(col => {
        const colPhases = phases.filter(p => p.status === col.match);
        const colColor = col.id === 'progress' ? _C.accent : col.id === 'closed' ? _C.ok : _C.t3;
        return (
          <div key={col.id} style={{
            // Visible kanban column: subtle bg + border so the divisions read.
            background: 'rgba(22,25,34,0.5)',
            border: `1px solid ${_C.border}`,
            borderRadius: 10,
            padding: '10px 10px 12px',
            display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0,
          }}>
            <div style={{
              fontSize: 10, color: _C.t2, fontWeight: 600,
              textTransform: 'uppercase', letterSpacing: 0.6,
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '0 2px 8px',
              borderBottom: `1px solid ${_C.border}`,
            }}>
              <div style={{ width: 6, height: 6, borderRadius: '50%', background: colColor }} />
              {col.label}
              <span style={{ marginLeft: 'auto', color: _C.t3 }}>{colPhases.length}</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {colPhases.map((p, i) => {
                const isActive = activePhase && activePhase.id === p.id;
                const isTyping = isActive && activePhase.typed.length < activePhase.text.length;
                return (
                  <div key={p.id} className={`lp-phase-card${isActive ? ' is-active' : ''}`} style={{ animationDelay: `${i * 60}ms` }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 5 }}>
                      <span style={{ fontSize: 10, color: _C.t3, fontFamily: 'var(--font-mono, monospace)' }}>{p.id.toUpperCase()}</span>
                      {isActive && <span style={{ marginLeft: 'auto', fontSize: 9.5, color: _C.claude, fontWeight: 700 }}>● describiendo</span>}
                    </div>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{p.name}</div>
                    <div className={`lp-phase-card-desc-inline${isTyping ? ' lp-typewriter' : ''}`}>
                      {isActive ? activePhase.typed : ''}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function _WsTasksListView({ tasks }) {
  const sc = (s) => ({ closed: _C.ok, review: _C.warn, progress: _C.accent, backlog: _C.t3 })[s] || _C.t3;
  const sl = (s) => ({ closed: 'Cerrada', review: 'Review', progress: 'En progreso', backlog: 'Backlog' })[s] || s;
  return (
    <div className="lp-tasks-list">
      {tasks.map((t, i) => {
        const c = sc(t.status);
        const av = t.assignee === 'claude' ? _C.claude : _C.accent;
        return (
          <div key={t.id} className="lp-task-row" style={{ animationDelay: `${i * 30}ms` }}>
            <div className="lp-task-row-head">
              <span className="lp-task-row-id">{t.id}</span>
              <div style={{ width: 16, height: 16, borderRadius: '50%', background: av, fontSize: 9, color: 'white', display: 'grid', placeItems: 'center', fontWeight: 700 }}>
                {t.assignee === 'claude' ? 'C' : 'S'}
              </div>
              {t.assignee === 'claude' && (
                <span style={{ fontSize: 10, color: _C.claude, fontWeight: 600, padding: '1px 7px', borderRadius: 999, background: 'rgba(249,115,22,.12)', border: '1px solid rgba(249,115,22,.3)' }}>Claude Code</span>
              )}
              <span className="lp-task-row-status" style={{ color: c, background: `${c}1A`, border: `1px solid ${c}55` }}>{sl(t.status)}</span>
            </div>
            <div className="lp-task-row-title">{t.title}</div>
            <div className="lp-task-row-desc">{t.descShort}</div>
          </div>
        );
      })}
    </div>
  );
}

const _COLS = [
  { id: 'backlog',  label: 'Backlog'    },
  { id: 'progress', label: 'En progreso' },
  { id: 'review',   label: 'Review'     },
  { id: 'closed',   label: 'Hecho'      },
];

function _WsKanban({ tasks, highlightTaskId }) {
  return (
    <div style={{
      flex: 1, minHeight: 0, padding: 14,
      display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, position: 'relative',
      overflowY: 'auto',
    }}>
      {_COLS.map(col => {
        const colTasks = tasks.filter(t => t.status === col.id);
        const colColor = col.id === 'progress' ? _C.accent : col.id === 'review' ? _C.warn : col.id === 'closed' ? _C.ok : _C.t3;
        return (
          <div key={col.id} style={{
            background: 'rgba(22,25,34,0.5)',
            border: `1px solid ${_C.border}`,
            borderRadius: 10,
            padding: '8px 8px 10px',
            display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0,
          }}>
            <div style={{
              fontSize: 10, color: _C.t2, fontWeight: 600,
              textTransform: 'uppercase', letterSpacing: 0.6,
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '0 2px 7px',
              borderBottom: `1px solid ${_C.border}`,
            }}>
              <div style={{ width: 6, height: 6, borderRadius: '50%', background: colColor }} />
              {col.label}
              <span style={{ marginLeft: 'auto', color: _C.t3 }}>{colTasks.length}</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {colTasks.map((t, i) => {
                const avColor = t.assignee === 'claude' ? _C.claude : _C.accent;
                const avLetter = t.assignee === 'claude' ? 'C' : 'S';
                const isHi = highlightTaskId === t.id;
                return (
                  <div key={t.id} className={`lp-task-card${isHi ? ' is-highlight' : ''}`} style={{ animationDelay: `${i * 30}ms` }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
                      <span style={{ fontSize: 10, color: _C.t3, fontFamily: 'var(--font-mono, monospace)' }}>{t.id}</span>
                      {t.assignee === 'claude' && (
                        <span style={{ marginLeft: 'auto', fontSize: 9.5, color: _C.claude, fontWeight: 600, padding: '1px 6px', borderRadius: 999, background: 'rgba(249,115,22,.12)', border: '1px solid rgba(249,115,22,.3)' }}>Claude Code</span>
                      )}
                    </div>
                    <div style={{ fontSize: 12, lineHeight: 1.4, marginBottom: 7 }}>{t.title}</div>
                    <div style={{
                      width: 18, height: 18, borderRadius: '50%', background: avColor,
                      fontSize: 10, color: 'white', display: 'grid', placeItems: 'center', fontWeight: 700,
                    }}>{avLetter}</div>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function _WsTerminalSide({ terminal }) {
  if (!terminal.open) return null;
  const colorOf = (kind) => kind === 'cmd' ? _C.t0 : kind === 'ok' ? _C.ok : kind === 'edit' ? _C.accent : _C.t1;
  const prefixOf = (kind) => kind === 'ok' ? '✓ ' : kind === 'edit' ? '◆ ' : kind === 'info' ? '› ' : '';
  return (
    <div className="lp-terminal-side">
      <div className="lp-terminal-side-head">
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: _C.claude }} />
        Claude Code · sesión activa · vps-aura-spa
      </div>
      {terminal.lines.map((l, i) => (
        <div key={i} className="lp-term-line" style={{ color: colorOf(l.kind) }}>
          <span style={{ color: _C.t3 }}>{prefixOf(l.kind)}</span>{l.text}
        </div>
      ))}
    </div>
  );
}

function _WsToast({ toast }) {
  if (!toast) return null;
  return (
    <div style={{ position: 'absolute', top: 56, left: '50%', transform: 'translateX(-50%)', zIndex: 6, pointerEvents: 'none' }}>
      <div className="lp-toast">
        <div style={{ width: 16, height: 16, borderRadius: '50%', background: _C.claude, display: 'grid', placeItems: 'center', color: 'white', fontWeight: 700, fontSize: 9 }}>C</div>
        {toast.text}
      </div>
    </div>
  );
}

// Right-sidebar drawer with smooth scroll-to-comment + comment typewriter.
function _WsRightDrawer({ drawer }) {
  const contentRef = React.useRef(null);
  React.useEffect(() => {
    if (!drawer) return;
    const el = contentRef.current;
    if (!el) return;
    if (!drawer.scrolled) {
      el.scrollTop = 0;
      return;
    }
    el.scrollTo({ top: 380, behavior: 'smooth' });
  }, [drawer?.scrolled, drawer?.id]);

  if (!drawer) return null;
  const isCommentTyping = drawer.typingStarted && drawer.commentTyped.length < drawer.commentTarget.length;
  return (
    <div className={`lp-rdrawer${drawer.closing ? ' is-closing' : ''}`}>
      <div className="lp-rdrawer-header">
        <span className="lp-rdrawer-id">{drawer.id}</span>
        <span className="lp-rdrawer-title">{drawer.title}</span>
        <span className="lp-rdrawer-status-pill">Review</span>
        <div className="lp-rdrawer-close-btn">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
        </div>
      </div>
      <div ref={contentRef} className="lp-rdrawer-content">
        <div className="lp-rdrawer-meta-row">
          <div>
            <div className="lp-rdrawer-meta-key">Asignado a</div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <div style={{ width: 18, height: 18, borderRadius: '50%', background: _C.claude, color: 'white', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 700 }}>C</div>
              <span style={{ color: _C.t0 }}>Claude Code</span>
            </div>
          </div>
          <div>
            <div className="lp-rdrawer-meta-key">Fase</div>
            <div style={{ color: _C.t1 }}>P2 · Construcción</div>
          </div>
          <div>
            <div className="lp-rdrawer-meta-key">Branch</div>
            <div style={{ color: _C.t1, fontFamily: 'var(--font-mono, monospace)', fontSize: 11.5 }}>feat/{drawer.id.toLowerCase()}</div>
          </div>
        </div>
        <div>
          <div className="lp-rdrawer-section-label">Descripción</div>
          <div className="lp-rdrawer-desc">{drawer.desc}</div>
        </div>
        <div className="lp-rdrawer-spacer" />
        <div>
          <div className="lp-rdrawer-section-label">Comentarios · 1</div>
          <div className="lp-rdrawer-comment-block">
            <div className="lp-rdrawer-comment-head">
              <div className="lp-rdrawer-comment-avatar">C</div>
              <span style={{ color: _C.claude, fontWeight: 600, fontSize: 12 }}>Claude Code</span>
              <span style={{ color: _C.t3, fontSize: 11 }}>· hace 12s</span>
            </div>
            <div className={`lp-rdrawer-comment-text${isCommentTyping ? ' lp-typewriter' : ''}`}>
              {drawer.commentTyped}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

const _WorkspaceScene = React.memo(function _WorkspaceScene({ ws }) {
  const isSplit = ws.layout === 'split';
  const taskCount = ws.tasks.filter(t => t.status !== 'closed').length;
  const docCount = ws.docs.length + 23; // base count for the demo so it doesn't read 0
  return (
    <div className="lp-ws">
      <_WsWindowBar project={ws.project} />
      <_WsTopBar project={ws.project} view={ws.view} claudeCode={ws.claudeCode} />
      <div className="lp-ws-body">
        <_WsSidebar project={ws.project} view={ws.view} docs={ws.docs} taskCount={taskCount} docCount={docCount} />
        <div className="lp-ws-main">
          <div className={`lp-ws-content${isSplit ? ' is-split' : ''}`}>
            {isSplit && <_WsTerminalSide terminal={ws.terminal} />}
            <div className="lp-kanban-area">
              {ws.view === 'phases-board' && <_WsPhasesBoard phases={ws.phases} activePhase={ws.activePhase} />}
              {ws.view === 'tasks-list'   && <_WsTasksListView tasks={ws.tasks} />}
              {ws.view === 'kanban'       && <_WsKanban tasks={ws.tasks} highlightTaskId={ws.highlightTaskId} />}
              <_WsToast toast={ws.toast} />
            </div>
          </div>
          <_WsRightDrawer drawer={ws.rdrawer} />
        </div>
      </div>
    </div>
  );
});

// ────────────────────────────────────────────────────────────────────────────
// LiveDemo orchestrator
// ────────────────────────────────────────────────────────────────────────────

function LiveDemo() {
  const [state, dispatch] = React.useReducer(_reducer, _initialState);
  const [paused, setPaused] = React.useState(false);
  const stepRef = React.useRef(0);
  const startRef = React.useRef(0);
  const pausedAtRef = React.useRef(0);
  // Set when the script clock is suspended (during prompt typing). On resume,
  // the clock rebases to the expected typing-end so the next event fires 50ms
  // after the actual last char.
  const clockPausedAtRef = React.useRef(0);
  const [reduced] = React.useState(() =>
    typeof window !== 'undefined' && window.matchMedia &&
    window.matchMedia('(prefers-reduced-motion: reduce)').matches
  );

  React.useEffect(() => {
    if (!reduced) return;
    dispatch({ type: 'SET_PHASE', phase: 'workspace' });
    dispatch({ type: 'WS_PROJECT', payload: { id: 'aura-spa', name: 'Aura Spa', client: 'Agente IA + Lanzamiento' } });
    [
      { id: 'p1', name: 'Discovery & estrategia',  status: 'pending' },
      { id: 'p2', name: 'Construcción del agente', status: 'pending' },
      { id: 'p3', name: 'Integraciones',            status: 'pending' },
      { id: 'p4', name: 'Landing + Funnel',         status: 'pending' },
      { id: 'p5', name: 'Email & Webinar',          status: 'pending' },
      { id: 'p6', name: 'Lanzamiento + analytics',  status: 'pending' },
    ].forEach(p => dispatch({ type: 'WS_PHASE', payload: p }));
    dispatch({ type: 'WS_VIEW', view: 'kanban' });
    _ALL_TASKS.slice(0, 6).forEach(t => dispatch({ type: 'WS_TASK', payload: t }));
    dispatch({ type: 'WS_DOC', path: '/decisiones/canal-whatsapp.md' });
  }, [reduced]);

  React.useEffect(() => {
    if (reduced) return;
    if (paused) return;

    // While the prompt typewriter is running, the script driver does NOTHING:
    // no RAF, no clock advance. The effect re-runs when typing state changes
    // (text reaches target), at which point we rebase and start the loop.
    const isTyping =
      state.phase === 'prompt' &&
      !!state.prompt.target &&
      state.prompt.text.length < state.prompt.target.length;
    if (isTyping) {
      if (clockPausedAtRef.current === 0) clockPausedAtRef.current = performance.now();
      return;
    }

    // Resume: rebase clock so the next script event lines up with typing-end.
    if (clockPausedAtRef.current > 0) {
      const expectedEnd = _TYPING_END_BY_TARGET.get(state.prompt.target);
      if (expectedEnd != null) {
        startRef.current = performance.now() - expectedEnd;
      } else {
        startRef.current += performance.now() - clockPausedAtRef.current;
      }
      clockPausedAtRef.current = 0;
    }

    let raf;
    if (!startRef.current) startRef.current = performance.now();
    const loop = () => {
      const elapsed = performance.now() - startRef.current;
      while (stepRef.current < _SCRIPT.length && _SCRIPT[stepRef.current].at <= elapsed) {
        dispatch(_SCRIPT[stepRef.current]);
        stepRef.current++;
      }
      if (elapsed >= _SCRIPT_TOTAL_MS) {
        setTimeout(() => {
          stepRef.current = 0;
          startRef.current = performance.now();
          clockPausedAtRef.current = 0;
          dispatch({ type: 'RESET' });
        }, 100);
        return;
      }
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => raf && cancelAnimationFrame(raf);
  }, [paused, reduced, state.phase, state.prompt.text, state.prompt.target]);

  // Typewriter effects (all share _MS_PER_CHAR).
  React.useEffect(() => {
    if (reduced) return;
    if (!state.prompt.target) return;
    if (state.prompt.text.length >= state.prompt.target.length) return;
    const t = setTimeout(() => dispatch({ type: 'PROMPT_TICK' }), _MS_PER_CHAR);
    return () => clearTimeout(t);
  }, [state.prompt.text, state.prompt.target, reduced]);

  React.useEffect(() => {
    if (reduced) return;
    if (!state.ws.activePhase) return;
    if (state.ws.activePhase.typed.length >= state.ws.activePhase.text.length) return;
    const t = setTimeout(() => dispatch({ type: 'WS_PHASE_DESC_TICK' }), _MS_PER_CHAR);
    return () => clearTimeout(t);
  }, [state.ws.activePhase, reduced]);

  // Right-drawer comment typewriter
  React.useEffect(() => {
    if (reduced) return;
    const r = state.ws.rdrawer;
    if (!r || !r.typingStarted) return;
    if (r.commentTyped.length >= r.commentTarget.length) return;
    const t = setTimeout(() => dispatch({ type: 'WS_RDRAWER_COMMENT_TICK' }), _MS_PER_CHAR);
    return () => clearTimeout(t);
  }, [state.ws.rdrawer, reduced]);

  const onEnter = React.useCallback(() => {
    if (reduced || paused) return;
    pausedAtRef.current = performance.now();
    setPaused(true);
  }, [paused, reduced]);
  const onLeave = React.useCallback(() => {
    if (reduced) return;
    if (pausedAtRef.current && startRef.current) {
      startRef.current += performance.now() - pausedAtRef.current;
    }
    pausedAtRef.current = 0;
    setPaused(false);
  }, [reduced]);

  const sceneOpacity = state.phase === 'fade' ? 0 : 1;

  return (
    <div className="lp-stage" onMouseEnter={onEnter} onMouseLeave={onLeave}>
      <div className="lp-scene" style={{ opacity: sceneOpacity, transition: `opacity ${_FADE_MS}ms cubic-bezier(.4,0,.2,1)` }}>
        {state.phase === 'prompt' && <_ClaudePromptScene prompt={state.prompt} />}
        {(state.phase === 'absorb' || state.phase === 'absorb-burst') && (
          <_AbsorbScene status={state.absorbStatus} bursting={state.phase === 'absorb-burst'} />
        )}
        {(state.phase === 'workspace' || state.phase === 'fade') && (
          <_WorkspaceScene ws={state.ws} />
        )}
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────────────────────
// Page sections
// ────────────────────────────────────────────────────────────────────────────

function _Nav({ onLogin, onSignup }) {
  return (
    <nav className="lp-nav">
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div className="lp-logo" />
        <span className="lp-logo-text">workspace</span>
      </div>
      <div style={{ flex: 1 }} />
      <button className="lp-nav-link" onClick={onLogin}>Iniciar sesión</button>
      <button className="lp-nav-cta" onClick={onSignup}>Empezar gratis</button>
    </nav>
  );
}

function _Hero() {
  return (
    <section className="lp-hero">
      <div className="lp-hero-headline">
        <h1 className="lp-hero-title">Workspace AI</h1>
        <p className="lp-hero-subtitle">
          <span className="lp-hero-pulse" />
          Beta gratuita solo por tiempo limitado
        </p>
      </div>
      <LiveDemo />
    </section>
  );
}

function _VideoBlock({ id, eyebrow, title, subtitle, subtitleNowrap, slot }) {
  return (
    <div style={{ maxWidth: 980, margin: '0 auto 56px' }}>
      <div className="lp-vid-eyebrow">{eyebrow}</div>
      <h2 className={`lp-vid-title${subtitle ? '' : ' is-solo'}`}>{title}</h2>
      {subtitle && <p className={`lp-vid-subtitle${subtitleNowrap ? ' is-nowrap' : ''}`}>{subtitle}</p>}
      <div style={{
        borderRadius: 16, overflow: 'hidden',
        border: `1px solid ${_C.border}`,
        boxShadow: '0 30px 80px -20px rgba(0,0,0,.6)',
        background: 'rgba(22,25,34,.6)', backdropFilter: 'blur(8px)',
      }}>
        {id ? (
          <div style={{ position: 'relative', width: '100%', aspectRatio: '16 / 9' }}>
            <iframe
              src={`https://fast.wistia.net/embed/iframe/${id}?seo=false&videoFoam=true`}
              title={title}
              allow="autoplay; fullscreen"
              allowFullScreen
              frameBorder="0"
              scrolling="no"
              loading="lazy"
              style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}
            />
          </div>
        ) : (
          <div className="lp-video-empty">
            <div>
              <div style={{ fontSize: 32, marginBottom: 8 }}>🎬</div>
              <div style={{ fontSize: 14, color: _C.t1, marginBottom: 4, fontWeight: 500 }}>
                Pegá el media ID de Wistia en <code style={{ color: _C.claude }}>WISTIA_VIDEOS.{slot}</code>
              </div>
              <div style={{ fontSize: 12 }}>
                Archivo: <code>web/landing.jsx</code> · línea ~22
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function _VideoSection() {
  return (
    <section className="lp-vid-section">
      <div style={{ maxWidth: 1100, margin: '0 auto' }}>
        <_VideoBlock
          id={WISTIA_VIDEOS.all}
          slot="all"
          eyebrow="Para todos"
          title="Cómo potenciar tus proyectos con Workspace"
          subtitle={<>Ejemplo llenando un workspace desde cero para un proyecto de <span style={{ color: _C.danger, fontWeight: 700 }}>2,200 USD</span></>}
          subtitleNowrap
        />
        <_VideoBlock
          id={WISTIA_VIDEOS.developers}
          slot="developers"
          eyebrow="Para developers"
          title={<>Workspace para <span style={{ fontFamily: '"JetBrains Mono", ui-monospace, Menlo, monospace', fontWeight: 500, letterSpacing: '-0.02em' }}>Developers</span></>}
          subtitle={<>Ejemplo delegando a Claude Code el desarrollo de un agente IA para un cliente real de <span style={{ color: _C.danger, fontWeight: 700 }}>2,200 USD</span>. Claude revisa las tareas y deja comentarios en el Workspace.</>}
        />
      </div>
    </section>
  );
}

function _Bento() {
  const cards = [
    { span: 4, title: 'Vault con historial real', body: 'Cada doc Markdown vive con su historia. Cada cambio firmado por quien lo hizo — humano o agente.', accent: _C.accent, icon: '📝' },
    { span: 2, title: 'Multi-tenant de verdad',   body: 'Cada user, su workspace, su VPS. Aislamiento real, no shared sandbox.', accent: _C.ok, icon: '🛡' },
    { span: 2, title: 'MCP Connector',             body: 'Claude.ai y ChatGPT con tu workspace en un click. OAuth real.', accent: _C.claude, icon: '🔌' },
    { span: 2, title: 'En tiempo real',            body: 'Cambios al toque entre todo el equipo, sin recargar.', accent: _C.warn, icon: '⚡' },
    { span: 4, title: 'Claude Code en tu VPS',     body: 'Tu servidor, tus credenciales, tu suscripción. Sesiones que sobreviven entre turnos.', accent: _C.claude, icon: '⌨' },
  ];
  return (
    <section style={{ padding: '20px 28px 60px' }}>
      <div style={{ maxWidth: 1240, margin: '0 auto' }}>
        <div className="lp-bento">
          {cards.map((c, i) => (
            <div key={i} className="lp-bento-card" style={{ gridColumn: `span ${c.span}` }}>
              <div style={{
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                width: 36, height: 36, borderRadius: 9,
                background: `${c.accent}1A`, border: `1px solid ${c.accent}55`,
                fontSize: 17, marginBottom: 14,
              }}>{c.icon}</div>
              <div style={{ fontSize: 18, fontWeight: 600, marginBottom: 8, letterSpacing: -0.2 }}>{c.title}</div>
              <div style={{ fontSize: 13.5, color: _C.t1, lineHeight: 1.55, maxWidth: 460 }}>{c.body}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function _FinalCTA({ onSignup }) {
  return (
    <section style={{ padding: '40px 28px 60px' }}>
      <div style={{ maxWidth: 760, margin: '0 auto', textAlign: 'center' }}>
        <button className="lp-btn lp-btn-primary" onClick={onSignup} style={{ fontSize: 15, padding: '14px 24px' }}>
          Empezar gratis
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
        </button>
      </div>
    </section>
  );
}

function _Footer() {
  return (
    <footer style={{
      padding: '24px 28px 40px', borderTop: `1px solid ${_C.border}`,
      color: _C.t2, fontSize: 13,
    }}>
      <div style={{ maxWidth: 1240, margin: '0 auto', display: 'flex', flexWrap: 'wrap', gap: 18, alignItems: 'center' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div className="lp-logo" style={{ width: 22, height: 22 }} />
          <span style={{ fontWeight: 600, color: _C.t1 }}>workspace</span>
        </div>
        <div style={{ flex: 1 }} />
        <span>© {new Date().getFullYear()} sebasai · workspace.sebasai.com</span>
      </div>
    </footer>
  );
}

function LandingScreen({ onGoLogin, onGoSignup }) {
  return (
    <div className="lp-page">
      <_StyleInject />
      <div className="lp-page-bg" />
      <div className="lp-content">
        <_Nav onLogin={onGoLogin} onSignup={onGoSignup} />
        <_Hero />
        <_VideoSection />
        <_Footer />
      </div>
      {/* Floating support widget — same component the production app uses
          in its TopBar (variant="corner" for the floating bottom-right look).
          data-no-record lets the demo recording script hide this so the
          chat bubble doesn't end up baked into the hero video. */}
      {window.SupportButton && (
        <div data-no-record style={{ position: 'fixed', bottom: 24, right: 24, zIndex: 60 }}>
          <window.SupportButton variant="corner" />
        </div>
      )}
    </div>
  );
}

window.LandingScreen = LandingScreen;
