/* app/assets/tokens.css — sistema de diseño de la interfaz nueva de Fyno AI (Fase 16, renovación
   visual premium). Aislado a propósito de index.html/admin.html: nada de aquí se importa desde ellos,
   y nada de aquí toca backend. Dark-first: la bare :root define directamente la paleta oscura (el tema
   PRINCIPAL de Fyno AI, no una alternativa de prefers-color-scheme); claro es una alternativa completa,
   diseñada de cero (no una simple inversión), activable por el sistema operativo O explícitamente vía
   [data-theme] (ver shell.js, initTema()) — nunca depende solo de la señal del SO.

   NOTA DE COMPATIBILIDAD: todos los nombres de token ya existentes (--bg, --bg-raised, --accent,
   --radius-md, --sp-4...) se CONSERVAN — los usan tanto shell.js como el <style> propio de cada
   página. Esta ronda evoluciona sus VALORES y AÑADE una capa nueva de tokens (superficies extra,
   acentos secundarios, glass, glow, movimiento) — nunca elimina ni renombra los que ya existían.
   ============================================================================================ */

:root{
  /* --- oscuro (por defecto): navy/negro con profundidad real, nunca negro plano --- */
  --bg:#07080c; --bg-raised:#12141c; --bg-sunken:#040509;
  /* superficies nuevas: --surface-2 es el "cristal" de navegación (topbar/bottomnav/dropdowns),
     --surface-hover el estado hover/activo de una superficie ya elevada — antes todo compartía
     --bg-raised sin más matices de profundidad. */
  --surface-2:#14161f; --surface-hover:#1b1e2a;
  --ink:#f4f5f8; --ink-soft:#9fa5b5; --ink-faint:#7a8094;
  --border:rgba(255,255,255,.09); --border-soft:rgba(255,255,255,.05); --border-strong:rgba(255,255,255,.16);
  /* --accent: fondos/CTA/elementos grandes. --accent-text: enlaces/texto pequeño — variante con
     contraste 4.5:1 verificado en claro (ver M del blueprint); en oscuro son valores cercanos porque
     --accent ya cumple contraste alto sobre --bg. Nunca usar --accent como color de texto pequeño en
     claro. --accent-2/--magenta/--violet/--blue: acentos secundarios — SOLO para gradientes, halos y
     detalles puntuales (glow de hero, líneas de conexión, iconos) — nunca sustituyen a --accent como
     color de marca/CTA principal. */
  --accent:#ff5a2c; --accent-2:#ff8f42; --accent-ink:#1a0700; --accent-soft:rgba(255,90,44,.15); --accent-text:#ff7c46;
  --magenta:#ec4899; --violet:#8b6cf6; --blue:#3fb2ff;
  --ok:#34d399; --ok-soft:rgba(52,211,153,.14); --warn:#fbbf24; --warn-soft:rgba(251,191,36,.14); --danger:#f87171; --danger-soft:rgba(248,113,113,.14);
  --shadow:0 1px 2px rgba(0,0,0,.45), 0 8px 24px -12px rgba(0,0,0,.55);
  --shadow-lg:0 4px 10px rgba(0,0,0,.45), 0 28px 64px -20px rgba(0,0,0,.65);
  /* glow: sombra de acento para botones/cards premium al hover/foco — sutil por defecto, se intensifica
     en :hover de cada componente (ver .btn-primary, .card-interactive más abajo), nunca ambas a la vez
     con --shadow-lg (son alternativas, no se suman). */
  --shadow-glow:0 0 0 1px rgba(255,90,44,.18), 0 8px 32px -8px rgba(255,90,44,.38);

  /* glass: navbar/dropdowns/pills — SIEMPRE con --glass-border a juego, nunca "cristal" sin borde. */
  --glass-bg:rgba(13,15,21,.72); --glass-border:rgba(255,255,255,.08); --glass-blur:18px;

  --radius-sm:8px; --radius-md:14px; --radius-lg:20px; --radius-xl:28px; --radius-pill:999px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px; --sp-7:48px; --sp-8:64px;

  --font-display:"Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --font-body:"IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono:"IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* movimiento: una única escala de easing/duración para toda la app — microinteracciones rápidas y
     coherentes (nunca animaciones lentas/vistosas). Ver @media (prefers-reduced-motion) al final. */
  --ease:cubic-bezier(.16,1,.3,1); --dur-1:110ms; --dur-2:190ms; --dur-3:340ms;

  --topbar-h:64px;         /* alto de la barra superior — reservado por #shell-topbar (sticky), no por <body> */
  --bottomnav-h:68px;      /* alto de la barra inferior móvil (Dashboard/Mis Shorts únicamente) */
  --tap-min:44px;          /* objetivo táctil mínimo — nunca se reduce para ahorrar espacio */
}

/* claro — alternativa completa DISEÑADA, no una inversión del oscuro: blanco roto cálido, sombras
   suaves con tinte cálido, mismo naranja de marca, glass claro. */
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]){
    --bg:#f8f6f2; --bg-raised:#ffffff; --bg-sunken:#efece4;
    --surface-2:#ffffff; --surface-hover:#f3f0ea;
    --ink:#1b1813; --ink-soft:#5f5a4f; --ink-faint:#726c5e;
    --border:rgba(28,20,8,.10); --border-soft:rgba(28,20,8,.06); --border-strong:rgba(28,20,8,.18);
    --accent:#e35a10; --accent-2:#ff8a3d; --accent-ink:#fff8f2; --accent-soft:rgba(227,90,16,.10); --accent-text:#bc4308;
    --magenta:#c22a72; --violet:#6d3fd1; --blue:#0f74c9;
    --ok:#1f8a4c; --ok-soft:rgba(31,138,76,.10); --warn:#a3660a; --warn-soft:rgba(163,102,10,.10); --danger:#c23a2e; --danger-soft:rgba(194,58,46,.10);
    --shadow:0 1px 2px rgba(35,25,10,.05), 0 8px 22px -12px rgba(35,25,10,.10);
    --shadow-lg:0 4px 10px rgba(35,25,10,.05), 0 26px 56px -18px rgba(35,25,10,.16);
    --shadow-glow:0 0 0 1px rgba(227,90,16,.16), 0 8px 26px -8px rgba(227,90,16,.24);
    --glass-bg:rgba(255,255,255,.72); --glass-border:rgba(28,20,8,.07); --glass-blur:18px;
  }
}
:root[data-theme="light"]{
  --bg:#f8f6f2; --bg-raised:#ffffff; --bg-sunken:#efece4;
  --surface-2:#ffffff; --surface-hover:#f3f0ea;
  --ink:#1b1813; --ink-soft:#5f5a4f; --ink-faint:#726c5e;
  --border:rgba(28,20,8,.10); --border-soft:rgba(28,20,8,.06); --border-strong:rgba(28,20,8,.18);
  --accent:#e35a10; --accent-2:#ff8a3d; --accent-ink:#fff8f2; --accent-soft:rgba(227,90,16,.10); --accent-text:#bc4308;
  --magenta:#c22a72; --violet:#6d3fd1; --blue:#0f74c9;
  --ok:#1f8a4c; --ok-soft:rgba(31,138,76,.10); --warn:#a3660a; --warn-soft:rgba(163,102,10,.10); --danger:#c23a2e; --danger-soft:rgba(194,58,46,.10);
  --shadow:0 1px 2px rgba(35,25,10,.05), 0 8px 22px -12px rgba(35,25,10,.10);
  --shadow-lg:0 4px 10px rgba(35,25,10,.05), 0 26px 56px -18px rgba(35,25,10,.16);
  --shadow-glow:0 0 0 1px rgba(227,90,16,.16), 0 8px 26px -8px rgba(227,90,16,.24);
  --glass-bg:rgba(255,255,255,.72); --glass-border:rgba(28,20,8,.07); --glass-blur:18px;
}
:root[data-theme="dark"]{
  --bg:#07080c; --bg-raised:#12141c; --bg-sunken:#040509;
  --surface-2:#14161f; --surface-hover:#1b1e2a;
  --ink:#f4f5f8; --ink-soft:#9fa5b5; --ink-faint:#7a8094;
  --border:rgba(255,255,255,.09); --border-soft:rgba(255,255,255,.05); --border-strong:rgba(255,255,255,.16);
  --accent:#ff5a2c; --accent-2:#ff8f42; --accent-ink:#1a0700; --accent-soft:rgba(255,90,44,.15); --accent-text:#ff7c46;
  --magenta:#ec4899; --violet:#8b6cf6; --blue:#3fb2ff;
  --ok:#34d399; --ok-soft:rgba(52,211,153,.14); --warn:#fbbf24; --warn-soft:rgba(251,191,36,.14); --danger:#f87171; --danger-soft:rgba(248,113,113,.14);
  --shadow:0 1px 2px rgba(0,0,0,.45), 0 8px 24px -12px rgba(0,0,0,.55);
  --shadow-lg:0 4px 10px rgba(0,0,0,.45), 0 28px 64px -20px rgba(0,0,0,.65);
  --shadow-glow:0 0 0 1px rgba(255,90,44,.18), 0 8px 32px -8px rgba(255,90,44,.38);
  --glass-bg:rgba(13,15,21,.72); --glass-border:rgba(255,255,255,.08); --glass-blur:18px;
}

/* transición de tema: solo colores/sombras, nunca layout — instantánea en el resto (F del blueprint de
   movimiento: microinteracciones rápidas, nunca un cross-fade largo de toda la pantalla). */
html{ transition:background-color var(--dur-2) var(--ease); }
body, #shell-topbar, #shell-bottomnav, .card, .panel, .btn, .field input, .field select, .field textarea{
  transition:background-color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}

/* ============================================================================================
   RESET + BASE
   ============================================================================================ */
*, *::before, *::after{ box-sizing:border-box; }
/* RONDA de pequeños ajustes — BUG REAL corregido: sin esto, tocar cualquier elemento en Chrome/Safari
   móvil pintaba el highlight táctil nativo (un rectángulo azul translúcido, SIEMPRE rectangular —
   ignora border-radius por completo, es un efecto del navegador, no de esta hoja de estilos) encima de
   cualquier botón/enlace, con forma distinta a la del propio botón. Se sustituye por los estados
   :hover/:active/:focus-visible ya definidos por componente (transform+brightness en .btn, etc.) —
   nunca se deja un toque sin ningún feedback visual, solo se retira el del navegador que no encajaba
   con el diseño. */
html{ -webkit-text-size-adjust:100%; -webkit-tap-highlight-color:transparent; }
body{
  margin:0; background:var(--bg); color:var(--ink); font-family:var(--font-body);
  line-height:1.5; font-size:16px; -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{ font-family:var(--font-display); font-weight:700; line-height:1.12; letter-spacing:-0.01em; text-wrap:balance; margin:0; color:var(--ink); }
p{ margin:0 0 var(--sp-3); color:var(--ink); }
a{ color:var(--accent-text); }
small,.small{ font-size:13px; color:var(--ink-soft); }
code,.mono{ font-family:var(--font-mono); }
img,video{ max-width:100%; display:block; }
button{ font-family:inherit; }

/* foco visible en TODO — nunca outline:none sin sustituto (M del blueprint). border-radius:4px
   ELIMINADO (RONDA de pequeños ajustes, BUG REAL): esa línea forzaba un radio de 4px sobre CUALQUIER
   elemento enfocado, aunque su forma real fuera otra (un botón .btn-primary con radio pill, un icono
   circular...) — el rectángulo de foco no coincidía con la forma del propio control. outline SIN
   border-radius propio ya sigue automáticamente las esquinas redondeadas reales del elemento que
   rodea (comportamiento estándar de Chrome/Firefox/Safari desde hace años) — nunca hace falta forzar
   un valor fijo aquí. Solo afecta a foco de TECLADO (:focus-visible) — el highlight táctil nativo de
   tocar en móvil es un mecanismo distinto, corregido arriba (-webkit-tap-highlight-color). */
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.visually-hidden{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }

/* PULIDO RESPONSIVE (revisión post-primera-prueba móvil): el atributo hidden tiene la MISMA
   especificidad que una clase (.cargar-mas{display:flex}, .cuenta-row{display:flex}...) — sin este
   !important, cualquier componente que fije su propio "display" en la hoja de estilos del autor GANA
   sobre [hidden] del navegador, y el elemento se ve aunque hidden=true (bug real detectado en
   #cargar-mas de Mis Shorts y #fila-verificacion de Cuenta). Regla global, una sola vez, nunca hay
   que acordarse de añadir un override por componente. */
[hidden]{ display:none !important; }

.skip-link{
  position:absolute; left:var(--sp-3); top:-100px; z-index:200; background:var(--accent); color:var(--accent-ink);
  padding:10px 16px; border-radius:var(--radius-sm); font-weight:600; text-decoration:none; transition:top .15s ease;
}
.skip-link:focus{ top:var(--sp-3); }

.container{ max-width:1180px; margin:0 auto; padding:0 var(--sp-5); }
@media (max-width:640px){ .container{ padding:0 var(--sp-4); } }

/* espacio inferior consistente del contenido principal de cada pantalla (respiro antes del final de
   la página / antes de la barra inferior móvil) — un único sitio, en vez de que cada página invente
   su propio padding-bottom suelto en su grid/lista. Selector "main.container" a propósito: solo
   afecta al contenedor de nivel superior de cada pantalla (uno por página), nunca a los .container
   repetidos dentro de <section> de la Landing. */
main.container{ padding-bottom:var(--sp-8); position:relative; z-index:1; }

/* ============================================================================================
   FONDO AMBIENTAL — halos difusos + ondas abstractas MUY transparentes, puramente CSS (sin imagen
   fija, sin vídeo) para que escale perfectamente en cualquier viewport. .ambient-bg es un contenedor
   fixed detrás de todo el contenido (z-index negativo, pointer-events:none) que cualquier página puede
   incluir una vez, justo tras <body>; sus 3 manchas (naranja/magenta/violeta) se posicionan por página
   con estilo inline o una clase de contexto (ver Landing/Dashboard). Movimiento opcional, extremadamente
   lento (--dur no se usa aquí a propósito: esto dura decenas de segundos, no cientos de ms) y siempre
   respeta prefers-reduced-motion (ver el final del archivo). En claro los halos son casi imperceptibles
   a propósito — profundidad sutil, nunca "manchas de color" sobre fondo blanco. */
.ambient-bg{ position:fixed; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.ambient-bg .blob{ position:absolute; border-radius:50%; filter:blur(70px); opacity:.35; will-change:transform; }
:root[data-theme="light"] .ambient-bg .blob{ opacity:.16; }
@media (prefers-color-scheme:light){ :root:not([data-theme="dark"]) .ambient-bg .blob{ opacity:.16; } }
.ambient-bg .blob-accent{ background:radial-gradient(circle at 30% 30%, var(--accent), transparent 70%); }
.ambient-bg .blob-magenta{ background:radial-gradient(circle at 30% 30%, var(--magenta), transparent 70%); }
.ambient-bg .blob-violet{ background:radial-gradient(circle at 30% 30%, var(--violet), transparent 70%); }
.ambient-bg .blob-blue{ background:radial-gradient(circle at 30% 30%, var(--blue), transparent 70%); }
@keyframes ambient-drift-1{ 0%,100%{ transform:translate(0,0) scale(1); } 50%{ transform:translate(3%,4%) scale(1.06); } }
@keyframes ambient-drift-2{ 0%,100%{ transform:translate(0,0) scale(1); } 50%{ transform:translate(-4%,-2%) scale(1.04); } }
.ambient-bg .blob{ animation:ambient-drift-1 34s ease-in-out infinite; }
.ambient-bg .blob:nth-child(2){ animation-name:ambient-drift-2; animation-duration:42s; }
.ambient-bg .blob:nth-child(3){ animation-duration:38s; }
/* líneas topográficas MUY sutiles (RONDA DE PERFECCIONAMIENTO: recuperadas de la referencia visual —
   curvas de nivel/"montañas" integradas en el fondo, nunca protagonistas) — un único SVG de trazo
   repetido vía background, no un elemento por línea (CSS/SVG puro, sin imagen de fondo pesada, según
   la prioridad de rendimiento pedida). Cada "curva de nivel" tiene su propia amplitud/fase para que no
   se lea como un patrón perfectamente repetitivo, más parecido a un mapa topográfico real. */
.ambient-bg .waves{
  position:absolute; inset:0; opacity:.09;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='700' viewBox='0 0 900 700'%3E%3Cg fill='none' stroke='white' stroke-width='1'%3E%3Cpath d='M-50 90 C 80 40, 160 140, 260 95 S 430 20, 520 80 S 690 150, 800 90 S 950 40, 1000 95'/%3E%3Cpath d='M-50 165 C 60 210, 190 120, 300 170 S 470 240, 560 175 S 720 100, 830 165 S 950 220, 1000 170'/%3E%3Cpath d='M-50 260 C 100 300, 220 220, 340 265 S 500 330, 610 260 S 760 190, 870 255 S 960 300, 1000 260' opacity='.7'/%3E%3Cpath d='M-50 370 C 90 320, 210 410, 330 365 S 490 300, 600 360 S 750 425, 860 370 S 950 330, 1000 365'/%3E%3Cpath d='M-50 470 C 70 510, 200 430, 320 475 S 480 540, 590 470 S 740 405, 850 465 S 950 505, 1000 470' opacity='.7'/%3E%3Cpath d='M-50 580 C 90 540, 220 620, 340 575 S 510 510, 620 570 S 770 630, 880 575 S 960 540, 1000 570'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat:repeat; background-size:900px 700px;
}
:root[data-theme="light"] .ambient-bg .waves{ opacity:.05; }
@media (prefers-color-scheme:light){ :root:not([data-theme="dark"]) .ambient-bg .waves{ opacity:.05; } }

/* ============================================================================================
   CABECERA DE PÁGINA — título (+ acción opcional a la derecha) con el mismo padding vertical en
   todas las pantallas autenticadas (antes: Mis Shorts/Créditos/Cuenta/Dashboard tenían cada una su
   propio valor de padding ligeramente distinto). Cada página solo pone su propio <h1>/subtítulo
   dentro; el saldo de créditos usa el componente .saldo-line de abajo, no texto suelto.
   ============================================================================================ */
.page-head{ padding:var(--sp-5) 0 var(--sp-4); display:flex; justify-content:space-between; align-items:flex-start; gap:var(--sp-4); flex-wrap:wrap; }
.page-head h1{ font-size:24px; margin-bottom:2px; }
.page-head p{ margin:0; color:var(--ink-soft); font-size:14px; }

/* ============================================================================================
   MENSAJE DE SALDO DE CRÉDITOS — píldora con su propio contorno, consistente con .credits-pill de la
   barra superior — mismo lenguaje visual para "esto es sobre tus créditos" se vea donde se vea.
   ============================================================================================ */
.saldo-line{
  display:inline-flex; align-items:center; gap:6px; background:var(--bg-raised); border:1px solid var(--border);
  border-radius:var(--radius-pill); padding:7px 16px; font-size:13.5px; color:var(--ink-soft);
  margin:var(--sp-2) 0 var(--sp-6); max-width:100%; box-sizing:border-box;
}
.saldo-line b{ color:var(--ink); font-family:var(--font-mono); font-weight:700; }

/* ============================================================================================
   BOTONES — min-height 44px real (no solo visual). Microinteracciones (F del blueprint de esta
   ronda): hover = leve escala + brillo + glow; active = leve reducción de escala (respuesta física).
   Todo con --dur-1 (~110ms) — instantáneo, nunca una animación que se note como tal.
   ============================================================================================ */
.btn{
  font-family:var(--font-body); font-size:14.5px; font-weight:600; padding:11px 20px; min-height:var(--tap-min);
  border-radius:var(--radius-sm); border:1px solid transparent; cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  transition:filter var(--dur-1) var(--ease), transform var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
  text-decoration:none; white-space:nowrap;
}
.btn:active{ transform:scale(.97); }
.btn-primary{ background:linear-gradient(135deg, var(--accent), var(--accent-2)); color:var(--accent-ink); box-shadow:0 1px 1px rgba(0,0,0,.15), 0 6px 20px -8px rgba(255,90,44,.55); }
.btn-primary:hover{ filter:brightness(1.07); transform:scale(1.02); box-shadow:var(--shadow-glow); }
.btn-primary:active{ transform:scale(.97); filter:brightness(1); }
.btn-secondary{ background:var(--bg-raised); color:var(--ink); border-color:var(--border); }
.btn-secondary:hover{ background:var(--surface-hover); border-color:var(--border-strong); transform:scale(1.015); }
.btn-ghost{ background:transparent; color:var(--ink-soft); }
.btn-ghost:hover{ color:var(--ink); background:var(--border-soft); }
.btn-danger{ background:transparent; color:var(--danger); border-color:color-mix(in srgb, var(--danger) 40%, var(--border)); }
.btn-danger:hover{ background:var(--danger-soft); }
.btn-block{ width:100%; }
.btn[disabled]{ opacity:.45; cursor:not-allowed; transform:none !important; filter:none !important; box-shadow:none !important; }
.btn .spinner{ width:15px; height:15px; flex:none; }
/* la flecha/carácter final de un botón (p.ej. "Crear mi primer Short →") se desplaza levemente al
   hover — un solo span opcional, .btn-arrow, envolviendo ese carácter; nunca obligatorio. */
.btn .btn-arrow{ display:inline-block; transition:transform var(--dur-1) var(--ease); }
.btn:hover .btn-arrow{ transform:translateX(3px); }

/* botón icono-solo (p.ej. cerrar un modal) — SIEMPRE 44×44 de área táctil aunque el icono sea menor */
.btn-icon{
  width:var(--tap-min); height:var(--tap-min); padding:0; border-radius:50%;
  background:transparent; border:none; color:var(--ink-soft); cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; flex:none;
  transition:background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.btn-icon:hover{ background:var(--border-soft); color:var(--ink); transform:scale(1.06); }
.btn-icon:active{ transform:scale(.94); }

/* ============================================================================================
   FORMULARIOS — foco con glow de acento + borde animado sutil; estados de error/éxito explícitos.
   ============================================================================================ */
.field{ display:flex; flex-direction:column; gap:6px; }
.field label{ font-size:13px; font-weight:600; color:var(--ink-soft); }
.field input, .field select, .field textarea{
  font-family:var(--font-body); font-size:15px; padding:12px 14px; min-height:var(--tap-min);
  border-radius:var(--radius-sm); border:1px solid var(--border); background:var(--bg-raised); color:var(--ink);
  width:100%; transition:border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease);
}
.field textarea{ min-height:88px; resize:vertical; }
.field input:hover, .field select:hover, .field textarea:hover{ border-color:var(--border-strong); }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible{
  outline:none; border-color:var(--accent); box-shadow:0 0 0 4px var(--accent-soft);
}
.field .help{ font-size:12.5px; color:var(--ink-faint); }
.field.err input, .field.err select, .field.err textarea{ border-color:var(--danger); box-shadow:0 0 0 4px var(--danger-soft); }
.field.err .help{ color:var(--danger); }
.field.ok input, .field.ok select, .field.ok textarea{ border-color:var(--ok); box-shadow:0 0 0 4px var(--ok-soft); }

/* ============================================================================================
   TARJETAS / PANELES — profundidad real (borde + sombra + fondo elevado). .card-interactive añade la
   microinteracción de hover "se levanta" (usar en tarjetas clicables: ejemplos, proyectos, planes) —
   nunca en tarjetas puramente informativas, para que "esto reacciona" siga significando "esto es
   interactivo" en toda la app (regla de calidad de interacción de esta ronda).
   ============================================================================================ */
.card{ background:var(--bg-raised); border:1px solid var(--border); border-radius:var(--radius-lg); padding:var(--sp-5); box-shadow:var(--shadow); }
.panel{ background:var(--bg-raised); border:1px solid var(--border); border-radius:var(--radius-lg); padding:var(--sp-5); }
.card-interactive{ transition:transform var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); cursor:pointer; }
.card-interactive:hover{ transform:translateY(-3px); border-color:var(--border-strong); box-shadow:var(--shadow-lg); }
.card-interactive:active{ transform:translateY(-1px) scale(.995); }

/* ============================================================================================
   GLASSMORPHISM — con moderación: navbar, pills de estado, pequeños controles flotantes. NUNCA la
   página entera; solo elementos "de chrome" que flotan sobre contenido.
   ============================================================================================ */
.glass{ background:var(--glass-bg); backdrop-filter:blur(var(--glass-blur)); -webkit-backdrop-filter:blur(var(--glass-blur)); border:1px solid var(--glass-border); }

/* ============================================================================================
   BADGES — semántico, siempre separado del acento de marca (K del blueprint)
   ============================================================================================ */
.badge{ display:inline-flex; align-items:center; gap:5px; padding:3px 10px; border-radius:var(--radius-pill); font-size:12px; font-weight:600; white-space:nowrap; }
.badge-ok{ background:var(--ok-soft); color:var(--ok); }
.badge-warn{ background:var(--warn-soft); color:var(--warn); }
.badge-danger{ background:var(--danger-soft); color:var(--danger); }
.badge-neutral{ background:var(--border-soft); color:var(--ink-soft); }
.badge-accent{ background:var(--accent-soft); color:var(--accent-text); }

/* ============================================================================================
   ESTADOS: skeleton (carga de contenido) — respeta prefers-reduced-motion
   ============================================================================================ */
.skeleton{ background:linear-gradient(90deg, var(--border-soft) 25%, var(--border) 37%, var(--border-soft) 63%); background-size:400% 100%; animation:sk-shimmer 1.4s ease infinite; border-radius:var(--radius-md); }
@keyframes sk-shimmer{ 0%{ background-position:100% 0; } 100%{ background-position:0 0; } }
/* PULIDO UI/UX (ronda 5): variante de .skeleton pensada para una LÍNEA de texto que todavía no se
   conoce (el saludo "Hola, [usuario]", el saldo de créditos...) — antes esas pantallas mostraban texto
   real pero incorrecto ("Hola" a secas, "Cargando saldo…") durante la carga, que luego se sustituía por
   el contenido real: un flash de contenido equivocado, no un estado de carga deliberado. Con esto, el
   placeholder se ve claramente como "cargando", nunca como una respuesta ya resuelta. */
.skeleton-line{ display:inline-block; height:0.85em; min-width:60px; vertical-align:middle; }

/* ============================================================================================
   ESTADO VACÍO — siempre incluye la acción que lo resuelve (E/H del blueprint)
   ============================================================================================ */
.empty-state{ text-align:center; padding:var(--sp-7) var(--sp-4); max-width:420px; margin:0 auto; }
.empty-state .ico{ font-size:32px; margin-bottom:var(--sp-3); opacity:.7; color:var(--ink-soft); display:flex; justify-content:center; }
.empty-state .ico svg{ width:32px; height:32px; }
.empty-state h3{ font-size:18px; margin-bottom:var(--sp-2); }
.empty-state p{ color:var(--ink-soft); font-size:14.5px; }

/* ============================================================================================
   TOASTS (confirmaciones breves, p.ej. "Guardado", "Sesión cerrada")
   ============================================================================================ */
.toast-host{ position:fixed; left:50%; bottom:calc(var(--sp-5) + env(safe-area-inset-bottom, 0px)); transform:translateX(-50%); z-index:300; display:flex; flex-direction:column; gap:8px; align-items:center; pointer-events:none; }
.toast{
  background:var(--glass-bg); backdrop-filter:blur(var(--glass-blur)); -webkit-backdrop-filter:blur(var(--glass-blur));
  border:1px solid var(--glass-border); color:var(--ink); box-shadow:var(--shadow-lg);
  border-radius:var(--radius-md); padding:12px 18px; font-size:14px; font-weight:500;
  opacity:0; transform:translateY(8px); transition:opacity .18s ease, transform .18s ease;
}
.toast.show{ opacity:1; transform:translateY(0); }
.toast.err{ border-color:color-mix(in srgb, var(--danger) 40%, var(--border)); color:var(--danger); }

/* ============================================================================================
   MODAL — sustituye a los confirm() nativos (K del blueprint)
   ============================================================================================ */
.modal-backdrop{ position:fixed; inset:0; background:rgba(0,0,0,.6); backdrop-filter:blur(2px); display:flex; align-items:center; justify-content:center; padding:var(--sp-4); z-index:400; }
.modal{ width:100%; max-width:420px; background:var(--bg-raised); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow-lg); padding:var(--sp-5); }
.modal h3{ font-size:18px; margin-bottom:var(--sp-2); }
.modal p{ font-size:14.5px; color:var(--ink-soft); }
.modal .row{ display:flex; gap:10px; justify-content:flex-end; margin-top:var(--sp-4); flex-wrap:wrap; }
@media (max-width:520px){
  /* en móvil, el modal se ancla abajo (patrón "hoja") — más fácil de alcanzar con el pulgar */
  .modal-backdrop{ align-items:flex-end; padding:0; }
  .modal{ max-width:none; border-radius:var(--radius-lg) var(--radius-lg) 0 0; }
}

/* ============================================================================================
   SHELL DE NAVEGACIÓN — barra superior fija (escritorio y móvil) + barra inferior de 3 pestañas
   (solo Dashboard/Mis Shorts — nunca en Editor/Generación, ver shell.js montar({conBottomNav})).
   Construido por shell.js dentro de #shell-topbar/#shell-bottomnav ya presentes en cada página.
   Renovación premium: glass real (blur + borde translúcido) en vez de un panel opaco plano.
   ============================================================================================ */
/* PULIDO RESPONSIVE: #shell-topbar es position:sticky, así que YA ocupa su propio espacio en el flujo
   normal del documento — nunca necesita que <body> reserve padding-top aparte para compensarlo (eso
   duplicaba el hueco: 60px de padding vacío + 60px del propio topbar = 120px de "vacío negro" antes
   del contenido real, el bug reportado tras la primera prueba en móvil). min-height aquí reserva el
   espacio DESDE EL PRIMER FRAME, antes de que shell.js termine de rellenarlo (evita un salto de
   layout cuando la barra aparece un instante después) — la única fuente de espacio, ahora. */
#shell-topbar{ position:sticky; top:0; z-index:100; min-height:var(--topbar-h); background:var(--glass-bg); backdrop-filter:blur(var(--glass-blur)); -webkit-backdrop-filter:blur(var(--glass-blur)); border-bottom:1px solid var(--glass-border); }
/* justify-content:space-between es necesario para móvil: .topbar-links (el flex:1 que separa marca de
   acciones en escritorio) se oculta por debajo de 760px, y sin esto la marca y los créditos/avatar
   quedaban apelotonados a la izquierda en vez de repartidos — no afecta a escritorio, donde
   .topbar-links con flex:1 ya ocupa el espacio intermedio de todos modos. */
.topbar-inner{ height:var(--topbar-h); display:flex; align-items:center; justify-content:space-between; gap:var(--sp-5); }
/* PULIDO UI/UX (ronda 4): antes marca+modo+links+crear+créditos+avatar competían en una única fila sin
   agrupación — "demasiados elementos compitiendo visualmente" (bug reportado). Ahora hay 3 grupos
   explícitos: .topbar-left (identidad de producto: marca + modo), .topbar-links (navegación, sin
   cambios), .topbar-right (acción principal "Crear" + .topbar-account-group). El grupo de cuenta tiene
   su propio gap interno más ajustado y un separador sutil respecto al botón Crear, para que el avatar
   se perciba como su propio elemento de cuenta, no pegado a la acción de creación. */
.topbar-left{ display:flex; align-items:center; gap:10px; flex:none; min-width:0; }
.topbar-brand{ display:flex; align-items:center; gap:9px; font-family:var(--font-display); font-weight:700; font-size:18px; color:var(--ink); text-decoration:none; flex:none; letter-spacing:-.01em; transition:opacity var(--dur-1) var(--ease); }
.topbar-brand:hover{ opacity:.85; }
/* logo real de Fyno AI (icono oficial proporcionado, sin rediseñar) — se muestra junto al nombre en
   texto real (tokens de color, se adapta solo a los dos temas); nunca se sustituye por el logotipo
   plano con texto en blanco (quedaría ilegible en claro) para que la marca siga siendo accesible en
   ambos temas sin necesitar dos exportaciones de imagen distintas. */
.topbar-logo-icon{ height:22px; width:auto; flex:none; }
.brand-icon{ height:26px; width:auto; flex:none; }
/* .mode-pill era antes un <span> DENTRO de .topbar-brand (un <a>) — un botón anidado dentro de un
   enlace. Ahora es un <button> hermano: HTML válido, sin elementos interactivos anidados, y sin el bug
   de navegación que eso causaba (ver shell.js, plantillaTopbar). border:none/font:inherit-safe porque
   ahora es un <button> real, no un <span>, y necesita el reset explícito de estilos de botón nativo. */
.mode-pill{ font-family:var(--font-mono); font-size:11.5px; background:var(--border-soft); border:1px solid var(--border-soft); color:var(--ink-soft); padding:5px 11px; border-radius:var(--radius-pill); cursor:pointer; min-height:28px; display:inline-flex; align-items:center; flex:none; transition:background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.mode-pill:hover{ background:var(--surface-hover); border-color:var(--border-strong); transform:scale(1.03); }
.topbar-links{ display:flex; gap:var(--sp-4); flex:1; min-width:0; }
.topbar-links a{ position:relative; color:var(--ink-soft); text-decoration:none; font-weight:500; font-size:14.5px; padding:8px 2px; transition:color var(--dur-1) var(--ease); }
.topbar-links a::after{ content:''; position:absolute; left:2px; right:2px; bottom:2px; height:2px; border-radius:2px; background:linear-gradient(90deg, var(--accent), var(--magenta)); transform:scaleX(0); transform-origin:left; transition:transform var(--dur-2) var(--ease); }
.topbar-links a:hover{ color:var(--ink); }
.topbar-links a:hover::after{ transform:scaleX(1); }
.topbar-links a.on{ color:var(--ink); }
.topbar-links a.on::after{ transform:scaleX(1); }
.topbar-right{ display:flex; align-items:center; gap:var(--sp-4); flex:none; }
.topbar-crear{ padding:9px 18px; font-size:13.5px; min-height:38px; }
.topbar-account-group{ display:flex; align-items:center; gap:10px; padding-left:var(--sp-3); border-left:1px solid var(--border); }
@media (max-width:760px){ .topbar-account-group{ border-left:none; padding-left:0; } }
.credits-pill{ font-family:var(--font-mono); font-size:13px; background:var(--accent-soft); color:var(--accent-text); padding:6px 13px; border-radius:var(--radius-pill); white-space:nowrap; text-decoration:none; display:inline-flex; align-items:center; min-height:32px; box-sizing:border-box; border:1px solid transparent; transition:filter var(--dur-1) var(--ease), transform var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.credits-pill:hover{ filter:brightness(1.12); transform:scale(1.03); border-color:color-mix(in srgb, var(--accent) 35%, transparent); }
.avatar-btn{ background:transparent; border:none; cursor:pointer; width:var(--tap-min); height:var(--tap-min); border-radius:50%; display:inline-flex; align-items:center; justify-content:center; padding:0; flex:none; transition:background-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.avatar-btn:hover{ background:var(--border-soft); transform:scale(1.05); }
/* ícono de crédito/moneda de .credits-pill — currentColor hereda el mismo naranja que el texto */
.credits-pill svg{ width:14px; height:14px; margin-right:1px; flex:none; }

/* selector de tema claro/oscuro (RONDA de acercamiento a la referencia) — botón circular único de 2
   estados (nunca 2 botones separados: seguiría siendo un solo control que ALTERNA, y 2 objetivos
   táctiles de 44px cada uno duplicarían el ancho sin ninguna ventaja real). Vive en tokens.css (antes
   solo en el <style> de index.html) porque ahora también lo usa la barra autenticada (shell.js) — un
   único sitio para una única pieza de UI, nunca una copia por página. --tap-min real, nunca se reduce. */
.theme-toggle-btn{ width:var(--tap-min); height:var(--tap-min); border-radius:50%; border:1px solid var(--border); background:var(--bg-raised); color:var(--ink-soft); display:inline-flex; align-items:center; justify-content:center; cursor:pointer; flex:none; transition:transform var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.theme-toggle-btn:hover{ transform:scale(1.08) rotate(-8deg); border-color:var(--border-strong); color:var(--ink); }
.theme-toggle-btn svg{ width:17px; height:17px; }
.avatar{ width:29px; height:29px; border-radius:50%; background:linear-gradient(135deg, var(--accent), var(--magenta)); color:#fff; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; box-shadow:0 0 0 2px var(--bg-raised); }
@media (max-width:760px){ .topbar-links{ display:none; } .topbar-crear{ display:none; } }
/* CORRECCIÓN DE CAUSA REAL (overflow horizontal real, 360-430px, tras añadir #topbar-theme-btn a
   .topbar-account-group): con topbar-links/topbar-crear ya ocultos, el contenido que queda
   (topbar-left: marca+mode-pill · topbar-right: tema+créditos+avatar, los 3 con flex:none/--tap-min
   real, nunca se reducen) sencillamente no cabía en el ancho disponible de un móvil estrecho —
   comprobado con medidas reales: a 360px sobraban ~46px. Nunca se resuelve ocultando el selector de
   modo o el de tema (ambos son funcionalidad real, no decoración) ni reduciendo un objetivo táctil por
   debajo de --tap-min: se recorta SOLO el relleno/separación puramente visual de estos 5 sitios
   (gap del topbar, gap entre marca y mode-pill, gap del grupo de cuenta, padding de credits-pill,
   padding de mode-pill) — libera ~46px, exactamente lo que faltaba, sin tocar ningún tamaño de icono,
   objetivo táctil ni ocultar ningún control. */
@media (max-width:480px){
  .topbar-inner{ gap:8px; }
  .topbar-left{ gap:6px; }
  .topbar-account-group{ gap:6px; }
  .credits-pill{ padding:6px 8px; }
  .mode-pill{ padding:5px 7px; }
}

/* BUG REAL corregido (ronda de pequeños ajustes): usaba --glass-bg (72% opaco — pensado para el topbar/
   bottomnav, que sí quieren dejar entrever un poco del fondo) — para un MENÚ con texto que hay que leer
   (selector de modo, menú de cuenta), ese 28% de transparencia dejaba el contenido del dashboard de
   detrás mezclado con las opciones del propio menú. --surface-2 ya existía en el sistema de tokens
   precisamente para esto ("el cristal de navegación... dropdowns", ver el comentario donde se define,
   arriba) pero nunca se había llegado a usar aquí — es opaco al 100%, mismo tono oscuro coherente con
   el resto de superficies elevadas de la app. backdrop-filter se conserva (sin efecto visible sobre un
   fondo ya opaco, salvo un suavizado casi imperceptible en el borde redondeado — inofensivo, no hace
   falta quitarlo para corregir el problema real). */
.dropdown-panel{ position:absolute; right:var(--sp-4); top:calc(var(--topbar-h) + 6px); min-width:240px; max-width:calc(100vw - 2 * var(--sp-4)); background:var(--surface-2); backdrop-filter:blur(var(--glass-blur)); -webkit-backdrop-filter:blur(var(--glass-blur)); border:1px solid var(--glass-border); border-radius:var(--radius-md); box-shadow:var(--shadow-lg); padding:6px; z-index:110; box-sizing:border-box; animation:dropdown-in var(--dur-2) var(--ease); }
@keyframes dropdown-in{ from{ opacity:0; transform:translateY(-4px) scale(.98); } to{ opacity:1; transform:translateY(0) scale(1); } }
.dropdown-item{ display:flex; align-items:center; justify-content:space-between; gap:8px; width:100%; box-sizing:border-box; padding:10px 12px; min-height:var(--tap-min); border-radius:var(--radius-sm); font-size:14px; color:var(--ink); text-decoration:none; background:transparent; border:none; text-align:left; font-family:var(--font-body); cursor:pointer; transition:background-color var(--dur-1) var(--ease); }
.dropdown-item:hover{ background:var(--border-soft); }
.dropdown-item-danger{ color:var(--danger); }
.dropdown-item-active{ background:var(--accent-soft); color:var(--accent-text); cursor:default; }
.dropdown-panel hr{ border:none; border-top:1px solid var(--border-soft); margin:6px 0; }
/* #mode-menu se abre desde .mode-pill, que vive en el lado IZQUIERDO de la barra (junto a la marca) —
   el resto de .dropdown-panel están anclados a la derecha porque su disparador (avatar) también está a
   la derecha. Ancla propia a la izquierda para que el panel aparezca bajo su propio botón, no al otro
   lado de la pantalla. */
#mode-menu{ right:auto; left:var(--sp-4); }
/* .dropdown-account: cabecera agrupada del menú de cuenta (email + plan + saldo juntos, antes el email
   era una única línea suelta sin relación visual con el resto). Referencia conceptual: agrupar
   identidad/plan/saldo en la cabecera del menú de usuario — construido con los componentes propios de
   Fyno (.badge, .dropdown-item), no una copia de ningún diseño ajeno. */
.dropdown-account-head{ padding:8px 12px 12px; }
.dropdown-account-email{ font-size:13.5px; font-weight:600; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-bottom:8px; }
.dropdown-account-meta{ display:flex; align-items:center; justify-content:space-between; gap:8px; flex-wrap:wrap; }
.dropdown-account-saldo{ font-family:var(--font-mono); font-size:12.5px; color:var(--ink-soft); }
.dropdown-account-saldo b{ color:var(--ink); }

/* PULIDO UI/UX (ronda 7): min-height añadido — a diferencia de #shell-topbar (que ya reservaba
   min-height:var(--topbar-h) desde el principio), #shell-bottomnav no reservaba ninguna altura
   mientras estaba vacío (recién cargada la página, antes de que shell.js lo rellene): con solo el
   padding propio (~12px + safe-area) medía una fracción de su alto real, y saltaba a ~64px en cuanto
   se montaban sus 3 elementos — un salto de layout real, no solo un cambio de contenido, y parte del
   parpadeo reportado al navegar entre pantallas. --bottomnav-h ya era el valor de referencia usado en
   otro sitio (body.con-bottomnav, más abajo) para este mismo alto — se reutiliza aquí, no se inventa
   uno nuevo. Renovación premium: mismo glass que el topbar, para que ambas barras se lean como una
   sola pieza de "chrome" de producto. */
#shell-bottomnav{
  position:fixed; left:0; right:0; bottom:0; z-index:100; display:flex;
  min-height:var(--bottomnav-h);
  background:var(--glass-bg); backdrop-filter:blur(var(--glass-blur)); -webkit-backdrop-filter:blur(var(--glass-blur)); border-top:1px solid var(--glass-border);
  padding:6px var(--sp-3) calc(6px + env(safe-area-inset-bottom, 0px));
}
@media (min-width:761px){ #shell-bottomnav{ display:none !important; } }
.bottomnav-item{ flex:1; display:flex; flex-direction:column; align-items:center; gap:2px; padding:6px 4px; min-height:var(--tap-min); color:var(--ink-faint); text-decoration:none; font-size:11px; border-radius:var(--radius-sm); transition:color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.bottomnav-item:active{ transform:scale(.94); }
.bottomnav-item.on{ color:var(--accent-text); }
.bottomnav-item span:first-child{ font-size:19px; line-height:1; }
.bottomnav-item span:first-child svg{ width:21px; height:21px; display:block; }
.bottomnav-crear{ color:var(--ink); }
/* botón central "Crear" destacado — círculo con gradiente de marca y glow propio, ligeramente elevado
   sobre la línea del resto de pestañas (referencia visual: acción primaria central de una tab bar). */
.bottomnav-crear-dot{ background:linear-gradient(135deg, var(--accent), var(--magenta)); color:#fff; width:38px; height:38px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:19px !important; box-shadow:0 4px 16px -4px rgba(255,90,44,.6); transition:transform var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease); }
.bottomnav-crear:active .bottomnav-crear-dot{ transform:scale(.92); }

/* body.con-shell YA NO añade padding-top — #shell-topbar (sticky) reserva su propio espacio (arriba).
   La clase se conserva en el HTML de cada página como marcador semántico ("esta pantalla usa el
   shell") y por si algún día el topbar pasa a position:fixed, pero hoy no aplica ninguna regla. */
body.con-bottomnav{ padding-bottom:calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px)); }

/* ============================================================================================
   REVEAL AL ENTRAR EN VIEWPORT — microinteracción sutil, nunca en el primer viewport (el hero
   siempre debe verse completo de inmediato, sin depender de JS ni de haber hecho scroll). Un script
   pequeño (IntersectionObserver) añade .is-visible la primera vez que cada elemento entra en
   pantalla; si JS no llega a ejecutarse por cualquier motivo, .reveal por sí solo NUNCA debe dejar
   contenido invisible de forma permanente — por eso el fallback vive en el propio script (ver
   landing), no aquí. prefers-reduced-motion ya neutraliza la transición vía la regla `*{
   transition:none }` de abajo — el contenido solo "aparece" sin animar, nunca queda oculto. */
.reveal{ opacity:0; transform:translateY(18px); transition:opacity .5s var(--ease), transform .5s var(--ease); }
.reveal.is-visible{ opacity:1; transform:none; }

@media (prefers-reduced-motion: reduce){
  *{ transition:none !important; animation:none !important; }
  .ambient-bg .blob{ animation:none !important; }
}
