/* ============================================================================
   Guidettips (antes "Biwenger Tips") — hoja de estilos completa, reescrita
   sobre el Guidettips Design System.

   Sustituye por completo a la anterior static/style.css. No se ha renombrado
   ninguna clase ni ningún id: todos los ganchos que usan las plantillas y
   static/js/*.js (ledger-table, .baseline-input, .chart-series.hidden,
   .chart-legend-item.inactive, .chart-focused, .bottom-nav-keyboard-hidden,
   .theme-toggle, aria-sort…) siguen exactamente igual.

   Fundamentos: verde césped como base, oro para puntos/avisos, celeste para
   info. Display en Archivo Black MAYÚSCULAS con skewX(-6deg), cuerpo en
   Outfit, TODA cifra en JetBrains Mono para que las columnas cuadren.
   Tema claro por defecto en :root, oscuro en :root[data-theme="dark"].
   ========================================================================= */

/* ── Tokens ───────────────────────────────────────────────────────────── */
:root {
  --green-950:#0d1710; --green-900:#0f2916; --green-800:#14532d;
  --green-700:#15803d; --green-600:#1f8f43; --green-500:#16a34a;
  --green-400:#22c55e; --green-300:#4ade80; --green-100:#d7f3dd;
  --gold-500:#f7b500; --gold-400:#ffc633; --gold-200:#ffe8a8; --gold-600:#d99b00;
  --celeste-500:#2f80ed; --celeste-300:#93bff7;
  --ink-900:#14251a; --ink-700:#26402c; --ink-500:#5b6b60; --ink-400:#7d8f84;
  --ink-300:#9fbaa6; --ink-200:#dce7de; --ink-100:#eef4ee; --white:#fff;

  --pos-por:#f7b500; --pos-def:#2f80ed; --pos-mig:#16a34a; --pos-del:#eb5757;
  --status-win:#15803d; --status-draw:#f7b500; --status-loss:#c0392b;

  --surface-app:#eef4ee; --surface-canvas:#eef4ee; --surface-card:#fff;
  --surface-inset:#eef4ee; --surface-overlay:rgba(20,37,26,.55);
  --surface-brand:#15803d; --surface-brand-soft:rgba(22,163,74,.07);
  --surface-warm-soft:rgba(247,181,0,.12); --surface-cool-soft:rgba(47,128,237,.10);
  --surface-bar:rgba(238,244,238,.88);

  --text-body:#14251a; --text-strong:#14532d; --text-muted:#5b6b60;
  --text-faint:#7d8f84; --text-on-brand:#fff; --text-brand:#15803d;
  --text-warm:#d99b00; --text-cool:#2f80ed;
  /* T118: los dos secundarios, en tonos que SÍ pasan contraste como texto.
     --gold-500 sobre fondo claro da ~1,9:1 y --gold-600 ~2,5:1: valen como
     fondo, borde o filete, no como letra. Estos dos son las versiones
     legibles, y son los únicos que se usan para texto de acento. */
  --text-accent-warm:#8a5e00; --text-accent-cool:#1b62c4;
  /* T120: las barras (arriba y, en móvil, abajo) y la cabecera de tabla
     llevan un TINTE naranja OPACO, nunca rgba. Las tres son
     `position: sticky`/`fixed`, o sea que el contenido les pasa por debajo
     y con alfa se transparentaría a través de ellas. Cada hex es la mezcla
     ya resuelta: la barra al 30% sobre --surface-app, la cabecera de tabla
     al 16% sobre --surface-card. Por eso hay dos valores por tema y no una
     sola función de color.
     El tinte deja el texto en sus colores de siempre, que es la diferencia
     con un naranja pleno: ahí habría que repintarlo todo en marrón. El
     naranja de verdad lo pone el filete de --gold-500 del borde. */
  /* T120 - LOS DOS TEMAS DIVERGEN A PROPÓSITO, y por eso hay tantas
     variables aquí en vez de reglas duplicadas. Decisión del usuario tras
     ver los dos en vivo:
       claro  -> el naranja va en los FONDOS (barras y cabecera de tabla,
                 en tinte), y ninguna letra es naranja.
       oscuro -> justo al revés: fondos como siempre y el naranja en la
                 LETRA de titulares y cabeceras de tabla.
     Cada regla de abajo se escribe una vez y lee la variable; el tema
     decide. Los tintes van OPACOS y no en rgba porque las barras y la
     cabecera de tabla son fijas y el contenido les pasa por debajo. */
  --surface-header:#f1e1a7;
  --border-header:2px solid var(--gold-500);
  --surface-thead:#fdf3d6;
  --border-thead:2px solid var(--gold-500);
  --text-thead:var(--text-muted);
  --text-heading:#14532d;
  --text-eyebrow:var(--text-brand);
  --nav-active-bar:var(--surface-brand);
  --text-bar-active:var(--text-strong);
  /* Sobre el tinte de las barras, --text-muted/--text-faint se quedan en
     4,3:1 y 3,9:1, por debajo de AA. Este es el mismo verde apagado un
     par de pasos más oscuro, que sube a 5,8:1 sin cambiar el carácter. */
  --text-on-bar-muted:#46564b;
  /* El contorno del logo es casi negro (luminancia 24/255), así que sobre
     la barra clara se lee solo y no necesita ayuda. Ver el valor de oscuro. */
  --brand-logo-halo:none;
  /* Césped de las franjas laterales (T131). A plena opacidad: sobre un
     fondo casi blanco, cualquier transparencia lava el verde hacia el
     blanco y el resultado es "césped con filtro", que es justo lo que el
     usuario rechazó dos veces. Lo que separa la franja del contenido es el
     degradado del borde, no rebajar la foto. */
  --pitch-opacity:1;
  --pitch-filter:saturate(1.12);
  --text-link:#15803d; --text-link-hover:#14532d;

  --border-subtle:rgba(20,83,45,.08); --border-default:#dce7de;
  --border-strong:#c3d6c7; --border-focus:#f7b500;

  --grad-hot:linear-gradient(100deg,#ffc633 0%,#f7b500 55%,#d99b00 100%);
  --grad-form:linear-gradient(100deg,#4ade80 0%,#16a34a 50%,#15803d 100%);
  --grad-pitch:linear-gradient(120deg,#14532d,#16a34a);
  --grad-glow:radial-gradient(1200px 420px at 50% -140px,rgba(22,163,74,.14),transparent 62%);

  --font-display:"Archivo Black","Space Grotesk",system-ui,sans-serif;
  --font-body:"Outfit","Space Grotesk",system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SFMono-Regular",monospace;
  --display-skew:-6deg;

  --radius-card:16px; --radius-input:12px; --radius-pill:999px;
  --shadow-card:0 8px 20px rgba(2,9,5,.10);
  --shadow-raised:0 14px 32px rgba(2,9,5,.14);
  --glow-brand:0 0 0 1px rgba(22,163,74,.35),0 10px 28px rgba(22,163,74,.22);

  --ease-pop:cubic-bezier(.34,1.56,.64,1);
  --content-max:1180px;
  --gutter:16px;
}

:root[data-theme="dark"] {
  --surface-app:#0d1710; --surface-canvas:#0d1710; --surface-card:#16241a;
  --surface-inset:#1e3324; --surface-overlay:rgba(13,23,16,.72);
  --surface-brand:#1f8f43; --surface-brand-soft:rgba(74,222,128,.07);
  --surface-warm-soft:rgba(247,181,0,.10); --surface-cool-soft:rgba(47,128,237,.14);
  --surface-bar:rgba(13,23,16,.86);

  --text-body:#e8f5e9; --text-strong:#d7f3dd; --text-muted:#9fbaa6;
  --text-faint:#9fbaa6; --text-brand:#4ade80; --text-on-brand:#0d1710;
  --text-warm:#f7b500; --text-link:#4ade80; --text-link-hover:#7ff0a5;
  /* Sobre fondo oscuro el problema se invierte: el oro apagado del tema
     claro se hunde y los tonos vivos son los legibles (T118). */
  --text-accent-warm:#ffc633; --text-accent-cool:#93bff7;
  /* Recalculados sobre las superficies oscuras. En oscuro el tinte da un
     oliva profundo en vez de una franja encendida cruzando la pantalla,
     que es justo lo que se buscaba al bajar la saturación. */
  /* Oscuro se queda EXACTAMENTE como estaba: barras traslúcidas de
     siempre, cabecera de tabla sin tinte, y el naranja en la letra. El
     usuario lo dio por bueno viéndolo en vivo, así que aquí no hay diseño
     nuevo, solo los valores de antes expresados con las variables que el
     tema claro necesitaba. */
  --surface-header:var(--surface-bar);
  /* Filete naranja también en oscuro: el hairline de --border-subtle no
     separaba la barra del contenido, y es el mismo acento que ya marca
     el borde en claro. Al ser el mismo token, la barra inferior de móvil
     lo hereda, que es lo coherente - las dos son la misma pieza. */
  --border-header:2px solid var(--gold-500);
  --surface-thead:var(--surface-card);
  --border-thead:1px solid var(--border-strong);
  --text-thead:var(--text-accent-warm);
  --text-heading:#ffc633;
  --text-eyebrow:var(--text-accent-warm);
  --nav-active-bar:var(--grad-hot);
  --text-bar-active:var(--text-accent-warm);
  --text-on-bar-muted:var(--text-muted);
  /* Sobre la barra oscura ese mismo contorno negro se funde con el fondo y
     las letras blancas quedan flotando sin silueta. Dos drop-shadow claros
     se la devuelven: siguen el canal alfa, o sea la forma real del logo, y
     no una caja - que es lo que haría un `background` con degradado. Uno
     ceñido para el filo y otro amplio para que la transición al fondo no
     tenga corte. */
  --brand-logo-halo:drop-shadow(0 0 1px rgba(215,243,221,.9)) drop-shadow(0 0 3px rgba(215,243,221,.75)) drop-shadow(0 0 12px rgba(215,243,221,.35));
  /* En oscuro la foto es MÁS clara que la página, así que hay que
     oscurecerla igualmente - bajar solo la opacidad la dejaría gris lavada
     en vez de césped de noche. Pero menos que antes: .4 de brillo la
     apagaba del todo. */
  --pitch-opacity:.8;
  --pitch-filter:brightness(.62);

  --border-default:#26402c; --border-strong:#3a5c42;
  --border-subtle:rgba(232,245,233,.08);

  --status-win:#4ade80; --status-loss:#ff8a80;
  --grad-pitch:linear-gradient(120deg,#0f2916,#1f8f43);
  --grad-glow:radial-gradient(1200px 420px at 50% -140px,rgba(74,222,128,.10),transparent 62%);
  --shadow-card:0 8px 20px rgba(2,9,5,.5);
  --shadow-raised:0 16px 36px rgba(2,9,5,.6);
}

/* ── Reset y base ─────────────────────────────────────────────────────── */
*,*::before,*::after { box-sizing: border-box; }

/* Tipografía fluida global. En esta hoja `rem` se usa SOLO para font-size
   (todo el espaciado, radios y anchos van en px), así que mover la raíz
   escala la LETRA y nada más: no se descoloca ningún layout.

   16px a partir de 760px - el único breakpoint del archivo, así que de
   761px para arriba se ve exactamente igual que antes - bajando hasta
   14px en 320px. Los topes van en rem, no en px, porque en el elemento
   raíz `rem` se resuelve contra el tamaño por defecto del NAVEGADOR (no
   circularmente): así se respeta la preferencia de tamaño de letra del
   usuario y el zoom al 200% sigue funcionando (WCAG 1.4.4). Por eso el
   suelo es .875rem y no menos. */
html {
  -webkit-text-size-adjust: 100%;
  font-size: clamp(.875rem, calc(.875rem + .125rem * ((100vw - 320px) / 440px)), 1rem);
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-body);
  /* 1rem, no 16px: en px el texto corrido se quedaba fuera del escalado
     fluido de la raíz. */
  font-size: 1rem;
  line-height: 1.45;
  color: var(--text-body);
  background: var(--surface-app);
  background-image: var(--grad-glow);
  background-repeat: no-repeat;
  text-wrap: pretty;
  -webkit-font-smoothing: antialiased;
}

/* T159: static/js/theme.js pone esta clase ~250ms al pulsar el conmutador
   claro/oscuro, para que el cambio de tema no sea un corte instantáneo en
   TODA la página. No es `transition: all`: eso animaría también
   transform/box-shadow/width de cualquier cosa con un cambio de estado
   simultáneo (un hover a mitad del cambio de tema, por ejemplo) con una
   duración que no le toca - se listan sólo las propiedades que de verdad
   cambian entre temas. `fill` cubre los SVG inline de _icons.html; los
   escudos van por <img>, no por fill. */
html.theme-fading,
html.theme-fading * {
  transition: background-color 200ms ease, color 200ms ease, border-color 200ms ease, fill 200ms ease !important;
}
@media (prefers-reduced-motion: reduce) {
  html.theme-fading,
  html.theme-fading * { transition: none !important; }
}

a { color: var(--text-link); text-decoration: none; }
a:hover { color: var(--text-link-hover); text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: 4px;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .01em;
  line-height: 1.05;
  color: var(--text-heading);
  transform: skewX(var(--display-skew));
  transform-origin: left bottom;
  margin: 0 0 12px;
}
h1 { font-size: clamp(1.75rem, 5vw, 2.6rem); }
h2 { font-size: clamp(1.25rem, 3vw, 1.6rem); }
h3 { font-size: 1.1rem; }

p { margin: 0 0 12px; }

code {
  font-family: var(--font-mono);
  font-size: .9em;
  background: var(--surface-inset);
  border-radius: 6px;
  padding: 1px 5px;
}

/* ── Cabecera ─────────────────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--surface-header);
  /* El desenfoque solo actúa en oscuro, donde la barra sigue siendo
     traslúcida; en claro el tinte es opaco y no hace nada. */
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: var(--border-header);
}

.header-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 10px var(--gutter);
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-right: auto;
  min-height: 44px;
  color: var(--text-strong);
}
.brand:hover { text-decoration: none; }

/* El logo apaisado sustituye a la insignia + el nombre en texto (T121). Se
   sirve al doble de resolución (407x128 para pintarse a 52px de alto) y con
   fondo transparente, así que funciona igual sobre la barra clara con tinte
   y sobre la oscura. */
.brand-logo {
  height: 52px;
  width: auto;
  display: block;
  filter: var(--brand-logo-halo);
}

.top-nav {
  display: flex;
  align-items: center;
  gap: 4px;
}
.top-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 14px;
  border-radius: var(--radius-pill);
  font-size: .82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-on-bar-muted);
  /* T158: filter/box-shadow en la lista - .nav-cta cambia los dos al hacer
     hover y hasta ahora saltaba en vez de animarse. */
  transition: background 160ms var(--ease-pop), color 160ms ease, transform 160ms var(--ease-pop), filter 160ms ease, box-shadow 160ms ease;
}
.top-nav a:hover {
  color: var(--text-strong);
  background: var(--surface-brand-soft);
  text-decoration: none;
  transform: translateY(-1px);
}
/* Sobre el tinte naranja, la barra oro que marcaba la sección activa
   (T118) se perdía contra su propio fondo: pasa a verde oscuro, que aquí
   es lo que contrasta. */
.top-nav a.active {
  position: relative;
  color: var(--text-strong);
  background: var(--surface-brand-soft);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.top-nav a.active::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: 3px;
  height: 2px;
  border-radius: var(--radius-pill);
  background: var(--nav-active-bar);
}
.top-nav .nav-cta {
  margin-left: 6px;
  color: var(--text-on-brand);
  background: var(--surface-brand);
  box-shadow: none;
}
.top-nav .nav-cta:hover {
  color: var(--text-on-brand);
  background: var(--surface-brand);
  filter: brightness(1.06);
  box-shadow: var(--glow-brand);
}
.top-nav .nav-cta.logout {
  color: var(--text-on-bar-muted);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.top-nav .nav-cta.logout:hover { color: var(--text-strong); filter: none; box-shadow: inset 0 0 0 1px var(--border-strong); }

/* Conmutador de tema: dos botones en el DOM (móvil / escritorio),
   exactamente uno visible por breakpoint — lo cablea static/js/theme.js. */
.theme-toggle {
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background: var(--surface-card);
  color: var(--text-muted);
  cursor: pointer;
  /* T158: filter en la lista - el brillo del hover saltaba en vez de animarse. */
  transition: transform 160ms var(--ease-pop), color 160ms ease, filter 160ms ease;
}
.theme-toggle:hover { color: var(--text-strong); transform: translateY(-2px); filter: brightness(1.06); }
.theme-toggle:active { transform: scale(.96); transition-duration: 90ms; }
.theme-toggle-desktop { margin-left: 6px; }
.theme-icon { display: none; line-height: 0; }
:root[data-theme="light"] .theme-icon-moon,
:root:not([data-theme="dark"]) .theme-icon-moon { display: block; }
:root[data-theme="dark"] .theme-icon-sun { display: block; }

/* ── Layout principal ─────────────────────────────────────────────────── */
main {
  max-width: 940px;
  margin: 0 auto;
  padding: 28px var(--gutter) 96px;
}
main.wide { max-width: var(--content-max); }
main.home { max-width: var(--content-max); }

footer {
  border-top: 1px solid var(--border-subtle);
  padding: 24px var(--gutter) calc(24px + env(safe-area-inset-bottom));
  color: var(--text-faint);
  font-size: .85rem;
  text-align: center;
}
footer nav { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; margin-bottom: 8px; }
footer a { color: var(--text-muted); }
footer p { margin: 0; }

/* ── Barra inferior (móvil) ───────────────────────────────────────────── */
.bottom-nav {
  display: none;
  position: fixed;
  z-index: 45;
  left: 0; right: 0; bottom: 0;
  padding-bottom: env(safe-area-inset-bottom);
  /* La misma pieza que la barra de arriba, partida por el breakpoint: en
     móvil los enlaces de sección viven aquí (T120). */
  background: var(--surface-header);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: var(--border-header);
}
.bottom-nav-item {
  flex: 1;
  min-height: 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--text-on-bar-muted);
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
}
.bottom-nav-item:hover { text-decoration: none; }
/* Mismo criterio en móvil que en escritorio (convención del repo): el
   estado activo lo marca el oro, no un verde ligeramente distinto. */
.bottom-nav-item.active { color: var(--text-bar-active); }
.bottom-nav-keyboard-hidden { display: none !important; }

/* ── Botones y formularios ────────────────────────────────────────────── */
.btn,
button[type="submit"],
form button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 22px;
  border: 0;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: .85rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .07em;
  cursor: pointer;
  background: var(--surface-brand);
  color: var(--text-on-brand);
  /* T158: `background` en la lista, no sólo transform/box-shadow/filter -
     cubre `.btn-ghost`/`.btn-inline` de una vez, que sólo cambian background
     al hacer hover y hasta ahora saltaban en vez de animarse. */
  transition: transform 160ms var(--ease-pop), box-shadow 160ms ease, filter 160ms ease, background 160ms ease;
}
.btn:hover,
button[type="submit"]:hover,
form button:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow: var(--glow-brand);
  text-decoration: none;
}
.btn:active,
button[type="submit"]:active,
form button:active { transform: scale(.96); transition-duration: 90ms; }
button[disabled] { opacity: .55; cursor: default; transform: none !important; box-shadow: none !important; }

.btn-ghost,
form button.btn-ghost {
  background: transparent;
  color: var(--text-strong);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.btn-ghost:hover { background: var(--surface-brand-soft); box-shadow: inset 0 0 0 1px var(--border-strong); }

.btn-inline {
  min-height: 36px;
  padding: 0 14px;
  font-size: .72rem;
  background: transparent;
  color: var(--text-strong);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.btn-inline:hover { background: var(--surface-brand-soft); box-shadow: inset 0 0 0 1px var(--border-strong); }

form { max-width: 460px; margin: 0 0 28px; }
form label {
  display: block;
  margin-bottom: 14px;
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
}
input[type="text"], input[type="email"], input[type="password"], input[type="number"] {
  display: block;
  width: 100%;
  min-height: 48px;
  margin-top: 6px;
  padding: 0 14px;
  font-family: var(--font-body);
  /* Suelo de 16px: por debajo de eso Safari en iOS hace zoom solo al
     enfocar el campo, y con la raíz fluida 1rem baja de 16px en móvil. */
  font-size: max(16px, 1rem);
  color: var(--text-body);
  background: var(--surface-inset);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-input);
}

/* T140: en tema claro los campos de escribir van en BLANCO, no en el verde
   pálido de --surface-inset (en oscuro se quedan como estaban). No se toca
   la variable en sí: la comparten ~10 reglas más (celdas, tarjetas…).

   OJO con `type="number"`: queda FUERA a propósito. Este selector sale
   (0,3,1) y le ganaría a `input.baseline-input` (0,2,0), que fija a posta
   `background: var(--surface-card)` para los campos de "Dinero inicial" de
   la tabla de Dinero - los pintaría de blanco de rebote. Esto era el
   formulario de login, no la tabla. */
:root[data-theme="light"] input[type="text"],
:root[data-theme="light"] input[type="email"],
:root[data-theme="light"] input[type="password"],
:root:not([data-theme="dark"]) input[type="text"],
:root:not([data-theme="dark"]) input[type="email"],
:root:not([data-theme="dark"]) input[type="password"] {
  background: #fff;
}
input[type="number"] { font-family: var(--font-mono); }
input:focus-visible { border-color: var(--border-focus); outline-offset: 0; }

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  text-transform: none;
  letter-spacing: 0;
  font-size: .95rem;
  font-weight: 400;
  color: var(--text-body);
}
.checkbox-label input { width: 20px; height: 20px; accent-color: var(--surface-brand); margin: 0; }

/* ── Cabeceras de página y microtexto ─────────────────────────────────── */
.page-head { margin-bottom: 24px; }
.eyebrow, .hero-kicker {
  font-family: var(--font-body);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--text-eyebrow);
  margin: 0 0 6px;
}
/* Filete oro bajo el título de página: el acento va en el cromo, nunca
   dentro de los datos - ver docs/038. */
.page-head h1::after,
.hero h1::after {
  content: "";
  display: block;
  width: 56px;
  height: 4px;
  margin-top: 12px;
  border-radius: var(--radius-pill);
  background: var(--grad-hot);
  transform: skewX(var(--display-skew));
}
.subtitle { max-width: 68ch; color: var(--text-muted); }
.icon-inline { display: inline-flex; vertical-align: -.15em; color: var(--text-brand); }
h1 .icon-inline { transform: skewX(6deg); }

.updated-at, .password-note, .disclaimer, .account-status, .match-count-note, .recalc-note {
  font-size: .8rem;
  color: var(--text-faint);
}
.disclaimer { max-width: 62ch; }
/* T97: ahora es un <p> propio en vez de un <span> junto al botón, así que
   puede leerse como píldora de estado. Clase y role="status" intactos: T71
   depende de ambos. */
.recalc-note {
  margin: -8px 0 18px;
  padding: 10px 14px;
  border-radius: var(--radius-input);
  background: var(--surface-brand-soft);
  border: 1px solid var(--border-strong);
  color: var(--text-brand);
  font-size: .8rem;
  font-weight: 700;
}

.error {
  padding: 12px 14px;
  border-radius: var(--radius-input);
  background: rgba(192,57,43,.10);
  color: var(--status-loss);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(192,57,43,.25);
}

.dashboard-meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin: 0 0 18px;
}
.dashboard-meta-action { display: inline-flex; align-items: center; gap: 10px; }
.dashboard-meta-action form { margin: 0; }

.empty-state {
  padding: 32px 20px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  color: var(--text-muted);
  text-align: center;
}
.loading-state { display: grid; justify-items: center; gap: 14px; border-style: solid; }
.spinner {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 3px solid var(--border-default);
  border-top-color: var(--text-brand);
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.nav-loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  background: var(--surface-overlay);
  backdrop-filter: blur(6px);
}
.nav-loading-overlay .empty-state { background: var(--surface-card); box-shadow: var(--shadow-raised); }

/* ── Inicio ───────────────────────────────────────────────────────────── */
.hero { padding: 24px 0 36px; max-width: 24ch; max-width: none; }
/* El titular principal se queda en verde en los dos temas: es lo primero
   que se ve y la marca es verde. El naranja de los titulares (que solo
   actúa en oscuro) se lo cede al resto de la página, y aquí lo aporta el
   filete de debajo. */
.hero h1 { font-size: clamp(2.1rem, 7vw, 3.8rem); max-width: 20ch; color: var(--text-brand); }
.hero-sub { max-width: 56ch; font-size: 1.05rem; color: var(--text-muted); }

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
  margin-bottom: 44px;
}
.feature-card {
  display: block;
  padding: 22px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  color: var(--text-body);
  transition: transform 240ms var(--ease-pop), box-shadow 240ms ease;
}
.feature-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); text-decoration: none; }
.feature-card h2 { font-size: 1.25rem; margin: 12px 0 8px; }
.feature-card p { color: var(--text-muted); font-size: .95rem; }
.feature-icon {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 13px;
  background: var(--surface-brand-soft);
  color: var(--text-brand);
}
/* Un tono por tarjeta (T118): oro / celeste / verde. Se hace con
   :nth-of-type y no con una clase por tarjeta para no tocar home.html, y
   arrastra también el filete superior y el "ver más" de cada una, de modo
   que cada tarjeta queda con una identidad y no tres verdes iguales. */
.feature-card { position: relative; overflow: hidden; }
.feature-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--grad-hot);
}
.feature-card:nth-of-type(2)::before { background: var(--text-accent-cool); }
.feature-card:nth-of-type(3)::before { background: var(--surface-brand); }
.feature-card:nth-of-type(1) .feature-icon {
  background: var(--surface-warm-soft);
  color: var(--text-accent-warm);
}
.feature-card:nth-of-type(2) .feature-icon {
  background: var(--surface-cool-soft);
  color: var(--text-accent-cool);
}
/* Mismo dorado que el h2 de esta tarjeta (regla de abajo), en los dos temas.
   Antes iba por una variable --text-feature-link-1 que valía verde en claro
   y dorado en oscuro: el enlace no pegaba con su propio título en claro. */
.feature-card:nth-of-type(1) .feature-link { color: var(--text-accent-warm); }
/* El titular de cada tarjeta toma el color de SU tarjeta, no el naranja
   general de los titulares (petición del usuario mirando la home en
   oscuro). Con esto el filete de arriba, el icono y el título dicen lo
   mismo, en vez de tres títulos naranjas sobre tres filetes distintos. */
.feature-card:nth-of-type(1) h2 { color: var(--text-accent-warm); }
.feature-card:nth-of-type(2) h2 { color: var(--text-accent-cool); }
.feature-card:nth-of-type(3) h2 { color: var(--text-brand); }
.feature-card:nth-of-type(2) .feature-link { color: var(--text-accent-cool); }
.feature-link {
  font-size: .75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-brand);
}

.how-it-works { margin-bottom: 40px; }
.steps {
  counter-reset: step;
  list-style: none;
  display: grid;
  gap: 12px;
  padding: 0;
  margin: 0;
  max-width: 70ch;
}
.steps li {
  counter-increment: step;
  position: relative;
  padding: 14px 18px 14px 56px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  color: var(--text-muted);
}
.steps li::before {
  content: counter(step);
  position: absolute;
  left: 16px; top: 14px;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--surface-brand);
  color: var(--text-on-brand);
  font-family: var(--font-mono);
  font-size: .8rem;
  font-weight: 700;
}
.steps strong { color: var(--text-body); }

/* ── Tablas ───────────────────────────────────────────────────────────── */
.table-wrap {
  margin: 0 0 24px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-wrap table {
  width: 100%;
  border-collapse: collapse;
  font-size: .92rem;
}
.table-wrap thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 12px 14px;
  text-align: left;
  white-space: nowrap;
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-thead);
  background: var(--surface-thead);
  border-bottom: var(--border-thead);
  cursor: pointer;
  user-select: none;
  /* T157: sin esto el resaltado de cabecera aparecía/desaparecía de golpe
     en cada barrido del ratón, en TODAS las tablas de la app. 100ms, no los
     160-240ms del resto de controles: una transición lenta aquí deja un
     rastro de celdas a medio iluminar al pasar el ratón deprisa. */
  transition: color 100ms ease;
}
.table-wrap thead th:hover { color: var(--text-strong); }
/* Celeste, no verde (T118): la columna por la que se ordena es ESTADO DE
   INTERACCIÓN, no un dato - por eso puede llevar acento sin pisarle el
   significado a nada. Y empareja con el celeste que ya tiene .th-info-icon.
   Dentro de las celdas no entra ningún color nuevo. */
.table-wrap thead th[aria-sort] { color: var(--text-accent-cool); }
.table-wrap thead th[aria-sort="ascending"]::after { content: " ▲"; font-size: .8em; }
.table-wrap thead th[aria-sort="descending"]::after { content: " ▼"; font-size: .8em; }
.table-wrap th.num, .table-wrap td.num { text-align: right; }

.table-wrap tbody td {
  height: 52px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}
.table-wrap tbody tr:last-child td { border-bottom: 0; }
/* T157: mismo arreglo que la cabecera de arriba, misma duración corta. */
.table-wrap tbody tr { transition: background 100ms ease; }
.table-wrap tbody tr:hover { background: var(--surface-brand-soft); }

/* Toda cifra en monoespaciada y sin partirse en dos líneas. */
.table-wrap td.num,
.table-wrap td[data-sort-value],
.total-cell, .net, .amount-cell, .overpay-cell, .gap-cell {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.total-cell { font-weight: 700; color: var(--text-strong); }
/* `.total-cell.positive/.negative` (0,2,0) gana a `.total-cell` (0,1,0) de
   arriba, así que el color por signo propio pisa al --text-strong genérico
   sin depender del orden. */
tr.positive .net, .total-cell.positive, .amount-cell.positive, .overpay-cell.positive, .gap-cell.positive { color: var(--status-win); }
tr.negative .net, .total-cell.negative, .amount-cell.negative, .overpay-cell.negative, .gap-cell.negative { color: var(--status-loss); }

.editable-col { background: var(--surface-warm-soft); }
.baseline-cell { display: grid; gap: 4px; justify-items: end; }
/* `input.baseline-input`, no `.baseline-input` a secas: la regla base
   `input[type="number"]` de más arriba lleva un selector de atributo, o sea
   (0,1,1), y le GANA a una clase sola (0,1,0). Con lo cual ni el `width` ni
   el `font-size` de este bloque se aplicaban nunca - el campo venía
   heredando `width:100%` y `font-size:1rem` de la regla genérica, y los
   122px que había aquí eran letra muerta desde el principio. Añadir el
   nombre de etiqueta lo sube a (0,2,0) y ya gana. */
input.baseline-input {
  /* Se ajusta al valor MÁS LARGO de la columna, no a un ancho fijo. `ch` es
     exacto aquí porque la fuente es monoespaciada, así que 1ch es justo el
     ancho de un dígito; el sumando cubre padding, borde y las flechas del
     input numérico, que las pinta el navegador y no miden igual en todos.
     --baseline-ch lo calcula static/js/dashboard.js, porque el valor cambia
     mientras se teclea y el que llega del servidor se queda viejo en cuanto
     alguien edita. */
  width: calc(var(--baseline-ch, 9) * 1ch + 46px);
  min-height: 38px;
  margin: 0;
  padding: 0 10px;
  text-align: right;
  font-family: var(--font-mono);
  font-size: .88rem;
  background: var(--surface-card);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  color: var(--text-body);
}
.loan-suggestion-btn {
  min-height: 28px;
  padding: 0 9px;
  border: 1px solid var(--border-focus);
  border-radius: var(--radius-pill);
  background: var(--surface-warm-soft);
  color: var(--text-warm);
  font-family: var(--font-mono);
  font-size: .68rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: filter 100ms ease;
}
.loan-suggestion-btn:hover { filter: brightness(1.06); }

.team-name-with-crest { display: flex; align-items: center; gap: 9px; }
.team-crest { width: 22px; height: 22px; object-fit: contain; flex: 0 0 22px; }
/* El escudo va DENTRO del <h2> de la tarjeta, y `h1,h2,h3` llevan
   skewX(--display-skew) para el look "display" del sitio: el bloque entero
   se inclina, así que el escudo se veía "en cursiva". Se contrarresta con el
   ángulo inverso, igual que hace `h1 .icon-inline` con su icono. */
.team-card h2 .team-crest { transform: skewX(6deg); }
.team-crest-lg { width: 38px; height: 38px; flex-basis: 38px; }

.th-info-icon { display: inline-flex; vertical-align: -.15em; color: var(--text-cool); cursor: help; }
.opponent-tier { font-family: var(--font-mono); font-size: .78em; color: var(--text-faint); }

.formation {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  box-shadow: inset 0 0 0 1px var(--border-default);
  font-family: var(--font-mono);
  font-size: .7rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.trade-sparkline {
  width: 54px; height: 18px;
  vertical-align: middle;
  margin-left: 8px;
  color: var(--text-faint);
}

/* ── Perfil de mánager ────────────────────────────────────────────────── */
.manager-head-row { display: flex; align-items: center; gap: 14px; }
.manager-avatar {
  width: 56px; height: 56px;
  flex: 0 0 56px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-inset);
  box-shadow: inset 0 0 0 1px var(--border-default);
}
.manager-head h1 { margin: 0; }

/* ── Cabecera de tarjeta (T97) ────────────────────────────────────────── */
.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.card-head h2 { margin: 0; font-size: 1rem; }
.card-head-meta {
  font-family: var(--font-mono);
  font-size: .7rem;
  color: var(--text-faint);
}

/* ── Avatar de mánager en la tabla de Dinero (T97) ────────────────────── */
.manager-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: inherit;
}
.manager-link:hover { text-decoration: none; }
.manager-link:hover .manager-name { text-decoration: underline; }
.manager-avatar {
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--grad-pitch);
  color: #fff;
  font-family: var(--font-body);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .02em;
}
/* Contenido generado a propósito: así las iniciales no entran en el
   textContent de la celda, que es por lo que tables.js ordena esta
   columna (ver el comentario en dashboard.html). */
.manager-avatar::before { content: attr(data-initials); }
.manager-name { font-weight: 600; color: var(--text-strong); white-space: nowrap; }
/* La celda de mánager no es una cifra. Ya no lleva data-sort-value, así
   que la regla mono no la alcanza, pero se deja explícito por si alguien
   se la vuelve a añadir. */
.table-wrap td.manager-cell {
  font-family: var(--font-body);
  font-variant-numeric: normal;
}

/* ── Matriz de próximos partidos (T98) ────────────────────────────────── */
.table-wrap th.fixture-slot-col { text-align: center; padding-left: 6px; padding-right: 6px; }
.table-wrap td.fixture-cell { text-align: center; padding: 6px 5px; }
.fixture-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  min-width: 54px;
  justify-content: center;
  padding: 4px 7px;
  border-radius: var(--radius-input);
  font-family: var(--font-body);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
  cursor: default;
}
.fixture-venue { font-size: .6rem; opacity: .75; }
/* Los 4 niveles del rival, de fácil a difícil. Fondo translúcido sobre el
   color de estado para que el texto siga legible en ambos temas sin tener
   que redefinir cada nivel en el bloque oscuro. */
.fixture-chip-t1 { background: color-mix(in srgb, var(--status-win) 18%, transparent); color: var(--status-win); }
.fixture-chip-t2 { background: color-mix(in srgb, var(--status-draw) 20%, transparent); color: var(--text-warm); }
.fixture-chip-t3 { background: color-mix(in srgb, var(--gold-600) 22%, transparent); color: var(--gold-600); }
.fixture-chip-t4 { background: color-mix(in srgb, var(--status-loss) 18%, transparent); color: var(--status-loss); }
.fixture-chip-t0, .fixture-chip-empty {
  background: var(--surface-inset);
  color: var(--text-faint);
  font-weight: 600;
}
.fixture-legend-note {
  margin: -12px 0 24px;
  font-size: .7rem;
  color: var(--text-faint);
}

/* ── Gráfico ──────────────────────────────────────────────────────────── */
.chart-wrap {
  position: relative;
  margin: 0 0 24px;
  padding: 18px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
}
.chart-svg { width: 100%; height: 300px; display: block; overflow: visible; }
.chart-gridline { stroke: var(--border-default); stroke-width: 1; }
.chart-zero-line { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.chart-axis-label {
  font-family: var(--font-mono);
  font-size: 1.3px;
  fill: var(--text-faint);
}
.chart-axis-label-x { font-size: 1.2px; }
.chart-line { stroke-linejoin: round; stroke-linecap: round; }
.chart-hit-path { stroke: transparent; stroke-width: 8; }
.chart-point { opacity: 0; transition: opacity 160ms ease; cursor: pointer; }
.chart-series:hover .chart-point, .chart-point:focus { opacity: 1; }
.chart-series.hidden { display: none; }
/* El relleno de área solo cuando quedan pocas series visibles (chart.js). */
.chart-area { opacity: 0; transition: opacity 240ms ease; }
.chart-svg.chart-focused .chart-area { opacity: 1; }

.chart-tooltip {
  position: absolute;
  transform: translate(-50%, calc(-100% - 10px));
  padding: 6px 10px;
  border-radius: 10px;
  background: var(--green-950);
  color: var(--green-100);
  font-family: var(--font-mono);
  font-size: .72rem;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: var(--shadow-raised);
}
.chart-tooltip[hidden] { display: none; }

.chart-legend-controls { display: flex; gap: 8px; margin: 14px 0 8px; }
.chart-toggle-all-btn {
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: color 100ms ease, background 100ms ease;
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  cursor: pointer;
}
.chart-toggle-all-btn:hover { color: var(--text-strong); background: var(--surface-brand-soft); }

.chart-legend { display: flex; flex-wrap: wrap; gap: 6px; }
.chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  padding: 0 11px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: .78rem;
  cursor: pointer;
  /* T158: background en la lista - el hover saltaba en vez de animarse. */
  transition: opacity 160ms ease, background 100ms ease;
}
.chart-legend-item:hover { background: var(--surface-brand-soft); }
.chart-legend-item.inactive { opacity: .42; }
.chart-swatch { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 10px; }

/* ── Banner de cuenta ─────────────────────────────────────────────────── */
.account-upsell-banner {
  display: none;
  position: relative;
  align-items: center;
  gap: 12px;
  margin: 0 0 20px;
  padding: 14px 48px 14px 16px;
  border-radius: var(--radius-card);
  background: var(--surface-cool-soft);
  box-shadow: inset 0 0 0 1px rgba(47,128,237,.28);
}
.account-upsell-banner.visible { display: flex; animation: pop-in 240ms var(--ease-pop); }
.account-upsell-banner p { margin: 0; font-size: .9rem; }
@keyframes pop-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.banner-close {
  position: absolute;
  top: 50%; right: 8px;
  transform: translateY(-50%);
  width: 34px; height: 34px;
  min-height: 34px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  font-size: 1.2rem;
  cursor: pointer;
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: background 100ms ease, color 100ms ease;
}
.banner-close:hover { background: rgba(47,128,237,.14); color: var(--text-strong); box-shadow: none; transform: translateY(-50%); }
.account-upsell-link { font-size: .85rem; }

/* ── Subnavegación de sección y selector de partidos ──────────────────── */
.section-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 20px;
  padding: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  box-shadow: inset 0 0 0 1px var(--border-subtle);
  width: fit-content;
}
.section-subnav a {
  display: inline-flex;
  align-items: center;
  /* min-height/padding en em, no px: así encogen junto con el font-size
     fluido de abajo y las 3 pestañas siguen cabiendo en una sola fila
     hasta los ~320px de ancho, en vez de partirse en dos líneas. */
  min-height: 3.3em;
  padding: 0 1.2em;
  border-radius: var(--radius-pill);
  /* Este clamp se COMPONE con el escalado fluido de la raíz (html), que ya
     encoge todo el rem. Por eso el suelo es .64rem y no .56rem: a 320px la
     raíz vale 14px, así que .64rem = 8,96px, que es el tamaño al que estas
     3 pestañas caben justas en una fila. Estas pastillas necesitan encoger
     más que el texto normal porque van muy apretadas.

     El valor plano de antes va DELANTE como respaldo: dividir longitud
     entre longitud dentro de calc() es CSS Values 4, y un navegador viejo
     que no lo entienda tira la declaración entera - sin el respaldo
     heredaría ~1rem, más grande incluso que el tamaño original, y
     volvería a partirse en dos filas. */
  font-size: .76rem;
  font-size: clamp(.64rem, calc(.64rem + .12rem * ((100vw - 320px) / 200px)), .76rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: color 100ms ease;
}
.section-subnav a:hover { color: var(--text-strong); text-decoration: none; }
.section-subnav a.active {
  background: var(--surface-card);
  color: var(--text-strong);
  box-shadow: var(--shadow-card), inset 0 -2px 0 var(--text-accent-warm);
}

/* Indicador deslizante (T121). El resaltado del enlace activo se lo cede al
   indicador SOLO cuando static/js/subnav-slide.js ha corrido y ha puesto
   .has-indicator: sin JS, la regla de arriba sigue intacta y la pestaña
   activa se ve igual que siempre. */
.section-subnav { position: relative; }
.section-subnav a { position: relative; z-index: 1; }
.section-subnav.has-indicator a.active { background: transparent; box-shadow: none; }
.section-subnav-indicator {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  opacity: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-card);
  box-shadow: var(--shadow-card), inset 0 -2px 0 var(--text-accent-warm);
  transition: transform 340ms var(--ease-pop), width 340ms var(--ease-pop);
}
/* Se revela cuando el JS ya lo ha medido y colocado, no antes: si no,
   asomaría un instante en la esquina superior izquierda. */
.section-subnav-indicator.is-ready { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .section-subnav-indicator { transition: none; }
}

.match-count-selector {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  /* Fluido igual que el font-size de abajo: menos hueco entre las bolas
     cuando ya van más apretadas. Respaldo plano delante por lo mismo que
     en las pestañas: si el navegador tira el clamp, sin él las bolas se
     quedarían pegadas (gap: normal). */
  gap: 6px;
  gap: clamp(3px, calc(3px + 3px * ((100vw - 320px) / 200px)), 6px);
  margin-top: 14px;
}
.match-count-label {
  /* Recalibrado igual que las pestañas: se compone con la raíz fluida, y
     con el mismo respaldo plano delante para navegadores viejos. */
  font-size: .7rem;
  font-size: clamp(.59rem, calc(.59rem + .11rem * ((100vw - 320px) / 200px)), .7rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  margin-right: 4px;
}
.match-count-option {
  display: inline-grid;
  place-items: center;
  /* En em, no px: encogen junto con el font-size fluido de abajo para que
     la etiqueta + las 5 bolas quepan en una sola fila hasta ~320px de
     ancho, en vez de que alguna se quede huérfana en su propia línea. */
  min-width: 3.1em;
  min-height: 3.1em;
  border-radius: var(--radius-pill);
  /* `currentColor`, no un token de borde: estos son botones sueltos sobre
     el fondo de la página, sin tarjeta que los recorte, y los tokens de
     borde están calibrados para separar superficies contiguas, no para
     dibujar un control en el aire - --border-default daba 1,2:1 contra el
     fondo y --border-strong 1,4:1, cuando un control necesita 3:1.
     Atándolo al color del texto quedan en 4,9:1 y el borde sigue solo al
     estado: se refuerza en hover sin una regla aparte. */
  border: 1px solid currentColor;
  font-family: var(--font-mono);
  /* Recalibrado igual que las pestañas: se compone con la raíz fluida, y
     con el mismo respaldo plano delante para navegadores viejos. */
  font-size: .85rem;
  font-size: clamp(.72rem, calc(.72rem + .13rem * ((100vw - 320px) / 200px)), .85rem);
  color: var(--text-muted);
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: color 100ms ease, background 100ms ease;
}
.match-count-option:hover {
  color: var(--text-strong);
  background: var(--surface-brand-soft);
  text-decoration: none;
}
.match-count-option.active {
  background: var(--surface-brand);
  border-color: var(--surface-brand);
  color: var(--text-on-brand);
}

/* ── Calendario de jornadas ───────────────────────────────────────────── */
.difficulty-legend { font-size: .8rem; color: var(--text-muted); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.difficulty-legend-bar {
  width: 88px; height: 8px;
  border-radius: var(--radius-pill);
  background: linear-gradient(100deg, hsl(120 55% 42%), hsl(60 70% 48%), hsl(0 65% 52%));
}

.fixture-day { margin-bottom: 26px; }
.fixture-day h2 { font-size: 1rem; color: var(--text-muted); }
.fixture-list { display: grid; gap: 8px; }
.fixture-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 8px 14px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
}
.fixture-team { display: flex; align-items: center; gap: 8px; font-weight: 600; }
.fixture-away { justify-content: flex-end; text-align: right; }
.fixture-score {
  font-family: var(--font-mono);
  font-weight: 700;
  white-space: nowrap;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  color: var(--text-strong);
}
.fixture-vs { color: var(--text-faint); font-weight: 400; }
/* Barra de dificultad por equipo: el hue lo inyecta la plantilla. */
.fixture-row.has-gradient { position: relative; overflow: hidden; }
.fixture-row.has-gradient::before,
.fixture-row.has-gradient::after {
  content: "";
  position: absolute;
  bottom: 0;
  height: 3px;
  width: 50%;
}
.fixture-row.has-gradient::before { left: 0; background: hsl(var(--home-hue) 60% 45%); }
.fixture-row.has-gradient::after { right: 0; background: hsl(var(--away-hue) 60% 45%); }

/* ── Onces y equipos ──────────────────────────────────────────────────── */
.pitch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}
.fixture-group {
  display: grid;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-brand-soft);
}
.fixture-group-head {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--text-muted);
}

.team-pitch {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.team-pitch-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
}
.team-pitch-head h2 { margin: 0; font-size: 1rem; }

.pitch {
  position: relative;
  aspect-ratio: 3 / 4;
  background: var(--grad-pitch);
  background-image:
    repeating-linear-gradient(180deg, rgba(255,255,255,.05) 0 8%, transparent 8% 16%),
    var(--grad-pitch);
}
.player {
  position: absolute;
  transform: translate(-50%, -50%);
  display: grid;
  justify-items: center;
  gap: 3px;
  width: 74px;
  text-align: center;
}
.player-badge { position: relative; display: block; }
.player-photo {
  width: 34px; height: 34px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--green-900);
  box-shadow: 0 0 0 2px rgba(255,255,255,.55);
}
.player-dot {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--green-950);
  color: #fff;
  font-family: var(--font-mono);
  /* Suelo en px frente al escalado fluido de la raíz: este texto ya nace
     diminuto y va dentro de círculos de px FIJOS (28px / 17px), que no
     encogen, así que no tiene margen para bajar más sin volverse
     ilegible. Deja escalar un poco y ahí se planta. */
  font-size: max(8.5px, .58rem);
  font-weight: 700;
}
.player-dot-mini {
  position: absolute;
  right: -4px; bottom: -4px;
  width: 17px; height: 17px;
  font-size: max(7.5px, .48rem);
}
.pos-POR .player-dot { background: var(--pos-por); color: var(--green-950); }
.pos-DEF .player-dot { background: var(--pos-def); }
.pos-MIG .player-dot { background: var(--pos-mig); color: var(--green-950); }
.pos-DEL .player-dot { background: var(--pos-del); }
.player-name {
  /* Mismo suelo que .player-dot: nombre sobre el campo, ya diminuto. */
  font-size: max(9px, .62rem);
  font-weight: 700;
  line-height: 1.15;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.75);
}
.player-name:hover { color: var(--gold-400); }

/* ── Once de consenso (T108, movido a /onces en T109) ────────────────────
   Mismo campo/.player de siempre; solo añade el estado de acuerdo entre
   fuentes: sólido cuando todas coinciden, atenuado y con contorno
   discontinuo cuando solo lo pone alguna. El contorno va tanto sobre la
   foto como sobre el punto de posición, porque un jugador tiene una u
   otra según lo cubra o no el scrape de FutbolFantasy. */
.consensus-partial .player-dot { opacity: .55; border: 1.5px dashed rgba(255,255,255,.85); }
.consensus-partial .player-photo {
  opacity: .6;
  box-shadow: 0 0 0 1.5px rgba(255,255,255,.5);
  filter: grayscale(.4);
}
.consensus-partial .player-name { opacity: .7; }
.consensus-full .player-photo { box-shadow: 0 0 0 2px var(--green-300); }
.consensus-count {
  display: block;
  font-family: var(--font-mono);
  /* Mismo suelo que .player-dot. */
  font-size: max(8px, .52rem);
  color: rgba(255,255,255,.85);
  text-shadow: 0 1px 3px rgba(0,0,0,.75);
}
.consensus-full .consensus-count { color: var(--green-300); }
.unidentified-note {
  margin: 10px 14px 14px;
  font-size: .78rem;
  color: var(--text-faint);
}

/* ── Precisión por jornada (T110) ────────────────────────────────────────
   Lista de jornadas desplegables con <details>, sin JS: el resumen lleva
   el % medio de cada fuente y el contenido, el desglose por equipo. */
.round-accuracy-list { display: flex; flex-direction: column; gap: 10px; }
.round-accuracy {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.round-accuracy > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 14px 18px;
  cursor: pointer;
  list-style: none;
  /* T158: sin transición ninguna en la base - el hover saltaba. */
  transition: background 100ms ease;
}
.round-accuracy > summary::-webkit-details-marker { display: none; }
.round-accuracy > summary:hover { background: var(--surface-brand-soft); }
.round-accuracy-label { font-weight: 700; color: var(--text-strong); }
.round-accuracy-label small {
  display: block;
  font-weight: 500;
  font-size: .72rem;
  color: var(--text-faint);
}
.round-accuracy-scores { display: flex; flex-wrap: wrap; gap: 8px; }
.source-pct {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--surface-inset);
  font-family: var(--font-mono);
  font-size: .82rem;
  font-weight: 700;
  color: var(--text-strong);
}
.source-pct em {
  font-family: inherit;
  font-style: normal;
  font-weight: 500;
  font-size: .7rem;
  color: var(--text-muted);
}
.source-pct-empty { color: var(--text-faint); }
.round-accuracy .table-wrap {
  border: 0;
  border-top: 1px solid var(--border-subtle);
  border-radius: 0;
  box-shadow: none;
}
.round-accuracy[open] > summary { border-bottom: 1px solid var(--border-subtle); }

.team-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  background: var(--surface-card);
  box-shadow: var(--shadow-card);
  transition: transform 240ms var(--ease-pop), box-shadow 240ms ease;
}
.team-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); text-decoration: none; }
.team-card h2 { display: flex; align-items: center; gap: 10px; margin: 0; font-size: 1.05rem; }
.team-card-count { font-family: var(--font-mono); font-size: .78rem; color: var(--text-faint); }

/* ── Power ranking ────────────────────────────────────────────────────── */
.ranking-override-input {
  width: 88px;
  min-height: 38px;
  margin: 0;
  padding: 0 10px;
  text-align: right;
  font-family: var(--font-mono);
  background: var(--surface-inset);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  color: var(--text-body);
}
.ranking-save-bar { display: flex; align-items: center; gap: 14px; margin-bottom: 28px; }
.ranking-save-bar button { min-height: 44px; }
#ranking-save-status { font-size: .82rem; color: var(--text-muted); }

/* ── Páginas legales ──────────────────────────────────────────────────── */
.legal-content { max-width: 68ch; color: var(--text-muted); }
.legal-content p { margin-bottom: 14px; }

/* ── Breakpoints ──────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  .top-nav { display: none; }
  .bottom-nav { display: flex; }
  main { padding-top: 20px; padding-bottom: 96px; }
  .table-wrap { border-radius: var(--radius-card); }
  .fixture-row { grid-template-columns: 1fr auto 1fr; padding: 8px 10px; }
  .player { width: 62px; }
}

@media (min-width: 761px) {
  .theme-toggle-mobile { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── Franjas de césped laterales (T131) ───────────────────────────────── */
/* Decoración en los márgenes que sobran cuando la ventana es más ancha que
   --content-max. Al pasar el ratón, la hierba se APARTA a su alrededor.

   La textura es una FOTO (static/img/grass-tile.jpg), no gradientes: el
   primer intento se generó con degradados y ruido, y al lado de césped de
   verdad se leía como rayas con grano - lo que vende el césped son las
   briznas, y con gradientes no se dibujan briznas. El mosaico repite sin
   costura, comprobado midiendo la junta contra la variación normal entre
   columnas contiguas, antes y después de reducirlo.

   DOS CAPAS de la misma textura, exactamente encajadas. La de abajo está
   quieta; la de arriba va recortada a un círculo que sigue al cursor y se
   ESCALA tomando ese punto como origen, así que dentro del círculo las
   briznas se alejan radialmente del ratón mientras el resto sigue quieto.
   Como las dos son la misma imagen en la misma posición, fuera del círculo
   no se distingue que haya dos. Es la versión que el usuario prefirió tras
   probar el temblor y el desplazamiento por mapa (feDisplacementMap).

   NO se pintan en móvil ni en táctil: el ancho no da, y sin ratón no hay
   efecto. */
.pitch-banner { display: none; }

@media (min-width: 1280px) and (hover: hover) and (pointer: fine) {
  .pitch-banner {
    display: block;
    position: fixed;
    top: 0;
    bottom: 0;
    /* Lo que queda a cada lado del contenido, menos el canalón. Si sale
       negativo, max() lo deja en cero y la franja no aparece. */
    width: max(0px, calc((100vw - var(--content-max)) / 2 - var(--gutter)));
    overflow: hidden;
    z-index: 0;
    pointer-events: none;
  }
  .pitch-banner-left { left: 0; }
  .pitch-banner-right { right: 0; }

  .pitch-grass {
    position: absolute;
    inset: 0;
    background-image: url("img/grass-tile.jpg");
    /* Un solo número decide el tamaño aparente de las briznas. */
    background-size: 360px 360px;
    filter: var(--pitch-filter);
    opacity: var(--pitch-opacity);
  }

  /* La capa que APARTA la hierba: recortada a un círculo que sigue al cursor
     (--pitch-mx/my) y escalada desde ese mismo punto, de modo que las
     briznas se alejan radialmente de él. --pitch-on la apaga al salir de la
     franja o al dejar de moverse. --pitch-r es el radio del círculo y
     --pitch-push cuánto se agranda: los dos números a tocar. */
  .pitch-grass-shimmer {
    position: absolute;
    inset: 0;
    background-image: url("img/grass-tile.jpg");
    background-size: 360px 360px;
    filter: var(--pitch-filter);
    opacity: calc(var(--pitch-opacity) * var(--pitch-on, 0));
    -webkit-mask-image: radial-gradient(
      circle var(--pitch-r, 42px) at var(--pitch-mx, -999px) var(--pitch-my, -999px),
      #000 0%, rgba(0,0,0,.6) 55%, transparent 100%);
    mask-image: radial-gradient(
      circle var(--pitch-r, 42px) at var(--pitch-mx, -999px) var(--pitch-my, -999px),
      #000 0%, rgba(0,0,0,.6) 55%, transparent 100%);
    transform-origin: var(--pitch-mx, 50%) var(--pitch-my, 50%);
    transform: scale(var(--pitch-push, 1.35));
    /* Solo la opacidad transiciona. El escalado NO: con transición, la
       hierba perseguiría al cursor con retraso en vez de abrirse bajo él. */
    transition: opacity 140ms ease;
    will-change: transform, opacity;
  }

  /* Difuminado hacia el contenido para que la franja no acabe en un corte
     recto. Empieza tarde (78%) para que se vea césped y no solo el borde. */
  .pitch-banner::after {
    content: "";
    position: absolute;
    inset: 0;
  }
  .pitch-banner-left::after {
    background: linear-gradient(90deg, transparent 78%, var(--surface-app) 100%);
  }
  .pitch-banner-right::after {
    background: linear-gradient(270deg, transparent 78%, var(--surface-app) 100%);
  }
}

/* Sin efecto si el sistema pide menos movimiento: el césped se queda quieto. */
@media (prefers-reduced-motion: reduce) {
  .pitch-grass-shimmer { display: none; }
}

/* Crédito de la textura (obligatorio por su licencia): visible pero sin
   competir con los enlaces legales que tiene al lado. */
footer .credits { font-size: .78rem; color: var(--text-faint); margin: 4px 0 0; }
footer .credits a { color: inherit; text-decoration: underline; }
