// ─────────────────────────────────────────────────────────────
// GATITAS — Flujo de registro (versión Web navegable)
// React + Babel · funciona en cualquier navegador (PC o móvil)
// ─────────────────────────────────────────────────────────────
const { useState, useEffect } = React;

const TOTAL_STEPS = 3; // cuenta (crear/iniciar sesión), verificar email, perfil

// Versión vigente del paquete de políticas publicado en /politicas.html
// (Términos, Privacidad, Contenido, +18 y Seguridad se versionan juntos,
// como un único paquete — ver esa página). El backend graba esta versión
// como Consent junto con la cuenta al registrarse.
const POLICIES_VERSION = '1.0';

// ─────────────────────────────────────────────────────────────
// Logo + wordmark
// ─────────────────────────────────────────────────────────────
// Isotipo "Gatitas": mismo SVG (wordmark con tipografía custom + gatito
// arriba de la "i") que usa el resto del sitio (ver gatitasLogo en
// shared.js) — se reescribe acá como JSX porque esta pantalla es la
// única que no corre sobre shared.js sino sobre React. El tamaño se
// controla por CSS (.logo-mark en styles.css), igual que en el resto.
function Logo() {
  return (
    <svg className="logo-mark" viewBox="0 0 459 166" aria-hidden="true">
      <g fill="currentColor">
        <path d="M104.17 95.38L104.17 95.38Q104.17 97.74 103.09 98.95Q102.02 100.16 100.62 100.91Q99.22 101.66 98.15 102.60Q97.08 103.54 97.08 105.37L97.08 105.37L97.08 125.03Q97.08 131.04 91.17 131.04L91.17 131.04Q88.96 131.04 87.33 129.73Q85.69 128.41 84.21 127.09Q82.73 125.78 81.07 125.78L81.07 125.78Q79.51 125.78 77.71 126.58Q75.91 127.39 74.46 128.03L74.46 128.03Q71.35 129.48 68.18 130.24Q65.01 130.99 61.52 130.99L61.52 130.99Q49.43 130.99 41.00 126.07Q32.57 121.16 28.16 112.32Q23.76 103.49 23.76 91.67L23.76 91.67Q23.76 83.29 26.88 76.12Q29.99 68.95 35.52 63.63Q41.05 58.32 48.33 55.34Q55.61 52.35 63.88 52.35L63.88 52.35Q67.05 52.35 70.17 52.76Q73.28 53.16 76.29 54.07L76.29 54.07Q77.85 54.50 79.32 54.93Q80.80 55.36 82.41 55.36L82.41 55.36Q83.81 55.36 84.96 54.64Q86.12 53.91 87.27 53.21Q88.43 52.52 89.82 52.52L89.82 52.52Q92.56 52.52 93.40 54.23Q94.23 55.95 94.87 58.10L94.87 58.10Q95.36 59.66 96.19 62.13Q97.02 64.60 97.91 67.37Q98.79 70.13 99.38 72.55Q99.98 74.97 99.98 76.36L99.98 76.36Q99.98 78.94 97.93 80.20Q95.89 81.47 93.58 81.47L93.58 81.47Q91.22 81.47 90.04 80.28Q88.86 79.10 87.68 77.28L87.68 77.28Q84.99 73.19 82.47 70.05Q79.94 66.91 76.53 65.14Q73.12 63.37 67.75 63.37L67.75 63.37Q62.59 63.37 59.21 65.65Q55.83 67.93 53.86 71.66Q51.90 75.40 51.07 79.77Q50.24 84.15 50.24 88.40L50.24 88.40Q50.24 91.51 50.64 94.71Q51.04 97.90 51.90 100.91L51.90 100.91Q53.09 104.94 55.48 108.67Q57.87 112.40 61.41 114.77Q64.96 117.13 69.52 117.13L69.52 117.13Q71.46 117.13 72.58 116.46Q73.71 115.79 73.71 113.64L73.71 113.64L73.71 105.37Q73.71 103.97 73.17 103.49Q72.64 103.00 71.56 102.36L71.56 102.36Q70.17 101.50 68.53 100.67Q66.89 99.84 65.76 98.63Q64.63 97.42 64.63 95.43L64.63 95.43Q64.63 92.42 66.51 91.16Q68.39 89.90 71.13 89.90L71.13 89.90L97.72 89.90Q100.46 89.90 102.31 91.13Q104.17 92.37 104.17 95.38ZM109.48 116.54L109.48 116.54Q109.48 111.60 111.79 108.29Q114.10 104.99 117.83 102.98Q121.57 100.96 125.92 100.10Q130.27 99.24 134.30 99.24L134.30 99.24Q135.48 99.24 136.71 99.27Q137.95 99.30 139.13 99.51L139.13 99.51L139.13 85.55Q139.13 84.21 138.57 82.43Q138.00 80.66 136.28 80.66L136.28 80.66Q134.62 80.66 134.22 82.03Q133.81 83.40 133.81 84.64L133.81 84.64Q133.81 85.17 133.84 85.74Q133.87 86.30 133.87 86.89L133.87 86.89Q133.87 92.42 130.05 94.65Q126.24 96.88 121.35 96.88L121.35 96.88Q117.27 96.88 114.26 95.06Q111.25 93.23 111.25 88.61L111.25 88.61Q111.25 86.78 111.98 85.06Q112.71 83.35 113.83 82.00L113.83 82.00Q117.11 78.03 122.08 75.93Q127.05 73.84 132.55 73.06Q138.06 72.28 142.89 72.28L142.89 72.28Q148.37 72.28 152.93 73.84Q157.50 75.40 160.24 79.02Q162.98 82.65 162.98 88.77L162.98 88.77L162.98 113.53Q162.98 114.44 163.41 115.14Q163.84 115.84 164.86 115.84L164.86 115.84Q165.66 115.84 166.23 115.33Q166.79 114.82 167.60 114.82L167.60 114.82Q169.16 114.82 169.93 115.90Q170.71 116.97 170.71 118.42L170.71 118.42Q170.71 122.18 168.43 124.89Q166.15 127.60 162.76 129.03Q159.38 130.45 155.94 130.45L155.94 130.45Q151.91 130.45 147.81 128.68Q143.70 126.91 142.14 123.15L142.14 123.15Q139.40 126.96 134.65 128.71Q129.89 130.45 125.33 130.45L125.33 130.45Q121.14 130.45 117.51 128.87Q113.89 127.28 111.68 124.17Q109.48 121.05 109.48 116.54ZM133.71 111.81L133.71 111.81Q133.71 113.96 134.73 115.87Q135.75 117.77 138.22 117.77L138.22 117.77Q138.70 117.77 139.13 117.67L139.13 117.67L139.13 106.55Q138.22 106.17 137.25 106.17L137.25 106.17Q135.21 106.17 134.46 108.19Q133.71 110.20 133.71 111.81ZM197.19 130.45L197.19 130.45Q188.01 130.45 182.72 126.18Q177.43 121.91 177.43 112.24L177.43 112.24L177.43 88.88Q177.43 86.57 176.41 85.44Q175.39 84.31 174.04 83.59Q172.70 82.86 171.68 81.82Q170.66 80.77 170.66 78.62L170.66 78.62Q170.66 76.42 172.22 75.16Q173.77 73.89 175.87 73.89L175.87 73.89L178.29 73.89Q179.84 73.89 181.37 72.31Q182.91 70.72 184.49 68.36Q186.07 66.00 187.82 63.66Q189.57 61.32 191.55 59.74Q193.54 58.16 195.90 58.16L195.90 58.16Q198.59 58.16 200.09 59.66Q201.60 61.16 201.60 63.85L201.60 63.85L201.60 73.89L213.79 73.89Q215.83 73.89 217.28 74.86Q218.73 75.83 218.73 78.08L218.73 78.08Q218.73 81.09 216.82 82.65Q214.92 84.21 212.23 84.72Q209.55 85.23 207.18 85.23L207.18 85.23L201.60 85.23L201.60 106.50Q201.60 109.13 202.62 111.46Q203.64 113.80 206.81 113.80L206.81 113.80Q208.90 113.80 210.38 112.59Q211.86 111.38 213.17 110.20Q214.49 109.02 215.99 109.02L215.99 109.02Q217.39 109.02 217.95 110.36Q218.52 111.71 218.52 112.78L218.52 112.78Q218.52 118.20 215.24 122.18Q211.96 126.15 207.05 128.30Q202.13 130.45 197.19 130.45Z"></path>
        <path d="M300.11 130.45L300.11 130.45Q290.93 130.45 285.64 126.18Q280.34 121.91 280.34 112.24L280.34 112.24L280.34 88.88Q280.34 86.57 279.32 85.44Q278.30 84.31 276.96 83.59Q275.62 82.86 274.60 81.82Q273.58 80.77 273.58 78.62L273.58 78.62Q273.58 76.42 275.13 75.16Q276.69 73.89 278.79 73.89L278.79 73.89L281.20 73.89Q282.76 73.89 284.29 72.31Q285.82 70.72 287.41 68.36Q288.99 66.00 290.74 63.66Q292.48 61.32 294.47 59.74Q296.46 58.16 298.82 58.16L298.82 58.16Q301.51 58.16 303.01 59.66Q304.51 61.16 304.51 63.85L304.51 63.85L304.51 73.89L316.71 73.89Q318.75 73.89 320.20 74.86Q321.65 75.83 321.65 78.08L321.65 78.08Q321.65 81.09 319.74 82.65Q317.83 84.21 315.15 84.72Q312.46 85.23 310.10 85.23L310.10 85.23L304.51 85.23L304.51 106.50Q304.51 109.13 305.54 111.46Q306.56 113.80 309.72 113.80L309.72 113.80Q311.82 113.80 313.30 112.59Q314.77 111.38 316.09 110.20Q317.41 109.02 318.91 109.02L318.91 109.02Q320.31 109.02 320.87 110.36Q321.43 111.71 321.43 112.78L321.43 112.78Q321.43 118.20 318.16 122.18Q314.88 126.15 309.97 128.30Q305.05 130.45 300.11 130.45ZM326.27 116.54L326.27 116.54Q326.27 111.60 328.58 108.29Q330.89 104.99 334.62 102.98Q338.35 100.96 342.70 100.10Q347.05 99.24 351.08 99.24L351.08 99.24Q352.26 99.24 353.50 99.27Q354.73 99.30 355.92 99.51L355.92 99.51L355.92 85.55Q355.92 84.21 355.35 82.43Q354.79 80.66 353.07 80.66L353.07 80.66Q351.40 80.66 351.00 82.03Q350.60 83.40 350.60 84.64L350.60 84.64Q350.60 85.17 350.63 85.74Q350.65 86.30 350.65 86.89L350.65 86.89Q350.65 92.42 346.84 94.65Q343.03 96.88 338.14 96.88L338.14 96.88Q334.06 96.88 331.05 95.06Q328.04 93.23 328.04 88.61L328.04 88.61Q328.04 86.78 328.77 85.06Q329.49 83.35 330.62 82.00L330.62 82.00Q333.89 78.03 338.86 75.93Q343.83 73.84 349.34 73.06Q354.84 72.28 359.68 72.28L359.68 72.28Q365.15 72.28 369.72 73.84Q374.29 75.40 377.02 79.02Q379.76 82.65 379.76 88.77L379.76 88.77L379.76 113.53Q379.76 114.44 380.19 115.14Q380.62 115.84 381.64 115.84L381.64 115.84Q382.45 115.84 383.01 115.33Q383.58 114.82 384.38 114.82L384.38 114.82Q385.94 114.82 386.72 115.90Q387.50 116.97 387.50 118.42L387.50 118.42Q387.50 122.18 385.22 124.89Q382.93 127.60 379.55 129.03Q376.17 130.45 372.73 130.45L372.73 130.45Q368.70 130.45 364.59 128.68Q360.48 126.91 358.92 123.15L358.92 123.15Q356.18 126.96 351.43 128.71Q346.68 130.45 342.11 130.45L342.11 130.45Q337.92 130.45 334.30 128.87Q330.67 127.28 328.47 124.17Q326.27 121.05 326.27 116.54ZM350.49 111.81L350.49 111.81Q350.49 113.96 351.51 115.87Q352.53 117.77 355.00 117.77L355.00 117.77Q355.49 117.77 355.92 117.67L355.92 117.67L355.92 106.55Q355.00 106.17 354.04 106.17L354.04 106.17Q352.00 106.17 351.24 108.19Q350.49 110.20 350.49 111.81ZM413.87 81.36L413.87 81.36Q412.04 81.36 410.59 82.16Q409.14 82.97 409.14 85.06L409.14 85.06Q409.14 86.78 409.95 87.70Q410.75 88.61 412.26 89.25L412.26 89.25Q413.87 89.95 415.64 90.27Q417.42 90.60 419.08 90.97L419.08 90.97Q424.02 92.05 428.32 94.60Q432.62 97.15 435.27 101.15Q437.93 105.15 437.93 110.63L437.93 110.63Q437.93 117.99 434.60 122.34Q431.27 126.69 425.77 128.57Q420.26 130.45 413.71 130.45L413.71 130.45Q412.04 130.45 409.12 130.02Q406.19 129.59 404.79 128.84L404.79 128.84L404.74 128.84Q404.20 128.57 402.97 128.25Q401.73 127.93 401.14 127.93L401.14 127.93Q399.48 127.93 398.29 129.24Q397.11 130.56 395.39 130.56L395.39 130.56Q393.08 130.56 391.77 129.05Q390.45 127.55 389.78 125.48Q389.11 123.41 388.57 121.64L388.57 121.64Q388.20 120.14 387.71 118.66Q387.23 117.18 387.23 115.63L387.23 115.63Q387.23 112.83 388.73 111.11Q390.24 109.40 393.08 109.40L393.08 109.40Q395.88 109.40 397.70 110.60Q399.53 111.81 400.95 113.59Q402.38 115.36 403.85 117.16Q405.33 118.96 407.42 120.17Q409.52 121.37 412.69 121.37L412.69 121.37Q414.89 121.37 416.02 120.06Q417.15 118.74 417.15 116.65L417.15 116.65Q417.15 113.64 415.54 112.78Q413.92 111.92 411.40 111.44L411.40 111.44Q406.78 110.52 402.62 109.29Q398.46 108.05 395.26 105.90Q392.06 103.76 390.21 100.21Q388.36 96.67 388.36 91.08L388.36 91.08Q388.36 84.47 391.96 80.31Q395.55 76.15 401.11 74.16Q406.67 72.17 412.42 72.17L412.42 72.17Q414.62 72.17 416.74 72.34Q418.87 72.50 420.96 73.19L420.96 73.19Q421.23 73.25 422.22 73.62Q423.22 74.00 424.18 74.35Q425.15 74.70 425.15 74.70L425.15 74.70Q426.92 74.70 428.18 73.44Q429.45 72.17 431.22 72.17L431.22 72.17Q433.47 72.17 434.55 73.92Q435.62 75.67 436.08 77.98Q436.54 80.28 436.80 81.90L436.80 81.90Q437.02 83.13 437.23 84.39Q437.45 85.66 437.45 86.89L437.45 86.89Q437.45 89.04 436.46 90.95Q435.46 92.85 432.94 92.85L432.94 92.85Q430.41 92.85 428.48 91.11Q426.55 89.36 424.61 87.11Q422.68 84.85 420.15 83.10Q417.63 81.36 413.87 81.36Z"></path>
        <rect x="233.61" y="76.00" width="26" height="64" rx="13"></rect>
      </g>
      <g transform="translate(220.61 20.00) scale(0.52)">
        <path d="M18 42 L22 10 L42 28 Q50 26 58 28 L78 10 L82 42 Q86 80 50 84 Q14 80 18 42 Z" fill="var(--logo-fg, #FBD7DC)"></path>
        <circle cx="38" cy="54" r="5" fill="var(--logo-bg, #0A0A0A)"></circle>
        <circle cx="62" cy="54" r="5" fill="var(--logo-bg, #0A0A0A)"></circle>
        <path d="M43 67 Q46.5 71 50 67 Q53.5 71 57 67" stroke="var(--logo-bg, #0A0A0A)" strokeWidth="3.5" fill="none" strokeLinecap="round"></path>
      </g>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Dark mode toggle
// ─────────────────────────────────────────────────────────────
function useDarkMode() {
  const [dark, setDark] = useState(() => {
    try { return localStorage.getItem('gatitas-theme') === 'dark'; }
    catch (e) { return false; }
  });
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
    try { localStorage.setItem('gatitas-theme', dark ? 'dark' : 'light'); } catch (e) {}
  }, [dark]);
  return [dark, () => setDark(d => !d)];
}

function ThemeToggle({ dark, onToggle }) {
  return (
    <button className="theme-toggle" onClick={onToggle}
      aria-label={dark ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro'}
      title={dark ? 'Modo claro' : 'Modo oscuro'}>
      <span className={'theme-toggle-thumb' + (dark ? ' dark' : '')}>
        {dark ? (
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <path d="M21 12.8A9 9 0 0111.2 3a7 7 0 109.8 9.8z" fill="var(--pink)"/>
          </svg>
        ) : (
          <svg width="14" height="14" viewBox="0 0 24 24">
            <circle cx="12" cy="12" r="4.5" fill="currentColor"/>
            <g stroke="currentColor" strokeWidth="1.8" strokeLinecap="round">
              <path d="M12 2v3M12 19v3M2 12h3M19 12h3M4.6 4.6l2.1 2.1M17.3 17.3l2.1 2.1M4.6 19.4l2.1-2.1M17.3 6.7l2.1-2.1"/>
            </g>
          </svg>
        )}
      </span>
    </button>
  );
}

function Wordmark() {
  return <span className="sr-only">Gatitas</span>;
}

// ─────────────────────────────────────────────────────────────
// Cabecera
// ─────────────────────────────────────────────────────────────
// loggedIn: esta pantalla ya sabe que el usuario está autenticado (venimos
// de un login/registro exitoso) — antes el botón decía "Iniciar sesión" acá
// también, dando a entender que la sesión no había prendido aunque sí lo
// había hecho (el resto de la pantalla ya usa la sesión real, ver
// AlreadyHasProfileScreen/DoneScreen). onLogin sigue siendo el mismo
// handler que cada pantalla ya pasaba — acá solo se corrige la etiqueta.
function Header({ onLogin, dark, onToggleTheme, loggedIn }) {
  return (
    <header className="header">
      <a className="brand" href="explorar.html" style={{ textDecoration: 'none', color: 'inherit' }}>
        <Logo />
        <Wordmark />
      </a>
      <nav>
        <a href="explorar.html">Explorar</a>
        <a href="publica-con-nosotros.html">Publicá con nosotros</a>
        {onToggleTheme && <ThemeToggle dark={dark} onToggle={onToggleTheme} />}
        <button className="login" onClick={onLogin}>{loggedIn ? 'Mi panel' : 'Iniciar sesión'}</button>
      </nav>
      <div className="header-mobile-actions">
        {onToggleTheme && <ThemeToggle dark={dark} onToggle={onToggleTheme} />}
        <button className="burger" aria-label="Menú">
          <span /><span /><span />
        </button>
      </div>
    </header>
  );
}

// ─────────────────────────────────────────────────────────────
// StepDots
// ─────────────────────────────────────────────────────────────
function StepDots({ index, total = TOTAL_STEPS }) {
  return (
    <div className="dots">
      {Array.from({ length: total }).map((_, i) => (
        <div key={i} className={'dot' + (i === index ? ' on' : '')} />
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Brand panel (lado izquierdo)
// ─────────────────────────────────────────────────────────────
function BrandPanel({ bg, accent, quote, author, role, hideAuthor = false, centered = false, brandHref, smallQuote = false }) {
  const brand = (
    <div className={'brand' + (centered ? ' centered' : '')}>
      <Logo />
      <Wordmark />
    </div>
  );
  return (
    <div className={'brand-panel' + (centered ? ' centered' : '')} style={{ background: bg }}>
      <div className="blob a" style={{ background: accent }} />
      <div className="blob b" style={{ background: 'var(--pink-deep)' }} />
      {brandHref ? (
        <a href={brandHref} className="brand-link" style={{ textDecoration: 'none', color: 'inherit', alignSelf: centered ? 'center' : 'flex-start' }}>
          {brand}
        </a>
      ) : brand}
      <div className={'quote' + (smallQuote ? ' small' : '')}>“{quote}”</div>
      {!hideAuthor && author && (
        <div className="author">
          <div className="avatar">{author.slice(0, 1)}</div>
          <div>
            <div className="name">{author}</div>
            <div className="role">{role}</div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Modal de legales (Términos / Privacidad)
// ─────────────────────────────────────────────────────────────
function LegalModal({ open, kind, onClose }) {
  if (!open) return null;
  const isTerms = kind === 'terms';
  const title = isTerms ? 'Términos y condiciones' : 'Política de privacidad';
  return (
    <div className="legal-modal-backdrop" onClick={onClose}>
      <div className="legal-modal" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" aria-label={title}>
        <div className="legal-modal-head">
          <div>
            <div className="legal-modal-tag">GATITAS · v 1.0 · {new Date().toLocaleDateString('es-AR')}</div>
            <div className="legal-modal-title">{title}</div>
          </div>
          <button className="legal-modal-close" onClick={onClose} aria-label="Cerrar">
            <svg width="14" height="14" viewBox="0 0 14 14"><path d="M2 2l10 10M12 2L2 12" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/></svg>
          </button>
        </div>
        <div className="legal-modal-body">
          {isTerms ? <TermsContent /> : <PrivacyContent />}
        </div>
        <div className="legal-modal-foot">
          <button className="btn primary" onClick={onClose}>Entendido</button>
        </div>
      </div>
    </div>
  );
}

function TermsContent() {
  return (
    <>
      <p>Bienvenido a <b>GATITAS</b>. Al crear una cuenta o utilizar nuestra plataforma, aceptás
      los presentes Términos y Condiciones. Te pedimos que los leas con atención.</p>

      <h3>1 · Aceptación</h3>
      <p>El uso de GATITAS implica la aceptación plena y sin reservas de estos términos.
      Si no estás de acuerdo, te pedimos no utilizar la plataforma.</p>

      <h3>2 · Cuenta de usuario</h3>
      <p>Debés ser mayor de edad en tu jurisdicción y proporcionar información veraz al
      registrarte. Sos responsable de la confidencialidad de tu contraseña y de toda
      actividad que ocurra en tu cuenta.</p>

      <h3>3 · Contenido publicado</h3>
      <p>Como colaborador, sos el único responsable del contenido que publicás. Garantizás
      ser titular de los derechos o contar con las autorizaciones necesarias. GATITAS
      no reclama propiedad sobre tu contenido; vos conservás todos los derechos.</p>

      <h3>4 · Conducta prohibida</h3>
      <p>Está prohibido publicar contenido ilegal, ofensivo, que infrinja derechos de
      terceros, contenga malware o promueva actividades ilícitas. GATITAS se reserva
      el derecho de remover contenido y suspender cuentas que incumplan estas reglas.</p>

      <h3>5 · Pagos y comisiones</h3>
      <p>Las comisiones aplicables a cada plan se detallan en la sección "Publicá con nosotros".
      GATITAS puede modificarlas con un aviso previo de 30 días.</p>

      <h3>6 · Limitación de responsabilidad</h3>
      <p>La plataforma se ofrece "tal cual". GATITAS no garantiza disponibilidad ininterrumpida
      ni resultados comerciales. En ningún caso seremos responsables por daños indirectos,
      lucro cesante o pérdida de datos.</p>

      <h3>7 · Cancelación</h3>
      <p>Podés cancelar tu cuenta en cualquier momento desde tu perfil. GATITAS puede
      suspender o terminar cuentas que violen estos términos o la ley aplicable.</p>

      <h3>8 · Modificaciones</h3>
      <p>Podemos actualizar estos términos. Te notificaremos por correo de cambios
      sustanciales con al menos 15 días de anticipación.</p>

      <h3>9 · Ley aplicable</h3>
      <p>Estos términos se rigen por las leyes de la República Argentina. Cualquier
      controversia se someterá a los tribunales ordinarios con asiento en la Ciudad
      Autónoma de Buenos Aires.</p>

      <h3>10 · Contacto</h3>
      <p>Para consultas escribinos a <b>legales@gatitas.com</b>.</p>
    </>
  );
}

function PrivacyContent() {
  return (
    <>
      <p>En <b>GATITAS</b> tu privacidad es prioridad. Esta política explica qué datos
      recolectamos, para qué los usamos y cómo los protegemos.</p>

      <h3>1 · Datos que recolectamos</h3>
      <p>Recolectamos: (a) datos de cuenta (correo, contraseña cifrada); (b) datos de tu
      perfil público (nombre, zona, bio, contacto) si publicás uno; y (c) datos de uso
      (navegación, búsquedas). Te pedimos documento de identidad y una selfie de
      verificación para corroborar que la persona sea 100% independiente. Estos
      documentos se usan exclusivamente para ese control interno y no implican
      reconocimiento facial automático ni verificación biométrica de ningún proveedor
      externo: cada perfil pasa por una revisión manual de un administrador antes de
      publicarse.</p>

      <h3>2 · Cómo usamos tus datos</h3>
      <p>Usamos tus datos exclusivamente para operar tu cuenta, publicar tu perfil si
      corresponde, prevenir fraudes y mejorar la plataforma. Nunca los vendemos ni
      cedemos a terceros con fines publicitarios.</p>

      <h3>3 · Almacenamiento y seguridad</h3>
      <p>Tu contraseña se guarda cifrada (nunca en texto plano). Aplicamos TLS en todo el
      sitio y controles de acceso sobre los datos que sí almacenamos.</p>

      <h3>4 · Compartición</h3>
      <p>No compartimos tus datos con terceros, salvo: (a) el procesador de pagos, solo
      para cobrar la publicación de tu perfil; (b) requerimiento legal de autoridad
      competente. Tu documento y selfie de verificación no se comparten con ningún
      proveedor externo — se usan únicamente para la revisión manual interna descripta
      en la sección 1.</p>

      <h3>5 · Cookies</h3>
      <p>Usamos cookies para mantener tu sesión iniciada, recordar tu tema (claro / oscuro)
      y tu moneda preferida. No utilizamos cookies de seguimiento publicitario.</p>

      <h3>6 · Tus derechos</h3>
      <p>Podés solicitar acceso, rectificación, portabilidad o eliminación de tus datos
      escribiendo a <b>privacidad@gatitas.com</b>. Responderemos en un plazo máximo de 30 días.</p>

      <h3>7 · Retención</h3>
      <p>Conservamos tus datos mientras tu cuenta esté activa y hasta 24 meses después
      del cierre, según obligaciones legales aplicables.</p>

      <h3>8 · Menores</h3>
      <p>GATITAS no está dirigida a menores de 18 años. Si detectamos cuentas de menores
      sin autorización parental, las cerraremos y eliminaremos sus datos.</p>

      <h3>9 · Actualizaciones</h3>
      <p>Podemos actualizar esta política con aviso previo. La versión vigente está
      siempre disponible desde tu perfil.</p>

      <h3>10 · Contacto</h3>
      <p>Para cualquier consulta sobre privacidad: <b>privacidad@gatitas.com</b>.</p>
    </>
  );
}

// ─────────────────────────────────────────────────────────────
// FormPanel — contenedor del paso
// ─────────────────────────────────────────────────────────────
function FormPanel({ stepIndex, title, subtitle, children, footerLeft, footerRight, onBack }) {
  return (
    <div className="form-panel">
      <div className="top-bar">
        {onBack ? (
          <button className="role" style={{ width: 38, flex: 'none', height: 38, borderRadius: 10, background: 'var(--surface-2)' }} onClick={onBack} aria-label="Atrás">
            <svg width="14" height="14" viewBox="0 0 14 14"><path d="M9 1L3 7l6 6" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </button>
        ) : <span />}
        <StepDots index={stepIndex} />
        <span className="step-count">Paso {stepIndex + 1} de {TOTAL_STEPS}</span>
      </div>
      <div className="container fade-in" key={stepIndex}>
        <div>
          <h1>{title}</h1>
          {subtitle && <div className="sub">{subtitle}</div>}
        </div>
        {children}
      </div>
      {(footerLeft || footerRight) && (
        <div className="footer">
          <div className="left">{footerLeft}</div>
          <div>{footerRight}</div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 0 · Bienvenida (landing)
// ─────────────────────────────────────────────────────────────
function Welcome({ onStart, onLogin, dark, onToggleTheme }) {
  return (
    <div className="app">
      <div className="welcome">
        <div className="blob a" />
        <div className="blob b" />
        <div className="blob c" />
        <Header onLogin={onLogin} dark={dark} onToggleTheme={onToggleTheme} />
        <div className="hero">
          <div className="hero-inner fade-in">
            <h1>Encontrá perfiles<br/><i>independientes</i> verificados.</h1>
            <p>Explorá el directorio y contactá directamente por WhatsApp. GATITAS no interviene en el contacto ni en ningún acuerdo posterior.</p>
            <div className="cta">
              <button className="btn primary" onClick={onStart}>Crear cuenta</button>
              <button className="btn ghost" onClick={onLogin}>Iniciar sesión</button>
              <a className="btn ghost" href="explorar.html">
                Ir a explorar
                <svg width="14" height="14" viewBox="0 0 14 14"><path d="M5 1l6 6-6 6" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </a>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 1 · Cuenta — crear cuenta / iniciar sesión en una sola pantalla con tabs.
// Antes, "Iniciar prueba gratuita" mandaba directo a este paso pero SOLO
// existía el modo registro: el link "¿Ya tienes una? Inicia sesión" apuntaba
// a la ruta "#login", que no estaba en ROUTES — no llevaba a ningún lado.
// Cualquier persona con cuenta chocaba con "email en uso" sin salida. Este
// componente reemplaza a SignupStep con las dos rutas reales.
// ─────────────────────────────────────────────────────────────
function AuthStep({ data, setData, onBack, onRegistered, onLoggedIn, initialMode = 'signup' }) {
  const [mode, setMode] = useState(initialMode); // 'signup' | 'login'
  const [showPw, setShowPw] = useState(false);
  const [legalModal, setLegalModal] = useState(null); // 'terms' | 'privacy' | null
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [emailTaken, setEmailTaken] = useState(false); // dispara el aviso "ya registrado → iniciá sesión"

  const emailValid = /\S+@\S+\.\S+/.test(data.email);
  const signupValid = emailValid && data.password.length >= 10 && data.password === data.confirmPassword && data.accept;
  const loginValid = emailValid && data.password.length > 0;

  function switchMode(next) {
    setMode(next);
    setError('');
    setEmailTaken(false);
  }

  async function submitSignup() {
    if (!signupValid || loading) return;
    setError('');
    setEmailTaken(false);
    setLoading(true);
    try {
      await window.GATITAS_API.register({
        email: data.email,
        password: data.password,
        termsVersion: POLICIES_VERSION,
        privacyVersion: POLICIES_VERSION,
      });
      onRegistered();
    } catch (e) {
      if (e.status === 409) {
        // "Este email ya está registrado" — sección 7: nunca se crea una
        // segunda cuenta, se ofrece pasar a iniciar sesión con el mismo email.
        setEmailTaken(true);
        setMode('login');
      } else {
        setError(e.message || 'No pudimos crear tu cuenta. Probá de nuevo.');
      }
    } finally {
      setLoading(false);
    }
  }

  async function submitLogin() {
    if (!loginValid || loading) return;
    setError('');
    setLoading(true);
    try {
      await window.GATITAS_API.login({ email: data.email, password: data.password });
      await onLoggedIn();
    } catch (e) {
      setError(e.message || 'No pudimos iniciar sesión. Probá de nuevo.');
    } finally {
      setLoading(false);
    }
  }

  const isSignup = mode === 'signup';

  return (
    <div className="app">
      <div className="split">
        <BrandPanel
          bg="var(--pink)" accent="var(--blue)"
          hideAuthor smallQuote
          brandHref="explorar.html"
          quote="Inicia sesión para hacer todos tus sueños realidad"
        />
        <FormPanel
          stepIndex={0}
          title={isSignup ? 'Creá tu cuenta' : 'Iniciá sesión'}
          subtitle={isSignup ? 'Empezá con tu correo electrónico.' : 'Ingresá con el email y la contraseña de tu cuenta.'}
          onBack={onBack}
          footerLeft={
            isSignup
              ? <>¿Ya tenés una? <a href="#" onClick={(e) => { e.preventDefault(); switchMode('login'); }}><b>Iniciá sesión</b></a></>
              : <>¿Sos nuevo/a? <a href="#" onClick={(e) => { e.preventDefault(); switchMode('signup'); }}><b>Creá una cuenta</b></a></>
          }
          footerRight={
            isSignup ? (
              <button className="btn primary" disabled={!signupValid || loading} onClick={submitSignup}>
                {loading ? 'Creando cuenta…' : 'Continuar'}
              </button>
            ) : (
              <button className="btn primary" disabled={!loginValid || loading} onClick={submitLogin}>
                {loading ? 'Ingresando…' : 'Iniciar sesión'}
              </button>
            )
          }
        >
          <div className="tabs" role="tablist" aria-label="Iniciar sesión o crear cuenta">
            <button type="button" role="tab" aria-selected={!isSignup} className={'tab' + (!isSignup ? ' on' : '')} onClick={() => switchMode('login')}>
              Iniciar sesión
            </button>
            <button type="button" role="tab" aria-selected={isSignup} className={'tab' + (isSignup ? ' on' : '')} onClick={() => switchMode('signup')}>
              Crear cuenta
            </button>
          </div>

          {emailTaken && (
            <div className="auth-notice">
              Este email ya está registrado. Iniciá sesión para continuar.
            </div>
          )}

          {/* "Continuar con Google" — oculto a propósito: usaba un client_id
              de placeholder que nunca correspondió a una app real de Google
              Cloud, así que Google devolvía "invalid_client" apenas alguien
              lo tocaba. Reactivar esto requiere un OAuth Client ID real
              (Google Cloud Console) más un endpoint de backend que
              intercambie el code por tokens — no existe ninguno de los dos
              todavía. El resto del flujo (email + contraseña) no depende de
              esto en absoluto. */}

          <div className="field">
            <label htmlFor="email">Correo electrónico</label>
            <div className="input">
              <input id="email" type="email" autoComplete="email" placeholder="tu@correo.com"
                value={data.email} onChange={e => { setData({ ...data, email: e.target.value }); setEmailTaken(false); }} />
            </div>
          </div>

          <div className="field">
            <label htmlFor="password">Contraseña</label>
            <div className="input">
              <input id="password" type={showPw ? 'text' : 'password'} autoComplete={isSignup ? 'new-password' : 'current-password'}
                placeholder={isSignup ? 'Mín. 10 caracteres' : 'Tu contraseña'}
                value={data.password} onChange={e => setData({ ...data, password: e.target.value })} />
              <button className="trailing" type="button" onClick={() => setShowPw(s => !s)}>
                {showPw ? 'Ocultar' : 'Ver'}
              </button>
            </div>
          </div>

          {isSignup && (
            <div className="field">
              <label htmlFor="confirmPassword">Confirmar contraseña</label>
              <div className="input">
                <input id="confirmPassword" type={showPw ? 'text' : 'password'} autoComplete="new-password" placeholder="Repetí la contraseña"
                  value={data.confirmPassword} onChange={e => setData({ ...data, confirmPassword: e.target.value })} />
              </div>
              {data.confirmPassword && data.password !== data.confirmPassword && (
                <div style={{ fontSize: 12, color: 'var(--pink-deep)', marginTop: 4 }}>Las contraseñas no coinciden.</div>
              )}
            </div>
          )}

          {!isSignup && (
            <div style={{ textAlign: 'right', marginTop: -8 }}>
              <a href="#olvide" style={{ fontSize: 13, fontWeight: 600 }}>¿Olvidaste tu contraseña?</a>
            </div>
          )}

          {error && (
            <div style={{
              padding: 12, borderRadius: 12, background: 'var(--pink-soft)',
              color: 'var(--ink)', fontSize: 13, fontWeight: 500,
            }}>{error}</div>
          )}

          {isSignup && (
            <label className="check">
              <input type="checkbox" required checked={data.accept} onChange={e => setData({ ...data, accept: e.target.checked })} />
              <span className="box">
                <svg width="12" height="12" viewBox="0 0 12 12"><path d="M2 6l3 3 5-6" stroke="#fff" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </span>
              <span className="label">
                Declaro que he leído y acepto los <a href="#terms" onClick={(e) => { e.preventDefault(); setLegalModal('terms'); }}>Términos y Condiciones</a>, la <a href="#privacy" onClick={(e) => { e.preventDefault(); setLegalModal('privacy'); }}>Política de Privacidad</a>, la Política de Contenido, la Política +18 y la Política de Seguridad, incluidas las condiciones para publicar contenido (<a href="politicas.html" target="_blank" rel="noopener">ver todas las políticas</a>). <span style={{ color: 'var(--pink-deep)' }}>*</span>
              </span>
            </label>
          )}
        </FormPanel>
      </div>
      <LegalModal open={legalModal !== null} kind={legalModal} onClose={() => setLegalModal(null)} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 1b · Verificar email — pantalla intermedia entre crear cuenta y perfil.
// No existía ningún concepto de verificación de email: register() dejaba
// autenticado de inmediato. Se agrega la pantalla y el bloqueo de "Continuar"
// hasta confirmar, pero el login NO depende de esto (ver auth.service.ts) —
// así nadie queda sin poder entrar si el correo no llegó.
// ─────────────────────────────────────────────────────────────
function VerifyEmailStep({ data, tokenFromLink, onVerified, onBack }) {
  const [checking, setChecking] = useState(false);
  const [resent, setResent] = useState(false);
  const [notYet, setNotYet] = useState(false);
  const [error, setError] = useState('');
  const [linkResult, setLinkResult] = useState(null); // 'ok' | 'error' | null — solo si vinimos de un link de email

  // Si la pantalla se abrió desde el link del correo (#verificar?token=…),
  // confirmamos ese token de una — no requiere sesión activa (puede ser un
  // navegador distinto al que hizo el registro), así que no dependemos de
  // "Ya verifiqué mi correo" (eso sí necesita sesión, vía /auth/me).
  useEffect(() => {
    if (!tokenFromLink) return;
    (async () => {
      try {
        await window.GATITAS_API.verifyEmail(tokenFromLink);
        setLinkResult('ok');
        if (window.GATITAS_API.isLoggedIn()) onVerified();
      } catch (e) {
        setLinkResult('error');
      }
    })();
  }, [tokenFromLink]);

  async function checkNow() {
    setChecking(true);
    setNotYet(false);
    setError('');
    try {
      const me = await window.GATITAS_API.me();
      if (me.emailVerified) onVerified();
      else setNotYet(true);
    } catch (e) {
      setError('No pudimos comprobar tu verificación. Probá de nuevo.');
    } finally {
      setChecking(false);
    }
  }

  async function resend() {
    setResent(false);
    try {
      await window.GATITAS_API.resendVerification(data.email);
      setResent(true);
    } catch (e) {
      setError('No pudimos reenviar el correo. Probá de nuevo en un momento.');
    }
  }

  return (
    <div className="app">
      <div className="split">
        <BrandPanel
          bg="var(--blue-soft)" accent="var(--pink-deep)"
          hideAuthor smallQuote
          brandHref="explorar.html"
          quote="Ya casi — solo falta confirmar tu correo"
        />
        <FormPanel
          stepIndex={1}
          title="Verificá tu correo electrónico"
          subtitle={<>Enviamos un correo de verificación a <b>{data.email}</b>. Revisá tu bandeja de entrada (y spam) y confirmá tu dirección para continuar.</>}
          onBack={onBack}
          footerRight={
            !(linkResult === 'ok' && !window.GATITAS_API.isLoggedIn()) && (
              <button className="btn primary" disabled={checking} onClick={checkNow}>
                {checking ? 'Comprobando…' : 'Ya verifiqué mi correo'}
              </button>
            )
          }
        >
          {linkResult === 'ok' && !window.GATITAS_API.isLoggedIn() && (
            <>
              <div className="auth-notice">Tu correo quedó verificado. Iniciá sesión para continuar con tu perfil.</div>
              <a className="btn primary full" href="#login">Iniciar sesión</a>
            </>
          )}
          {linkResult === 'error' && (
            <div className="auth-notice">Ese enlace no es válido o ya venció. Pedí uno nuevo con "Reenviar correo".</div>
          )}
          {notYet && (
            <div className="auth-notice">Todavía no vemos tu correo confirmado. Si ya hiciste click en el link, esperá unos segundos y volvé a intentar.</div>
          )}
          {error && (
            <div style={{ padding: 12, borderRadius: 12, background: 'var(--pink-soft)', color: 'var(--ink)', fontSize: 13, fontWeight: 500 }}>{error}</div>
          )}
          <button type="button" className="btn ghost full" onClick={resend}>Reenviar correo</button>
          {resent && <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>Te reenviamos el correo de verificación.</div>}
        </FormPanel>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 1c · Recuperar contraseña — no existía ningún flujo, ni siquiera el link
// era funcional. Mismo criterio de no-enumeración que el backend: el mensaje
// es igual exista o no la cuenta.
// ─────────────────────────────────────────────────────────────
function ForgotPasswordStep({ onBack }) {
  const [email, setEmail] = useState('');
  const [loading, setLoading] = useState(false);
  const [sent, setSent] = useState(false);
  const valid = /\S+@\S+\.\S+/.test(email);

  async function submit() {
    if (!valid || loading) return;
    setLoading(true);
    try {
      await window.GATITAS_API.forgotPassword(email);
    } catch (e) { /* respuesta genérica igual — no delatamos errores acá */ }
    finally {
      setLoading(false);
      setSent(true);
    }
  }

  return (
    <div className="app">
      <div className="split">
        <BrandPanel bg="var(--pink-soft)" accent="var(--blue-deep)" hideAuthor smallQuote brandHref="explorar.html" quote="Te ayudamos a volver a entrar" />
        <FormPanel
          stepIndex={0}
          title="Recuperar contraseña"
          subtitle="Ingresá el email de tu cuenta y te mandamos un enlace para elegir una contraseña nueva."
          onBack={onBack}
          footerRight={
            !sent && <button className="btn primary" disabled={!valid || loading} onClick={submit}>{loading ? 'Enviando…' : 'Enviar enlace'}</button>
          }
        >
          {sent ? (
            <div className="auth-notice">Si ese correo tiene una cuenta, te enviamos un enlace para restablecer la contraseña. Revisá tu bandeja de entrada.</div>
          ) : (
            <div className="field">
              <label htmlFor="fp-email">Correo electrónico</label>
              <div className="input">
                <input id="fp-email" type="email" autoComplete="email" placeholder="tu@correo.com" value={email} onChange={e => setEmail(e.target.value)} />
              </div>
            </div>
          )}
        </FormPanel>
      </div>
    </div>
  );
}

function ResetPasswordStep({ token, onDone, onBack }) {
  const [showPw, setShowPw] = useState(false);
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [done, setDone] = useState(false);
  const valid = password.length >= 10 && password === confirmPassword;

  async function submit() {
    if (!valid || loading) return;
    setLoading(true);
    setError('');
    try {
      await window.GATITAS_API.resetPassword(token, password);
      setDone(true);
    } catch (e) {
      setError(e.message || 'El enlace no es válido o ya venció. Pedí uno nuevo.');
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="app">
      <div className="split">
        <BrandPanel bg="var(--blue-soft)" accent="var(--pink-deep)" hideAuthor smallQuote brandHref="explorar.html" quote="Elegí una contraseña nueva" />
        <FormPanel
          stepIndex={0}
          title="Elegí una contraseña nueva"
          onBack={onBack}
          footerRight={
            !done && <button className="btn primary" disabled={!valid || loading} onClick={submit}>{loading ? 'Guardando…' : 'Guardar contraseña'}</button>
          }
        >
          {done ? (
            <>
              <div className="auth-notice">Listo — tu contraseña se actualizó.</div>
              <button type="button" className="btn primary full" onClick={onDone}>Iniciar sesión</button>
            </>
          ) : (
            <>
              <div className="field">
                <label htmlFor="new-password">Contraseña nueva</label>
                <div className="input">
                  <input id="new-password" type={showPw ? 'text' : 'password'} autoComplete="new-password" placeholder="Mín. 10 caracteres"
                    value={password} onChange={e => setPassword(e.target.value)} />
                  <button className="trailing" type="button" onClick={() => setShowPw(s => !s)}>{showPw ? 'Ocultar' : 'Ver'}</button>
                </div>
              </div>
              <div className="field">
                <label htmlFor="confirm-new-password">Confirmar contraseña</label>
                <div className="input">
                  <input id="confirm-new-password" type={showPw ? 'text' : 'password'} autoComplete="new-password" placeholder="Repetí la contraseña"
                    value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} />
                </div>
                {confirmPassword && password !== confirmPassword && (
                  <div style={{ fontSize: 12, color: 'var(--pink-deep)', marginTop: 4 }}>Las contraseñas no coinciden.</div>
                )}
              </div>
              {error && (
                <div style={{ padding: 12, borderRadius: 12, background: 'var(--pink-soft)', color: 'var(--ink)', fontSize: 13, fontWeight: 500 }}>{error}</div>
              )}
            </>
          )}
        </FormPanel>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 1d · Ya tenés un perfil — sección 12: si "Iniciar prueba gratuita" (u otro
// punto de entrada) detecta cuenta + perfil ya creados, no se genera un
// perfil nuevo ni se repite el formulario — se ofrece administrar el
// existente.
// ─────────────────────────────────────────────────────────────
function AlreadyHasProfileScreen({ profile, dark, onToggleTheme }) {
  return (
    <div className="app">
      <div className="done">
        <div className="blob a" />
        <div className="blob b" />
        <Header onLogin={() => { location.href = 'vender.html'; }} loggedIn dark={dark} onToggleTheme={onToggleTheme} />
        <div className="body">
          <div className="card fade-in">
            <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: 1.2, textTransform: 'uppercase', color: '#7A7A7A' }}>
              Ya tenés un perfil registrado
            </div>
            <h1 style={{ margin: '4px 0 0', fontSize: 32 }}>Hola de nuevo, <i>{profile.displayName}</i></h1>
            <p style={{ marginTop: 12, fontSize: 14, color: 'var(--ink-2)' }}>
              No hace falta crear otro perfil — podés seguir administrando el que ya tenés.
            </p>
            <div className="actions">
              <button className="btn primary" onClick={() => { location.href = 'vender.html'; }}>Administrar mi perfil</button>
              <a className="btn ghost" href={'creador.html?slug=' + encodeURIComponent(profile.slug)}>Ver mi perfil público</a>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 2 · Perfil
// ─────────────────────────────────────────────────────────────
// Sin selector de rol "Comprador/Creador": visitantes no necesitan cuenta
// (ver dossier de cumplimiento, Sección 6), así que registrarse siempre crea
// una cuenta de anunciante. Tampoco hay carga de foto todavía — la API no
// tiene un endpoint de subida de media en esta fase; se agrega junto con la
// moderación de contenido (fase 3).
function ProfileStep({ data, setData, onBack, onNext }) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const valid = data.displayName.trim().length >= 2;

  // País/ciudad/barrio vienen del catálogo real en SQL (GET /locations/*),
  // no de un objeto JS estático — se cargan acá y en cascada, igual que en
  // el panel de Filtros (shared.js). Nunca texto libre (evita duplicados
  // tipo "Palermo"/"palermo"/"Palermo, CABA").
  const [countries, setCountries] = useState([]);
  const [cities, setCities] = useState([]);
  const [neighborhoods, setNeighborhoods] = useState([]);

  useEffect(() => {
    window.GATITAS_LOCATIONS_API?.getCountries({ onlyPublished: false })
      .then(setCountries).catch(() => setCountries([]));
  }, []);
  useEffect(() => {
    if (!data.countryId) { setCities([]); return; }
    window.GATITAS_LOCATIONS_API?.getCities({ countryId: data.countryId, onlyPublished: false })
      .then(setCities).catch(() => setCities([]));
  }, [data.countryId]);
  useEffect(() => {
    if (!data.cityId) { setNeighborhoods([]); return; }
    window.GATITAS_LOCATIONS_API?.getNeighborhoods({ cityId: data.cityId, onlyPublished: false })
      .then(setNeighborhoods).catch(() => setNeighborhoods([]));
  }, [data.cityId]);

  async function submit() {
    if (!valid || loading) return;
    setError('');
    setLoading(true);
    try {
      await window.GATITAS_API.createProfile({
        displayName: data.displayName.trim(),
        countryId: data.countryId || undefined,
        cityId: data.cityId || undefined,
        neighborhoodId: data.neighborhoodId || undefined,
        nationality: data.nationality || undefined,
        serviceType: data.serviceType || undefined,
        bio: data.bio.trim() || undefined,
        publicContact: data.publicContact.trim() || undefined,
      });
      // Espejo liviano en localStorage, solo para que el header de las
      // páginas estáticas (shared.js) sepa mostrar la sesión — la sesión
      // real vive en el access token en memoria + la cookie de refresh.
      window.GATITAS?.setUser?.({
        name: data.displayName.trim(),
        email: data.email,
        photo: null,
        createdAt: Date.now(),
      });
      // "Publicá con nosotros" guarda esta marca antes de mandar a un
      // usuario sin cuenta a registrarse — si está, retomamos la
      // contratación de PRO Max en vez de mostrar la pantalla normal de
      // "listo". No se toca nada más del flujo de registro para esto.
      let pendingPlan = null;
      try { pendingPlan = sessionStorage.getItem('gatitas-pending-plan'); } catch (e) {}
      if (pendingPlan === 'PRO_MAX') {
        try { sessionStorage.removeItem('gatitas-pending-plan'); } catch (e) {}
        location.href = 'precios.html?resume=1';
        return;
      }
      onNext();
    } catch (e) {
      setError(e.message || 'No pudimos crear tu perfil. Probá de nuevo.');
    } finally {
      setLoading(false);
    }
  }

  return (
    <div className="app">
      <div className="split">
        <BrandPanel
          bg="var(--pink-soft)" accent="var(--blue-deep)"
          hideAuthor smallQuote
          brandHref="explorar.html"
          quote="Atrevé siempre a un poco más"
        />
        <FormPanel
          stepIndex={2}
          title="Creá tu perfil"
          subtitle="Esto es lo que van a ver los visitantes del directorio. Podés editarlo después."
          onBack={onBack}
          footerLeft="El perfil queda en borrador hasta que verifiques tu identidad."
          footerRight={
            <button className="btn primary" disabled={!valid || loading} onClick={submit}>
              {loading ? 'Creando perfil…' : 'Continuar'}
            </button>
          }
        >
          <div className="field">
            <label htmlFor="displayName">Nombre público</label>
            <div className="input">
              <input id="displayName" type="text" autoComplete="name" placeholder="Como querés que te vean"
                value={data.displayName} onChange={e => setData({ ...data, displayName: e.target.value })} />
            </div>
          </div>

          <div className="field-row">
            <div className="field">
              <label htmlFor="country">País</label>
              <select id="country" value={data.countryId}
                onChange={e => setData({ ...data, countryId: e.target.value, cityId: '', neighborhoodId: '' })}>
                <option value="">Elegí un país</option>
                {countries.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>
            <div className="field">
              <label htmlFor="cityGeneral">Ciudad / zona</label>
              <select id="cityGeneral" value={data.cityId} disabled={!data.countryId}
                onChange={e => setData({ ...data, cityId: e.target.value, neighborhoodId: '' })}>
                <option value="">{data.countryId ? 'Elegí una ciudad' : 'Elegí primero un país'}</option>
                {cities.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>
          </div>

          <div className="field-row">
            <div className="field">
              <label htmlFor="neighborhood">Barrio</label>
              <select id="neighborhood" value={data.neighborhoodId} disabled={!data.cityId}
                onChange={e => setData({ ...data, neighborhoodId: e.target.value })}>
                <option value="">{data.cityId ? 'Elegí un barrio' : 'Elegí primero una ciudad'}</option>
                {neighborhoods.map(n => <option key={n.id} value={n.id}>{n.name}</option>)}
              </select>
            </div>
            <div className="field">
              <label htmlFor="nationality">Nacionalidad</label>
              <select id="nationality" value={data.nationality} onChange={e => setData({ ...data, nationality: e.target.value })}>
                <option value="">Elegí una nacionalidad</option>
                {(window.GATITAS_NATIONALITIES || []).map(n => <option key={n} value={n}>{n}</option>)}
              </select>
            </div>
          </div>

          <div className="field">
            <label htmlFor="serviceType">Tipo de servicio</label>
            <select id="serviceType" value={data.serviceType} onChange={e => setData({ ...data, serviceType: e.target.value })}>
              <option value="">Preferís no decirlo por ahora</option>
              <option value="PRESENCIAL">Presencial</option>
              <option value="VIRTUAL">Virtual</option>
              <option value="AMBOS">Ambos</option>
            </select>
          </div>

          <div className="field">
            <label htmlFor="bio">Sobre vos</label>
            <div className="input">
              <textarea id="bio" rows={3} placeholder="Una breve presentación"
                value={data.bio} onChange={e => setData({ ...data, bio: e.target.value })} />
            </div>
          </div>

          <div className="field">
            <label htmlFor="publicContact">Contacto público (WhatsApp)</label>
            <div className="input">
              <input id="publicContact" type="text" placeholder="Ej. +54 9 11 1234-5678"
                value={data.publicContact} onChange={e => setData({ ...data, publicContact: e.target.value })} />
            </div>
            <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 4 }}>
              Es el único dato de contacto que vamos a mostrar públicamente. Nada más de tu
              verificación (documento, dirección real) aparece jamás en tu perfil.
            </div>
          </div>

          {error && (
            <div style={{
              padding: 12, borderRadius: 12, background: 'var(--pink-soft)',
              color: 'var(--ink)', fontSize: 13, fontWeight: 500,
            }}>{error}</div>
          )}
        </FormPanel>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// 3 · Listo (cuenta + perfil creados, a la espera de revisión del admin)
// ─────────────────────────────────────────────────────────────
function DoneScreen({ data, onGoToPanel, dark, onToggleTheme }) {
  const firstName = (data.displayName.trim() || 'ahí').split(/\s+/)[0];
  const initials = (data.displayName.trim() || 'TÚ').split(/\s+/).map(p => p[0]).slice(0, 2).join('').toUpperCase();

  return (
    <div className="app">
      <div className="done">
        <div className="blob a" />
        <div className="blob b" />
        <Header onLogin={onGoToPanel} loggedIn dark={dark} onToggleTheme={onToggleTheme} />
        <div className="body">
          <div className="card fade-in">
            <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
              <div style={{
                width: 72, height: 72, borderRadius: '50%',
                background: 'linear-gradient(135deg, #FBD7DC, #E3F0FA)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'var(--font-primary)', fontSize: 27, fontWeight: 500, color: '#0A0A0A',
              }}>{initials}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: 1.2, textTransform: 'uppercase', color: '#7A7A7A' }}>
                  ¡Perfil creado!
                </div>
                <h1 style={{ margin: '4px 0 0', fontSize: 32 }}>Hola, <i>{firstName}</i></h1>
              </div>
            </div>

            <div style={{
              marginTop: 18, padding: 16, borderRadius: 14,
              background: 'var(--pink-soft)', border: '1px dashed #F5B6C0',
              display: 'flex', alignItems: 'center', gap: 14,
            }}>
              <div style={{
                width: 44, height: 44, borderRadius: 12, background: 'var(--surface)',
                display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
              }}>
                <svg width="22" height="22" viewBox="0 0 24 24">
                  <path d="M12 2l2.9 5.9 6.5.9-4.7 4.6 1.1 6.5L12 16.9 6.2 19.9l1.1-6.5L2.6 8.8l6.5-.9L12 2z" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinejoin="round"/>
                </svg>
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 14, fontWeight: 600, color: '#0A0A0A' }}>
                  Tu perfil está en revisión
                </div>
                <div style={{ fontSize: 13, color: '#3D3D3D' }}>
                  Nadie lo ve todavía. Nuestro equipo revisa cada perfil antes de publicarlo — te avisamos por email.
                </div>
              </div>
            </div>

            <div className="next-list">
              <div className="next-item primary">
                <div className="next-num">1</div>
                <div style={{ flex: 1 }}>
                  <div className="t">Revisión del equipo</div>
                  <div className="d">Un administrador revisa tus datos y tus fotos antes de publicar</div>
                </div>
                <svg width="14" height="14" viewBox="0 0 14 14"><path d="M5 1l6 6-6 6" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </div>
            </div>

            <div className="actions">
              <button className="btn primary" onClick={onGoToPanel}>Ir a mi panel</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Router por hash (#bienvenida, #registro, #login, #verificar, #olvide,
// #restablecer, #perfil, #perfil-existente, #listo)
// El route puede traer query propia, ej. "#verificar?token=…" — se separa
// acá para no mezclar el parseo en cada pantalla.
// ─────────────────────────────────────────────────────────────
const ROUTES = [
  'bienvenida', 'registro', 'login', 'verificar', 'olvide', 'restablecer',
  'perfil', 'perfil-existente', 'listo',
];

function useHashRoute() {
  function parse() {
    const raw = location.hash.replace('#', '') || 'bienvenida';
    const [name, qs] = raw.split('?');
    return { name, params: new URLSearchParams(qs || '') };
  }
  const [state, setState] = useState(parse);
  useEffect(() => {
    const onHash = () => setState(parse());
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  const go = (r) => { location.hash = '#' + r; window.scrollTo({ top: 0 }); };
  return [state.name, state.params, go];
}

// ─────────────────────────────────────────────────────────────
// App
// ─────────────────────────────────────────────────────────────
function App() {
  const [route, routeParams, go] = useHashRoute();
  const [dark, toggleTheme] = useDarkMode();
  const [data, setData] = useState({
    email: '', password: '', confirmPassword: '', accept: false,
    displayName: '', countryId: '', cityId: '', neighborhoodId: '',
    nationality: '', serviceType: '', bio: '', publicContact: '',
  });
  const [sessionChecked, setSessionChecked] = useState(false);
  const [ownProfile, setOwnProfile] = useState(null);

  // Al cargar la SPA intentamos renovar el access token con la cookie de
  // refresh y, si hay sesión, volvemos a pedir el perfil propio — nunca
  // confiamos solo en el estado en memoria (se pierde con una recarga).
  useEffect(() => {
    window.GATITAS_API.initSession()
      .then((hasSession) => hasSession ? window.GATITAS_API.getOwnProfile() : null)
      .then((profile) => setOwnProfile(profile))
      .catch(() => {})
      .finally(() => setSessionChecked(true));
  }, []);

  // Después de un login o de crear cuenta+verificar, decide a dónde seguir
  // sin volver a mostrar pasos ya hechos ni crear un segundo perfil:
  //  - si veníamos de "Iniciar prueba gratuita" (gatitas-pending-plan),
  //    volvemos ahí directo, con o sin perfil ya creado;
  //  - si ya tiene perfil, se le avisa en vez de mandarlo de nuevo al form;
  //  - si no tiene perfil, recién ahí entra a crearlo.
  function continueAfterAuth(profile) {
    let pendingPlan = null;
    try { pendingPlan = sessionStorage.getItem('gatitas-pending-plan'); } catch (e) {}
    if (pendingPlan === 'PRO_MAX') {
      try { sessionStorage.removeItem('gatitas-pending-plan'); } catch (e) {}
      location.href = 'precios.html?resume=1';
      return;
    }
    if (profile) {
      setOwnProfile(profile);
      go('perfil-existente');
    } else {
      go('perfil');
    }
  }

  // Sección 33 del pedido de RBAC: el backend determina el rol, el frontend
  // solo redirige según lo que ya vino en /auth/me — nunca al revés. Un rol
  // ADMIN o USER ni siquiera intenta entrar al wizard de creadoras de acá
  // abajo (ese wizard es exclusivamente para advertiser).
  function safeReturnUrl() {
    let path = null;
    try { path = sessionStorage.getItem('gatitas-return-url'); sessionStorage.removeItem('gatitas-return-url'); } catch (e) {}
    // Nunca un redirect externo: se descarta cualquier valor que no sea una
    // ruta relativa simple del propio sitio (defensa en profundidad, aunque
    // sessionStorage ya es same-origin).
    if (!path || /^\/\/|:\/\//.test(path)) return 'explorar.html';
    return path;
  }

  async function handleLoggedIn() {
    // El LOGIN nunca exige email verificado (pedido de RBAC, sección 1/39):
    // si el email y la contraseña son correctos y la cuenta está habilitada,
    // entra directo. La pantalla "Verificá tu correo" sigue existiendo, pero
    // solo como paso posterior a CREAR una cuenta nueva (onRegistered más
    // abajo) — nunca como un gate que bloquee un login normal.
    let me = null;
    try { me = await window.GATITAS_API.me(); } catch (e) { /* seguimos igual al flujo normal si /auth/me falla */ }

    if (me && me.role === 'admin') { location.href = 'admin.html'; return; }
    if (me && me.role === 'user') { location.href = safeReturnUrl(); return; }

    let profile = null;
    try { profile = await window.GATITAS_API.getOwnProfile(); } catch (e) { /* 404 = sin perfil todavía */ }
    continueAfterAuth(profile);
  }

  if (!ROUTES.includes(route)) return <Welcome onStart={() => go('registro')} onLogin={() => go('login')} />;

  let screen;
  switch (route) {
    case 'bienvenida':
      screen = <Welcome onStart={() => go('registro')} onLogin={() => go('login')} dark={dark} onToggleTheme={toggleTheme} />;
      break;
    case 'registro':
      screen = <AuthStep data={data} setData={setData} initialMode="signup"
        onBack={() => go('bienvenida')} onRegistered={() => go('verificar')} onLoggedIn={handleLoggedIn} />;
      break;
    case 'login':
      screen = <AuthStep data={data} setData={setData} initialMode="login"
        onBack={() => go('bienvenida')} onRegistered={() => go('verificar')} onLoggedIn={handleLoggedIn} />;
      break;
    case 'verificar':
      screen = <VerifyEmailStep data={data} tokenFromLink={routeParams.get('token')}
        onBack={() => go('registro')} onVerified={() => go('perfil')} />;
      break;
    case 'olvide':
      screen = <ForgotPasswordStep onBack={() => go('login')} />;
      break;
    case 'restablecer':
      screen = <ResetPasswordStep token={routeParams.get('token')}
        onDone={() => go('login')} onBack={() => go('login')} />;
      break;
    case 'perfil':
      screen = <ProfileStep data={data} setData={setData}
        onBack={() => go('registro')} onNext={() => go('listo')} />;
      break;
    case 'perfil-existente':
      screen = ownProfile
        ? <AlreadyHasProfileScreen profile={ownProfile} dark={dark} onToggleTheme={toggleTheme} />
        : null;
      break;
    case 'listo':
      screen = <DoneScreen data={data}
        onGoToPanel={() => { location.href = 'vender.html'; }}
        dark={dark} onToggleTheme={toggleTheme} />;
      break;
    default:
      screen = null;
  }

  return screen;
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
