/*
 * Mov — hoja de estilos única.
 * ---------------------------------------------------------------------------
 * Sin framework, a propósito. El producto tiene una paleta corta de componentes
 * y cargar 40 kB de CSS de terceros para usar el 5 % penaliza justo donde más
 * duele: la app de la cuadrilla se abre en un teléfono viejo, con la pantalla al
 * sol y una barra de cobertura.
 *
 * Tampoco hay tipografías web. Traerlas de un CDN obliga a la instalación de la
 * oficina a salir a internet para dibujar una pantalla, y la red de una empresa
 * de mudanzas no siempre está. La jerarquía la hacen el peso, el tamaño y el
 * interletrado, no una familia descargada.
 *
 * Reglas que no se negocian:
 * - contraste mínimo 4,5:1 en todo texto (hay una prueba que lo mide);
 * - el estado nunca se comunica solo con color: siempre hay texto o forma;
 * - objetivos táctiles de 44 px en cualquier control que use la cuadrilla;
 * - todo color sale de una variable: no hay un solo valor hexadecimal suelto
 *   fuera del bloque de tokens, para que el modo oscuro no tenga agujeros.
 */

/* ===========================================================================
   1 · Tokens
   ===========================================================================
   La paleta es de papel: un fondo cálido en vez de blanco puro, superficies
   blancas encima y un verde profundo como único color de marca. Es una pantalla
   que alguien mira ocho horas seguidas — el azul saturado de los paneles de
   control cansa, y el gris puro sobre blanco puro deja la vista sin descanso.
   El color se reserva para lo que significa algo: verde correcto, ámbar
   atención, rojo dinero en riesgo. Si en una pantalla no hay nada mal, no hay
   nada de color. */

:root {
  color-scheme: light;

  --ground:      #f1f0eb;
  --surface:     #ffffff;
  --surface-2:   #e9e8e1;
  --surface-3:   #f7f6f2;

  --ink:         #17191a;
  --ink-2:       #4c534e;
  --ink-3:       #6b726c;

  --line:        #dcdbd3;
  --line-strong: #8d8c82;

  --accent:      #1b5e45;
  --accent-ink:  #13452f;
  --accent-soft: #dfeae4;
  /* La tinta que va ENCIMA del acento y del color del dinero.
     Existe porque en modo oscuro los dos son claros —un verde menta y un
     azul cielo— y el blanco fijo que había antes dejaba el botón primario
     en 2,2:1. Nadie lo vio en la oficina y en el patio, con sol, el botón
     de fichar desaparecía. */
  --on-accent:   #ffffff;
  --on-money:    #ffffff;
  --on-crit:     #ffffff;

  --good:        #16714f;
  --good-soft:   #ddece4;
  --warn:        #7c5200;
  --warn-soft:   #f5e9d1;
  --crit:        #9a2a20;
  --crit-soft:   #f8e2df;
  --money:       #17566f;
  --money-soft:  #dde9ef;

  /* Colores de datos: el reparto de la jornada y las barras. Se distinguen en
     escala de grises y por posición, no solo por tono. */
  --data-1: #1b5e45;
  --data-2: #2f7f9c;
  --data-3: #8a6d3b;
  --data-4: #9aa69e;

  --rail:       #1a211d;
  --rail-ink:   #c9d3cc;
  --rail-ink-2: #97a49c;
  --rail-line:  #2d3831;

  --radius:    10px;
  --radius-sm: 7px;
  --shadow: 0 1px 2px rgb(20 28 22 / 6%), 0 10px 26px -18px rgb(20 28 22 / 30%);
  --shadow-lift: 0 2px 4px rgb(20 28 22 / 8%), 0 18px 40px -22px rgb(20 28 22 / 35%);

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
          "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono",
          "Segoe UI Mono", "Roboto Mono", Menlo, Consolas, monospace;
}

/* El modo oscuro no es una cortesía: el despachador de la mañana abre esto a las
   cinco y media. Se define dos veces —por preferencia del sistema y por
   elección explícita— para que el interruptor pueda ganarle a la preferencia. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --ground:      #0f1211;
    --surface:     #181c19;
    --surface-2:   #222722;
    --surface-3:   #1d221e;

    --ink:         #e9ede8;
    --ink-2:       #a8b0a9;
    --ink-3:       #8b948c;

    --line:        #2b312c;
    --line-strong: #6f7a73;

    --accent:      #5cbe94;
    --accent-ink:  #8ed7b5;
    --accent-soft: #17281f;
    --on-accent:   #0c130f;
    --on-money:    #0c130f;
    --on-crit:     #170e0d;

    --good:        #5cbe94;
    --good-soft:   #16261e;
    --warn:        #d9a75a;
    --warn-soft:   #2a2315;
    --crit:        #e3837a;
    --crit-soft:   #2d1a18;
    --money:       #7bb8d2;
    --money-soft:  #15242b;

    --data-1: #5cbe94;
    --data-2: #6bb0cd;
    --data-3: #c5a05e;
    --data-4: #77837b;

    --rail:       #0b0e0d;
    --rail-ink:   #c7d2cb;
    --rail-ink-2: #8e9b94;
    --rail-line:  #1e2622;

    --shadow: 0 1px 2px rgb(0 0 0 / 50%), 0 10px 26px -18px rgb(0 0 0 / 90%);
    --shadow-lift: 0 2px 4px rgb(0 0 0 / 55%), 0 18px 40px -22px rgb(0 0 0 / 95%);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --ground:      #0f1211;
  --surface:     #181c19;
  --surface-2:   #222722;
  --surface-3:   #1d221e;

  --ink:         #e9ede8;
  --ink-2:       #a8b0a9;
  --ink-3:       #8b948c;

  --line:        #2b312c;
  --line-strong: #6f7a73;

  --accent:      #5cbe94;
  --accent-ink:  #8ed7b5;
  --accent-soft: #17281f;
  --on-accent:   #0c130f;
  --on-money:    #0c130f;
  --on-crit:     #170e0d;

  --good:        #5cbe94;
  --good-soft:   #16261e;
  --warn:        #d9a75a;
  --warn-soft:   #2a2315;
  --crit:        #e3837a;
  --crit-soft:   #2d1a18;
  --money:       #7bb8d2;
  --money-soft:  #15242b;

  --data-1: #5cbe94;
  --data-2: #6bb0cd;
  --data-3: #c5a05e;
  --data-4: #77837b;

  --rail:       #0b0e0d;
  --rail-ink:   #c7d2cb;
  --rail-ink-2: #8e9b94;
  --rail-line:  #1e2622;

  --shadow: 0 1px 2px rgb(0 0 0 / 50%), 0 10px 26px -18px rgb(0 0 0 / 90%);
  --shadow-lift: 0 2px 4px rgb(0 0 0 / 55%), 0 18px 40px -22px rgb(0 0 0 / 95%);
}

/* ===========================================================================
   2 · Base
   =========================================================================== */

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; }
[hidden] { display: none !important; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-ink); }

h1, h2, h3, h4 { letter-spacing: -.015em; }
h1 { font-size: 1.32rem; font-weight: 700; margin: 0; }
h2 { font-size: 1rem; font-weight: 650; margin: 0 0 .75rem; }
h3 { font-size: .92rem; font-weight: 650; margin: 0 0 .5rem; }
h4 { font-size: .82rem; font-weight: 650; margin: 0 0 .4rem; }

p { margin: 0 0 .75rem; }
p:last-child { margin-bottom: 0; }

/* El foco se ve siempre. Media pantalla de este producto se recorre con el
   tabulador porque quien aprueba horas no suelta el teclado. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.muted { color: var(--ink-2); }
.small { font-size: .82rem; }
.right { text-align: right; }

/* Toda cifra va en tipografía monoespaciada y con cifras tabulares: una columna
   de dinero que no alinea se lee mal y se suma peor. */
.num {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.is-warn   { color: var(--warn); font-weight: 600; }
.is-loss   { color: var(--crit); font-weight: 600; }
.is-raised { color: var(--money); font-weight: 600; }
.is-credit { color: var(--good); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ===========================================================================
   3 · Estructura: riel, barra superior, contenido
   =========================================================================== */

.shell {
  display: grid;
  grid-template-columns: 224px minmax(0, 1fr);
  height: 100%;
}

.rail {
  background: var(--rail);
  color: var(--rail-ink);
  /* En modo oscuro el riel y el fondo casi coinciden: sin este filo la pantalla
     parece una sola superficie y la navegación deja de leerse como tal. */
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  padding: 1rem .75rem calc(.9rem + env(safe-area-inset-bottom, 0px));
  overflow-y: auto;
}

.rail__brand { display: flex; align-items: center; gap: .55rem; padding: .1rem .4rem 0; }
.rail__mark {
  width: 28px; height: 28px; border-radius: 7px;
  background: var(--accent); color: var(--on-accent);
  display: grid; place-items: center;
  font-weight: 700; font-size: .85rem; letter-spacing: -.02em;
}
.rail__company {
  font-weight: 650; color: #fff; font-size: .93rem; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* La navegación va agrupada. Trece enlaces seguidos no son un menú, son una
   lista: agrupados por lo que la persona ha venido a hacer —el día, las
   operaciones, la gente, la flota, el dinero— se recorren de un vistazo. */
.rail__group { display: flex; flex-direction: column; gap: 2px; }
.rail__label {
  font-family: var(--mono);
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--rail-ink-2); padding: 0 .5rem .3rem;
}
.rail__nav { list-style: none; margin: 0; padding: 0; display: contents; }
.rail__group a {
  display: flex; align-items: center; gap: .55rem;
  padding: .42rem .55rem; border-radius: 6px;
  color: var(--rail-ink); text-decoration: none;
  font-size: .87rem; line-height: 1.3;
}
.rail__group a::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: .4; flex: none;
}
.rail__group a:hover { background: rgb(255 255 255 / 7%); color: #fff; }
.rail__group a.is-active {
  background: var(--accent); color: var(--on-accent); font-weight: 550;
}
.rail__group a.is-active::before { opacity: 1; }

/* El contador dice cuántas cosas esperan detrás del enlace. Solo se pinta si hay
   algo: un cero en un globo es ruido con forma de aviso. */
.rail__count {
  margin-left: auto; font-family: var(--mono); font-size: .66rem;
  background: rgb(255 255 255 / 12%); color: #fff;
  padding: .05rem .35rem; border-radius: 99px;
}
.rail__group a.is-active .rail__count { background: rgb(0 0 0 / 25%); }
.rail__count--alert { background: var(--crit); color: var(--on-crit); }

.rail__foot {
  margin-top: auto; border-top: 1px solid var(--rail-line);
  padding-top: .8rem; display: flex; flex-direction: column; gap: .45rem;
}
.rail__user { margin: 0; color: #fff; font-size: .87rem; font-weight: 550; }
.rail__role { margin: 0; font-size: .75rem; color: var(--rail-ink-2); }
.rail__tz { margin: 0; font-size: .71rem; line-height: 1.35; color: var(--rail-ink-2); }
.rail__tz strong { color: var(--rail-ink); font-weight: 600; }

/* El aviso de «sin ubicación», dentro del reloj. Va entre la cabecera y el
   botón a propósito: se lee en el camino a pulsarlo, no después. */
.clock__ubi { margin: 0 0 .8rem; font-size: .84rem; line-height: 1.45; }

/* «Buscando la ubicación» no es un aviso, es un estado normal que a veces
   tarda. Si se pintara con el amarillo del aviso, la cuadrilla aprendería en
   una semana a no mirar el amarillo — y entonces el aviso de verdad tampoco se
   leería. */
.clock__ubi--buscando {
  padding: 0; border: 0; background: none; color: var(--ink-3);
}

/* «Esta persona no registra ubicación» es un hecho, no un problema: una empresa
   puede operar así perfectamente. Se dice en gris, no en amarillo. */
.clock__sinubi {
  margin: 0 0 .8rem; font-size: .78rem; line-height: 1.45; color: var(--ink-3);
}
.clock__sinubi a { color: inherit; }

/* La versión: tiene que poder leerse, y no tiene que competir con nada. */
.rail__version {
  margin: .35rem 0 0; font-size: .68rem; letter-spacing: .01em;
  color: var(--rail-ink-2); font-variant-numeric: tabular-nums;
}

.linkish {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--rail-ink-2); text-decoration: underline;
  font: inherit; font-size: .8rem; text-align: left;
}
.linkish:hover { color: #fff; }

/* -- barra superior -- */

.main { display: flex; flex-direction: column; min-width: 0; overflow: hidden; }

.topbar {
  display: flex; align-items: center; gap: .85rem; flex-wrap: wrap;
  padding: .7rem 1.25rem;
  padding-top: calc(.7rem + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.topbar__titles { min-width: 0; }
.topbar h1 { font-size: 1.06rem; }
.topbar__sub { margin: 0; font-size: .79rem; color: var(--ink-2); }
.topbar__spacer { flex: 1; }
.topbar__actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

.content { overflow-y: auto; flex: 1; padding: 1.25rem 1.25rem 3.5rem; }
.view { max-width: 1180px; display: flex; flex-direction: column; gap: 1rem; }

/* `min-width: 0` en todo hijo de `.view`, y no es una línea de adorno: es la
   que impide que una tabla ancha empuje la pantalla entera hacia la derecha.

   Un hijo de un contenedor flexible trae `min-width: auto` de fábrica, que
   significa «no encojas por debajo de tu contenido». Una tabla de nueve
   columnas es ese contenido: el panel crecía hasta caber la tabla, se salía de
   su caja, y había que arrastrar la pantalla en horizontal para leer el resto
   — en un teléfono, cada pantalla con tabla. `.main` ya llevaba esta misma
   línea por el mismo motivo; faltaba un nivel más abajo.
   
   Con esto, el panel se queda del ancho que le toca y es la TABLA la que se
   desplaza dentro de su `.tablewrap`, que es justo para lo que existe. */
.view > *, .split > *, .hero > *, .panel, .card { min-width: 0; }

/* El encabezado dentro del contenido sobrevive para las pantallas que llevan una
   segunda cabecera bajo la barra superior (una ficha, un recibo). */
.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; margin-bottom: 1rem;
}
.crumb { margin: 0 0 .2rem; font-size: .8rem; }
.head-actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

/* ===========================================================================
   4 · Tarjetas y cifras
   =========================================================================== */

/* `.panel` es la tarjeta de siempre; `.card` con cabecera propia es la del
   prototipo. Las dos existen y se ven igual por fuera. */
.panel, .card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.panel { padding: 1rem 1.15rem; margin-bottom: 1rem; }
.view > .panel { margin-bottom: 0; }

.panel__title, .card-h h2 {
  font-size: .95rem; font-weight: 650; letter-spacing: -.01em;
}
.panel__note {
  margin: .7rem 0 0; font-size: .82rem; color: var(--ink-2);
}

.card-h {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .75rem 1.15rem; border-bottom: 1px solid var(--line);
}
.card-h h2 { margin: 0; }
.card-h .hint { font-size: .76rem; color: var(--ink-3); margin-left: auto; text-align: right; }
.card-b { padding: 1rem 1.15rem; }

.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem; }
.split--wide { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }

/* -- cifras grandes -- */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: .7rem;
  margin-bottom: 1rem;
}
.view > .tiles { margin-bottom: 0; }

.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius); padding: .8rem .9rem;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: .1rem;
}
.tile__label {
  margin: 0; font-size: .76rem; color: var(--ink-2);
}
.tile__value {
  margin: 0; font-size: 1.6rem; font-weight: 700; line-height: 1.15;
  letter-spacing: -.025em; font-variant-numeric: tabular-nums;
}
.tile__note { margin: .15rem 0 0; font-family: var(--mono); font-size: .68rem; color: var(--ink-3); }

.tile--ok       { border-left-color: var(--good); }
.tile--warn     { border-left-color: var(--warn); }
.tile--critical { border-left-color: var(--crit); }
.tile--warn .tile__value     { color: var(--warn); }
.tile--critical .tile__value { color: var(--crit); }
.tile--ok .tile__value       { color: var(--good); }

.tiles--compact .tile__value { font-size: 1.25rem; }

/* La cifra que abre la pantalla del dueño: una sola, del tamaño que merece. */
.hero {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  overflow: hidden;
}
.hero__main {
  padding: 1.25rem 1.4rem; border-right: 1px solid var(--line);
  display: flex; flex-direction: column; justify-content: center; gap: .2rem;
}
.hero__label { font-size: .82rem; color: var(--ink-2); }
.hero__value {
  font-size: clamp(2.2rem, 5vw, 3rem); font-weight: 800; line-height: 1;
  letter-spacing: -.035em; font-variant-numeric: tabular-nums;
}
.hero__sub { font-family: var(--mono); font-size: .73rem; color: var(--ink-3); margin-top: .35rem; }
.hero__side { padding: 1.1rem 1.4rem; display: flex; flex-direction: column; gap: .8rem; justify-content: center; }
.hero__chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .6rem; }

/* ===========================================================================
   5 · Etiquetas
   =========================================================================== */

/* Una etiqueta lleva siempre palabra, nunca solo color: el 8 % de los hombres no
   distingue el rojo del verde, y aquí el verde y el rojo son «puede salir» y
   «no puede salir». */
.tag, .chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .1rem .45rem; border-radius: 99px;
  font-size: .72rem; font-weight: 600; letter-spacing: .01em;
  white-space: nowrap;
  border: 1px solid var(--line-strong);
  background: var(--surface-3); color: var(--ink-2);
}
.tag--ok, .chip--ok, .tag--available, .tag--in_service, .tag--paid, .tag--active,
.tag--approved, .tag--current {
  background: var(--good-soft); color: var(--good); border-color: var(--good);
}
.tag--warn, .chip--warn, .tag--reserved, .tag--minor, .tag--pending, .tag--tentative {
  background: var(--warn-soft); color: var(--warn); border-color: var(--warn);
}
.tag--critical, .chip--critical, .tag--overlocked, .tag--out_of_service,
.tag--blocked, .tag--delinquent {
  background: var(--crit-soft); color: var(--crit); border-color: var(--crit);
}
.tag--money, .tag--ddt, .tag--occupied {
  background: var(--money-soft); color: var(--money); border-color: var(--money);
}
.tag--accent {
  background: var(--accent-soft); color: var(--accent-ink); border-color: var(--accent);
}
.tag--info, .tag--maintenance, .tag--unrentable {
  background: var(--surface-2); color: var(--ink-2); border-color: var(--line-strong);
}

.pill {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .7rem; border-radius: 99px;
  font-size: .8rem; font-weight: 600; text-decoration: none;
  border: 1px solid var(--line-strong); background: var(--surface-3); color: var(--ink-2);
}
.pill--critical { background: var(--crit-soft); color: var(--crit); border-color: var(--crit); }
.pill--critical:hover { color: var(--crit); }

/* ===========================================================================
   6 · Botones
   =========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .45rem .85rem; min-height: 36px;
  border: 1px solid var(--line-strong); border-radius: 7px;
  background: var(--surface); color: var(--ink);
  font: inherit; font-weight: 600; font-size: .84rem;
  cursor: pointer; text-decoration: none; white-space: nowrap;
}
.btn:hover { background: var(--surface-2); color: var(--ink); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.btn--primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.btn--primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); color: var(--on-accent); }
.btn--danger { background: var(--surface); border-color: var(--crit); color: var(--crit); }
.btn--danger:hover { background: var(--crit-soft); color: var(--crit); }
.btn--small { padding: .25rem .55rem; min-height: 30px; font-size: .79rem; }
.btn--ghost { background: transparent; border-color: var(--line-strong); color: var(--ink-2); }
.btn--ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn--block { width: 100%; margin-top: .4rem; }

/* El botón de la cuadrilla es otro animal: se pulsa de pie, con guantes, con el
   teléfono en una mano. 56 px de alto y a lo ancho de la pantalla. */
.btn--field {
  min-height: 56px; font-size: 1rem; width: 100%; max-width: 34rem;
  border-radius: 9px; letter-spacing: -.01em;
}

.btnrow { display: flex; flex-wrap: wrap; gap: .5rem; }

/* ===========================================================================
   7 · Tablas
   =========================================================================== */

/* La tabla se desplaza AQUÍ dentro, no arrastrando la página. El
   `max-width` es el cinturón del `min-width: 0` de arriba: sin él, un
   navegador que no aplique lo otro deja que el envoltorio crezca igual. */
.tablewrap { overflow-x: auto; max-width: 100%; }

.table { width: 100%; border-collapse: collapse; font-size: .86rem; }
.table th {
  text-align: left; font-family: var(--mono);
  font-size: .64rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 600; white-space: nowrap;
  background: var(--surface-3);
  border-bottom: 1px solid var(--line); padding: .45rem .7rem;
}
.table td { padding: .55rem .7rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table--rows tbody tr:hover { background: var(--surface-3); }
.table tfoot td { font-weight: 650; background: var(--surface-3); }

.row--critical { background: var(--crit-soft); }
.row--critical:hover { background: var(--crit-soft); }
.row-error { margin: .3rem 0 0; font-size: .78rem; color: var(--crit); }

/* Una tabla dentro de una tarjeta ocupa todo el ancho: el aire lo pone la
   tarjeta, no la tabla. */
/* La tabla sangra hasta los bordes del panel: sin esto queda un marco blanco
   alrededor que la hace parecer una tarjeta dentro de otra.

   El margen inferior negativo solo cuando la tabla es lo ÚLTIMO del panel. Antes
   se aplicaba siempre, y cualquier cosa que viniera después —el formulario de
   añadir un día, el de asignar a alguien— subía un centímetro y se montaba
   encima de la última fila. Se veía en dos pantallas y en las dos parecía un
   fallo distinto. */
.panel > .tablewrap, .card > .tablewrap { margin: 0 -1.15rem; }
.panel > .tablewrap:last-child, .card > .tablewrap:last-child { margin-bottom: -1rem; }
.panel > .tablewrap + *, .card > .tablewrap + * { margin-top: 1.1rem; }
.panel > .tablewrap .table th:first-child,
.panel > .tablewrap .table td:first-child,
.card  > .tablewrap .table th:first-child,
.card  > .tablewrap .table td:first-child { padding-left: 1.15rem; }
.panel > .tablewrap .table th:last-child,
.panel > .tablewrap .table td:last-child,
.card  > .tablewrap .table th:last-child,
.card  > .tablewrap .table td:last-child { padding-right: 1.15rem; }
.card > .tablewrap:last-child .table tbody tr:last-child td { border-bottom: 0; }

.empty {
  padding: 2rem 1rem; text-align: center; color: var(--ink-2);
}
/* El vacío no es un hueco: dice qué falta y ofrece el botón que lo llena. */
.empty__title { font-weight: 650; color: var(--ink); margin: 0 0 .25rem; }
.empty__hint  { margin: 0 0 .8rem; font-size: .86rem; }

/* ===========================================================================
   8 · Avisos
   =========================================================================== */

.callout, .note {
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: .65rem .85rem;
  font-size: .86rem; color: var(--ink-2);
  margin: 0 0 1rem;
}
.callout b, .note b, .callout strong, .note strong { color: var(--ink); }
.callout--warn, .note--warn { border-left-color: var(--warn); background: var(--warn-soft); }
.callout--critical, .note--critical { border-left-color: var(--crit); background: var(--crit-soft); }
.callout--quiet { border-left-color: var(--line-strong); background: var(--surface-3); }
.callout ul { margin: .35rem 0 0; padding-left: 1.1rem; display: block; }
.callout li + li { margin-top: .25rem; }
.callout p:last-child { margin-bottom: 0; }

.flashes { margin-bottom: 1rem; }
.flash {
  padding: .6rem .85rem; border-radius: var(--radius-sm); margin: 0 0 .4rem;
  font-size: .87rem; border: 1px solid var(--line-strong);
  background: var(--surface-3); color: var(--ink-2);
}
.flash--success { background: var(--good-soft); color: var(--good); border-color: var(--good); }
.flash--error   { background: var(--crit-soft); color: var(--crit); border-color: var(--crit); }
.flash--warning { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }

/* ===========================================================================
   9 · Listas de sucesos
   =========================================================================== */

.feed { list-style: none; margin: 0; padding: 0; }
.feed__item {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .5rem 0; border-bottom: 1px solid var(--line); font-size: .88rem;
}
.feed__item:last-child { border-bottom: 0; }
.feed__item--critical { border-left: 3px solid var(--crit); padding-left: .6rem; }
.feed__item--warning  { border-left: 3px solid var(--warn); padding-left: .6rem; }
.feed__detail { color: var(--ink-2); font-size: .83rem; flex-basis: 100%; }
.feed__item time { margin-left: auto; color: var(--ink-3); font-family: var(--mono); font-size: .75rem; }

.exceptions { list-style: none; margin: 0; padding: 0; }
.exception {
  border: 1px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius-sm); padding: .7rem .85rem; margin-bottom: .55rem;
  background: var(--surface);
}
.exception:last-child { margin-bottom: 0; }
.exception--critical { border-left-color: var(--crit); background: var(--crit-soft); }
.exception--warning  { border-left-color: var(--warn); background: var(--warn-soft); }
.exception.is-resolved { opacity: .6; }
.exception__head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.exception__detail { margin: .3rem 0 .45rem; font-size: .87rem; }
.exception__form { display: flex; gap: .4rem; }
.exception__form input { flex: 1; }
.exception__resolution { margin: 0; font-size: .81rem; color: var(--ink-2); }

/* -- línea de tiempo -- */
.timeline {
  list-style: none; margin: 0; padding: 0 0 0 1rem;
  border-left: 2px solid var(--line);
}
.timeline__item {
  display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap;
  padding: .35rem 0; font-size: .87rem; position: relative;
}
.timeline__item::before {
  content: ""; position: absolute; left: -1.32rem; top: .8rem;
  width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong);
}
.timeline__item--key::before { background: var(--accent); }
.timeline__item time {
  font-family: var(--mono); font-size: .76rem; color: var(--ink-3); min-width: 6.5rem;
}

/* -- libro mayor: filas de etiqueta / cifra / banderas -- */
.ledger {
  display: flex; flex-direction: column; gap: 1px;
  background: var(--line); border-radius: var(--radius-sm); overflow: hidden;
  border: 1px solid var(--line);
}
.led {
  display: grid; grid-template-columns: 1fr auto auto auto; gap: .6rem;
  align-items: center; background: var(--surface); padding: .45rem .75rem; font-size: .83rem;
}
.led__label { display: flex; align-items: center; gap: .5rem; }
.led__sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.led__num { font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ink-2);
            min-width: 4.2em; text-align: right; }
.led__flag { font-family: var(--mono); font-size: .7rem; color: var(--ink-3);
             min-width: 3.6em; text-align: center; }
.led__flag--on { color: var(--good); }
.led__flag--off { opacity: .45; }
.led--head {
  background: var(--surface-3); font-family: var(--mono);
  font-size: .62rem; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3);
}
.led--total { background: var(--surface-3); font-weight: 650; }

/* ===========================================================================
   10 · Gráficos de una sola dimensión
   =========================================================================== */

/* Barra apilada del reparto de la jornada. Se llamó `.stack` una vez y chocó con
   el apilado de los formularios: dos cosas distintas, dos nombres distintos. */
.meter {
  display: flex; height: 14px; border-radius: 99px; overflow: hidden;
  background: var(--surface-2);
}
.meter__part { display: block; height: 100%; }
.meter__part--1 { background: var(--data-1); }
.meter__part--2 { background: var(--data-2); }
.meter__part--3 { background: var(--data-3); }
.meter__part--4 { background: var(--data-4); }

.legend { list-style: none; margin: .8rem 0 0; padding: 0; font-size: .84rem; }
.legend li { display: flex; align-items: center; gap: .45rem; padding: .12rem 0; }
.legend__dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }
.legend__dot--1 { background: var(--data-1); }
.legend__dot--2 { background: var(--data-2); }
.legend__dot--3 { background: var(--data-3); }
.legend__dot--4 { background: var(--data-4); }

/* Medidor con marca de objetivo: la cifra sola no dice si está bien. */
.gauge { display: flex; flex-direction: column; gap: .35rem; }
.gauge__top { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.gauge__name { font-size: .82rem; color: var(--ink-2); }
.gauge__value { font-weight: 700; font-size: 1.1rem; letter-spacing: -.02em;
                font-variant-numeric: tabular-nums; }
.gauge__track { position: relative; height: 9px; background: var(--surface-2); border-radius: 99px; }
.gauge__fill { position: absolute; left: 0; top: 0; height: 100%; border-radius: 99px;
               background: var(--good); }
.gauge__fill--warn { background: var(--warn); }
.gauge__fill--crit { background: var(--crit); }
.gauge__mark { position: absolute; top: -4px; width: 2px; height: 17px;
               background: var(--ink-3); border-radius: 1px; }
.gauge__foot { display: flex; justify-content: space-between; gap: .5rem;
               font-family: var(--mono); font-size: .66rem; color: var(--ink-3); }
.gauges { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

/* Barra pequeña dentro de una celda de tabla. */
.mini { display: flex; align-items: center; gap: .5rem; min-width: 110px; }
.mini__bar { flex: 1; height: 6px; background: var(--surface-2); border-radius: 99px; overflow: hidden; }
.mini__fill { display: block; height: 100%; background: var(--accent); }
.mini__fill--warn { background: var(--warn); }
.mini__fill--crit { background: var(--crit); }
.mini span { font-family: var(--mono); font-size: .7rem; color: var(--ink-2); min-width: 3em; text-align: right; }

/* Barras por semana de la pantalla de desempeño. En CSS puro, sin librería de
   gráficos: son doce o cincuenta y dos rectángulos y una altura, y una
   dependencia de 300 KB para eso se paga en el teléfono de la cuadrilla.

   `align-items: end` y el hueco de altura fija son lo que hace que la barra
   crezca desde abajo. Sin el hueco, un porcentaje de altura no tiene contra qué
   resolverse y todas las barras salen del mismo tamaño. */
/* Rejilla y no `flex`: con `flex: 1 1 0` cada columna se redondea por su cuenta
   y catorce columnas suman cinco píxeles de más, que bastan para que aparezca una
   barra de desplazamiento horizontal donde no sobra nada. `minmax(14px, 1fr)`
   reparte el ancho exacto y solo desborda cuando de verdad no caben —cincuenta y
   dos semanas en un teléfono—, que es cuando el desplazamiento sirve. */
.barras {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(14px, 1fr);
  align-items: end; gap: 3px;
  margin: 1rem 0 .4rem; overflow-x: auto; padding-bottom: .2rem;
}
.barras__col { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.barras__hueco {
  height: 86px; display: flex; align-items: flex-end;
  background: var(--surface-2); border-radius: 3px;
}
.barras__barra {
  width: 100%; background: var(--accent); border-radius: 3px;
  /* Una semana con horas pero muy pocas tiene que verse: sin el mínimo, media
     jornada al lado de una semana de sesenta horas se redondea a nada, y la
     barra vacía dice «no trabajó», que es falso. */
  min-height: 2px;
}
.barras__pie {
  font-family: var(--mono); font-size: .6rem; color: var(--ink-3);
  text-align: center; white-space: nowrap;
}
/* Con muchas barras las fechas no caben: catorce en una columna de 460 píxeles dan
   treinta por fecha y «22 Jun» necesita treinta y tres, así que se montan unas
   sobre otras y no se lee ninguna. Se escribe una de cada dos o de cada cuatro
   —el paso lo decide el servidor, que sabe cuántas hay— y las demás quedan en el
   título del rectángulo, que es donde se leen de una en una.

   En un teléfono la columna es la mitad de ancha, así que el paso se dobla. */
.barras--cada2 .barras__col:not(:nth-child(2n+1)) .barras__pie,
.barras--cada4 .barras__col:not(:nth-child(4n+1)) .barras__pie { visibility: hidden; }

@media (max-width: 700px) {
  .barras--cada2 .barras__col:not(:nth-child(4n+1)) .barras__pie,
  .barras--cada4 .barras__col:not(:nth-child(8n+1)) .barras__pie { visibility: hidden; }
}

/* Barras de dinero: dos partes apiladas dentro de una.

   La altura entera es el ingreso del día; el trozo de arriba es el margen y el
   de abajo, el costo de la cuadrilla. Una barra sola diría cuánto se facturó y
   no cuánto quedó, que es la cifra por la que se abre la pantalla: un día de
   ocho mil dólares con siete mil de cuadrilla y uno de cuatro mil con mil son la
   misma barra y no son el mismo día.

   Un día en pérdidas se pinta entero en el color de alarma, porque un margen
   negativo no se puede apilar encima de nada. */
/* Aquí el hueco NO se pinta, y es deliberado. En la pantalla de horas el fondo
   gris se lee como un carril; con treinta columnas y la mitad en blanco —los
   fines de semana— se lee como una barra gris de altura completa, es decir,
   como si ese día hubiera pasado algo. Un día sin trabajo tiene que verse
   vacío. Queda la línea de base, que es lo que hace falta para leer la altura
   del resto. */
.barras--dinero .barras__hueco {
  height: 120px; background: none;
  border-bottom: 1px solid var(--line);
}
.barras__pila {
  width: 100%; display: flex; flex-direction: column;
  border-radius: 3px; overflow: hidden; min-height: 2px;
}
.barras__parte { display: block; width: 100%; }
.barras__parte--margen { background: var(--data-1); flex: none; }
/* El costo se lleva lo que sobre: así las dos partes suman siempre el ingreso
   sin que haya que calcular la segunda altura en la plantilla. */
.barras__parte--costo { background: var(--data-2); flex: 1 1 auto; min-height: 0; }
.barras__barra--perdida { background: var(--crit); }

/* Las notas de la cuadrilla en «Mi día».

   Se leen de pie, en la acera, con una mano y a veces con guantes. De ahí el
   tamaño: son la única cosa de esa pantalla que no se puede deducir mirando
   alrededor —la dirección se ve, el camión se ve, el código del portón no— así
   que se leen antes que el resto o no se leen. */
.notas { display: flex; flex-direction: column; gap: .4rem; margin-top: .9rem; }
.notas__item {
  margin: 0; padding: .6rem .75rem;
  background: var(--surface-2); border-radius: var(--radius);
  border-left: 3px solid var(--line-strong);
  font-size: 1rem; line-height: 1.45;
}
.notas__item--fija { border-left-color: var(--accent); font-weight: 600; }

/* Día por día: una fila, una línea. En un teléfono la columna «esperada» lleva la
   hora y de dónde salió, y sin esto se parte en cuatro líneas y cada fila ocupa
   media pantalla. Con las celdas en una sola línea la tabla se desplaza a lo
   ancho —`.tablewrap` ya lo hace— y se recorre el mes de un vistazo, que es para
   lo que se abre. */
.perf-dias th, .perf-dias td { white-space: nowrap; }

/* ===========================================================================
   11 · Formularios
   =========================================================================== */

/* Sin librería de formularios: media docena de reglas cubren todo lo que este
   producto pide, y una librería obligaría a pelearse con sus valores por
   defecto en cada pantalla. */

input[type="text"], input[type="search"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="time"], input[type="tel"],
input[type="url"], input[type="datetime-local"], select, textarea {
  padding: .45rem .6rem; min-height: 38px;
  border: 1px solid var(--line-strong); border-radius: 7px;
  font: inherit; font-size: .88rem;
  background: var(--surface); color: var(--ink);
  width: 100%;
}
select { min-height: 38px; }
textarea { min-height: 84px; resize: vertical; }
input[readonly], input:disabled, select:disabled, textarea:disabled {
  background: var(--surface-2); color: var(--ink-2);
}
input::placeholder, textarea::placeholder { color: var(--ink-3); }

.field { display: flex; flex-direction: column; gap: .25rem; margin: 0 0 .8rem; }
.field > label { font-size: .8rem; font-weight: 600; color: var(--ink-2); }
.field__help { font-size: .78rem; color: var(--ink-3); }
.field-error { color: var(--crit); font-size: .8rem; }

/* Apilar en vertical: lo que un formulario necesita y lo que su nombre dice. El
   botón no se estira, porque un «Guardar» de mil píxeles no se lee como botón. */
.stack { display: flex; flex-direction: column; }
.stack > .btn { align-self: flex-start; }

/* Formulario en rejilla: dos columnas en escritorio, una en el teléfono. */
.formgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0 1rem; }
.formgrid .field--wide { grid-column: 1 / -1; }

/* Un campo de cuatro dígitos con setecientos píxeles de ancho no se lee como un
   campo de cuatro dígitos: se lee como un descuido. Los que tienen una longitud
   conocida se acotan; el texto libre sigue ocupando la columna. */
.field input[type="number"], .field input[type="date"], .field input[type="time"],
.field input[type="datetime-local"] { max-width: 15rem; }

.inline-form { display: inline-flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.inline-form input, .inline-form select { width: auto; min-width: 8rem; }

.daypicker { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.daypicker label { font-size: .82rem; color: var(--ink-2); }
/* El `<select>` también, no solo el `<input>`.

   Sin esta línea el desplegable hereda el `width: 100%` general, se lleva la
   fila entera y empuja el botón a la siguiente: la barra de búsqueda quedaba en
   tres alturas con un campo estrecho arriba y un desplegable enorme debajo. Se
   veía igual en trabajos y en peticiones, que comparten este marcado. */
.daypicker input, .daypicker select { width: auto; }
/* Y el campo de búsqueda con sitio de verdad: es donde se escribe una dirección
   entera, y en 200 px no cabe «5412 Monte Vista St». */
.daypicker input[type="search"] { min-width: min(24rem, 100%); flex: 1 1 14rem; }

.channels { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
.channels label { display: flex; align-items: center; gap: .4rem; font-size: .85rem; }
.channels input { width: auto; min-height: auto; }

/* Casillas en rejilla, no en lista larga. Acotado a los formularios: una regla
   que alcance a todo `ul` acaba pintando una lista de avisos que no era suya. */
.panel > form ul, .stack > form ul, form .field ul, .card-b > form ul {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: .3rem .8rem;
}
form ul li label { font-weight: 400; font-size: .88rem; display: flex; align-items: center; gap: .35rem; }
form ul li label input { width: auto; min-height: auto; }

.nextstep {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1.25rem; flex-wrap: wrap;
}
.nextstep form { display: flex; align-items: flex-start; gap: .7rem; flex-wrap: wrap; }

/* Ficha de datos: etiqueta y valor en dos columnas. */
.facts { display: grid; grid-template-columns: minmax(6rem, 30%) 1fr; gap: .4rem .9rem; margin: 0; }
.facts dt { font-size: .8rem; color: var(--ink-2); }
.facts dd { margin: 0; }

/* Formulario que rellena la cuadrilla: campos grandes, de pie, junto al camión,
   con guantes y con sol en la pantalla. */
.damage-report__row { display: flex; flex-wrap: wrap; gap: .65rem; align-items: end; }
.damage-report__field { display: flex; flex-direction: column; flex: 1 1 11rem; }
.damage-report__field--wide { flex: 2 1 18rem; }
.damage-report__field label { font-size: .78rem; color: var(--ink-2); margin-bottom: .2rem; }
.damage-report__field input, .damage-report__field select { min-height: 44px; }
.damage-report__row .btn { min-height: 44px; }

/* ===========================================================================
   11 bis · El reloj de la cuadrilla
   ===========================================================================
   Se usa de pie, junto al camión, con una mano y con sol en la pantalla. El
   botón principal ocupa el ancho entero y mide 56 px de alto; las alternativas
   van debajo y pequeñas, porque son lo que pasa el 10 % de los días. */

.clockhead {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; margin-bottom: .9rem;
}
.clockhead__count { text-align: right; }
.clockhead__hours {
  margin: .25rem 0 0; font-size: 1.35rem; font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.clockhead__count p { margin: 0; }
.clockform { display: flex; flex-direction: column; gap: .5rem; }
.clockform__hint { margin: 0; }
.clockalt { margin-top: .6rem; }
.clockalt .btn { min-height: 44px; }

/* ===========================================================================
   12 · Inspecciones: fotos y hallazgos
   =========================================================================== */

/* Las dos fotos, lado a lado, son el módulo entero. Si esto se ve mal, el
   expediente no vale para una disputa. */
.pair { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: .8rem;
        background: var(--surface); overflow: hidden; }
.pair__head {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .6rem .85rem; border-bottom: 1px solid var(--line); font-size: .87rem;
}
.pair__imgs { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); }
.pair__foot { padding: .6rem .85rem; border-top: 1px solid var(--line); font-size: .83rem; color: var(--ink-2);
              display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

.shot { background: var(--surface-2); padding: .5rem; }
.shot__frame { position: relative; }
.shot img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
            border-radius: var(--radius-sm); background: var(--surface-3); }
.shot--empty {
  display: grid; place-items: center; aspect-ratio: 4 / 3;
  color: var(--ink-3); font-size: .82rem; text-align: center;
}
.shot__label { display: block; font-size: .78rem; font-weight: 600; margin-bottom: .35rem; }
.shot__meta { display: block; font-family: var(--mono); font-size: .68rem; color: var(--ink-3); margin-top: .35rem; }
.shot--pm img { outline: 2px solid var(--crit); outline-offset: -2px; }

/* Los seis ángulos, en rejilla. Se rellenan en desorden porque se rodea el
   camión mientras se marcan otras cosas, así que cada hueco se sostiene solo y
   dice qué falta. */
.angles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: .7rem; }
.angle {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .6rem; background: var(--surface-3);
  display: flex; flex-direction: column; gap: .4rem;
}
.angle--done { border-color: var(--good); background: var(--good-soft); }
.angle img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 5px; }
.angle__label { margin: 0; font-size: .8rem; font-weight: 650; }
.angle__meta { margin: 0; font-family: var(--mono); font-size: .68rem; color: var(--ink-3); }
.angle__form { display: flex; flex-direction: column; gap: .35rem; margin-top: auto; }
.angle__form input[type="file"] { font-size: .78rem; border: 0; padding: 0; min-height: 0; }

/* Una fila de la lista de revisión: tres estados y una nota, en una línea en
   el escritorio y apilada en el teléfono. */
.itemrow { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.itemrow__states { display: flex; gap: .3rem; flex-wrap: wrap; }
.itemrow__state {
  display: inline-flex; align-items: center; gap: .3rem;
  border: 1px solid var(--line-strong); border-radius: 99px;
  padding: .2rem .55rem; font-size: .8rem; cursor: pointer; background: var(--surface);
}
.itemrow__state input { width: auto; min-height: 0; }
.itemrow__state:has(input:checked) {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-ink);
  font-weight: 600;
}
.itemrow input[type="text"] { flex: 1 1 12rem; min-width: 8rem; }

@media (max-width: 760px) {
  .itemrow { flex-direction: column; align-items: stretch; }
  .itemrow__state { min-height: 44px; }
}

.reviewform { display: flex; gap: .4rem; flex-wrap: wrap; width: 100%; }
.reviewform input[type="text"] { flex: 1 1 12rem; min-width: 11rem; }
.reviewform__why { width: 100%; margin: 0 0 .4rem; }

/* El recuadro del hallazgo va sobre la foto, en coordenadas relativas. */
.box { position: absolute; border: 2px solid var(--money); border-radius: 3px; pointer-events: none; }
.box--new { border-color: var(--crit); }
.box__tag {
  position: absolute; top: -.85rem; left: -2px;
  background: var(--money); color: var(--on-money); font-family: var(--mono);
  font-size: .58rem; padding: 0 .25rem; border-radius: 2px;
}
.box--new .box__tag { background: var(--crit); }

/* ===========================================================================
   13 · Recibo de pago
   ===========================================================================
   Es papel: márgenes de papel, sin barra lateral y sin botones, porque lo que se
   entrega en mano no lleva enlaces. */

.paystub {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.6rem; max-width: 820px;
}
.paystub__head {
  display: flex; justify-content: space-between; gap: 1.5rem;
  border-bottom: 2px solid var(--accent); padding-bottom: .85rem; margin-bottom: 1.15rem;
}
.paystub__head h2 { margin: 0; font-size: 1.12rem; }
.paystub__period { text-align: right; font-size: .84rem; }
.paystub__period p { margin: 0 0 .35rem; }
.paystub__note {
  margin: 1rem 0 0; font-size: .8rem; color: var(--ink-2);
  border-left: 3px solid var(--line); padding-left: .75rem;
}

@media print {
  .rail, .topbar, .no-print, .flashes { display: none !important; }
  .shell, .main { display: block; height: auto; overflow: visible; }
  .content { padding: 0; overflow: visible; }
  .paystub { border: 0; padding: 0; max-width: none; box-shadow: none; }
  body { background: #fff; }
}

/* ===========================================================================
   14 · Demostración
   =========================================================================== */

/* Visiblemente aparte del resto: un botón que borra datos no debe parecerse a
   los que no lo hacen. */
.panel--demo { border: 1px dashed var(--line-strong); background: var(--surface-3); box-shadow: none; }
.panel--demo .btn { border-color: var(--warn); color: var(--warn); }
.panel--demo .btn:hover { background: var(--warn-soft); }

/* ===========================================================================
   15 · Pantalla de acceso
   =========================================================================== */

.page-auth { background: var(--rail); }
.auth { min-height: 100vh; display: grid; place-items: center; padding: 1.5rem; }
.auth__card {
  background: var(--surface); border-radius: 14px; padding: 2rem;
  width: min(380px, 100%); box-shadow: var(--shadow-lift);
}
.auth__mark { margin: 0; font-weight: 800; color: var(--accent); letter-spacing: -.03em; font-size: 1.3rem; }
.auth__title { font-size: 1.1rem; margin: 0 0 1.15rem; color: var(--ink-2); font-weight: 500; }
.auth__card label { display: block; font-size: .82rem; font-weight: 600; margin: .7rem 0 .25rem; color: var(--ink-2); }
.auth__error {
  background: var(--crit-soft); color: var(--crit); border: 1px solid var(--crit);
  padding: .6rem .8rem; border-radius: var(--radius-sm); font-size: .85rem;
}

/* ===========================================================================
   16 · Ajustes del riel (idioma, zona, tema)
   =========================================================================== */

.railform { margin: 0; }
.railform select {
  width: 100%; padding: .25rem .35rem; min-height: 30px; border-radius: 6px;
  border: 1px solid var(--rail-line); background: transparent;
  color: var(--rail-ink); font: inherit; font-size: .79rem;
}
.railform select option { color: var(--ink); background: var(--surface); }
.railform select:hover { border-color: var(--rail-ink-2); }

.themeswitch {
  display: flex; gap: .25rem; border: 1px solid var(--rail-line);
  border-radius: 7px; padding: 2px;
}
.themeswitch button {
  flex: 1; background: none; border: 0; border-radius: 5px; cursor: pointer;
  color: var(--rail-ink-2); font: inherit; font-size: .72rem; padding: .22rem .3rem;
}
.themeswitch button:hover { color: #fff; }
.themeswitch button[aria-pressed="true"] { background: rgb(255 255 255 / 12%); color: #fff; }

/* ===========================================================================
   17 · Adaptación a pantallas pequeñas
   ===========================================================================
   La cuadrilla es el usuario móvil principal del producto. En 414 px el riel
   ocupaba media pantalla y había que bajar por delante del selector de idioma
   para llegar a «a qué trabajo voy». Aquí se convierte en una fila que se
   desplaza en horizontal. */

@media (max-width: 960px) {
  .split, .split--wide { grid-template-columns: 1fr; }
  .hero { grid-template-columns: 1fr; }
  .hero__main { border-right: 0; border-bottom: 1px solid var(--line); }
  .pair__imgs { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .shell { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); height: 100%; }
  .rail {
    flex-direction: row; align-items: center; gap: .6rem;
    overflow-x: auto; padding: .5rem .75rem; flex-wrap: nowrap;
  }
  .rail__brand { flex: 0 0 auto; margin: 0; }
  .rail__company { max-width: 8rem; font-size: .88rem; }
  .rail__group { flex-direction: row; gap: .25rem; flex: 0 0 auto; }
  .rail__label { display: none; }
  .rail__group a { white-space: nowrap; padding: .35rem .55rem; font-size: .84rem; }
  .rail__group a::before { display: none; }
  .rail__foot {
    margin: 0 0 0 auto; border: 0; padding: 0; flex: 0 0 auto;
    flex-direction: row; align-items: center; gap: .5rem;
  }
  /* En el riel horizontal no cabe, y la versión no es algo que se consulte a
     diario: sigue en `check_install` y en la pantalla de instalación. */
  .rail__role, .rail__tz, .railform--tz, .rail__version { display: none; }
  .railform { width: 6.5rem; }
  .rail__user { font-size: .8rem; white-space: nowrap; max-width: 6rem;
                overflow: hidden; text-overflow: ellipsis; }
  .topbar { padding: .6rem .9rem; }
  .content { padding: .9rem .9rem 3rem; }
  .page-head { flex-direction: column; }
  .facts { grid-template-columns: 1fr; gap: .1rem .9rem; }
  .facts dd { margin-bottom: .5rem; }
  .damage-report__field, .damage-report__field--wide { flex: 1 1 100%; }
  .damage-report__row .btn { width: 100%; }
  .panel > .tablewrap, .card > .tablewrap { margin: 0 -1.15rem -1rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ===========================================================================
   18 · La aplicación instalada y el corte de línea
   ===========================================================================
   Dos situaciones que el navegador no tiene y la app sí: que no haya cobertura
   —y que eso se vea antes de tocar nada— y que la pantalla llegue hasta el
   borde del teléfono, por debajo de la muesca. */

.offline {
  margin: 0 0 1rem;
  padding: .7rem .9rem;
  border-radius: 10px;
  border: 1px solid var(--warn);
  border-left-width: 4px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: .9rem;
  line-height: 1.45;
}
.offline strong { color: var(--warn); }

/* Sin línea el reloj sigue funcionando: guarda el fichaje en el teléfono.
   Lo que se apaga es el botón de quien ya tiene uno esperando, porque el
   siguiente paso del día lo decide el servidor y sin él no se sabe cuál es. */
[data-reloj] button[type="submit"]:disabled {
  opacity: .45;
  cursor: not-allowed;
  filter: saturate(.3);
}

/* El fichaje que espera en el teléfono. Ámbar mientras espera; rojo si el
   servidor lo rechazó, que es cuando hay que enseñárselo a alguien. */
.pendiente {
  margin: 0 0 .75rem;
  padding: .6rem .8rem;
  border-radius: 10px;
  border: 1px solid var(--warn);
  border-left-width: 4px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: .9rem;
  line-height: 1.45;
}
.pendiente--error { border-color: var(--crit); background: var(--crit-soft); color: var(--crit); }

/* Instalada, la app llega hasta el borde: hay que respetar la muesca y la
   barra de gestos, o el último botón de la pantalla queda debajo de ella. */
@supports (padding: env(safe-area-inset-bottom)) {
  .content { padding-bottom: calc(3rem + env(safe-area-inset-bottom)); }
  .rail { padding-left: calc(.75rem + env(safe-area-inset-left)); }
}

/* La pantalla de corte y cualquier otra que se sirva sin sesión: centrada, sin
   riel y sin un solo dato de la empresa. */
.plain {
  display: flex; min-height: 100%;
  align-items: center; justify-content: center;
  padding: 1.5rem 1rem; background: var(--ground);
}
.plain__box { width: 100%; max-width: 32rem; }
.plain__box h1 { font-size: 1.35rem; margin: 0 0 .5rem; }
.plain__box > p:not(.plain__mark) { color: var(--ink-2); line-height: 1.55; }
.plain__box .panel { margin-top: 1rem; }
.plain__foot {
  margin-top: 1.4rem; font-size: .72rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.plain__mark {
  width: 2.5rem; height: 2.5rem; margin: 0 0 1rem;
  display: grid; place-items: center;
  border-radius: 9px; background: var(--accent);
  color: var(--on-accent); font-weight: 700; font-size: 1.2rem;
}
.plain__list { margin: 0; padding-left: 1.1rem; color: var(--ink-2); line-height: 1.5; }
.plain__list li + li { margin-top: .4rem; }

/* ===========================================================================
   19 · La pregunta de la geocerca
   ===========================================================================
   Sale en lugar del botón de fichar cuando alguien marca lejos del sitio. Se
   lee de pie, con una mano, con sol en la pantalla — así que va en ámbar y no
   en rojo: no es un error de esa persona, es una pregunta. El rojo aquí diría
   «te pillé», y lo que se quiere es una respuesta honesta. */

.whereform {
  border: 1px solid var(--warn);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--warn-soft);
  padding: .9rem;
}
.whereform__lead {
  margin: 0 0 .3rem; font-weight: 650; color: var(--warn); font-size: 1rem;
}
.whereform__note {
  margin: 0 0 .8rem; color: var(--ink-2); font-size: .85rem; line-height: 1.45;
}
.whereform__chips {
  display: flex; flex-wrap: wrap; gap: .45rem; margin-bottom: .8rem;
}
/* Los botones de respuesta no compiten con el de enviar: fondo de tarjeta, no
   de acento. El único acento de este bloque es el que ficha. */
.whereform__chips .btn {
  flex: 1 1 auto; background: var(--surface); text-align: center;
  white-space: normal; line-height: 1.25;
}
.whereform .field { margin-bottom: .7rem; }
.whereform__missing {
  margin: 0 0 .6rem; font-size: .85rem; font-weight: 600; color: var(--crit);
}

/* ===========================================================================
   20 · La captura de la inspección, en un teléfono
   ===========================================================================
   Esta pantalla se usa de pie, junto al camión, con guantes y con una mano
   sujetando la puerta. Todo lo de aquí sale de verla fallar en ese sitio:

   - la lista era una tabla de tres columnas y en 390 px la etiqueta se partía
     en cuatro líneas — una tabla sirve para comparar filas, y aquí no se
     compara nada: se marca una cosa y se pasa a la siguiente;
   - los estados eran píldoras de 26 px de alto: por debajo del objetivo táctil
     de 44 px, que es el mínimo con el dedo desnudo, no digamos con guante;
   - el selector de archivo salía como un control del navegador, minúsculo y
     distinto en cada teléfono. */

.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }

.check {
  border: 1px solid var(--line);
  border-left: 4px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: .65rem .75rem;
  background: var(--surface);
}
/* El estado se ve en el borde antes de leer nada: se recorre la lista de un
   vistazo buscando lo que falta, no leyendo dieciséis etiquetas. */
.check--ok  { border-left-color: var(--good); }
.check--bad { border-left-color: var(--crit); background: var(--crit-soft); }

.check__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: .5rem; margin-bottom: .5rem;
}
.check__name { margin: 0; font-weight: 600; font-size: .92rem; line-height: 1.3; }
.check__form { display: grid; gap: .5rem; }
.check__states { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: .35rem; }
.check__state {
  display: flex; align-items: center; justify-content: center; gap: .3rem;
  min-height: 44px; padding: .3rem .4rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface-3); cursor: pointer;
  font-size: .85rem; font-weight: 550; text-align: center; line-height: 1.2;
}
/* El radio se oculta pero sigue ahí: es lo que mantiene el grupo navegable con
   teclado y anunciable por un lector de pantalla. La pista visual la da el
   recuadro, no un punto de 13 px. */
.check__state input { position: absolute; opacity: 0; width: 0; height: 0; }
.check__state:has(input:checked) {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.check__state:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.check__note { width: 100%; }

/* El botón de la foto. La etiqueta ES el botón: el `input[type=file]` desnudo
   se pinta distinto en cada navegador y en el teléfono sale minúsculo. */
.angle__shoot {
  display: flex; align-items: center; justify-content: center;
  min-height: 48px; padding: .5rem .7rem;
  border: 1px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--accent); color: var(--on-accent);
  font-weight: 600; font-size: .86rem; cursor: pointer; text-align: center;
}
.angle__shoot input { position: absolute; opacity: 0; width: 0; height: 0; }
.angle__shoot:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* HTMX enciende esto mientras la petición está en vuelo. Con una barra de
   cobertura una foto tarda, y sin señal de que está subiendo la gente vuelve a
   pulsar — y sube la misma foto tres veces. */
.angle__busy { display: none; font-size: .8rem; color: var(--ink-2); text-align: center; }
.htmx-request .angle__busy, .htmx-request.angle__busy { display: block; }
.htmx-request .angle__shoot { opacity: .5; pointer-events: none; }

@media (max-width: 420px) {
  /* Los tres estados siguen EN FILA, con la etiqueta partida en dos líneas.
     Apilarlos parecía lo correcto en un teléfono y era peor: cada ítem pasaba a
     ocupar cinco renglones, los dieciséis se iban a cinco mil píxeles de
     desplazamiento, y la lista dejaba de poder recorrerse de un vistazo — que
     es lo único que hace que alguien la complete junto al camión y no después,
     de memoria, sentado en la cabina. */
  .check__state { font-size: .78rem; padding: .3rem .2rem; }
  .angles { grid-template-columns: 1fr; }
}

/* La lista de comprobaciones de la pantalla de instalación. Verde o rojo, con
   un signo delante: el estado no se comunica solo con color, porque una de cada
   doce personas no distingue esos dos. */
.checks { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.checks__item {
  position: relative; padding: .4rem 0 .4rem 1.6rem;
  font-size: .9rem; line-height: 1.45;
}
.checks__item::before {
  position: absolute; left: 0; top: .35rem;
  font-weight: 700; font-size: .95rem;
}
.checks__item--ok  { color: var(--ink-2); }
.checks__item--ok::before  { content: "✓"; color: var(--good); }
.checks__item--bad { color: var(--crit); font-weight: 550; }
.checks__item--bad::before { content: "✕"; color: var(--crit); }

/* El botón de «usar dónde estoy», en el alta de un patio. Va arriba del
   formulario y destacado porque es el camino bueno: los dos campos de
   coordenadas de más abajo son la salida de emergencia, no el método. */
.aqui {
  border: 1px solid var(--accent);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  padding: .8rem .9rem;
  margin-bottom: 1rem;
}
.aqui .btn { margin-bottom: .5rem; }
.aqui p { margin: 0; line-height: 1.45; }

/* El mapa del perímetro. Alto fijo y generoso: un mapa de 200 px no deja
   distinguir un patio de la nave de al lado, que es justo para lo que se abre. */
.mapa { margin-bottom: 1rem; }
.mapa__lienzo {
  width: 100%; height: 380px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.mapa p { margin: .45rem 0 0; line-height: 1.45; }

@media (max-width: 760px) {
  .mapa__lienzo { height: 300px; }
}
/* El aviso de que el mapa no cargó, dentro del propio hueco del mapa. Lo borra
   el mapa al arrancar, así que si se ve es porque de verdad no cargó. */
.mapa__fallo {
  margin: 0; padding: 1.2rem; max-width: 46ch;
  color: var(--ink-2); font-size: .88rem; line-height: 1.5;
}

/* El plano a escala: el perímetro y los fichajes, sin mapa y sin salir a
   internet. No imita un mapa a propósito — es un dibujo técnico, y se lee como
   tal. Lo que no puede hacer es engañar: nadie debe creer que ese punto de la
   derecha es la gasolinera de enfrente. */
.plano { margin-bottom: 1rem; }
.plano__lienzo {
  /* Centrado. Sin `margin-inline`, un lienzo con `max-width` dentro de un panel
     ancho se queda pegado a la izquierda con un palmo de vacío a la derecha, y
     se lee como un error de maquetación — que es exactamente como se leyó. */
  width: 100%; max-width: 460px; height: auto; margin-inline: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  display: block;
}
.plano__fondo { fill: var(--surface-3); }
.plano__reticula line { stroke: var(--line); stroke-width: 1; }
.plano__cerca {
  fill: var(--accent); fill-opacity: .12;
  stroke: var(--accent); stroke-width: 2;
}
.plano__sitio line { stroke: var(--ink); stroke-width: 2; }
.plano__punto { stroke: var(--surface); stroke-width: 1.5; }
.plano__punto--dentro { fill: var(--good); }
.plano__punto--fuera  { fill: var(--crit); }
/* El nombre del sitio, escrito en el plano. `paint-order: stroke` dibuja el
   contorno DEBAJO del relleno, así que el texto queda legible aunque caiga
   encima del círculo de la geocerca — sin esa línea, el nombre desaparece
   justo sobre el sitio que nombra. */
.plano__rotulo {
  fill: var(--ink); font-size: 10px; font-weight: 600; text-anchor: middle;
  stroke: var(--surface); stroke-width: 3; paint-order: stroke;
}
/* Los mandos del zoom, encima del plano. */
.plano__mandos {
  display: flex; align-items: center; gap: .4rem; margin-bottom: .5rem;
  flex-wrap: wrap;
}
.plano__ayuda { font-size: .74rem; color: var(--ink-3); }

/* El arrastre: el cursor lo anuncia, y `touch-action: none` es obligatorio —
   sin ella el navegador se queda el gesto para desplazar la página y el mapa no
   se mueve en el teléfono, que es justo donde más falta hace. */
.plano__lienzo { cursor: grab; touch-action: none; }
.plano__lienzo:active { cursor: grabbing; }

.plano__marca { cursor: pointer; }
.plano__marca:focus { outline: none; }
.plano__marca:focus .plano__punto,
.plano__marca:hover .plano__punto { stroke: var(--ink); stroke-width: 2.5; }
/* El globo con «cuántos fichajes hay aquí». Va al lado de la pila y no encima:
   encima taparía los propios puntos que está contando. */
.plano__globo { pointer-events: none; }
.plano__globo circle { fill: var(--ink); }
.plano__globo text {
  fill: var(--surface); font-size: 9px; font-weight: 700; text-anchor: middle;
}

/* El recuadro que dice quién fichó ahí. Altura mínima fija: si creciera y
   encogiera al pasar el ratón por las marcas, el plano entero daría saltos. */
.plano__info {
  margin: .5rem 0 0; min-height: 2.4em; font-size: .82rem; line-height: 1.4;
  color: var(--ink-2); padding: .45rem .6rem;
  background: var(--surface-3); border-radius: var(--radius-sm);
}

/* La coordenada en la tabla: monoespaciada para que los dígitos se alineen
   entre filas y se pueda comparar de un vistazo, y en su propia línea la
   precisión — que es la mitad del dato. */
.coord { white-space: nowrap; }
.coord code {
  font-family: var(--mono); font-size: .78rem; display: block;
}
.coord .small { font-size: .7rem; }
.plano__escala line { stroke: var(--ink-2); stroke-width: 1.5; }
.plano__escala text {
  fill: var(--ink-2); font-family: var(--mono); font-size: 11px;
}
.plano__norte { font-weight: 700; font-size: 13px !important; }
.plano__pie { margin: .5rem 0 0; line-height: 1.45; max-width: 60ch; }
/* El plano de un día entero es más ancho: abarca la ciudad, no un patio. */
/* El plano del día es la pantalla entera, no una ilustración al margen: abarca
   la ciudad y hay que distinguir puntos separados por metros. A 620 px ocupaba
   la mitad del panel y los fichajes eran cabezas de alfiler. */
.plano__lienzo--ancho { max-width: 760px; }

/* ==========================================================================
   El cubesheet
   ========================================================================== */
/* La barra de dictado. Todo el diseño de esta pantalla sale de una sola frase:
   quien mide una casa tiene el teléfono en una mano y no tiene la otra libre.
   La casilla del código es la más ancha y va primera porque es la única que se
   toca; la cantidad, la habitación y quién embala se quedan donde estaban entre
   línea y línea, así que se rellenan una vez por habitación y no por artículo. */
.dictado {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem;
  padding: .85rem 1rem; background: var(--surface-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.dictado label { display: flex; flex-direction: column; gap: .2rem; }
.dictado__etiqueta {
  font-size: .74rem; letter-spacing: .02em; text-transform: uppercase;
  color: var(--ink-3);
}
.dictado input, .dictado select { width: auto; }
/* En un teléfono la casilla del código ocupa la fila entera y las demás se
   reparten la siguiente: la alternativa es una casilla de cuatro dígitos de
   ancho, y el código se teclea sin mirar. */
.dictado__codigo { flex: 1 1 11rem; }
.dictado__codigo input {
  width: 100%; font-family: var(--mono); font-size: 1.15rem; font-weight: 600;
  min-height: 46px;
}
/* El texto de ejemplo no puede parecer un valor tecleado: en negrita y en
   monoespaciada, «302» se lee como una línea a punto de añadirse. */
.dictado__codigo input::placeholder { font-weight: 400; }
.dictado input[type="number"] { width: 5.5rem; min-height: 46px; }
.dictado select { min-height: 46px; }
.dictado .btn { min-height: 46px; }
/* La ayuda ocupa su propia línea completa y no empuja a los campos. */
.dictado__ayuda { flex: 1 1 100%; margin: 0; }

/* Los candidatos de un código que no resolvió. Botones y no texto: estando en
   casa del cliente, leer «quizá querías el 306» y tener que teclearlo es una
   gestión de más que se hace de pie. */
.candidatos { list-style: none; margin: .6rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.candidatos .btn { font-weight: 400; }
.candidatos strong { font-family: var(--mono); }

/* Una tabla de cuarenta líneas tiene que caber: filas más bajas y tipografía
   un punto menor, sin bajar de lo legible a un brazo de distancia. */
.table--compacta th, .table--compacta td { padding-top: .35rem; padding-bottom: .35rem; }
.table--compacta td { font-size: .87rem; }
/* Menos, más y quitar, juntos y en una sola línea: si se envolvieran, cada fila
   crecería y la tabla dejaría de leerse de un vistazo. */
.acciones { white-space: nowrap; }
.acciones .inline-form { display: inline-block; margin: 0; }
.acciones .btn { min-width: 34px; padding-left: .4rem; padding-right: .4rem; }
/* El botón de quitar la habitación, a la derecha del título y sin negrita: es
   una acción rara y no tiene por qué competir con el nombre de la habitación.
   Con flex y no flotando: flotándolo se metía encima de la cabecera de la tabla
   en cuanto la pantalla se estrechaba. */
.panel__title--con-accion {
  display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem;
}
.panel__accion { margin: 0; font-weight: 400; flex: 0 0 auto; }

/* En un teléfono la tabla deja de ser una tabla. Con seis columnas a 390 px, lo
   que queda fuera de la pantalla es justo lo que hace falta —los pies cúbicos y
   los botones de corregir la cantidad—, y una tabla que hay que arrastrar de
   lado con una mano ocupada no se usa. Cada línea pasa a ser un bloque: el
   artículo arriba, sus cifras debajo en pequeño, y los tres botones anclados a
   la derecha, siempre visibles. */
@media (max-width: 720px) {
  .table--compacta thead { display: none; }
  .table--compacta, .table--compacta tbody { display: block; }
  .table--compacta tr {
    display: block; position: relative; border-bottom: 1px solid var(--line);
    padding: .5rem 9rem .5rem 0;  /* los tres botones miden 129 px medidos */
  }
  .table--compacta tr:last-child { border-bottom: 0; }
  .table--compacta td {
    display: inline; border: 0; padding: 0; text-align: left; font-size: .82rem;
  }
  .table--compacta .linea__item { display: block; font-size: .9rem; }
  .table--compacta .linea__cuantos, .table--compacta .linea__pies,
  .table--compacta .linea__libras, .table--compacta .linea__embala {
    color: var(--ink-2); font-family: var(--mono); font-size: .76rem;
  }
  /* Las unidades las decía la cabecera, que aquí no está. Son símbolos, no
     palabras: no hay nada que traducir. */
  .table--compacta .linea__cuantos::before { content: "×"; }
  .table--compacta .linea__pies::after { content: " ft³ ·"; }
  .table--compacta .linea__libras::after { content: " lb ·"; }
  .table--compacta .linea__cuantos::after { content: " · "; }
  .table--compacta .acciones { position: absolute; right: 0; top: .45rem; }

  /* El catálogo, igual. Sus dos últimas columnas —la densidad, que es lo que
     delata un artículo mal medido, y las horas propias— son justo las que se
     quedaban fuera de la pantalla, así que la tabla no servía de referencia en
     el sitio donde se consulta: de pie, en casa de alguien. */
  .table--catalogo thead { display: none; }
  .table--catalogo, .table--catalogo tbody { display: block; }
  .table--catalogo tr {
    display: block; border-bottom: 1px solid var(--line); padding: .5rem 0;
  }
  .table--catalogo tr:last-child { border-bottom: 0; }
  .table--catalogo td {
    display: inline; border: 0; padding: 0; text-align: left;
  }
  .table--catalogo .cat__codigo { font-family: var(--mono); margin-right: .4rem; }
  .table--catalogo .cat__nombre { font-size: .9rem; }
  .table--catalogo .cat__nombre br { display: none; }
  .table--catalogo .cat__nombre .small { margin-left: .35rem; }
  .table--catalogo .cat__pies, .table--catalogo .cat__libras,
  .table--catalogo .cat__densidad {
    font-family: var(--mono); font-size: .76rem; color: var(--ink-2);
  }
  /* Un salto de línea de verdad antes de las cifras: en un bloque, «35.0» justo
     detrás del nombre se lee como parte del nombre. */
  .table--catalogo .cat__pies::before { content: "\A"; white-space: pre; }
  .table--catalogo .cat__pies::after { content: " ft³ · "; }
  .table--catalogo .cat__libras::after { content: " lb · "; }
  .table--catalogo .cat__densidad::after { content: " lb/ft³"; }
  .table--catalogo .cat__horas { display: block; margin-top: .25rem; }
  .table--catalogo .cat__horas .muted { display: none; }
}

/* La foto de una línea del cubesheet. Pequeña y al lado del nombre: es una
   prueba que se consulta, no una galería que se mira. */
.linea__foto { display: inline-flex; align-items: center; gap: .35rem; margin-left: .4rem; }
.linea__foto img {
  width: 34px; height: 34px; object-fit: cover; border-radius: var(--radius-sm);
  border: 1px solid var(--line); vertical-align: middle; display: block;
}
.linea__camara { display: inline-block; margin: 0 0 0 .4rem; }
/* La etiqueta es el botón: un `input[type=file]` desnudo se pinta distinto en
   cada navegador y en un teléfono sale minúsculo. El campo se esconde sin
   `display:none`, que en algunos lectores de pantalla lo saca del orden de
   tabulación. */
.linea__disparo { position: relative; display: inline-block; cursor: pointer; }
.linea__disparo input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;
}
.linea__disparo svg {
  width: 17px; height: 17px; display: block; vertical-align: middle;
  fill: none; stroke: var(--ink-3); stroke-width: 1.6;
  stroke-linejoin: round; stroke-linecap: round;
}
.linea__disparo:hover svg { stroke: var(--ink); }
/* El área táctil es mayor que el dibujo: en un teléfono, 17 px no se aciertan
   con el pulgar mientras se sujeta una puerta. */
.linea__disparo { padding: .3rem; margin: -.3rem 0 -.3rem .15rem; }
.linea__foto .btn { padding: .05rem .3rem; min-height: 0; line-height: 1.1; }

/* La trampa antispam del formulario público. Fuera de la pantalla y no
   `display:none`: algunos robots saltan lo que está oculto de la forma
   evidente, y este campo solo sirve si lo rellenan. */
.trampa {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

/* Una tabla ancha en un teléfono: cada fila pasa a ser un bloque y cada cifra
   lleva su nombre al lado. Con nueve columnas a 390 px se quedaban fuera justo
   las que deciden algo —la conversión, el coste y lo reservado—, y una tabla
   que hay que arrastrar de lado no se lee: se ignora.

   El nombre de cada cifra sale de `data-label`, que lo pone la plantilla y por
   tanto está traducido. Escribirlo aquí en `content:` lo dejaría en inglés para
   siempre. */
@media (max-width: 720px) {
  .table--etiquetada thead { display: none; }
  .table--etiquetada, .table--etiquetada tbody { display: block; }
  .table--etiquetada tr {
    display: block; padding: .6rem 0; border-bottom: 1px solid var(--line);
  }
  .table--etiquetada tr:last-child { border-bottom: 0; }
  .table--etiquetada td {
    display: flex; justify-content: space-between; gap: 1rem;
    border: 0; padding: .12rem 0; text-align: right; font-size: .85rem;
  }
  .table--etiquetada td::before {
    content: attr(data-label); color: var(--ink-3); font-size: .76rem;
    text-align: left; font-family: var(--font);
  }
  .table--etiquetada .etiquetada__titulo {
    display: block; text-align: left; font-weight: 650; margin-bottom: .25rem;
  }
  .table--etiquetada .etiquetada__titulo::before { content: none; }
  /* La celda de acciones no lleva nombre al lado: el botón ya dice qué hace, y
     una etiqueta vacía deja un hueco raro a la izquierda. */
  .table--etiquetada .etiquetada__accion { justify-content: flex-end; }
  .table--etiquetada .etiquetada__accion::before { content: none; }
}

/* Las opciones de cobertura: una lista de tarjetas con el precio a la derecha,
   y no un desplegable. Se venden enseñándolas juntas —el cliente compara la
   prima de cada franquicia con el ojo— y un desplegable esconde justo esa
   comparación. La recomendada lleva el borde del color de «bien». */
/* Las reglas de `form ul` de arriba las pintan como casillas en rejilla; aquí
   se vuelve a una columna, con la misma especificidad y después. */
.panel > form ul.opciones, .stack > form ul.opciones, form ul.opciones {
  list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr; gap: .5rem;
}
form ul.opciones li label, .opcion label {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: .7rem;
  align-items: center; cursor: pointer; font-size: .95rem; font-weight: 400;
  background: var(--surface); border: 1px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius); padding: .65rem .8rem;
}
.opcion.is-recomendada label { border-left-color: var(--good); }
.opcion.is-elegida label { background: var(--accent-soft); border-color: var(--accent); }
.opcion input[type=radio] { margin: 0; width: 1.05rem; height: 1.05rem; }
.opcion__cuerpo { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.opcion__nombre { font-weight: 600; display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.opcion__precio { font-variant-numeric: tabular-nums; font-size: 1.05rem; white-space: nowrap; }
.check { display: flex; gap: .5rem; align-items: flex-start; font-weight: 500; cursor: pointer; }
.check input { margin-top: .2rem; }

/* El buscador de direcciones de Google encima de la casilla: mismo alto y
   borde que un campo, para que se lea como «aquí se escribe la dirección» y
   la casilla de abajo como «y aquí queda». */
gmp-place-autocomplete.buscador-direccion {
  display: block; width: 100%; margin-bottom: .35rem;
  --gmp-mat-color-surface: var(--surface);
  --gmp-mat-color-on-surface: var(--ink);
  --gmp-mat-color-primary: var(--accent);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.daypicker gmp-place-autocomplete.buscador-direccion { width: auto; min-width: 16rem; margin: 0; }

/* ===========================================================================
   El portal del cliente
   ===========================================================================
   Una cifra grande, una frase que dice qué clase de promesa es, y el resto en
   paneles cortos. Se lee en un teléfono, desde un mensaje, por alguien que no
   ha visto Mov nunca. */
/* Una página más alta que la pantalla no se centra en vertical: un flex
   centrado con desbordamiento recorta la cabecera, y en un teléfono el total
   quedaría fuera del alcance del pulgar. */
.plain--largo { align-items: flex-start; }
.portal { max-width: 36rem; }
.portal__precio { text-align: center; }
.portal__total {
  margin: 0; font-size: 2.4rem; font-weight: 700; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.portal__tipo { margin: .1rem 0 .6rem; color: var(--ink-2); font-weight: 600; }
.portal__explica { margin: 0; color: var(--ink-2); line-height: 1.5; font-size: .92rem; }
.portal__datos { display: grid; grid-template-columns: auto 1fr; gap: .35rem .9rem; margin: 0; }
.portal__datos dt { color: var(--ink-3); font-size: .8rem; font-weight: 600; padding-top: .1rem; }
.portal__datos dd { margin: 0; }
.portal__tabla td { padding: .45rem .3rem; }
.portal__suma td { font-weight: 700; border-top: 2px solid var(--line-strong); }
.portal__terminos { font-size: .88rem; color: var(--ink-2); line-height: 1.55; max-height: 18rem; overflow: auto; }
.portal__iniciales { margin-top: .75rem; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; gap: .75rem; }
.portal__iniciales input { width: 7rem; max-width: 7rem; text-align: center; letter-spacing: .15em; font-weight: 600; }
.portal__lienzo {
  width: 100%; height: auto; touch-action: none; display: block; margin: .3rem 0;
  border: 1px dashed var(--line-strong); border-radius: var(--radius); background: var(--surface);
}
.portal__firma { max-width: 20rem; border-bottom: 1px solid var(--line-strong); }
/* Un fieldset sin caja: se usa para deshabilitar un formulario entero de una
   vez (una cotización firmada), no para dibujar un borde. */
fieldset.sin-borde { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset.sin-borde:disabled { opacity: .6; }

/* ===========================================================================
   La venta guiada: el carril y sus pasos
   ===========================================================================
   Un carril de siete píldoras que cabe en un teléfono sin envolver, y un panel
   por paso con una sola pregunta grande. */
.carril { display: flex; gap: .35rem; overflow-x: auto; padding: 0 0 .4rem; margin: 0 0 .8rem; scrollbar-width: none; }
.carril__paso {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: .4rem;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-2);
  border-radius: 999px; padding: .3rem .7rem .3rem .35rem; font-size: .8rem; text-decoration: none;
}
.carril__n { width: 1.25rem; height: 1.25rem; border-radius: 50%; background: var(--surface-3); display: grid; place-items: center; font-size: .7rem; font-weight: 700; }
.carril__paso.is-done { color: var(--ink); }
.carril__paso.is-done .carril__n { background: var(--good); color: var(--on-accent); }
.carril__paso.is-now { border-color: var(--accent); background: var(--accent-soft); color: var(--ink); }
.carril__paso.is-now .carril__n { background: var(--accent); color: var(--on-accent); }
.carril__paso.is-off { opacity: .5; }
.panel__why { margin: -.2rem 0 .9rem; color: var(--ink-3); font-size: .85rem; }
.venta__total { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; margin: 0 0 .6rem; }
.venta__total strong { font-size: 2rem; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.chip { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid var(--line-strong); background: var(--surface); border-radius: 999px; padding: .3rem .7rem; font-size: .88rem; cursor: pointer; }
.chip input[type=radio] { margin: 0; }
.chip:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); }
.chip--num input[type=number] { width: 3.2rem; min-height: 1.6rem; padding: .1rem .3rem; }
.estado { padding: .6rem .8rem; border-radius: var(--radius); background: var(--surface-3); font-size: .9rem; }
.estado--ok { background: var(--accent-soft); }
/* El botón grande de «Nueva venta» donde el teléfono suena: arriba del riel. */
.rail__cta { display: block; margin: .6rem .9rem .2rem; text-align: center; }

/* ===========================================================================
   Factura y cobro
   ===========================================================================
   El formulario de cobrar se rellena de pie con el cliente delante: tres
   campos en una fila que caben en un teléfono, y nada que haga scroll. */
.cobro__fila { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: .6rem; }
.cobro__fila .field { margin: 0; }
.detalle { margin: .6rem 0; }
.detalle > summary { cursor: pointer; color: var(--ink-2); font-size: .9rem; padding: .3rem 0; }
.detalle[open] > summary { margin-bottom: .5rem; }
.detalle--compacto > summary { font-size: .8rem; padding: 0; }
.detalle--compacto form { min-width: 12rem; text-align: left; }
/* La factura que ve el cliente: el mismo cuerpo que el portal, y al
   imprimir, solo la factura. */
.factura__cabecera { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; align-items: flex-start; }
.factura__num { font-size: .85rem; color: var(--ink-3); }
.factura__saldo { font-size: 1.6rem; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.factura__pagado { color: var(--good); }
@media print {
  .no-print { display: none !important; }
  body.plain { background: #fff; }
  .plain__box { box-shadow: none; border: 0; max-width: none; }
}
.lista { list-style: none; margin: 0; padding: 0; }
.lista li { padding: .45rem 0; border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; gap: .6rem; flex-wrap: wrap; }
.lista li:last-child { border-bottom: 0; }
.pasos { margin: 0 0 .8rem; padding-left: 1.2rem; }
.pasos li { margin: 0 0 .5rem; }
.pasos .field { margin-top: .4rem; }
/* Cotizado → facturado → cobrado: cuatro cifras en fila, con flechas entre
   ellas. Cabe en un teléfono porque se envuelve. */
.cadena { display: flex; flex-wrap: wrap; gap: .6rem 1.4rem; align-items: flex-start; }
.cadena__paso { display: flex; flex-direction: column; gap: .1rem; position: relative; min-width: 8rem; }
.cadena__paso + .cadena__paso::before { content: "→"; position: absolute; left: -1.1rem; top: 1.1rem; color: var(--ink-3); }
.cadena__label { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); }
.cadena__paso strong { font-size: 1.35rem; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
/* La ficha de un punto en el mapa de fichajes (globo de Google). */
.mapa__ficha { font: 400 .85rem/1.4 system-ui, sans-serif; color: #1a1a1a; max-width: 16rem; }
.mapa__ficha strong { font-weight: 700; }

/* ===========================================================================
   El calendario de capacidad (rediseño 1.26).

   Se lee de un vistazo y los números confirman: un medidor por día (firme,
   tentativo, sobreventa, libre), las horas libres como titular con lo que
   valen, la gente y los camiones como puntos, los trabajos como fichas y un
   cajón lateral con el detalle. Todo sale de los tokens de arriba, así que
   el modo oscuro y cualquier cambio de paleta llegan solos.
   =========================================================================== */
.cal-num { font-variant-numeric: tabular-nums lining-nums; letter-spacing: -.01em; font-family: var(--font); }

/* el conmutador de rango */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 999px; padding: 3px; background: var(--surface); }
.seg a { padding: .3rem .85rem; border-radius: 999px; color: var(--ink-2); text-decoration: none; font-weight: 500; font-size: .85rem; }
.seg a.is-on { background: var(--ink); color: var(--surface); }

/* las cuatro cifras */
.cal-kpis { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem; }
.cal-kpi { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 1.25rem 1.4rem; min-width: 0; }
.cal-kpi.is-attn .cal-kpi__value { color: var(--crit); }
.cal-kpi__label { margin: 0 0 .6rem; font-size: .78rem; color: var(--ink-3); letter-spacing: .02em; display: flex; justify-content: space-between; gap: .5rem; flex-wrap: wrap; }
.cal-kpi__value { margin: 0; font-size: 2.1rem; font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.cal-kpi__value small { font-size: .9rem; font-weight: 500; color: var(--ink-3); letter-spacing: 0; margin-left: .3rem; }
.cal-kpi__money { margin-left: .9rem; font-size: 1.25rem; font-weight: 500; color: var(--ink-2); }
.cal-kpi__sub { margin: .6rem 0 0; font-size: .78rem; color: var(--ink-2); line-height: 1.4; }
.cal-kpi__sub a { color: var(--accent); font-weight: 600; text-decoration: none; }
.cal-ribbon { display: flex; gap: 3px; height: 34px; align-items: flex-end; margin-top: .9rem; }
.cal-ribbon i { flex: 1; height: 100%; border-radius: 3px 3px 0 0; background: var(--surface-2); position: relative; overflow: hidden; }
.cal-ribbon i b { position: absolute; left: 0; right: 0; bottom: 0; background: var(--accent); }
.cal-ribbon i.is-t b { background: var(--warn); }
.cal-ribbon i.is-today { outline: 2px solid var(--ink); outline-offset: 1px; }
.cal-legend { display: flex; gap: 1rem; font-size: .75rem; color: var(--ink-2); margin: .7rem 0 0; flex-wrap: wrap; }
.cal-legend span { display: inline-flex; align-items: center; gap: .35rem; }
.cal-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.cal-legend .is-bk, .cal-meter .is-bk { background: var(--accent); }
.cal-legend .is-tt, .cal-meter .is-tt { background: repeating-linear-gradient(135deg, var(--warn) 0 4px, var(--warn-soft) 4px 8px); }
.cal-legend .is-op { background: var(--surface-2); }
.cal-legend .is-ov, .cal-meter .is-ov { background: var(--crit); }
.cal-donut { float: right; width: 60px; height: 60px; border-radius: 50%; margin: -.3rem 0 0 .5rem;
  background: conic-gradient(var(--accent) 0 var(--p), var(--surface-2) var(--p) 100%); display: grid; place-items: center; }
.cal-donut b { width: 42px; height: 42px; border-radius: 50%; background: var(--surface); display: grid; place-items: center; font-size: .75rem; font-weight: 600; }

/* la semana */
.cal-week { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; margin-bottom: 1.25rem; overflow: hidden; }
.cal-week > header { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: .9rem 1.4rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.cal-week > header h2 { margin: 0; font-size: .98rem; font-weight: 600; letter-spacing: -.01em; }
.cal-week__meta { color: var(--ink-3); font-size: .82rem; }
.cal-week__meta b { color: var(--ink); font-weight: 600; }
.cal-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.cal-day { padding: .9rem 1rem 1rem; border-right: 1px solid var(--line); min-height: 15rem; min-width: 0; position: relative; cursor: pointer; transition: background .15s; }
.cal-day:last-child { border-right: 0; }
.cal-day:hover, .cal-day:focus-visible { background: var(--surface-3); outline: none; }
.cal-day.is-weekend { background: var(--surface-3); }
.cal-day.is-past { opacity: .55; }
.cal-day.is-selected { box-shadow: inset 0 0 0 2px var(--ink); }
.cal-day__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: .7rem; }
.cal-day__name { font-weight: 600; font-size: .9rem; }
.cal-day__name small { color: var(--ink-3); font-weight: 500; margin-left: .2rem; }
.cal-day.is-today .cal-day__name { color: var(--accent); }
.cal-day.is-today .cal-day__name::after { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); margin-left: .4rem; vertical-align: middle; }
.cal-flag { width: 7px; height: 7px; border-radius: 50%; background: var(--crit); box-shadow: 0 0 0 3px var(--crit-soft); }
.cal-meter { height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; display: flex; }
.cal-meter b { display: block; height: 100%; }
.cal-open { margin: .7rem 0 0; display: flex; align-items: baseline; gap: .35rem; }
.cal-open__h { font-size: 1.45rem; font-weight: 600; letter-spacing: -.03em; }
.cal-open__u { font-size: .75rem; color: var(--ink-3); }
.cal-money { margin: .1rem 0 0; font-size: .76rem; color: var(--ink-2); }
.cal-open.is-full .cal-open__h { color: var(--ink-3); font-weight: 500; font-size: 1.1rem; }
.cal-open.is-over .cal-open__h { color: var(--crit); }
.cal-row { display: flex; justify-content: space-between; gap: .5rem; margin: .35rem 0 0; font-size: .74rem; color: var(--ink-3); flex-wrap: wrap; }
.cal-row b { color: var(--ink-2); font-weight: 500; }
.cal-row.is-tt { color: var(--warn); }
.cal-res { display: flex; gap: .7rem; margin: .7rem 0 0; flex-wrap: wrap; }
.cal-res > span { display: inline-flex; align-items: center; gap: .35rem; font-size: .74rem; color: var(--ink-2); }
.cal-dots { display: inline-flex; gap: 2px; }
.cal-dots i { width: 7px; height: 7px; border-radius: 2px; background: var(--surface-2); }
.cal-dots i.on { background: var(--ink-2); }
.cal-dots i.short { background: var(--crit); }
.cal-dotrow { display: none; }
.cal-jobs { margin: .7rem 0 0; display: grid; gap: .35rem; }
.cal-chip { display: grid; grid-template-columns: 1fr auto; gap: .1rem .5rem; align-items: center; padding: .45rem .6rem; border-radius: 8px;
  background: var(--accent-soft); border-left: 3px solid var(--accent); font-size: .76rem; color: var(--ink); text-decoration: none; min-width: 0; }
.cal-chip:hover { filter: brightness(.98); }
.cal-chip.is-tentative { background: var(--warn-soft); border-left-color: var(--warn); }
.cal-chip.is-quoted { background: var(--surface-2); border-left-color: var(--line-strong); }
.cal-chip__tm { font-weight: 600; white-space: nowrap; }
.cal-chip__st { color: var(--ink-3); white-space: nowrap; font-size: .72rem; }
.cal-chip.is-unconfirmed .cal-chip__st { color: var(--crit); font-weight: 600; }
.cal-chip__nm { grid-column: 1 / -1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--ink-2); }
.cal-chip__cr { grid-column: 1 / -1; font-size: .7rem; color: var(--ink-3); }
.cal-empty { margin: .8rem 0 0; font-size: .76rem; color: var(--ink-3); }
.cal-empty a { color: var(--accent); font-weight: 600; text-decoration: none; }

/* cuatro semanas: el mismo componente, sin fichas */
.cal--month .cal-day { min-height: 9.5rem; }
.cal--month .cal-jobs, .cal--month .cal-res, .cal--month .cal-empty__nb { display: none; }
.cal--month .cal-dotrow { display: flex; gap: 3px; margin: .6rem 0 0; }
.cal-dotrow i { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.cal-dotrow i.is-t { background: var(--warn); }

/* el cajón del día */
.cal-scrim { position: fixed; inset: 0; background: rgb(20 22 21 / 18%); z-index: 40; }
.cal-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 100vw); background: var(--surface); border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lift); transform: translateX(100%); transition: transform .22s ease; padding: 1.75rem; overflow: auto; z-index: 50; }
.cal-drawer.is-open { transform: none; }
.cal-drawer__x { position: absolute; top: 1rem; right: 1rem; }
.cal-drawer h3 { margin: 0 2.5rem 0 0; font-size: 1.35rem; letter-spacing: -.02em; font-weight: 600; }
.cal-drawer__big { font-size: 2.5rem; font-weight: 600; letter-spacing: -.03em; margin: 1rem 0 .1rem; }
.cal-drawer__big .is-over { color: var(--crit); }
.cal-drawer__mut { color: var(--ink-3); font-size: .85rem; margin: 0; }
.cal-drawer__block { margin-top: 1.4rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.cal-drawer__block h4 { margin: 0 0 .6rem; font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); font-weight: 600; }
.cal-drawer__block .is-attn { color: var(--crit); font-weight: 500; margin: 0; }
.cal-kv { display: grid; grid-template-columns: 1fr auto; gap: .35rem .8rem; font-size: .85rem; margin: 0; }
.cal-kv dt { color: var(--ink-2); } .cal-kv dd { margin: 0; font-weight: 500; text-align: right; }
.cal-jobrow { display: grid; grid-template-columns: 3.2rem 1fr auto; gap: .6rem; align-items: center; padding: .6rem 0; border-bottom: 1px solid var(--line); font-size: .85rem; color: var(--ink); text-decoration: none; }
.cal-jobrow:last-of-type { border-bottom: 0; }
.cal-jobrow small { display: block; color: var(--ink-3); font-size: .75rem; }
.cal-drawer__actions { display: flex; gap: .5rem; margin-top: 1.4rem; flex-wrap: wrap; }

@media (max-width: 1100px) { .cal-kpis { grid-template-columns: 1fr 1fr; } }
@media (max-width: 900px) { .cal-days { grid-template-columns: repeat(2, minmax(0, 1fr)); } .cal-day { border-bottom: 1px solid var(--line); } }
@media (max-width: 520px) { .cal-days { grid-template-columns: 1fr; } .cal-kpis { grid-template-columns: 1fr; } }
@media print { .cal-drawer, .cal-scrim { display: none !important; } }

/* ===========================================================================
   «Hoy», rediseñado (1.27): tres números, una tira, dos columnas y la semana.
   Hereda los tokens y las piezas del calendario (.cal-meter, .cal-num).
   =========================================================================== */
.td-hero { display: grid; grid-template-columns: 1.35fr 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
.td-k { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; padding: 1.3rem 1.5rem; min-width: 0; }
.td-k__label { margin: 0 0 .6rem; font-size: .78rem; color: var(--ink-3); letter-spacing: .02em; display: flex; justify-content: space-between; gap: .5rem; flex-wrap: wrap; }
.td-k__value { margin: 0; font-size: 2.5rem; font-weight: 600; letter-spacing: -.035em; line-height: 1; }
.td-k.is-crit .td-k__value { color: var(--crit); }
.td-k.is-warn .td-k__value { color: var(--warn); }
.td-k.is-ok .td-k__value { color: var(--good); }
.td-k__sub { margin: .7rem 0 0; font-size: .78rem; color: var(--ink-2); line-height: 1.45; }
.td-k__sub a { color: var(--accent); font-weight: 600; text-decoration: none; }
.td-bars { margin-top: .9rem; display: grid; gap: .4rem; }
.td-bars > div { display: grid; grid-template-columns: 4rem 1fr 4.5rem; align-items: center; gap: .6rem; font-size: .76rem; color: var(--ink-2); }
.td-bars i { height: 8px; border-radius: 999px; background: var(--surface-2); overflow: hidden; display: block; }
.td-bars i b { display: block; height: 100%; background: var(--ink-3); }
.td-bars .is-bill i b { background: var(--accent); }
.td-bars .is-lost i b { background: var(--crit); }
.td-bars > div > span:last-child { text-align: right; font-weight: 600; color: var(--ink); }

.td-strip { display: grid; grid-template-columns: repeat(6, 1fr); gap: .75rem; margin-bottom: 1.5rem; }
.td-s { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: .85rem 1rem; min-width: 0; }
.td-s__label { margin: 0 0 .35rem; font-size: .7rem; color: var(--ink-3); letter-spacing: .02em; }
.td-s__value { margin: 0; font-size: 1.25rem; font-weight: 600; letter-spacing: -.02em; }
.td-s__sub { margin: .25rem 0 0; font-size: .7rem; color: var(--ink-3); }
.td-s.is-warn .td-s__value { color: var(--warn); }

.td-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 1rem; margin-bottom: 1rem; }
.td-p { margin: 0; }
.td-p__title { margin: 0 0 .9rem; font-size: .98rem; font-weight: 600; letter-spacing: -.01em; display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.td-p__title span { font-size: .76rem; color: var(--ink-3); font-weight: 500; }
.td-p__title span a { color: var(--accent); text-decoration: none; font-weight: 600; }
.td-meter { height: 10px; }
.td-meter .is-1 { background: var(--data-1); } .td-meter .is-2 { background: var(--data-2); }
.td-meter .is-3 { background: var(--data-3); } .td-meter .is-4 { background: var(--data-4); }
.td-legend { display: grid; grid-template-columns: repeat(4, 1fr); gap: .5rem; margin-top: .9rem; }
.td-legend > div { font-size: .76rem; color: var(--ink-2); }
.td-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: .4rem; vertical-align: -1px; }
.td-legend .is-1 { background: var(--data-1); } .td-legend .is-2 { background: var(--data-2); }
.td-legend .is-3 { background: var(--data-3); } .td-legend .is-4 { background: var(--data-4); }
.td-legend b { display: block; font-size: 1.05rem; color: var(--ink); font-weight: 600; letter-spacing: -.02em; margin-top: .1rem; }
.td-legend b span { font-size: .72rem; color: var(--ink-3); font-weight: 500; }

.td-who { display: grid; gap: .6rem; }
.td-who > div { display: grid; grid-template-columns: auto 1fr auto; gap: .7rem; align-items: center; font-size: .85rem; }
.td-who small { display: block; color: var(--ink-3); font-size: .75rem; }
.td-who small a { color: inherit; }
.td-who__t { font-weight: 600; }
.td-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--data-4); }
.td-dot.is-site { background: var(--accent); animation: td-pulse 1.8s infinite; }
.td-dot.is-travel { background: var(--data-2); }
.td-dot.is-yard { background: var(--data-3); }
@keyframes td-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); } 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (prefers-reduced-motion: reduce) { .td-dot.is-site { animation: none; } }

.td-jobs { display: grid; gap: .5rem; }
.td-job { display: grid; grid-template-columns: 3.2rem 1fr 10rem auto; gap: .9rem; align-items: center; padding: .75rem .9rem; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-3); color: var(--ink); text-decoration: none; min-width: 0; }
.td-job:hover { border-color: var(--line-strong); }
.td-job__tm { font-weight: 600; }
.td-job__nm { min-width: 0; }
.td-job__nm small { display: block; color: var(--ink-3); font-size: .74rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.td-job__prog i { display: block; height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.td-job__prog i b { display: block; height: 100%; background: var(--accent); }
.td-job__prog small { display: block; font-size: .68rem; color: var(--ink-3); margin-top: .25rem; text-align: right; white-space: nowrap; }
.tag--done { background: var(--surface-2); color: var(--ink-2); }
.tag--quiet { background: transparent; border: 1px solid var(--line-strong); color: var(--ink-2); }

.td-hum { display: grid; gap: .5rem; }
.td-hum > div { display: grid; grid-template-columns: 4px 1fr auto auto auto; gap: .8rem; align-items: center; padding: .7rem .85rem; border: 1px solid var(--line); border-radius: 12px; font-size: .85rem; }
.td-hum i { display: block; width: 4px; height: 100%; min-height: 2.2rem; border-radius: 2px; background: var(--crit); }
.td-hum .is-warn i { background: var(--warn); }
.td-hum__k { min-width: 0; }
.td-hum__k small { display: block; color: var(--ink-3); font-size: .74rem; }
.td-hum__n { font-weight: 600; }
.td-hum__money { font-weight: 600; color: var(--money); background: var(--money-soft); padding: .15rem .6rem; border-radius: 999px; font-size: .74rem; }
.td-hum__act { font-size: .76rem; font-weight: 600; color: var(--accent); text-decoration: none; }
.td-empty { margin: 0; font-size: .85rem; color: var(--ink-3); }
.td-empty.is-ok { color: var(--good); }
.td-empty a { color: var(--accent); font-weight: 600; text-decoration: none; }

.td-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: .5rem; }
.td-wd { display: block; border: 1px solid var(--line); border-radius: 12px; padding: .75rem .75rem .6rem; background: var(--surface); color: var(--ink); text-decoration: none; min-width: 0; }
.td-wd:hover { border-color: var(--line-strong); }
.td-wd.is-today { border-color: var(--ink); }
.td-wd > span { display: block; }
.td-wd__d { font-size: .74rem; color: var(--ink-3); display: flex !important; justify-content: space-between; }
.td-wd__d b { color: var(--ink); }
.td-wd__m { height: 6px; border-radius: 999px; background: var(--surface-2); margin: .6rem 0 .5rem; overflow: hidden; }
.td-wd__m b { display: block; height: 100%; background: var(--accent); }
.td-wd__m b.is-over { background: var(--crit); }
.td-wd__h { font-size: .9rem; font-weight: 600; letter-spacing: -.02em; }
.td-wd__h small { font-size: .7rem; color: var(--ink-3); font-weight: 500; margin-left: .15rem; }

@media (max-width: 1100px) { .td-hero, .td-grid { grid-template-columns: 1fr; } .td-strip { grid-template-columns: repeat(3, 1fr); } .td-week { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 600px) { .td-strip { grid-template-columns: repeat(2, 1fr); } .td-legend { grid-template-columns: repeat(2, 1fr); } .td-job { grid-template-columns: 3rem 1fr; } .td-job__prog, .td-job .tag { grid-column: 1 / -1; } }

/* ===========================================================================
   Despacho (rediseño 1.28): el día como un tablero por camión.
   =========================================================================== */
.dp-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: .75rem; margin-bottom: 1.25rem; }
.dp-s { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: .85rem 1rem; display: flex; align-items: center; gap: .8rem; min-width: 0; }
.dp-s__v { font-size: 1.7rem; font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.dp-s__v small { font-size: .9rem; color: var(--ink-3); font-weight: 500; }
.dp-s__l { font-size: .78rem; color: var(--ink-2); line-height: 1.3; min-width: 0; }
.dp-s__l small { display: block; color: var(--ink-3); font-size: .7rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dp-s.is-ok .dp-s__v { color: var(--good); } .dp-s.is-crit .dp-s__v { color: var(--crit); } .dp-s.is-warn .dp-s__v { color: var(--warn); }

.dp-board { background: var(--surface); border: 1px solid var(--line); border-radius: 16px; overflow: hidden; margin-bottom: 1rem; }
.dp-board > header { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: .9rem 1.4rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.dp-board > header h2 { margin: 0; font-size: .98rem; font-weight: 600; }
.dp-board > header span { font-size: .76rem; color: var(--ink-3); }
.dp-tl { display: grid; grid-template-columns: 11rem 1fr; }
.dp-tl__corner, .dp-lab { border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.dp-tl__hours { display: grid; grid-template-columns: repeat(var(--cols), 1fr); font-size: .7rem; color: var(--ink-3); padding: .5rem 0 .4rem; border-bottom: 1px solid var(--line); }
.dp-tl__hours span { padding-left: .5rem; }
.dp-lab { padding: .85rem 1.1rem; display: flex; flex-direction: column; justify-content: center; gap: .1rem; min-height: 4.9rem; }
.dp-lab b { font-size: .9rem; }
.dp-lab small { color: var(--ink-3); font-size: .72rem; }
.dp-lab__st { display: inline-flex; align-items: center; gap: .35rem; font-size: .7rem; font-weight: 600; color: var(--ink-3); margin-top: .15rem; }
.dp-lab__st i { width: 7px; height: 7px; border-radius: 50%; background: var(--line-strong); }
.dp-lab__st.is-ok { color: var(--good); } .dp-lab__st.is-ok i { background: var(--good); }
.dp-lab__st.is-blocked { color: var(--crit); } .dp-lab__st.is-blocked i { background: var(--crit); }
.dp-lane { position: relative; border-bottom: 1px solid var(--line); min-height: 4.9rem;
  background: repeating-linear-gradient(90deg, transparent 0 calc(100% / var(--cols) - 1px), var(--line) calc(100% / var(--cols) - 1px) calc(100% / var(--cols))); }
.dp-lane.is-unassigned { background-color: var(--surface-3); }
.dp-now { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--ink); opacity: .55; z-index: 2; pointer-events: none; }
.dp-now span { position: absolute; top: 3px; left: 5px; font-size: .62rem; font-weight: 600; color: var(--ink); }
.dp-bar { position: absolute; top: .55rem; height: 3.8rem; border-radius: 9px; background: var(--accent-soft); border-left: 4px solid var(--accent);
  padding: .4rem .6rem; display: grid; grid-template-columns: 1fr auto; gap: .1rem .5rem; align-content: start; font-size: .74rem; color: var(--ink);
  text-decoration: none; overflow: hidden; box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 12%, transparent); z-index: 1; }
.dp-bar:hover { box-shadow: var(--shadow-lift); z-index: 3; }
.dp-bar > b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
.dp-bar__st { font-size: .68rem; color: var(--ink-3); white-space: nowrap; }
.dp-bar__cr { grid-column: 1 / -1; display: flex; gap: .25rem; align-items: center; font-size: .68rem; color: var(--ink-2); white-space: nowrap; overflow: hidden; }
.dp-bar__cr i { display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--surface); border: 1px solid var(--line-strong); font-size: .55rem; font-weight: 700; font-style: normal; color: var(--ink-2); flex: none; }
.dp-bar__cr i.is-ok { border-color: var(--good); color: var(--good); }
.dp-bar__cr i.is-no { border-color: var(--crit); color: var(--crit); border-style: dashed; }
.dp-bar__prog { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: color-mix(in srgb, var(--accent) 15%, transparent); }
.dp-bar__prog b { display: block; height: 100%; background: var(--accent); }
.dp-bar.is-live { background: color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 12%); }
.dp-bar.is-done { background: var(--surface-2); border-left-color: var(--ink-3); }
.dp-bar.is-done .dp-bar__prog b { background: var(--ink-3); }
.dp-bar.is-warn { background: var(--warn-soft); border-left-color: var(--warn); }
.dp-bar.is-blocked { background: var(--crit-soft); border-left-color: var(--crit); }
.dp-bar.is-booked { background: transparent; border: 1px dashed var(--line-strong); border-left: 4px solid var(--line-strong); box-shadow: none; }
.dp-drop { position: absolute; inset: .6rem .75rem; border: 1px dashed var(--line-2, var(--line-strong)); border-radius: 9px; display: grid; place-items: center; font-size: .74rem; color: var(--ink-3); }
.dp-empty { margin: 0; padding: 1rem 1.4rem; font-size: .85rem; color: var(--ink-3); }

.dp-cols { display: grid; grid-template-columns: 1fr 24rem; gap: 1rem; margin-bottom: 1rem; }
.dp-p { margin: 0; }
.dp-att { display: grid; gap: .5rem; }
.dp-att > div { display: grid; grid-template-columns: 4px 1fr auto; gap: .8rem; align-items: center; padding: .65rem .8rem; border: 1px solid var(--line); border-radius: 10px; font-size: .85rem; }
.dp-att i { width: 4px; min-height: 2.2rem; border-radius: 2px; background: var(--crit); }
.dp-att .is-warn i { background: var(--warn); } .dp-att .is-ok i { background: var(--good); }
.dp-att small { display: block; color: var(--ink-3); font-size: .74rem; }
.dp-att b a { color: inherit; text-decoration: none; }
.dp-att > div > a { font-size: .76rem; font-weight: 600; color: var(--accent); text-decoration: none; white-space: nowrap; }
.dp-crew { display: grid; }
.dp-crew > div { display: grid; grid-template-columns: 26px 1fr auto; gap: .7rem; align-items: center; font-size: .85rem; padding: .45rem 0; border-bottom: 1px solid var(--line); }
.dp-crew > div:last-child { border-bottom: 0; }
.dp-crew i { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--surface-2); font-size: .6rem; font-weight: 700; font-style: normal; color: var(--ink-2); }
.dp-crew small { display: block; color: var(--ink-3); font-size: .72rem; }
.dp-wd__r { display: block; margin-top: .35rem; font-size: .68rem; color: var(--ink-3); }
.dp-wd__r b { color: var(--ink-2); font-weight: 500; }
.dp-wd__r b.is-bad { color: var(--crit); font-weight: 600; }

@media (max-width: 1100px) { .dp-strip { grid-template-columns: repeat(3, 1fr); } .dp-cols { grid-template-columns: 1fr; } .dp-tl { grid-template-columns: 7.5rem 1fr; } }
@media (max-width: 600px) { .dp-strip { grid-template-columns: repeat(2, 1fr); } .dp-tl { grid-template-columns: 5.5rem 1fr; } .dp-bar__cr { display: none; } }

/* ===========================================================================
   Horas (rediseño 1.29): una fila-tarjeta por persona con el medidor de su
   jornada, la semana contra las 40 y las excepciones como píldoras.
   =========================================================================== */
.hr-strip { grid-template-columns: repeat(5, 1fr); }
.hr-head, .hr-row { display: grid; grid-template-columns: 11rem 1.4fr 8rem 7.5rem 1.2fr auto; gap: 1rem; align-items: center; }
.hr-head { padding: 0 1.1rem .4rem; font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.hr-right { text-align: right; }
.hr-rows { display: grid; gap: .5rem; }
.hr-row { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: .8rem 1.1rem; min-width: 0; }
.hr-row.is-critical { border-left: 4px solid var(--crit); padding-left: calc(1.1rem - 3px); }
.hr-row.is-approved { opacity: .72; }
.hr-who a { color: var(--ink); text-decoration: none; font-size: .9rem; }
.hr-who small { display: block; color: var(--ink-3); font-size: .72rem; margin-top: .1rem; }
.hr-meter { height: 8px; }
.hr-meter .is-site, .hr-shift small .is-site, .hr-legend .is-site { background: var(--data-1); }
.hr-meter .is-travel, .hr-shift small .is-travel, .hr-legend .is-travel { background: var(--data-2); }
.hr-meter .is-yard, .hr-shift small .is-yard, .hr-legend .is-yard { background: var(--data-3); }
.hr-meter .is-break, .hr-shift small .is-break, .hr-legend .is-break { background: var(--data-4); }
.hr-shift small { display: flex; gap: .7rem; margin-top: .35rem; font-size: .7rem; color: var(--ink-3); flex-wrap: wrap; }
.hr-shift small i { display: inline-block; width: 7px; height: 7px; border-radius: 2px; margin-right: .3rem; vertical-align: 0; }
.hr-shift small .is-ot { color: var(--warn); font-weight: 600; }
.hr-hours { text-align: right; }
.hr-hours b { font-size: 1.15rem; font-weight: 600; letter-spacing: -.02em; }
.hr-hours small { display: block; color: var(--ink-3); font-size: .7rem; }
.hr-hours .is-lost { color: var(--warn); }
.hr-week__bar { display: block; height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.hr-week__bar b { display: block; height: 100%; background: var(--accent); }
.hr-week__bar b.is-over { background: var(--crit); }
.hr-week small { display: block; font-size: .7rem; color: var(--ink-2); margin-top: .3rem; font-weight: 600; }
.hr-week small span { color: var(--ink-3); font-weight: 400; }
.hr-exc { display: flex; flex-wrap: wrap; gap: .3rem; min-width: 0; }
.hr-pill { font-size: .7rem; padding: .2rem .55rem; border-radius: 999px; background: var(--surface-2); color: var(--ink-2); text-decoration: none; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.hr-pill.is-critical { background: var(--crit-soft); color: var(--crit); font-weight: 600; }
.hr-pill.is-warn { background: var(--warn-soft); color: var(--warn); font-weight: 600; }
.hr-clean { font-size: .72rem; color: var(--good); font-weight: 600; }
.hr-act { display: flex; gap: .35rem; align-items: center; justify-content: flex-end; }
.hr-ok { font-size: .76rem; color: var(--good); font-weight: 600; white-space: nowrap; }
.hr-legend { display: flex; gap: 1rem; margin: .8rem .2rem 0; font-size: .72rem; color: var(--ink-3); flex-wrap: wrap; }
.hr-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: .35rem; vertical-align: -1px; }
@media (max-width: 1100px) { .hr-head { display: none; } .hr-row { grid-template-columns: 1fr 1fr; } .hr-shift { grid-column: 1 / -1; } .hr-exc { grid-column: 1 / -1; } .hr-strip { grid-template-columns: repeat(3, 1fr); } }

/* ===========================================================================
   Mi día (rediseño 1.29): el reloj con el color del segmento y el tiempo
   latiendo, el trabajo como ruta de dos paradas, «Voy» como un gran botón.
   =========================================================================== */
.clock { border-top: 4px solid var(--line-strong); }
.clock--site { border-top-color: var(--accent); }
.clock--travel { border-top-color: var(--data-2); }
.clock--yard { border-top-color: var(--data-3); }
.clock--break { border-top-color: var(--data-4); }
.clockhead__state { margin: .25rem 0 0; font-size: .85rem; color: var(--ink-2); display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.clockhead__state b { color: var(--ink); font-weight: 600; }
.clockhead__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); flex: none; }
.clock--site .clockhead__dot { background: var(--accent); animation: td-pulse 1.8s infinite; }
.clock--travel .clockhead__dot { background: var(--data-2); }
.clock--yard .clockhead__dot { background: var(--data-3); }
.clock--break .clockhead__dot { background: var(--data-4); }
.clockhead__since { font-weight: 600; color: var(--ink); }
.clockhead__hours { font-size: 1.6rem; font-weight: 600; letter-spacing: -.03em; line-height: 1; margin: 0; }

.md-job__head { display: grid; grid-template-columns: auto 1fr; gap: 1rem; align-items: start; margin-bottom: .9rem; }
.md-job__time { margin: 0; font-size: 2rem; font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.md-job__arrival { margin: .3rem 0 0; font-size: .74rem; color: var(--ink-3); white-space: nowrap; }
.md-job__who .panel__title { margin: 0 0 .35rem; }
.md-job__tags { margin: 0; display: flex; gap: .3rem; flex-wrap: wrap; }
.md-route { list-style: none; margin: 0 0 .9rem; padding: 0 0 0 1.2rem; position: relative; }
.md-route::before { content: ""; position: absolute; left: .3rem; top: .6rem; bottom: .9rem; width: 2px; background: var(--line-strong); }
.md-route li { position: relative; padding: 0 0 .9rem; }
.md-route li::before { content: ""; position: absolute; left: -1.2rem; top: .35rem; width: 10px; height: 10px; border-radius: 50%; background: var(--surface); border: 2px solid var(--accent); }
.md-route li:last-child::before { background: var(--accent); }
.md-route__lbl { display: block; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.md-route b { display: block; font-size: 1rem; font-weight: 600; }
.md-route small { display: block; color: var(--ink-3); font-size: .78rem; }
.md-route__go { display: inline-block; margin-top: .3rem; font-size: .76rem; font-weight: 600; color: var(--accent); text-decoration: none; }
.md-crew { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; font-size: .85rem; }
.md-crew__lbl { font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin-right: .2rem; }
.md-mate { display: inline-flex; align-items: center; gap: .4rem; }
.md-mate i { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--surface-2); font-size: .7rem; font-weight: 700; font-style: normal; color: var(--ink-2); }
.md-mate small { color: var(--ink-3); }
.md-call { margin-left: auto; }
.md-empty { text-align: center; padding: 2rem 1rem; }
.md-empty__t { margin: 0 0 .25rem; font-size: 1.05rem; font-weight: 600; }
.md-h { font-size: 1rem; font-weight: 600; margin: 1.4rem 0 .6rem; letter-spacing: -.01em; }
.md-h span { color: var(--ink-3); font-weight: 500; }
.md-tmrw.is-ok { border-left: 4px solid var(--good); }
.md-tmrw h3 { margin: .2rem 0; font-size: 1rem; font-weight: 600; }
.md-coming { margin: .6rem 0 0; font-weight: 600; }
.md-coming.is-ok { color: var(--good); }
.md-coming__btn { width: 100%; }
@media (max-width: 520px) { .md-job__head { grid-template-columns: 1fr; gap: .3rem; } .md-call { margin-left: 0; width: 100%; justify-content: center; } }

/* Matriz de campo (entrega 1.10): una casilla grande por rol y capacidad. */
.center { text-align: center; }
.matriz th.center { width: 7rem; }
.matriz__casilla { display: inline-flex; padding: .5rem; cursor: pointer; }
.matriz__casilla input { width: 1.4rem; height: 1.4rem; accent-color: var(--accent, #2563eb); }
.matriz tr.is-changed td:first-child { box-shadow: inset 3px 0 0 var(--accent, #2563eb); }

/* Fichajes sustituidos por una corrección: siguen a la vista, tachados. */
tr.is-superseded td { text-decoration: line-through; color: var(--muted, #6b7280); }
tr.is-superseded td .tag { text-decoration: none; }

/* ===========================================================================
   El portal del cliente (1.30): la cotización y «Your move» en el teléfono
   ===========================================================================
   Una columna, una cifra o una frase grande, pasos que se leen de un vistazo.
   El cliente no conoce Mov: nada aquí puede necesitar explicación. */
.pt-body { align-items: flex-start; padding-top: 1.25rem; }
.pt { padding-bottom: 5.5rem; }
.pt .panel { padding: 1.1rem 1.1rem; }
.pt .panel__title { font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); margin-bottom: .7rem; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.pt-head { display: grid; grid-template-columns: auto 1fr; gap: .4rem .85rem; align-items: center; }
.pt-head .plain__mark { margin: 0; width: 2.75rem; height: 2.75rem; border-radius: 11px; }
.pt-head h1 { margin: 0; font-size: 1.3rem; letter-spacing: -.015em; }
.pt-eyebrow { margin: 0; font-size: .75rem; font-weight: 600; color: var(--ink-3); letter-spacing: .04em; text-transform: uppercase; }
.pt-meta { margin: .15rem 0 0; font-size: .82rem; color: var(--ink-3); }
.pt-status {
  grid-column: 1 / -1; justify-self: start; display: inline-flex; align-items: center; gap: .4rem;
  border-radius: 999px; padding: .3rem .75rem; font-size: .78rem; font-weight: 600;
  background: var(--warn-soft); color: var(--ink);
}
.pt-status.is-signed { background: var(--good-soft); }
.pt-status--travel { background: var(--data-2, var(--accent-soft)); color: var(--on-accent, #fff); }
.pt-status--live { background: var(--good); color: var(--on-accent); }
.pt-status--quiet { background: var(--surface-3); }
.pt-live { width: .5rem; height: .5rem; border-radius: 50%; background: currentColor; animation: pt-pulse 1.4s ease-in-out infinite; }
@keyframes pt-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } }
@media (min-width: 30rem) {
  .pt-head { grid-template-columns: auto 1fr auto; }
  .pt-status { grid-column: auto; }
}
.pt-callout { margin-top: 1rem; }

/* El precio / la frase grande */
.pt-price { text-align: center; padding: 1.5rem 1.1rem 1.25rem; }
.pt-price__label { margin: 0; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.pt-price__total { margin: .2rem 0 0; font-size: 2.8rem; font-weight: 700; letter-spacing: -.035em; line-height: 1.05; }
.pt-price__type { margin: .35rem 0 0; font-weight: 600; color: var(--ink-2); }
.pt-price__explain { margin: .6rem auto 0; max-width: 28rem; color: var(--ink-2); line-height: 1.5; font-size: .9rem; }
.pt-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.pt-facts div { display: grid; gap: .1rem; }
.pt-facts b { font-size: 1.05rem; letter-spacing: -.01em; }
.pt-facts small { color: var(--ink-3); font-size: .72rem; line-height: 1.3; }
.pt-hero__h { font-size: 1.9rem; letter-spacing: -.02em; }
.pt-hero--live { box-shadow: inset 0 3px 0 var(--good); }
.pt-hero--travel { box-shadow: inset 0 3px 0 var(--data-2, var(--accent)); }
.pt-hero--done { box-shadow: inset 0 3px 0 var(--ink-3); }

/* La ruta: dos paradas unidas por una línea */
.pt-route { list-style: none; margin: 0 0 .9rem; padding: 0; position: relative; }
.pt-route li { position: relative; padding: 0 0 .9rem 1.6rem; display: grid; gap: .1rem; }
.pt-route li:last-child { padding-bottom: 0; }
.pt-route li::before { content: ""; position: absolute; left: .3rem; top: .45rem; width: .6rem; height: .6rem; border-radius: 50%; border: 2px solid var(--ink); background: var(--surface); box-sizing: border-box; }
.pt-route li:last-child::before { background: var(--ink); }
.pt-route li:not(:last-child)::after { content: ""; position: absolute; left: .55rem; top: 1.05rem; bottom: -.1rem; border-left: 2px dotted var(--line-strong); }
.pt-route__lbl { font-size: .72rem; font-weight: 600; color: var(--ink-3); text-transform: uppercase; letter-spacing: .05em; }
.pt-route b { font-weight: 600; line-height: 1.35; }
.pt-kv { display: grid; grid-template-columns: auto 1fr; gap: .4rem 1rem; margin: 0; padding-top: .8rem; border-top: 1px solid var(--line); }
.pt-kv--sola { padding-top: 0; border-top: 0; }
.pt-kv dt { color: var(--ink-3); font-size: .82rem; font-weight: 600; }
.pt-kv dd { margin: 0; text-align: right; }

/* Lo que compone el precio */
.pt-lines { display: grid; }
.pt-lines > div { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: .5rem 0; border-bottom: 1px solid var(--line); }
.pt-lines > div:last-child { border-bottom: 0; }
.pt-lines span { display: grid; }
.pt-lines small { color: var(--ink-3); font-size: .76rem; }
.pt-lines b { font-weight: 500; white-space: nowrap; }
.pt-lines--pagos { margin-top: .9rem; padding-top: .4rem; border-top: 1px dashed var(--line-strong); }
.pt-lines__total { margin-top: .25rem; padding-top: .75rem !important; border-top: 2px solid var(--ink); border-bottom: 0 !important; }
.pt-lines__total b { font-weight: 700; font-size: 1.15rem; }
.pt-lines__total span { font-weight: 600; }

/* Cobertura, condiciones, anexos */
.pt-cov { box-shadow: inset 3px 0 0 var(--good); }
.pt-cov.is-released { box-shadow: inset 3px 0 0 var(--warn); }
.pt-cov p { margin: 0 0 .5rem; line-height: 1.5; }
.pt-cov p:last-child { margin-bottom: 0; }
.pt-note p { margin: 0; line-height: 1.55; }
.pt-terms { max-height: 11rem; overflow: hidden; position: relative; }
.pt-terms.is-clipped::after { content: ""; position: absolute; inset: auto 0 0; height: 3.5rem; background: linear-gradient(to bottom, transparent, var(--surface)); pointer-events: none; }
.pt-terms.is-open { max-height: none; }
.pt-more { background: none; border: 0; padding: .4rem 0 0; color: var(--accent); font: inherit; font-size: .85rem; font-weight: 600; cursor: pointer; }
.pt-chip { font-size: .66rem; letter-spacing: .04em; border-radius: 999px; padding: .15rem .55rem; background: var(--warn-soft); color: var(--ink); font-weight: 600; text-transform: uppercase; }
.pt-addendum.needs-initials { box-shadow: inset 3px 0 0 var(--accent); }
.pt-addendum .portal__iniciales { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.pt-addendum .portal__iniciales input { width: 6.5rem; max-width: 6.5rem; font-size: 1.15rem; }
.pt-initialed { margin: .8rem 0 0; color: var(--ink-2); }
.pt-initialed b { display: inline-block; padding: .1rem .6rem; border-bottom: 2px solid var(--ink); margin-left: .3rem; letter-spacing: .15em; }

/* El depósito y la firma */
.pt-deposit p, .pt-sign p { line-height: 1.5; }
.pt-deposit.is-paid { box-shadow: inset 3px 0 0 var(--good); }
.pt-sign { box-shadow: inset 3px 0 0 var(--accent); }
.pt-sign .field > span { font-weight: 600; font-size: .85rem; }
.pt-check { font-weight: 500; line-height: 1.45; font-size: .92rem; }
.pt-sign__btn { width: 100%; justify-content: center; font-size: 1.05rem; }
.pt-signed__who { margin: .5rem 0 .25rem; }
.pt-pdf { margin: 1.2rem 0 0; text-align: center; }
.pt-foot { text-align: center; line-height: 1.6; }
.pt-foot a { color: inherit; }

/* La barra fija del teléfono */
.pt-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .7rem max(1rem, env(safe-area-inset-right)) calc(.7rem + env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line); box-shadow: 0 -8px 24px rgba(0,0,0,.06);
  transition: transform .25s ease, opacity .25s ease;
}
.pt-bar.is-hidden { transform: translateY(110%); opacity: 0; pointer-events: none; }
.pt-bar > span { display: grid; line-height: 1.15; }
.pt-bar small { font-size: .7rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .05em; }
.pt-bar b { font-size: 1.15rem; letter-spacing: -.02em; }
.pt-bar .btn { white-space: nowrap; }
@media (min-width: 48rem) { .pt-bar { left: 50%; right: auto; transform: translateX(-50%); width: min(36rem, 100%); border-radius: var(--radius) var(--radius) 0 0; border: 1px solid var(--line); border-bottom: 0; } .pt-bar.is-hidden { transform: translate(-50%, 110%); } }

/* «Your move»: la línea de tiempo */
.pt-follow { display: flex; align-items: center; justify-content: space-between; gap: 1rem; text-decoration: none; color: inherit; margin-top: 1rem; box-shadow: inset 3px 0 0 var(--accent); }
.pt-follow div { display: grid; gap: .15rem; }
.pt-follow small { color: var(--ink-2); line-height: 1.4; }
.pt-follow span { font-size: 1.4rem; color: var(--accent); }
.pt-steps { list-style: none; margin: 1rem 0 0; padding: 1.1rem 1.1rem; display: grid; grid-template-columns: repeat(5, 1fr); gap: .25rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); position: relative; }
.pt-steps::before { content: ""; position: absolute; left: calc(10% + 1.1rem * .8); right: calc(10% + 1.1rem * .8); top: calc(1.1rem + .55rem); border-top: 2px solid var(--line-strong); }
.pt-step { position: relative; display: grid; justify-items: center; text-align: center; gap: .45rem; font-size: .72rem; }
.pt-step__dot { width: 1.15rem; height: 1.15rem; border-radius: 50%; background: var(--surface); border: 2px solid var(--line-strong); box-sizing: border-box; display: grid; place-items: center; }
.pt-step.is-done .pt-step__dot { background: var(--ink); border-color: var(--ink); }
.pt-step.is-done .pt-step__dot::after { content: ""; width: .32rem; height: .55rem; border: solid var(--on-accent); border-width: 0 2px 2px 0; transform: translateY(-1px) rotate(45deg); }
.pt-step.is-current .pt-step__dot { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.pt-step.is-current .pt-step__dot::after { content: ""; width: .45rem; height: .45rem; border-radius: 50%; background: var(--accent); }
.pt-step.is-skipped { opacity: .45; }
.pt-step.is-upcoming { color: var(--ink-3); }
.pt-step div { display: grid; gap: .1rem; }
.pt-step b { font-weight: 600; font-size: .74rem; color: var(--ink); }
.pt-step.is-upcoming b { color: var(--ink-3); }
.pt-step small { font-size: .66rem; color: var(--ink-3); line-height: 1.25; }
.pt-step.is-current small { color: var(--accent); font-weight: 600; }
@media (max-width: 24rem) { .pt-step small { display: none; } }
.pt-todo { box-shadow: inset 3px 0 0 var(--accent); }
.pt-todo .btn--field { width: 100%; justify-content: center; }
.pt-confirm .btnrow { flex-direction: column; }
.pt-invoice { box-shadow: inset 3px 0 0 var(--money, var(--accent)); }
.pt-invoice.is-paid { box-shadow: inset 3px 0 0 var(--good); }
.pt-invoice .btnrow { margin-top: .9rem; }
.pt-invoice .btn--field { width: 100%; justify-content: center; }
.pt-check-list { margin: 0; padding-left: 1.2rem; line-height: 1.6; color: var(--ink-2); }
.pt-check-list li + li { margin-top: .25rem; }

/* ===========================================================================
   Teléfono y textos (1.31): el hilo de una persona y el cuadro de «Text»
   =========================================================================== */
.thr { list-style: none; margin: .4rem 0 0; padding: 0; display: grid; gap: .45rem; }
.thr__msg { max-width: 78%; padding: .55rem .8rem; border-radius: 14px; background: var(--surface-2); }
.thr__msg.is-in { justify-self: start; border-bottom-left-radius: 4px; }
.thr__msg.is-out { justify-self: end; background: var(--accent-soft); border-bottom-right-radius: 4px; }
.thr__msg.is-failed { background: var(--crit-soft); }
.thr__body { margin: 0; white-space: pre-wrap; line-height: 1.4; }
.thr__meta { margin: .2rem 0 0; font-size: .7rem; color: var(--ink-3); }
.thr__call { display: flex; gap: .5rem; align-items: center; justify-content: center; font-size: .8rem; color: var(--ink-2); padding: .2rem 0; }
.thr__call.is-missed { color: var(--warn); }
.thr__ico { font-weight: 700; }
.thr__send { margin: 0 0 .6rem; }
.thr__sendrow { display: grid; grid-template-columns: 11rem 1fr auto; gap: .4rem; align-items: center; }
@media (max-width: 40rem) { .thr__sendrow { grid-template-columns: 1fr; } }
.thr__unknown { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
.thr__unknown li { display: flex; justify-content: space-between; gap: .8rem; align-items: center; padding: .4rem 0; border-bottom: 1px solid var(--line); }
.thr__unknown li:last-child { border-bottom: 0; }
.tag--quiet { background: var(--surface-3); color: var(--ink-2); }
