/* ==========================================================
   ZENT — Tokens de diseño (refinamiento estricto según DESIGN.md)
   Sistema visual Linear.app sobre la app:
   - Canvas profundo + escalera de superficies (sin sombras de marca).
   - Hairline de 1px en tarjetas/dividers; radios compactos.
   - Único acento cromático de marca: lavanda #5e6ad2 (CTA, focus, links).
   - Los colores de categoría (cyan eventos / ámbar racha) actúan
     como etiquetas discretas de producto, no como acentos de marca.
   ========================================================== */
:root {
  color-scheme: light;
  --color-bg:           #FBFBFD;          /* inverse-canvas sedoso */
  --color-surface:      #FFFFFF;          /* inverse-surface-1 */
  --color-surface-2:    #F5F6F6;          /* inverse-surface-2 */
  --color-surface-3:    #EFEFF1;
  --color-border:       #E7E9EC;          /* hairline */
  --color-border-strong:#DBDEE3;          /* hairline-strong */
  --color-overlay:      rgba(17, 18, 22, 0.45);

  --color-primary:        #5e6ad2;        /* Linear lavender - marca */
  --color-primary-hover:  #515dd0;
  --color-primary-focus:  #5e69d1;
  --color-primary-soft:   #EEF0FB;
  --color-focus-ring:     rgba(94, 105, 209, 0.5);
  --color-secondary:      #7C9C8C;        /* salvia - tranquilidad */
  --color-secondary-soft: #EAF0EB;
  --color-accent:         #E0A458;        /* ámbar - motivación / racha */
  --color-accent-soft:    #FBEEDC;

  --color-events-accent:      #4A6357;
  --color-events-accent-soft: rgba(124, 156, 140, 0.14);
  --color-tasks-accent:       #5e6ad2;
  --color-tasks-accent-soft:  var(--color-primary-soft);

  --color-text:       #17181C;            /* ink */
  /* Oscurecido de #6C7380 a #656C78. El anterior cumplia AA sobre
     --color-bg (4.62:1) pero se caia en las dos superficies mas oscuras:
     4.41:1 sobre --color-surface-2 y 4.15:1 sobre --color-surface-3, por
     debajo del 4.5:1 que WCAG AA pide para texto normal. Como hay texto
     atenuado sobre esas superficies, el fallo era real y no teorico. Este
     valor deja el peor caso en 4.61:1 y no obliga a tocar ninguna
     superficie, que es lo mas barato de arreglar. */
  --color-text-muted: #656C78;            /* ink-muted, AA sobre las 4 superficies */
  --color-danger:     #C03A2F;

  /* Calendarios: color de los puntos de calendario y color de los avisos de
     "un calendario no se pudo leer". Es ámbar y no rojo a propósito: no es un
     error de la app ni un fallo de red, es un dato que falta, y un rojo haría
     pensar que Zent está roto. Como tampoco es un estado de error de la UI
     existente, se declara aquí. */
  --cal-fallback:     #B26A00;

  /* Linear usa su propia sans; el sustituto recomendado es Inter. */
  --font-display: "Inter", -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  --font-body:    "Inter", -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;

  /* La mono se usaba como `var(--font-mono, ui-monospace, monospace)` en el
     único sitio que la necesitaba, así que el valor de verdad vivía dentro de
     la regla y no se podía reutilizar ni cambiar desde `:root`. Se sube aquí
     para que sea una variable del sistema, como las otras dos.

     Se mantienen los tres niveles de respaldo a propósito: `ui-monospace` es lo
     que da la fuente del sistema (SF Mono en Apple, Cascadia en Windows) y solo
     existe en navegadores modernos; `monospace` es la palabra clave CSS, que no
     puede faltar nunca y termina en la misma fuente por defecto del sistema
     si los dos anteriores no existen. Los tres van sin comillas porque son
     nombres genéricos, no familias concretas. */
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono",
               Menlo, Consolas, monospace;

  /* Escala tipografica. Antes habia 21 tamanos en `rem` escritos a mano
     (0.62, 0.68, 0.7, 0.72, 0.75, 0.76, 0.78, 0.8, 0.82, 0.83, 0.85, 0.875,
     0.92, 0.98, 1.0, 1.02, 1.05, 1.2, 1.3, 1.55, 2.6...), de los que seis
     valores distintos eran el mismo numero escrito de otra manera. Con eso no
     se puede cambiar el cuerpo de texto sin recorrer media hoja.

     Se definen solo los seis niveles que ya existen en el producto. La
     escala no va mas alla a proposito: anadir niveles que nadie usa invite a
     inventar el siguiente en la siguiente regla.

     `xs` es el suelo legible. Antes el texto mas pequeno de la app era
     0.62rem (los chips dentro de `.event-chips`), que a 360 px de ancho es
     por debajo de lo que se considera comfortable; 0.75rem sigue siendo
     denso pero se lee. Por eso el multiplicador de abajo no baja de 0.9: a
     esa escala el suelo queda en 0.675rem, que se lee, y a 0.8 se caeria al
     suelo que la Fase A.Sequero levantar y que este ajuste no puede volver a
     tirar.

     Los seis multiplican `--font-scale`, que es lo que hace funcionar el
     ajuste de tamano de letra de Ajustes. Va con `calc()` en los seis, y no
     en un unico sitio mas abajo, porque si el multiplicador viviera solo en
     `body` los elementos con `font-size` en `rem` de un subarbol —los chips
     de una tarjeta, las celdas del timeline— se calcularian contra la raiz y
     no se escalarian. Multiplicando el token, TODO lo que usa la escala se
     mueve a la vez, y un ajuste de lectura no deja partes sin escalar.

     `--font-scale` lo pone en linea `js/apariencia.js` sobre `<html>`, antes
     del primer pintado: asi no hay un instante en el que se ve una cosa y
     acto seguido otra. Este `1` de aqui es el valor por defecto para cuando no
     hay JS, no un valor que se pueda quitar. */

  --font-scale: 1;
  --font-size-xs:   calc(0.75rem   * var(--font-scale));  /* chips, etiquetas muy cortas */
  --font-size-sm:   calc(0.8125rem * var(--font-scale));  /* descripciones, pestanas */
  --font-size-base: calc(0.875rem  * var(--font-scale));  /* botones y cuerpo de la interfaz */
  --font-size-md:   calc(1rem      * var(--font-scale));  /* input, texto de formulario */
  --font-size-lg:   calc(1.25rem   * var(--font-scale));  /* subtitulos, cifras destacadas */
  --font-size-xl:   calc(1.6rem    * var(--font-scale));  /* titulos de seccion */

  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-pill: 999px;
  --shadow-soft: 0 1px 2px rgba(23, 24, 28, 0.05);
  --glass-blur: none;

  /* Movimiento: solo transform/opacity, 150-250 ms, sin rebotes.
     Único cambio de idioma se permite 50 ms (micro-cambio de texto). */
  --dur-rapida: 150ms;
  --dur-media:  200ms;
  --dur-lenta:  250ms;
  --dur-idioma: 50ms;
  --dur-toast:  200ms;
  --dur-modal:  150ms;
  --dur-pill:   200ms;
  --ease-pill:  cubic-bezier(.4, 0, .2, 1);
  --ease-out:   cubic-bezier(.2, .8, .2, 1);
}

/* Dark — línea de diseño Linear ("Dark Premium"):
   canvas casi negro, escalera surface-1..3, hairlines, tinta en gris claro.
   Elevación sin sombras: superficie + borde hairline + highlight superior. */
[data-theme="dark"] {
  color-scheme: dark;
  --color-bg:           #010102;          /* canvas */
  --color-surface:      #0f1011;          /* surface-1 */
  --color-surface-2:    #141516;          /* surface-2 */
  --color-surface-3:    #18191a;          /* surface-3 */
  --color-surface-4:    #191a1b;
  --color-border:       #23252a;          /* hairline */
  --color-border-strong:#34343a;          /* hairline-strong */
  --color-overlay:      rgba(0, 0, 0, 0.62);

  --color-primary:        #5e6ad2;        /* lavender - único acento de marca */
  --color-primary-hover:  #828fff;
  --color-primary-focus:  #5e69d1;
  --color-primary-soft:   rgba(94, 106, 210, 0.14);
  --color-focus-ring:     rgba(94, 105, 209, 0.5);
  --color-secondary:      #38bdf8;        /* cyan - categoría: eventos */
  --color-secondary-soft: rgba(56, 189, 248, 0.12);
  --color-accent:         #E7B778;        /* ámbar - racha / acciones clave */
  --color-accent-soft:    rgba(231, 183, 120, 0.12);

  --color-events-accent:      #38bdf8;
  --color-events-accent-soft: rgba(56, 189, 248, 0.10);
  --color-tasks-accent:       #5e6ad2;    /* lavanda - categoría: tareas */
  --color-tasks-accent-soft:  rgba(94, 106, 210, 0.12);

  --color-text:       #f7f8f8;            /* ink */
  --color-text-muted: #d0d6e0;            /* ink-muted */
  /* Más claro que en claro: sobre fondo oscuro el mismo ámbar del modo claro
     no llega al contraste mínimo y el aviso se lee como texto apagado. */
  --cal-fallback:     #F0A830;

  --shadow-soft: 0 0 0 rgba(0, 0, 0, 0);  /* Linear: sin sombras de marca */
  --glass-blur: none;
}

* { box-sizing: border-box; }
html, body { height: 100%; }

/* ============================================================
   FOCO VISIBLE (respaldo global)
   ============================================================
   Hay 22 reglas `:focus-visible` sueltas por la hoja, todas con la misma
   forma. Lo que NO habia era un respaldo: cualquier elemento fuera de esa
   lista se quedaba con el anillo que ponga el navegador, que cambia entre
   Chrome, Firefox y Safari, y que sobre `--color-bg` puede ser casi
   invisible. Es decir, el indicador de foco era consistente justo en los
   sitios donde ya se habia escrito a mano, e impredecible en el resto.

   Este selector va a propósito SIN clase: con especificidad 0,1,0 no gana a
   ninguna de las 22 reglas de componente (0,2,0), asi que sigue mandando
   donde ya hay un anillo propio con su offset y su color. Solo actúa donde
   no hay nada.

   `:focus-visible` y no `:focus`: con `:focus` el anillo aparece también al
   pulsar con el raton, que es cuando la persona no lo necesita. El teclado y
   el mando lo activan; el raton no.

   No se anula el `outline` en ningun sitio. Para los inputs sin borde hay
   una regla de foco propia mas abajo, con `:focus-within` sobre el marco. */
:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* ---------- Google Material Symbols ----------
   Iconografía oficial de Google (Material Symbols Outlined). La fuente se
   carga desde Google Fonts en app.html/admin.html. El span trae el nombre del
   símbolo como texto: <span class="material-symbols-outlined">edit</span>.

   Material Symbols es una fuente con métricas propias, así que hay que
   neutralizar el interlineado del texto que contiene el nombre del símbolo
   (si no, el glifo se descentra dentro del botón). */
.material-symbols-outlined {
  font-family: 'Material Symbols Outlined';
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  -webkit-font-smoothing: antialiased;
  -webkit-font-feature-settings: 'liga';
  font-feature-settings: 'liga';
  /* Por defecto neutro; cada botón ajusta el tamaño con su propia regla. */
  font-size: 1.15em;
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
  user-select: none;
  vertical-align: middle;
  flex-shrink: 0;
}
/* El span trae el NOMBRE del símbolo como texto ("edit", "close"). Si la
   fuente no llegara a cargar (PWA sin conexión, CDN caído), se vería esa
   palabra suelta. config.js hace una comprobación de document.fonts y, si la
   fuente no está, marca <html class="sin-material-symbols"> y estos iconos se
   ocultan por completo: el botón conserva su aria-label y sigue siendo
   usable, pero no muestra un glifo ni una palabra rara. */
html.sin-material-symbols .material-symbols-outlined { visibility: hidden; }

/* Tamaños para los iconos de acción. Material Symbols es variable y usa
   "opsz" (optical sizing) para ajustar el grosor del trazo: si no coincide con
   el tamaño real, los glifos se ven finos o difusos, así que se fija por regla. */
.card-edit .material-symbols-outlined,
.card-del .material-symbols-outlined {
  font-size: 17px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
}
.modal-close .material-symbols-outlined {
  font-size: 20px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
.racha-popover-cerrar .material-symbols-outlined {
  font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
}
.ctx-item-icon {
  font-size: 17px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
}
.adj-preview-cerrar .material-symbols-outlined {
  font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20;
}

/* ---------- Pantalla de carga (splash) ---------- */
.splash {
  position: fixed; inset: 0; z-index: 300;
  /* Va centrada, pero en un móvil muy bajo con notch el logo puede quedar
     rozando el borde superior; el inset lo baja un poco. */
  padding-top: env(safe-area-inset-top, 0px);
  background: var(--color-bg);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  transition: opacity .45s ease;
}
.splash.hide { opacity: 0; pointer-events: none; }
.splash-logo { width: 180px; height: auto; max-width: 60vw; animation: splashPulse 1.4s ease-in-out infinite; }
@keyframes splashPulse {
  0%, 100% { transform: scale(1); opacity: 0.92; }
  50%      { transform: scale(1.06); opacity: 1; }
}
.splash-text { color: var(--color-text); font-size: 0.98rem; }
.splash-dots span { display: inline-block; font-weight: 700; animation: dotBlink 1.1s infinite; }
.splash-dots span:nth-child(2) { animation-delay: .18s; }
.splash-dots span:nth-child(3) { animation-delay: .36s; }
@keyframes dotBlink { 0%, 100% { opacity: .2; } 50% { opacity: 1; } }
/* --- Zonas seguras ----------------------------------------------------
   `viewport-fit=cover` (en la meta viewport de las seis HTML) deja que la
   página se dibuje DEBAJO de la muesca y de la Dynamic Island. Sin esta
   reserva, en un iPhone con notch la barra superior queda medio tapada por el
   reloj, y en horizontal los botones de los extremos quedan bajo el corte.

   Abajo ya había `env(safe-area-inset-bottom)` para el dock y los bottom
   sheets; arriba no había nada, que es justo lo que este bloque arregla.

   `env(...)` lleva SIEMPRE el segundo argumento con el 0px de reserva: en
   navegadores que no conocen la función, un `env()` sin valor por defecto
   hace que TODO el `padding` de la declaración sea inválido y se pierda. */
body {
  margin: 0;
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  transition: background .2s ease, color .2s ease;
}
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; margin: 0; }
a { color: var(--color-primary); }
ul { list-style: none; margin: 0; padding: 0; }

/* ---------- Botones ---------- */
.btn {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--font-size-base);
  padding: 8px 14px;               /* spec Linear: botones 8x14 */
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform .12s ease, background .15s ease, border-color .15s ease;
}
.btn:active { transform: scale(0.98); }
.btn-block { width: 100%; }

/* Botón deshabilitado.
   `.btn` no tenía ninguna regla `:disabled`, y `.btn:active` se aplicaba
   igual, así que un botón apagado seguía hundiéndose al pulsarlo y seguía
   cambiando de color al pasar el ratón por encima: dos señales que mienten con
   su estado. Con `cursor: not-allowed` el puntero además avisa de que no hay
   nada que pulsar.

   Se baja la opacidad en vez de cambiar el color a gris para que siga leyéndose
   el texto y la jerarquía se mantenga. `.btn-generate` ya define su propio
   `:disabled` en otro sitio (era el único que lo tenía), así que esta regla no
   le pisa nada: el orden del fichero manda. */
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: .4;
  cursor: not-allowed;
  transform: none;
}
/* Los `:hover` de las variantes NO filtraban `:disabled` (solo lo hacia
   `.btn-generate`), de modo que un `.btn-primary` apagado se ponia lavanda
   al pasar el raton por encima. Se les anade `:not(:disabled)` para dejar
   el estado quieto. */
.btn:disabled:hover,
.btn[aria-disabled="true"]:hover { transform: none; }
.btn-sm { padding: 6px 12px; font-size: 0.8rem; }

/* Linear button-primary: lavanda (#5e6ad2), press #5e69d1, hover #828fff */
.btn-primary { background: var(--color-primary); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--color-primary-hover); }
.btn-primary:active:not(:disabled) { background: var(--color-primary-focus); }
.btn-outline { background: transparent; border-color: var(--color-border); color: var(--color-text); }
.btn-outline:hover:not(:disabled) { background: var(--color-primary-soft); }
.btn-danger { background: transparent; color: var(--color-danger); border-color: var(--color-danger); }

/* Botón principal de la vista IA: mismo acento lavanda (Linear no usa
   contraste de color extra para el CTA principal). */
.btn-generate {
  background: var(--color-primary); color: #fff;
  box-shadow: 0 1px 2px rgba(23, 24, 28, 0.18);
}
.btn-generate:hover:not(:disabled) { background: var(--color-primary-hover); color: #fff; }
.btn-generate:active:not(:disabled) { background: var(--color-primary-focus); color: #fff; }
[data-theme="dark"] .btn-generate {
  background: var(--color-primary); color: #fff;
  box-shadow: none;
}
[data-theme="dark"] .btn-generate:hover:not(:disabled) { background: var(--color-primary-hover); color: #fff; }
/* Acción principal de panel: "+" circular con relleno lavanda de alto
   contraste (Linear button-primary en forma de check-open). El halo de
   hover es un anillo de surface tint, no una sombra de marca. */
.btn-icon-round {
  width: 34px; height: 34px; border: none; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-primary); color: #fff;
  font-size: 1.2rem; font-weight: 600; line-height: 1; cursor: pointer;
  flex-shrink: 0;
  transition: background .15s ease, transform .12s ease, box-shadow .2s ease;
}
.btn-icon-round:hover:not(:disabled) {
  background: var(--color-primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 0 0 4px var(--color-primary-soft);
}
.btn-icon-round:active {
  background: var(--color-primary-focus);
  transform: translateY(0) scale(.96);
}
.btn-icon-round:focus-visible {
  outline: 2px solid var(--color-focus-ring); outline-offset: 2px;
}

/* ==========================================================
   PANTALLA DE BIENVENIDA (banner de inicio)
   ========================================================== */
.welcome-body {
  background: linear-gradient(180deg, var(--color-secondary-soft) 0%, var(--color-bg) 55%);
}
.welcome-screen {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px 24px;
  text-align: center;
}
.welcome-header { display: flex; flex-direction: column; align-items: center; }
.welcome-logo { margin-bottom: 0; }
.welcome-title {
  font-family: var(--font-display);
  font-weight: 600;
  /* `clamp()` en vez de un 2.6rem fijo: a 360 px, 2.6rem son 41.6 px y el
     logotipo se comia media pantalla en un movil pequeno. El minimo (1.6rem,
     el token `--font-size-xl`) mantiene la presencia de marca; el maximo
     conserva el 2.6rem de escritorio, de modo que en un monitor grande no
     cambia ni un pixel. El termino `6vw` hace que en tablet quede en medio,
     que es donde el salto fijo se notaba mas. */
  font-size: clamp(1.6rem, 6vw + 0.6rem, 2.6rem);
  letter-spacing: 0.05em;
  margin-top: 18px;
}
.brand-logo-full { width: 200px; height: auto; max-width: 60vw; }
.tagline { color: var(--color-text-muted); margin-top: 10px; font-size: 1rem; }
#about {
  width: 100%;
  max-width: 560px;
  margin: 40px 0 44px;
  padding: 28px 30px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}
#about h2 { font-size: 1.55rem; margin-bottom: 12px; }
#about p { color: var(--color-text-muted); font-size: 0.98rem; line-height: 1.65; margin: 0; }
.welcome-actions { width: 100%; max-width: 340px; display: flex; flex-direction: column; gap: 12px; }
.welcome-note { font-size: 0.78rem; color: var(--color-text-muted); line-height: 1.4; margin-top: 6px; }

/* Aviso de "tu sesión se cerró" (llega desde app.html?sesion=expirada):
   se pinta antes de los botones para que se lea sin tener que buscarse el
   motivo de que la app le haya cerrado la sesión en la cara. */
.login-aviso {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 14px; padding: 10px 12px;
  font-size: 0.82rem; line-height: 1.4; text-align: left;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-secondary);
  border-radius: var(--radius-sm);
}
.login-aviso.hidden { display: none; }
/* El tema se sigue aplicando por atributo, `[data-theme="dark"]`, y NUNCA por
   `@media (prefers-color-scheme: dark)`.

   El motivo de que siga siendo por atributo es el de siempre: la media query
   pregunta al SISTEMA y no se puede ganarle a la eleccion de la persona. Con las
   dos a la vez pasaba esto: alguien elige "claro" en un movil con el sistema en
   oscuro, y el borde naranja del aviso se le queda en su variante oscura
   mientras el resto de la pagina esta en claro.

   Lo que si ha cambiado es el punto de partida: `js/theme.js` ahora consulta la
   preferencia del sistema SOLO cuando no hay eleccion guardada, y deja de
   seguir al sistema en cuanto la hay. Son dos cosas distintas que conviene no
   confundirlas:
     - el RESPALDO por defecto es el del sistema;
     - la CAPACIDAD de override sigue siendo de la persona.
   `data-theme` lo escribe `zentAplicarTema`, tanto al arrancar (theme.js) como
   al cambiarlo en Ajustes (settings.js, que delega en la misma funcion). */
[data-theme="dark"] .login-aviso { border-left-color: #f97316; }
.welcome-signin { margin-top: 40px; font-size: 0.9rem; color: var(--color-text-muted); }
.btn-icon { display: inline-flex; }

/* Enlaces legales de la portada. Antes de esto no había ninguna forma de llegar
   a los documentos legales desde la pantalla de consentimento: OAuth exige que
   estén a la vista ANTES de que la persona autorice el acceso al calendario. */
.welcome-note a { color: var(--color-primary); text-decoration: underline; }
.welcome-note a:hover { color: var(--color-primary-hover); }
.welcome-note a:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
.welcome-legal {
  display: flex; gap: 6px 16px; flex-wrap: wrap; justify-content: center;
  margin-top: 18px; font-size: 0.78rem;
}
.welcome-legal a { color: var(--color-text-muted); text-decoration: none; }
.welcome-legal a:hover { color: var(--color-text); text-decoration: underline; }
.welcome-legal a:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; border-radius: 4px; }

/* ==========================================================
   APP — Navegador (topbar + tabbar)
   ========================================================== */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px;
  padding-top: calc(16px + env(safe-area-inset-top, 0px));
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}
.topbar-brand { display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 600; font-size: 1.15rem; }

/* Botón de búsqueda del topbar: discreto, se ensancha al pasar por encima. */
.topbar-search {
  display: inline-flex; align-items: center; gap: 7px;
  margin-left: auto; margin-right: 10px;
  padding: 5px 10px; border-radius: 8px;
  border: 1px solid var(--color-border);
  background: var(--color-surface-2);
  color: var(--color-text-muted, #7a8291);
  font: inherit; font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.topbar-search:hover { background: var(--color-surface-3); border-color: var(--color-border-strong); }
.topbar-search:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
.topbar-search .material-symbols-outlined { font-size: 18px; }
.topbar-search-kbd {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.68rem; letter-spacing: 0.02em;
  padding: 1px 5px; border-radius: 4px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted, #7a8291);
}
@media (max-width: 560px) {
  .topbar-search-label, .topbar-search-kbd { display: none; }
  .topbar-search { padding: 6px 8px; margin-right: 6px; }
}

/* ==========================================================
   Command Palette (Ctrl/Cmd + K)
   ========================================================== */
.search-overlay {
  position: fixed; inset: 0; z-index: 400;
  display: flex; justify-content: center;
  /* El panel arranca cerca del borde superior, como en Linear: así se ve la
     lista sin tener que mirar hacia abajo. */
  align-items: flex-start;
  padding: 8vh 16px 16px;
  background: var(--color-overlay, rgba(17, 18, 22, 0.45));
  backdrop-filter: blur(2px);
}
.search-overlay.hidden { display: none; }

.search-panel {
  width: 100%; max-width: 620px;
  max-height: 76vh;
  display: flex; flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(17, 18, 22, 0.24);
  overflow: hidden;
}

.search-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--color-border);
}
.search-head-icon { color: var(--color-text-muted, #7a8291); font-size: 20px; }
.search-input {
  flex: 1; min-width: 0;
  /* Sin `outline: 0`: este input no tiene borde propio, y su unico indicador
     de foco era el anillo del navegador sobre un fondo transparente. */
  border: 0; background: transparent;
  color: var(--color-text);
  font: inherit; font-size: 1rem;
}
/* El anillo se pone en el marco que lo rodea, no en el input: un rectángulo
   alrededor del texto suelto se ve descuadrado dentro de una caja redondeada.
   `:focus-within` cubre tambien el caso de pegar con el raton dentro del
   campo, que con `:focus-visible` no daria ningun aviso. */
.search-head:focus-within {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: -1px;
}
.search-input::placeholder { color: var(--color-text-muted, #7a8291); }
.search-cerrar {
  border: 0; background: transparent; cursor: pointer;
  color: var(--color-text-muted, #7a8291);
  font-size: 20px; padding: 2px; border-radius: 6px;
}
.search-cerrar:hover { background: var(--color-surface-3); }

.search-results { overflow-y: auto; padding: 6px; flex: 1; }

.sp-grupo-titulo {
  margin: 10px 8px 4px;
  font-size: 0.7rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-text-muted, #7a8291);
}
.sp-fila {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: left;
  padding: 8px 10px; margin: 1px 0;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--color-text); font: inherit;
  cursor: pointer;
}
.sp-fila:hover { background: var(--color-surface-2); }
.sp-fila.sel { background: var(--color-primary-soft, #eef0fb); }
.sp-icon { color: var(--color-text-muted, #7a8291); font-size: 20px; flex: none; }
.sp-fila.sel .sp-icon { color: var(--color-primary, #5e6ad2); }
.sp-cuerpo { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sp-titulo {
  font-size: 0.92rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-sub {
  font-size: 0.76rem; color: var(--color-text-muted, #7a8291);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-meta {
  font-size: 0.72rem; color: var(--color-text-muted, #7a8291);
  white-space: nowrap; flex: none;
}
.sp-grupo {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 6px; border-radius: 4px; flex: none;
  background: var(--color-surface-2); color: var(--color-text-muted, #7a8291);
}
/* Sello de "tarea completada" en la paleta: se distingue de un resultado
   pendiente sin tener que abrir la tarjeta. */
.sp-badge-done {
  display: inline-block; vertical-align: middle; margin-left: 2px;
  padding: 1px 6px; border-radius: 999px;
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.04em;
  background: color-mix(in srgb, #2e9e5b 18%, transparent);
  color: #2e9e5b; font-weight: 600;
}
.sp-titulo mark {
  background: transparent; color: var(--color-primary, #5e6ad2);
  font-weight: 600;
}
.sp-vacio {
  margin: 0; padding: 26px 14px; text-align: center;
  color: var(--color-text-muted, #7a8291); font-size: 0.88rem;
}
/* Aviso de "el servidor no responde", encima de los resultados. No es un
   error: la paleta sigue buscando en lo que hay; por eso el tono es
   informativo y no rojo. */
.sp-nota-red {
  display: flex; align-items: center; gap: 8px;
  margin: 6px 8px 0;
  padding: 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface-2);
  color: var(--color-text-muted, #7a8291);
  font-size: 0.78rem;
}
.sp-nota-red .material-symbols-outlined { font-size: 16px; flex: none; }

/* Respuesta de un comando ("tareas hoy"): no es una fila navegable, así que
   no lleva hover ni cursor de acción; se lee como el resultado de una
   pregunta. */
.sp-comando {
  display: flex; align-items: center; gap: 10px;
  margin: 10px 6px; padding: 14px 12px;
  border: 1px solid var(--color-border);
  border-radius: 10px;
  background: var(--color-surface-2);
}
.sp-comando .sp-icon { color: var(--color-tasks-accent, #5e6ad2); }
.sp-comando .sp-titulo { font-weight: 600; white-space: normal; }
.sp-comando .sp-meta {
  font-size: 1.15rem; font-weight: 700;
  color: var(--color-primary, #5e6ad2);
}

.search-foot {
  display: flex; gap: 14px; align-items: center;
  padding: 8px 14px;
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-2);
  font-size: 0.7rem; color: var(--color-text-muted, #7a8291);
}
.search-foot kbd {
  font-family: var(--font-mono, ui-monospace, monospace);
  /* Estos `<kbd>` son atajos de teclado ("⌘K", "Esc"). La nueva variable de
     `:root` no trae comillas porque son nombres genéricos, pero aquí, dentro de
     un pseudo-elemento de contenido, sí se muestran las teclas tal cual. */
  font-size: 0.68rem; padding: 1px 5px; margin-right: 3px;
  border-radius: 4px; border: 1px solid var(--color-border);
  background: var(--color-surface);
}
/* FASE F — fila de filtros activos y avisos de la paleta.
   Va entre la caja de búsqueda y los resultados, que es donde el ojo ya está:
   se lee como parte de la consulta, no como una nota aparte. */
.search-filtros {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 8px 12px 0;
}
.search-filtros[hidden] { display: none; }

.sp-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--color-primary, #5e6ad2);
  background: color-mix(in srgb, var(--color-primary, #5e6ad2) 10%, transparent);
  color: var(--color-text);
  font-size: 0.72rem; line-height: 1.5;
  cursor: pointer;
}
.sp-chip:hover { background: color-mix(in srgb, var(--color-primary, #5e6ad2) 18%, transparent); }
.sp-chip-texto { font-variant-numeric: tabular-nums; }
.sp-chip-x { font-size: 13px; opacity: 0.6; }
.sp-chip-x:hover, .sp-chip:hover .sp-chip-x { opacity: 1; }
/* "Limpiar filtros" es la acción destructiva de la fila: sin borde, en
   apagado, para que no se confunda con un filtro puesto. */
.sp-chip-todo {
  border-color: var(--color-border); background: transparent;
  color: var(--color-text-muted, #7a8291);
}
.sp-chip-todo:hover {
  background: var(--color-surface-2); color: var(--color-text);
  border-color: var(--color-border);
}

/* El aviso de operador mal escrito. Va en tono de aviso, no de error, porque
   la búsqueda sigue funcionando: simplemente ese filtro no se ha aplicado. */
.search-aviso {
  padding: 6px 12px 0; font-size: 0.72rem;
  color: #B26A00;
}
.search-aviso[hidden] { display: none; }
[data-theme="dark"] .search-aviso { color: #F0A830; }

/* La pista de sintaxis se va primero cuando la pantalla es estrecha: es la
   parte menos necesaria de las tres. */
.search-foot-filtros {
  margin-left: auto; font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.66rem; opacity: 0.75;
}
@media (max-width: 560px) { .search-foot { display: none; } }

.racha {
  display: inline-flex; align-items: center;
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid var(--color-border, #e2e6ee);
  background: rgba(127, 127, 127, 0.06); /* fondo semi-transparente discreto */
  color: #666666;
  font: inherit; font-weight: 600; font-size: 0.85rem;
  white-space: nowrap; line-height: 1; cursor: pointer;
  transition: color .3s ease, border-color .3s ease, background .3s ease;
}
.racha:hover { background: rgba(127, 127, 127, 0.12); }
.racha:focus-visible { outline: 2px solid var(--color-primary, #4a78f5); outline-offset: 2px; }
.racha-count { font-variant-numeric: tabular-nums; }

/* ---------- Llama animada de la racha ----------
   Se construye con dos pseudo-elementos y CSS keyframes (sin Lottie ni
   peticiones extra). Por defecto está oculta y sin animación: racha.js solo
   añade .racha-flame-activa cuando la racha es mayor que 0. */
.racha-flame {
  position: relative; display: none;
  width: 11px; height: 14px; margin-right: 6px; flex-shrink: 0;
  filter: drop-shadow(0 0 3px rgba(249, 115, 22, .45));
}
.racha-flame-activa { display: inline-block; }
.racha-flama-nucleo, .racha-flama-lengua {
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
}
.racha-flama-nucleo {
  width: 10px; height: 13px;
  background: linear-gradient(180deg, #fbbf24 0%, #f97316 45%, #ea580c 100%);
  animation: racha-llama-latido 1.15s ease-in-out infinite;
  transform-origin: 50% 100%;
}
.racha-flama-lengua {
  width: 5px; height: 7px; bottom: 1px;
  background: linear-gradient(180deg, #fde68a 0%, #fbbf24 100%);
  animation: racha-llama-llama 0.78s ease-in-out infinite alternate;
  transform-origin: 50% 100%;
}
@keyframes racha-llama-latido {
  0%, 100% { transform: translateX(-50%) scaleY(1) scaleX(1); }
  35%      { transform: translateX(-50%) scaleY(1.16) scaleX(.92); }
  65%      { transform: translateX(-50%) scaleY(.93) scaleX(1.05); }
}
@keyframes racha-llama-llama {
  from { transform: translateX(-50%) translateY(0) scaleY(1); opacity: .95; }
  to   { transform: translateX(-50%) translateY(-3px) scaleY(1.35); opacity: .55; }
}
/* Respeta la preferencia de movimiento reducido del sistema. */
@media (prefers-reduced-motion: reduce) {
  .racha-flama-nucleo, .racha-flama-lengua { animation: none; }
}

/* ---------- Racha perdida: el fuego se apaga ----------
   Se añade al pill cuando, al entrar, el backend detecta que pasó un día
   completo sin generar ni escuchar el resumen diario: el badge se sacude y la
   llama mengua hasta apagarse. Lo dispara racha.js (animarRachaPerdida). */
@keyframes zent-rp-sacudida {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-4px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}
@keyframes zent-rp-apagar {
  0%   { opacity: 1; transform: scale(1) translateY(0); }
  100% { opacity: 0; transform: scale(.35) translateY(3px); }
}
.zent-racha-perdida {
  animation: zent-rp-sacudida 450ms cubic-bezier(.36, .07, .19, .97) both;
  border-color: var(--color-danger, #ef4444) !important;
}
.zent-racha-perdida .racha-flame { animation: zent-rp-apagar 650ms ease-in forwards; }

/* ------- Popover del botón de racha ------- */
.racha-popover {
  position: fixed; z-index: 130; width: 280px;
  background: var(--color-surface, #fff);
  color: var(--color-text, #1b1f27);
  border: 1px solid var(--color-border, #e2e6ee);
  border-radius: 12px; padding: 12px 14px 12px 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
  font-size: 0.82rem; line-height: 1.5;
  animation: racha-pop-in .18s ease;
}
.racha-popover.hidden { display: none; }
.racha-popover-tit { font-weight: 600; padding-right: 22px; }
.racha-popover-sub { margin-top: 5px; color: var(--color-text-muted, #7a8291); font-size: 0.78rem; }
.racha-popover-cerrar {
  position: absolute; top: 6px; right: 6px;
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--color-text-muted, #7a8291);
  font-size: 0.85rem; cursor: pointer; border-radius: 50%;
}
.racha-popover-cerrar:hover { background: var(--color-primary-soft, #e8f0fe); }
@keyframes racha-pop-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.tabbar {
  display: flex;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky; top: 0; z-index: 5;
  /* La barra pega al borde superior, así que su padding es lo que aparta el
     contenido del reloj y de la muesca. */
  padding-top: env(safe-area-inset-top, 0px);
}
/* Indicador tipo pastilla: se desliza con transform (compuesto) para no
   provocar reflow al cambiar de pestaña. */
.tab-pill {
  position: absolute; bottom: -1px; left: 0;
  height: 2px; width: 0;
  background: var(--color-primary);
  border-radius: 2px 2px 0 0;
  transform: translateX(0);
  transition: transform var(--dur-pill) var(--ease-pill), width var(--dur-pill) var(--ease-pill);
  pointer-events: none;
  will-change: transform;
}
.tab-btn {
  flex: 1;
  background: none; border: none; cursor: pointer;
  padding: 12px 8px 10px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--color-text-muted);
  font-family: var(--font-body); font-size: var(--font-size-sm); font-weight: 600;
  transition: color var(--dur-rapida) ease;
}
.tab-icon { font-size: 1.05rem; }
.tab-btn.active { color: var(--color-primary); }

/* Ancho de trabajo: en escritorios grandes la lectura se rompe más
   allá de cierto punto, pero 1100 px dejaba la mitad de la pantalla
   vacía. 1400 px centra el conjunto y deja a Tareas y Eventos un
   hueco proporcional de verdad (ver F5 y el informe de UI). */
.views { max-width: 1400px; margin: 0 auto; padding: 24px 20px 60px; }
.view { display: none; }
.view.active { display: block; animation: fadeIn .2s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px);} to { opacity: 1; transform: none; } }

/* ---------- Vista Visual ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
/* Los hijos de un grid se niegan a encoger por debajo de su contenido
   (min-width: auto) y un título o un chip largo empujaba la columna
   vecina hasta montar una columna sobre otra. min-width: 0 devuelve al
   grid el control del reparto. */
.split > * { min-width: 0; }
/* En modo Timeline el lienzo ocupa la fila ENTEA. Antes caía en una
   celda de media pantalla (1fr): las columnas de solape colapsaban,
   los bloques se montaban unos sobre otros y la rejilla de horas
   quedaba ilegible. */
.split .timeline-view:not(.hidden) { grid-column: 1 / -1; }

/* Vistas combinadas (la barra Lista/Mini/Timeline). `data-vista` lo
   escribe minical.js y aquí se decide qué se ve, sin estilos inline:
   Mini es exclusivo (sólo el widget centrado) y Timeline puede ir solo
   (lienzo a todo el ancho, sin paneles) o con Lista (paneles arriba,
   lienzo a fila completa debajo). */
#view-visual[data-vista="mini"] > .split { display: none; }
#view-visual[data-vista="timeline"] > .split > .panel { display: none; }
@media (max-width: 720px) { .split { grid-template-columns: 1fr; } }
.panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 18px;
  box-shadow: var(--shadow-soft);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
.panel-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 14px; }
.panel-counter { margin: 4px 0 0; font-size: 0.8rem; color: var(--color-text-muted); }
/* Acciones del header: el filtro y el "+" van en fila, pegados al borde
   derecho, con el "+" (acción principal) como último para que el pulgar caiga
   en él. El filtro es secundario: por eso es un botón fantasma. */
.panel-acciones { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }

/* Botón fantasma de icono: mismo tamaño que .btn-icon-round, pero sin relleno
   de marca. Es para acciones que se usan de vez en cuando (ordenar), no para
   la acción principal del panel. */
.btn-icon-ghost {
  width: 34px; height: 34px; border: none; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--color-text-muted);
  cursor: pointer; flex-shrink: 0; padding: 0;
  transition: background var(--dur-rapida) ease, color var(--dur-rapida) ease;
}
.btn-icon-ghost:hover:not(:disabled) { background: var(--color-primary-soft); color: var(--color-primary); }
.btn-icon-ghost:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
/* Desplegable abierto: el botón se queda marcado, para que se sepa qué
   botón es el que tiene el menú flotando debajo. */
.btn-icon-ghost[aria-expanded="true"] { background: var(--color-primary-soft); color: var(--color-primary); }
.btn-icon-ghost .material-symbols-outlined { font-size: 20px; line-height: 1; }

/* Interruptor "Mostrar / Ocultar completadas": un botón fantasma con texto, lo
   bastante pequeño para caber en el header junto al filtro y el "+". El estado
   activo (mostrando completadas) lleva la marca tenue para no competir con la
   acción principal del panel. */
.btn-toggle-completadas {
  display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 10px; border: 1px solid var(--color-border);
  border-radius: 999px; background: transparent;
  color: var(--color-text-muted); font-size: 0.78rem; cursor: pointer;
  transition: background var(--dur-rapida) ease, color var(--dur-rapida) ease,
    border-color var(--dur-rapida) ease;
}
.btn-toggle-completadas .material-symbols-outlined { font-size: 17px; line-height: 1; }
.btn-toggle-completadas:hover:not(:disabled) {
  background: var(--color-primary-soft); color: var(--color-primary);
}
.btn-toggle-completadas.activo { color: var(--color-primary); border-color: var(--color-primary); }
.btn-toggle-completadas:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
/* Sin tareas hechas el interruptor no tiene nada que esconder: se apaga sin
   quitarse del DOM (su estado sigue siendo el que es) pero deja claro que
   tocar no hará nada. */
.btn-toggle-completadas:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Desplegable de ordenamiento (hermano del menú contextual, se apoya en los
   mismos tokens y la misma sombra). `max-height` + scroll por si en una pantalla
   muy baja no cabe debajo del botón: mejor que se recorra a que se corte. */
.orden-menu {
  position: fixed; z-index: 300; min-width: 190px;
  max-height: min(60vh, 320px); overflow-y: auto;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
  padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.orden-menu-tit {
  margin: 0 0 4px; padding: 4px 12px 6px;
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--color-text-muted);
  border-bottom: 1px solid var(--color-border);
}
.orden-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  text-align: left; padding: 9px 12px; border: none; border-radius: var(--radius-xs);
  background: none; cursor: pointer; white-space: nowrap;
  font-family: var(--font-body); font-size: 0.85rem; font-weight: 500; color: var(--color-text);
  transition: background var(--dur-rapida) ease, color var(--dur-rapida) ease;
}
.orden-item:hover { background: var(--color-primary-soft); }
.orden-item:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: -2px; }
.orden-item.activo { color: var(--color-primary); font-weight: 600; }
.orden-item-icon { font-size: 17px; color: var(--color-text-muted); }
.orden-item.activo .orden-item-icon { color: var(--color-primary); }
/* La columna del check reserva el hueco siempre: si no, la lista "da saltos"
   horizontalmente cada vez que se elige una opción distinta. */
.orden-item-check { font-size: 17px; color: var(--color-primary); margin-left: auto; }
.orden-item-check:empty { visibility: hidden; }
.panel-progress {
  height: 2px; width: 100%; margin-top: 8px;
  background: var(--color-border, #e2e6ee);
  border-radius: 999px; overflow: hidden;
}
.panel-progress-fill {
  display: block; height: 100%;
  background: var(--color-primary, #4f46e5);
  border-radius: 999px;
  transition: width .3s ease;
}

/* --- Tareas: rectángulos con check + hora, expandibles --- */
.task-list { display: flex; flex-direction: column; gap: 8px; list-style: none; margin: 0; padding: 0; }
/* Separa las pendientes de las ya completadas. Sin esto, al marcar tareas se
   mezclaban con las pendientes y la lista se volvía difícil de recorrer. */
.task-group-separator {
  display: flex; align-items: center; gap: 10px;
  margin: 6px 2px 0; list-style: none;
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--color-text-muted);
}
.task-group-separator::after {
  content: ""; flex: 1; height: 1px;
  background: var(--color-border);
}
.task-card {
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: pointer;
  transition: transform .12s ease, border-color .15s ease, box-shadow .2s ease;
}
.task-card:hover { transform: translateY(-1px); }
.task-card:active { transform: translateY(0) scale(.99); }
.task-card-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; }
.task-card.done .task-card-row { opacity: 0.5; }
.task-card.done .task-title { text-decoration: line-through; }
.card-del {
  width: 24px; height: 24px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: transparent; color: var(--color-text-muted);
  font-size: 0.8rem; line-height: 1; cursor: pointer;
  opacity: 0.5; transition: opacity .15s ease, background .15s ease, color .15s ease;
}
.card-del:hover { opacity: 1; background: var(--color-danger); color: #fff; }
.task-card:hover .card-del, .event-card:hover .card-del { opacity: 0.9; }
/* Grupo de acciones (editar + eliminar) de cada tarjeta. Se mantiene siempre
   visible en la sección "Sin hora" para que ninguna tarea quede sin salida. */
.card-acciones { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }
.card-edit {
  width: 24px; height: 24px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: 50%;
  background: transparent; color: var(--color-text-muted);
  font-size: 0.8rem; line-height: 1; cursor: pointer;
  opacity: 0.5; transition: opacity .15s ease, background .15s ease;
}
.card-edit:hover { opacity: 1; background: var(--color-primary-soft); }
.task-card:hover .card-edit, .event-card:hover .card-edit { opacity: 0.9; }
.mini-item .card-acciones .card-edit,
.mini-item .card-acciones .card-del { opacity: 0.8; }
.task-check {
  width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid var(--color-tasks-accent); background: transparent; cursor: pointer;
}
.task-check.checked { background: var(--color-tasks-accent); }
.task-title {
  flex: 1; font-weight: 500; text-transform: capitalize;
  min-width: 0; overflow-wrap: anywhere; word-break: break-word; white-space: normal;
  line-height: 1.3;
}
.task-time {
  font-size: 0.75rem; font-weight: 600; color: var(--color-tasks-accent);
  background: var(--color-tasks-accent-soft); padding: 3px 9px; border-radius: 999px; white-space: nowrap;
  border: 1px solid transparent;
}
[data-theme="dark"] .task-time { border-color: rgba(94, 106, 210, 0.25); }
[data-theme="dark"] .task-card {
  background: rgba(255, 255, 255, 0.03);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow-soft);
}
.task-desc {
  max-height: 0; overflow: hidden; transition: max-height .2s ease, padding .2s ease;
  padding: 0 14px; font-size: 0.85rem; color: var(--color-text-muted); line-height: 1.5;
  overflow-wrap: anywhere; word-break: break-word;
}
.task-card.expanded .task-desc { max-height: 200px; padding: 0 14px 14px; }
.task-desc-empty { font-style: italic; opacity: 0.7; }

/* Etiquetas dentro de cada tarjeta de tarea: nota, prioridad, rutina, lista, tags */
.task-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 14px 8px 14px; }
.task-chip, .event-chip {
  font-size: var(--font-size-xs); font-weight: 700; letter-spacing: 0.02em;
  padding: 3px 9px; border-radius: var(--radius-pill);
  border: 1px solid var(--color-border); background: var(--color-primary-soft);
  color: var(--color-text-muted); white-space: nowrap;
  /* Un enlace o una etiqueta largos (p. ej. el título de un adjunto de Drive)
     rompían la tarjeta por su borde derecho: la etiqueta no cabía y la parrilla
     la estiraba. Se corta con puntos suspensivos dentro de la columna. */
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.chip-rutina {
  background: var(--color-accent-soft); color: var(--color-accent);
  border-color: transparent;
}
.chip-note { text-transform: uppercase; }
.chip-prio.prio-1 { background: var(--color-secondary-soft); color: var(--color-secondary); border-color: transparent; }
.chip-prio.prio-3 { background: var(--color-accent-soft); color: #A9742F; border-color: transparent; }
[data-theme="dark"] .chip-prio.prio-3 { color: var(--color-accent); }
.chip-prio.prio-5 { background: var(--color-danger); color: #fff; border-color: transparent; }
.chip-tag { font-weight: 600; }

/* Lista pequeña "Sin hora": tareas sin fecha asignada */
.panel-sub { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--color-border); }
.panel-sub h3 {
  font-family: var(--font-body); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--color-text-muted); margin-bottom: 8px;
}

/* Panel "SIN HORA" al quedarse vacío: colapsa su altura antes de desmontarse.
   grid-template-rows 0fr -> 1fr evita tener que medir la altura real; el
   envoltorio interno recorta durante la transición. */
.panel-sub.animable {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 220ms var(--ease-out), opacity 180ms ease;
}
.panel-sub.animable > * { min-height: 0; }
/* El recorte solo hace falta durante el colapso: en abierto recortaría los
   focus rings de los botones de la lista. */
.panel-sub.animable.zent-panel-colapsando > * { overflow: hidden; }
.panel-sub.animable.zent-panel-colapsando {
  grid-template-rows: 0fr;
  opacity: 0;
  pointer-events: none;
}
.mini-list { display: flex; flex-direction: column; gap: 6px; }
.mini-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--color-surface); border: 1px solid var(--color-border);
  font-size: 0.82rem;
  transition: border-color .15s ease;
}
.mini-item:hover { border-color: var(--color-tasks-accent); }
.mini-item .mini-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini-item.done .mini-title { text-decoration: line-through; opacity: .55; }
/* Checkbox de la sección "Sin hora": mismas interacciones que la lista del día. */
.mini-check { width: 16px; height: 16px; border-width: 2px; }
.mini-badge {
  font-size: 0.62rem; font-weight: 700; color: var(--color-secondary);
  padding: 2px 7px; border-radius: 999px; background: var(--color-secondary-soft);
}

/* Animación al cambiar de día: los elementos entran deslizados y con fade */
@keyframes cardIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.task-card, .event-card { animation: cardIn 220ms var(--ease-out) both; }

/* Eliminado: la tarjeta se desplaza 20px y se desvanece en 200 ms. Al
   desmontarla, el resto se recoloca solo (sin animar su layout). */
@keyframes zent-card-sale {
  from { opacity: 1; transform: translateX(0) scale(1); }
  to   { opacity: 0; transform: translateX(20px) scale(0.95); }
}
.zent-card-salida {
  animation: zent-card-sale var(--dur-media) var(--ease-out) both !important;
  pointer-events: none;
}
/* Salida de un bloque del timeline (eliminar): fade + pequeño encogido, igual
   que las tarjetas de la lista. El nodo se quita al acabar la animación o al
   llegar el re-render. */
@keyframes zent-bloque-sale {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.95); }
}
.timeline-bloque.zent-bloque-salida {
  animation: zent-bloque-sale 220ms var(--ease-out) both;
  pointer-events: none;
}

/* --- Eventos: tarjetas de altura natural --- */
.event-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px;
}
/* La tarjeta ocupa lo que necesita su contenido. Antes llevaba
   `aspect-ratio: 1 / 1`, pensado para una cuadrícula de cuadrados: en móvil
   la rejilla pasa a una sola columna, así cada tarjeta se volvía un cuadrado
   del ancho de la pantalla y quedaba altísima respecto a su texto. */
.event-card {
  position: relative;
  height: auto;
  border: 1px solid var(--color-border);
  background: var(--color-events-accent-soft);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  display: flex; flex-direction: column; gap: 6px;
  cursor: pointer;
  transition: transform .12s ease, border-color .15s ease;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
.event-card:hover { transform: translateY(-2px); }
.event-card:active { transform: translateY(0) scale(.98); }
.event-card .card-acciones { position: absolute; top: 8px; right: 8px; z-index: 2; }
.event-card-time {
  align-self: flex-start;
  font-size: 0.7rem; font-weight: 700; color: var(--color-events-accent);
  background: rgba(255,255,255,0.6); padding: 2px 8px; border-radius: 999px;
  border: 1px solid transparent;
}
[data-theme="dark"] .event-card-time { background: rgba(56, 189, 248, 0.1); border-color: rgba(56, 189, 248, 0.2); }
.event-card-title {
  font-weight: 600; font-size: 0.92rem; line-height: 1.25; text-transform: capitalize;
  min-width: 0; overflow-wrap: anywhere; word-break: break-word; white-space: normal;
}
.event-card-desc {
  font-size: var(--font-size-sm); color: var(--color-text-muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  overflow-wrap: anywhere; word-break: break-word;
}
.event-card.expanded .event-card-desc { -webkit-line-clamp: unset; overflow-y: auto; }
.event-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.event-chips .event-chip { align-self: flex-start; font-size: var(--font-size-xs); }

/* De qué calendario es cada evento. El punto lleva el color que eligió la
   persona en Google; el nombre va al lado porque con dos calendarios del mismo
   color el punto no basta para distinguirlos. */
.event-card-calendar {
  display: flex; align-items: center; gap: 6px;
  grid-column: 1 / -1;
  font-size: var(--font-size-xs); color: var(--color-text-muted);
  min-width: 0;
}
.event-card-calendar-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}

/* El punto de color es reutilizable en la lista de Ajustes, en el detalle y en
   la tarjeta. Es decorativo y lleva la inicial como texto de respaldo: si el
   color no llega (un calendario sin color, o un bloqueo de CSS que impida el
   `background`), se ve una inicial y no un hueco. */
.calendar-dot {
  width: 12px; height: 12px; border-radius: 50%;
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: 7px; font-weight: 700; line-height: 1;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.15);
}

/* Aviso de calendario caído: ámbar, no rojo. No es un error de la app ni un
   fallo de red, es un dato que falta, y ponerlo en rojo haría sospechar de
   algo que está funcionando. Sigue el mismo mecanismo que el resto de la banda
   de estado (`data-tipo`) para no inventar una clase paralela. */
.zent-estado[data-tipo="aviso"] { border-color: var(--cal-fallback); }
.zent-estado[data-tipo="aviso"] .zent-estado-icono { color: var(--cal-fallback); }

.grid-empty, .item-empty {
  grid-column: 1 / -1; color: var(--color-text-muted); font-size: 0.85rem;
  padding: 22px 16px; text-align: center;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  animation: cardIn .28s ease both;
}

/* ---------- Modal (agregar tarea / evento) ---------- */
.modal-overlay {
  position: fixed; inset: 0;
  /* Capa de fondo: 75% de negro + desenfoque. Con el 45% anterior se seguían
     leyendo las tarjetas del fondo y competían con el texto del modal. */
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  /* Por encima de todo lo demás (topbar 5, dock 60, búsqueda 120, ajustes y
     developer terminal 400): si no, un modal abierto desde la paleta de
     comandos o la terminal se quedaba por debajo de ellas. */
  z-index: 1000;
  padding: 20px;
  opacity: 0;
  transition: opacity var(--dur-modal) var(--ease-out);
}
.modal-overlay.zent-abierto { opacity: 1; }
.modal-overlay.hidden { display: none; }
.modal-box {
  background: var(--color-surface); border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  width: 100%; max-width: 420px; padding: 22px; box-shadow: 0 12px 40px rgba(0,0,0,0.25);
  /* El tope no puede ser 100vh a secas: en móvil, 100vh mide la ventana
     INCLUYE la barra de direcciones, así que la caja se salía por debajo de
     la UI del navegador y el botón "Guardar" quedaba inalcanzable aunque la
     caja scrollease. dvh (dynamic viewport) ya descuenta esa barra; se
     declara 88vh antes para los navegadores que no lo conocen, que se
     quedan con un tope algo más alto pero siempre dentro de la pantalla. */
  max-height: 88vh;
  max-height: min(88vh, calc(100dvh - 32px));
  overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--color-border) transparent;
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  /* Entrada discreta: escala 0.97 -> 1 en 150 ms, sin rebote. */
  opacity: 0; transform: scale(.97);
  transition: opacity var(--dur-modal) var(--ease-out),
              transform var(--dur-modal) var(--ease-out);
}
.modal-overlay.zent-abierto .modal-box { opacity: 1; transform: scale(1); }
.modal-box::-webkit-scrollbar { width: 8px; }
.modal-box::-webkit-scrollbar-track { background: transparent; }
.modal-box::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 999px; }

/* ---- El modal que tiene <form> (Nueva tarea) ----
   Aquí el scroll pasa de la caja al <form>, para que la cabecera (título y
   cerrar) no se vaya con el contenido y el botón Guardar pueda fijarse al
   fondo. min-height:0 es imprescindible: sin él, un hijo flex no baja de su
   altura de contenido y no llega a scrollear. Se limita a #modal-overlay para
   no tocar los otros modales (detalles, adjuntos, feedback), que comparten
   .modal-box pero llevan su propio esquema. */
#modal-overlay .modal-box {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
#modal-overlay .modal-form {
  min-height: 0;
  overflow-y: auto;
  /* contain evita que el scroll "rebote" hacia la página de detrás. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Espacio para que el botón pegado no se solape con el último campo. */
  padding-bottom: 4px;
}

/* Guardar siempre visible, sin tapar el campo que se esté rellenando.
   El velo opaco va en un pseudo-elemento y NO como background del botón:
   "Guardar" es un .btn-primary y sobrescribir su fondo lo dejaba blanco.
   El botón es position:sticky con z-index, así que crea contexto de apilado
   y el ::before con z-index:-1 queda por detrás de su fondo pero por delante
   del formulario, que es justo lo que hace falta. */
#modal-overlay .modal-form > .btn[type="submit"] {
  position: sticky;
  bottom: 0;
  z-index: 1;
}
#modal-overlay .modal-form > .btn[type="submit"]::before {
  content: "";
  position: absolute;
  /* 12px a los lados y 18px por arriba: el margen del botón (16px) más un
     margen de holgura. Cierra el hueco por el que se asomaría el contenido. */
  left: -12px; right: -12px; top: -18px; bottom: 0;
  background: var(--color-surface);
  z-index: -1;
}
/* La cabecera no debe comprimirse al encogerse la caja: si se aprieta, el
   título y el botón de cerrar se cutan. */
#modal-overlay .modal-header { flex-shrink: 0; }
.modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.modal-close {
  background: none; border: none; font-size: 1.1rem; color: var(--color-text-muted); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;
  transition: background .15s ease, color .15s ease;
}
.modal-close:hover { background: var(--color-primary-soft, #e8f0fe); color: var(--color-text); }
.modal-form { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: 0.78rem; font-weight: 600; color: var(--color-text-muted); margin-top: 8px; }
.modal-form input[type="text"],
.modal-form textarea,
.modal-form select {
  width: 100%; padding: 12px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text);
  font-family: var(--font-body); font-size: 1.05rem;
}
.modal-form select { cursor: pointer; }
.modal-form input:focus,
.modal-form select:focus,
.modal-form textarea:focus {
  outline: 2px solid var(--color-secondary);
  outline-offset: -1px;
}
.field-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.toggle-label { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.toggle-label input { width: auto; }
.modal-form .btn { margin-top: 16px; }
.hidden { display: none !important; }

/* ---------- Selector "Fecha y hora" (panel expansible inline) ---------- */
.pick-field { position: relative; }

/* El input nativo queda "invisible pero vivo": modal.js lo lee al guardar */
.pick-native {
  position: absolute; width: 1px; height: 1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden;
  white-space: nowrap;
}

/* Botón que abre el selector (mismo lenguaje visual que los inputs) */
.pick-btn {
  width: 100%; min-height: 46px; box-sizing: border-box;
  display: flex; align-items: center; gap: 8px;
  padding: 12px 14px; margin-top: 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text); font-family: var(--font-body);
  font-size: 1rem; font-weight: 500;
  cursor: pointer; text-align: left;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.pick-btn:hover { border-color: var(--color-secondary); }
.pick-btn:focus-visible { outline: 2px solid var(--color-secondary); outline-offset: -1px; }
.pick-btn.open { border-color: var(--color-secondary); box-shadow: 0 0 0 3px var(--color-secondary-soft); }
.pick-ico { color: var(--color-secondary); flex-shrink: 0; }
.pick-caret {
  margin-left: auto; color: var(--color-text-muted); flex-shrink: 0;
  transition: transform .2s ease;
}
.pick-btn.open .pick-caret { transform: rotate(180deg); }
.pick-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Panel expansible: se abre DENTRO del flujo del formulario y empuja los
   campos siguientes (nada se superpone ni se tapa). Fondo propio sólido,
   sin transparencias, con la identidad visual de Zent. */
.pick-panel {
  margin-top: 8px; padding: 14px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  animation: fadeIn .16s ease;
}
.pick-panel[hidden] { display: none; }

/* Atajos */
.pick-shortcuts { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.pick-sc {
  border: 1px solid var(--color-border); background: var(--color-surface);
  color: var(--color-text); font-family: var(--font-body);
  font-size: 0.8rem; font-weight: 500;
  padding: 6px 12px; border-radius: 999px; cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.pick-sc:hover { border-color: var(--color-primary); background: var(--color-primary-soft); }

/* Calendario */
.pick-cal-head {
  display: grid; grid-template-columns: 32px 1fr 32px; align-items: center;
  gap: 4px; margin-bottom: 6px;
}
.pick-nav {
  border: 1px solid var(--color-border); background: var(--color-surface);
  color: var(--color-primary); font-size: 1.05rem; line-height: 1;
  width: 30px; height: 30px; border-radius: var(--radius-sm);
  cursor: pointer; transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.pick-nav:hover { background: var(--color-primary-soft); border-color: var(--color-primary); }
.pick-cal-title {
  font-family: var(--font-display); font-weight: 600; font-size: 0.95rem;
  text-align: center; text-transform: capitalize; color: var(--color-text);
}
.pick-cal-week { display: grid; grid-template-columns: repeat(7, 1fr); padding: 0 4px; }
.pick-cal-week span {
  text-align: center; font-size: 0.66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted);
  padding: 4px 0;
}
.pick-cal-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; padding: 0 4px 4px; }
.pick-day {
  border: none; background: transparent; color: var(--color-text);
  font-family: var(--font-body); font-size: 0.85rem; text-align: center;
  aspect-ratio: 1 / 1; border-radius: var(--radius-sm); cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.pick-day:hover { background: var(--color-primary-soft); }
.pick-day.muted { color: var(--color-text-muted); opacity: 0.5; }
.pick-day.today { box-shadow: inset 0 0 0 1.5px var(--color-secondary); }
.pick-day.selected { background: var(--color-primary); color: #fff; font-weight: 700; }

/* Hora: input nativo <input type="time"> estilizado para Zent.
   El picker táctil es el del propio navegador (Chrome/Safari/Android/iOS):
   no hay desplegables custom que se escapen del modal. */
.pick-time-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--color-border);
}
.pick-time-caption { font-size: 0.78rem; font-weight: 600; color: var(--color-text-muted); }
.modal-form .pick-time-input {
  width: auto; min-width: 148px;
  padding: 8px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-bg);
  color: var(--color-text); font-family: var(--font-body);
  font-size: 1rem; font-weight: 600;
  color-scheme: light dark;
  transition: border-color .15s ease;
}
.modal-form .pick-time-input:hover { border-color: var(--color-secondary); }
.modal-form .pick-time-input:focus { outline: 2px solid var(--color-secondary); outline-offset: -1px; }

/* Reloj de término: más compacto */
.pick-panel-end { padding: 12px; }
.pick-panel-end .pick-time-row { margin-top: 0; padding-top: 0; border-top: none; }

/* Acciones */
.pick-panel-actions { display: flex; justify-content: flex-end; margin-top: 12px; }
.pick-panel-actions .btn { margin-top: 0; padding: 8px 18px; }

/* En pantallas muy angostas, Fecha y Hora (y hora inicial/término) se apilan
   en una sola columna para que los botones no se peguen ni salgan de su caja */
@media (max-width: 400px) {
  .field-row { grid-template-columns: 1fr; }
  .pick-time-row { flex-direction: column; align-items: stretch; }
  .pick-time-row .pick-time-input { width: 100%; min-width: 0; }
}

/* ---------- Proceso guiado de 4 pasos (onboarding) ----------
   Pantalla completa y recorrido horizontal: la cabecera y el progreso quedan
   fijos arriba, y las cuatro cajas se reparten en fila de forma horizontal. */
.onboarding-overlay {
  position: fixed; inset: 0; z-index: 200;
  width: 100vw; height: 100vh; height: 100dvh;
  max-width: none; max-height: none;
  background: var(--color-bg);
  display: flex; align-items: stretch; justify-content: stretch;
  padding: 0; overflow: hidden;
}
.onboarding-box {
  --ob-pad: clamp(16px, 2.4vw, 32px);
  width: 100vw; height: 100vh; height: 100dvh;
  max-width: none; max-height: none;
  display: flex; flex-direction: column;
  background:
    radial-gradient(circle at 8% 0%, var(--color-primary-soft), transparent 32%),
    var(--color-bg);
  border: 0; border-radius: 0; box-shadow: none;
  padding: var(--ob-pad);
  padding-top: max(var(--ob-pad), env(safe-area-inset-top));
  padding-right: max(var(--ob-pad), env(safe-area-inset-right));
  padding-bottom: max(var(--ob-pad), env(safe-area-inset-bottom));
  padding-left: max(var(--ob-pad), env(safe-area-inset-left));
  overflow: hidden;
}
.onboarding-top { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.onboarding-top img { flex: 0 0 auto; width: 30px; height: 30px; }
.onboarding-top span {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem); letter-spacing: -0.02em;
}
.onboarding-top .modal-close {
  margin-left: auto; width: 42px; height: 42px;
  display: inline-flex; align-items: center; justify-content: center;
}
.onboarding-progress {
  flex: 0 0 auto; height: 5px; background: var(--color-border);
  border-radius: 999px; margin: clamp(12px, 1.6vh, 20px) 0 clamp(14px, 1.9vh, 24px);
  overflow: hidden;
}
.onboarding-bar {
  height: 100%; width: 0%; background: var(--color-primary);
  border-radius: 999px; transition: width .35s var(--ease-out);
}

/* Fila de pasos. Se reparten horizontalmente de izquierda a derecha por toda
   la pantalla. Cada paso ocupa ancho uniforme; el activo se expande un poco
   para dar énfasis. */
.onboarding-steps {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: row; align-items: stretch;
  gap: clamp(12px, 1.8vw, 24px);
  width: 100%;
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding: 2px 4px 6px;
  scrollbar-width: thin; scrollbar-color: var(--color-border) transparent;
}
.onboarding-steps::-webkit-scrollbar { height: 8px; }
.onboarding-steps::-webkit-scrollbar-track { background: transparent; }
.onboarding-steps::-webkit-scrollbar-thumb {
  background: var(--color-border); border-radius: 999px;
}
.onboarding-step {
  position: relative; isolation: isolate;
  flex: 1 1 0; min-width: 0; min-height: 0;
  display: flex; flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: clamp(18px, 2vw, 28px);
  background: var(--color-surface-2);
  overflow: hidden;
  scroll-snap-align: center;
  transition:
    flex-grow .35s var(--ease-out),
    border-color .2s ease, background .2s ease, box-shadow .2s ease;
}
.onboarding-step.active {
  flex-grow: 1.8;
  border-color: var(--color-primary);
  background: var(--color-surface);
  box-shadow: 0 20px 56px rgba(94, 106, 210, 0.18);
}
.onboarding-step.done:not(.active) { background: var(--color-primary-soft); }

/* Badge "Cuenta lista / Ready" en cabecera y colapsado */
.ob-ready-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: #fff;
  background: var(--color-secondary);
  border: 1px solid var(--color-secondary);
  margin-left: auto;
}
.ob-step-head .ob-ready-badge { margin-left: 8px; }
.onboarding-step.active .ob-ready-badge { display: none; }

/* Barra superior de cada caja: lavanda en la activa, verde en las completadas.
   El número grande de fondo hace que las cajas plegadas no parezcan vacías. */
.onboarding-step::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 3px;
  background: transparent; z-index: 2; pointer-events: none;
  transition: background .2s ease;
}
.onboarding-step.active::before { background: var(--color-primary); }
.onboarding-step.done::before { background: var(--color-secondary); }
.onboarding-step::after {
  content: attr(data-step);
  position: absolute; right: clamp(10px, 1.4vw, 20px); bottom: clamp(4px, 1vh, 12px);
  z-index: 0; pointer-events: none; user-select: none;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(4rem, 8vw, 8rem); line-height: .8;
  color: var(--color-primary); opacity: .07;
  transition: opacity .2s ease;
}
.onboarding-step.active::after { opacity: .035; }

.ob-step-head {
  position: relative; z-index: 1;
  display: flex; align-items: flex-start; gap: 12px; width: 100%;
  flex: 0 0 auto;
  background: none; border: 0; border-radius: 0;
  padding: clamp(14px, 1.8vw, 22px);
  color: var(--color-text); font: inherit;
  text-align: left; cursor: pointer;
}
.ob-step-head:hover { background: var(--color-primary-soft); }
.ob-step-head:focus-visible {
  outline: 2px solid var(--color-primary); outline-offset: -3px;
}
.ob-step-headtext { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.ob-num {
  font-size: var(--font-size-xs); text-transform: uppercase; font-weight: 600;
  letter-spacing: 0.06em; color: var(--color-text-muted); margin: 0 0 5px;
}
.ob-step-title {
  font-family: var(--font-display);
  font-size: clamp(.95rem, 1.25vw, 1.2rem);
  font-weight: 600; line-height: 1.25; letter-spacing: -0.015em;
}
.onboarding-step.active .ob-step-title { color: var(--color-primary); }
.ob-step-check { font-size: 21px; color: var(--color-secondary); display: none; }
.onboarding-step.done .ob-step-check { display: inline-block; }
.ob-step-chevron {
  font-size: 21px; color: var(--color-text-muted); flex: 0 0 auto;
  margin-left: auto; transition: transform .25s ease;
}
.onboarding-step.active .ob-step-chevron { transform: rotate(180deg); }

/* La caja activa ocupa el alto restante y el contenido scrollea dentro, sin
   mover la cabecera ni la barra de progreso. `inert` (lo pone JS) impide que
   Tab entre en lo plegado. */
.ob-step-body {
  position: relative; z-index: 1;
  display: grid; grid-template-rows: 0fr; flex: 0 0 auto;
  min-height: 0; overflow: hidden; opacity: 0;
  transition: grid-template-rows .35s var(--ease-out), opacity .22s ease;
}
.onboarding-step.active .ob-step-body {
  grid-template-rows: 1fr; flex: 1 1 auto; opacity: 1;
}
.ob-step-inner {
  display: flex; flex-direction: column;
  min-height: 0; overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain;
  text-align: center; padding: 0 clamp(14px, 1.8vw, 22px);
  scrollbar-width: thin; scrollbar-color: var(--color-border) transparent;
}
.ob-step-inner::-webkit-scrollbar { width: 5px; }
.ob-step-inner::-webkit-scrollbar-track { background: transparent; }
.ob-step-inner::-webkit-scrollbar-thumb {
  background: var(--color-border); border-radius: 999px;
}
.onboarding-step.active .ob-step-inner { padding-bottom: clamp(14px, 1.8vw, 22px); }
.onboarding-step .ob-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: var(--radius-md);
  background: var(--color-primary-soft); color: var(--color-primary);
  font-size: 21px;
}
.onboarding-step.active .ob-ico { background: var(--color-primary); color: #fff; }
.onboarding-step.done:not(.active) .ob-ico {
  background: var(--color-secondary-soft); color: var(--color-secondary);
}
.onboarding-step p {
  color: var(--color-text-muted); font-size: var(--font-size-base);
  line-height: 1.55; margin: 0 0 14px;
}
.onboarding-step textarea,
.onboarding-step .ob-input {
  width: 100%; padding: 10px 12px; border-radius: var(--radius-md);
  border: 1px solid var(--color-border); background: var(--color-surface-2);
  color: var(--color-text); font-family: var(--font-body);
  font-size: var(--font-size-md); margin-bottom: 12px; text-align: left;
}
.onboarding-step textarea:focus-visible,
.onboarding-step .ob-input:focus-visible {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-soft);
}
.ob-tip {
  background: var(--color-surface-2); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); padding: 10px 12px;
  font-size: var(--font-size-sm) !important; color: var(--color-text) !important;
  text-align: left;
}
.ob-nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: auto; padding-top: 12px;
  border-top: 1px solid var(--color-border);
}
.onboarding-step .btn-link { margin-top: 10px; }

@media (max-width: 960px) {
  .onboarding-steps { scroll-snap-type: x mandatory; }
  .onboarding-step,
  .onboarding-step.active {
    flex: 0 0 min(86vw, 460px);
    min-width: min(86vw, 460px);
  }
}
@media (max-width: 600px) {
  .onboarding-box { --ob-pad: 14px; }
  .onboarding-top img { width: 26px; height: 26px; }
  .onboarding-top span { font-size: 1rem; }
  .onboarding-progress { margin: 12px 0 14px; }
  .onboarding-steps { gap: 10px; }
  .onboarding-step,
  .onboarding-step.active {
    flex-basis: min(88vw, 460px);
    min-width: min(88vw, 460px);
  }
  .ob-step-head { padding: 14px; }
  .onboarding-step.active .ob-step-inner { padding-bottom: 14px; }
}
@media (max-height: 560px) {
  .onboarding-box { --ob-pad: 12px; }
  .onboarding-progress { margin: 9px 0 11px; }
  .ob-step-head { padding: 12px 14px; }
  .ob-step-title { font-size: .95rem; }
  .onboarding-step.active .ob-step-inner { padding-bottom: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .ob-step-body, .ob-step-chevron, .onboarding-step,
  .onboarding-bar, .onboarding-step::before, .onboarding-step::after {
    transition: none;
  }
}
/* Zent Share Modal (YouTube style) */
.zent-share-overlay {
  position: fixed; inset: 0; z-index: 10001;
  background: rgba(0,0,0,0.7);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.zent-share-overlay.hidden { display: none; }
.zent-share-dialog {
  width: min(680px, 96vw);
  background: #0f0f0f;
  color: #fff;
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.8);
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.08);
}
.zent-share-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}
.zent-share-title { font-weight: 600; font-size: 1rem; }
.zent-share-close {
  background: transparent; border: 0; color: #fff; cursor: pointer;
  width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
}
.zent-share-close:hover { background: rgba(255,255,255,0.08); }
.zent-share-body { padding: 16px; }
.zent-share-apps {
  display: flex; gap: 12px; flex-wrap: nowrap; overflow-x: auto;
  padding-bottom: 8px;
}
.zent-share-app {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  min-width: 84px; text-decoration: none; color: #fff;
  background: transparent; border: 0; cursor: pointer;
}
.zent-share-ic {
  width: 56px; height: 56px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: #272727; font-size: 24px;
}
.zent-share-app:hover .zent-share-ic { background: #3f3f3f; }
.zent-share-lbl { font-size: 12px; text-align: center; }
.zent-share-linkrow {
  display: flex; gap: 10px; align-items: center;
  margin-top: 12px; background: #272727; border-radius: 12px; padding: 8px;
}
.zent-share-input {
  flex: 1; background: transparent; border: 0; color: #fff; font-size: 0.9rem;
  padding: 6px 8px;
}
.zent-share-copybtn {
  background: #3ea6ff; color: #000; border: 0; border-radius: 999px;
  padding: 8px 14px; font-weight: 600; cursor: pointer;
}
.zent-share-copybtn:hover { filter: brightness(1.05); }
.zent-share-status { margin-top: 8px; font-size: 0.8rem; color: #aaa; min-height: 18px; }

.btn-link { background: none; border: none; color: var(--color-text-muted); cursor: pointer; font-size: 0.82rem; text-decoration: underline; }

/* ---------- Superposición de controles de ventana (PWA de escritorio) ---------- */
@media (display-mode: window-controls-overlay) {
  .topbar {
    padding-left: env(titlebar-area-x, 0px);
    padding-top: env(titlebar-area-y, 0px);
    padding-right: env(titlebar-area-width, 0px);
    height: env(titlebar-area-height, 56px);
    -webkit-app-region: drag;
  }
  .topbar button,
  .topbar .racha,
  .topbar a {
    -webkit-app-region: no-drag;
  }
}

/* ---------- Vista IA ---------- */
.ia-card {
  max-width: 640px; margin: 0 auto; text-align: center;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: 36px 28px; box-shadow: var(--shadow-soft);
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
}
.ia-subtitle { color: var(--color-text-muted); margin: 10px 0 24px; }

.ia-options {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-bottom: 16px; font-size: 0.82rem;
}
.ia-options .field-label { margin: 0; }
.ia-options select {
  padding: 6px 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-bg);
  color: var(--color-text); font-family: var(--font-body); font-size: 0.85rem;
}

.ia-actions {
  display: flex; justify-content: center; gap: 10px; margin-top: 12px; flex-wrap: wrap;
}
/* Los botones de copiar/descargar llevan icono + texto: sin esto el <span> del
   glifo se pegaría a la palabra y el botón quedaría descentrado. */
.ia-actions .btn { display: inline-flex; align-items: center; gap: 6px; }

/* ---------- Tarjeta flotante de la propuesta de organización ----------
   Antes la propuesta era un bloque a todo el ancho, arriba de la vista
   IA, que empujaba el resumen hacia abajo con cada "Sugerir". Ahora es
   una tarjeta lateral compacta: flotante (ni empuja ni tapa), con tope
   de alto y su propio scroll, plegable a una tira y cerrable. Va
   ENCIMA del FAB de feedback, no a su costa. */
.zent-sugerir-salida {
  position: fixed; right: 18px; bottom: 76px; z-index: 55;
  width: min(340px, calc(100vw - 24px));
  max-height: min(58vh, 460px);
  display: flex; flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}
body[data-nav-pos="bottom"] .zent-sugerir-salida {
  bottom: calc(132px + env(safe-area-inset-bottom, 0px));
}
.zent-sugerir-cab {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-2);
}
.zent-sugerir-cab-tit {
  flex: 1;
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.zent-sugerir-plegar,
.zent-sugerir-cerrar {
  border: 0; background: transparent;
  color: var(--color-text-muted);
  font-size: 16px; line-height: 1;
  padding: 3px; border-radius: 6px;
  cursor: pointer;
}
.zent-sugerir-plegar:hover,
.zent-sugerir-cerrar:hover { background: var(--color-surface-2); color: var(--color-text); }
.zent-sugerir-cuerpo {
  padding: 10px 12px;
  overflow-y: auto;
  font-size: 12.5px;
}
.zent-sugerir-salida.plegado .zent-sugerir-cuerpo { display: none; }
.zent-sugerir-salida.plegado .zent-sugerir-cab { border-bottom: 0; }

/* Cerrada con la X: la tarjeta se oculta y deja en su lugar un botón discreto
   para volver a abrirla. Cerrar es reversible; antes la X borraba la tarjeta
   del DOM y no había forma de recuperarla sin recargar la página. */
.zent-sugerir-salida[hidden] { display: none; }
.zent-sugerir-reabrir {
  position: fixed; right: 18px; bottom: 76px; z-index: 55;
  box-shadow: var(--shadow-soft);
}
body[data-nav-pos="bottom"] .zent-sugerir-reabrir {
  bottom: calc(132px + env(safe-area-inset-bottom, 0px));
}
.ia-actions .btn .material-symbols-outlined { font-size: 1rem; }
.ia-actions .btn:disabled {
  opacity: .4; cursor: not-allowed; filter: grayscale(0.5);
  box-shadow: none; transform: none; pointer-events: none;
}

.day-nav {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  margin-bottom: 20px;
}
.day-nav-arrow {
  width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--color-border);
  background: var(--color-bg); color: var(--color-primary); font-size: 1.1rem; cursor: pointer;
}
.day-nav-arrow:disabled { opacity: 0.3; cursor: not-allowed; }
.day-nav-label { font-weight: 600; min-width: 120px; text-align: center; font-size: 1.02rem; }
.ia-text {
  text-align: left; background: var(--color-secondary-soft);
  border-radius: var(--radius-md); padding: 20px; margin-bottom: 20px;
  min-height: 90px; line-height: 1.6;
  /* Un resumen largo no debe empujar los controles ni alargar la vista: el
     texto se desplaza dentro de su caja. En móvil hay un tope menor (260px). */
  max-height: min(420px, 52vh); overflow-y: auto;
  overscroll-behavior-y: contain; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; scrollbar-color: var(--color-border) transparent;
}
.ia-text::-webkit-scrollbar { width: 5px; }
.ia-text::-webkit-scrollbar-track { background: transparent; }
.ia-text::-webkit-scrollbar-thumb {
  background: var(--color-border); border-radius: 3px;
}
.ia-text:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.ia-text p { margin: 0 0 12px; }
.ia-text p:last-child { margin-bottom: 0; }
.ia-text .ia-lista { margin: 0 0 12px; padding-left: 20px; }
.ia-text .ia-lista li { margin-bottom: 4px; }
.ia-placeholder { color: var(--color-text-muted); margin: 0; }

/* Skeleton de la generación: bloques con un barrido sutil de luz.
   El barrido es funcional (indica progreso), no decorativo: por eso es un
   gradiente móvil y muy tenue, no un efecto atmosférico. */
.zent-skeleton-wrap {
  display: flex; flex-direction: column; gap: 10px;
  text-align: left; background: var(--color-secondary-soft);
  border-radius: var(--radius-md); padding: 20px; margin-bottom: 20px;
  min-height: 90px;
}
.zent-skeleton-wrap[hidden] { display: none; }
.zent-skeleton {
  position: relative; overflow: hidden;
  display: block; height: 11px; width: 100%;
  background: var(--color-surface-2);
  border-radius: var(--radius-xs);
}
.zent-skeleton.w-90 { width: 90%; }
.zent-skeleton.w-70 { width: 70%; }
.zent-skeleton.w-45 { width: 45%; }
.zent-skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--color-surface-3), transparent);
  animation: zent-shimmer 1.5s ease-in-out infinite;
}
@keyframes zent-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}
/* ============================================================
   ESQUELETOS DE CARGA DE LISTAS (tareas y eventos)
   ============================================================
   La generación por IA ya tenía esqueleto, pero las dos listas principales no:
   al abrir la app se veía el panel de tareas y el de eventos VACÍOS detrás del
   splash, y luego aparecía el contenido de golpe. Eso se lee como fallo, y en
   una carga lenta parece que la app no ha hecho nada.

   Las barras reutilizan el mismo `zent-shimmer` que la IA, y por eso heredan
   su anulación con `prefers-reduced-motion` (más abajo, bloque L2790).

   `.zent-esq-barra` es una `<span>`, y un span inline no tiene altura: sin
   `display: block` las barras colapsarían a 0 px y el esqueleto no se vería
   NADA. Es el mismo motivo por el que `.zent-skeleton` lleva `display: block`. */
.zent-esq-fila {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.zent-esq-caja {
  display: block; flex: 0 0 auto;
  width: 18px; height: 18px; border-radius: var(--radius-sm);
  background: var(--color-surface-2);
}
.zent-esq-lineas { display: flex; flex-direction: column; gap: 8px; flex: 1 1 auto; min-width: 0; }
.zent-esq-barra {
  display: block; position: relative; overflow: hidden;
  height: 10px; border-radius: var(--radius-xs);
  background: var(--color-surface-2);
}
.zent-esq-barra::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--color-surface-3), transparent);
  animation: zent-shimmer 1.5s ease-in-out infinite;
}

/* ---- Sin salto de layout al pasar de esqueleto a datos ----
   El `min-height` reserva el hueco de cuatro filas ANTES de que existan. Sin
   esto, el panel de tareas crece de 0 a su altura real cuando llegan los datos
   y empuja hacia abajo los eventos y el resto de la página: en el móvil eso
   significa que el contenido que estabas leyendo se mueve solo.

   Cuatro filas es un mínimo, no un objetivo: si el día tiene menos de cuatro,
   sobra espacio en blanco; es preferible a que la página dé un tirón al
   cargar. */
.task-list[data-esqueleto] { min-height: 224px; }
.event-grid[data-esqueleto] { min-height: 224px; }

/* ---- Carga del timeline: indicador neón + rejilla de horas atenuada ----
   Los bloques grises del esqueleto se sustituyeron por esto: en lugar de
   simular contenido que todavía no existe, la rejilla real se pinta ya (el eje
   de horas no depende de la respuesta) y se atenúa a la mitad de opacidad,
   igual que cuando un diálogo bloquea el fondo. Eso deja claro que se está
   cargando sin inventar bloques falsos, y el indicador de arriba —un aro que
   gira y una barra con degradado azul→violeta— comunica el progreso. */
.timeline-cargando {
  display: none;
  align-items: center; gap: 10px;
  padding: 4px 12px 10px;
}
.timeline-view[data-cargando] .timeline-cargando { display: flex; }
.timeline-spinner {
  flex: 0 0 auto; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid rgba(94, 106, 210, 0.22);
  border-top-color: #5e6ad2;
  box-shadow: 0 0 8px rgba(94, 106, 210, 0.55);
  animation: zent-spin 0.8s linear infinite;
}
.timeline-progreso {
  position: relative; flex: 1 1 auto; height: 3px; overflow: hidden;
  border-radius: 999px; background: rgba(94, 106, 210, 0.14);
}
.timeline-progreso::before {
  content: ""; position: absolute; inset: 0; width: 38%;
  border-radius: 999px;
  background: linear-gradient(90deg, #2563eb, #7c3aed);
  box-shadow: 0 0 10px rgba(124, 58, 237, 0.8);
  animation: zent-progreso 1.1s ease-in-out infinite;
}
@keyframes zent-progreso {
  from { transform: translateX(-110%); }
  to   { transform: translateX(280%); }
}
/* La cuadrícula no se vacía mientras carga: se atenúa. Así el hueco ya tiene
   la forma del día (eje de horas) y no aparece un panel en blanco. */
.timeline-view[data-cargando] .timeline-grid,
.timeline-view[data-cargando] .timeline-all-day,
.timeline-view[data-cargando] .timeline-sin-hora {
  opacity: 0.5;
  transition: opacity 0.2s ease;
}

/* Aviso de que los datos del día cambiaron tras generar el resumen. El texto
   NO se borra (así se puede releer), solo se indica que quedó desfasado. */
/* Aviso de resumen desactualizado: ahora es un botón de acción directa. */
.ia-obsoleto {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 10px 0 0; padding: 7px 12px;
  font-family: var(--font-body); font-size: 0.76rem; font-weight: 600; line-height: 1.4;
  color: var(--color-primary);
  background: var(--color-primary-soft, #e8f0fe);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-sm, 8px);
  cursor: pointer; text-align: left;
  transition: background .15s ease, transform .12s ease;
}
.ia-obsoleto:hover { background: var(--color-surface); }
.ia-obsoleto:active { transform: scale(.98); }
.ia-obsoleto:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.ia-obsoleto .material-symbols-outlined { font-size: 16px; }
button.ia-obsoleto:disabled { opacity: .6; cursor: default; }

/* Aviso de idioma: el resumen ya existe pero se redactó en otro idioma.
   Es una fila con texto + botón, no un texto suelto: la acción (regenerar) es
   lo importante y tiene que estar a un clic. Usa el tono ámbar de aviso para
   destacar sin competir con el botón principal de "Generar". */
.ia-lang-aviso {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px; padding: 12px 14px;
  background: var(--color-accent-soft);
  border: 1px solid var(--color-accent); border-radius: var(--radius-md);
}
.ia-lang-aviso.hidden { display: none; }
/* Contador de cuota de IA: una línea discreta bajo el botón de generar. Va
   muted a propósito porque es un dato de contexto, no un aviso: no debe
   competir con el botón ni con el resumen. Cuando quedan 0 ya no es contexto
   sino un bloqueo, y por eso `.ia-quota-agotada` sí se pone en el color de
   error. */
.ia-quota {
  margin: 10px 0 0; text-align: center;
  font-size: .82rem; color: var(--color-text-muted);
}
.ia-quota.hidden { display: none; }
.ia-quota-agotada { color: var(--color-danger); font-weight: 600; }

/* Historial de resúmenes: plegado por defecto, debajo del reproductor. Es lo
   último de la vista porque es una función secundaria: el resumen de HOY es lo
   que se viene a hacer, y una lista de 30 días abierta de salida taparía lo
   único que importa en esa pantalla. */
.ia-historial { margin-top: 16px; border-top: 1px solid var(--color-border); padding-top: 10px; }
.ia-historial.hidden { display: none; }
.ia-historial-cabecera {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 0; padding: 6px 2px; cursor: pointer;
  color: var(--color-text-muted); font: inherit; font-size: .88rem; text-align: left;
}
.ia-historial-cabecera:hover { color: var(--color-text); }
.ia-historial-cabecera:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.ia-historial-icon { font-size: 18px; }
.ia-historial-chevron { margin-left: auto; transition: transform .2s ease; }
/* El chevron gira con aria-expanded, no con una clase aparte: una sola fuente
   de verdad para "está abierto o no", que es lo que un lector de pantalla
   lee y lo que evita que se desincronicen el giro y el atributo. */
.ia-historial-cabecera[aria-expanded="true"] .ia-historial-chevron { transform: rotate(180deg); }
.ia-historial-lista {
  list-style: none; margin: 6px 0 0; padding: 0 2px 0 0;
  max-height: min(260px, 42vh); overflow-y: auto;
  overscroll-behavior-y: contain; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; scrollbar-color: var(--color-border) transparent;
}
.ia-historial-lista::-webkit-scrollbar { width: 5px; }
.ia-historial-lista::-webkit-scrollbar-track { background: transparent; }
.ia-historial-lista::-webkit-scrollbar-thumb {
  background: var(--color-border); border-radius: 3px;
}
.ia-historial-lista[hidden] { display: none; }
.ia-historial-item {
  display: flex; align-items: baseline; gap: 8px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--color-text); font: inherit;
  font-size: .86rem; text-align: left; cursor: pointer;
}
.ia-historial-item:hover { background: var(--color-primary-soft); }
.ia-historial-item:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.ia-historial-fecha { flex-shrink: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
/* Extracto del resumen. Una sola línea con elipsis: el texto entero ya está en
   la búsqueda y en el día al que saltas, aquí solo hace falta reconocerlo. */
.ia-historial-texto {
  flex: 1; min-width: 0; color: var(--color-text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ia-historial-hoy {
  flex-shrink: 0; font-size: .72rem; padding: 1px 7px; border-radius: 999px;
  background: var(--color-primary-soft); color: var(--color-primary); font-weight: 600;
}
.ia-historial-vacio { padding: 8px 10px; color: var(--color-text-muted); font-size: .85rem; }
.ia-lang-aviso-icon { font-size: 20px; color: var(--color-accent); flex-shrink: 0; }
.ia-lang-aviso-txt { flex: 1; min-width: 0; }
.ia-lang-aviso-titulo {
  margin: 0; font-size: 0.83rem; font-weight: 600; line-height: 1.35; color: var(--color-text);
}
.ia-lang-aviso-sub { margin: 2px 0 0; font-size: 0.76rem; line-height: 1.4; color: var(--color-text-muted); }
.ia-lang-aviso-btn { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; }
.ia-lang-aviso-btn .material-symbols-outlined { font-size: 16px; }
@media (max-width: 560px) {
  .ia-lang-aviso { flex-wrap: wrap; }
  .ia-lang-aviso-btn { width: 100%; justify-content: center; }
}

/* Aviso de estado de carga (error / sin conexión / sincronización).
   Misma estructura que .ia-lang-aviso porque cumple el mismo papel: un aviso
   persistente con acción. El color cambia por `data-tipo` para que un fallo y
   un aviso informativo no se confundan. */
.zent-estado {
  display: flex; align-items: center; gap: 12px;
  margin: 0 16px 12px; padding: 12px 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.zent-estado.hidden { display: none; }
/* El tema de Zent es plano (sin sombras de marca), así que el estado se
   distingue por el borde y el icono, no por un tinte de fondo inventado. */
.zent-estado[data-tipo="error"] { border-color: var(--color-danger); }
.zent-estado[data-tipo="offline"] { border-color: var(--color-accent); }
.zent-estado-icono { font-size: 20px; color: var(--color-text-muted); flex-shrink: 0; }
.zent-estado[data-tipo="error"] .zent-estado-icono { color: var(--color-danger); }
.zent-estado[data-tipo="offline"] .zent-estado-icono { color: var(--color-accent); }
.zent-estado-texto { flex: 1; min-width: 0; }
.zent-estado-titulo { margin: 0; font-size: 0.83rem; font-weight: 600; line-height: 1.35; color: var(--color-text); }
.zent-estado-sub { margin: 2px 0 0; font-size: 0.76rem; line-height: 1.4; color: var(--color-text-muted); }
.zent-estado-btn { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 560px) {
  .zent-estado { flex-wrap: wrap; margin: 0 12px 12px; }
  .zent-estado-btn { width: 100%; justify-content: center; }
}

/* Estado vacío con acción: "no has conectado nada". Antes no existía y el
   backend devolvía `tasks: []` con normalidad, así que el primer día de cada
   usuario nuevo se vestía de día tranquilo. */
.item-empty-acciones { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.item-empty-acciones .item-empty { margin: 0; }


.audio-player {
  display: flex; align-items: center; gap: 12px;
  margin-top: 22px; padding: 10px 14px;
  background: var(--color-primary-soft);
  border: 1px solid var(--color-border); border-radius: 999px;
  position: relative; /* ancla del ecualizador superpuesto al play */
}
.play-btn {
  width: 34px; height: 34px; border-radius: 50%; border: none;
  background: var(--color-primary); color: #fff; cursor: pointer;
  font-size: 1.2rem;
  display: flex; align-items: center; justify-content: center;
  transition: transform .12s ease, background .15s ease;
}
.play-btn:hover:not(:disabled) { transform: scale(1.06); }
/* Estado "generando el audio": el círculo de progreso gira hasta que Google TTS
   responde. Antes era un "…" de texto plano, que no sugiere que la app trabaja. */
.ic-cargando { animation: zent-giro 1.1s linear infinite; }
@keyframes zent-giro { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ic-cargando { animation: none; } }
.play-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.play-btn .material-symbols-outlined { font-size: 1.3rem; }
/* Ecualizador: 4 barras superpuestas al botón de play, así no reservan hueco
   en el flex ni desplazan la barra de progreso. Solo se anima al reproducir. */
.zent-eq {
  position: absolute; left: 14px; top: 50%;
  width: 34px; height: 34px; margin-top: -17px;
  display: none; align-items: center; justify-content: center; gap: 2px;
  pointer-events: none;
}
.audio-player.reproduciendo .zent-eq { display: flex; }
.audio-player.reproduciendo .play-btn { color: transparent; }
.zent-eq i {
  display: block; width: 2.5px; height: 30%;
  background: #fff; border-radius: 2px;
  transform-origin: center center;
}
.audio-player.reproduciendo .zent-eq i { animation: zent-eq-pulso .9s ease-in-out infinite; }
.zent-eq i:nth-child(2) { animation-delay: .18s; }
.zent-eq i:nth-child(3) { animation-delay: .36s; }
.zent-eq i:nth-child(4) { animation-delay: .1s; }
@keyframes zent-eq-pulso {
  0%, 100% { transform: scaleY(.35); }
  50%      { transform: scaleY(1); }
}
.seek-btn {
  width: 30px; height: 30px; border-radius: 50%; border: none; flex-shrink: 0;
  background: var(--color-primary-soft); color: var(--color-primary);
  font-size: 1rem; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s ease, transform .12s ease, opacity .15s ease;
}
.seek-btn:hover:not(:disabled) { background: var(--color-secondary-soft); transform: scale(1.06); }
.seek-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.audio-track {
  flex: 1; height: 18px; position: relative;
  display: flex; align-items: center;
  cursor: pointer; touch-action: none;
}
.audio-bar {
  width: 100%; height: 5px;
  background: var(--color-border); border-radius: 999px; overflow: hidden;
}
.audio-progress {
  height: 100%; width: 0%; border-radius: 999px;
  background: linear-gradient(90deg, var(--color-accent), var(--color-secondary));
}
.audio-thumb {
  position: absolute; left: 0%; top: 50%;
  width: 14px; height: 14px; border-radius: 50%;
  background: #fff; border: 2px solid var(--color-primary);
  transform: translate(-50%, -50%);
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
  pointer-events: none;
  opacity: 0; transition: opacity .15s ease, transform .15s ease;
}
.audio-player.ready .audio-thumb,
.audio-track:hover .audio-thumb,
.audio-track.dragging .audio-thumb { opacity: 1; }
.audio-track.dragging .audio-thumb { transform: translate(-50%, -50%) scale(1.3); }
.audio-time { font-size: 0.75rem; color: var(--color-text-muted); min-width: 32px; }

/* ---------- Vista Settings ---------- */
.settings-list { max-width: 640px; margin: 0 auto; padding: 0 16px; width: 100%; box-sizing: border-box; display: flex; flex-direction: column; gap: 22px; }
.settings-group h3 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-text-muted); margin-bottom: 8px; font-family: var(--font-body); }
.settings-privacy-group h3 { margin-bottom: 0; }
.privacy-card {
  border: 1px solid var(--color-border, #e2e6ee);
  border-radius: var(--radius-lg, 12px);
  padding: 14px 16px;
  background: linear-gradient(180deg, var(--color-primary-soft, #e8f0fe), rgba(255, 255, 255, 0));
  display: flex; flex-direction: column; gap: 10px;
}
.privacy-badge {
  display: inline-flex; align-items: center; justify-content: center;
  align-self: flex-start;
  font-size: 0.78rem; font-weight: 600;
  color: var(--color-primary, #4a78f5);
  border: 1px solid var(--color-border, #e2e6ee);
  background: rgba(255, 255, 255, 0.6);
  border-radius: 999px; padding: 4px 11px;
  gap: 5px;
}
.privacy-badge .material-symbols-outlined { font-size: 0.8rem; }
.privacy-list { margin: 0; padding-left: 18px; display: grid; gap: 6px; }
.privacy-list li { font-size: 0.8rem; line-height: 1.45; color: var(--color-text, #1b1f27); }
.privacy-card .btn { align-self: flex-start; }
.settings-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); margin-bottom: 6px;
}
/* El selector de zona horaria contiene nombres largos (p. ej.
   "America/Argentina/Buenos_Aires"): lo limitamos para que no desborde
   la fila ni aplaste la etiqueta en pantallas estrechas. */
.settings-row select { padding: 6px 8px; border-radius: var(--radius-sm); border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text); cursor: pointer; max-width: 58%; min-width: 0; }
/* Campos de texto de Ajustes (el nombre con el que te llaman, tu interés).
   Mismo tratamiento que el `select` de al lado: mismo borde, mismo fondo y el
   mismo `min-width: 0`, que es lo que evita que un input ancho desborde la
   fila en pantallas estrechas. `width: 100%` porque aquí el campo es el
   protagonista de la fila apilada, no un control a la derecha. */
.settings-row input[type="text"] { padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text); width: 100%; min-width: 0; font: inherit; }
.settings-row input[type="text"]:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
/* Fila con etiqueta + campo + pista apilados en vertical. La de por defecto es
   `space-between` en horizontal, que para un input deja el texto|label|input
   colgando y con la pista sin sitio. */
.settings-row-stack { flex-direction: column; align-items: stretch; gap: 4px; }
.settings-row-stack label { font-size: .92rem; font-weight: 600; }
/* Pista de ayuda bajo un campo. Muted y pequeña a propósito: es contexto, no
   otra etiqueta, y compite por la atención con lo que la persona está
   escribiendo. */
.settings-hint { color: var(--color-text-muted); font-size: .8rem; line-height: 1.35; }
.settings-row.clickable { cursor: pointer; transition: background .15s ease; }
.settings-row.clickable:hover { background: var(--color-primary-soft); }
.settings-row.clickable:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.settings-chevron { color: var(--color-text-muted); font-size: 1.1rem; }
.settings-chevron.material-symbols-outlined { font-size: 1.15rem; }

/* Enlaces secundarios (Desarrollador / Nosotros / Privacidad / Términos):
   estilo de lista de ajustes nativa, sin el azul/subrayado del navegador.
   Texto gris neutro, chevron a la derecha y hover suave a blanco (dark). */
.settings-row.settings-link-row { padding: 0; cursor: pointer; }
.settings-link-row a {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  flex: 1; min-height: 24px; padding: 10px 12px;
  color: #999; text-decoration: none; cursor: pointer;
  transition: color .15s ease;
}
.settings-link-row a .settings-chevron { color: inherit; opacity: .75; font-size: 1.15rem; }
.settings-link-row:hover { background: var(--color-primary-soft); }
.settings-link-row a:hover { color: #17181C; }
.settings-link-row a:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
[data-theme="dark"] .settings-link-row a { color: #A1A1AA; }
[data-theme="dark"] .settings-link-row a:hover { color: #FFF; }

/* Modal de feedback / reporte de bug */
.fb-pills { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.fb-pill {
  border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text);
  border-radius: 999px; padding: 7px 14px; font-size: 0.85rem; font-family: var(--font-body);
  cursor: pointer; transition: background .15s ease, border-color .15s ease;
}
.fb-pill.active { background: var(--color-primary-soft); border-color: var(--color-primary); font-weight: 600; }
.fb-context { font-size: 0.74rem; color: var(--color-text-muted); margin: 10px 0 14px; line-height: 1.4; }
.fb-done { text-align: center; font-weight: 600; color: var(--color-secondary); padding: 34px 12px; font-size: 0.9rem; }

/* Confirmación de cierre de sesión: por encima de onboarding (200) y por
   debajo del aviso beta (300), que solo sale en la primera visita. */
#signout-overlay { z-index: 260; }
.confirm-box { max-width: 430px; }
.confirm-box h3 {
  font-family: var(--font-display); font-weight: 600; font-size: 1.2rem;
  margin: 0 0 10px; color: var(--color-text);
}
.confirm-warning {
  color: var(--color-text-muted); font-size: 0.9rem; line-height: 1.55;
  margin: 0;
}
.confirm-actions {
  display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;
  flex-wrap: wrap;
}
@media (max-width: 480px) {
  .confirm-actions { flex-direction: column-reverse; }
  .confirm-actions .btn { width: 100%; }
}

/* Aviso de Producción / Beta (primera visita): sobre onboarding y celebración */
#beta-overlay { z-index: 300; }
#beta-overlay .modal-box { max-width: 470px; }
.beta-notice { text-align: center; padding: 6px 4px; }
.beta-notice h3 {
  font-family: var(--font-display); font-weight: 600; font-size: 1.25rem;
  margin: 0 0 10px;
}
.beta-notice p {
  color: var(--color-text-muted); font-size: 0.9rem; line-height: 1.55;
  margin: 0 0 18px;
}
.account-name { display: flex; flex-direction: column; gap: 2px; font-weight: 600; }
.account-status {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.72rem; font-weight: 500; letter-spacing: 0.02em;
}
.account-status .material-symbols-outlined { font-size: 0.85rem; }
.account-status[data-connected="true"] { color: #2E9E5B; }
.account-status[data-connected="false"] { color: var(--color-text-muted); }
[data-theme="dark"] .account-status[data-connected="true"] { color: #4ADE80; }

/* Cambio de idioma: micro-fundido de 50 ms. Es un cambio de texto puro, así
   que basta con atenuar y restaurar: si durara más se leería como parpadeo. */
.topbar, .tabbar, .day-bar, .views {
  transition: opacity var(--dur-idioma) ease;
}
body.zent-cambiando-idioma .topbar,
body.zent-cambiando-idioma .tabbar,
body.zent-cambiando-idioma .day-bar,
body.zent-cambiando-idioma .views {
  opacity: 0;
}

/* Tarjeta abierta desde la Command Palette: se resalta un instante para que se
   vea a qué elemento se saltó. */
.zent-buscado {
  animation: zent-buscado 1s ease-out;
  border-radius: var(--radius-md);
}
@keyframes zent-buscado {
  0%   { box-shadow: 0 0 0 0 var(--color-primary); background: var(--color-primary-soft); }
  60%  { box-shadow: 0 0 0 3px var(--color-primary-soft); background: var(--color-primary-soft); }
  100% { box-shadow: 0 0 0 3px transparent; background: transparent; }
}

/* ---------- Toast ---------- */
.toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translateX(-50%) translateY(16px);
  background: var(--color-primary); color: #fff; padding: 10px 18px; border-radius: 999px;
  font-size: 0.85rem; opacity: 0; pointer-events: none; z-index: 50;
  /* Solo transform y opacity: `all` recalcularía el layout en cada frame. */
  transition: opacity var(--dur-toast) var(--ease-out),
              transform var(--dur-toast) var(--ease-out);
  overflow: hidden;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Barra de tiempo: se vacía en horizontal mientras el aviso está visible. */
.zent-toast-barra {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: rgba(255, 255, 255, .32);
  transform-origin: left center;
  animation: zent-barra-vacia linear forwards;
  pointer-events: none;
}
@keyframes zent-barra-vacia {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

/* ---------- Menú contextual (clic derecho sobre tareas y eventos) ---------- */
.ctx-menu {
  position: fixed; z-index: 300; min-width: 180px;
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
  padding: 6px; display: flex; flex-direction: column; gap: 2px;
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
}
.ctx-item {
  text-align: left; padding: 9px 12px; border: none; border-radius: 6px;
  background: none; cursor: pointer;
  font-family: var(--font-body); font-size: 0.88rem; font-weight: 500; color: var(--color-text);
  display: flex; align-items: center; gap: 9px; white-space: nowrap;
  transition: background .12s ease, color .12s ease;
}
.ctx-item:hover { background: var(--color-primary-soft); }
.ctx-item-icon { font-size: 17px; color: var(--color-text-muted); }
.ctx-item:hover .ctx-item-icon { color: inherit; }
.ctx-danger { color: var(--color-danger); }
.ctx-danger:hover { background: var(--color-danger); color: #fff; }

/* ---------- Celebración de racha (al terminar el audio del día) ---------- */
.streak-celebration {
  position: fixed; inset: 0; z-index: 200;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: rgba(15, 20, 24, 0.55);
  opacity: 0; pointer-events: none;
}
.streak-celebration.show {
  animation: streakFade 2s ease forwards;
}
.streak-celebration-logo {
  width: 64px; height: 64px; margin-bottom: 14px;
}
.streak-celebration.show .streak-celebration-logo {
  animation: streakPop 2s ease forwards;
}
.streak-celebration-days {
  font-family: var(--font-display); font-size: 1.7rem; font-weight: 600; color: #fff;
}
.streak-celebration-level {
  margin-top: 6px; font-size: 1.05rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: #FFE08A;
}
@keyframes streakFade {
  0%   { opacity: 0; }
  15%  { opacity: 1; }
  80%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes streakPop {
  0%   { transform: scale(0.5); }
  20%  { transform: scale(1.15); }
  35%  { transform: scale(1); }
  100% { transform: scale(1); }
}

/* ==========================================================
   PÁGINAS INFORMATIVAS (Privacidad, Sobre nosotros)
   ========================================================== */
.info-page {
  max-width: 720px; margin: 0 auto; padding: 32px 20px 80px;
}
.info-header { text-align: center; margin-bottom: 28px; }
.info-header .info-brand { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 14px; }
.info-header h1 { font-size: 1.9rem; }
.info-header .info-sub { color: var(--color-text-muted); font-size: 0.95rem; }
.info-updated {
  display: inline-block; font-size: 0.72rem; color: var(--color-text-muted);
  background: var(--color-primary-soft); border-radius: 999px; padding: 4px 12px; margin-top: 10px;
}
.info-card {
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: 24px; margin-bottom: 18px;
  box-shadow: var(--shadow-soft); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
}
.info-card h2 {
  font-size: 1.1rem; margin-bottom: 10px;
  display: flex; align-items: center; gap: 8px;
}
.info-card p, .info-card li { color: var(--color-text); line-height: 1.65; font-size: 0.92rem; }
.info-card ul { list-style: disc; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; }
.info-card a { color: var(--color-secondary); font-weight: 600; }
.info-contact { text-align: center; font-size: 0.85rem; color: var(--color-text-muted); margin-top: 24px; }
.info-back { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 24px; color: var(--color-secondary); font-weight: 600; text-decoration: none; }
.info-back .material-symbols-outlined { font-size: 18px; }
.info-back:hover { text-decoration: underline; }

/* Selector de idioma de las páginas legales. Es lo único que estas páginas
   tienen y la app no: sin él, los textos legalizados en los seis idiomas
   serían inalcanzables para quien no lee en español. */
.info-lang {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 28px; font-size: 0.85rem; color: var(--color-text-muted);
}
.info-lang label { font-weight: 600; }
.info-lang select {
  font: inherit; font-size: 0.85rem; color: var(--color-text);
  background: var(--color-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px); padding: 6px 10px; cursor: pointer;
}
.info-lang select:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* ============================================================
   AJUSTES AVANZADOS — Apariencia (persistidos en localStorage)
   ============================================================ */

/* --- Switch ON/OFF reutilizable (racha: mostrar/ocultar contador) --- */
.switch {
  position: relative; display: inline-flex; flex: none;
  width: 44px; height: 24px; cursor: pointer;
}
.switch input {
  position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer;
}
.switch-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--color-border); transition: background .15s ease;
}
.switch-track::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--color-surface); box-shadow: var(--shadow-soft);
  transition: transform .15s ease;
}
.switch input:checked + .switch-track { background: var(--color-primary); }
.switch input:checked + .switch-track::after { transform: translateX(20px); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* --- Botón flotante "Feedback" (FAB, discreto, abajo-derecha) --- */
.fab-feedback {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 10px 16px; border-radius: 999px; border: 1px solid var(--color-border);
  background: var(--color-surface); color: var(--color-text);
  font-family: var(--font-body); font-size: 0.82rem; font-weight: 600;
  box-shadow: var(--shadow-soft); cursor: pointer;
  opacity: 0.88; transition: opacity .15s ease, transform .15s ease;
}
.fab-feedback:hover { opacity: 1; transform: translateY(-1px); }
.fab-feedback:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* --- Menú de navegación flotante inferior (Ajustes → "Ubicación del menú") ---
   body[data-nav-pos="bottom"] convierte la barra superior fija en una
   píldora flotante centrada en la parte inferior, estilo barra de app. */
body[data-nav-pos="bottom"] .tabbar {
  position: fixed; top: auto; bottom: 20px; left: 50%; transform: translateX(-50%);
  width: max-content; max-width: calc(100vw - 32px);
  display: flex; gap: 4px; padding: 6px 8px;
  border-radius: 999px; border: 1px solid var(--color-border);
  background: var(--color-surface); box-shadow: var(--shadow-soft);
}
body[data-nav-pos="bottom"] .tab-btn { border-bottom: none; }
body[data-nav-pos="bottom"] .tab-btn.active {
  border-bottom: none; background: var(--color-primary-soft);
  color: var(--color-primary); border-radius: 999px;
}
/* En el menú inferior la pestaña activa ya se marca con su propia pastilla de
   fondo, así que la línea de 2px de la barra superior sobra: al ser la barra
   una píldora redondeada, la línea quedaba pegada al borde y parecía un
   fragmento morado suelto. Se oculta y no se recoloca. */
body[data-nav-pos="bottom"] .tab-pill { display: none; }
@media (max-width: 720px) { body[data-nav-pos="bottom"] .tabbar { width: auto; max-width: calc(100% - 32px); left: 50%; transform: translateX(-50%); border-radius: 9999px; } }
@media (min-width: 721px) {
  /* La píldora flotante mide ~50 px y va a 20 px del borde: reservar
     sólo 96 px dejaba la última tarjeta y el reproductor de la vista
     IA a un paso de montarse sobre la barra. `main` y `.views` son el
     mismo elemento: una sola regla. */
  body[data-nav-pos="bottom"] .views { padding-bottom: 112px; }
}
/* ============================================================
   F1 — Conflicto visual discreto (tarjetas del día)
   ============================================================ */
.zent-solapa {
  outline: 1.5px solid rgba(214, 162, 42, 0.55) !important;
  outline-offset: -1.5px;
}
.zent-solapa-badge {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 9.5px; font-weight: 600; letter-spacing: .02em;
  color: #8a6d1f; background: rgba(214, 162, 42, 0.12);
  border: 1px solid rgba(214, 162, 42, 0.35);
  border-radius: 999px; padding: 2px 7px; margin-left: 6px;
  vertical-align: middle; line-height: 1.4;
}
html[lang] .zent-solapa-badge { color: #8a6d1f; }
/* Mismo motivo que en `.login-aviso`: esto tiene que seguir al tema que eligió
   la persona, no al del sistema operativo. */
[data-theme="dark"] .zent-solapa-badge { color: #dbb45a; background: rgba(214,162,42,.16); }

/* ============================================================
   F2 / F3 — Tarjetas nuevas en la pestaña de IA
   ============================================================ */
.zent-ia-block {
  margin: 10px 0 6px; padding: 12px 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}
.zent-ia-block h4 {
  margin: 0 0 8px; font-size: 12.5px; font-weight: 600;
  color: var(--color-text);
}
.zent-ia-block button.zent-prim,
.zent-ia-block button.zent-sec {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 500; cursor: pointer;
  border-radius: 999px; padding: 7px 14px; border: 1px solid var(--color-border);
  background: var(--color-surface); color: var(--color-text);
}
.zent-ia-block button.zent-prim:hover { border-color: var(--color-primary); color: var(--color-primary); }
.zent-ia-block button.zent-sec { background: transparent; }
.zent-ia-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.zent-ia-list li {
  display: flex; gap: 8px; align-items: baseline;
  font-size: 12.5px; line-height: 1.5;
}
.zent-ia-list .zent-h { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 86px; }
.zent-ia-nota { margin: 8px 0 0; font-size: 11px; color: var(--color-text-muted); }
.zent-recap { border-left: 3px solid var(--color-primary); }

/* ============================================================
   F5 — Mini-calendario (barra flotante de 7 días)
   ============================================================ */
.zent-minitoggle {
  display: inline-flex; gap: 6px; align-items: center;
  margin: 0 0 10px;
}
.zent-minitoggle button {
  font-size: 11px; font-weight: 500; cursor: pointer;
  padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--color-border);
  background: var(--color-surface); color: var(--color-text-muted);
}
.zent-minitoggle button[data-activo] {
  color: var(--color-primary); border-color: var(--color-primary);
  background: var(--color-primary-soft);
}
.zent-minical {
  /* El widget actual apila en vertical la tira de días (.zent-minical-semana,
     que sí tiene su propia rejilla de 7 columnas), el título y la agenda.
     Antes se heredaba aquí una rejilla de 7 columnas iguales que comprimía
     la tira, el título y la lista en las tres primeras celdas: los dígitos
     de los días se encimaban a la izquierda ("567891011") y la agenda quedaba
     ilegible. El bloque "Vista Mini" (más abajo) da el acabado de tarjeta;
     aquí solo se garantiza el apilado vertical. */
  display: block;
  padding: 10px; margin: 0 0 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

/* ============================================================
   F7 — Modal de búsqueda global (Cmd/Ctrl+K)
   ============================================================ */
#zent-buscar-modal { position: fixed; inset: 0; z-index: 120; }
#zent-buscar-modal .zent-fondo {
  position: absolute; inset: 0; background: rgba(12, 14, 20, 0.35);
  backdrop-filter: blur(2px);
}
#zent-buscar-modal .zent-caja {
  position: relative; width: min(700px, 92vw); margin: 12vh auto 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 18px 50px rgba(0,0,0,.18);
  overflow: hidden;
  animation: zent-bajar .16s ease-out;
}
@keyframes zent-bajar { from { opacity: 0; transform: translateY(-6px); } }
#zent-buscar-modal input {
  /* Sin `outline: 0`: aqui no hay marco contenedor al que=colgar el anillo,
     asi que se deja el del respaldo global (ver bloque de foco visible). */
  width: 100%; border: 0; font-size: 14px;
  padding: 14px 16px; background: transparent; color: var(--color-text);
}
#zent-buscar-modal .zent-res { max-height: 46vh; overflow: auto; border-top: 1px solid var(--color-border); }
#zent-buscar-modal .zent-pie {
  display: flex; gap: 14px; padding: 8px 16px;
  font-size: 10.5px; color: var(--color-text-muted);
  border-top: 1px solid var(--color-border);
}
#zent-buscar-modal .zent-gr {
  padding: 6px 14px 2px; font-size: 10px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--color-text-muted);
}
#zent-buscar-modal button.zent-f {
  display: flex; flex-direction: column; gap: 1px; width: 100%;
  text-align: left; padding: 9px 14px; background: transparent;
  border: 0; cursor: pointer; color: var(--color-text);
}
#zent-buscar-modal button.zent-f:hover { background: var(--color-primary-soft); }
#zent-buscar-modal button.zent-f .zent-s { font-size: 11px; color: var(--color-text-muted); }

/* ============================================================
   F6 — Estado offline (píldora discreta + cola)
   ============================================================ */
.zent-estado-red {
  position: fixed; right: auto; left: 180px; bottom: 14px; z-index: 60;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--color-text-muted);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px; padding: 6px 12px;
  opacity: .92; box-shadow: var(--shadow-soft);
  pointer-events: none;
}
.zent-offline-sync::after {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-primary);
  animation: zent-spin .8s linear infinite;
}
@keyframes zent-spin { to { transform: rotate(360deg); } }

/* ============================================================
   Adjuntos (F8) — Feedback, Tareas y Eventos
   ============================================================ */
.zent-adj input[type=file]:focus + * { box-shadow: 0 0 0 2px var(--color-primary-soft); }
.zent-adj-preview img { display:block; }
.zent-adj { animation: zent-aparece .14s ease-out; }
.zent-adj-lab .zent-adj-stat { font-weight: 500; opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 90px; }
@keyframes zent-aparece { from { opacity:0; transform: translateY(2px); } }
@media (max-width: 560px) {
  .zent-adj-preview { gap:6px!important; }
}

/* ============================================================
   F9 — Modal de Detalles + Deshacer (tareas y eventos)
   ============================================================ */

/* ---------- Toast con acción (botón Deshacer) ---------- */
.toast.zent-toast-accion {
  display: flex; align-items: center; gap: 12px;
  pointer-events: auto; max-width: calc(100vw - 32px);
  /* Radio compacto: con 999px la barra de tiempo (2px, abajo) quedaría
     recortada por el overflow. */
  border-radius: var(--radius-lg);
  padding-bottom: 12px;
}
.zent-toast-undo {
  background: rgba(255,255,255,.28); color: #fff;
  border: none; border-radius: 999px; padding: 5px 14px;
  font-family: var(--font-body); font-size: .8rem; font-weight: 700;
  cursor: pointer; white-space: nowrap; flex-shrink: 0;
  transition: background .12s ease, transform .12s ease;
}
.zent-toast-undo:hover { background: rgba(255,255,255,.42); }
.zent-toast-undo:active { transform: scale(.96); }

/* ---------- Modal de detalles ---------- */
.modal-box-detail { max-width: 520px; }
.detail-tipo {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .7rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--color-primary);
  background: var(--color-primary-soft);
  border: 1px solid var(--color-primary);
  border-radius: 999px; padding: 3px 10px;
}
.detail-titulo { font-size: 1.25rem; margin: 8px 0 10px; line-height: 1.3; }
.detail-meta,
.detail-filas { display: flex; flex-wrap: wrap; gap: 6px; }
.detail-meta { margin-bottom: 4px; }
.detail-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .76rem; font-weight: 600;
  background: var(--color-bg); color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: 999px; padding: 4px 11px;
}
.detail-chip .material-symbols-outlined { font-size: 0.8rem; }
.detail-chip-link {
  color: var(--color-primary); border-color: var(--color-primary);
  text-decoration: none;
}
.detail-chip-link:hover { background: var(--color-primary-soft); }
.detail-seccion { margin-top: 14px; }
.detail-seccion-tit,
.detail-adjuntos-titulo {
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--color-text-muted);
  margin: 0 0 8px;
}
.detail-desc { white-space: pre-wrap; word-break: break-word; font-size: .92rem; color: var(--color-text); margin: 0; }
.detail-subtareas { margin: 0; padding-left: 18px; color: var(--color-text); font-size: .92rem; }
.detail-subtask { margin: 3px 0; }
.detail-subtask.done { text-decoration: line-through; color: var(--color-text-muted); }

/* ---------- Adjuntos en detalle ---------- */
.detail-adjuntos { margin-top: 16px; }
.detail-adj-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.detail-adj-vacio { color: var(--color-text-muted); font-size: .85rem; margin: 0; }
.detail-adj-img {
  width: 112px; cursor: zoom-in; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); overflow: hidden;
  background: var(--color-bg);
  display: flex; flex-direction: column;
  transition: border-color .12s ease, transform .12s ease;
}
.detail-adj-img:hover { border-color: var(--color-primary); transform: translateY(-1px); }
.detail-adj-img img { width: 100%; height: 84px; object-fit: cover; display: block; }
.detail-adj-cap { font-size: .68rem; padding: 4px 6px; color: var(--color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.detail-adj-doc {
  display: flex; align-items: center; gap: 10px;
  min-width: 208px; max-width: 100%;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: 10px; background: var(--color-bg);
}
.detail-adj-doc-ico {
  width: 38px; height: 38px; border-radius: 10px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--color-primary-soft); color: var(--color-primary);
  font-size: .68rem; font-weight: 800;
}
.detail-adj-doc-info { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 5px; }
.detail-adj-doc-nom { font-size: .88rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.detail-adj-doc-btn {
  align-self: flex-start; font-size: .74rem; font-weight: 700;
  color: var(--color-primary); text-decoration: none;
  border: 1px solid var(--color-primary); padding: 3px 12px; border-radius: 999px;
  background: transparent; cursor: pointer; font-family: inherit; line-height: 1.4;
  transition: background .12s ease;
}
.detail-adj-doc-btn:hover { background: var(--color-primary-soft); }
.detail-adj-img:focus-visible,
.detail-adj-doc-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 1px; }

.chip-adj { font-weight: 700; }
/* El chip de adjunto es ahora un <button> (vista previa interna): seneutraliza
   el aspecto de enlace por defecto del navegador. */
button.chip-adj { border: inherit; cursor: pointer; font-family: inherit; line-height: inherit; }
button.chip-adj:hover { background: var(--color-primary-soft); }

/* ---------- Visor integrado de adjuntos (In-App Preview) ---------- */
/* Visor de adjuntos: backdrop más oscuro y esmerilado para separar la
   previsualización del fondo, con la misma entrada de escala del modal. */
.adj-preview-overlay {
  z-index: 160;
  background: rgba(8, 10, 14, .72);
  backdrop-filter: blur(6px) saturate(1.1);
  -webkit-backdrop-filter: blur(6px) saturate(1.1);
}
.modal-box-adj {
  max-width: min(960px, 100%); height: min(88vh, 100%);
  display: flex; flex-direction: column; padding: 14px 16px 16px;
}
.adj-preview-head { flex-shrink: 0; margin-bottom: 12px; gap: 12px; }
.adj-preview-titulo {
  font-size: 0.95rem; font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.adj-preview-acciones { display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0; }
.adj-preview-cerrar { white-space: nowrap; }
.adj-preview-cuerpo {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  background: var(--color-bg); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); overflow: hidden;
}
.adj-preview-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.adj-preview-frame { width: 100%; height: 100%; border: 0; background: #fff; }
.adj-preview-sin { text-align: center; padding: 32px 20px; color: var(--color-text-muted); }
.adj-preview-sin-ico {
  font-size: 0.9rem; font-weight: 700; letter-spacing: .04em;
  color: var(--color-primary); border: 1px solid var(--color-border);
  border-radius: 999px; padding: 6px 14px; display: inline-block; margin-bottom: 12px;
}
.adj-preview-sin-txt { margin: 0; font-size: 0.85rem; }
/* Evita que la página de fondo siga desplazándose con el visor abierto. */
body.adj-preview-abierto { overflow: hidden; }

@media (max-width: 560px) {
  .detail-adj-img { width: 46%; }
  .detail-adj-doc { min-width: 0; width: 100%; }
}

/* ============================================================
   F10 — Terminal de desarrollador (overlay persistente)
   ============================================================ */
#zent-devterm {
  position: fixed; left: 50%; bottom: 12px; transform: translateX(-50%);
  width: min(760px, calc(100vw - 24px)); max-height: 46vh;
  display: flex; flex-direction: column;
  background: rgba(10, 12, 17, .93);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 12px;
  box-shadow: 0 18px 60px rgba(0, 0, 0, .45);
  color: #d7dae0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  z-index: 400; overflow: hidden;
}
.zdt-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 7px 10px; border-bottom: 1px solid rgba(255, 255, 255, .1);
  background: rgba(255, 255, 255, .04);
}
.zdt-titulo { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: #8b93a7; font-weight: 700; }
.zdt-acc { display: flex; gap: 6px; }
.zdt-btn {
  background: transparent; border: 1px solid rgba(255, 255, 255, .16); color: #c4c9d4;
  font-size: 10px; font-family: inherit; padding: 3px 8px; border-radius: 6px; cursor: pointer;
}
.zdt-btn:hover { background: rgba(255, 255, 255, .12); }
.zdt-out {
  flex: 1; overflow-y: auto; max-height: 30vh;
  padding: 8px 12px; font-size: 12px; line-height: 1.55;
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .18) transparent;
}
.zdt-out::-webkit-scrollbar { width: 6px; }
.zdt-out::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .18); border-radius: 999px; }
.zdt-line.err { color: #ff7b82; }
.zdt-line.ok { color: #7ee2a8; }
.zdt-line.dim { color: #8b93a7; }
.zdt-fila {
  display: flex; align-items: center; gap: 8px;
  border-top: 1px solid rgba(255, 255, 255, .1); padding: 7px 12px;
  background: rgba(0, 0, 0, .25);
}
.zdt-prompt { color: #7ee2a8; font-size: 13px; font-weight: 700; }
.zdt-inp {
  /* Sin `outline: 0`: mismo caso que el modal de busqueda, el anillo lo aporta
     el respaldo global. */
  flex: 1; background: transparent; border: 0;
  color: #e6e9ef; font-family: inherit; font-size: 12.5px;
}
.zdt-inp::placeholder { color: #5c6475; }
@media (max-width: 560px) {
  #zent-devterm { width: calc(100vw - 16px); bottom: 8px; }
}

/* ============================================================
   L12 — Refinamiento estructural estricto según DESIGN.md
   Bordes hairline de 1px, superficies sólidas en escalera,
   radios compactos (8px botones / 12px tarjetas), espaciado
   compacto y un único acento cromático de marca (lavanda).
   ============================================================ */

/* ---------- Espaciado compacto ---------- */
/* El inset de zona segura se repite aquí a propósito: el `padding` de
   arriba es un atajo que pondría los cuatro lados a 0, así que sin esta línea
   el móvil compacto perdería la reserva del reloj. */
.topbar { padding: 10px 16px; padding-top: calc(10px + env(safe-area-inset-top, 0px)); }
.views { padding: 16px 16px 56px; }
.split { gap: 14px; }
.panel { padding: 14px 16px; border-radius: var(--radius-lg); }
.panel-header { margin-bottom: 12px; }
.task-list { gap: 6px; }
.task-card-row { padding: 10px 12px; }
.task-desc { padding: 4px 12px 0; }
.task-card.expanded .task-desc { padding: 4px 12px 4px; }
.task-chips { padding: 0 12px 8px; }
.event-grid { gap: 8px; }
/* el padding de .event-card vive solo en la regla base */
.event-card { border-radius: var(--radius-lg); }
.grid-empty, .item-empty { padding: 16px 12px; border-radius: var(--radius-lg); }
.mini-item { padding: 7px 10px; }
.settings-list { gap: 16px; }
.settings-row { padding: 10px 12px; border-radius: var(--radius-sm); }
.modal-box { padding: 16px 18px; border-radius: var(--radius-lg); }
.modal-header { margin-bottom: 12px; }
.modal-form { gap: 8px; }
.modal-form .btn { margin-top: 16px; }
.ia-card { padding: 28px 22px; border-radius: var(--radius-lg); }

/* --- Resumen de IA en móvil: alto acotado, scroll interno ---
   Sin esto, un resumen largo empuja el botón "Generar", los de copiar y
   descargar y el reproductor de audio fuera de la pantalla, y hay que
   hacer scroll para llegar a ellos. Con el tope de 260px el texto se
   desplaza dentro de su propio cuadro y los controles quedan siempre a la
   vista, sin scroll largo.
   -webkit-overflow-scrolling: touch da el impulso de iOS sin la barra
   gigante que mete el navegador por su cuenta. */
@media (max-width: 768px) {
.ia-text {
  padding: 16px;
  max-height: 260px;
  overflow-y: auto;
  overscroll-behavior-y: contain;
  -webkit-overflow-scrolling: touch;
  /* La barra solo aparece al desplazar, y fina: en un móvil una barra
     gruesa se come el ancho del texto. */
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
.ia-text::-webkit-scrollbar { width: 5px; }
.ia-text::-webkit-scrollbar-track { background: transparent; }
.ia-text::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 3px;
}
/* El botón de "Actualizar" se queda pegado al borde inferior, para que siga
   siendo pulsable sin tener que bajar hasta el final del texto. */
.ia-text .ia-obsoleto { position: sticky; bottom: 0; }
}
.info-card { padding: 18px 20px; border-radius: var(--radius-lg); }
.racha-popover, .ctx-menu { border-radius: var(--radius-md); }

/* ---------- Inputs y pickers: spec Linear ----------
   text-input = surface + hairline, padding 8px 12px, radius md 8px. */
.modal-form input[type="text"],
.modal-form input[type="date"],
.modal-form input[type="time"],
.modal-form textarea,
.modal-form select {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  padding: 8px 12px;
  font-size: 0.9rem;
  font-family: var(--font-body);
  border-radius: var(--radius-md);
}
.modal-form input::placeholder,
.modal-form textarea::placeholder { color: var(--color-text-muted); opacity: .7; }
.pick-btn {
  padding: 9px 12px; font-size: 0.9rem; min-height: 40px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-2);
  color: var(--color-text);
}
.pick-panel {
  padding: 12px;
  background: var(--color-surface-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

/* Focus al estilo Linear: anillo de 2px de lavender a 50% de opacidad */
.modal-form input:focus,
.modal-form select:focus,
.modal-form textarea:focus,
.modal-form .pick-time-input:focus,
.modal-form .pick-native:focus-visible,
.pick-btn:focus-visible,
.modal-adv-btn:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: -1px;
  border-color: var(--color-primary-focus);
}

/* ---------- Dark: superficies sólidas + hairline + top highlight,
   sin translucidez, sin desenfoque y sin sombras de marca ---------- */
[data-theme="dark"] .panel,
[data-theme="dark"] .task-card,
[data-theme="dark"] .event-card,
[data-theme="dark"] .ia-card,
[data-theme="dark"] .info-card,
[data-theme="dark"] .settings-row,
[data-theme="dark"] .mini-item,
[data-theme="dark"] .zent-minical,
[data-theme="dark"] .pick-panel,
[data-theme="dark"] .ctx-menu,
[data-theme="dark"] .orden-menu,
[data-theme="dark"] .onboarding-box,
[data-theme="dark"] .modal-box {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
  background: var(--color-surface);
  border-color: var(--color-border);
}
[data-theme="dark"] .task-card:hover { border-color: var(--color-tasks-accent); }
[data-theme="dark"] .event-card {
  border-left: 2px solid var(--color-events-accent);
  border-left-style: solid;
}
[data-theme="dark"] .event-card:hover { border-color: var(--color-events-accent); }
[data-theme="dark"] .task-time {
  background: var(--color-tasks-accent-soft);
  border: 1px solid rgba(94, 106, 210, 0.25);
}
[data-theme="dark"] .event-card-time {
  background: var(--color-events-accent-soft);
  border: 1px solid rgba(56, 189, 248, 0.22);
}
[data-theme="dark"] .event-chip {
  background: var(--color-events-accent-soft);
}

/* Hairline superior de luz en superficies elevadas (dark) —
   el "pixel-rendered" edge de los panels Linear. */
[data-theme="dark"] .panel,
[data-theme="dark"] .task-card,
[data-theme="dark"] .event-card,
[data-theme="dark"] .ia-card,
[data-theme="dark"] .info-card,
[data-theme="dark"] .settings-row,
[data-theme="dark"] .zent-minical,
[data-theme="dark"] .modal-box,
[data-theme="dark"] .onboarding-box,
[data-theme="dark"] .ctx-menu,
[data-theme="dark"] .orden-menu,
[data-theme="dark"] .racha-popover {
  border-top-color: rgba(255, 255, 255, 0.08);
}

/* ---------- Scrims unificados ---------- */
.modal-overlay,
.onboarding-overlay,
.streak-celebration {
  background: var(--color-overlay);
}

/* ============================================================
   Modal de creación: Nivel Rápido vs Opciones Avanzadas
   Quick  -> Título + Fecha y hora + (toggle) + Save
   Avanzado -> acordeón suave (grid 0fr -> 1fr)
   ============================================================ */
.modal-quick { display: flex; flex-direction: column; gap: 8px; }

/* Botón secundario discreto ("Más opciones") — estilo texto,
   sin marco pesado; separado del nivel rápido por un hairline. */
.modal-adv-toggle {
  margin-top: 14px;
  border-top: 1px solid var(--color-border);
  padding-top: 10px;
}
.modal-adv-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 6px;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0;
  cursor: pointer;
  transition: color .15s ease, background .15s ease;
}
.modal-adv-btn:hover { color: var(--color-primary); background: var(--color-primary-soft); }
.modal-adv-btn .modal-adv-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Acordeón: grid-template-rows 0fr -> 1fr animado; contenido revelado
   con overflow oculto (recorte durante la transición). */
.modal-advanced {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 220ms var(--ease-out);
}
.modal-advanced.open { grid-template-rows: 1fr; }
.modal-adv-inner {
  overflow: hidden;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  visibility: hidden;
  transition: visibility 0s linear 220ms;
}
.modal-advanced.open .modal-adv-inner {
  visibility: visible;
  transition-delay: 0s;
  border-top: 1px dashed var(--color-border);
  margin-top: 14px;
  padding-top: 12px;
}

/* End-picker dentro del acordeón: al desplegarse el panel de hora
   liberamos el overflow para no recortar el dropdown (pickers.js). */
.modal-advanced.overflow-open,
.modal-advanced.overflow-open .modal-adv-inner { overflow: visible; }

.modal-adv-group { display: flex; flex-direction: column; gap: 6px; }
.modal-quick .field-label,
.modal-advanced .field-label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 0;
}
.modal-quick .pick-field,
.modal-advanced .pick-field { margin: 0; }
.modal-form .field-row { gap: 10px; }

/* ============================================================
   Navegación de día: barra global, calendario desplegable,
   "Volver a Hoy" y modo histórico (daynav.js)
   ============================================================ */
.day-bar {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin-bottom: 20px;
}
.day-bar .day-nav { margin-bottom: 0; gap: 12px; }

.day-nav-label {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: none;
  font-family: var(--font-display);
  font-weight: 600; min-width: 120px; text-align: center; font-size: 1.02rem;
  color: var(--color-text); cursor: pointer;
  padding: 6px 10px; border-radius: var(--radius-md);
  transition: background .15s ease, color .15s ease;
}
.day-nav-label:hover { background: var(--color-surface-2); color: var(--color-primary); }

.day-nav-back {
  display: inline-flex; align-items: center; gap: 6px;
  line-height: 1;
  font-size: 0.8rem; font-weight: 600; padding: 6px 14px; border-radius: 999px;
  cursor: pointer; border: 1px solid var(--color-border); background: var(--color-surface);
  color: var(--color-primary);
  transition: background .15s ease, border-color .15s ease, color .15s ease,
              opacity var(--dur-media) var(--ease-out),
              transform var(--dur-media) var(--ease-out);
  /* Entrada discreta: escala .9 -> 1 en 200 ms. */
  opacity: 0; transform: scale(.9);
}
.day-nav-back.zent-abierto { opacity: 1; transform: scale(1); }
.day-nav-back:hover { background: var(--color-primary-soft); border-color: var(--color-primary); }
.day-nav-back[hidden] { display: none; }

.day-picker {
  position: absolute; top: 100%; margin-top: 6px; left: 50%;
  transform: translateX(-50%) translateY(-4px);
  transform-origin: top center;
  width: 272px;
  /* En pantallas más estrechas que el picker, se encoge en vez de sacar un
     scroll horizontal del que sólo se entera quien arrastra a un lado. */
  max-width: calc(100vw - 24px);
  /* Nada del picker debe asomar: las celdas de dentro ya no desbordan y
     un fondo que se salga del borde redondeado se vería cortado feo. */
  overflow: hidden;
  padding: 12px; border-radius: var(--radius-lg);
  background: var(--color-surface); border: 1px solid var(--color-border-strong);
  box-shadow: var(--shadow-soft); z-index: 70;
  /* Despliega 4px hacia abajo desde el borde superior, 150 ms. */
  opacity: 0;
  transition: opacity var(--dur-rapida) var(--ease-out),
              transform var(--dur-rapida) var(--ease-out);
}
.day-picker.zent-abierto {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.day-picker[hidden] { display: none; }
.day-picker-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.day-picker-titulo { font-weight: 700; font-size: 0.9rem; text-transform: capitalize; }
.day-picker-arrow {
  width: 26px; height: 26px; border-radius: 999px; border: 1px solid var(--color-border);
  background: var(--color-surface-2); color: var(--color-text); cursor: pointer; font-size: 1rem;
  display: inline-flex; align-items: center; justify-content: center; line-height: 1;
}
.day-picker-arrow:hover { color: var(--color-primary); border-color: var(--color-primary); }
/* Los chevrons heredan el tamaño de la fuente del glifo, no el del botón. */
.day-picker-arrow .material-symbols-outlined { font-size: 18px; }
/* Las mallas de 7 columnas van con minmax(0, 1fr): un `1fr` a secas no
   encoge por debajo de su contenido (min-width: auto implícito) y una
   cabecera o celda larga empujaba al resto hasta desbordar el picker.
   `width: 100%` las ata al ancho del panel, que ya tiene box-sizing
   global (ver el `*` de arriba). */
.day-picker-semana {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 2px; margin-bottom: 4px; width: 100%;
}
.day-picker-wd {
  text-align: center; font-size: 0.62rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--color-text-muted); padding: 4px 0;
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
.day-picker-malla {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 2px; width: 100%;
  /* Contención de último recurso: si una celda volviera a crecer, la
     scrollbar horizontal aparecería DENTRO del picker, no en la página. */
  overflow: hidden;
}
.day-picker-cell {
  height: 32px; border: none; border-radius: var(--radius-sm); background: transparent;
  color: var(--color-text); font-size: 0.8rem; cursor: pointer; font-family: var(--font-body);
  min-width: 0;
}
.day-picker-cell:hover { background: var(--color-surface-2); }
.day-picker-cell.vacia { cursor: default; pointer-events: none; }
.day-picker-cell.hoy { font-weight: 700; color: var(--color-primary); }
.day-picker-cell.sel { background: var(--color-primary); color: #fff; font-weight: 700; }
.day-picker-cell.sel:hover { background: var(--color-primary-hover); }
.day-picker-hoy {
  width: 100%; margin-top: 10px; padding: 7px; border-radius: var(--radius-md);
  border: 1px solid var(--color-border); background: var(--color-surface-2);
  color: var(--color-primary); font-size: 0.78rem; font-weight: 700; cursor: pointer;
  transition: background .15s ease;
}
.day-picker-hoy:hover { background: var(--color-primary-soft); }

/* Badge "Atrasado": tarea vencida auto-traspasada a la vista de Hoy */
.chip-atrasado { background: var(--color-danger); color: #fff; border-color: transparent; }
.task-time.overdue { color: var(--color-danger); }

/* Adjuntos en tarjetas: enlace para ver/descargar sin abrir el detalle */
a.chip-adj { text-decoration: none; cursor: pointer; }
a.chip-adj:hover { border-color: var(--color-primary); color: var(--color-primary); }

/* Días pasados = registro histórico: atenuado y desaturado */
body.zent-historial #view-visual,
body.zent-historial #view-ia {
  filter: grayscale(0.75);
  opacity: 0.85;
  transition: filter var(--dur-lenta) ease, opacity var(--dur-lenta) ease;
}

/* Cambio de día: carrusel "slide & fade" en dos tiempos.
   El JS encadena salida -> carga de datos -> entrada, de modo que el contenido
   antigo se desliza fuera mientras sigue visible y el nuevo entra después.
   Avanzar al día siguiente: sale hacia la izquierda, entra desde la derecha.
   Retroceder: exactamente el reflejo.
   Duración 180-220ms por tramo con cubic-bezier(0.4, 0, 0.2, 1): rápido y
   sobrio, sin rebote. Solo se animan transform y opacity (propiedades del
   compositor) y se fija la altura durante el cambio para que las tarjetas no
   salten de alto. */
:root {
  --dur-dia-salida:  180ms;
  --dur-dia-entrada: 200ms;
  --ease-dia:        cubic-bezier(0.4, 0, 0.2, 1);
  --dia-desplaza:    20px;
}

@keyframes zent-dia-sale {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(var(--zent-dia-dx-salida)); }
}
@keyframes zent-dia-entra {
  from { opacity: 0; transform: translateX(var(--zent-dia-dx-entrada)); }
  to   { opacity: 1; transform: translateX(0); }
}

.zent-dia-saliendo {
  animation: zent-dia-sale var(--dur-dia-salida) var(--ease-dia) both;
  will-change: transform, opacity;
}
.zent-dia-entrando {
  animation: zent-dia-entra var(--dur-dia-entrada) var(--ease-dia) both;
  will-change: transform, opacity;
}
/* Durante el cambio no queremos un doble toque ni que nada reciba el foco. */
.zent-dia-saliendo, .zent-dia-entrando { pointer-events: none; }

.zent-dia-avanza    { --zent-dia-dx-salida: calc(-1 * var(--dia-desplaza)); --zent-dia-dx-entrada: var(--dia-desplaza); }
.zent-dia-retrocede { --zent-dia-dx-salida: var(--dia-desplaza); --zent-dia-dx-entrada: calc(-1 * var(--dia-desplaza)); }

/* Cambio de día en la vista Visual y la lista: los contenidos de #timeline-view
   y #list-tasks entran con un pequeño deslizamiento desde la derecha. Es una
   animación distinta de la del carrusel (zent-dia-saliendo/entrando), que por
   el contrario anima los PANELES enteros al saltar de día con el teclado. */
@keyframes zent-cambio-dia {
  from { opacity: 0; transform: translateX(10px); }
  to   { opacity: 1; transform: translateX(0); }
}
.zent-cambio-dia {
  animation: zent-cambio-dia 220ms var(--ease-dia) both;
  will-change: transform, opacity;
}

/* Cambio de día del timeline: el lienzo redibujado entra subiendo 4px con un
   fade. A diferencia de zent-cambio-dia (deslizamiento lateral), este fade-slide
   acompaña al REFETCH de datos: al navegar Hoy→Ayer el contenido nuevo aparece
   volviendo a subir, en vez de deslizarse desde un lado. */
@keyframes zent-fade-slide {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.zent-fade-slide {
  animation: zent-fade-slide 300ms cubic-bezier(.2, .8, .2, 1) both;
  will-change: transform, opacity;
}

/* ============================================================
   MÓVIL — adaptación mobile-first (< 768px)
   Objetivo: una sola columna a ancho completo, paneles deslizantes
   inferiores, sin-delay de tap, sin zoom de iOS al enfocar y sin
   rebote/pull-to-refresh del navegador.
   ============================================================ */

/* --- 2. Comportamientos web en móvil ---
   touch-action: manipulation quita el retardo de ~300ms del tap sin
   desactivar el scroll ni el zoom por pellizco.
   overscroll-behavior-y: contain frena el pull-to-refresh y el efecto
   de rebote al llegar al final de la lista. */
@media (max-width: 768px) {
  html, body {
    overscroll-behavior-y: contain;
    -webkit-text-size-adjust: 100%;
  }
  /* El contenedor principal también, para que el bloqueo apply en el
     scroll interno de listas largas. */
  main, .views, .panel, .task-list, .event-grid, .modal-box, .ia-text {
    overscroll-behavior-y: contain;
  }
  button, .btn, .tab-btn, .fab, [role="button"], .ctx-item,
  .task-card, .event-card, .mini-item, .settings-row, label[for] {
    touch-action: manipulation;
  }
  /* Los 16px son el umbral de iOS: por debajo, Safari hace zoom al enfocar. */
  .modal-form input,
  .modal-form select,
  .modal-form textarea,
  .day-picker input,
  .settings-row select,
  .settings-row input[type="text"],
  .ia-text input,
  .search-input {
    font-size: 16px !important;
  }
}

/* --- 1. Layout a una columna, ancho completo, padding lateral 16px --- */
@media (max-width: 768px) {
  .split { grid-template-columns: 1fr !important; gap: 14px; }
  .views { padding: 14px 16px 96px; }
  .panel { padding: 14px 16px; }
  .task-list, .event-grid { width: 100%; }
  .event-grid { grid-template-columns: 1fr !important; }
  .task-card, .event-card, .ia-card, .info-card { width: 100%; }
}

/* --- 1b. Dock flotante inferior: fijo, z-index alto y safe-area ---
   Solo aplica cuando el menú está configurado abajo
   (body[data-nav-pos="bottom"]). env(safe-area-inset-*) mantiene el dock
   por encima del indicador de inicio del iPhone. */
@media (max-width: 768px) {
  body[data-nav-pos="bottom"] .tabbar {
    position: fixed;
    top: auto;
    bottom: 16px;
    left: 50%;
    right: auto;
    width: auto;
    max-width: calc(100% - 32px);
    transform: translateX(-50%);
    z-index: 9999;
    border-radius: 9999px;
    border: 1px solid var(--color-border);
    padding: 6px 10px;
    padding-bottom: 6px;
    background: var(--color-surface);
    box-shadow: var(--shadow-soft);
  }
  /* Reservamos el alto del dock + safe-area para que nada quede tapado. */
  body[data-nav-pos="bottom"] main,
  body[data-nav-pos="bottom"] .views {
    padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  }
  body[data-nav-pos="bottom"] .tab-btn { padding: 8px 10px; }
  /* El FAB de feedback va a la esquina derecha, separado del dock centrado. */
  body[data-nav-pos="bottom"] .fab-feedback {
    right: 16px;
    bottom: calc(16px + 72px + env(safe-area-inset-bottom, 0px));
  }
}

/* --- 3. Modales y visor de adjuntos como bottom sheets ---
   92% de la altura con dvh (respeta la barra de direcciones del
   navegador) y esquinas superiores redondeadas. */
@media (max-width: 768px) {
  .modal-overlay { align-items: flex-end; padding: 0; }
  .modal-box {
    width: 100%;
    max-width: 100%;
    max-height: 92vh;
    max-height: 92dvh;
    height: auto;
    border-radius: 20px 20px 0 0;
    border-bottom: none;
    padding: 20px 16px calc(20px + env(safe-area-inset-bottom, 0px));
    /* El scale del escritorio se sustituye por un deslizamiento corto
       desde abajo, coherente con el sheet. */
    transform: translateY(16px);
  }
  .modal-overlay.zent-abierto .modal-box { transform: translateY(0); }
  .modal-close { width: 44px; height: 44px; }

  /* Modal de tarea: padding uniforme de 16px y el safe-area en el <form>, que
     es el que scrollea. El padding inferior del sheet se pone a 0 para no
     sumar las dos zonas seguras (si no, los 20px + inset + 16px + inset
     dejan un hueco muerto enorme bajo el botón).
     El inset de abajo se pide con 24px de reserva: si el dispositivo no lo
     da (o se abre en escritorio), los checkboxes y Guardar no quedan pegados
     al borde inferior. */
  #modal-overlay .modal-box { padding: 16px 16px 0; }
  #modal-overlay .modal-form {
    padding-bottom: calc(16px + env(safe-area-inset-bottom, 24px));
  }

  /* El velo del botón pegado llega hasta el padding real del sheet (16px) y
     baja lo mismo que reserva el form por abajo, para que el botón termine
     siempre en el borde de la hoja: con un inset fijo se quedaba corto en
     los teléfonos con barra de inicio. */
  #modal-overlay .modal-form > .btn[type="submit"]::before {
    left: -16px; right: -16px;
    bottom: calc(-16px - env(safe-area-inset-bottom, 24px));
  }

  /* El visor de adjuntos se construye como .modal-overlay > .modal-box.modal-box-adj,
     así que hereda todo lo anterior; solo fijamos su alto máximo. */
  .modal-box-adj { max-height: 92vh; max-height: 92dvh; }
}

/* --- 4. Áreas táctiles mínimas de 44x44 ---
   Los controles pequeños (checkbox 20px, cerrar 28px, editar 24px, "+" 34px)
   conservan su tamaño visual y amplían el área de toque con un pseudo
   elemento, para no romper la composición de las tarjetas. */
@media (max-width: 768px) {
  .task-check,
  .card-edit,
  .card-del,
  .btn-icon-round,
  .modal-close,
  .tab-btn,
  .ctx-item {
    position: relative;
  }
  .task-check::after,
  .card-edit::after,
  .card-del::after,
  .btn-icon-round::after,
  .modal-close::after,
  .ctx-item::after {
    content: "";
    position: absolute;
    /* 44px - tamaño visual; el inset se calcula por control. */
    inset: -12px;
    border-radius: 50%;
  }
  .card-edit::after,
  .card-del::after { inset: -10px; }
  .btn-icon-round::after { inset: -5px; }
  .modal-close::after { inset: -8px; }
}

/* ============================================================
   Movimiento reducido (prefers-reduced-motion)
   Se anulan loops, shimmer, ecualizador y desplazamientos;
   los cambios de estado se resuelven de inmediato.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .racha-flama-nucleo, .racha-flama-lengua,
  .zent-eq i, .zent-skeleton, .zent-skeleton::after,
  .zent-esq-fila, .zent-esq-barra::after,
  .timeline-spinner, .timeline-progreso::before {
    animation: none !important;
  }
  /* Sin giro ni barrido, el aro y la barra quedarían congelados; se dejan a
     media opacidad para que se lean como "pendiente" y no como un adorno roto. */
  .timeline-spinner, .timeline-progreso::before { opacity: 0.6; }
  /* Sin el barrido, una barra estática es indistinguible de un bloque de color
     plano y parece un elemento roto. Se le da una opacidad menor para que se
     lea como "pendiente" y no como contenido. */
  .zent-esq-caja, .zent-esq-barra { opacity: 0.55; }
  .modal-overlay, .modal-box, .day-picker, .adj-preview-overlay,
  .adj-preview-card, .day-nav-back, .toast, .tab-pill, .timeline-bloque,
  .zent-dia-saliendo, .zent-dia-entrando, .zent-card-salida, body.zent-cambiando-idioma {
    transition-duration: 1ms !important;
  }
  .zent-card-salida, .zent-panel-colapsando, .timeline-bloque.zent-bloque-salida,
  .zent-dia-saliendo, .zent-dia-entrando, .zent-cambio-dia, .zent-fade-slide,
  .zent-racha-perdida, .zent-racha-perdida .racha-flame, .modal-box {
    animation: none !important;
    transform: none !important;
  }
}

/* ============================================================
   ICONOS QUE SUSTITUYEN A EMOJIS
   ============================================================
   Los pictogramas (📎 🔗 📍 ⚙ ⬇ ▶ ⏸…) eran emoji del sistema: se veían
   distintos en cada SO, salían del color del texto y en algunos Android
   creaban su propia imagen. Ahora son Material Symbols, que se veían igual en
   todas partes y heredan el color del botón.
   Las reglas de aquí son solo los tamaños: cada botón mantiene el suyo. */
.material-symbols-outlined { font-size: 1.05rem; }
.chip-adj .material-symbols-outlined,
.event-chip .material-symbols-outlined { font-size: 0.85rem; }

/* ============================================================
   F3 — Línea de tiempo (vista Visual, opción "Timeline")
   ============================================================
   Lienzo vertical de 00:00 a 24:00. El alto de cada hora se fija en
   `timeline.js` (56 px) y aquí solo se estiliza. Los bloques usan
   `position:absolute` con `top`/`height` calculados por timeline-core.js;
   las animaciones se limitan a transform/opacity y respetan
   `prefers-reduced-motion` (regla global de más arriba). */
.timeline-view { margin-top: 4px; }
.timeline-view.hidden { display: none; }

/* Franja superior: eventos de día completo. */
.timeline-all-day {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 8px 10px; margin-bottom: 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.timeline-all-day.hidden { display: none; }
.timeline-allday-chip {
  font-size: var(--font-size-xs); font-weight: 600;
  padding: 4px 10px; border-radius: var(--radius-pill);
  border: 1px solid var(--color-events-accent);
  background: var(--color-events-accent-soft);
  color: var(--color-text); cursor: pointer;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Sección colapsable "Sin hora". */
.timeline-sin-hora {
  margin-bottom: 8px; border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); background: var(--color-surface);
  overflow: hidden;
}
.timeline-sin-hora.hidden { display: none; }
.timeline-sin-hora-cab {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 12px; border: 0; background: transparent;
  color: var(--color-text); cursor: pointer;
  font-family: var(--font-body); font-size: var(--font-size-sm); font-weight: 600;
  text-align: left;
}
.timeline-sin-hora-cab .timeline-chevron { margin-left: auto; transition: transform var(--dur-rapida) var(--ease-out); }
.timeline-sin-hora-cab.open .timeline-chevron { transform: rotate(180deg); }
.timeline-sin-hora-lista { list-style: none; margin: 0; padding: 0 8px 8px; }
.timeline-sin-hora-lista.hidden { display: none; }
.timeline-sin-hora-item {
  width: 100%; text-align: left; padding: 8px 10px; margin-top: 4px;
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-bg); color: var(--color-text); cursor: pointer;
  font-family: var(--font-body); font-size: var(--font-size-sm);
}

/* Lienzo con scroll: la altura la fija `pintarEje()`. */
.timeline-scroll {
  position: relative; max-height: 70vh; overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.timeline-grid { position: relative; min-height: 100%; }

/* Rejilla de horas. */
.timeline-hora {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 1px solid var(--color-border);
}
.timeline-hora-marca {
  position: absolute; left: 8px; top: -0.7em;
  font-variant-numeric: tabular-nums;
  font-size: var(--font-size-xs); color: var(--color-text-muted);
  background: var(--color-surface); padding: 0 4px;
}

/* Línea de la hora actual: sólo se pinta cuando el día mostrado es HOY
   (`timeline.js`). Va por encima de los bloques, con el color de acento y un
   punto en el extremo para que se lea como "ahora mismo" y no como otra
   línea de la rejilla. `top` es un porcentaje del día entero (ver pintarLineaAhora). */
.current-time-line {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 2px solid var(--color-danger, #d9534f);
  z-index: 3; pointer-events: none;
}
.current-time-line::before {
  content: ""; position: absolute; left: 2px; top: -4px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--color-danger, #d9534f);
}

/* Bloques de evento/tarea. `left`/`width` los calcula timeline.js. */
.timeline-bloque {
  position: absolute; overflow: hidden; text-align: left;
  display: flex; flex-direction: column; gap: 1px;
  margin-left: 44px; /* deja libre la columna de las horas */
  /* El padding inferior es algo mayor: con `overflow: hidden`, la última
     línea envuelta quedaba cortada por el borde a mitad de glifo (los
     bloques miden lo que duran en minutos, no lo que pide el texto). */
  padding: 3px 8px 5px;
  line-height: 1.2;
  border: 1px solid var(--color-border);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  color: var(--color-text); cursor: pointer;
  font-family: var(--font-body);
  /* Transición suave para todo lo que cambia de sitio o tamaño: mover un
     bloque, estirarlo de duración, el realce al pasar por encima. La duración
     de 0.25 s con esta curva (la de Material) es lo que hace que el gesto se
     vea "asentarse" en su hueco y no dar un salto seco. */
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Mientras se arrastra, la transición sobra: cada `pointermove` pinta una
   posición nueva y una animación de 0.25 s por frame es lo que produce el lag.
   Se apaga durante el gesto y se vuelve a encender al soltar (al quitar la
   clase), que es cuando interesa que el bloque se asiente. */
.timeline-bloque.is-dragging { transition: none !important; }
.timeline-bloque:hover { transform: translateY(-1px); }
/* Una tarea completada sigue en el lienzo (si se piden las completadas) pero
   se lee como hecha: apagada y con el título tachado. */
.timeline-bloque.tarea-completada { opacity: 0.5; }
.timeline-bloque.tarea-completada .timeline-bloque-titulo { text-decoration: line-through; }
/* Conflicto de horario: dos bloques se pisan (mismo minuto, dos citas). El
   borde y el anillo rojos los pinta timeline.js (inline, porque el color de
   borde ya lo decidió el calendario o el tipo); aquí vive el icono de aviso:
   un disco con fondo de superficie para separarse del color del bloque. */
.timeline-bloque.has-conflict { z-index: 2; }
.timeline-bloque-conflicto {
  position: absolute; top: 2px; right: 2px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  font-size: 13px; line-height: 1;
  color: var(--color-danger);
  background: var(--color-surface);
  border-radius: 999px;
  box-shadow: 0 0 0 1px var(--color-danger);
}
/* Al pasar por encima, el aviso cede su rincón a las acciones (editar/borrar)
   y el tooltip nativo del bloque ya explicó el conflicto. */
.timeline-bloque:hover .timeline-bloque-conflicto,
.timeline-bloque:focus-within .timeline-bloque-conflicto,
.timeline-bloque.arrastrando .timeline-bloque-conflicto { display: none; }
.timeline-bloque-hora { font-size: var(--font-size-xs); font-weight: 700; font-variant-numeric: tabular-nums; }
/* El título envuelve, pero con tope: máximo dos líneas con elipsis. Sin el
   tope, la tercera línea se pintaba igual y el `overflow: hidden` del bloque
   la cortaba por la mitad. `min-width: 0` deja al grid/flex encogerlo. */
.timeline-bloque-titulo {
  font-size: var(--font-size-sm); font-weight: 500; white-space: normal;
  min-width: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Bloques bajos (30 min): una sola fila, hora + título con elipsis. Es la
   clase que pone `pintarBloques` cuando el alto no da para dos líneas. */
.timeline-bloque.corto {
  flex-direction: row; align-items: center; gap: 6px;
  padding: 2px 8px;
}
.timeline-bloque.corto .timeline-bloque-hora { flex: none; }
.timeline-bloque.corto .timeline-bloque-titulo {
  flex: 1; min-width: 0;
  display: block;
  -webkit-line-clamp: unset;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Invitados del evento (icono + número), sólo en bloques altos: la lógica
   de `pintarBloques` lo omite cuando no cabe. */
.timeline-bloque-inv {
  display: inline-flex; align-items: center; gap: 2px;
  margin-top: 2px;
  font-size: var(--font-size-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}
.timeline-bloque-inv .material-symbols-outlined { font-size: 13px; }

/* Acciones rápidas (editar/eliminar) y agarrador de estirado (F3.2).
   Van SIEMPRE en el DOM y se enseñan al pasar o enfocar: un bloque
   agarrado con teclado también tiene que poder estirarse. */
.timeline-bloque { touch-action: none; }
.timeline-bloque.arrastrando {
  z-index: 30;
  opacity: 0.85;
  cursor: grabbing;
  box-shadow: var(--shadow-soft);
}
.timeline-bloque-acciones {
  position: absolute; top: 2px; right: 2px;
  display: none; gap: 2px;
}
.timeline-bloque:hover .timeline-bloque-acciones,
.timeline-bloque:focus-within .timeline-bloque-acciones { display: inline-flex; }
.timeline-bloque-accion {
  padding: 1px; border: 0; border-radius: 6px;
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: 14px; line-height: 1;
  cursor: pointer;
}
.timeline-bloque-accion:hover { background: var(--color-surface-2); color: var(--color-text); }
.timeline-bloque-accion[aria-label*="Eliminar"]:hover { color: var(--color-danger, #d9534f); }
.timeline-bloque-resize {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 10px;
  cursor: ns-resize;
  opacity: 0;
}
.timeline-bloque-resize::after {
  content: "";
  position: absolute; left: 50%; bottom: 3px;
  transform: translateX(-50%);
  width: 28px; height: 3px; border-radius: 999px;
  background: currentColor;
  opacity: 0.5;
}
.timeline-bloque:hover .timeline-bloque-resize { opacity: 1; }
.timeline-bloque.corto .timeline-bloque-resize::after { width: 18px; }
/* Línea de destino al arrastrar algo ("Sin hora" → lienzo). */
.timeline-drop {
  position: absolute; left: 44px; right: 8px;
  border: 2px dashed var(--color-primary);
  border-radius: var(--radius-sm);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-size: var(--font-size-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  display: flex; align-items: flex-end; justify-content: flex-end;
  padding: 2px 6px;
  pointer-events: none;
  z-index: 25;
}
/* Las tareas de "Sin hora" se arrastran al lienzo para agendarlas. */
.timeline-sin-hora-item { cursor: grab; }
.timeline-sin-hora-item.arrastrando { opacity: 0.6; cursor: grabbing; }

/* Móvil: el lienzo ocupa todo el ancho y respeta el dock inferior. */
@media (max-width: 768px) {
  .timeline-scroll { max-height: calc(100vh - 260px); }
  body[data-nav-pos="bottom"] .timeline-scroll {
    max-height: calc(100vh - 260px - env(safe-area-inset-bottom, 0px));
  }
  .timeline-bloque { margin-left: 38px; }
}

/* ============================================================
   F5 — Vista "Mini": widget compacto del día
   ------------------------------------------------------------
   Antes "Mini" pintaba UNA tira semanal a todo lo ancho de la vista
   (hasta 1400 px de celdas de 10 px) y escondía todo lo demás: la
   pantalla quedaba vacía y el "widget" era ilegible. Ahora es un
   panel centrado y acotado (la tira + la agenda del día, en vertical)
   que se comporta como el widget que promete el botón.
   ============================================================ */
.zent-minical {
  max-width: 480px;
  margin: 0 auto 12px;
  padding: 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}
.zent-minical.hidden { display: none; }
.zent-minical-semana {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
  width: 100%;
}
.zent-minical-wd {
  text-align: center;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  padding: 2px 0 6px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.zent-minical-dia {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--font-size-sm);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  min-width: 0;
  transition: background var(--dur-rapida) ease;
}
.zent-minical-dia:hover { background: var(--color-primary-soft); }
.zent-minical-dia.hoy {
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-weight: 700;
}
/* El día elegido se marca con el azul de marca, por delante del "hoy" (cuando
   ambos coinciden manda la selección). */
.zent-minical-dia.is-selected,
.zent-minical-dia.is-selected:hover {
  background: var(--color-primary);
  color: #fff;
  font-weight: 700;
}
.zent-minical-agenda-titulo {
  margin: 14px 0 8px;
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.zent-minical-agenda {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
.zent-minical-fila {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-text);
  text-align: left;
  font-family: var(--font-body);
  font-size: var(--font-size-sm);
}
.zent-minical-fila.hecha { opacity: 0.55; }
.zent-minical-fila.hecha .zent-minical-nombre { text-decoration: line-through; }
.zent-minical-hora {
  flex-shrink: 0;
  min-width: 76px;
  font-size: var(--font-size-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}
.zent-minical-fila.es-evento .zent-minical-hora { color: var(--color-events-accent); }
.zent-minical-tipo {
  flex-shrink: 0;
  font-size: 1rem;
  line-height: 1;
}
.zent-minical-nombre {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.zent-minical-vacio {
  margin: 0;
  padding: 10px 4px 2px;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}
/* Día saturado: solo 3 filas a la vista y el resto plegado tras "Ver X más".
   El pliegue usa `grid-template-rows` (0fr -> 1fr), que se anima con la
   transición; un display:none o un max-height aproximado aparecerían de golpe
   o cortarían filas a media altura. */
.zent-minical-resto {
  display: grid;
  grid-template-rows: 0fr;
  gap: 8px;
  overflow: hidden;
  min-height: 0;
  transition: grid-template-rows var(--dur-lenta, 0.25s) ease;
}
.zent-minical-resto-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
  min-height: 0;
  overflow: hidden;
}
.zent-minical-resto-lista .zent-minical-fila { min-height: 0; }
.zent-minical-mas {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 7px 10px;
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--font-size-xs);
  font-weight: 600;
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.zent-minical-mas:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
@media (max-width: 560px) {
  .zent-minical { max-width: none; }
}

/* ---------- Selección de calendarios (Ajustes > Cuentas) ---------- */

.settings-subgroup {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--color-border);
}
.settings-row-sub { padding: 2px 0; }
.settings-row-actions { gap: 10px; padding-top: 2px; }

.calendar-list {
  list-style: none;
  margin: 8px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 260px;
  overflow-y: auto;
}
.calendar-item + .calendar-item { border-top: 1px solid var(--color-border-soft, var(--color-border)); }
/* El label entero es la casilla. Antes de esto había que acertar en el
   cuadrado de 12px, que es un objetivo de pulsación de un tamaño ridículo
   para quien usa el dedo o tiene temblor. */
.calendar-label {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 4px;
  border-radius: var(--radius-sm, 8px);
  cursor: pointer;
  min-width: 0;
}
.calendar-label:hover { background: var(--color-bg-hover, rgba(127,127,127,.08)); }
/* `accent-color` para que la casilla siga la paleta de la app; el resto es lo
   que ya hace el navegador. Sin esto la casilla sale azul del sistema y es lo
   único de la fila que no parece de Zent. */
.calendar-check { width: 16px; height: 16px; flex: 0 0 auto; accent-color: var(--color-primary); cursor: pointer; }
.calendar-name {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* El rol va a la derecha, en pequeño y apagado: es información de contexto, no
   un dato que haya que leer para usar el panel. */
.calendar-note {
  flex: 0 0 auto; font-size: var(--font-size-xs); color: var(--color-text-muted);
  padding: 1px 7px; border: 1px solid var(--color-border); border-radius: 999px;
}
/* Un calendario de sólo-ocupación no se puede marcar, así que la fila entera se
   ve inactive: si sólo se apagase la casilla, parecería un fallo. */
.calendar-label:has(.calendar-check:disabled) { cursor: not-allowed; opacity: .65; }

/* ============================================================
   FASE E — Centro de notificaciones
   ============================================================ */

/* La campana. Mismo tamaño y forma que la píldora de racha para que las dos
   cosas que hay en la barra se lean como el mismo tipo de control, y no como
   un botón suelto pegado a un indicador. */
.notis-campana {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-surface); color: var(--color-text);
  cursor: pointer;
}
.notis-campana:hover { background: var(--color-surface-2, var(--color-bg-hover, rgba(127,127,127,.1))); }
.notis-campana[aria-expanded="true"] { border-color: var(--color-primary); color: var(--color-primary); }
.notis-campana > .material-symbols-outlined { font-size: 20px; }

/* El contador. Va arriba a la derecha, saliéndose del borde a propósito: es lo
   que hace que se vea de lejos sin tener que leer el número. */
.notis-badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px;
  background: var(--color-danger); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 17px; text-align: center;
  font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--color-bg);
  pointer-events: none;
}

.notis-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, .28);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 64px 16px 16px;
}
.notis-box {
  width: min(460px, 100%);
  max-height: min(70vh, 620px);
  display: flex; flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .22);
  overflow: hidden;
}
.notis-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--color-border);
}
.notis-titulo { margin: 0; font-size: .95rem; font-weight: 600; }
.notis-cerrar {
  border: 0; background: transparent; color: var(--color-text-muted);
  cursor: pointer; display: inline-flex; padding: 4px; border-radius: var(--radius-sm);
}
.notis-cerrar:hover { color: var(--color-text); background: var(--color-bg-hover, rgba(127,127,127,.1)); }

.notis-lista {
  list-style: none; margin: 0; padding: 0;
  overflow-y: auto; flex: 1 1 auto;
}
.notis-vacio { margin: 0; padding: 28px 16px; text-align: center; color: var(--color-text-muted); font-size: .87rem; }

.notis-item {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 14px;
  border-bottom: 1px solid var(--color-border);
}
.notis-item:last-child { border-bottom: 0; }
/* Lo leído se atenúa en lugar de desaparecer: sigue siendo un problema real,
   sólo que ya lo miraste. Si se fuera, "marcar como leída" sería indistinguible
   de "descartar". */
.notis-item.is-leida { opacity: .55; }

.notis-icono { font-size: 18px; flex: 0 0 auto; margin-top: 1px; }
.notis-conflicto .notis-icono { color: #B26A00; }
.notis-sugerencia .notis-icono { color: var(--color-primary); }
.notis-integracion .notis-icono { color: var(--color-danger); }
.notis-vencida .notis-icono { color: var(--color-text-muted); }
[data-theme="dark"] .notis-conflicto .notis-icono { color: #F0A830; }

.notis-cuerpo { flex: 1 1 auto; min-width: 0; }
.notis-linea { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.notis-hora {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: .78rem;
  color: var(--color-primary); min-width: 38px;
}
.notis-titulo {
  font-size: .87rem; font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1 1 auto;
}
.notis-sub { font-size: .78rem; color: var(--color-text-muted); flex: 1 1 100%; }

.notis-acciones { display: flex; gap: 4px; margin-top: 6px; }
.notis-accion {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--color-border); background: transparent;
  color: var(--color-text-muted); cursor: pointer;
  font-size: .72rem; line-height: 1.5;
}
.notis-accion:hover { color: var(--color-text); border-color: var(--color-primary); }
.notis-accion .material-symbols-outlined { font-size: 14px; }

.notis-pie {
  display: flex; gap: 8px; align-items: center;
  padding: 10px 14px; border-top: 1px solid var(--color-border);
  background: var(--color-bg);
}

/* Los botones son iconos con `title`/`aria-label`, no texto: a 14px en una fila
   de tres caben justo y en móvil no desbordan. El texto largo ("Marcar todas
   como leídas") se queda en el `title` y en el `aria-label` para quien no ve
   los iconos. */
@media (max-width: 560px) {
  .notis-overlay { padding: 56px 8px 8px; }
  .notis-box { max-height: 76vh; }
}

/* ============================================================
   FASE G — DENSIDAD DE INTERFAZ
   ============================================================
   `comoda` es lo que ya hay escrito en las reglas de cada componente, asi que
   no necesita ninguna regla aqui: si el atributo no esta o vale `comoda`, la
   hoja se comporta exactamente como antes de esta fase. Solo `compacta` se
   declara, y va al FINAL de la hoja a proposito.

   Dos cosas hacen que estas reglas ganen sin `!important`:

   · `[data-density="compacta"] .task-card-row` tiene especificidad (0,2,0) y
     las reglas de componente tienen (0,1,0), asi que gana aunque esten antes.
     Este bloque al final es por legibilidad, no por Cascade.
   · los `padding` de `@media (max-width: 560px)` que hay por ahi tambien son
     (0,1,0), de modo que en movil la compacta manda sobre ellos sin tener que
     declarar un bloque dentro de la media query. Los valores de aqui son MAS
     justos que los de la media query a proposito: en un movil ya se ha
     quitado relleno, y quitarlo mas es lo que hace que quepan mas filas.

   Y lo que NO hay aqui, que es lo importante: ninguna regla de esta seccion
   toca un `--color-*`. La densidad mueve cajas, la escala tipografica mueve
   letras, y ninguna de las dos cosas puede cambiar un color. Si alguna vez se
   tocara, el contraste que la Fase A midio para estos pares dejaria de estar
   medido, y eso no lo ve nadie hasta que alguien con la vista fina lo
   reporta. `test_ajustes_fe.mjs` lo vigila. */

[data-density="compacta"] .task-list { gap: 4px; }
[data-density="compacta"] .task-card-row { padding: 7px 10px; gap: 8px; }
[data-density="compacta"] .task-card.expanded .task-desc { padding: 0 10px 10px; }
[data-density="compacta"] .task-chips { padding: 0 10px 6px; gap: 4px; }

/* La rejilla de eventos baja el minimo de columna antes que el gap: con 160px
   una tarjeta estrecha ya no cabe su titulo en dos lineas y lo que se gana es
   hueco, no contenido. */
[data-density="compacta"] .event-grid {
  grid-template-columns: repeat(auto-fill, minmax(136px, 1fr));
  gap: 6px;
}
[data-density="compacta"] .event-card { padding: 8px 10px; gap: 4px; }

/* Timeline: el alto de la hora lo pone timeline.js (42px en vez de 56), que es
   lo que de verdad encoge la vista. Aqui solo el relleno de los bloques y de
   las listas laterales, que en JS no se tocan. */
[data-density="compacta"] .timeline-bloque { padding: 2px 6px; }
[data-density="compacta"] .timeline-sin-hora-item { padding: 5px 8px; margin-top: 2px; }
[data-density="compacta"] .timeline-sin-hora-lista { padding: 0 6px 6px; }
[data-density="compacta"] .timeline-all-day { padding: 4px 8px; margin-bottom: 4px; gap: 4px; }

/* ==================================================================
   VISTA STATS — estadísticas del periodo (semana / mes / año)
   Todas las cifras vienen del backend; aquí solo se pintan.
   ================================================================== */
.stats-wrap { max-width: 900px; margin: 0 auto; display: flex; flex-direction: column; gap: 18px; }
.stats-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px; }
.stats-head h2 { margin: 0; }
.stats-subtitle { margin: 4px 0 0; color: var(--color-text-muted); font-size: var(--font-size-sm); }

.stats-periodos { display: inline-flex; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-pill); padding: 3px; gap: 2px; }
.stats-periodo { border: none; background: none; cursor: pointer; padding: 6px 14px; border-radius: var(--radius-pill); color: var(--color-text-muted); font-family: var(--font-body); font-size: var(--font-size-sm); font-weight: 600; transition: background var(--dur-rapida) ease, color var(--dur-rapida) ease; }
.stats-periodo.active { background: var(--color-primary); color: #FFFFFF; }

.stats-nav { display: flex; align-items: center; justify-content: center; gap: 14px; }
.stats-rango { min-width: 170px; text-align: center; font-weight: 600; color: var(--color-text); }

.stats-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 18px; box-shadow: var(--shadow-soft); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); }
.stats-card h3 { margin: 0 0 14px; font-size: var(--font-size-md); }

.stats-metricas { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }
.stats-metrica { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 14px; display: flex; flex-direction: column; gap: 4px; box-shadow: var(--shadow-soft); }
.stats-metrica-valor { font-size: var(--font-size-xl); font-weight: 700; color: var(--color-primary); }
.stats-metrica-etiqueta { font-size: var(--font-size-xs); color: var(--color-text-muted); }

.stats-chart { width: 100%; overflow-x: auto; }
.stats-svg { width: 100%; height: 150px; display: block; }
.stats-barra { fill: var(--color-primary); opacity: .92; }
.stats-barra-etiqueta { fill: var(--color-text-muted); font-size: 9px; }
.stats-barra-valor { font-size: 9px; font-weight: 600; fill: var(--color-text); }
[data-theme="dark"] .stats-barra-valor { fill: #fff; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.9)); }
[data-theme="light"] .stats-barra-valor { fill: #1a1a1a; filter: drop-shadow(0 1px 1px rgba(255,255,255,0.8)); }

.stats-categorias { display: flex; flex-direction: column; gap: 12px; }
.stats-categoria-cabecera { display: flex; justify-content: space-between; gap: 10px; font-size: var(--font-size-sm); margin-bottom: 4px; }
.stats-categoria-nombre { font-weight: 600; }
.stats-categoria-valor { color: var(--color-text-muted); }
.stats-categoria-pista { height: 8px; background: var(--color-surface-3); border-radius: var(--radius-pill); overflow: hidden; }
.stats-categoria-barra { display: block; height: 100%; background: var(--color-primary); border-radius: var(--radius-pill); transition: width var(--dur-media) var(--ease-out); }

.stats-vacio { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; padding: 40px 20px; color: var(--color-text-muted); }
.stats-vacio-icon { font-size: 2.4rem; color: var(--color-border-strong); }
.stats-esqueleto { display: flex; flex-direction: column; gap: 10px; }

.stats-resumen-titulo { display: flex; align-items: center; gap: 8px; }
.stats-resumen-nuevo { border-color: var(--color-primary); box-shadow: 0 0 0 2px var(--color-primary-soft); }

.stats-footer { display: flex; justify-content: flex-end; padding-top: 4px; }
.stats-borrar { color: var(--color-danger); border-color: var(--color-danger); }

@media (max-width: 720px) {
  .stats-head { flex-direction: column; align-items: stretch; }
  .stats-metricas { grid-template-columns: repeat(2, 1fr); }
}

/* ==================================================================
   Compartir resúmenes (Web Share API con respaldo de portapapeles)
   ================================================================== */
.stats-resumen .ia-text h4,
.stats-resumen .ia-text h5,
.stats-resumen .ia-text h6 {
  margin: 14px 0 6px;
  font-size: var(--font-size-md);
  color: var(--color-text);
}
.stats-resumen .ia-text h4:first-child { margin-top: 0; }
.stats-resumen .ia-text .ia-lista { margin: 4px 0 10px; }
.stats-share-row { display: flex; justify-content: flex-end; margin-top: 14px; }
.audio-share { flex: none; }

/* ==================================================================
   Móvil pequeño: el FAB de feedback no debe tapar el dock inferior.
   El dock sube su z-index y el FAB se coloca por encima de él, también
   cuando el menú está arriba (en ese caso 75px deja aire sobre el borde).
   ================================================================== */
@media (max-width: 640px) {
  body[data-nav-pos="bottom"] .tabbar {
    bottom: 16px;
    left: 50%;
    right: auto;
    width: auto;
    max-width: calc(100% - 32px);
    transform: translateX(-50%);
    z-index: 9999;
    border-radius: 9999px;
    padding: 6px 10px;
    padding-bottom: 6px;
  }
  .fab-feedback {
    right: 16px;
    bottom: calc(16px + 72px + env(safe-area-inset-bottom, 0px));
    z-index: 9998;
    padding: 9px 14px;
  }
  body[data-nav-pos="bottom"] .fab-feedback {
    bottom: calc(16px + 72px + env(safe-area-inset-bottom, 0px));
  }
  body[data-nav-pos="bottom"] main,
  body[data-nav-pos="bottom"] .views {
    padding-bottom: calc(110px + env(safe-area-inset-bottom, 0px));
  }

  /* Eventos en móvil: ancho completo, sin desbordes horizontales */
  .event-grid {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    overflow-x: hidden;
    gap: 8px;
  }
  .event-card {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    gap: 8px;
    min-width: 0;
  }
  .event-card * {
    min-width: 0;
    max-width: 100%;
  }
  .event-card-title,
  .event-card-desc,
  .event-card-calendar-name {
    word-break: break-word;
    overflow-wrap: anywhere;
    hyphens: auto;
  }
  .event-card-desc {
    -webkit-line-clamp: 3;
  }
}

/* ==================================================================
   Hoja de compartir de escritorio (fallback de Web Share API)
   ================================================================== */
.zent-share-box { max-width: 460px; }
.zent-share-hint { margin: 4px 0 16px; color: var(--color-text-muted); font-size: var(--font-size-sm); }
.zent-share-redes { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.zent-share-red { flex: 1 1 auto; justify-content: center; }
.zent-share-copy { margin-top: 2px; }
.zent-share-status { min-height: 18px; margin: 10px 0 0; font-size: var(--font-size-sm); color: var(--color-text-muted); text-align: center; }

/* ==================================================================
   ZENT WRAPPED — tarjeta visual del periodo
   ================================================================== */
.wrapped-box { max-width: 540px; background: transparent; border: none; box-shadow: none; padding: 0; overflow: visible; }
.wrapped-sheet { display: flex; flex-direction: column; gap: 14px; }
.wrapped-sheet .modal-header { padding: 0 2px; }
.wrapped-sheet .modal-header h3 { margin: 0; }
.wrapped-sheet .modal-close { background: rgba(255, 255, 255, 0.92); }

.wrapped-card {
  position: relative; overflow: hidden; isolation: isolate;
  border-radius: 28px; padding: 26px 24px 24px;
  color: #fff;
  background:
    radial-gradient(circle at 12% 8%, rgba(255, 255, 255, 0.32), transparent 34%),
    radial-gradient(circle at 92% 18%, rgba(255, 196, 87, 0.4), transparent 38%),
    linear-gradient(135deg, #5e6ad2 0%, #8b5cf6 46%, #ec4899 100%);
  box-shadow: 0 22px 60px rgba(59, 36, 129, 0.38);
}
.wrapped-card::before,
.wrapped-card::after {
  content: ""; position: absolute; z-index: -1; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.22);
}
.wrapped-card::before { width: 190px; height: 190px; right: -58px; top: -64px; }
.wrapped-card::after { width: 130px; height: 130px; right: 18px; bottom: -78px; }

.wrapped-eyebrow {
  margin: 0 0 4px; font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.9;
}
.wrapped-title { margin: 0; font-size: 1.7rem; line-height: 1.1; color: #fff; }
.wrapped-range { margin: 6px 0 0; font-size: var(--font-size-sm); opacity: 0.85; }

.wrapped-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 22px; }
.wrapped-stat {
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 18px; padding: 13px 14px; min-width: 0;
  backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);
}
.wrapped-stat .material-symbols-outlined { font-size: 1.15rem; opacity: 0.9; }
.wrapped-stat-valor {
  display: block; margin-top: 4px;
  font-size: 1.75rem; font-weight: 800; line-height: 1.05;
  overflow-wrap: anywhere;
}
.wrapped-stat-valor.es-fecha { font-size: 1.08rem; line-height: 1.25; }
.wrapped-stat-label {
  display: block; margin-top: 4px; font-size: 0.72rem;
  text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.82;
}
.wrapped-stat-detalle { margin: 6px 0 0; font-size: 0.78rem; opacity: 0.86; }
.wrapped-actions { display: flex; justify-content: flex-end; }
.wrapped-actions .btn { background: var(--color-surface); }

@media (max-width: 640px) {
  .wrapped-box { padding: 0 12px; }
  .wrapped-card { border-radius: 24px; padding: 22px 18px 20px; }
  .wrapped-title { font-size: 1.45rem; }
  .wrapped-stat-valor { font-size: 1.5rem; }
}

.stats-head-acciones { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.stats-wrapped-open { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 720px) {
  .stats-head-acciones { width: 100%; justify-content: space-between; }
}
