:root {
  color-scheme: dark light;

  /* Palette */
  --bg: #0f1115;
  --panel: #181c23;
  --panel-2: #1f242d;
  --text: #eef1f6;
  --muted: #9aa4b2;
  --border: #2a313c;
  --accent: #4ade80;
  --accent-2: #38bdf8;
  --gold: #fbbf24;
  --danger: #f87171;

  /* Layout. Tres cortes de página, siempre los mismos: 640 px (cabecera y
     rejillas pequeñas), 1024 px (la página se parte en columnas) y 1200 px
     (cuando esas columnas ya tienen sitio para su contenido). Solo dos sitios
     puntuales usan otro: 900 px para los dos conmutadores de la clasificación y
     1100 px para las dos columnas de /admin. El contenedor es fluido y solo se
     topa en pantallas enormes; --gutter crece con la ventana y es el mismo
     margen que usan la cabecera, el pie y el contenido, para que todo quede a
     la misma altura. */
  --page-max: 1800px;
  --gutter: clamp(.625rem, .3rem + 1.7vw, 2.75rem);
  --grid-gap: clamp(.75rem, .5rem + .5vw, 1.25rem);
  --card-pad: clamp(.75rem, .55rem + .55vw, 1.4rem);
  /* Ancho de lectura: los párrafos y las listas no se estiran aunque la
     tarjeta que los lleva ocupe toda la pantalla. */
  --measure: 66ch;

  /* Type scale. Los tres tamaños pequeños son los de siempre —el móvil es el
     que manda— y los tres grandes crecen con la ventana. */
  --text-xs: .72rem;
  --text-sm: .84rem;
  --text-md: clamp(.94rem, .9rem + .2vw, 1.02rem);
  --text-base: clamp(1rem, .96rem + .18vw, 1.0625rem);
  --text-lg: clamp(1.18rem, 1.06rem + .45vw, 1.45rem);
  --text-xl: clamp(1.5rem, 1.18rem + 1.1vw, 2.15rem);

  /* Spacing and shape */
  --space-1: .25rem;
  --space-2: .5rem;
  --space-3: .75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --radius: 14px;
  --radius-sm: 10px;
  --radius-pill: 999px;
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 6px 16px -12px rgba(0, 0, 0, .6);
  --shadow-soft: 0 1px 2px rgba(0, 0, 0, .25);
  --runner-shadow: rgba(0, 0, 0, .45);
  --lane-tint: 10%;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f5f6f8;
    --panel: #ffffff;
    --panel-2: #f0f2f5;
    --text: #14181f;
    --muted: #5d6675;
    --border: #dde2ea;
    --accent: #16a34a;
    --accent-2: #0284c7;
    --gold: #b45309;
    --danger: #dc2626;
    --shadow: 0 1px 2px rgba(15, 20, 30, .06), 0 8px 20px -18px rgba(15, 20, 30, .5);
    --shadow-soft: 0 1px 2px rgba(15, 20, 30, .05);
    --runner-shadow: rgba(15, 23, 42, .18);
    --lane-tint: 8%;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: var(--text-base)/1.5 system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  -webkit-text-size-adjust: 100%;
}

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

/* Sticky header: on a phone the brand shrinks to its icon and the pills wrap to
   a second row, so the six sections stay reachable without side-scrolling.
   The safe-area paddings keep it below the notch and the rounded corners when
   the app runs standalone from the home screen. The row itself is capped and
   centred like the content, but the bar behind it is not. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  padding:
    calc(var(--space-2) + env(safe-area-inset-top, 0px))
    calc(var(--gutter) + env(safe-area-inset-right, 0px))
    var(--space-2)
    calc(var(--gutter) + env(safe-area-inset-left, 0px));
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(10px);
}

.topbar-inner {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--space-2);
  max-width: var(--page-max);
  margin: 0 auto;
}

.brand {
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}
.brand:hover { text-decoration: none; }

.topbar nav {
  display: flex;
  gap: var(--space-1);
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.topbar nav a {
  color: var(--muted);
  padding: .35rem .6rem;
  border-radius: var(--radius-pill);
  font-size: var(--text-md);
  white-space: nowrap;
}
.topbar nav a.active,
.topbar nav a:hover { color: var(--text); background: var(--panel-2); text-decoration: none; }

/* En un movil el icono de la app es redundante —ya estas dentro— y seis
   secciones no caben a su lado: se le cede todo el ancho al menu. */
@media (max-width: 640px) {
  .topbar-inner { gap: var(--space-1); }
  .topbar .brand { display: none; }
  /* Al partirse en dos filas, alinear a la derecha dejaria una pildora suelta
     a la derecha de la segunda: se lee mejor en orden natural. */
  .topbar nav { gap: 2px; justify-content: flex-start; }
  .topbar nav a { padding: .3rem .4rem; font-size: var(--text-sm); }
}

/* Entre la tableta y el portatil el nombre de la app y las siete secciones ya
   no caben en la misma fila: se le da al nombre su propia linea, en lugar de
   dejar media fila vacia a la izquierda del menu. */
@media (min-width: 641px) and (max-width: 899px) {
  .topbar-inner { flex-wrap: wrap; row-gap: 0; }
  .topbar .brand { flex: 0 0 100%; }
  .topbar nav { justify-content: flex-start; }
}

main {
  max-width: var(--page-max);
  margin: 0 auto;
  padding:
    var(--space-4)
    calc(var(--gutter) + env(safe-area-inset-right, 0px))
    calc(4rem + env(safe-area-inset-bottom, 0px))
    calc(var(--gutter) + env(safe-area-inset-left, 0px));
}

.site-footer {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 calc(var(--gutter) + env(safe-area-inset-right, 0px)) 2rem
    calc(var(--gutter) + env(safe-area-inset-left, 0px));
}

h1 { font-size: var(--text-xl); line-height: 1.2; margin: var(--space-1) 0 var(--space-3); letter-spacing: -.01em; text-wrap: balance; }
h2 {
  font-size: var(--text-lg);
  margin: clamp(1.25rem, 1rem + .8vw, 2rem) 0 var(--space-2);
  letter-spacing: -.01em;
}
h3 {
  font-size: var(--text-sm);
  margin: var(--space-3) 0 var(--space-2);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 600;
}
/* Un encabezado al principio de una tarjeta no lleva margen de arriba: el
   relleno de la tarjeta ya hace ese papel. */
.card > h3:first-child,
.editor-section > h3:first-child { margin-top: 0; }

/* La prosa se queda en un ancho legible aunque la tarjeta ocupe 1800 px. */
main p,
main li,
main dl,
main details,
main .prose { max-width: var(--measure); }
main p.center, main li.center { margin-inline: auto; }

.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--card-pad);
  box-shadow: var(--shadow);
  margin-bottom: var(--grid-gap);
}

.card.compact { padding: var(--space-2) var(--space-3); }

/* Un estado vacío es una frase suelta: no gana nada por medir 1800 px. Se
   estrecha y se centra, y así se ve igual en todas las páginas. */
.card.empty {
  border-style: dashed;
  background: transparent;
  box-shadow: none;
  color: var(--muted);
  font-size: var(--text-sm);
  text-align: center;
  padding: var(--space-5) var(--space-4);
  max-width: min(100%, 52rem);
  margin-inline: auto;
}

.muted { color: var(--muted); }
.small { font-size: var(--text-sm); }
.tiny { font-size: var(--text-xs); }
.center { text-align: center; }
.row { display: flex; align-items: center; gap: var(--space-2); }
.row.between { justify-content: space-between; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.dot {
  display: inline-block;
  width: .6rem;
  height: .6rem;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: baseline;
}

/* Rejillas de página ------------------------------------------------------
   Dos piezas y una regla: `.stack` apila tarjetas con la misma separación que
   la rejilla, y `.split` pone dos bloques lado a lado a partir de 1024 px. Las
   tarjetas que van dentro pierden su margen inferior, porque el hueco lo pone
   el `gap`. Móvil siempre primero: en una columna el orden es el del documento.
   La columna es `minmax(0, 1fr)` y no el `auto` de serie: con `auto` una tabla
   ancha ensancharía su columna —y con ella toda la página— en vez de desplazarse
   dentro de su tarjeta. */
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-content: start; }
.split { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
.stack > *,
.split > * { margin-bottom: 0; }

@media (min-width: 1024px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split--aside-right { grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); }
  .split--aside-left { grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr); }
}

/* Segmented control (period and view switchers) */
.board-tabs { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); margin: var(--space-2) 0; }
@media (min-width: 900px) {
  /* Los dos conmutadores, uno al lado del otro y sin estirarse: a lo ancho de
     una pantalla grande dos pastillas de 384 px se leen de un vistazo. */
  .board-tabs {
    grid-template-columns: repeat(2, minmax(0, 24rem));
    column-gap: var(--space-4);
  }
}

.segmented {
  display: flex;
  gap: var(--space-1);
  padding: var(--space-1);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}
.segmented .seg {
  flex: 1;
  text-align: center;
  padding: .4rem .5rem;
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: var(--text-md);
  font-weight: 500;
  white-space: nowrap;
}
.segmented .seg:hover { color: var(--text); text-decoration: none; }
.segmented .seg.active {
  background: var(--panel);
  color: var(--text);
  font-weight: 600;
  box-shadow: var(--shadow-soft);
}

.avatar {
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: var(--text-sm);
  color: #0b0e12;
  background: var(--team, var(--accent));
}

.avatar-runner {
  /* La caja se ajusta al corredor: recortarlo con overflow:hidden le cortaba la
     cabeza y la sombra. */
  width: fit-content;
  height: fit-content;
  flex: 0 0 auto;
  border-radius: 12px;
  background: color-mix(in srgb, var(--team, var(--accent)) 20%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--team, var(--accent)) 40%, var(--border));
  overflow: hidden;
}

.leader-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}
.leader-row:last-child { border-bottom: 0; }
.leader-row .rank { width: 1.6rem; text-align: center; font-weight: 700; color: var(--muted); }
.leader-row .meta { font-size: var(--text-sm); color: var(--muted); }
.leader-row .value { text-align: right; font-variant-numeric: tabular-nums; }
.leader-row .value strong { font-size: var(--text-lg); }
.leader-row.top-1 {
  background: linear-gradient(90deg, color-mix(in srgb, var(--gold) 14%, transparent), transparent);
  border-radius: var(--radius-sm);
}

.bar {
  height: 7px;
  max-width: 44rem;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  overflow: hidden;
  margin-top: .35rem;
}
.bar > span {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 55%, transparent), var(--accent));
  transition: width .5s ease;
}
.bar.over > span { background: linear-gradient(90deg, var(--accent), var(--gold)); }

/* Racetrack -------------------------------------------------------------- */

.race {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  margin-bottom: var(--grid-gap);
}

.lane {
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--lane) var(--lane-tint), transparent), transparent 55%),
    var(--panel);
  border: 1px solid var(--border);
  border-left: 4px solid var(--lane);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3) var(--space-1);
  box-shadow: var(--shadow);
  min-width: 0;
}

.lane-head { display: flex; align-items: center; gap: var(--space-2); }
.lane-avatar { display: inline-flex; }
.lane-name { display: flex; align-items: center; gap: .35rem; min-width: 0; }
.lane-value { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lane-value strong { font-size: var(--text-md); display: block; }
.lane-value .tiny { display: block; }

.lane-head .rank {
  width: 1.35rem;
  flex: 0 0 1.35rem;
  text-align: center;
  font-weight: 700;
  color: var(--muted);
  font-size: var(--text-md);
}
.rank--medal {
  display: grid;
  place-items: center;
  width: 1.6rem;
  flex-basis: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  font-size: 1rem;
  background: color-mix(in srgb, var(--medal, var(--gold)) 24%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--medal, var(--gold)) 45%, transparent);
}

/* Los tres primeros van con medalla en el carril: es el podio, y se ve sin
   contar puestos. */
.lane[data-rank="1"] { --medal: var(--gold); }
.lane[data-rank="2"] { --medal: #cbd5e1; }
.lane[data-rank="3"] { --medal: #d97706; }
.lane[data-rank] {
  border-left-color: var(--medal);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--medal) 9%, transparent), transparent 62%),
    linear-gradient(90deg, color-mix(in srgb, var(--lane) var(--lane-tint), transparent), transparent 55%),
    var(--panel);
}
/* El carril propio, para encontrarse de un vistazo. */
.lane[data-me="1"],
.leader-row[data-me="1"] {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  border-left-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 25%, transparent), var(--shadow);
}

.badge-me {
  flex: none;
  font-size: .6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: #06130a;
  background: var(--accent);
  border-radius: var(--radius-pill);
  padding: 0 .35rem;
}
.gap {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--muted);
  background: var(--panel-2);
  border-radius: var(--radius-pill);
  padding: 0 .35rem;
}
.gap--leader { color: var(--gold); background: color-mix(in srgb, var(--gold) 16%, transparent); }

/* La pista de cada carril: la superficie es el recorrido entero, el relleno es
   lo que lleva andado ese carril. Los dos van en porcentaje del ancho, así que
   la meta cae al final de la pista mientras nadie pase de su objetivo. */
.track {
  position: relative;
  height: 64px;
  margin-top: var(--space-1);
  /* Tres franjas: abajo los rótulos de distancia, en medio la pista por la que
     se corre y arriba el corredor (con la corona del líder por encima). */
  --label-row: 13px;
  --surface-h: 10px;
  --surface-bottom: var(--label-row);
  --surface-top: calc(var(--label-row) + var(--surface-h));
  /* Hueco reservado a la derecha: la etiqueta «Meta» y la mitad del corredor
     necesitan sitio cuando alguien alcanza el 100 %. */
  --gutter: 38px;
}
.track-inner { position: absolute; inset: 0 var(--gutter) 0 var(--gutter-left, 0px); }
/* El pelotón de un equipo va centrado en su posición: al principio necesita
   medio ancho a la izquierda o se corta contra el borde de la calle. */
.race--teams .track { --gutter-left: 52px; }

/* En una pantalla ancha la pista es larga: con unos píxeles más de alto el
   corredor y los rótulos de distancia dejan de ir apretados. Todo lo que cuelga
   de la pista (marcas, salida, meta, corredor) se coloca a partir de estas
   variables, así que subirlas aquí no descoloca nada. */
@media (min-width: 1024px) {
  .track { height: 72px; --surface-h: 12px; }
  .tick-label,
  .start-label,
  .finish-label { font-size: var(--text-xs); }
}

.track-surface,
.track-fill,
.track-extra {
  position: absolute;
  bottom: var(--surface-bottom);
  height: var(--surface-h);
}
.track-surface {
  left: 0;
  right: 0;
  border-radius: 5px;
  background-color: color-mix(in srgb, var(--lane) 12%, var(--panel-2));
  background-image: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--text) 7%, transparent) 0 1px,
    transparent 1px 16px
  );
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent);
}
.track-fill {
  left: 0;
  border-radius: 5px 0 0 5px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--lane) 50%, transparent), var(--lane));
  transition: width .9s cubic-bezier(.22, .61, .36, 1);
}
/* El tramo que queda por encima de la meta: la pista se estira y ese trozo se
   marca en dorado. */
.track-extra {
  right: 0;
  border-radius: 0 5px 5px 0;
  background: repeating-linear-gradient(
    115deg,
    color-mix(in srgb, var(--gold) 42%, transparent) 0 5px,
    transparent 5px 10px
  );
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gold) 45%, transparent);
}
.tick {
  position: absolute;
  bottom: var(--surface-top);
  height: 7px;
  width: 1px;
  background: color-mix(in srgb, var(--text) 24%, transparent);
}
.tick-label {
  position: absolute;
  bottom: calc(-1 * var(--surface-top) + 1px);
  left: 0;
  transform: translateX(-50%);
  font-size: .58rem;
  line-height: 1;
  color: var(--muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.start {
  position: absolute;
  bottom: var(--surface-bottom);
  height: calc(var(--surface-h) + 13px);
  width: 2px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--text) 40%, transparent);
}
.start-label {
  position: absolute;
  bottom: calc(-1 * var(--surface-top) + 1px);
  left: 3px;
  font-size: .58rem;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  white-space: nowrap;
}
.finish {
  position: absolute;
  bottom: var(--surface-bottom);
  height: calc(var(--surface-h) + 26px);
  width: 7px;
}
/* Bandera de cuadros: dos gradientes repetidos cruzados bastan y no hace falta
   ninguna imagen. */
.finish-banner {
  position: absolute;
  inset: 0;
  background-color: var(--panel);
  background-image:
    repeating-conic-gradient(
      color-mix(in srgb, var(--text) 88%, transparent) 0% 25%,
      transparent 0% 50%
    );
  background-size: 7px 7px;
  border-radius: 2px;
}
.finish-label {
  position: absolute;
  bottom: calc(-1 * var(--surface-top) + 1px);
  left: 50%;
  transform: translateX(-50%);
  font-size: .6rem;
  line-height: 1;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.runner-slot {
  position: absolute;
  /* Las suelas quedan a 5,5 de las 64 unidades del dibujo por encima del borde
     de la caja, asi que se sube el corredor ese trozo para que pise la pista. */
  bottom: calc(var(--surface-top) - 2.7px);
  transition: transform .9s cubic-bezier(.22, .61, .36, 1);
  will-change: transform;
}
.runner-chip,
.runner-pack {
  display: flex;
  align-items: flex-end;
  transform: translateX(-50%);
}
.runner-pack--lane { position: relative; }

.pack-item { display: block; margin-left: -14px; }
.pack-item:first-child { margin-left: 0; }
.pack-more {
  align-self: center;
  margin-left: -6px;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0 .3rem;
}

/* La corona la lleva quien va primero y viaja con su corredor: se coloca sobre
   el hueco que el dibujo deja encima de la cabeza. */
.crown {
  position: absolute;
  bottom: calc(100% - 3px);
  left: 50%;
  width: 10px;
  height: 7px;
  transform: translateX(-50%);
  background: var(--gold);
  clip-path: polygon(0% 100%, 0% 22%, 24% 58%, 50% 0%, 76% 58%, 100% 22%, 100% 100%);
  filter: drop-shadow(0 1px 1px color-mix(in srgb, #000 45%, transparent));
}

/* The runner: legs and arms swing around their joints. The pivot of each group
   travels inline in the markup, because the hip and the knee move with the
   chosen build. */
.runner { color: var(--runner-shadow); display: block; }
.runner-shadow { opacity: .42; }
.runner-leg-front,
.runner-leg-back,
.runner-shank-front,
.runner-shank-back,
.runner-arm-front,
.runner-arm-back { transform-box: view-box; }

@media (prefers-reduced-motion: no-preference) {
  .runner-leg-front { animation: stride-forward .72s ease-in-out infinite alternate; }
  .runner-leg-back { animation: stride-back .72s ease-in-out infinite alternate; }
  .runner-shank-front { animation: knee-forward .72s ease-in-out infinite alternate; }
  .runner-shank-back { animation: knee-back .72s ease-in-out infinite alternate; }
  .runner-arm-front { animation: swing .72s ease-in-out infinite alternate; }
  .runner-arm-back { animation: swing .72s ease-in-out infinite alternate-reverse; }
  .preview-runner .runner-leg-front,
  .preview-runner .runner-leg-back,
  .preview-runner .runner-shank-front,
  .preview-runner .runner-shank-back,
  .preview-runner .runner-arm-front,
  .preview-runner .runner-arm-back { animation-duration: .95s; }
}

@keyframes stride-forward {
  from { transform: rotate(-16deg); }
  to { transform: rotate(6deg); }
}
@keyframes stride-back {
  from { transform: rotate(6deg); }
  to { transform: rotate(-16deg); }
}
@keyframes knee-forward {
  from { transform: rotate(-7deg); }
  to { transform: rotate(9deg); }
}
@keyframes knee-back {
  from { transform: rotate(9deg); }
  to { transform: rotate(-7deg); }
}
@keyframes swing {
  from { transform: rotate(10deg); }
  to { transform: rotate(-10deg); }
}

@media (prefers-reduced-motion: reduce) {
  .runner-leg-front,
  .runner-leg-back,
  .runner-shank-front,
  .runner-shank-back,
  .runner-arm-front,
  .runner-arm-back { animation: none; }
  .runner-slot { transition: none; }
  .track-fill { transition: none; }
  .bar > span { transition: none; }
}

/* Avatar editor ---------------------------------------------------------- */

.avatar-form { display: grid; gap: var(--grid-gap); }

.editor-section { display: grid; gap: var(--space-2); }
.editor-section > h3 { margin: 0; }

/* El lienzo manda y ocupa todo lo ancho; las secciones de opciones se reparten
   en dos columnas cuando hay sitio para ambas. */
@media (min-width: 900px) {
  .avatar-form { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .avatar-form > .preview-stage,
  .avatar-form > .editor-actions { grid-column: 1 / -1; }
}

.group {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  padding: var(--space-2) var(--space-3) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.group > legend,
.group-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  font-weight: 600;
  padding: 0 .3rem;
}

/* El lienzo: el corredor grande sobre un trozo de pista, para juzgarlo como se
   verá en la clasificación. La pista es CSS puro; el único <svg> del parcial
   tiene que seguir siendo el corredor. */
.preview-stage {
  display: grid;
  place-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-3) var(--space-2);
  border-radius: var(--radius);
  background:
    radial-gradient(120% 70% at 50% 100%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 70%),
    var(--panel-2);
  border: 1px solid var(--border);
}
.preview-scene {
  position: relative;
  display: grid;
  justify-items: center;
  align-items: end;
  width: 100%;
  min-width: 0;
  /* El lienzo no se estira con la tarjeta: una pista de 1300 px para un solo
     corredor deja de leerse como una pista. */
  max-width: 40rem;
}
.preview-runner {
  grid-area: 1 / 1;
  align-self: end;
  /* Las suelas van 5,5 de 64 unidades por encima del borde de la caja. */
  margin-bottom: 14px;
  z-index: 1;
}
.preview-track {
  grid-area: 1 / 1;
  align-self: end;
  position: relative;
  display: block;
  width: 100%;
  height: 56px;
}
.preview-surface {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 16px;
  height: 12px;
  border-radius: 6px;
  background-color: color-mix(in srgb, var(--c-shirt, var(--accent)) 16%, var(--panel));
  background-image: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--text) 7%, transparent) 0 1px,
    transparent 1px 18px
  );
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent);
}
.preview-gate {
  position: absolute;
  bottom: 16px;
  width: 4px;
  height: 30px;
  border-radius: 0 0 2px 2px;
  background: color-mix(in srgb, var(--text) 18%, transparent);
}
.preview-gate--start { left: 0; }
.preview-gate--a { left: 33%; }
.preview-gate--b { left: 66%; }
.preview-gate--finish {
  left: auto;
  right: 0;
  width: 7px;
  height: 40px;
  background-color: var(--panel);
  background-image: repeating-conic-gradient(
    color-mix(in srgb, var(--text) 88%, transparent) 0% 25%,
    transparent 0% 50%
  );
  background-size: 7px 7px;
  border-radius: 2px;
}
.preview-stage p { margin: 0; }

.swatches { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.swatch { display: inline-flex; cursor: pointer; }
.swatch input,
.opt input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* 44 px de alto con el pulgar: el punto de color va dentro de un área que se
   puede tocar sin apuntar. */
.swatch-dot {
  display: block;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--sw);
  border: 2px solid color-mix(in srgb, var(--text) 15%, transparent);
  box-shadow: var(--shadow-soft);
  transition: transform .12s ease, border-color .12s ease;
}
.swatch:hover .swatch-dot { transform: scale(1.06); }
.swatch input:checked + .swatch-dot {
  border-color: var(--text);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent);
}
.swatch input:focus-visible + .swatch-dot,
.opt input:focus-visible + span {
  outline: 2px solid var(--accent-2);
  outline-offset: 3px;
}

.options { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.opt { cursor: pointer; }
.opt > span {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: .4rem .7rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--muted);
  font-size: var(--text-sm);
}
.opt:hover > span { color: var(--text); }
.opt input:checked + span {
  background: color-mix(in srgb, var(--accent) 18%, var(--panel-2));
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  color: var(--text);
  font-weight: 600;
}

.editor-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-1);
}
.editor-actions button { min-height: 40px; }
.avatar-flash {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
}
.avatar-flash:empty { display: none; }
.avatar-flash:not(:empty) {
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--panel));
  border-radius: var(--radius-pill);
  padding: .25rem .7rem;
}

.me-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

/* El panel personal. De 720 px para arriba el anillo y las cifras van uno al
   lado del otro en vez de sumar otra pila de bloques; el grupo de cifras tiene
   un mínimo, así que si la columna se queda estrecha —que es lo que pasa cuando
   el panel comparte fila con otra tarjeta— baja entero debajo del anillo en vez
   de partir los números en dos renglones. */
.me-stats { display: grid; gap: var(--space-2); align-content: center; margin-top: var(--space-3); }
.me-stats .stats + .stats { margin-top: 0; }

@media (min-width: 720px) {
  #me-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-4);
  }
  #me-panel > .me-head { flex: 0 0 100%; }
  #me-panel > .ring-wrap { flex: 0 0 auto; }
  #me-panel > .me-stats { flex: 1 1 14rem; margin-top: 0; }
  #me-panel > .me-flash { flex: 0 0 100%; margin: var(--space-2) 0 0; }
}

/* De 1200 px para arriba el panel siempre comparte fila con otra tarjeta y se
   queda con media pantalla: el anillo pasa a su propia línea, centrado, y las
   seis cifras se quedan todo el ancho. Con menos sitio los números de tres
   cifras y pico se partirían en dos renglones. */
@media (min-width: 1200px) {
  .me-top > #me-panel > .ring-wrap,
  .avatar-layout > #me-panel > .ring-wrap { flex: 0 0 100%; }
  .me-top > #me-panel > .me-stats,
  .avatar-layout > #me-panel > .me-stats { flex: 1 1 100%; }
}

/* Forms ------------------------------------------------------------------ */

.form-grid { display: grid; gap: var(--space-2); grid-template-columns: 1fr 1fr; max-width: 46rem; }
.form-grid .full { grid-column: 1 / -1; }

/* Renombrado en bloque: el identificador a la izquierda y el nombre editable a
   la derecha, para ver de un vistazo a quién se está renombrando. */
.rename-list { display: grid; gap: var(--space-1); margin-bottom: var(--space-2); max-width: 46rem; }
.rename-row {
  display: grid;
  grid-template-columns: minmax(6rem, 10rem) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2);
}
.rename-row input { width: 100%; }
@media (max-width: 560px) {
  .rename-row { grid-template-columns: minmax(0, 1fr); gap: 0; }
}

input, select, textarea, button {
  font: inherit;
  color: var(--text);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: .55rem .65rem;
  width: 100%;
}

button, .button {
  cursor: pointer;
  background: var(--accent);
  color: #06130a;
  border: 1px solid transparent;
  font-weight: 600;
  padding: .55rem .9rem;
  border-radius: var(--radius-sm);
  width: auto;
  transition: filter .12s ease, transform .12s ease;
}
button:hover, .button:hover { filter: brightness(1.06); text-decoration: none; }
button:active, .button:active { transform: translateY(1px); }

button.ghost, .button.ghost { background: var(--panel-2); color: var(--text); border: 1px solid var(--border); }
button.link { background: none; border: 0; color: var(--accent-2); padding: .1rem .2rem; font-weight: 500; }
button.danger { background: var(--danger); color: #2a0505; }
button.small, .button.small { padding: .3rem .6rem; font-size: var(--text-sm); }

.reactions { display: flex; gap: var(--space-1); flex-wrap: wrap; margin-top: var(--space-2); }
.reactions form { margin: 0; }
.reactions button {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: .25rem .5rem;
  border-radius: var(--radius-pill);
  font-size: var(--text-md);
  display: flex;
  gap: .25rem;
  align-items: center;
}
.reactions button.mine {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 18%, var(--panel-2));
}

.post { padding: var(--space-3); }
.post .body { white-space: pre-wrap; word-wrap: break-word; }
.post.system { border-left: 3px solid var(--gold); }
/* Las llegadas de la Compañía son las del grupo entero: en el muro llevan el
   mismo filo dorado que los avisos del sistema, pero con el nombre del grupo. */
.post.group { border-left: 3px solid var(--gold); background: color-mix(in srgb, var(--gold) 7%, var(--panel)); }

.ring-wrap { display: grid; place-items: center; padding: var(--space-1) 0; }
.ring { transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 9; stroke-linecap: round; }
.ring .track { stroke: var(--panel-2); }
.ring .value { stroke: var(--accent); transition: stroke-dashoffset .4s ease; }
.ring-label { text-align: center; margin-top: -.6rem; }
.ring-label strong { font-size: clamp(1.6rem, 1.4rem + .8vw, 2.2rem); display: block; font-variant-numeric: tabular-nums; }

.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); text-align: center; }
.stats div { background: var(--panel-2); border-radius: 12px; padding: var(--space-2) var(--space-1); min-width: 0; }
.stats strong {
  display: block;
  font-size: clamp(1.18rem, 1.02rem + .6vw, 1.6rem);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.stats span { font-size: var(--text-xs); color: var(--muted); }
.stats + .stats { margin-top: var(--space-2); }

details { margin-top: var(--space-2); }
details > summary { cursor: pointer; color: var(--muted); font-size: var(--text-md); }
details[open] > summary { margin-bottom: var(--space-2); }

table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
th, td { text-align: left; padding: .35rem .3rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th { color: var(--muted); font-weight: 600; }
/* En un movil una tabla de siete columnas ensancharia toda la pagina. Que se
   desplace ella sola dentro de la tarjeta en vez de arrastrar el diseño. */
@media (max-width: 560px) {
  .card table { display: block; overflow-x: auto; white-space: nowrap; }
}
.ok { color: var(--accent); }
.warn { color: var(--gold); }
.err { color: var(--danger); }

.toast {
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--panel));
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
}
dt { color: var(--muted); font-size: var(--text-sm); }
ol, ul { padding-left: 1.1rem; }
code { background: var(--panel-2); padding: .1rem .3rem; border-radius: 6px; font-size: .85em; }
pre { background: var(--panel-2); padding: var(--space-2); border-radius: var(--radius-sm); overflow-x: auto; font-size: var(--text-xs); }
.instructions li { margin-bottom: .3rem; }

.tag {
  font-size: var(--text-xs);
  padding: .1rem .45rem;
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  color: var(--muted);
  white-space: nowrap;
  flex: none;
}

/* La ruta (app/routes.py) ------------------------------------------------- */

/* El lienzo: el SVG lleva el terreno y el camino; los rótulos y los marcadores
   van en HTML encima, para que el texto no encoja con el viewBox. De ahí que el
   contenedor mantenga la proporción 1000×700 y las capas se ajusten a él. */
.rt-card { padding-bottom: var(--space-2); }
.rt-head { margin-bottom: var(--space-2); }
.rt-title { display: block; font-weight: 700; }
.rt-sub { display: block; }

.rt-wrap {
  position: relative;
  width: calc(100% + 2 * var(--space-3));
  /* El mapa sangra hasta el borde de la tarjeta: en un móvil cada píxel de
     ancho es un kilómetro más de camino que se ve. */
  margin: 0 calc(-1 * var(--space-3));
  aspect-ratio: 1000 / 700;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
  overflow: hidden;
}
.rt-map { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.rt-sky { fill: url(#rt-sky); }

/* El paisaje de fondo. Cada escena (app/templates/_scene_*.html) dibuja sus
   manchas con estas clases, y el color sale siempre de las variables de la
   paleta mezcladas con transparente: así el mapa entero se apaga o se aclara
   con el tema, sin quedar turbio ni deslumbrar al cambiar de esquema. */
.rt-hill { stroke: none; }
.rt-hill--far { fill: color-mix(in srgb, var(--accent) 8%, transparent); }
.rt-hill--mid { fill: color-mix(in srgb, var(--accent-2) 9%, transparent); }
.rt-hill--near { fill: color-mix(in srgb, var(--text) 6%, transparent); }

.rt-sea { fill: color-mix(in srgb, var(--accent-2) 13%, transparent); }
.rt-coast {
  fill: none;
  stroke: color-mix(in srgb, var(--accent-2) 40%, transparent);
  stroke-width: 2.4;
}
.rt-inland-sea {
  fill: color-mix(in srgb, var(--accent-2) 10%, transparent);
  stroke: color-mix(in srgb, var(--accent-2) 26%, transparent);
  stroke-width: 2;
}
.rt-river { fill: color-mix(in srgb, var(--accent-2) 20%, transparent); }
.rt-mordor { fill: color-mix(in srgb, var(--text) 7%, transparent); stroke: none; }
.rt-gorgoroth { fill: color-mix(in srgb, var(--text) 5%, transparent); stroke: none; }
.rt-forest {
  fill: color-mix(in srgb, var(--accent) 14%, transparent);
  stroke: color-mix(in srgb, var(--accent) 26%, transparent);
  stroke-width: 1.2;
}
/* El pico se repite a lo largo de la espina de cada sierra: el relleno le da
   cuerpo y el trazo lo hace legible cuando el lienzo entero cabe en un móvil. */
.rt-peak { stroke-width: 1.5; stroke-linejoin: round; }
.rt-peak--misty {
  fill: color-mix(in srgb, var(--text) 10%, transparent);
  stroke: color-mix(in srgb, var(--text) 34%, transparent);
}
.rt-peak--wall {
  fill: color-mix(in srgb, var(--text) 8%, transparent);
  stroke: color-mix(in srgb, var(--text) 26%, transparent);
}
.rt-hummocks {
  fill: color-mix(in srgb, var(--text) 9%, transparent);
  stroke: color-mix(in srgb, var(--text) 24%, transparent);
  stroke-width: 1;
}
.rt-marsh {
  fill: color-mix(in srgb, var(--accent-2) 12%, transparent);
  stroke: color-mix(in srgb, var(--accent-2) 32%, transparent);
  stroke-width: 2.2;
  stroke-linecap: round;
}
.rt-volcano-cone {
  fill: color-mix(in srgb, var(--text) 22%, transparent);
  stroke: color-mix(in srgb, var(--text) 46%, transparent);
  stroke-width: 1.4;
  stroke-linejoin: round;
}
.rt-volcano-plume {
  fill: none;
  stroke: color-mix(in srgb, var(--muted) 55%, transparent);
  stroke-width: 2.2;
  stroke-linecap: round;
}

/* La ruta que queda por recorrer. Sobre el paisaje de la Tierra Media —mar,
   ríos, bosques y sierras— una línea de puntos al 34 % se perdía, así que va
   más marcada y con los puntos más juntos: es lo que se mira para saber cuánto
   falta. */
.rt-path {
  fill: none;
  stroke: color-mix(in srgb, var(--text) 52%, transparent);
  stroke-width: 10;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 3 11;
}
.rt-path-done {
  fill: none;
  stroke: var(--accent);
  stroke-width: 11;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .5;
}
.rt-node { fill: var(--panel); stroke: color-mix(in srgb, var(--text) 55%, transparent); stroke-width: 5; }
.rt-node--start { fill: var(--panel-2); stroke: color-mix(in srgb, var(--text) 70%, transparent); }
.rt-node--finish { fill: var(--gold); stroke: var(--panel); stroke-width: 6; }

.rt-layer { position: absolute; inset: 0; }

/* Topónimos del paisaje. Van sin caja, en cursiva y apagados: nombran el fondo
   sin competir con los nombres de etapa, que son lo que se lee primero. El
   halo del texto los mantiene legibles encima de una sierra o de un bosque. */
.rt-place {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: .6rem;
  font-style: italic;
  letter-spacing: .02em;
  color: var(--muted);
  opacity: .8;
  white-space: nowrap;
  pointer-events: none;
  text-shadow: 0 0 4px var(--panel), 0 0 3px var(--panel);
}

/* Rótulos de etapa. Dos juegos: en el móvil solo caben cuatro nombres, así que
   el juego corto sale siempre y el largo entra a partir de 620 px. */
.rt-wp {
  position: absolute;
  display: none;
  flex-direction: column;
  align-items: center;
  max-width: 60%;
  transform: translate(-50%, 9px);
  pointer-events: none;
  text-align: center;
  line-height: 1.15;
  /* Por encima de los marcadores: quien llega a una etapa se planta justo
     encima de su rotulo, y taparlo dejaba «Santiago de Compostela» ilegible. */
  z-index: 3;
}
.rt-wp--phone { display: flex; }
.rt-wp--left { align-items: flex-start; transform: translate(-3px, 9px); text-align: left; }
.rt-wp--right { align-items: flex-end; transform: translate(calc(-100% + 3px), 9px); text-align: right; }
.rt-wp--up { transform: translate(-50%, calc(-100% - 9px)); }
.rt-wp--up.rt-wp--left { transform: translate(-3px, calc(-100% - 9px)); }
.rt-wp--up.rt-wp--right { transform: translate(calc(-100% + 3px), calc(-100% - 9px)); }
.rt-wp-name {
  font-size: .58rem;
  font-weight: 600;
  color: var(--text);
  /* Translucida y desenfocada: se lee el nombre y aun se intuye el corredor
     que queda debajo. */
  background: color-mix(in srgb, var(--panel) 76%, transparent);
  backdrop-filter: blur(3px);
  border-radius: 5px;
  padding: 0 .22rem;
}
.rt-wp-km { font-size: .55rem; color: var(--muted); font-variant-numeric: tabular-nums; }

@media (min-width: 620px) {
  .rt-wp--phone { display: none; }
  .rt-wp--wide { display: flex; }
  .rt-wp-name { font-size: var(--text-xs); }
  .rt-wp-km { font-size: .62rem; }
  .rt-place { font-size: var(--text-xs); }
}

/* Marcadores. El tamaño es un porcentaje del lienzo: así guardan la proporción
   con el mapa en móvil y en escritorio, y el reparto de app/routes.py
   (fan_out) vale para los dos. */
.rt-marker {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  width: 4.4%;
  min-width: 15px;
}
.rt-marker--team { width: 5.2%; }
/* El estandarte de la Compañía: más grande que nadie, dorado y por encima de
   los rótulos de etapa (z-index), porque en una ruta larga los marcadores de
   las personas se quedan todos en la salida y quien viaja es el grupo. */
.rt-marker--group { width: 7.4%; z-index: 4; }
.rt-banner {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in srgb, var(--gold) 28%, var(--panel));
  box-shadow: 0 0 0 3px var(--gold), 0 0 0 6px color-mix(in srgb, var(--gold) 24%, transparent);
}
.rt-banner svg { width: 82%; height: auto; display: block; }
.rt-banner-pole { stroke: color-mix(in srgb, var(--text) 74%, transparent); stroke-width: 2.6; stroke-linecap: round; fill: none; }
.rt-banner-pennant { fill: var(--gold); }
.rt-banner--mini {
  width: 16px;
  box-shadow: 0 0 0 2px var(--gold);
}
.rt-banner--mini svg { width: 76%; }
.rt-dot {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in srgb, var(--team, var(--accent)) 22%, var(--panel));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--team, var(--accent)) 85%, transparent);
}
/* El corredor va algo encogido dentro del aro: a tamaño completo se le cortarían
   los brazos y la sombra contra el borde del círculo. */
.rt-dot--runner .runner { width: 88%; height: auto; }
.rt-dot--team { background: color-mix(in srgb, var(--team, var(--accent)) 85%, var(--panel)); }
/* Dos puntos dentro del aro: el marcador de equipo es un grupo, no una persona. */
.rt-dot-dots {
  display: block;
  width: 66%;
  height: 66%;
  background-image: radial-gradient(circle, var(--panel) 46%, transparent 48%),
    radial-gradient(circle, var(--panel) 46%, transparent 48%);
  background-size: 40% 40%, 40% 40%;
  background-position: 18% 50%, 82% 50%;
  background-repeat: no-repeat;
}
.rt-marker--me .rt-dot { box-shadow: 0 0 0 3px var(--accent), 0 0 0 6px color-mix(in srgb, var(--accent) 28%, transparent); }
/* La etiqueta de cada marcador sale en uno de cuatro sitios (arriba o abajo,
   a la izquierda o a la derecha, rotando): dos corredores pegados no escriben el
   nombre uno encima del otro aunque el hueco sea pequeño. */
.rt-marker--p0 .rt-tag { order: 1; align-self: flex-start; }
.rt-marker--p1 .rt-tag { order: 1; align-self: flex-end; }
.rt-marker--p2 .rt-tag { order: -1; align-self: flex-start; }
.rt-marker--p3 .rt-tag { order: -1; align-self: flex-end; }

.rt-tag {
  font-size: .5rem;
  line-height: 1.1;
  max-width: 190%;
  color: var(--text);
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  border-radius: 5px;
  padding: 0 .18rem;
  white-space: nowrap;
}
.rt-tag-short { display: inline; font-weight: 600; }
.rt-tag-full { display: none; }
.rt-tag--me { background: var(--accent); color: #06130a; font-weight: 700; }
.rt-tag-me { font-weight: 700; }
.rt-marker--team .rt-tag { border: 1px solid color-mix(in srgb, var(--team) 60%, transparent); }
/* Sin sitio para el nombre, se calla y sale al pasar por encima. El tuyo no:
   encontrarte de un vistazo es lo primero que se hace en este mapa. */
.rt-marker--crowded .rt-tag { opacity: 0; transition: opacity .15s ease; }
.rt-marker--crowded:hover .rt-tag,
.rt-marker--crowded:focus-within .rt-tag { opacity: 1; }
.rt-marker--crowded.rt-marker--me .rt-tag { opacity: 1; }
.rt-marker--group .rt-tag {
  font-weight: 700;
  background: color-mix(in srgb, var(--gold) 22%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--gold) 60%, transparent);
}

@media (min-width: 620px) {
  .rt-tag { font-size: var(--text-xs); max-width: 200%; }
  .rt-tag-short { display: none; }
  .rt-tag-full { display: inline; }
}

.rt-note { margin: var(--space-2) 0 0; }
.rt-empty { margin: var(--space-3) 0 0; }
.rt-me-line {
  margin: var(--space-3) 0 0;
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}

/* La etapa de la Compañía, por encima de las cifras: en una ruta larga es el
   único dato que se mueve, así que va destacado y no como una estadística más. */
.rt-compass {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid color-mix(in srgb, var(--gold) 38%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--gold) 12%, var(--panel-2));
}
.rt-compass-flag {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.1rem;
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in srgb, var(--gold) 28%, var(--panel));
  box-shadow: 0 0 0 2px var(--gold);
}
.rt-compass-flag svg { width: 74%; height: auto; display: block; }
.rt-compass-title { display: block; font-weight: 700; }
.rt-compass-line { margin: .25rem 0 0; }

.rt-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--muted);
}
.rt-legend-item { display: inline-flex; align-items: center; gap: .3rem; }
.rt-dot--mini { width: 14px; box-shadow: none; font-size: 0; }
.rt-legend-line {
  display: inline-block;
  width: 18px;
  height: 5px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--accent) 55%, transparent);
}

/* Etapas */
.rt-stages { list-style: none; padding: 0; margin: 0; }
.rt-stage {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}
.rt-stage:last-child { border-bottom: 0; }
.rt-stage-km {
  flex: 0 0 4.2rem;
  font-size: var(--text-xs);
  color: var(--muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
  padding-top: .1rem;
}
.rt-stage-name { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
.rt-stage-people { display: block; }
.rt-stage--passed .rt-stage-km { color: var(--accent); }
.rt-stage-tick { color: var(--accent); font-weight: 700; }
.rt-stage-group { display: block; color: var(--gold); }

@media (max-width: 430px) {
  .rt-stage-km { flex-basis: 3.4rem; }
}

/* Charts (inline SVG, see app/charts.py) --------------------------------- */

/* El SVG guarda la proporción del lienzo 640×260 con el que se calcula, así que
   en una tarjeta ancha se escala entero: rótulos y trazos crecen con él. El tope
   de alto evita que en una pantalla enorme el gráfico acabe siendo un mural;
   `preserveAspectRatio` se encarga de centrarlo en lo que quede. */
.chart {
  width: 100%;
  height: auto;
  max-height: min(60vh, 44rem);
  display: block;
}
.chart text {
  font-size: 11px;
  fill: var(--muted);
  font-family: inherit;
}
.chart-grid line { stroke: var(--border); stroke-width: 1; }
.chart-goal { stroke: var(--accent-2); stroke-width: 1.5; stroke-dasharray: 5 4; opacity: .8; }
.chart-goal-label { fill: var(--accent-2); font-size: 10px; }
.chart-line {
  fill: none;
  stroke: var(--line, var(--accent));
  stroke-width: 2.2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart-legend {
  list-style: none;
  padding: 0;
  margin: var(--space-3) 0 0;
  display: grid;
  gap: .3rem;
  font-size: var(--text-sm);
}
.chart-legend li { display: flex; align-items: center; gap: var(--space-2); max-width: none; }
/* De 640 px para arriba la leyenda se reparte en tantas columnas como quepan:
   una lista de diez nombres deja de ser una tira larga. */
@media (min-width: 640px) {
  .chart-legend { grid-template-columns: repeat(auto-fill, minmax(14.5rem, 1fr)); column-gap: var(--space-4); }
}

/* Challenges ------------------------------------------------------------- */

/* Una tarjeta por reto, en rejilla: en el móvil sigue siendo una sola columna
   (minmax con `min()` nunca pide más de lo que hay) y en pantalla ancha entran
   las que quepan. Todas las de una fila se estiran a la misma altura y el botón
   de marcar queda abajo, alineado con los de al lado. */
#retos,
#reto-hoy {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
  margin-bottom: var(--grid-gap);
}
#retos > *,
#reto-hoy > * { margin-bottom: 0; }
#retos > .reto,
#reto-hoy > .reto { display: flex; flex-direction: column; }
#retos > .reto > form,
#reto-hoy > .reto > form { margin-top: auto; padding-top: var(--space-2); }
#retos > h2,
#retos > .card.empty,
#reto-hoy > .card.empty { grid-column: 1 / -1; }

.reto-people {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
  align-items: flex-start;
}
.reto-person {
  display: grid;
  justify-items: center;
  gap: .1rem;
  max-width: 5.2rem;
}
.reto-person .runner { border-radius: 10px; }
.reto-done { border-left: 3px solid var(--accent); }

/* Report ----------------------------------------------------------------- */

.podium {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
  text-align: center;
}
.podium-place {
  display: grid;
  justify-items: center;
  gap: .15rem;
  padding: var(--space-2) var(--space-1);
  background: var(--panel-2);
  border-radius: var(--radius-sm);
  min-width: 0;
}
/* Names are not truncated in a podium: they wrap, however long they are. */
.podium-place strong {
  max-width: 100%;
  text-align: center;
  overflow-wrap: anywhere;
}
.podium-medal { font-size: var(--text-lg); }
.award {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}
.award:last-of-type { border-bottom: 0; }

/* Offline notice (app.js) ------------------------------------------------ */

.net-notice {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  max-width: min(90vw, 30rem);
  padding: .5rem .8rem;
  border-radius: var(--radius-pill);
  background: var(--panel);
  border: 1px solid var(--gold);
  color: var(--text);
  box-shadow: var(--shadow);
  font-size: var(--text-sm);
  text-align: center;
}
.net-notice[hidden] { display: none; }

@media (max-width: 430px) {
  .brand-name { display: none; }
  .segmented .seg { font-size: var(--text-sm); }
}

/* Páginas a lo ancho ------------------------------------------------------
   Cada bloque de aquí es el reparto de una página concreta a partir de 1024 px
   (algunos a partir de 1100 o 1200, cuando el contenido ya cabe en columnas).
   En el móvil no se aplica nada: las páginas son las mismas, en una columna y
   en el orden del documento. */

/* Mi página: el panel y el gráfico comparten la primera fila; debajo, el editor
   de avatar a todo lo ancho y las tres herramientas del día en fila. La primera
   fila se parte tarde a propósito: el panel lleva el anillo y seis cifras, y en
   media pantalla no le caben. */
.me-top { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
@media (min-width: 1200px) {
  .me-top { grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr); }
}
.me-tools { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
.me-tools > .card { margin-bottom: 0; }
@media (min-width: 1024px) {
  .me-tools { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* La ruta: el mapa se queda con la columna ancha y crece con ella; las etapas
   van al lado, a toda la altura, y el resumen del grupo se pone bajo el mapa
   para que las dos columnas acaben más o menos a la misma altura. */
.rt-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
@media (min-width: 1024px) {
  .rt-layout { grid-template-columns: minmax(0, 2.1fr) minmax(0, 1fr); }
  .rt-layout > .rt-main { grid-column: 1; }
  .rt-layout > .rt-stages-card { grid-column: 2; }
}

/* Mi avatar: el panel personal en una columna estrecha y el editor —que es lo
   que se viene a hacer aquí— con el resto. */
.avatar-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
@media (min-width: 1200px) {
  .avatar-layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr); }
}

/* El muro: una columna de mensajes, centrada y con ancho de lectura. */
.feed-page { max-width: min(100%, 52rem); margin-inline: auto; }
.feed-page > #feed > .post:last-child { margin-bottom: 0; }

/* El informe: podio, premios y equipos en una fila; la tabla de participantes,
   que es la más ancha, debajo y de lado a lado. Cada tarjeta con su altura:
   estiradas, las cortas quedarían con un marco y un hueco dentro. */
.report-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); align-items: start; }
.report-grid > * { margin-bottom: 0; }
@media (min-width: 1200px) {
  .report-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .rp-podium { grid-area: 1 / 1; }
  .rp-awards { grid-area: 1 / 2; }
  .rp-teams { grid-area: 1 / 3; }
  .rp-people { grid-area: 2 / 1 / 3 / -1; }
}

/* La administración: dos columnas de tarjetas a partir de 1100 px. Las rápidas
   van de lado a lado; el resto se empareja por alturas y las tablas se quedan en
   media pantalla, que les llega. */
.admin-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap); }
.admin-grid > * { margin-bottom: 0; }
@media (min-width: 1100px) {
  .admin-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .admin-quick { grid-column: 1 / -1; }
}
