/* app.css — sistema de diseño común. Tema oscuro SIEMPRE, alto contraste, objetivos táctiles grandes. */

:root {
  color-scheme: dark;
  --bg: #0b0d10;
  --surface: #15181d;
  --surface-2: #1d2128;
  --surface-3: #262b34;
  --border: #2d333d;
  --border-strong: #3b424e;
  --text: #f3f5f7;
  --text-2: #c2c9d3;
  --muted: #929baa;
  --accent: #b8f34a;
  --accent-ink: #0b0d10;
  --accent-soft: rgba(184, 243, 74, 0.14);
  --info: #60a5fa;
  --info-soft: rgba(96, 165, 250, 0.14);
  --warn: #fbbf24;
  --warn-soft: rgba(251, 191, 36, 0.14);
  --danger: #f87171;
  --danger-soft: rgba(248, 113, 113, 0.14);
  --ok: #4ade80;
  --ok-soft: rgba(74, 222, 128, 0.14);
  --pr: #fbbf24;

  /* Estados de día del calendario */
  --st-done: #4ade80;
  --st-partial: #facc15;
  --st-subst: #60a5fa;
  --st-skip: #f87171;
  --st-rest: #858d9b;
  --st-pending: #929baa;

  /* Colores por actividad */
  --act-strength: #b8f34a;
  --act-run: #f97316;
  --act-bike: #38bdf8;
  --act-swim: #818cf8;
  --act-hike: #2dd4bf;
  --act-other: #e879f9;

  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  --tap: 48px;
  --tap-lg: 56px;
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);
  /* Barra de pestañas: cápsula flotante de --tb-h a --tb-gap del borde inferior (dentro del área segura si la
     hay). --tabbar-h + --sab = espacio que ocupa desde abajo (lo usan el contenido, los avisos y los pies fijos). */
  --tb-h: 50px;
  --tb-gap: max(6px, calc(var(--sab) - 10px));
  --tabbar-h: calc(var(--tb-h) + var(--tb-gap) - var(--sab));
  --kb: 0px;

  /* Movimiento. Curvas de muelle: aquí la alternativa cubic-bezier; con linear() (Safari 17.2+) se usan los
     muelles de verdad (bloque @supports justo después de :root). */
  --ease-ios: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-press: cubic-bezier(0.25, 0.8, 0.3, 1);
  --spring-nav: var(--ease-ios); /* amortiguado, sin rebote: pantallas y hojas */
  --spring-soft: cubic-bezier(0.22, 1, 0.36, 1); /* casi sin rebote: título compacto */
  --spring-mid: cubic-bezier(0.34, 1.25, 0.64, 1); /* rebote corto: cápsula de pestañas */
  --spring-bounce: cubic-bezier(0.34, 1.5, 0.64, 1); /* rebote visible: hoja que vuelve al soltarla */
  --dur-sheet: 350ms;
  --dur-nav: 380ms;
  --dur-enter: 300ms;
  --dur-tab: 200ms;
  --dur-press: 120ms;

  /* Cristal («Liquid Glass»): mismo fondo oscuro, translúcido y muy desenfocado (con blur fuerte el texto de
     debajo no se puede leer: esa es la garantía de legibilidad), canto interior brillante, reflejo superior
     suave y sombra ligera. Sin backdrop-filter o con «reducir transparencia» → opaco (al final del archivo). */
  --glass-blur: blur(28px) saturate(190%);
  --glass-bar: rgba(11, 13, 16, 0.72);
  --glass-float: rgba(33, 37, 45, 0.66);
  --glass-panel: rgba(22, 25, 31, 0.76);
  --glass-edge: rgba(255, 255, 255, 0.13);
  --glass-hairline: rgba(255, 255, 255, 0.09);
  --glass-shine: inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 0 0 1px rgba(255, 255, 255, 0.025);
  --glass-sheen: linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.025) 42%, rgba(255, 255, 255, 0) 62%);
  --glass-shadow: 0 10px 30px rgba(0, 0, 0, 0.34), 0 1px 3px rgba(0, 0, 0, 0.22);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", system-ui, sans-serif;

  /* Escala tipográfica (docs/PULIDO.md). 12 px es el mínimo para texto dentro de las pantallas (la etiqueta de la
     barra de pestañas, 11 px, es la de iOS). Los tamaños sueltos con medio píxel se han llevado a esta escala. */
  /* Tamaño de texto del sistema (Ajustes › Pantalla › Tamaño del texto): app.js pone --ts en <html> (1 a 1,5).
     Todos los tamaños de letra son calc(Npx * var(--ts)), salvo la etiqueta de la barra de pestañas (fija, como iOS). */
  --ts: 1;
  --fs-xs: calc(12px * var(--ts));   /* etiquetas en mayúsculas, insignias pequeñas, sufijos de unidad */
  --fs-sm: calc(13px * var(--ts));   /* notas, subtítulos de fila, insignias */
  --fs-md: calc(15px * var(--ts));   /* texto secundario de tarjetas y filas */
  --fs-body: calc(17px * var(--ts)); /* cuerpo (iOS) */
  --fs-title: calc(20px * var(--ts));
  --fs-display: calc(28px * var(--ts));
}

/* Muelles de verdad (masa-muelle muestreado) donde hay linear(); si no, se quedan las curvas de arriba. */
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    --spring-nav: linear(0, 0.172, 0.343, 0.494, 0.619, 0.717, 0.793, 0.85, 0.892, 0.923, 0.946, 0.962, 0.973, 0.981, 0.987, 0.991, 0.994, 0.996, 0.997, 0.998, 1);
    --spring-soft: linear(0, 0.145, 0.305, 0.459, 0.593, 0.705, 0.793, 0.861, 0.91, 0.946, 0.97, 0.986, 0.995, 1.001, 1.004, 1.005, 1.005, 1.005, 1.004, 1.003, 1.003, 1.002, 1.001, 1.001, 1);
    --spring-mid: linear(0, 0.135, 0.299, 0.464, 0.614, 0.74, 0.84, 0.914, 0.967, 1.001, 1.021, 1.031, 1.034, 1.032, 1.028, 1.023, 1.017, 1.013, 1.009, 1.005, 1.003, 1.001, 1, 0.999, 0.999, 0.999, 1);
    --spring-bounce: linear(0, 0.127, 0.303, 0.491, 0.665, 0.812, 0.925, 1.005, 1.054, 1.079, 1.086, 1.081, 1.069, 1.054, 1.038, 1.024, 1.013, 1.004, 0.998, 0.995, 0.993, 0.993, 0.993, 0.995, 0.996, 0.997, 0.998, 0.999, 1);
  }
}

*,
*::before,
*::after { box-sizing: border-box; }

html {
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}
body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: calc(17px * var(--ts));
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}
button, input, select, textarea { font: inherit; color: inherit; }
button { touch-action: manipulation; cursor: pointer; }
a { color: var(--accent); text-decoration: none; touch-action: manipulation; }
h1, h2, h3, h4 { margin: 0; line-height: 1.2; }
h2 { font-size: calc(20px * var(--ts)); font-weight: 750; }
h3 { font-size: calc(17px * var(--ts)); font-weight: 700; }
p { margin: 0; }
img, svg { display: block; }
[hidden] { display: none !important; }
.num, .tnum { font-variant-numeric: tabular-nums; }
/* Solo para VoiceOver: fuera de la vista pero en el árbol de accesibilidad */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* Foco con teclado (teclado externo, Acceso total con teclado): anillo verde en botones y enlaces. Los títulos y
   hojas reciben el foco por código (para VoiceOver) y no lo muestran. */
:where(a, button, summary, [role="button"], [role="tab"], [role="switch"], [role="checkbox"], [role="radio"]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.topbar h1:focus, .sheet-panel:focus, .sheet-title:focus { outline: none; }

/* ---------- Estructura ---------- */
#app { min-height: 100vh; }
.view {
  min-height: 100vh;
  padding-left: var(--sal);
  padding-right: var(--sar);
  padding-bottom: calc(var(--tabbar-h) + var(--sab) + 24px);
  background: var(--bg);
}
/* Testigo del título compacto (ui.js): los primeros px de la página. */
.topbar-probe { position: absolute; top: 0; left: 0; width: 1px; pointer-events: none; visibility: hidden; }
.view-inner { min-height: 60vh; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: calc(52px + var(--sat));
  padding: calc(var(--sat) + 6px) 12px 8px 16px;
  background: var(--glass-bar);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  /* Arriba del todo la barra se funde con la página; al desplazar aparecen el filo, el reflejo y la sombra
     (como iOS). */
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
.topbar.is-compact {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0) 75%), var(--glass-bar);
  border-bottom-color: var(--glass-hairline);
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.03), 0 8px 24px rgba(0, 0, 0, 0.2);
}
.topbar:has(.back-btn) { padding-left: 4px; }
.topbar-titles { flex: 1; min-width: 0; overflow: hidden; }
.topbar h1 {
  width: fit-content;
  max-width: 100%;
  font-size: calc(22px * var(--ts));
  font-weight: 800;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Pantallas de detalle con un nombre largo (ui.fitTitle): 18 px y hasta dos líneas en vez de «…», como la sesión.
   Dos líneas de 18 px caben en el alto del botón «atrás»: la cabecera no cambia de alto al pasar a compacta. */
.topbar.topbar-long h1 { font-size: calc(18px * var(--ts)); line-height: 1.2; white-space: normal; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
/* Pantallas raíz (pestañas): título grande, como iOS */
.topbar-root h1 { font-size: calc(30px * var(--ts)); letter-spacing: -0.02em; }
.topbar-sub { width: fit-content; max-width: 100%; font-size: calc(13px * var(--ts)); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-actions { display: flex; gap: 2px; align-items: center; }
/* Título compacto: el título grande se encoge y se centra en la barra (ui.js calcula --tb-x/-y/-s). Solo
   transform: la cabecera no cambia de alto y nada se corta más que antes. */
.topbar h1,
.topbar-sub { transform-origin: 50% 50%; transition: transform 460ms var(--spring-soft), color 0.25s ease; }
.topbar.is-compact h1,
.topbar.is-compact .topbar-sub {
  width: var(--tb-w, fit-content);
  max-width: none;
  transform: translate(var(--tb-x, 0px), var(--tb-y, 0px)) scale(var(--tb-s, 1));
}
.topbar.tb-instant h1,
.topbar.tb-instant .topbar-sub { transition: none; }

.content {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px 24px;
}
/* Pantallas sin cabecera (errores): con status-bar black-translucent el contenido empieza bajo la hora. */
.content-safe { padding-top: calc(var(--sat) + 14px); }
.section-title {
  font-size: calc(13px * var(--ts));
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin: 10px 2px -2px;
}

/* ---------- Barra de pestañas (cápsula de cristal flotante, como iOS 26) ---------- */
.tabbar {
  position: fixed;
  left: calc(12px + var(--sal));
  right: calc(12px + var(--sar));
  bottom: var(--tb-gap);
  z-index: 30;
  display: flex;
  height: var(--tb-h);
  max-width: 560px;
  margin: 0 auto;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--glass-sheen), var(--glass-float);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-shine), var(--glass-shadow);
}
/* Cápsula «líquida» de la pestaña activa: se desliza hasta ella con un muelle (--tab-i lo pone app.js) y,
   mientras se mueve, se estira hacia donde va y se recoge (app.js alterna data-pill para repetir la animación;
   --pill-stretch y --pill-origin según la distancia y la dirección). Propiedades translate/scale separadas. */
.tabbar::before {
  content: "";
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc((100% - 8px) / var(--tab-n, 5));
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.06));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 0 0 1px rgba(255, 255, 255, 0.05), 0 2px 8px rgba(0, 0, 0, 0.18);
  translate: calc(var(--tab-i, 0) * 100%) 0;
  transform-origin: var(--pill-origin, 50% 50%);
}
.ready .tabbar::before { transition: translate 560ms var(--spring-mid); }
.tabbar[data-pill="a"]::before { animation: pill-stretch-a 520ms cubic-bezier(0.3, 0.7, 0.25, 1); }
.tabbar[data-pill="b"]::before { animation: pill-stretch-b 520ms cubic-bezier(0.3, 0.7, 0.25, 1); }
@keyframes pill-stretch-a { 0%, 100% { scale: 1 1; } 30% { scale: var(--pill-stretch, 1.3) 0.86; } 62% { scale: 0.97 1.03; } }
@keyframes pill-stretch-b { 0%, 100% { scale: 1 1; } 30% { scale: var(--pill-stretch, 1.3) 0.86; } 62% { scale: 0.97 1.03; } }
.tab {
  position: relative;
  z-index: 1;
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.01em;
  /* Son enlaces: sin menú ni vista previa de iOS al mantener pulsado. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.tab.active { color: var(--accent); }
.tab-icon { position: relative; }
.tab-dot {
  position: absolute;
  top: -2px;
  right: -4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--warn);
  border: 2px solid #1b1e24;
}
body:has(.sheet-overlay.open) .tabbar { pointer-events: none; }

/* ---------- Modo foco: barra de la sesión en curso (ui.js focusBar, js/views/session.js; PULIDO §18) ----------
   La misma cápsula, algo más alta para que «Hoy» y «Terminar» tengan 44 px con aire. --tb-h mueve también el
   hueco del contenido, los avisos y los pies fijos (--tabbar-h). */
html.focus-mode { --tb-h: 56px; }
.tabbar.tabbar-focus { padding: 0 5px; }
.tabbar.tabbar-focus::before { display: none; }
.focusbar { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; }
.fb-exit {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: 44px;
  padding: 0 12px 0 6px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font-size: calc(15px * var(--ts));
  font-weight: 650;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.fb-exit.is-pressed { background: rgba(255, 255, 255, 0.08); transform: scale(0.94); }
.fb-status { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.15; text-align: center; }
.fb-kicker { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--accent); }
.fb-count { font-size: var(--fs-md); font-weight: 700; color: var(--text); }
/* Ronda 8 (H): el centro es el botón «Siguiente pendiente» (⌄ junto a n/N). Sin pendientes queda desactivado y sin
   ⌄, pero no atenuado: sigue diciendo cuántas series llevas. */
.fb-next {
  min-height: 44px;
  padding: 2px 0; /* sin relleno lateral: «23/37 series» cabe en una línea a 375 px */
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: var(--text);
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.fb-next.is-pressed { background: rgba(255, 255, 255, 0.08); transform: scale(0.97); }
.fb-next:disabled { opacity: 1; cursor: default; }
.fb-line { display: inline-flex; align-items: center; gap: 2px; max-width: 100%; }
.fb-next-chev { flex: none; display: inline-flex; color: var(--accent); }
.fb-next-chev .icon { width: calc(14px * var(--ts)); height: calc(14px * var(--ts)); }
.fb-next-chev-lg { display: none; }
html.text-large .fb-next-chev { display: none; }
html.text-large .fb-next-chev-lg:not([hidden]) { display: inline-flex; }
.fb-finish { flex: none; min-height: 44px; padding: 0 16px; gap: 6px; border-radius: 999px; font-size: calc(15px * var(--ts)); white-space: nowrap; }

/* ---------- Tarjetas y listas ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.card-tight { padding: 10px 12px; gap: 6px; }
.card-accent { border-color: rgba(184, 243, 74, 0.45); background: linear-gradient(180deg, rgba(184, 243, 74, 0.07), transparent 70%), var(--surface); }
.card-warn { border-color: rgba(251, 191, 36, 0.45); background: var(--warn-soft); }
.card-danger { border-color: rgba(248, 113, 113, 0.5); background: var(--danger-soft); }
.card-info { border-color: rgba(96, 165, 250, 0.45); background: var(--info-soft); }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.card-title { font-size: calc(17px * var(--ts)); font-weight: 750; }
.card-sub { font-size: calc(14px * var(--ts)); color: var(--muted); }

.list {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.list-item {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 10px 14px;
  width: 100%;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  text-align: left;
  color: var(--text);
}
.list-item:last-child { border-bottom: 0; }
.list-item.is-pressed { background: var(--surface-2); }
.list-item.is-pressed > * { opacity: 0.8; }
/* Anillo hacia dentro: .list recorta (overflow: hidden) el que se dibuja por fuera */
.list-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.list-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.list-item-title { font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list-item-sub { font-size: calc(14px * var(--ts)); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Texto del sistema por encima del 100 % (app.js → html.text-large): como en iOS, lo que a tamaño normal se recorta
   con «…» ocupa más líneas en vez de cortarse (docs/PULIDO.md §17). A 100 % no cambia nada. */
html.text-large :is(.list-item-title, .list-item-sub, .topbar-sub, .cal-ses-key, .cyc-kpi-value, .cyc-kpi-sub, .cyc-eff-th,
  .prg-stat-value, .prg-link-label, .act-live-label, .lib-item-note, .imp-item-title, .today-backup .banner-title,
  .today-backup .banner-text, .an-card-head > .badge) {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: break-word;
  hyphens: auto;
}
.list-item-sub.wrap { white-space: normal; }
/* Nombres largos (rutinas, carreras): hasta dos líneas antes de recortar */
.list-item-title.lines-2 {
  white-space: normal;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.list-item-sub > .badge { margin-left: 6px; vertical-align: 1px; }
.list-item-sub > .badge:first-child { margin-left: 0; }
.list-item .chev { color: var(--muted); flex: none; }

/* ---------- Icono + etiqueta (docs/PULIDO.md, «Icono + etiqueta») ----------
   El icono nunca cede ancho: sin esto, un ítem flex se encoge (9–16 px) cuando el texto no cabe. Lo que se adapta es
   la etiqueta. Y una etiqueta junto a un icono no se centra por dentro: si parte de línea, cada línea centrada aleja el
   primer glifo del icono (30–50 px); el centrado lo hace el contenedor con justify-content. */
.icon { flex: none; }

/* ---------- Botones ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 18px;
  border-radius: 12px;
  border: 1px solid transparent;
  font-weight: 700;
  font-size: calc(16px * var(--ts));
  line-height: 1.1;
  text-align: center;
  user-select: none;
  -webkit-user-select: none;
}
.btn:has(> svg.icon) { text-align: start; } /* con icono: si parte de línea, el texto sigue junto al icono (sin icono, centrado) */
.btn:disabled { opacity: 0.45; pointer-events: none; }
.btn-block { width: 100%; }
.btn-lg { min-height: var(--tap-lg); font-size: calc(18px * var(--ts)); border-radius: 14px; }
.btn-sm { min-height: 44px; padding: 0 12px; font-size: calc(15px * var(--ts)); border-radius: 10px; } /* compacto, pero 44 px de alto: objetivo táctil mínimo */
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-secondary { background: var(--surface-3); color: var(--text); border-color: var(--border-strong); }
.btn-ghost { background: transparent; color: var(--text-2); border-color: var(--border); }
.btn-danger { background: var(--danger); color: #1a0606; }
.btn-danger-ghost { background: transparent; color: var(--danger); border-color: rgba(248, 113, 113, 0.5); }
.btn-row { display: flex; gap: 8px; }
.btn-row > .btn { flex: 1; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 6px;
  border: 0;
  background: none;
  color: var(--text);
  border-radius: 12px;
}
.icon-btn.is-pressed { background: rgba(255, 255, 255, 0.07); }
.icon-btn-text { font-weight: 700; font-size: calc(16px * var(--ts)); color: var(--accent); }
.back-btn { color: var(--accent); min-width: 44px; }

/* ---------- Chips, segmentado, badges ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chips-scroll { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; margin: 0 -16px; padding-left: 16px; padding-right: 16px; }
.chips-scroll::-webkit-scrollbar { display: none; }
.chip {
  min-height: 44px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-weight: 650;
  font-size: calc(15px * var(--ts));
  white-space: nowrap;
  flex: none;
}
.chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.chip-num { min-width: 44px; padding: 0; }
.rpe-chips { gap: 6px; }
.rpe-chips .chip { flex: 1 0 calc(20% - 6px); min-width: 0; min-height: 46px; font-size: calc(17px * var(--ts)); }
.rpe-hint { font-size: calc(14px * var(--ts)); margin-top: 6px; }

.seg {
  display: flex;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 3px;
  gap: 3px;
}
.seg-btn {
  flex: 1;
  min-height: 44px;
  border: 0;
  border-radius: 9px;
  background: none;
  color: var(--text-2);
  font-weight: 650;
  font-size: calc(15px * var(--ts));
  padding: 0 6px;
  white-space: nowrap;
}
.seg-btn.active { background: var(--surface-3); color: var(--text); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06) inset, 0 1px 3px rgba(0, 0, 0, 0.4); }
.seg-btn, .chip { transition: transform var(--dur-press) var(--ease-press), opacity var(--dur-press) ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease; }
.seg-sm .seg-btn { min-height: 34px; font-size: calc(14px * var(--ts)); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: calc(12px * var(--ts));
  font-weight: 750;
  letter-spacing: 0.01em;
  background: var(--surface-3);
  color: var(--text-2);
  white-space: nowrap;
}
.badge-accent { background: var(--accent-soft); color: var(--accent); }
.badge-ok { background: var(--ok-soft); color: var(--ok); }
.badge-warn { background: var(--warn-soft); color: var(--warn); }
.badge-danger { background: var(--danger-soft); color: var(--danger); }
.badge-info { background: var(--info-soft); color: var(--info); }
.badge-pr { background: rgba(251, 191, 36, 0.18); color: var(--pr); }

/* Estados (ui.js stateTag, docs/PULIDO.md §5): el mismo componente en toda la app; icono + texto, nunca solo color.
   Relleno suave para el estado; contorno para la confianza (es una cualidad del dato, no un juicio). */
.state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: var(--fs-xs);
  font-weight: 800;
  letter-spacing: 0.02em;
  line-height: 1.25;
  white-space: nowrap;
  background: var(--surface-3);
  color: var(--text-2);
}
.state .icon { flex: none; }
.state-sm { padding: 2px 8px 2px 6px; }
.state-ok, .state-progress { background: var(--ok-soft); color: var(--ok); }
.state-warn, .state-stalled { background: var(--warn-soft); color: var(--warn); }
.state-info { background: var(--info-soft); color: var(--info); }
.state-neutral { background: var(--surface-3); color: var(--text-2); }
.state-insufficient { background: transparent; border: 1px dashed var(--border-strong); color: var(--muted); }
.state-pr { background: rgba(251, 191, 36, 0.18); color: var(--pr); }
.state-error { background: var(--danger-soft); color: var(--danger); }
.state[class*="state-conf-"] { padding: 2px 9px; background: transparent; font-weight: 700; border-color: var(--border-strong); }
.state-conf-high { border-color: rgba(74, 222, 128, 0.5); color: var(--ok); }
.state-conf-medium { color: var(--text-2); }
.state-conf-low { border-color: rgba(251, 191, 36, 0.55); color: var(--warn); }
.state-conf-insufficient { border-style: dashed; color: var(--muted); }

/* ---------- Respuesta al toque (escala + atenuación, sin retrasar el clic) ----------
   .is-pressed la pone ui.js tras ~50 ms sin moverse (no al empezar a desplazar ni al deslizar desde el borde)
   y la quita al mover, soltar o cancelar. Al soltar vuelve con un muelle corto. */
.btn, .icon-btn, .why-btn, .stepper-btn, .action-item, .pick-row, .pick-create, .toast-action, .tab, .list-item {
  transition: transform var(--dur-press) var(--ease-press), opacity var(--dur-press) ease, background-color 0.18s ease;
}
.btn.is-pressed, .chip.is-pressed, .seg-btn.is-pressed, .why-btn.is-pressed, .stepper-btn.is-pressed, .toast-action.is-pressed, .pick-create.is-pressed {
  transform: scale(0.97);
  opacity: 0.84;
}
.icon-btn.is-pressed { transform: scale(0.92); opacity: 0.75; }
.tab.is-pressed { transform: scale(0.92); opacity: 0.7; }
.action-item.is-pressed, .pick-row.is-pressed { opacity: 0.8; }

/* Estado de día */
.status { display: inline-flex; align-items: center; gap: 6px; font-size: calc(13px * var(--ts)); font-weight: 700; }
.status::before { content: ""; width: 10px; height: 10px; border-radius: 50%; background: currentColor; }
.status-done { color: var(--st-done); }
.status-partial { color: var(--st-partial); }
.status-substituted { color: var(--st-subst); }
.status-skipped { color: var(--st-skip); }
.status-rest { color: var(--st-rest); }
.status-pending { color: var(--st-pending); }
.status-pending::before { background: transparent; border: 2px solid currentColor; }

/* ---------- Formularios ---------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: calc(14px * var(--ts)); font-weight: 650; color: var(--text-2); }
.field-hint { font-size: calc(13px * var(--ts)); color: var(--muted); }
.form-error { color: var(--danger); font-size: calc(14px * var(--ts)); font-weight: 600; }
.input {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  font-size: calc(17px * var(--ts)); /* ≥16px evita el zoom de iOS al enfocar */
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* El gris por defecto de WebKit se queda en ~2,5:1; opacity 1 porque algunos motores lo atenúan */
.input::placeholder { color: var(--muted); opacity: 1; }
textarea.input { min-height: 88px; resize: vertical; line-height: 1.4; }
select.input { background-image: none; }
.input-num { font-variant-numeric: tabular-nums; }
.input-suffix-wrap { position: relative; display: flex; align-items: center; }
.input-suffix-wrap .input { padding-right: 58px; }
.input-suffix { position: absolute; right: 12px; color: var(--muted); font-size: calc(15px * var(--ts)); pointer-events: none; }
input[type="date"].input, input[type="time"].input { min-height: var(--tap); }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.stack-sm { display: flex; flex-direction: column; gap: 6px; }
.row { display: flex; align-items: center; gap: 8px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.muted { color: var(--muted); }
.text-2 { color: var(--text-2); }
.small { font-size: calc(14px * var(--ts)); }
.tiny { font-size: calc(12px * var(--ts)); }
.bold { font-weight: 700; }
.accent { color: var(--accent); }
.ok { color: var(--ok); }
.warn { color: var(--warn); }
.danger { color: var(--danger); }
.center { text-align: center; }
.divider { height: 1px; background: var(--border); margin: 4px 0; }

.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; }
.switch { position: relative; width: 52px; height: 32px; flex: none; }
.switch input { opacity: 0; margin: 0; position: absolute; top: -6px; left: -4px; width: calc(100% + 8px); height: calc(100% + 12px); z-index: 1; } /* área táctil 44 px */
.switch span { position: absolute; inset: 0; border-radius: 999px; background: var(--surface-3); border: 1px solid var(--border-strong); transition: background 0.15s; }
.switch span::after { content: ""; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%; background: #fff; transition: transform 0.15s; }
.switch input:checked + span { background: var(--accent); border-color: var(--accent); }
.switch input:checked + span::after { transform: translateX(20px); }

/* ---------- Stepper (−/+) ---------- */
.stepper { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.stepper-label { font-size: calc(12px * var(--ts)); font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; text-align: center; }
.stepper-row { display: flex; align-items: stretch; gap: 4px; }
.stepper-btn {
  flex: none;
  width: 48px;
  min-height: 52px;
  border-radius: 12px;
  border: 1px solid var(--border-strong);
  background: var(--surface-3);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  user-select: none;
  -webkit-user-select: none;
}
.stepper-btn.is-pressed { background: var(--border-strong); }
.stepper-step { font-size: calc(14px * var(--ts)); font-weight: 750; font-variant-numeric: tabular-nums; }
.stepper-field { position: relative; flex: 1; min-width: 0; display: flex; }
.stepper-input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  border-radius: 12px;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  text-align: center;
  font-size: calc(24px * var(--ts));
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  outline: none;
  padding: 0 4px;
  -webkit-appearance: none;
  appearance: none;
}
.stepper-input:focus { border-color: var(--accent); }
.stepper-suffix { position: absolute; right: 8px; bottom: 5px; font-size: var(--fs-xs); color: var(--muted); pointer-events: none; }
.stepper-md .stepper-btn { width: 44px; min-height: 46px; }
.stepper-md .stepper-input { min-height: 46px; font-size: calc(20px * var(--ts)); }
.stepper-sm .stepper-btn { width: 38px; min-height: 40px; }
.stepper-sm .stepper-input { min-height: 40px; font-size: calc(18px * var(--ts)); }

/* ---------- Duración ---------- */
.dur { display: flex; gap: 8px; }
.dur-part { position: relative; flex: 1; display: flex; }
.dur-input {
  width: 100%;
  min-height: var(--tap);
  border-radius: 12px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  font-size: calc(20px * var(--ts));
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 0 28px 0 8px;
  outline: none;
}
.dur-input:focus { border-color: var(--accent); }
.dur-unit { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); font-size: calc(13px * var(--ts)); color: var(--muted); pointer-events: none; }

/* ---------- Hojas (bottom sheet) ---------- */
/* Abren y cierran con la curva de iOS; el fondo se oscurece con un fundido (capa ::before, solo opacidad).
   Al cerrar (.closing) ya no reciben toques y se quitan del DOM al terminar (ui.js). */
.sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.sheet-overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity var(--dur-sheet) ease;
}
/* Al arrastrar la hoja hacia abajo el fondo se aclara con ella (--sheet-drag 0…1, ui.js). */
.sheet-overlay.open::before { opacity: calc(1 - var(--sheet-drag, 0)); }
html.sheet-dragging .sheet-overlay::before { transition: none; }
.sheet-overlay.closing { pointer-events: none; }
.sheet-panel {
  position: relative;
  background: var(--glass-sheen), var(--glass-panel);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-top-left-radius: 26px;
  border-top-right-radius: 26px;
  border: 1px solid var(--glass-edge);
  border-bottom: 0;
  box-shadow: var(--glass-shine), 0 -10px 36px rgba(0, 0, 0, 0.3);
  max-height: calc(92vh - var(--kb));
  margin-bottom: var(--kb);
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  transition: transform var(--dur-sheet) var(--spring-nav);
  padding-bottom: calc(var(--sab) + 8px);
  padding-left: var(--sal);
  padding-right: var(--sar);
}
/* Prolongación bajo el borde inferior: al rebotar hacia arriba nunca se ve un hueco debajo de la hoja. */
.sheet-panel::after {
  content: "";
  position: absolute;
  left: -1px;
  right: -1px;
  top: calc(100% - 1px);
  height: 60px;
  background: var(--glass-panel);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  pointer-events: none;
}
.sheet-overlay.open .sheet-panel { transform: translateY(0); }
.sheet-tall { height: calc(88vh - var(--kb)); }
/* Asa y cabecera: se arrastran hacia abajo para cerrar (sin desplazamiento del navegador). */
.sheet-grabber { width: 38px; height: 5px; border-radius: 3px; background: rgba(255, 255, 255, 0.28); margin: 8px auto 2px; flex: none; position: relative; touch-action: none; }
.sheet-grabber::before { content: ""; position: absolute; inset: -10px -40px -6px; }
.sheet-head { display: flex; align-items: center; gap: 8px; padding: 4px 8px 6px 18px; flex: none; touch-action: none; }
.sheet-title { flex: 1; font-size: calc(19px * var(--ts)); font-weight: 750; }
.sheet-body { overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; padding: 4px 16px 12px; flex: 1; min-height: 0; }
.sheet-actions { display: flex; flex-direction: column; gap: 8px; padding: 8px 16px 4px; flex: none; }
.sheet-actions-inline { padding: 8px 0 0; }
.sheet-msg { color: var(--text-2); line-height: 1.45; }

.action-list { display: flex; flex-direction: column; gap: 2px; padding-bottom: 6px; }
.action-item {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 54px;
  padding: 0 12px;
  border: 0;
  border-radius: 12px;
  background: none;
  color: var(--text);
  font-size: calc(17px * var(--ts));
  font-weight: 600;
  text-align: left;
}
.action-item.is-pressed { background: rgba(255, 255, 255, 0.07); }
.action-item.danger { color: var(--danger); }
.action-item:disabled { opacity: 0.4; }
.action-hint { margin-left: auto; color: var(--muted); font-size: calc(14px * var(--ts)); font-weight: 500; }

/* ---------- Selectores ---------- */
.pick { display: flex; flex-direction: column; gap: 10px; }
.search-input { position: sticky; top: 0; z-index: 1; }
.pick-list { display: flex; flex-direction: column; }
.pick-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 56px;
  padding: 8px 6px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: none;
  color: var(--text);
  text-align: left;
  width: 100%;
}
.pick-row.is-pressed { background: rgba(255, 255, 255, 0.06); }
.pick-name { font-weight: 650; font-size: calc(17px * var(--ts)); }
.pick-meta { font-size: calc(13px * var(--ts)); color: var(--muted); }
.pick-section { font-size: calc(12px * var(--ts)); font-weight: 750; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); padding: 14px 6px 4px; }
.pick-empty { padding: 20px 6px; }
.pick-create {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  margin-top: 8px;
  padding: 0 10px;
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
  background: none;
  color: var(--accent);
  font-weight: 700;
}

/* ---------- Toast ---------- */
.toast {
  position: fixed;
  left: calc(12px + var(--sal));
  right: calc(12px + var(--sar));
  bottom: calc(var(--tabbar-h) + var(--sab) + 10px + var(--kb));
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 52px;
  padding: 8px 8px 8px 16px;
  border-radius: 18px;
  /* Cristal claro (mismo color y texto oscuro de siempre): translúcido y muy desenfocado, con el canto
     brillante, el reflejo superior y una sombra ligera. */
  --toast-tint: 238, 241, 244;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0.06) 55%, rgba(255, 255, 255, 0) 70%), rgba(var(--toast-tint), 0.78);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(255, 255, 255, 0.55);
  color: #0b0d10;
  font-weight: 600;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), inset 0 -1px 0 rgba(0, 0, 0, 0.06), var(--glass-shadow);
  transform: translateY(16px) scale(0.96);
  opacity: 0;
  /* Salida corta (200 ms, ui.js la espera); la entrada con un muelle corto */
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.toast.show { transform: none; opacity: 1; transition: transform 0.5s var(--spring-mid), opacity 0.2s ease; }
.toast:not(.show) { pointer-events: none; }
.toast-msg { flex: 1; font-size: calc(15px * var(--ts)); line-height: 1.3; }
.toast-action {
  flex: none;
  min-height: 40px;
  padding: 0 14px;
  border: 0;
  border-radius: 10px;
  background: #0b0d10;
  color: var(--accent);
  font-weight: 800;
}
/* Con el pie fijo de las actividades («Listo») o el aviso de versión nueva, el toast sube por encima. */
body:has(.act-footer) .toast { bottom: calc(var(--tabbar-h) + var(--sab) + 10px + var(--kb) + 76px); }
body:has(.update-bar:not([hidden])) .toast { bottom: calc(var(--tabbar-h) + var(--sab) + 10px + var(--kb) + 66px); }
/* Con una hoja abierta, el toast sube arriba para no tapar sus botones. */
body:has(.sheet-overlay.open) .toast { top: calc(var(--sat) + 10px); bottom: auto; transform: translateY(-20px); }
body:has(.sheet-overlay.open) .toast.show { transform: translateY(0); }
.toast-error { --toast-tint: 254, 202, 202; }
.toast-pr { --toast-tint: 253, 230, 138; }
.toast-success { --toast-tint: 217, 249, 157; }

/* ---------- Aviso de versión nueva (app.js) ---------- */
.update-bar {
  position: fixed;
  left: calc(12px + var(--sal));
  right: calc(12px + var(--sar));
  bottom: calc(var(--tabbar-h) + var(--sab) + 10px);
  z-index: 90;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 56px;
  padding: 6px 4px 6px 14px;
  border-radius: 16px;
  border: 1px solid rgba(184, 243, 74, 0.45);
  background: var(--glass-sheen), rgba(38, 43, 52, 0.74);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shine), var(--glass-shadow);
}
.update-bar-msg { flex: 1; min-width: 0; font-size: calc(15px * var(--ts)); font-weight: 650; line-height: 1.3; }
.update-bar-btn { flex: none; min-height: 44px; }
body:has(.update-bar:not([hidden])) .view { padding-bottom: calc(var(--tabbar-h) + var(--sab) + 24px + 66px); }

/* ---------- ¿Por qué? ---------- */
.why { display: flex; flex-direction: column; gap: 6px; }
.why-btn {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: calc(14px * var(--ts));
  font-weight: 700;
}
.why-btn.open { color: var(--accent); border-color: rgba(184, 243, 74, 0.5); }
.why-body {
  font-size: calc(14px * var(--ts));
  line-height: 1.5;
  color: var(--text-2);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
}
.why-body ul { margin: 6px 0 0; padding-left: 18px; }
.why-body li + li { margin-top: 3px; }

/* ---------- Estados vacíos y avisos ---------- */
.empty { text-align: center; padding: 28px 16px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.empty-emoji { font-size: calc(40px * var(--ts)); }
.empty-title { font-weight: 750; font-size: calc(18px * var(--ts)); }
.empty-text { color: var(--muted); max-width: 30em; }
.banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}
.banner-warn { border-color: rgba(251, 191, 36, 0.5); background: var(--warn-soft); }
.banner-info { border-color: rgba(96, 165, 250, 0.5); background: var(--info-soft); }
.banner-accent { border-color: rgba(184, 243, 74, 0.5); background: var(--accent-soft); }
.banner-main { flex: 1; min-width: 0; }
.banner-title { font-weight: 750; }
.banner-text { font-size: calc(14px * var(--ts)); color: var(--text-2); }
.err-pre { white-space: pre-wrap; font-size: calc(12px * var(--ts)); color: var(--text-2); background: var(--bg); padding: 8px; border-radius: 8px; max-height: 200px; overflow: auto; }

/* ---------- KPIs ---------- */
.kpis { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.kpis-2 { grid-template-columns: repeat(2, 1fr); }
.kpi { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px; min-width: 0; }
/* Envolver antes que cortar con «…» (pulido): la etiqueta y la cifra parten en los espacios, nunca dentro de un número */
.kpi-label { font-size: var(--fs-xs); color: var(--muted); font-weight: 650; line-height: 1.25; }
.kpi-value { font-size: calc(20px * var(--ts)); font-weight: 800; line-height: 1.2; font-variant-numeric: tabular-nums; }
.kpi-unit { font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.kpi-sub { font-size: calc(12px * var(--ts)); color: var(--muted); }

@media (min-width: 700px) {
  .content { max-width: 680px; margin: 0 auto; }
}

/* ---------- Transiciones entre pantallas (router.js) ----------
   Con View Transitions (Safari 18+, Chromium) el navegador anima una imagen de la pantalla anterior
   (::view-transition-old) y la nueva en vivo (::view-transition-new); el tipo va en <html data-nav>.
   La cabecera y la barra de pestañas tienen nombre propio: no se desplazan con la pantalla. */
::view-transition { pointer-events: none; } /* no basta: mientras se pinta, WebKit y Chromium dan los toques a <html>; una pulsación salta la transición (router.js watchPress) */
.tabbar { view-transition-name: tabbar; }
.view-inner > .topbar { view-transition-name: topbar; }
.toast.show { view-transition-name: toast; }
/* Una hoja que se está cerrando no se queda congelada en la imagen de la pantalla anterior */
html[data-nav] .sheet-overlay.closing { visibility: hidden; }

::view-transition-group(root) { animation: none; }
html[data-nav="push"]::view-transition-old(root),
html[data-nav="push"]::view-transition-new(root),
html[data-nav="pop"]::view-transition-old(root),
html[data-nav="pop"]::view-transition-new(root) {
  mix-blend-mode: normal;
  animation-duration: var(--dur-nav);
  animation-timing-function: var(--spring-nav);
  animation-fill-mode: both;
}
/* push: la nueva entra desde la derecha (con sombra); la anterior se desplaza un poco y se atenúa */
html[data-nav="push"]::view-transition-old(root) { animation-name: vt-behind-out; }
html[data-nav="push"]::view-transition-new(root) { animation-name: vt-slide-in; box-shadow: -10px 0 28px rgba(0, 0, 0, 0.45); }
/* pop: la actual sale hacia la derecha por encima; la anterior vuelve de la izquierda */
html[data-nav="pop"]::view-transition-old(root) { animation-name: vt-slide-out; z-index: 1; box-shadow: -10px 0 28px rgba(0, 0, 0, 0.45); }
html[data-nav="pop"]::view-transition-new(root) { animation-name: vt-behind-in; }
/* tab: fundido corto (el del navegador, más breve) */
html[data-nav="tab"]::view-transition-old(root),
html[data-nav="tab"]::view-transition-new(root) { animation-duration: var(--dur-tab); animation-timing-function: ease; }

/* Cabecera: se queda en su sitio y cambia el título con un fundido */
::view-transition-group(topbar) { animation-duration: var(--dur-nav); animation-timing-function: var(--spring-nav); }
::view-transition-old(topbar),
::view-transition-new(topbar) { animation-duration: calc(var(--dur-nav) * 0.6); }
html[data-nav="tab"]::view-transition-group(topbar),
html[data-nav="tab"]::view-transition-old(topbar),
html[data-nav="tab"]::view-transition-new(topbar) { animation-duration: var(--dur-tab); }
/* Barra de pestañas y aviso: en vivo, sin animación propia (la cápsula activa se desliza sola) */
::view-transition-group(tabbar),
::view-transition-new(tabbar) { animation: none; }
::view-transition-old(tabbar) { display: none; }
::view-transition-group(toast) { animation-duration: var(--dur-tab); }
/* El cristal no se captura en la imagen: se reaplica al grupo mientras dura la transición */
::view-transition-group(tabbar) { border-radius: 999px; -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
::view-transition-group(topbar) { -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }

@keyframes vt-slide-in { from { transform: translateX(100%); } }
@keyframes vt-slide-out { to { transform: translateX(100%); } }
@keyframes vt-behind-out { to { transform: translateX(-28%); opacity: 0.5; } }
@keyframes vt-behind-in { from { transform: translateX(-28%); opacity: 0.5; } }
@keyframes vt-fade-in { from { opacity: 0; } }
@keyframes vt-fade-out { to { opacity: 0; } }

/* Sin View Transitions (iOS 17): solo entra la vista nueva (la anterior ya no existe); la cabecera no se mueve */
.view-enter > :not(.topbar) { animation: vt-enter-push var(--dur-enter) var(--spring-nav) both; }
.view-enter-pop > :not(.topbar) { animation-name: vt-enter-pop; }
.view-enter-tab > :not(.topbar) { animation: vt-fade-in var(--dur-tab) ease both; }
@keyframes vt-enter-push { from { transform: translateX(44px); opacity: 0; } }
@keyframes vt-enter-pop { from { transform: translateX(-44px); opacity: 0; } }

/* ---------- Aparición escalonada del contenido al entrar (solo push; router.js pone .view-stagger) ----------
   Los 6 primeros bloques, solo opacidad y transform, ≤ 250 ms en total (190 ms + 60 ms de escalón). */
.view-stagger > .content > :nth-child(-n+6) { animation: stagger-in 190ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.view-stagger > .content > :nth-child(2) { animation-delay: 12ms; }
.view-stagger > .content > :nth-child(3) { animation-delay: 24ms; }
.view-stagger > .content > :nth-child(4) { animation-delay: 36ms; }
.view-stagger > .content > :nth-child(5) { animation-delay: 48ms; }
.view-stagger > .content > :nth-child(6) { animation-delay: 60ms; }
@keyframes stagger-in { from { opacity: 0; transform: translateY(10px); } }

/* ---------- Efecto tarjeta con una hoja abierta (ui.js) ----------
   La pantalla de detrás se encoge y redondea; el origen es el centro de lo que se ve (--lock-y = scroll al
   abrir). El transform va en #view, que no contiene position:fixed (la barra de pestañas y los avisos están
   fuera); la cabecera pegajosa sigue en su sitio dentro de la tarjeta. Al arrastrar la hoja vuelve con ella
   (--sheet-drag). Durante una transición entre pantallas no se anima (la imagen se captura a tamaño real). */
#view {
  transform-origin: 50% calc(var(--lock-y, 0px) + 50vh);
  transition: transform var(--dur-sheet) var(--spring-nav), clip-path var(--dur-sheet) var(--spring-nav);
}
html.sheet-card body,
html.sheet-card-out body { background: #000; }
html.sheet-card #view {
  transform: scale(calc(0.94 + 0.06 * var(--sheet-drag, 0)));
  clip-path: inset(var(--lock-y, 0px) 0 calc(100% - var(--lock-y, 0px) - 100vh) 0 round 24px);
}
html.sheet-card-out #view { clip-path: inset(var(--lock-y, 0px) 0 calc(100% - var(--lock-y, 0px) - 100vh) 0 round 0px); }
html.sheet-dragging #view,
html.sheet-instant #view,
html[data-nav] #view { transition: none !important; }
html.sheet-instant .sheet-overlay::before { transition: none !important; }

/* ---------- Sin backdrop-filter: superficies opacas con los mismos colores ---------- */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  /* Con el token opaco también lo es la cabecera compacta (.topbar.is-compact pinta su reflejo sobre --glass-bar) */
  :root { --glass-bar: var(--bg); }
  .topbar { background: var(--bg); }
  /* Barras pegajosas de Progreso y Actividad (progress.css, activity.css se cargan después: body sube la especificidad) */
  body .prg-period-bar, body .act-footer { background: var(--bg); }
  .tabbar { background: #171a20; }
  .sheet-panel { background: var(--surface); }
  .sheet-panel::after { background: var(--surface); }
  .update-bar { background: var(--surface-3); }
  .toast { background: linear-gradient(180deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0) 60%), rgb(var(--toast-tint)); }
}
/* «Reducir transparencia» (Ajustes › Accesibilidad): lo mismo, opaco */
@media (prefers-reduced-transparency: reduce) {
  :root { --glass-bar: var(--bg); }
  .topbar { background: var(--bg); }
  body .prg-period-bar, body .act-footer { background: var(--bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .tabbar { background: #171a20; }
  .sheet-panel { background: var(--surface); }
  .sheet-panel::after { background: var(--surface); }
  .update-bar { background: var(--surface-3); }
  .toast { background: linear-gradient(180deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0) 60%), rgb(var(--toast-tint)); }
}

/* ---------- Reducir movimiento: sin desplazamientos, como mucho fundidos cortos ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
  .btn.is-pressed, .chip.is-pressed, .seg-btn.is-pressed, .why-btn.is-pressed, .stepper-btn.is-pressed, .toast-action.is-pressed,
  .pick-create.is-pressed, .icon-btn.is-pressed, .tab.is-pressed { transform: none; }
  /* Hojas y avisos: aparecen con un fundido, sin subir; la pantalla de detrás no se encoge */
  .sheet-panel, .sheet-overlay.open .sheet-panel { transform: none; opacity: 0; transition: opacity 150ms ease !important; }
  .sheet-overlay.open .sheet-panel { opacity: 1; }
  .sheet-overlay::before { transition: opacity 150ms ease !important; }
  html.sheet-card #view, html.sheet-card-out #view { transform: none; clip-path: none; }
  .toast, .toast.show { transform: none; transition: opacity 150ms ease !important; }
  /* Cápsula de pestañas sin estirarse; contenido sin desplazarse al entrar */
  .tabbar::before { animation: none !important; }
  .view-stagger > .content > * { animation-name: vt-fade-in !important; }
  /* Pantallas: fundido cruzado corto en lugar de deslizar */
  html[data-nav]::view-transition-old(root),
  html[data-nav]::view-transition-old(topbar),
  html[data-nav]::view-transition-old(toast) { animation: vt-fade-out 150ms ease both !important; box-shadow: none; }
  html[data-nav]::view-transition-new(root),
  html[data-nav]::view-transition-new(topbar),
  html[data-nav]::view-transition-new(toast) { animation: vt-fade-in 150ms ease both !important; box-shadow: none; }
  html[data-nav]::view-transition-group(topbar),
  html[data-nav]::view-transition-group(toast) { animation: none !important; }
  .view-enter > :not(.topbar) { animation: vt-fade-in 150ms ease both !important; }
}

/* ---------- Aumentar contraste (Ajustes › Accesibilidad): bordes, filos y texto secundario más marcados ----------
   Solo tokens: mismo tema oscuro y mismo verde. Va después de «reducir transparencia» para ganar en los filos. */
@media (prefers-contrast: more) {
  :root {
    --border: #59616f;
    --border-strong: #737c8b;
    --text-2: #dde2e8;
    --muted: #b4bcc8;
    --glass-edge: rgba(255, 255, 255, 0.34);
    --glass-hairline: rgba(255, 255, 255, 0.28);
  }
}

/* ---------- Texto grande del sistema (html.text-large, docs/PULIDO.md §17) ----------
   A 125–150 % los botones, segmentos y fichas pueden ocupar dos líneas en vez de desbordarse; lo que a 100 % se
   recorta a N líneas tiene más; las cifras de los pasos (−2,5) y de las casillas crecen menos. A 100 % no aplica. */
html.text-large :is(.btn, .seg-btn, .chip, .today-quick-btn, .prg-mrow) {
  white-space: normal;
  overflow-wrap: break-word;
  hyphens: auto;
  height: auto;
  padding-top: 6px;
  padding-bottom: 6px;
  line-height: 1.15;
}
/* :where(): pesa como `.chip` (gana a su `flex: none` por orden), así que el reparto propio de una fila de fichas
   (`.rpe-chips .chip`, RIR, zonas, flujo del ciclo) sigue mandando; antes lo pisaba y las cifras se quedaban en 15–20 px. */
:where(html.text-large) .chip { flex: 0 1 auto; max-width: 100%; }
html.text-large :is(.list-item-title.lines-2, .lib-tpl-ex, .cal-row-plan-name) { -webkit-line-clamp: 4; line-clamp: 4; }
html.text-large .topbar.topbar-long h1 { -webkit-line-clamp: 3; line-clamp: 3; }
html.text-large .stepper-step { font-size: calc(14px * min(var(--ts), 1.15)); }
html.text-large .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html.text-large .kpis-2 { grid-template-columns: minmax(0, 1fr); }
html.text-large :is(.kpi-label, .kpi-value, .kpi-sub) { overflow-wrap: break-word; hyphens: auto; }
/* Etiqueta + control en una fila: con texto grande, la etiqueta va encima (como en Ajustes de iOS) */
html.text-large .cfg-num { flex-wrap: wrap; }
html.text-large .cfg-num-text { flex-basis: 100%; }
html.text-large .cfg-num .cfg-stepper { margin-left: auto; }
html.text-large .cfg-kv { flex-wrap: wrap; justify-content: flex-start; column-gap: 12px; }
html.text-large .cfg-kv-value { margin-left: auto; }
html.text-large .cfg-day .list-item-main { flex-basis: 100%; }
html.text-large .cfg-day { flex-wrap: wrap; }
html.text-large .cfg-day-name { width: auto; }
html.text-large :is(.cfg-day .list-item-title, .cfg-day .list-item-sub, .ses-view .topbar h1) { -webkit-line-clamp: 4; }
html.text-large .ses-field { grid-template-columns: minmax(0, 1fr); gap: 4px; }
html.text-large .ses-field-label { min-height: 0; }
html.text-large .ci-toggle { flex-wrap: wrap; padding-top: 6px; padding-bottom: 6px; }
html.text-large .prg-status { width: auto; white-space: normal; }
html.text-large .prg-mrow-top { flex-wrap: wrap; }
html.text-large .prg-ov-label { letter-spacing: 0.02em; overflow-wrap: anywhere; }
html.text-large .prd-race-head { flex-wrap: wrap; }
html.text-large .today-quick-btn { overflow-wrap: anywhere; }
/* Tablas de cifras densas (medias por fase, carga por deporte): las cifras crecen menos y la tabla respira */
html.text-large :is(.cyc-eff-val, .cyc-eff-th, .an-load-chg) { font-size: calc(14px * min(var(--ts), 1.12)); letter-spacing: -0.02em; }
html.text-large .cyc-eff-row { padding: 0 4px; gap: 1px; }
html.text-large .an-load-row { grid-template-columns: minmax(0, 1fr) auto auto; }
html.text-large .cyc-kpi-label { overflow-wrap: anywhere; }
html.text-large .act-live-value { font-size: calc(26px * min(var(--ts), 1.2)); }
html.text-large .ci-toggle .ci-title { white-space: normal; min-width: 0; flex: 1 1 auto; overflow-wrap: break-word; }
html.text-large .ci-toggle > * { min-width: 0; }
/* Un control segmentado que no cabe a lo ancho pasa a dos filas (WebKit no parte «Moderado» ni «Drop») */
html.text-large .seg { flex-wrap: wrap; }
html.text-large .seg-btn { flex: 1 1 auto; min-width: min-content; }
html.text-large .btn { padding-left: 12px; padding-right: 12px; }
/* Selectores de deporte en rejilla (.act-kinds, .act-seg-wrap): con texto grande, dos por fila. Las reglas de
   activity.css reparten 3 + 2 con selectores :nth-child muy específicos; aquí se anulan a propósito. */
html.text-large :is(.act-kinds, .act-seg-wrap) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html.text-large :is(.act-kinds, .act-seg-wrap) > .seg-btn { grid-column: auto !important; min-width: 0; }
html.text-large .cyc-actions { grid-template-columns: minmax(0, 1fr); }
/* Barra de la sesión (modo foco) con texto grande: la cápsula crece en alto (el hueco de abajo con ella) y las
   iconos y palabras ceden sitio a «En sesión · n/N» sin reducir la letra: «Hoy» se queda en la flecha (como
   el «atrás» de iOS; VoiceOver sigue diciendo «Ir a Hoy») y «Terminar» pierde el icono antes que el texto. */
html.text-large.focus-mode { --tb-h: 64px; }
html.text-large .fb-finish { white-space: nowrap; padding-left: 14px; padding-right: 14px; }
html.text-large .fb-finish svg { display: none; }
html.text-large .fb-exit { min-width: 44px; justify-content: center; padding: 0 4px; }
html.text-large .fb-exit-label { display: none; }
html.text-large .fb-status { overflow-wrap: break-word; }
html.text-large .fb-count-unit { display: none; }
/* ---------- Texto grande: reflujo en vez de palabras partidas y cifras encima de su unidad (ronda 8, A2) ----------
   La guarda visual (tests/e2e/visual-guard.test.cjs) falla si una palabra corta se parte a media palabra
   («Senderism|o»), si un valor pisa su unidad («00» sobre «min») o si un texto pisa el trazo de un anillo. Aquí se
   resuelve sin bajar la letra: columnas → filas, unidades debajo de la cifra y nombres en su propia línea. */
/* Unidad superpuesta (−/+ y duración h·min·s): con texto grande no cabe al lado de la cifra; va debajo, centrada,
   y el campo reserva su hueco (crece en alto, no encoge la cifra). */
html.text-large .stepper-field:has(.stepper-suffix) .stepper-input { min-height: 0; padding: 2px 4px calc(var(--fs-xs) * 1.2 + 6px); }
html.text-large .stepper-suffix { left: 0; right: 0; bottom: 5px; text-align: center; line-height: 1.2; }
html.text-large .dur-input { padding: 4px 4px calc(13px * var(--ts) * 1.2 + 8px); }
html.text-large .dur-unit { top: auto; bottom: 6px; left: 0; right: 0; transform: none; text-align: center; line-height: 1.2; }
/* «Más datos» de la actividad (desnivel, mochila, FC…): un campo por fila; a media fila no cabían la etiqueta
   («Desnivel positivo»), el ejemplo («p. ej. 850») y la unidad, que además crece con la letra */
html.text-large .act-grid { grid-template-columns: minmax(0, 1fr); }
html.text-large .act-grid .input-suffix-wrap .input { padding-right: calc(14px * var(--ts) * 2.4 + 12px); }
/* Selector de deporte (formulario de actividad, objetivo, filtro de km): una opción por línea cuando la palabra
   más larga («Senderismo») no cabe en media fila. Flex con base automática: cada botón mide al menos su palabra
   más larga y la fila se reparte el resto. */
html.text-large :is(.act-kinds, .act-seg-wrap) { display: flex; flex-wrap: wrap; }
html.text-large :is(.act-kinds, .act-seg-wrap) > .seg-btn { flex: 1 1 auto; min-width: min-content; overflow-wrap: normal; hyphens: manual; }
/* Accesos rápidos de Hoy: dos por fila («Senderismo» y «Natación» no caben en un tercio) */
html.text-large .today-quick, html.text-large .today-quick.act-quick-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html.text-large .today-quick-btn { overflow-wrap: break-word; }
/* Peso rápido de Hoy: la cifra necesita todo el ancho; «Guardar», debajo */
html.text-large .bwq-row { flex-wrap: wrap; }
html.text-large .bwq-stepper { flex-basis: 100%; }
html.text-large .bwq-save { flex: 1 1 100%; }
/* Anillo pequeño de la tarjeta del ciclo (Hoy): crece con el número para que no pise el trazo */
html.text-large .cyc-today-ring, html.text-large .cyc-today-ring .cyc-ring-svg { width: 76px; height: 76px; }
/* Tablas por músculo (panel semanal, Progreso): el nombre en su línea; debajo, las series y el estado (como a 320 px) */
html.text-large :is(.wk-mrow-top, .prg-mrow-top) { flex-wrap: wrap; row-gap: 2px; }
html.text-large :is(.wk-mrow-name, .prg-mrow-name) { flex: 1 0 100%; overflow-wrap: break-word; }
html.text-large :is(.wk-mrow-val, .prg-mrow-val) { margin-right: auto; }
/* «Cómo vas» (Progreso): la cifra y el cambio a todo lo ancho; la minigráfica y el estado, debajo */
html.text-large .prg-ov-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "main chev" "side chev"; row-gap: 6px; }
html.text-large .prg-ov-main { grid-area: main; }
html.text-large .prg-ov-side { grid-area: side; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: 6px 12px; }
html.text-large .prg-ov-row .chev { grid-area: chev; align-self: center; }
html.text-large :is(.prg-ov-label, .prg-ov-value) { overflow-wrap: break-word; }
/* Accesos de Progreso: los anchos, una fila cada uno; los pequeños, dos por fila (el último, a lo ancho) */
html.text-large .prg-link-wide { grid-column: 1 / -1; }
html.text-large .prg-link:not(.prg-link-wide, .prg-link-full) { grid-column: span 3; }
html.text-large .prg-link:not(.prg-link-wide, .prg-link-full):last-child:nth-child(even) { grid-column: 1 / -1; }
html.text-large .prg-link-label { overflow-wrap: break-word; }
/* Cifras breves sobre las gráficas: una columna menos estrecha → la etiqueta parte entre palabras */
html.text-large .prg-stat-label { overflow-wrap: break-word; }
html.text-large .prg-stats { column-gap: 10px; }
/* Carga por deporte (análisis): nombre y % arriba; los minutos y la carga, debajo */
html.text-large .an-load-row { grid-template-columns: minmax(0, 1fr) auto; row-gap: 0; }
html.text-large .an-load-name { grid-column: 1; grid-row: 1; overflow-wrap: break-word; }
html.text-large .an-load-chg { grid-column: 2; grid-row: 1; }
html.text-large .an-load-val { grid-column: 1 / -1; grid-row: 2; white-space: normal; }
/* Resumen del periodo: un deporte por fila; «Más progresan» con el cambio debajo del nombre */
html.text-large .sum-sport-grid { grid-template-columns: minmax(0, 1fr); }
html.text-large :is(.sum-sport-main, .sum-sport-name, .sum-prog-name, .sum-rec-label) { overflow-wrap: break-word; }
html.text-large .sum-prog-btn { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; row-gap: 6px; }
html.text-large .sum-prog-btn .sum-prog-main { grid-column: 1; grid-row: 1; }
html.text-large .sum-prog-btn .sum-delta { grid-column: 1; grid-row: 2; justify-self: start; max-width: 100%; }
html.text-large .sum-prog-btn .chev { grid-column: 2; grid-row: 1 / span 2; }
/* Ciclo: las tres cifras de «Tus ciclos», dos por fila; la tabla por fase con columnas a la medida de su título */
html.text-large .cyc-hist-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html.text-large .cyc-hist-kpis > :last-child:nth-child(odd) { grid-column: 1 / -1; }
html.text-large .cyc-kpi-label { overflow-wrap: break-word; }
html.text-large .cyc-eff-row { grid-template-columns: var(--eff-fit, var(--eff-even, repeat(5, minmax(0, 1fr)))); }
/* (dos clases: la regla general de arriba, con :is(.today-backup .banner-title…), pesa más que una sola) */
html.text-large .cyc-eff-row .cyc-eff-th { white-space: normal; overflow-wrap: normal; hyphens: manual; }
/* Filas de lista con una cifra o un estado a la derecha (análisis, ejercicios de Progreso, ejercicios de una
   rutina): el texto de la fila no encoge por debajo de su palabra más larga; si con la cifra no cabe, la cifra
   (y la flecha) bajan a otra línea en vez de partir «Flexion|es» o «Elevacione|s». */
html.text-large :is(.list-item, .lib-item-head) { flex-wrap: wrap; row-gap: 6px; }
/* Base = su palabra más larga (decide si la cifra baja de línea) pero nunca más que la fila: con min-width:
   min-content, una palabra más ancha que la fila («Euskalherriamaratoia») sacaba el texto por la derecha. */
html.text-large :is(.list-item-main, .lib-item-main) { min-width: 0; flex-basis: min-content; max-width: 100%; }
html.text-large .lib-item-name { overflow-wrap: break-word; }
html.text-large .lib-item-target { max-width: none; }
/* La flecha no baja sola a otra línea: queda fija a la derecha, centrada en la fila, con su hueco reservado */
html.text-large .list-item:has(> .chev:last-child), html.text-large .lib-item-head { position: relative; padding-right: 40px; }
html.text-large .list-item > .chev:last-child, html.text-large .lib-item-head > .lib-item-chev { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); }
/* Anillo del ciclo: el hueco no da para «Día del ciclo», la cifra, la fase en dos líneas y «estimada» a 150 %
   (pisaban el trazo). Con texto grande el anillo crece hasta 290 px, dentro quedan el rótulo y el día, y la fase
   y «estimada» pasan debajo. Una rejilla superpone el dibujo y el centro: las filas 1–4 son el cuadrado del
   anillo (rótulo y día centrados entre dos filas flexibles) y las 5–6, el pie. */
html.text-large .cyc-ring { display: grid; grid-template-rows: 1fr auto auto 1fr auto auto; justify-items: center; width: min(100%, 290px); height: auto; }
html.text-large .cyc-ring-svg { grid-row: 1 / 5; grid-column: 1; width: 100%; height: auto; aspect-ratio: 1; }
html.text-large .cyc-ring-center { display: contents; }
html.text-large .cyc-ring-center > * { grid-column: 1; max-width: 62%; text-align: center; }
html.text-large .cyc-ring-kicker { grid-row: 2; }
html.text-large .cyc-ring-big { grid-row: 3; }
html.text-large .cyc-ring-phase { grid-row: 5; max-width: 100%; margin-top: 10px; }
html.text-large .cyc-ring-est { grid-row: 6; max-width: 100%; }
