/* GENERACYE — mobile.css v7 · Capa responsive + pulido de capas (cargada la última)
   Auditoría real a 375px (auditor MQA + capturas + sesión owner):
   v1 landing (stats/product/demo-input) → v2 col/orb/min-width → v3 wrap del
   titular → v4 pantalla de acceso → v5 PANEL móvil (cinta vs navegación) →
   v6 ESCRITORIO: las bandas superiores (topbar/cinta) siempre POR ENCIMA del
   contenido que scrollea (el briefing IA se montaba sobre la cinta) →
   v7 EL PANEL DEJA DE SER UNA VENTANA DE 323 px (ver el bloque del final).
   Regla: en móvil NADA desborda; lo ancho scrollea DENTRO de su caja. */

/* ── Guardas globales (todas las páginas, todos los anchos) ── */
html, body { overflow-x: clip; }
#root { max-width: 100vw; overflow-x: clip; }

/* Las bandas superiores ganan a cualquier tarjeta/panel que pase por debajo.
   Solo z-index (sin tocar position: si la banda es sticky/fija, se respeta). */
[class*="topbar"], .app nav { z-index: 80; }
/* 13-sep-2026: aquí había además `background: #0a0a0a`, bajo un comentario que
   dice «Solo z-index». No era solo z-index: `background` es un atajo, así que
   borraba el `background-image` de quien pasara por debajo — y esta hoja carga
   la última, así que ganaba siempre y en TODOS los anchos, no solo en móvil.

   Medido en producción antes de tocar nada:

     .ticker-tape-wrap   backgroundImage "none"   backgroundColor rgb(10,10,10)

   cuando cinematic.css:125 le declara
   `background: linear-gradient(180deg, oklch(0 0 0 / 0.2), transparent)`.
   Quitando la declaración en vivo, el degradado vuelve solo: comprobado, no
   deducido. O sea que un elemento de diseño de la portada llevaba tiempo
   apagado sin que nada diera error — la familia de «un CSS que desaparece en
   silencio» que este proyecto ya conoce.

   Se puede quitar sin consecuencias porque los dos elementos que alcanzaba
   —.ticker-tape-wrap y .ticker-tape-badge— son `position: static` (medido):
   no hay nada deslizándose por debajo que necesitara taparse. Y el color era
   además un literal fuera del sistema de tokens. */
[class*="tape"], [class*="ticker"] { z-index: 70; }

/* 760 y no 720 (11-sep-2026). Era 720 y polish.css colapsa el Panel a una
   columna en 760: en la franja de 40 px que quedaba en medio, `.side` seguía
   siendo la columna de escritorio de styles.css:617 y, con una sola columna,
   se estiraba a todo lo ancho. Medido a 736x414 —un iPhone 8 Plus / XR / 11 en
   horizontal— lo primero bajo la barra es el rótulo ESPACIO DE TRABAJO y el
   menú apilado a 708 px de ancho, con los datos empujados debajo. Justo lo que
   la tira de chips de más abajo existe para evitar. */
@media (max-width: 760px) {

  /* Cortafuegos universal móvil: min-width:auto de flex/grid es la causa nº1
     de desbordes — en móvil ningún div impone ancho mínimo intrínseco. */
  #root div { min-width: 0; }
  img, svg, video, canvas { max-width: 100%; height: auto; }

  /* ── Tipografía fluida: los titulares nunca se cortan ── */
  h1, .h1 { font-size: clamp(26px, 8.6vw, 38px) !important; line-height: 1.12 !important; overflow-wrap: break-word; letter-spacing: -0.02em !important; }
  h2 { font-size: clamp(20px, 6.2vw, 28px) !important; line-height: 1.2 !important; overflow-wrap: break-word; }
  h3 { font-size: clamp(16px, 5vw, 22px) !important; }
  /* El span destacado del hero («cada convicción») envuelve, nunca se corta */
  h1 span, .h1 span, .accent { white-space: normal !important; overflow-wrap: break-word; font-size: inherit; }

  /* ── ACCESO / FORMULARIOS · verificado con captura: el enlace
     «¿Olvidaste la contraseña?» se cortaba porque la tarjeta es más ancha
     que el viewport y la columna de arte queda como franja muerta ── */
  div:has(> form) { display: block !important; max-width: 100vw !important; }
  form { max-width: 100% !important; min-width: 0 !important; box-sizing: border-box; padding-right: 4px; }
  form a { white-space: nowrap; font-size: 12px; }
  /* 8-oct-2026 · Sin casillas ni botones de opción: con `form input` a secas,
     la casilla de «Acepto los Términos» del registro medía 151 px de ancho
     (medido a 375 px) y empujaba su texto a una columna estrecha. */
  form input:not([type="checkbox"]):not([type="radio"]) { width: 100% !important; box-sizing: border-box; }
  form input[type="checkbox"], form input[type="radio"] { flex: 0 0 auto; width: 18px; height: 18px; }
  /* El formulario de registro es tan ancho como su marco, no como la ventana:
     polish.css le daba `100vw − 24px` y styles.css otros 12 px de margen a cada
     lado, dentro de un marco con 20 px de aire: se salía 8 px por la derecha y
     cortaba los campos y el botón de «Crear cuenta». */
  .auth-stage .auth-card { width: 100% !important; margin: 0 !important; }

  /* ── LANDING · offenders reales del auditor ── */
  .demo-input { width: 100% !important; max-width: 100% !important; min-width: 0 !important; box-sizing: border-box; }
  .orb-stage { max-width: 86vw !important; margin-inline: auto !important; }
  div:has(> .stats-cell) { display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 10px !important; width: 100% !important; max-width: 100% !important; }
  .stats-cell { width: auto !important; min-width: 0 !important; }
  div:has(> .cell.prod) { display: grid !important; grid-template-columns: 1fr !important; gap: 12px !important; max-width: 100% !important; }
  .cell.prod { width: auto !important; min-width: 0 !important; max-width: 100% !important; }
  /* Columnas (footer/secciones .col) → apiladas */
  div:has(> .col) { display: grid !important; grid-template-columns: 1fr !important; gap: 16px !important; max-width: 100% !important; }
  .col { width: auto !important; min-width: 0 !important; max-width: 100% !important; }
  /* Filas flex de la landing que no caben → se envuelven */
  section > div { flex-wrap: wrap; }
  /* 15-oct-2026 · El terminal de la portada (landing.js, .criterio-rejilla)
     escribe cada línea con `white-space: pre` en línea: a 375 px la caja mide
     327 px y las líneas piden 454, así que «✓ Yahoo  ✓ Stooq EOD  ✓ TradingView
     ✓ SEC EDGAR  ✓ Finnhub» se corta por la derecha sin ninguna pista. Que
     envuelva: pre-wrap conserva los espacios dobles del terminal. */
  .criterio-rejilla div[style*="white-space: pre"] { white-space: pre-wrap !important; }
  /* blobs/anillos decorativos: grandes por diseño — su contenedor los recorta */
  section, header, footer, main { max-width: 100vw; overflow-x: clip; }

  /* ── APP SHELL ── */
  .app { max-width: 100vw; overflow-x: clip; }

  /* Topbar / navegación / cintas de cotizaciones: scroll horizontal propio,
     nunca recortan ni empujan la página */
  /* 13-sep-2026: la lista llevaba [class*="tape"], [class*="ticker"] y
     [class*="marquee"]. Ninguno alcanzaba a la cinta del Panel —que es
     .gen-marketbar (professional.js:139) y no contiene ninguna de las tres
     palabras— y lo unico que alcanzaban de verdad eran la cinta de la PORTADA
     y su pista de repuesto. Medido en produccion a 375 px, con el widget de
     TradingView caido (que es cuando entra el repuesto, y hoy esta entrando):

       .mb-marquee   clientWidth 297 · scrollWidth 5.163 · max-width 375,33 px

     La animacion de polish.css:187 es translateX(-50%) sobre los 5.163 px
     reales de la pista (la lista va duplicada a proposito), asi que con la
     caja recortada a 297 px la cinta se va media pantalla y deja la banda en
     negro. Una pista animada no es una barra con scroll. Hallazgo SHELL-06. */
  .app nav, [class*="topbar"], [class*="tabs"], .gen-marketbar {
    overflow-x: auto !important; max-width: 100vw !important; flex-wrap: nowrap !important;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .app nav::-webkit-scrollbar, [class*="topbar"]::-webkit-scrollbar, .gen-marketbar::-webkit-scrollbar { display: none; }

  /* VERIFICADO EN SESIÓN: la cinta de cotizaciones (sticky/absoluta) tapaba la
     fila de navegación del Panel — en móvil pasa al flujo normal del documento */
  /* 13-sep-2026: misma correccion. La cinta que habia que sacar de la capa
     flotante es la del Panel, .gen-marketbar. Con la lista ancha, el que
     recibia el position:static era el rotulo de la cinta de la PORTADA:
     cinematic.css:131 lo quiere absolute con transform: translateY(-50%), y al
     pasarlo a estatico CONSERVA el transform, asi que ocupa linea propia y
     empuja el widget dentro de una caja con overflow:hidden. Medido a 375 px:
     .ticker-tape-badge position "static" y .ticker-tape-wrap de 69 px de alto
     en vez de 46. Hallazgo SHELL-03. */
  /* 20-sep-2026: `static` se pasó de frenada. La cinta lleva dentro su pista
     de repuesto (.mb-fallback, professional.js:158) con `position:absolute;
     inset:0`, y un padre estático no es bloque contenedor: la pista se
     colgaba de `.app` —el primer antepasado posicionado— y se estiraba sobre
     la PÁGINA ENTERA. Medido en producción a 760 px con el widget de
     TradingView caído: .mb-fallback 554 px de alto (el alto de la app) en vez
     de 46, con los precios pintados encima del texto de la pantalla.
     Y el widget está caído para todo el que aún no ha aceptado cookies, que
     es justo el visitante nuevo.
     `relative` mantiene la cinta en el flujo —que es lo que buscaba la
     corrección del 13-sep, no floten sobre la navegación— y le devuelve el
     bloque contenedor a su pista. */
  .app .gen-marketbar { position: relative !important; }

  /* Sidebar del panel → tira horizontal de chips (el contenido queda arriba,
     no tras una pantalla entera de menú) — SIEMPRE visible sobre cualquier banda */
  .dashboard .side, .app .side {
    display: flex !important; flex-direction: row !important; align-items: center;
    overflow-x: auto !important; max-width: 100vw !important; gap: 6px;
    padding: 8px 10px !important; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    position: relative !important; z-index: 30; background: rgba(10,10,10,.96);
    height: auto !important; min-height: 0 !important;
  }
  .side::-webkit-scrollbar { display: none; }
  .side > * { flex: 0 0 auto !important; }
  .side .item { white-space: nowrap; min-height: 40px; display: inline-flex; align-items: center; }
  .side .group-label { display: none !important; } /* etiquetas de sección fuera en móvil */

  /* ── Grids → una columna ── */
  .grid-2, .kpi-row, .weekly-pick-grid { display: grid !important; grid-template-columns: 1fr !important; gap: 12px !important; }
  .card { max-width: 100%; min-width: 0; box-sizing: border-box; }
  .card, [class*="panel"] { overflow-x: clip; }

  /* ── Tablas y filas anchas: scroll interno honesto ── */
  /* 15-oct-2026 · SIN `-webkit-overflow-scrolling: touch`. En un iPhone con
     Safari, la «muestra» de la portada se quedaba BLANCA a partir de «El
     historial completo»: esa tabla mide 3.134 px de alto en el móvil (cada
     fila es una tarjeta) y, al ser una caja desplazable con desplazamiento
     táctil, Safari la pinta en una capa aparte; con una capa tan alta no la
     rasteriza y la deja en blanco, y con ella todo lo que va debajo. Medido
     en producción a 375 px: table → overflow auto, 3.134 px. El desplazamiento
     con inercia es el de siempre desde iOS 13, así que esta propiedad no
     aportaba nada y solo creaba la capa. */
  .metric-table, table { display: block; max-width: 100%; overflow-x: auto; }
  /* 15-oct-2026 · LA FICHA DE UN VALOR ERA OTRA CAJA DESPLAZABLE DE 21.000 px.
     styles.css:718 da a .analysis `overflow-y: auto` para la estación de
     escritorio; en el teléfono nadie le pone alto, así que la ficha entera
     (medida en el banco a 375 px: HURN 21.483 px, AAPL 21.978, VWCE.DE 13.911)
     era UNA caja con desplazamiento: el mismo patrón que la tabla del
     historial que dejaba la muestra en blanco en el iPhone. Quien desplaza es
     .screen (600-710 px de alto); la ficha fluye dentro. Lo ancho ya lo
     recorta `.screen { overflow-x: clip }` (más abajo en este fichero) y,
     medido, ningún elemento de la ficha pasa de 375 px.
     Y las tres .metric-table de la ficha (6, 8 y 35 filas; la técnica mide
     2.068 px de alto) caben en su tarjeta (scrollWidth = clientWidth = 307),
     así que el overflow-x: auto de la línea de arriba solo les creaba la capa. */
  .analysis { overflow: visible !important; }
  .analysis .metric-table { overflow: visible; }
  .watch-row { min-width: 0; }
  .watch-row .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40vw; }

  /* ── Widgets embebidos (TradingView) ── */
  iframe { max-width: 100% !important; }

  /* ── Modales y visores a pantalla casi completa ── */
  [class*="modal"] { width: 96vw !important; max-width: 96vw !important; }
  .gen-export-viewer > div { width: 96vw !important; height: 88vh !important; }

  /* ── Ergonomía táctil ── */
  /* 31-oct-2026 · De 42 a 44 px, y también lo que no era .btn: pestañas de 27 px,
     filtros de alertas y botones de cabecera (auditoría de la aplicación por dentro). */
  .btn, button[class*="btn"], .tabs button, .filtro-alerta { min-height: 44px; }
  .top-right button { min-width: 44px; min-height: 44px; }
  input, select, textarea { font-size: 16px !important; } /* evita el auto-zoom de iOS */
  body { padding-bottom: env(safe-area-inset-bottom); }

  /* Orbe decorativo del dashboard: que no dispare el ancho */
  .dash-orb-wrap { max-width: 45vw; }
}

/* ── «ENTRAR» NO SE OCULTA NUNCA ────────────────────────────
   styles.css esconde `.top-right .btn-ghost` a partir de 1200 px para quitar
   el botón de prueba gratuita, pero se llevaba por delante el de iniciar
   sesión, que comparte clase. Resultado medido a 375 px: un cliente que YA
   PAGA abre la portada en el móvil y no tiene por dónde entrar — no hay menú
   hamburguesa que lo rescate. El de sesión lleva ahora .btn-signin y vuelve. */
.top-right .btn-signin { display: inline-flex !important; align-items: center; }

@media (max-width: 768px) {
  /* Que quepa junto al botón primario sin empujar la barra: los dos se
     encogen en tipografía y relleno, ninguno parte su texto en dos líneas. */
  .top-right { gap: 6px; }
  .top-right .btn-signin,
  .top-right .btn-primary {
    font-size: 12px; padding: 6px 10px;
    white-space: nowrap; flex-shrink: 0;
  }
}

@media (max-width: 400px) {
  .top-right { gap: 4px; }
  .top-right .btn-signin,
  .top-right .btn-primary { font-size: 11px; padding: 5px 8px; }
}

/* Pantallas muy pequeñas */
@media (max-width: 400px) {
  h1, .h1 { font-size: clamp(24px, 8.2vw, 32px) !important; }
  .stats-cell { font-size: 12px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   EL PANEL EN EL MÓVIL ERA UNA VENTANA DE 323 px (11-sep-2026)

   Medido en producción con un móvil real emulado a 375x812 y recarga previa
   (con el panel del navegador oculto `innerWidth` es 0 y las cifras mienten):

     .dashboard  → grid-template-rows: 64px / 322,5px / 323,5px
     .center     → alto 323 px, contenido 10.016 px  (31 pantallas)
     .right      → alto 323 px, contenido  3.210 px  (10 pantallas)
     documento   → no scrollea (body overflow:hidden)

   O sea: el cliente leía el producto entero por una rendija de un tercio de
   pantalla, y debajo otra rendija con la lista de seguimiento compitiendo por
   su atención. La Acción de la Semana mide 3.010 px: nueve rendijas de scroll
   para una sola tarjeta. El 13F quedaba a catorce arrastres del principio.

   POR QUÉ PASABA. `.dashboard` es la estación de trabajo de ESCRITORIO: tres
   columnas (styles.css:611) donde cada panel scrollea por su cuenta, que es lo
   correcto con un ratón y 1.900 px. `.center` y `.right` traen su
   `overflow-y: auto` de styles.css:640 y :679, FUERA de toda consulta de
   medios. polish.css:61 colapsa las COLUMNAS a una sola en móvil, pero nadie
   devolvía el alto ni quitaba el scroll interno: las tres columnas se
   convirtieron en tres filas que se reparten los 710 px del contenedor.

   EL ARREGLO. En móvil el Panel se comporta como una página: scrollea UNA sola
   caja (`main`) y dentro todo fluye. Verificado a 375x812: 13.736 px seguidos,
   sin cajas anidadas, sin desbordes laterales (scrollWidth == clientWidth).

   El corte es 760 px a propósito, el mismo de polish.css:61 (donde el grid pasa
   a una columna). Entre 761 y 1080 la estación sigue siendo de escritorio con
   sus paneles independientes — ahí no se toca nada.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  .app > main {
    overflow-y: auto !important;
    /* 15-oct-2026: sin `-webkit-overflow-scrolling: touch` (ver la nota de las
       tablas, más arriba): desde iOS 13 no hace falta y obliga a Safari a pintar
       el Panel entero, 11.000 px, en una capa aparte. */
    overscroll-behavior-y: contain;
  }
  .dashboard { display: block !important; height: auto !important; }
  .dashboard > .center,
  .dashboard > .right { height: auto !important; overflow-y: visible !important; }

  /* Los dos botones flotantes vuelven a aparecer al llegar al fondo (así está
     escrito en flotantes.js: «ahí no hay texto debajo que tapar»). Ahora sí lo
     hay, porque el Panel termina donde termina su contenido: 76 px de aire para
     que la última fila no quede debajo del botón de IA. */
  .dashboard { padding-bottom: 76px !important; }

  /* ── 56 px de los 375 se iban en relleno lateral ──────────────────────
     .center trae `padding: 22px 28px` de escritorio (styles.css:640) y cada
     tarjeta otros 18. Medido: el contenido de la Acción de la Semana vivía en
     273 px de los 375 — el 27 % de la pantalla era margen. Con esto pasa a
     305 px y la cabecera baja de 4 líneas a 2. */
  .center, .right { padding: 16px 12px !important; }
  .card { padding: 14px !important; }
}

/* ── LA ACCIÓN DE LA SEMANA · su cabecera y sus sellos ──────────────────────
   La cabecera es un flex de dos columnas con `justify-content: space-between`
   (dashboard.js): a 375 px el rótulo «ACCIÓN DE LA SEMANA · PRE-RUPTURA» se
   partía en cuatro líneas de dos palabras mientras la fecha se apretaba a su
   derecha en otras tres. En el móvil van uno debajo del otro.

   Y los sellos que dicen si la pick es la EMITIDA o un cálculo PROVISIONAL
   están escritos a 7,5 px. Ese sello es la prueba de que lo que ves en la web
   es lo mismo que llegó por correo: si no se lee, no sirve. 10 px mínimo. */
@media (max-width: 760px) {
  .wp-head {
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 6px;
  }
  .wp-head > .mono:first-child { flex-wrap: wrap; }
  /* 15-oct-2026: 11 px, el suelo del móvil. Con 10 px esta regla, que pesa
     más que la del suelo, lo dejaba por debajo. */
  .wp-head .mono { font-size: 11px !important; letter-spacing: .08em !important; }
  .kpi-row .kpi .label { font-size: 11px !important; letter-spacing: .1em !important; }
  /* 15-oct-2026: la rotación sectorial y el cribado de menos de 50 $ iban
     en dos columnas (1,4fr / 1fr): a 375 px cada sector quedaba en 19 px y
     se leía «C… +3,14 %». Uno debajo del otro. */
  .regimen-sectores-cribado { grid-template-columns: 1fr !important; }
}

/* ── LA TABLA DE PICKS ABIERTAS, COMO FICHAS EN EL MÓVIL (16-oct-2026) ──────
   Nueve columnas en 375 px solo se leían deslizando de lado, sin ninguna
   pista de que había más. Cada fila pasa a ser una ficha con sus rótulos
   (data-label, en dashboard.js). */
@media (max-width: 640px) {
  .tabla-abiertas { overflow: visible !important; }
  .tabla-abiertas thead { display: none; }
  .tabla-abiertas table, .tabla-abiertas tbody, .tabla-abiertas tr, .tabla-abiertas td { display: block; width: 100%; }
  .tabla-abiertas tr { display: grid !important; grid-template-columns: 1fr 1fr; gap: 6px 12px; padding: 12px 0; }
  .tabla-abiertas td { padding: 0 !important; white-space: normal !important; }
  .tabla-abiertas td::before { content: attr(data-label); display: block; font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
  .tabla-abiertas td:first-child { grid-column: 1 / -1; font-size: 16px !important; }
  .tabla-abiertas td:first-child::before { display: none; }
}

/* ── EL 13F: TRES MANDOS DE 4x4 px ──────────────────────────────────────────
   El radar institucional cambia de vista cada 9 segundos y sus únicos mandos
   son tres puntos de 4x4 px separados 3 px (dashboard.js). La yema de un dedo
   mide unos 34 px: los cubre los tres a la vez. WCAG 2.2 (2.5.8) pide 24x24
   como mínimo y las guías de Apple y Google, 44x44.

   En el móvil el punto pasa a 8 px y su área de toque a 26x26 con un
   pseudoelemento invisible. El número no es capricho: las áreas NO pueden
   solaparse. Con `inset: -9px` cada área mide 8 + 9 + 9 = 26 px y el hueco
   entre puntos es 18, así que una acaba justo donde empieza la siguiente.
   Probado antes con áreas de 44 px: se pisaban unas a otras y el navegador
   entregaba el toque al ÚLTIMO punto del DOM — tocabas el primero y cambiaba
   al tercero. 26x26 cumple el mínimo de WCAG 2.2 (2.5.8) sin solapes.

   En escritorio no se toca nada: con ratón los 4 px de siempre. */
@media (max-width: 760px) {
  .radar13f-dots { gap: 18px !important; margin-left: 8px !important; }
  .radar13f-dots > span { width: 8px !important; height: 8px !important; position: relative; }
  .radar13f-dots > span::after { content: ""; position: absolute; inset: -9px; }
}

/* ── LA CARTERA DEL CLIENTE ESCONDÍA EL DINERO ──────────────────────────────
   La tarjeta de Cartera es `grid-template-columns: 140px 1fr` con 24 px de
   hueco (estilo en línea): el donut se lleva 140 y a la leyenda le quedan 151.
   Medido a 375 px: de cada posición se veía «AAPL · 510 accs.» y el importe
   ($169.457,70) quedaba cortado por el borde y el peso (30,3 %) ENTERO fuera
   de la pantalla, sin forma de llegar a él. Es el dinero del cliente.
   En móvil: donut arriba, leyenda debajo a todo lo ancho. */
@media (max-width: 760px) {
  .cartera-donut {
    grid-template-columns: 1fr !important;
    gap: 14px !important;
    justify-items: center;
  }
  .cartera-donut > * { width: 100%; min-width: 0; }
}

/* ── LAS COTIZACIONES DEL HERO NACEN FUERA DE LA PANTALLA ───────────────────
   Las cinco burbujas que orbitan la esfera de la portada (`.orb-tick`) se
   colocan con desplazamientos fijos de ±150, ±170 y ±200 px escritos en línea
   desde landing.js, pensados para una escena ancha. Medido a 375 px: cuatro de
   las cinco nacen fuera del viewport (x = −86, −66, 401 y 425) y se ven
   cortadas por el borde — «GOOGL 338,5» partido a mitad de cifra.

   COMPROBADO ANTES DE TOCAR NADA: la página NO se arrastra de lado. `.screen`
   da scrollWidth 432 contra clientWidth 365, pero al forzar scrollLeft = 200 se
   queda en 0, porque `html, body { overflow-x: clip }` (arriba en este mismo
   fichero) ya recorta. O sea: no hay desplazamiento lateral que arreglar; hay
   contenido pintado donde no se ve.

   Las mismas cotizaciones, completas, están en la cinta que va justo debajo.
   En el móvil no se pintan las burbujas. */
@media (max-width: 760px) {
  .orb-tick { display: none !important; }
}

/* ── EL RELOJ DE MERCADO TAPABA EL BOTÓN DEL MENÚ (12-sep-2026) ─────────────
   Medido en una ventana real de 391 px, con sesión, DESPUÉS de devolver el
   botón hamburguesa a la aplicación:

     .nav-burger          x  42 →  82   (40x40, visible)
     .top-right-cluster   x −54 → 379   (433 px de ancho)
     solape                40 de 40 px
     elementFromPoint(centro del botón) → span.mono   ← el texto del reloj

   O sea: el botón estaba, medía bien y NO se podía pulsar. Mi clic por código
   sí llegaba —`.click()` no mira quién está encima— y el de un dedo, no. Es
   exactamente el fallo de los dos botones flotantes del 3-sep, y se caza con
   la misma prueba: elementFromPoint en el centro.

   El reloj se lleva 234 de esos 433 px. styles.css:931 ya intenta esconderlo
   por debajo de 1040 px, pero NO PUEDE: su `display: flex` va en el atributo
   style del componente (professional.js), y contra un estilo en línea no hay
   hoja que gane sin `!important`.

   Y el bloque derecho lleva `min-width: max-content` (styles.css:183-184) más
   `flexShrink: 0` en línea, así que tampoco cede: por eso la columna del menú
   se quedaba en 0 px. En el móvil se le permite encoger.

   El estado del mercado no se pierde: la cinta del Panel y la ficha de cada
   valor lo dicen («● PRECIO EN VIVO» / «ÚLTIMO PRECIO · BOLSA CERRADA»). */
@media (max-width: 760px) {
  .top-right-cluster > .market-clock { display: none !important; }
  .top-right, .top-right-cluster { min-width: 0 !important; }
}

/* ── MERCADOS, MACRO Y SEÑALES EN EL MÓVIL (12-sep-2026) ────────────────────
   Las tres pantallas se pintan con rejillas fijas escritas EN LÍNEA sobre
   divs sin clase, así que ninguna hoja podía alcanzarlas. Medido a 375 px
   antes de tocar nada (estudio del móvil, docs/ESTUDIO-MOVIL-11-SEP-2026):

     Mercados  3 columnas →  61 px por tabla de cotizaciones
     Macro     2×2         →  53 px por widget de TradingView
     Señales   6 columnas  →  45 px por KPI, con .kpi en overflow:hidden,
                              o sea cifras CORTADAS, no envueltas

   Ahora cada una lleva su clase real (markets.js, macro.js, signals.js) y
   se apilan aquí. El !important es obligado: compiten contra el atributo
   style del propio div, no contra otra regla. En escritorio no cambia nada.

   Los KPI van de DOS en dos y no de uno en uno: seis cifras en una columna
   son seis pantallas de scroll para el bloque que dice si el servicio
   funciona. A 391 px eso deja ~170 px por caja, de sobra para 18 px. */
@media (max-width: 760px) {
  .screen > .screen-pad { padding-left: 12px !important; padding-right: 12px !important; }
  .mk-movers, .macro-cols, .macro-dos { grid-template-columns: minmax(0, 1fr) !important; }
  /* 15-oct-2026 · El cierre de la «muestra» (demo.js, .demo-cierre) es una
     rejilla de dos columnas escrita en línea: medida a 375 px, 146 + 133 px,
     con el párrafo «La parte que se paga» en la estrecha y la lista de lo que
     incluye el plan en la otra. En el teléfono, una columna. */
  .demo-cierre { grid-template-columns: minmax(0, 1fr) !important; }
  .kpi-6, .form-6 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  /* Y que la cifra no se recorte dentro de su caja, que es lo que hacía. */
  .kpi-6 .kpi { padding: 12px !important; }
  .kpi-6 .value { overflow-wrap: anywhere; }
}

/* ── UNA TIRA DE PESTAÑAS EN 7 px (12-sep-2026) ─────────────────────────────
   Medido en Señales, ventana de 391 px, con los KPI ya arreglados:

     .tabs  «DEL ESCÁNER · MI CUADERNO · COMPARAR»   pide 392 px → tiene 130
     .tabs  «TODAS · ABIERTAS · GANADORAS · PERDEDORAS» pide 338 → tiene   7

   Las dos viven en filas flex junto a vecinos que no ceden (el botón «←
   Volver», el título, el selector de orden y «+ Nueva señal»). La segunda
   además trae `flex: 0 1 0%`, así que se encoge hasta desaparecer: cuatro
   filtros del cuaderno de operaciones en siete píxeles.

   Es el mismo fallo que dejó el menú principal en 0 px, y la misma lección:
   cuando un hijo no cabe, el que tiene que ceder es el padre.

   No se arregla con scroll horizontal: mobile.css:68 ya lo pone, y un scroll
   de 7 px de ancho no lo encuentra nadie. Un `overflow-x` sin pista no es un
   scroll (regla escrita el 3-sep). Aquí caben envolviendo: la tira ocupa su
   propia fila y sus botones bajan de línea. Sin scroll, sin pista que
   inventar y sin nada escondido. */
@media (max-width: 760px) {
  div:has(> .tabs) { flex-wrap: wrap !important; }
  .tabs {
    flex: 1 1 100% !important;
    min-width: 0 !important;
    flex-wrap: wrap !important;
    overflow-x: visible !important;
    row-gap: 6px;
  }
  /* La atribución de TradingView va con `margin-left: auto` en esa misma fila:
     medida a 391 px, se salía 31 px y se leía «POWERED BY TRADINGVIEW ·». No
     se esconde —hay que acreditarlos—: baja a su propia línea. */
  /* Y el padre tiene que dejarla bajar. Primer intento: solo `flex: 1 0 100%`
     en la propia etiqueta — medido después, seguía saliéndose (294 px con el
     borde derecho en 634 de 391), porque su fila tiene `flex-wrap: nowrap` y
     un ancho base del 100 % dentro de una fila que no envuelve solo ensancha
     la fila. Cuando un hijo no cabe, el que cede es el padre. Tercera vez que
     muerde la misma regla en esta sesión: el menú, las pestañas y esto. */
  div:has(> .tv-credito) { flex-wrap: wrap !important; }
  .tv-credito { flex: 1 0 100% !important; margin-left: 0 !important; text-align: right; }
  /* 15-oct-2026 · La tira «Acciones · Divisas · Cripto · Materias primas ·
     Índices · Bonos» del Pulso del mercado del Panel (dashboard.js:300, estilo
     en línea con overflow-x: auto) mide 347 px y pide 511: «Materias primas»
     quedaba cortada en «Materias prim» e «Índices» y «Bonos» fuera, sin pista
     de que se puede arrastrar. Misma receta que las pestañas de arriba:
     envuelve. Medido con la regla puesta: dos filas de 40 px, nada fuera. */
  .dashboard div[style*="gap: 2px"][style*="overflow-x: auto"] { flex-wrap: wrap; overflow-x: visible !important; }
}

/* ── EL MENÚ SE ABRÍA Y NADIE PODÍA TOCARLO (12-sep-2026) ───────────────────
   Drew: «le doy al menú de las 3 líneas y no sale nada». Reproducido en la
   ventana de 391 px, y el panel SÍ se abría:

     nav.nav  display:flex · data-abierto="true" · 391x241 en y=55 · opacidad 1

   Pero al preguntar quién hay en el centro de cada destino:

     Panel    → iframe          TAPADO
     Mercados → span            TAPADO
     Macro    → section.center  TAPADO

   La causa es una regla de este mismo fichero (línea 68): la barra superior
   lleva `overflow-x: auto` para que su contenido nunca empuje la página. Un
   contenedor con overflow RECORTA a sus hijos absolutos, y el panel cuelga del
   header con `top: 100%` — o sea, justo fuera de su caja. Se dibujaba entero y
   se recortaba entero: por eso al tocar no pasaba nada y el dedo aterrizaba en
   el contenido de debajo.

   Ya no hace falta que la barra scrolle: el menú es un panel y el reloj se
   aparta, así que ahí dentro caben la marca, el botón y el bloque derecho
   (medido: 22 + 40 + 193 + huecos = 283 de 367 útiles).

   Y la lección, que es la tercera vez hoy: comprobar que un control EXISTE y
   MIDE bien no es comprobar que se puede tocar. Eso solo lo dice
   elementFromPoint en su centro. */
@media (max-width: 760px) {
  .topbar { overflow: visible !important; z-index: 1200 !important; }
}

/* Destinos que solo existen en el menú del teléfono: en escritorio se llega a
   ellos por la tira lateral del Panel y por el menú del avatar. */
.solo-movil { display: none; }
@media (max-width: 760px) {
  .topbar nav.nav .solo-movil { display: block; }

  /* Y al revés: lo que no cabe en un teléfono. El aviso «Activar precios
     live» mide ~200 px y solo aparece en los navegadores que no tienen la
     clave guardada —o sea, justo en el móvil de un cliente—: empujaba el
     bloque derecho a 407 px y tapaba el botón del menú. Pegar una clave no se
     hace desde el teléfono; la opción vive en Ajustes → API. */
  .solo-escritorio { display: none !important; }

  /* Blindaje: pase lo que pase en ese bloque, no puede volver a invadir el
     hueco de la marca y del menú. Si algún día no cabe, se recorta por su
     lado izquierdo en vez de montarse encima. */
  .top-right { overflow: hidden !important; justify-content: flex-end !important; }
}

/* ── LO QUE NO SE PUEDE TOCAR CON UN DEDO (12-sep-2026) ─────────────────────
   Barrido de los 57 controles del Panel a 391 px, descontando los que ya
   llevan un ::after que amplía su zona (el de PULSE, por ejemplo):

     53 por debajo de 44 px, y el grupo peor son 18 botones de 40x15
     ✕ de cada fila de la lista de seguimiento   40x15   ← borrar un valor
     Ver el historial completo →                201x15
     Todo · < $20 · < $50 · < $100               79x26   ← filtros del escáner

   La ✕ sube a 34 px y no más: la fila mide 41, y una zona que se saliera de
   ella robaría el toque a la fila de al lado — que abre la ficha. Un borrado
   por accidente es peor que un botón pequeño. Es la misma cuenta de los tres
   puntos del radar 13F: el área no puede pisar a la vecina. */
@media (max-width: 760px) {
  /* 15-oct-2026 · El alto subió a 34 el 12-sep, pero el ancho seguía siendo el
     de la columna del cambio diario: la ✕ de borrar un valor medía 9 x 34 px
     (medido con sesión a 375 px, en las ocho filas). La columna es `auto`,
     así que crece con el botón; la fila sigue en 347 px (medido después). */
  .watch-row button { min-height: 34px !important; min-width: 34px !important; }
  .chip-precio { min-height: 40px !important; font-size: 11px !important; }
  .enlace-bloque { min-height: 44px !important; padding: 12px 0 !important; }

  /* El resto del barrido, por grupos medidos:
       barra superior   tema 30x30 · avisos 32x32 · avatar 32x32
       Panel            «Ver análisis completo» 208x33 · la fila de la pick
                        184x31 · «+» 24x24 · «PULSO DEL MERCADO» 233x31
       pulso            Acciones · Divisas · Cripto · Materias primas… 25 px
     Ninguno tiene clase propia, así que se acotan por su contenedor: la barra
     y el Panel. Subir un mínimo no mueve nada de lo que ya llega a 40. */
  .top-right-cluster button, .settings-avatar { min-width: 40px !important; min-height: 40px !important; }
  .dashboard button { min-height: 40px; }
  /* La tira de secciones del Panel (Resumen · Cartera · Lista de seguimiento…)
     se quedaba en 40 px: es el menú por el que pasa cada pantalla del producto
     y el pulgar roza la de al lado. Hallazgo TACT-6 del estudio del móvil. */
  .side .item { min-height: 44px !important; }
  /* 15-oct-2026 · En la ficha, las pestañas del gráfico (TV · GRÁFICO · RSI ·
     MACD · FIBO · VOL · BACKTEST · IA) medían 27 px de alto y los plazos
     (15m · 1h · 1D · 1S · 1M) 20 px: son los mandos de la tarjeta principal.
     Medido con la regla puesta: la cabecera de la tarjeta sigue en 303 px de
     ancho, sin desbordar; solo crece en alto. */
  .analysis .card-title .tabs button { min-height: 36px; }
  .analysis .card-title .actions > span { min-height: 32px; display: inline-flex; align-items: center; }
}

/* ── EL PRECIO DE COMPRA ESTABA DOS PANTALLAS MÁS ABAJO (12-sep-2026) ───────
   La Acción de la Semana es una rejilla de DOS hijos: a la izquierda la
   identidad y el relato, a la derecha el PLAN OPERATIVO. En escritorio van en
   paralelo; en el móvil la rejilla colapsa a una columna y el plan cae al
   final. Medido a 391 px:

     hijo 1 (identidad + razones + estudio + 3 botones)   672 px
     hijo 2 (PLAN OPERATIVO: precio, mejor compra, stop,
             objetivo, R/R y tamaño)                      empieza 684 px abajo

   O sea: el cliente abre el Panel para ver qué comprar y lo primero que
   recibe son cinco razones, el estudio y tres botones; el precio al que hay
   que comprar —lo que paga por ver— llega dos pantallas después.

   Con `display: contents` el hijo 1 deja de ser una caja y sus partes pasan a
   ser celdas de la rejilla, así que se pueden ordenar: símbolo y nombre
   arriba, el plan justo detrás, y las razones, el estudio y los botones
   después. El orden de escritorio no se toca.

   `grid-template-columns: minmax(0,1fr)` es obligatorio: al perder la caja se
   pierde su `min-width: 0`, y una pista «1fr» con contenido largo dentro
   empujaría el ancho del panel. Lo avisó el escéptico del estudio. */
@media (max-width: 900px) {
  .weekly-pick-grid { grid-template-columns: minmax(0, 1fr) !important; }
  .weekly-pick-grid > div:first-child { display: contents; }
  .weekly-pick-grid > div:last-child { order: 2; }
  .weekly-pick-grid > div:first-child > :nth-child(n+3) { order: 3; }
}

/* ── EL CAMPO DONDE ALGUIEN DEJA SU CORREO MEDÍA 24 px (12-sep-2026) ────────
   Medido en la portada a 391 px:

     footer            rejilla de 2 columnas de 160,67 px
     .waitlist         161 px, sin envolver → input 24 px + botón 107

   Veinticuatro píxeles para escribir un correo, en el único sitio de la
   portada donde un visitante deja algo suyo.

   La causa es una regla de este fichero (línea 56) escrita justo para esto:
   `div:has(> .col)` apila las columnas en el móvil… y el pie no es un div, es
   un <footer>. La regla llevaba desde v1 sin aplicarse ahí, y nadie lo vio
   porque no rompe nada: solo encoge.

   De paso, dos zonas de escritura por debajo del mínimo táctil: el propio
   campo del correo y el buscador de la demo (270x21). */
@media (max-width: 760px) {
  footer:has(> .col), section:has(> .col) {
    display: grid !important;
    grid-template-columns: 1fr !important;
    gap: 16px !important;
  }
  .waitlist { flex-wrap: wrap; }
  .waitlist input { flex: 1 1 100% !important; min-width: 0 !important; }
  .waitlist input, .demo-input { min-height: 40px; }

  /* Y la ✕ de los cuadros de diálogo (estado del servicio, nueva contraseña):
     23x17 medidos, por debajo del mínimo de WCAG 2.2. El título mide 48, así
     que 40 cabe sin mover nada. */
  .est-cerrar { min-width: 40px !important; min-height: 40px !important; }
}
/* ═══════════════════════════════════════════════════════════════════════════
   CRIBA DEL ESTUDIO DEL MOVIL · lo que seguia vivo el 13-sep-2026
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── SHELL-02 · SOLO EL PANEL RESERVA HUECO PARA LOS FLOTANTES ──────────────
   flotantes.js:72-73 devuelve los dos botones al llegar al fondo, y dice la
   premisa en voz alta: «Al fondo tambien: ahi no hay texto debajo que tapar».
   En la portada es cierta. En Mercados, Macro, Senales, la ficha de un valor y
   Ajustes, no: ahi los ultimos pixeles son datos.

   El Panel ya esta cubierto —.dashboard { padding-bottom: 76px }, mas arriba
   en este mismo fichero— y era el unico.

   POR QUE .screen Y NO .analysis NI .settings-page. Quien scrollea en
   todas esas pantallas es .screen (styles.css:195 → height:100%,
   overflow:auto), y las otras dos viven DENTRO de el: analysis.js:6610 devuelve
   .screen > .analysis y settings.js:74-76 devuelve .screen > .settings-page.
   Reservar en las tres daria 116 px de vacio al final. Y sobre .screen no
   hace falta !important: ninguna de las ocho hojas declara su padding —
   contra .analysis habria que vencer el atajo con !important de polish.css:66.

   EL NUMERO: .ai-fab vive en bottom:20 con 48 px de alto (estilo en linea de
   assistant.js:513 mas polish.css:580) = 68 px de franja, mas 8 de aire = 76.
   El mismo que ya usa el Panel, a proposito: dos numeros distintos para la
   misma franja es como se calcula mal el siguiente hueco.

   POR QUE AL FINAL DEL FICHERO. Es la correccion al arreglo que trae el
   estudio: un atajo padding: posterior con igual especificidad e importancia
   reescribe el padding-bottom. Escrito antes de la linea 202
   (.center, .right { padding: 16px 12px !important }) quedaria muerto. */
@media (max-width: 760px) {
  .screen { padding-bottom: 76px; }
}

/* ── SHELL-06 · LA SEGUNDA CAUSA, QUE EL ESTUDIO NO VIO ─────────────────────
   Quitar [class*="marquee"] de la linea 68 no basta. Medido en produccion a
   375 px DESPUES de quitarlo, la pista seguia en 296 px:

     .mb-marquee   display flex · flex-shrink 1 · min-width 0px · ancho 296
     .mb-fallback  display flex · overflow hidden

   La pista es un ITEM FLEX dentro de .mb-fallback (professional.js:157). Un
   item flex con contenido nowrap no se encoge porque su min-width automatico
   vale su tamano minimo de contenido… salvo que alguien se lo ponga a cero. Y
   eso lo hace la linea 30 de este mismo fichero: el cortafuegos universal
   #root div { min-width: 0 }, que es la causa nº 1 de que nada desborde y
   aqui trabaja en contra.

   Por eso en ESCRITORIO la cinta va bien: alli ese cortafuegos no aplica.

   Consecuencia: la animacion de polish.css:187 es translateX(-50%) y el
   porcentaje se resuelve contra la caja del PROPIO elemento, asi que sobre
   296 px desplazaba 148 px en vez de los 2.582 que son la mitad de la lista
   duplicada. La cinta se movia un dedo y saltaba al principio.

   Medido despues de esta regla: ancho 5.163 px → translateX(-50%) = 2.582 px,
   exactamente media pista. El recorte lo sigue haciendo el overflow:hidden del
   padre, que es donde tiene que estar.

   !important en las dos: compiten contra el cortafuegos de la linea 30, que no
   lo lleva pero es posterior en especificidad para min-width, y contra el
   flex-shrink por defecto. */
@media (max-width: 760px) {
  .mb-marquee { flex: 0 0 auto !important; min-width: max-content !important; }
}

/* ── capas-3 · EL RECORRIDO DE BIENVENIDA NO SE PUEDE DESPLAZAR ─────────────
   cinematic.css:498 .onb-overlay { position: fixed; inset: 0; display: grid;
   place-items: center; padding: 20px } — SIN overflow, o sea que la capa no
   scrollea; y .onb-card (cinematic.css:506) lleva overflow:hidden. Con
   place-items:center un hijo mas alto que el contenedor desborda por ARRIBA Y
   POR ABAJO a la vez, y en un position:fixed sin overflow ese desbordamiento
   no se recupera con el dedo. «Saltar tour» y «Siguiente» son el ultimo hijo:
   quedan fuera de alcance y no hay salida del tour salvo recargar.

   El hermano ya resuelto es paywall.css:12-13, que si lleva max-height y
   overflow:auto.

   start center es OBLIGATORIO y no es un detalle: con center el trozo que
   desborda por arriba sigue siendo inalcanzable aunque el contenedor scrollee.

   Sin !important: misma especificidad (0,1,0) que cinematic.css:498 y :668, y
   esta hoja carga la ultima. Se omite .onb-card { max-height: none } del
   arreglo propuesto: es un no-op, .onb-card nunca tuvo max-height.

   NO CUBIERTO DESDE AQUI: onboarding.js:40 abre el teclado del telefono solo
   (autoFocus), y es lo que reduce el area visible a 400-500 px y convierte un
   desbordamiento «por poco» en uno seguro. Eso exige tocar onboarding.js. */
@media (max-width: 760px) {
  .onb-overlay { place-items: start center; overflow-y: auto; }
  /* 15-oct-2026 · Con 120 px el dibujo de bienvenida no cabía: .onb-art mide
     157 px de contenido (la cinta, seis chips y el pie «Se queda en tu lista
     de seguimiento…») y cinematic.css le da el 80 % del alto del marco, así
     que el pie se cortaba a media línea (medido a 375 px: marco de 158 px y
     pie hasta 194). Con 200, el pie termina en 224 dentro de un marco que
     acaba en 245; la tarjeta mide 640 px, cabe en 812 y la capa ya desplaza. */
  .onb-art-wrap { min-height: 200px; }
}

/* ── ficha-1 · «ZONA DE ENTRADA» SE CORTA CON PUNTOS SUSPENSIVOS ────────────
   tradeplan.js:184 pinta el valor con whiteSpace:nowrap + overflow:hidden +
   textOverflow:ellipsis. El cliente lee «$211,28 – $2…»: no hay scroll ni zoom
   que lo rescate, porque el texto no esta oculto, esta RECORTADO por CSS, y
   tampoco hay senal de que le falte un numero. Es el techo de la zona de
   compra, en la tarjeta por la que paga.

   Las cuentas: la rejilla es repeat(auto-fit, minmax(150px, 1fr))
   (tradeplan.js:221), o sea dos columnas a 375 px; menos el padding 12/14 de
   la caja y el borde quedan ~124 px para «$211,28 – $225,23», que en
   monoespaciada de 15 px pide 140-153. No cabe ni en el caso mas favorable.

   EL ANCLA. El arreglo del estudio usaba [style*="font-size: 15px"], que se
   rompe el dia que alguien cambie el 15 por un 15,5 o por una variable. Se usa
   text-overflow en su lugar: grep -c textOverflow tradeplan.js = 1, asi que
   es el unico elemento del fichero que lo declara y el ancla describe el
   defecto en vez de una medida que puede cambiar.

   !important obligatorio: las tres propiedades van en el atributo style, y
   contra un estilo en linea no hay especificidad que valga.

   Al envolver, el rango parte por el espacio del guion («$211,28 –» arriba,
   «$225,23» abajo): nunca entre una cifra y su moneda, porque ahi no hay
   espacio. NO CUBIERTO: en escritorio, con auto-fit salen 4-5 columnas de
   ~170 px y el recorte se reproduce igual. Eso es tradeplan.js:184. */
@media (max-width: 760px) {
  [data-comment-anchor="trade-plan"] .mono[style*="text-overflow"] {
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
    line-height: 1.25;
  }
}

/* ── ficha-3 · REJILLAS DE METRICAS DE 4 Y 5 COLUMNAS FIJAS ─────────────────
   analysis.js escribe repeat(4, 1fr) cuatro veces y repeat(5, 1fr) una,
   todas en el atributo style. Cuentas a 375 px sobre la peor (analysis.js:7896,
   el resumen tecnico: RSI / vs MA50 / vs MA200 / Desde max 52S): 311 px de
   tarjeta menos 3 huecos de 8 = 287, entre 4 = 71,75 por celda; menos el
   padding 12/14 y el borde = 41,75 px de texto para un valor a 18 px
   monoespaciado que pide 65-70. Y styles.css:1704 SUBE las etiquetas de 9 a
   11 px en movil, asi que «Desde max 52S» ocupa mas, no menos.

   minmax(0, 1fr) y no 1fr: al perder el ancho intrinseco la celda tiene que
   poder encoger. La linea 30 de este fichero (#root div { min-width: 0 }) ya
   lo cubriria, pero explicito es mejor que dependiente de otra regla.

   SIN prefijo .analysis a proposito: analysis.js:1141 esta dentro de
   BacktestPanel, un componente distinto, y el prefijo podria no alcanzarlo.
   Comprobado el radio de accion: repeat(4, 1fr) y repeat(5, 1fr) solo
   existen en analysis.js — la unica aparicion de landing.js esta dentro de un
   COMENTARIO (landing.js:1551), que no llega al DOM.

   Efecto colateral asumido y declarado: tambien alcanza la cinta de cuatro
   etapas de analysis.js:7534 (BASE/AVANCE/...). Pasar a 2x2 es justo lo que
   polish.css:74 queria para .stage-strip — la regla que nunca llego a
   aplicarse porque esa clase no existe.

   !important obligatorio: compite contra el atributo style, no contra otra
   regla de hoja. */
@media (max-width: 760px) {
  #root div[style*="grid-template-columns: repeat(4"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  #root div[style*="grid-template-columns: repeat(5"] { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
  /* 15-oct-2026 · quantkit.js:793 escribe la rejilla de la zona de compra por
     volumen como `1fr 1fr 1fr 1fr` (sin repeat), así que la regla de arriba no
     la ve: a 375 px son cuatro columnas de 58 px con «$135,75–$139,4»,
     «INVALIDACIÓN POR VOLUMEN» y «$112,48» dentro (74-102 px de contenido
     por celda, medido): cifras cortadas. De dos en dos, como el resto. */
  .analysis div[style*="grid-template-columns: 1fr 1fr 1fr 1fr"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}

/* ── H6 · LAS FILAS DEL HISTORIAL SE PARTEN EN TRES Y EL VEREDICTO QUEDA
       HUERFANO A LA IZQUIERDA ──────────────────────────────────────────────
   historial.js:337-347 es un flex con flexWrap:"wrap" y seis hijos con ancho
   minimo: 62 + 46 + 54 + 190 + 62 + 70 = 484, mas 5 huecos de 10 = 534 px
   necesarios frente a los ~319 disponibles. La fila se parte en TRES lineas y
   en la tercera el textAlign: "right" de historial.js:382 y :397 es INERTE:
   alinea a la derecha dentro de una caja de 62 y 70 px que esta pegada al
   borde izquierdo. Asi que el «✕ STOP» / «✓ OBJETIVO» —la respuesta a «¿esto
   me ha servido de algo?»— aparece suelto y sin relacion visual con el ticker
   que esta dos lineas mas arriba.

   La fila no tiene clase; se engancha por su unico hijo con base 190 px. Se
   usa [style*="190px"] y no la forma completa flex: 1 1 190px porque esta
   depende de como serialice el navegador el atajo flex. Comprobado el radio
   de accion: 190px sale en cuatro ficheros, pero los de markets.js y
   simulator.js son minmax(190px, 1fr) sobre divs y el de waitlist.js es un
   input — el selector exige > span, asi que solo casa historial.js:372.

   :has() ya se usa cinco veces en este fichero; no introduce ningun requisito
   de navegador que el proyecto no asuma ya. !important porque compite contra
   el atributo style de la fila (historial.js:339). */
@media (max-width: 760px) {
  #root div:has(> span[style*="190px"]) {
    justify-content: space-between !important;
    row-gap: 2px !important;
  }
}

/* ── TACT-5 · ESTE FICHERO ROMPE EL INTERRUPTOR MENSUAL/ANUAL ───────────────
   Medido HOY en produccion a 375 px: .pricing-toggle-btn mide 44x42. Deberia
   medir 44x24 (styles.css:1194), y su bolita esta posicionada contra ese alto
   (styles.css:1204 → top: 3px): al estirar la caja a 42 px la bolita se queda
   pegada al borde superior. Es el control que decide si el visitante ve el
   precio mensual o el anual, justo en el momento de decidir la compra.

   La culpa es de la linea 110 de este mismo fichero:
   button[class*="btn"] es una SUBCADENA, no una palabra, y casa con
   «pricing-toggle-btn».

   OJO CON LA ESPECIFICIDAD: el estudio daba por hecho un empate y no lo hay.
   button[class*="btn"] es (0,1,1) y le gana a .pricing-toggle-btn (0,1,0)
   aunque vaya despues. Por eso aqui se escribe button.pricing-toggle-btn
   —tambien (0,1,1)—, que empata y gana por orden, sin necesidad de !important.

   El area de toque se amplia con un ::before invisible (styles.css solo usa
   ::after para la bolita): 44+12 x 24+22 sin mover ni un pixel del dibujo.

   NO CUBIERTO: los rotulos «Mensual» y «Anual» siguen sin onClick
   (landing.js:2316 y :2327). Eso es JS. */
@media (max-width: 760px) {
  button.pricing-toggle-btn { min-height: 24px; }
  .pricing-toggle-btn::before {
    content: ""; position: absolute;
    top: -11px; bottom: -11px; left: -6px; right: -6px;
  }
}

/* ── LAND-03 + LAND-04 · LOS 11 ENCABEZADOS DE SECCION DE LA PORTADA ────────
   Medido en produccion a 375 px, no deducido:

     .section-head   n = 11 · margin-top 96 · padding-top 40 · margin-bottom 28
                     display: flex · padding-left 16

   styles.css:990, dentro del @media (max-width: 768px) que abre en :980, anade
   40 px de relleno superior y NO toca el margin: 96px 0 28px de la linea 548.
   164 px de aire por encabezado x 11 = 1.804 px, mas de dos pantallas de 812.
   Y ese padding: 40px 16px 0 mete 16 px laterales que el resto del contenido
   no tiene (.landing lleva 18 de polish.css:45), asi que los titulares
   quedan visiblemente a la derecha de las tarjetas de debajo.

   Y sigue siendo una fila flex sin wrap (LAND-04): el h2 y su etiqueta se
   pelean por 339 px, asi que «Preguntas que oimos justo antes de que alguien se
   suscribe» (landing.js:2517) se parte en cuatro o cinco lineas en media
   columna. El h2 no se beneficia del cortafuegos de la linea 30 porque no es un
   div: conserva min-width:auto.

   EL CORTE ES 768 Y NO 760 A PROPOSITO: la regla defectuosa vive en el bloque
   de 768 de styles.css. Con 760 se dejaba la franja 761-768 intacta. Sigue muy
   por debajo de 900, asi que el escritorio no se toca.

   Sin !important: misma especificidad (0,1,0) que styles.css:548 y :990, y
   esta hoja carga despues. */
@media (max-width: 768px) {
  .section-head { display: block; margin: 40px 0 16px; padding: 0 0 12px; }
  .section-head h2 { margin: 0 0 8px; }
}

/* ── H3 · SENALES: EL UNICO OVERRIDE MOVIL DE ESA PANTALLA ESTA MUERTO ──────
   signals.js:1384 pinta className: "analysis-wrap" con padding: "24px 28px"
   EN LINEA. styles.css:1373 escribio hace tiempo .analysis-wrap { padding:
   12px } dentro de su @media de 768 y no hace nada: una declaracion en linea
   sin !important gana a cualquier declaracion de hoja sin !important, con
   independencia del orden de carga y de la especificidad.

   Lo peor para el proyecto no son los 56 de 375 px (el 15 %) que se van en
   margenes en la pantalla con la tabla mas ancha del producto (minWidth 880):
   es que en el codigo PARECE resuelto, asi que nadie lo vuelve a mirar.

   El !important no es cosmetico: es lo unico que permite ganar al atributo
   style. Y el corte es 768, el mismo que apuntaba styles.css:1373, para no
   dejar viva la franja 761-768. */
@media (max-width: 768px) {
  .analysis-wrap { padding: 12px !important; }

  /* ── SEÑALES: EL CUADERNO, EN EL TELÉFONO, DEJA DE SER UNA TABLA (15-oct-2026)
     signals.js:1386 pinta la lista con `minWidth: 980` dentro de un div con
     overflow-x: auto. Medido con sesión a 375 px: 980 px de tabla en 341 de
     caja; se ven VALOR, EMITIDA y SETUP, y quedan fuera los puntos, la zona
     de compra, el stop, el objetivo, el estado, la revisión y los días: lo
     que dice si la señal sirvió. Y en un teléfono no hay barra que insinúe
     el arrastre. Misma receta que el historial de la portada (polish.css):
     cada señal es una ficha con sus once campos rotulados.
     Los rótulos salen de la cabecera real de signals.js, en su orden: si
     alguien añade o mueve una columna hay que tocar esto a la vez. Los
     !important son obligados: padding, white-space, text-align y el borde van
     en el atributo style de cada celda. Medido con la regla puesta: 341 px de
     tabla en 341 de caja, 353 px por señal, nada fuera de 375. */
  .analysis-wrap div:has(> table[style*="min-width: 980px"]) { overflow: visible !important; border: 0 !important; }
  .analysis-wrap table[style*="min-width: 980px"] { min-width: 0 !important; display: block; overflow: visible; }
  .analysis-wrap table[style*="min-width: 980px"] thead { display: none; }
  .analysis-wrap table[style*="min-width: 980px"] tbody { display: block; }
  .analysis-wrap table[style*="min-width: 980px"] tbody tr { display: block; border: 1px solid var(--line-soft); border-radius: 12px; padding: 4px 12px; margin-bottom: 10px; }
  .analysis-wrap table[style*="min-width: 980px"] tbody td { display: block; position: relative; padding: 7px 0 7px 128px !important; min-height: 18px; text-align: left !important; white-space: normal !important; border-bottom: 1px solid var(--line-soft) !important; }
  .analysis-wrap table[style*="min-width: 980px"] tbody td:last-child { border-bottom: 0 !important; }
  .analysis-wrap table[style*="min-width: 980px"] tbody td::before { position: absolute; left: 0; top: 8px; width: 116px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(1)::before { content: "Valor"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(2)::before { content: "Emitida"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(3)::before { content: "Setup"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(4)::before { content: "Puntos"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(5)::before { content: "Zona de compra"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(6)::before { content: "Stop"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(7)::before { content: "Objetivo"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(8)::before { content: "Estado"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(9)::before { content: "Desde entonces"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(10)::before { content: "Revisión"; }
  .analysis-wrap table[style*="min-width: 980px"] td:nth-child(11)::before { content: "Días"; }
}

/* ── H5 · LAS DOS CONTRASENAS NUEVAS, EN DOS COLUMNAS DE 142 px ─────────────
   settings.js:891-902 pone los dos campos en 1fr 1fr sin ningun <label>: el
   placeholder es lo UNICO que distingue uno del otro. Cuentas a 375 px: 142,5
   px por input, menos el padding 9/12 y el borde = 116,5 px de caja de texto…
   y la tipografia no es la de launch.css:324 (13 px) sino los 16 px que fuerza
   la linea 111 de este fichero para evitar el auto-zoom de iOS. «Nueva
   contrasena» son 16 caracteres: no entra. «Repitela» si. O sea dos casillas
   de puntos identicas, la primera con el rotulo cortado y la segunda pidiendo
   repetir algo que ya no se sabe que era, en el flujo de cambio de contrasena
   de una cuenta de pago.

   ACOTADO A AJUSTES A PROPOSITO. El arreglo que proponia el estudio
   (#root div[style*="grid-template-columns: 1fr 1fr"]) alcanza 15 rejillas en
   linea de analysis.js, dashboard.js, macro.js, paywall.js y regimen.js, muchas
   de ellas pares de cifras compactas que el proyecto mantiene DELIBERADAMENTE a
   dos columnas en movil. Apilar media aplicacion por un placeholder de 116 px
   no sale a cuenta.

   El arreglo de fondo es poner <label> en vez de fiar la etiqueta al
   placeholder, pero eso ya no es maquetacion movil: es settings.js. */
@media (max-width: 760px) {
  .settings-section-body > div[style*="grid-template-columns: 1fr 1fr"] {
    grid-template-columns: minmax(0, 1fr) !important;
  }
}

/* ── capas-5 · LOS DIALOGOS DE estado.js Y nueva-clave.js SE RECORTAN ───────
   styles.css:1600 .est-caja { width: 100%; max-width: 460px; ... overflow:
   hidden; } — overflow:hidden SIN max-height, dentro de .est-capa, que es
   display: grid; place-items: center; padding: 20px. Es el mismo patron que
   deja el recorrido de bienvenida sin scroll: si la lista de servicios crece,
   las ultimas filas y el pie «Comprobado hace…» se cortan sin que nada indique
   que hay mas.

   overflow-y: auto y no overflow: auto: el hidden del eje X se conserva,
   que es lo que respeta el border-radius de la caja.

   Sin !important: misma especificidad (0,1,0) y esta hoja carga la ultima.

   NO CUBIERTO DESDE AQUI: estado.js:143 y nueva-clave.js:187 siguen sin
   aria-modal="true", asi que la regla de polish.css:753 que aparta los tres
   botones flotantes no se activa y siguen dibujados tras el velo. nueva-clave.js:82
   SI lo tiene ya. Es un atributo por linea, en JS. */
@media (max-width: 760px) {
  .est-caja { max-height: calc(100vh - 40px); overflow-y: auto; }
}

/* ── capas-2 · LA ✕ DEL MURO DE PAGO MIDE 32 px ─────────────────────────────
   paywall.css:22 .pw-x { position: absolute; top:16px; right:16px; width:32px;
   height:32px }, 12 por debajo del minimo de WCAG 2.2 (2.5.8) y de los 44 que
   piden Apple y Google. Sube a 44, que es el mismo criterio que este fichero ya
   aplica a .est-cerrar en la linea 518.

   HONESTIDAD SOBRE EL ALCANCE: el escéptico del estudio TUMBO la parte grave de
   este hallazgo y tenia razon — el modal tiene un boton «Ahora no» a ancho
   completo en el pie (paywall.js:1168), cierre por Escape (paywall.js:727) y
   cierre tocando el fondo, asi que nadie se queda encerrado. Lo que queda en
   pie es el tamano, y es lo que se arregla.

   LA OTRA MITAD NO SE PUEDE ARREGLAR DESDE AQUI: la ✕ es absolute DENTRO del
   contenedor que scrollea (.pw-card, paywall.css:10, overflow:auto), asi que
   se va hacia arriba con el contenido. Sacarla de ese contenedor es paywall.js;
   forzarla a sticky desde la hoja le quita el anclaje a la esquina. */
@media (max-width: 760px) {
  .pw-x { min-width: 44px !important; min-height: 44px !important; }
}

/* ── PICK-5 · LOS BOTONES DE LA ACCION DE LA SEMANA NO LLEVAN className ─────
   «Ver analisis completo», «Simular compra» y «↓ Descargar PDF»
   (dashboard.js:3061, :3091 y :3154) se crean SIN className, asi que la regla
   tactil de la linea 110 de este fichero —.btn, button[class*="btn"]— no los
   ve. 9+9 de relleno sobre una linea de 13 px ≈ 35 px de alto; los chips de
   «TAMBIEN A PUNTO DE ROMPER» (dashboard.js:3318) se quedan en ~30. Por debajo
   del minimo de 42 que el propio proyecto se fijo.

   Contraste dentro del MISMO componente: los chips del panel de hoy si llevan
   className: "btn btn-ghost" (dashboard.js:2654) y por eso esos si lo reciben.

   margin-left: 0 !important es obligatorio y no es cosmetico: «Simular
   compra» y «Descargar PDF» llevan marginLeft: 10 en linea, asi que al
   envolver a su propia linea quedaban sangrados 10 px respecto al primero.
   min-height no lo necesita: no esta declarado en linea en ninguno de los
   tres. */
@media (max-width: 760px) {
  .weekly-pick-grid button { min-height: 44px; margin-left: 0 !important; }
}

/* ── AREA SEGURA DEL TELEFONO (14-sep-2026) ─────────────────────────────
   `index.html` pasa a declarar `viewport-fit=cover`, que es lo que hace que
   `env(safe-area-inset-*)` deje de valer 0. Hasta hoy la unica linea que la
   usaba —`body { padding-bottom: env(...) }`, mas arriba en este fichero—
   no hacia nada: sin el atributo la medida no llega, y ademas un padding del
   body no mueve un `position: fixed`.

   Con el contenido ya a borde completo, lo que queda pegado abajo tiene que
   apartarse de la barra de inicio. Son tres botones fijos y las dos reservas
   de hueco que se pusieron el 13-sep para que los flotantes no tapen la
   ultima linea al llegar al fondo.

   El `0px` de respaldo hace que en un telefono sin muesca la cuenta de
   exactamente el valor anterior: este bloque no puede romper nada donde no
   hay area segura. Y sin respaldo, un `env()` desconocido invalidaria el
   `calc` entero y la declaracion se perderia sin dar error. */
@media (max-width: 760px) {
  /* Los dos botones llevan el `bottom` en estilo EN LINEA (assistant.js:510
     y support.js), y un estilo en linea gana a la hoja: el !important no es
     opcional aqui. */
  .ai-fab { bottom: calc(20px + env(safe-area-inset-bottom, 0px)) !important; }
  .gen-soporte-fab { bottom: calc(84px + env(safe-area-inset-bottom, 0px)) !important; }
  .pulse { bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important; }

  /* Y el hueco reservado crece lo mismo, o la ultima linea vuelve a quedar
     debajo de los botones justo donde `flotantes.js` los devuelve. */
  .dashboard { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important; }
  .screen { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
}

/* ── AUDITORÍA DE DISEÑO DEL 8-OCT-2026 (medida en producción a 375×812) ── */
@media (max-width: 760px) {
  /* La ficha: «COMPRAR» a 32 px medía 191 px en una celda de 168 y pisaba
     45 px a la tarjeta de al lado («FUNDAMENTAL 80»). */
  .verdict > div { padding: 14px 12px !important; }
  .verdict .v { font-size: 20px !important; letter-spacing: -0.01em; overflow-wrap: anywhere; }

  /* Lo que se pulsa mide al menos 44 px de alto: los botones de la portada
     estaban en 42, la hamburguesa en 40 y «Activar» en 25. Solo en la portada,
     el registro y la cabecera: dentro de la aplicación hay botones pequeños a
     propósito, en tablas y filtros. */
  .landing .btn, .auth-card .btn, .cta-visitante { min-height: 44px; }
  .nav-burger { min-width: 44px; min-height: 44px; }
  .gen-tv-retenido button { min-height: 36px; padding: 6px 14px !important; }
  .footer a, .footer button { min-height: 40px; display: inline-flex; align-items: center; }
  .auth-card .auth-back, .auth-card .auth-check a, .auth-card .auth-switch a, .auth-card .auth-switch button { padding-top: 10px; padding-bottom: 10px; }

  /* La barra horizontal fantasma del pie: `.screen` medía 430 px de contenido
     en 365 de ancho y no se podía arrastrar. Se recorta lo que sobra. */
  .screen { overflow-x: clip !important; }
}

/* ── ALERTAS EN EL TELÉFONO (8-oct-2026) ─────────────────────────────────────
   La pantalla trae 32 px de margen lateral escritos en línea y se medía por
   fuera de la caja: 435 px de ancho en una pantalla de 375. «+ Nueva alerta»
   quedaba 59 px fuera y la ✕ de cada alerta, 30: no se podían pulsar enteras.
   (Y `.screen` recorta lo que sobra, así que ni se veía ni se podía arrastrar.) */
@media (max-width: 760px) {
  .pantalla-alertas { box-sizing: border-box; padding: 18px 14px !important; }
  .pantalla-alertas > div { flex-wrap: wrap; row-gap: 8px; }
  .pantalla-alertas .alertas-cabecera > div:last-child { margin-left: 0 !important; width: 100%; }
  .pantalla-alertas .alertas-cabecera > div:last-child > button { flex: 1 1 auto; min-height: 44px; }
}

/* El suelo de 11 px del móvil (styles.css) busca «font-size: 9px», con espacio,
   que es como lo escribe React. Lo que se inyecta como HTML en la ficha lo
   escribe sin espacio y se quedaba en 9: 69 textos por debajo de 11 px. */
@media (max-width: 760px) {
  [style*="font-size:7px"], [style*="font-size:7.5px"], [style*="font-size:8px"], [style*="font-size:8.5px"],
  [style*="font-size:9px"], [style*="font-size:9.5px"], [style*="font-size:10px"], [style*="font-size:10.5px"] { font-size: 11px !important; }
  /* 15-oct-2026 · Las etiquetas de los KPI del Panel («Valor del portafolio ·
     USD», «Coste base», «Rentabilidad total», «Capital virtual»…) van a 9 px
     con !important desde styles.css:1538; el bloque móvil de styles.css:1742
     quiere 11,5 px pero sin !important y pierde. Suelo de 11 px, como todo. */
  .kpi-row .kpi .label { font-size: 11px !important; }
}

/* ── LA TABLA DE COMPARABLES CABE EN EL MÓVIL (9-oct-2026) ─────────────────
   Seis columnas en 279 px: RSI y la distancia a la media de 50 quedaban
   fuera sin avisar. En el teléfono se quitan las de 1 y 3 meses (3.ª y 4.ª):
   lo que queda es lo que la tarjeta compara. */
@media (max-width: 640px) {
  .tabla-comparables table { min-width: 0 !important; }
  .tabla-comparables th:nth-child(3), .tabla-comparables td:nth-child(3),
  .tabla-comparables th:nth-child(4), .tabla-comparables td:nth-child(4) { display: none; }
}

/* ── LOS FLOTANTES, EN UNA FILA ABAJO A LA DERECHA (15-oct-2026) ─────────────
   La evaluación independiente del 12-oct (apartado 3, punto 12) lo midió a
   375×812: «IA» abajo a la izquierda, «?» encima de él y PULSE abajo a la
   derecha tapaban la tarjeta de la Acción de la Semana en el Panel y la
   cabecera de la ficha de un fondo. Medido aquí antes de tocar nada, en el
   Panel con la tarjeta de la pick al pie de la pantalla (x · y en píxeles):

     IA      20-68   · 744-792  → tapaba «ACCIÓN DE LA SEMANA · …»
     ?       20-66   · 682-728  → tapaba el texto de «Hoy en GENERACYE»
     PULSE   282-363 · 767-800  → tapaba «ÚLTIMA EMITIDA · 2026-W41 (…)»
     Q       305-357 · 702-754  → solo en la ficha: tapaba «Anclado a precio real»

   Dos columnas en las dos esquinas de abajo son 110 px de alto ocupados a
   cada lado de la columna de texto. Ahora los cuatro van en UNA fila de 48 px
   pegada al borde inferior derecho, con 8 px entre ellos (medido después):

     IA 315-363 · ? 259-307 · Q 203-251 · PULSE 114-195, todos en y 752-800

   La reserva de hueco al final de cada pantalla (.screen y .dashboard, 76 px,
   más arriba en este fichero) ya cubre los 60 px de la fila, así que la
   última línea sigue libre. Ninguno lleva ya `left`, por lo que la fila no
   puede sacar nada por la derecha (medido: scrollWidth 375 en 375).

   POR QUÉ CON !important Y AL FINAL DEL FICHERO. Los cuatro llevan su posición
   en estilo EN LÍNEA (assistant.js, support.js, godtier.js) y las tres líneas
   de «ÁREA SEGURA DEL TELÉFONO» de más arriba fijan `bottom` también con
   !important: a igual importancia y especificidad gana la última, y por eso
   este bloque va después y manda sobre ellas. Los huecos entre botones los
   cierra `:has()`, que polish.css ya usa para estos mismos botones: «?» solo
   existe con sesión y «Q» solo en la ficha. Sin :has() (navegadores de antes
   de 2023) cada uno conserva su sitio fijo: queda un hueco, nunca un solape.

   Y PULSE plegado pasa de 33 a 44 px de alto: la zona táctil ampliada de su
   botón (pulse.css, un ::after de 44 px) quedaba recortada por el
   `overflow: hidden` del propio widget, así que con el pulgar eran 33 px. */
@media (max-width: 760px) {
  .ai-fab, .gen-soporte-fab, .gen-quant-fab, .pulse.collapsed {
    left: auto !important;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
  }
  /* Los tres botones redondos miden 48 (el «?» medía 46 y «Q» 52): con el
     mismo ancho la cuenta de los huecos es una sola: 12 + 48 + 8 = 68, etc. */
  .ai-fab { right: 12px !important; }
  .gen-soporte-fab { right: 68px !important; width: 48px !important; height: 48px !important; }
  .gen-quant-fab { right: 124px !important; width: 48px !important; height: 48px !important; }
  .pulse.collapsed {
    right: 180px !important;
    min-height: 44px; box-sizing: border-box;
    display: flex; align-items: center; justify-content: center;
  }
  body:not(:has(.gen-soporte-fab)) .gen-quant-fab { right: 68px !important; }
  body:not(:has(.gen-soporte-fab)) .pulse.collapsed,
  body:not(:has(.gen-quant-fab)) .pulse.collapsed { right: 124px !important; }
  body:not(:has(.gen-soporte-fab)):not(:has(.gen-quant-fab)) .pulse.collapsed { right: 68px !important; }
  /* PULSE desplegado se queda ENCIMA de la fila (compartía esquina con ella y
     los botones tapaban su fila de índices) y ya puede usar todo el ancho:
     no queda nada en la esquina de la izquierda que respetar. */
  .pulse:not(.collapsed) {
    bottom: calc(68px + env(safe-area-inset-bottom, 0px)) !important;
    max-width: calc(100vw - 24px) !important;
  }
  /* La ventana del agente «Q» (godtier.js, en línea: right 18, width 400,
     height calc(100vh - 110px)) se salía 18 px por la izquierda y su pie
     quedaba debajo de la fila. Ahora va de borde a borde con 12 px y termina
     72 px por encima del suelo, es decir, por encima de los botones. */
  .gen-quant-fab + div {
    left: 12px !important; right: 12px !important; width: auto !important;
    height: auto !important;
    bottom: calc(72px + env(safe-area-inset-bottom, 0px)) !important;
  }
}
