/* ═══ HERO DEL PANEL (prototipo `.hero`) ═════════════════════════════════════
   La tarjeta verde de bienvenida del prototipo: antetítulo con la empresa,
   saludo en `--font-display`, resumen del día y una fila de chips con los datos
   de contexto. El único cambio de fondo respecto del prototipo es que acá la
   superficie es PLANA y no un degradado: la auditoría de contraste no mide texto
   sobre degradados, así que los dos párrafos del hero quedarían sin auditar y la
   corrida falla por cada par sin medir (`contrast-sin-medir`). El brillo ámbar
   del prototipo se conserva como pseudo-elemento decorativo, que no lleva texto.

   Los chips son `<span>` informativos y no controles, así que no les aplica el
   mínimo táctil de 44px de los botones; el botón «Nuevo trabajo» que va en la
   misma fila sí lo cumple. */

.hero {
    position: relative;
    overflow: hidden;
    margin-bottom: var(--space-4);
    padding: var(--space-5);
    border-radius: var(--radius-xl);
    background: var(--hero-bg);
    color: var(--hero-text);
    box-shadow: var(--hero-shadow);
}
.hero::after {
    content: '';
    position: absolute;
    right: -70px;
    top: -70px;
    width: 240px;
    height: 240px;
    border-radius: 50%;
    background: var(--hero-glow);
    pointer-events: none;
}
.hero .hero-eyebrow {
    position: relative;
    z-index: 1;
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--hero-text-soft);
}
.hero h2 {
    position: relative;
    z-index: 1;
    margin: 6px 0 4px;
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    text-wrap: balance;
    color: var(--hero-text);
}
.hero p {
    position: relative;
    z-index: 1;
    font-size: var(--fs-sm);
    color: var(--hero-text-soft);
    max-width: 46ch;
    text-wrap: pretty;
}
.hero .hero-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
    position: relative;
    z-index: 1;
}
.hero .hero-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-height: 34px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-xl);
    background: var(--hero-chip-bg);
    border: 1px solid var(--hero-chip-border);
    font-size: var(--fs-xs);
    font-weight: 650;
    color: var(--hero-text);
    backdrop-filter: blur(6px);
}
.hero .hero-chip i {
    font-size: var(--fs-xs);
}

/* ═══ ENCABEZADO DE VISTA (prototipo `.page-hd`) ═════════════════════════════
   Titular de página + una línea que explica qué se está viendo. Reemplaza al
   `.section-header.page-header` de las listas, que solo tenía el título y el
   contador: el contador se mudó a las pestañas de filtro, que ahora lo llevan
   por estado. */
.page-intro {
    margin-bottom: var(--space-4);
}
/* Titular y contador en la misma línea; el contador se separa al extremo. */
.page-intro-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}
.page-intro h2 {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    text-wrap: balance;
    color: var(--text);
}
.page-intro p {
    margin-top: 4px;
    max-width: 62ch;
    font-size: var(--fs-sm);
    color: var(--text-soft);
    text-wrap: pretty;
}

/* ═══ GRILLA DE TARJETAS (prototipo `.list-cards`) ═══════════════════════════
   A partir del ancho de escritorio las listas de tarjetas pasan a columnas
   automáticas de 430px como mínimo, que es la medida del prototipo. El corte de
   900px es el mismo que usa el resto de la app para el layout de escritorio, y
   se respeta a propósito: `auto-fill` con un mínimo de 430px sobre un ancho de
   360px daría una columna más ancha que la pantalla y desbordaría en móvil.
   `minmax(0, 1fr)` es obligatorio en la definición —sin él, el contenido largo
   de una tarjeta fija el ancho de la columna y la grilla desborda—.

   La tarjeta trae su propio `margin-bottom` para las listas apiladas; dentro de
   la grilla el espacio lo da el `gap`, así que se anula. */
.cards-grid {
    display: grid;
    gap: var(--space-4);
    align-items: start;
}
.cards-grid > .job-card,
.cards-grid > .list-card {
    margin-bottom: 0;
}
@media (min-width: 900px) {
    .cards-grid {
        grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
    }
}

/* ═══ PANEL DE INICIO: FILA DE KPIs ══════════════════════════════════════════
   Valores del prototipo «Bosque editorial» (`.kpis` / `.kpi`): etiqueta arriba,
   número en `--font-display` con cifras tabulares y una nota de contexto. Móvil
   primero: dos columnas acá y el ancho de escritorio en `responsive.css`.

   El número por variante usa las TINTAS (`*-ink`) y no los tonos medios: mide
   28px en escritorio (mínimo AA 3:1) pero 36px en móvil, y `--amber-500` sobre la
   tarjeta da 2.17:1. `--amber-ink` da 5.92:1 y en tema oscuro 9.30:1. */

.stats-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-5);
}
.stat-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: var(--space-4);
    text-align: left;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast);
}
/* El orden visual no depende del orden del marcado: `superadmin.js` —que no se
   toca en esta tarea— emite el número y después la etiqueta, y las dos pantallas
   tienen que verse igual. */
.stat-card .stat-label { order: 1; }
.stat-card .stat-number { order: 2; }
.stat-card .stat-note { order: 3; }

.stat-card .stat-label {
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-faint);
}
.stat-card .stat-number {
    font-family: var(--font-display);
    font-size: var(--fs-3xl);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.stat-card .stat-note {
    font-size: var(--fs-xs);
    color: var(--text-soft);
}
.stat-card.green .stat-number,
.stat-card.brand .stat-number { color: var(--brand); }
.stat-card.orange .stat-number,
.stat-card.accent .stat-number { color: var(--amber-ink); }
.stat-card.red .stat-number { color: var(--danger-ink); }
.stat-card.blue .stat-number,
.stat-card.info .stat-number { color: var(--info-ink); }
.stat-card.plum .stat-number { color: var(--plum-ink); }

/* Barra de avance del KPI «Completados» (prototipo `.stat-bar`). Va SIEMPRE al
   final de la tarjeta: la etiqueta, el número y la nota llevan `order` explícito
   (1, 2 y 3), así que sin `order: 4` esta barra —que no tenía ninguno— quedaba
   con el `order: 0` por defecto y aparecía arriba del rótulo. */
.stat-card .stat-bar {
    order: 4;
    display: block;
    height: 4px;
    margin-top: 6px;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    overflow: hidden;
}
.stat-card .stat-bar i {
    display: block;
    height: 100%;
    border-radius: var(--radius-sm);
    background: var(--brand);
}

.section-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin: var(--space-6) 0 var(--space-3);
}
.section-header h3 {
    font-size: var(--fs-lg);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}
.section-header .section-count {
    font-size: var(--fs-xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-faint);
    white-space: nowrap;
}
.section-header .see-all {
    font-size: var(--fs-xs);
    color: var(--brand);
    font-weight: 600;
    cursor: pointer;
    background: none;
    border: none;
}
/* Aviso bajo la cabecera de sección («solo el administrador puede gestionar…»).
   Reemplaza el `style` en línea que traían las tres páginas de listas. */
.section-hint {
    margin: 0 0 var(--space-3);
    font-size: var(--fs-xs);
    color: var(--text-soft);
}
/* Agrupación del título con su contador DENTRO de `.section-header`.
   Con tres hijos (título, contador, acción) el `justify-content: space-between`
   de `.section-header` dejaba el contador flotando en el medio de la fila, donde
   no se sabe si cuenta títulos o acciones. En el prototipo el contador acompaña al
   título (`.section-hd .count`) y la acción queda sola en el extremo derecho, así
   que el título y su contador se envuelven en este contenedor. Es un contenedor
   propio de las listas: `.section-header` y `.section-count` NO se tocan porque
   los comparten el panel de Inicio, Informes, el historial y superadmin (que los
   usan con dos hijos, donde el contador va al extremo y se ve igual que antes). */
.section-title {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    min-width: 0;
}

/* ═══ TARJETA DE TRABAJO ═════════════════════════════════════════════════════
   Es la pieza más reutilizada de la app: la emiten `rendering.js:jobCardHTML` y
   `ui.js:jobHistoryCardHTML` (historial), y la muestran Trabajos, Inicio,
   Calendario y la vista pública. El segundo marcado NO tiene `job-when` ni
   `job-sub`, así que todo lo de acá tiene que funcionar con los dos: se
   reescriben las clases que ya existen en vez de renombrarlas.

   Valores del prototipo: tarjeta `.job-card` (#FFF = `--surface-raised`, radio
   `--radius-lg`, `--shadow-sm`), barra de estado de 4px en `.job-card::before`,
   bloque de fecha `.job-when` y fichas `.job-meta`/`.job-col-*` de una línea.
   Ninguna capa lleva gradiente: el texto mide sobre un fondo sólido.

   Esa última frase SÍ se cumplía para la tarjeta pero NO para su botonera: el
   bloque `.btn-*` de `responsive.css` (≥900px) le ponía un `linear-gradient` a
   `.btn-success`, y con un gradiente detrás la auditoría no puede medir el color
   que ve el usuario —`contrast-sin-medir/button.btn.btn-success@12.5/600`, el
   botón «Completar»—, o sea una desviación registrada y no un aprobado. El
   gradiente se retiró en la ronda de corrección 1 (misma hoja, mismo bloque) y el
   color se fija ahí con `--success-500`: blanco sobre #2E7D5B = 5.00:1, AA. */

.job-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast);
}
/* Barra de estado. Sustituye al `border-left: 4px` anterior para que el color no
   cambie el ancho de la caja; el radio se limita solo a 2px por el ancho de 4px,
   igual que el `--r-pill` del prototipo. */
.job-card::before {
    content: '';
    position: absolute;
    left: 0;
    top: 14px;
    bottom: 14px;
    width: 4px;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: var(--amber-500);
}
.job-card.pending::before { background: var(--amber-500); }
.job-card.completed::before { background: var(--success-500); }
.job-card.completed { background: var(--surface); }

.job-card .job-header {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}
.job-card .job-when {
    flex: none;
    width: 54px;
    padding: 7px 0;
    text-align: center;
    line-height: 1;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.job-card .job-when-day {
    display: block;
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.job-card .job-when-month {
    display: block;
    margin-top: 3px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-faint);
}
.job-card .job-when.today {
    background: var(--brand);
    border-color: var(--brand);
}
.job-card .job-when.today .job-when-day,
.job-card .job-when.today .job-when-month { color: var(--on-brand); }

/* Título, estado y subtítulo en un mismo renglón que se envuelve. */
.job-card .job-title-wrap {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    flex: 1 1 auto;
    min-width: 0;
}
.job-card .job-title {
    font-size: var(--fs-md);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    min-width: 0;
    overflow-wrap: anywhere;
}
.job-card .job-sub {
    flex-basis: 100%;
    font-size: var(--fs-xs);
    color: var(--text-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.job-card .job-cost {
    flex: none;
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
}
.job-card .job-cols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2) var(--space-4);
}
.job-card .job-col {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}
.job-card .job-col-item {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    min-width: 0;
}
.job-card .job-col-item > i {
    flex: none;
    width: 15px;
    text-align: center;
    font-size: var(--fs-xs);
    color: var(--text-faint);
}
/* Etiqueta y valor en una línea: es el `.job-meta b` del prototipo (`Empleado
   Martín Gómez`), y sirve igual para el marcado viejo que los tiene apilados. */
.job-card .job-col-content {
    display: flex;
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-2);
    min-width: 0;
}
.job-card .job-col-label {
    flex: none;
    font-size: var(--fs-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-faint);
    font-weight: 700;
    white-space: nowrap;
}
.job-card .job-col-value {
    font-size: var(--fs-sm);
    color: var(--text);
    font-weight: 600;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.job-card .job-col-value.is-due { color: var(--danger-ink); }
.job-card .job-col-value.is-paid { color: var(--success-ink); }

.job-card .job-desc {
    padding: var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--surface);
    border: 1px dashed var(--border);
    font-size: var(--fs-sm);
    line-height: 1.45;
    color: var(--text-soft);
}
.job-card .job-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
/* El mínimo táctil (WCAG 2.5.5) va acá y no en `.btn`: es el alto lo que estaba
   por debajo. El borde de 1.5px transparente reserva la caja del nivel «outline»
   sin desplazar el texto de las variantes rellenas. El tamaño de letra y el peso
   se dejan literales (`0.7rem`/`600` acá, `0.78rem` en el corte de 900) porque el
   id de contraste los lleva: moverlos cambiaría el perfil medido sin ninguna
   ganancia visual (`contrast-sin-medir` de `.btn-success` lo causaba el gradiente,
   no la tipografía; ver la cabecera del bloque de la tarjeta). */
.job-card .job-actions .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    min-width: 44px;
    min-height: 44px;
    padding: 0 var(--space-4);
    border: 1.5px solid transparent;
    border-radius: var(--radius-xl);
    font-size: 0.7rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
/* Nivel «outline» de la botonera, con los valores del prototipo
   (`--btn-fg: var(--text)`, `--btn-bd: var(--border-strong)`). Hacía falta una
   regla propia: el `border` de arriba es 0-3-0 y le ganaba al de `.btn-outline`
   (0-1-0, en `components.css` y otra vez en `responsive.css`), así que «Editar»,
   «Historial» y «Reabrir» se veían como texto plano mientras «Completar» quedaba
   como un relleno saturado: la jerarquía del prototipo (primary / outline / ghost)
   estaba invertida. El color de la tinta también es el del prototipo: sobre la
   tarjeta completada (`--surface`) el gris heredado medía 4.64:1, muy cerca del
   mínimo. */
.job-card .job-actions .btn-outline {
    border-color: var(--border-strong);
    color: var(--text);
}
/* `:hover` del nivel «outline» de la botonera (arreglo arrastrado de la revisión
   de la Task 7). La regla de arriba es 0-3-0 y le gana a `.btn-outline:hover`
   (0-2-0) sin importar el orden de carga, así que al pasar el mouse el borde y la
   tinta NO cambiaban: quedaban el tinte, la elevación y la sombra del `:hover`
   general, y el botón se veía «muerto» al señalarlo. Acá el borde sube a
   `--text-soft`, que es el `--btn-bd` del `:hover` del prototipo
   (`parqueapp-rediseno.html:344`). La especificidad 0-4-0 es a propósito: es el
   único modo de que este estado gane sin tocar el nivel base. */
.job-card .job-actions .btn-outline:hover {
    border-color: var(--text-soft);
}
/* ── MINIATURAS DE FOTO ──────────────────────────────────────────────────────
   El botón de borrar mide 44×44 (mínimo táctil de la app) y el chip visible
   sigue siendo chico: el rectángulo MEDIDO es el del botón —transparente— y el
   círculo oscuro lo dibuja el icono, anclado a la esquina superior derecha. Antes
   el botón medía 18×18 en la tarjeta y 26×26 en el modal: era el único control
   por debajo del mínimo en toda la pantalla.

   La miniatura de la tarjeta crece de 60 a 84px por la misma razón: con 60px, un
   área de toque de 44px sobre la esquina se comía la miniatura entera. */
.photo-thumb-delete {
    position: absolute;
    top: 0;
    right: 0;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    z-index: 2;
}
.photo-thumb-delete i {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    /* Opaco y no `--scrim`: el velo translúcido del modal (46% en claro) deja
       pasar la foto y el chip queda lavado sobre una imagen clara. La tinta más
       profunda del sistema sostiene el icono claro sobre CUALQUIER foto. */
    background: var(--canopy-950);
    color: var(--paper-0);
    font-size: 0.7rem;
    transition: background var(--transition-fast), transform var(--transition-fast);
}
.photo-thumb-delete:hover i,
.photo-thumb-delete:focus-visible i {
    background: var(--danger-fill);
    transform: scale(1.08);
}
.photo-thumb-delete:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
.photo-thumb-label {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    text-align: center;
    margin-top: var(--space-1);
    font-weight: 600;
}
.job-card .photo-preview {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-3);
    flex-wrap: wrap;
}
.job-card .photo-preview .photo-thumb {
    position: relative;
    flex: none;
    width: 84px;
    height: 84px;
}
.job-card .photo-preview .photo-thumb img {
    width: 84px;
    height: 84px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    border: 1px solid var(--border);
    display: block;
}
.job-card .photo-preview .photo-thumb .photo-thumb-delete i {
    top: 2px;
    right: 2px;
    width: 18px;
    height: 18px;
    font-size: 0.55rem;
}
.modal .photo-preview {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-1);
}
.modal .photo-preview .photo-thumb {
    position: relative;
    flex: none;
    width: 104px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-width: 0;
}
.modal .photo-preview .photo-thumb img {
    width: 104px;
    height: 104px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    cursor: zoom-in;
    display: block;
}
.photo-upload-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(4px);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.25s ease;
}
.photo-upload-overlay.open {
    opacity: 1;
}
.photo-upload-modal {
    background: var(--surface-raised);
    border-radius: 16px;
    padding: 28px 24px;
    width: 90%;
    max-width: 320px;
    text-align: center;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
}
.photo-upload-spinner {
    font-size: 2.2rem;
    color: var(--brand);
    margin-bottom: 12px;
}
.photo-upload-title {
    font-size: 1.05rem;
    font-weight: 700;
    margin-bottom: 10px;
    color: var(--text-soft);
}
.photo-upload-progress {
    font-size: 0.9rem;
    color: var(--text-soft);
    margin-bottom: 12px;
}
.photo-upload-bar {
    width: 100%;
    height: 8px;
    background: var(--border);
    border-radius: 999px;
    overflow: hidden;
}
.photo-upload-bar-fill {
    height: 100%;
    width: 0%;
    background: var(--brand);
    border-radius: 999px;
    transition: width 0.3s ease;
}
.job-card .photo-upload-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.65rem;
    color: var(--brand);
    font-weight: 600;
    cursor: pointer;
    background: var(--brand-soft);
    padding: 4px 12px;
    border-radius: 30px;
    border: none;
    margin-top: 6px;
}
.job-card .photo-upload-btn i {
    font-size: 0.8rem;
}
/* Chapita de estado: el `.chip` del prototipo. Las tintas (`--amber-ink`,
   `--success-ink`) sobre los fondos tenues dan 5.05:1 y 5.46:1; el par anterior
   (`--amber-500` sobre `#fff3e0`) medía 1.97:1 y estaba en la línea base. */
.job-card .status-badge {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-xl);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    background: var(--surface-sunken);
    color: var(--text-soft);
}
.job-card .status-badge.completed {
    background: var(--success-100);
    color: var(--success-ink);
}
.job-card .status-badge.pending {
    background: var(--amber-100);
    color: var(--amber-ink);
}

/* TINTA SOBRE RELLENO DE MARCA: `--on-brand`, no `--paper-0`.
   Los tres usos de abajo (`.btn-primary`, el `.btn-submit` del modal y
   `#pwaInstallBtn`) pintan texto sobre `--brand`, y el relleno de marca SÍ cambia
   entre temas: #14512F en claro, #6FBF8F en oscuro. Con el blanco del primitivo
   el par mide 9.34:1 en claro (AA) pero 2.20:1 en oscuro: el «botón primario
   ilegible en modo oscuro» que el propio comentario de `responsive.css` describe.
   `--on-brand` es el token del sistema con ese papel —«texto sobre relleno de
   marca»— y ya lo usan `.btn-primary` a ≥900px (`responsive.css`) y el
   `.btn-submit` de las pantallas de acceso (`auth.css`), así que el mismo control
   tenía una tinta distinta según el ancho. Con el token, el par mide 9.34:1 en
   claro y 8.38:1 en oscuro.
   NEUTRO EN CLARO: `--on-brand` es `var(--paper-0)` en el tema claro (base.css),
   así que el valor computado en claro NO cambia — es el mismo blanco. */
.btn-primary {
    background: var(--brand);
    color: var(--on-brand);
}
.btn-primary:hover {
    background: var(--brand-strong);
}
.btn-outline {
    background: transparent;
    border: 1.5px solid var(--border);
    color: var(--text-soft);
}
.btn-outline:hover {
    border-color: var(--brand);
    color: var(--brand);
}
.btn-success {
    background: var(--canopy-500);
    color: var(--paper-0);
}
.btn-danger {
    background: var(--danger-500);
    color: var(--paper-0);
}
.btn-accent {
    background: var(--amber-500);
    color: var(--paper-0);
}
.btn-sm {
    padding: 4px 12px;
    font-size: 0.65rem;
}

.modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(4px);
    z-index: 100;
    align-items: flex-end;
    justify-content: center;
    animation: fadeIn 0.25s ease;
}
.modal-overlay.open {
    display: flex;
}

.modal {
    background: var(--surface-raised);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    width: 100%;
    max-width: 480px;
    max-height: 90vh;
    padding: 24px 20px 32px;
    overflow-y: auto;
    animation: slideUp 0.3s ease;
}
.modal .modal-handle {
    width: 40px;
    height: 4px;
    background: var(--border);
    border-radius: 10px;
    margin: 0 auto 16px;
}
.modal h2 {
    font-size: 1.2rem;
    margin-bottom: 16px;
    font-weight: 700;
}
.modal .form-group {
    margin-bottom: 14px;
}
.modal .form-group label {
    display: block;
    font-size: 0.8rem;
    font-weight: 600;
    margin-bottom: 4px;
    color: var(--text-soft);
}
.modal .form-group input,
.modal .form-group select,
.modal .form-group textarea {
    width: 100%;
    padding: 10px 14px;
    border: 1.5px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
    font-family: inherit;
    transition: 0.2s;
    background: var(--surface-raised);
}
.modal .form-group input:focus,
.modal .form-group select:focus,
.modal .form-group textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.15);
}
.modal .form-group textarea {
    resize: vertical;
    min-height: 60px;
}
/* Texto de ayuda del formulario: el gris por defecto del control nativo
   (`#757575`, el MISMO en los dos temas porque no lo elige ningún token) da
   4.61:1 en claro —apenas por encima de AA— pero 3.34:1 sobre el campo oscuro
   (`--surface-raised`, #13291E), por debajo de AA, y la corrección es acotada:
   el modal se publica con el modo oscuro recién implementado.
   Con `--text-faint` el par mide 6.07:1 en claro y 4.75:1 en oscuro, y es el
   token que YA usan como placeholder los seis formularios de acceso
   (`auth.css`, `#authScreens .input-wrap input::placeholder`): el modal quedaba
   con un gris fuera del sistema mientras las pantallas de acceso usaban este.
   Cambia el valor computado en claro (el gris neutro pasa al neutro cálido del
   sistema), pero SIEMPRE hacia arriba en contraste: 4.61:1 → 6.07:1. */
.modal .form-group input::placeholder,
.modal .form-group textarea::placeholder {
    color: var(--text-faint);
}
.modal .form-actions {
    display: flex;
    gap: 10px;
    margin-top: 18px;
}
.modal .form-actions .btn {
    flex: 1;
    padding: 12px;
    border-radius: var(--radius-sm);
    border: none;
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    transition: 0.2s;
}
.modal .form-actions .btn-cancel {
    background: var(--border);
    color: var(--text-soft);
}
.modal .form-actions .btn-submit {
    background: var(--brand);
    color: var(--on-brand);
}
.modal .form-actions .btn-submit:hover {
    background: var(--brand-strong);
}

.toast-container {
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 200;
    width: 90%;
    max-width: 420px;
    pointer-events: none;
}
.toast {
    background: #1f2937;
    color: var(--paper-0);
    padding: 14px 20px;
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
    margin-bottom: 8px;
    font-size: 0.85rem;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 12px;
    animation: toastIn 0.4s ease;
    pointer-events: auto;
}
.toast i {
    font-size: 1.2rem;
    color: var(--canopy-500);
}
.toast.success i { color: #4caf50; }
.toast.error i { color: #ef5350; }

/* ═══ ESTADO VACÍO ═══════════════════════════════════════════════════════════
   El `.empty` del prototipo: caja punteada, contenido centrado y una pista
   debajo del título. Lo usan las listas (Trabajos, Clientes, Equipo, Tipos), la
   búsqueda sin resultados y las pantallas de carga de los perfiles, así que el
   aire NO se toca: se reescriben tinte, fondo y borde, que es lo que estaba
   fuera del sistema de tokens (la regla vieja usaba los neutros que hoy son
   `--text-soft` y `--border`, pero no les daba fondo ni borde propios). */
.empty-state {
    display: grid;
    place-items: center;
    gap: var(--space-3);
    padding: 40px 20px;
    text-align: center;
    background: var(--surface);
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--radius-lg);
    color: var(--text-soft);
}
.empty-state i {
    font-size: 2rem;
    color: var(--brand);
    opacity: 0.8;
}
.empty-state p {
    font-size: var(--fs-sm);
    max-width: 42ch;
    color: var(--text-soft);
}
/* Pista del estado vacío: qué hacer a continuación. Es un `span` y no un `p`
   para no competir con el mensaje en el mismo nivel de jerarquía. */
.empty-state .empty-hint {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    max-width: 42ch;
}

/* ── CALENDARIO ──────────────────────────────────────────────────────────────
   La tarjeta del mes, la barra de navegación (nueva) y la grilla. Los días de
   los meses vecinos van como `<div class="day-cell other-month">`: no son
   controles —no llevan a ningún lado— así que no tienen mínimo táctil ni están
   en el orden de tabulación. */

.agenda-layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
/* Móvil: la grilla ocupa todo el ancho de la columna (sin marco ni aire lateral)
   para que cada día mida 44px o más con el gap de 2px. Desde 600px vuelve la
   tarjeta con marco. */
.calendar-card {
    padding: var(--space-3) 0;
}
@media (min-width: 600px) {
    .calendar-card {
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        padding: var(--space-4);
        box-shadow: var(--shadow-sm);
    }
}
/* La lista del día vive en media columna: una sola tarjeta por fila aunque el
   ancho de la ventana active las 2 columnas de Trabajos. */
.agenda-layout .day-group {
    grid-template-columns: minmax(0, 1fr);
}
/* Bajo ~352px la columna deja pistas de menos de 44px (a 320: 39px; a 350:
   43,7px). La grilla sale del gutter (llega al borde de la ventana) y sin
   separación: 320/7 = 45,7px por día. El corte es 351,98px y no 340px: con
   gap 2px las 7 pistas miden 44px recién desde 352px de ventana. */
@media (max-width: 351.98px) {
    .agenda-layout > #calendarContainer {
        margin-inline: calc(-1 * var(--space-4));
    }
    .cal-g { gap: 0; }
}
/* Por debajo de 1200px el calendario es de una columna: la TARJETA llena la
   columna (alineada con la lista y el selector), pero la grilla y la barra de
   mes no se estiran (las celdas serían enormes) y quedan centradas en 560px. */
@media (max-width: 1199.98px) {
    .agenda-layout .calendar-nav,
    .agenda-layout .cal-g,
    .agenda-layout .legend {
        max-width: 560px;
        margin-inline: auto;
    }
}
.calendar-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.calendar-month-label {
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    letter-spacing: -.02em;
    color: var(--text);
    text-align: center;
}
.calendar-day-head {
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .01em;
    margin-bottom: var(--space-2);
}
.calendar-empty {
    padding: var(--space-4) 0;
}
/* Control circular con icono. El mínimo es 44×44 porque es un control real: con
   el icono suelto el arnés no tendría nada que medir, pero el dedo sí. */
.icon-btn {
    flex: none;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-raised);
    color: var(--text-soft);
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
}
.icon-btn:hover:not(:disabled) {
    border-color: var(--brand);
    color: var(--brand);
    transform: translateY(-1px);
}
.icon-btn:disabled {
    opacity: .45;
    cursor: not-allowed;
}
.icon-btn:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

.cal-g {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 2px;
    text-align: center;
}
.cal-g .day-name {
    font-size: .72rem;
    font-weight: 600;
    color: var(--text-soft);
    padding: var(--space-1) 0;
}
.cal-g .day-cell {
    min-width: 0;
    min-height: 44px;
    aspect-ratio: 1 / 1;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 0;
    border: 0;
    border-radius: 11px;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: .9rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}
.cal-g .day-cell.other-month {
    color: var(--text-faint);
    cursor: default;
    pointer-events: none;
}
/* Hoy: color y peso. El día elegido: fondo invertido. */
.cal-g .day-cell.today {
    color: var(--brand);
    font-weight: 700;
}
.cal-g .day-cell.sel {
    background: var(--text);
    color: var(--surface-sunken);
}
.cal-g .day-cell:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}
@media (hover: hover) {
    .cal-g .day-cell:not(.sel):not(.other-month):hover {
        background: var(--brand-soft);
    }
}
.cal-g .dots {
    display: flex;
    gap: 2px;
    height: 5px;
}
.cal-g .dots i,
.legend i {
    display: inline-block;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--amber-500);
}
.cal-g .dots i.d,
.legend i.d {
    background: var(--success-fill);
}
.legend {
    display: flex;
    gap: 14px;
    padding: var(--space-2) var(--space-1) 0;
    font-size: var(--fs-xs);
    color: var(--text-soft);
}
.legend i {
    width: 8px;
    height: 8px;
    margin-right: 5px;
}

/* ═══ ALERTAS (notificaciones) ═══════════════════════════════════════════════
   El `.notif` del prototipo: fila con chip de icono, mensaje y fecha. El aviso
   sin leer se marca con filete y fondo tenue de marca (`--brand-soft`) más una
   chip «Nueva», en vez de un relleno de color plano: la marca no gana contraste
   con un fondo fuerte y el texto tiene que seguir midiendo AA.

   El bloque de escritorio de `responsive.css` (≥900px) reescribe estas mismas
   reglas con literales (`#fff`, `#e5e7eb`): se reescribió también, si no gana
   por orden de carga y el rediseño no se vería en escritorio. */

.notif-note {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--brand-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text);
    font-size: var(--fs-sm);
    line-height: 1.5;
}
.notif-note i {
    color: var(--brand-ink);
    margin-top: 3px;
}

.notif-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.notif-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-left: 3px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.notif-item:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}
.notif-item.is-unread {
    background: var(--brand-soft);
    border-left-color: var(--brand);
}
.notif-item .notif-icon {
    flex: none;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--text-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-md);
}
.notif-item.is-unread .notif-icon {
    background: var(--surface-raised);
    color: var(--brand-ink);
}
.notif-item .notif-text {
    flex: 1;
    min-width: 0;
}
.notif-item .notif-msg {
    font-size: var(--fs-md);
    line-height: 1.45;
    color: var(--text);
    overflow-wrap: anywhere;
}
.notif-item .notif-time {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    font-size: var(--fs-xs);
    color: var(--text-faint);
}
.notif-item .notif-flag {
    flex: none;
    align-self: center;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--surface-raised);
    border: 1px solid var(--border-strong);
    color: var(--brand-ink);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* ═══ LISTAS DE PERSONAS (CLIENTES Y EQUIPO) ═════════════════════════════════
   El `.user-row` del prototipo: fila de tarjeta con avatar de iniciales, bloque
   de texto que abre el perfil y botonera de iconos. El marcado que la consume
   (`rendering.js:userCardHTML`) NO se renombra: `.user-card`, `data-user-id`,
   `data-user-type` y los `data-action` de los botones los lee
   `bindUserCardActions`, y el `onclick` del bloque `.info` navega al perfil.

   Los botones pasan de 32×32 a 44×44: son los ofensores
   `clients/touch-targets/button.{whatsapp,edit,delete}@32` de la línea base
   (WCAG 2.5.5 exige 44×44 lógicos). El `background` deja de ser un gris de
   relleno y pasa a transparente con borde reservado —el `.icon-btn` del
   prototipo—, así el icono deja de parecer un botón relleno permanente. */
.user-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.user-card {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast);
}
.user-card:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
}
/* Indicador de foco de las tarjetas de SELECCIÓN (las de las hojas de empleado y
   de empresa, que la Task 13 volvió operables con el teclado: `role="button"` +
   `tabindex="0"` + `Enter`/`Espacio`). Un control enfocable SIN indicador visible
   es una falla propia —WCAG 2.4.7—, así que el `tabindex` no se podía agregar sin
   esto. Va acotado a `.modal` para no tocar las tarjetas de las pantallas de
   datos, que no son enfocables ni lo fueron. El `outline` no ocupa lugar: no
   cambia ninguna medida de `touch-targets` ni de desborde. */
.modal .user-card:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-color: var(--border-strong);
}
.user-card .avatar {
    flex: none;
    width: 46px;
    height: 46px;
    border-radius: var(--radius-md);
    background: var(--brand-soft);
    color: var(--brand-ink);
    border: 1px solid var(--border);
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 700;
    letter-spacing: -0.01em;
}
/* Empleado inactivo: la caja de iniciales se apaga y el estado se dice con
   todas las letras en la línea de contexto (`.is-inactive`). */
.user-card.is-off .avatar {
    background: var(--surface-sunken);
    color: var(--text-faint);
    border-color: var(--border);
}
.user-card .info {
    flex: 1 1 auto;
    min-width: 0;
    cursor: pointer;
}
.user-card .name {
    font-size: var(--fs-md);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-card .meta {
    margin-top: 2px;
    font-size: var(--fs-xs);
    color: var(--text-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Saldo del cliente y estado del empleado en la tinta semántica de texto
   (`*-ink`), no en el color de relleno: sobre la tarjeta clara estas tintas
   miden 6.82:1 (debe) y 6.43:1 (al día / inactivo) y pasan AA. */
.user-card .meta .is-due,
.user-card .meta .is-inactive { color: var(--danger-ink); font-weight: 700; }
.user-card .meta .is-paid { color: var(--success-ink); font-weight: 700; }
.user-card .actions {
    display: flex;
    gap: var(--space-1);
    flex: none;
}
.user-card .actions button {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1.5px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-faint);
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast),
                border-color var(--transition-fast);
}
.user-card .actions button:hover {
    background: var(--surface-sunken);
    border-color: var(--border);
    color: var(--text);
}
.user-card .actions button.edit:hover {
    background: var(--brand-soft);
    border-color: var(--border-strong);
    color: var(--brand-ink);
}
.user-card .actions button.delete:hover {
    background: var(--danger-100);
    border-color: var(--danger-100);
    color: var(--danger-ink);
}
.user-card .actions button.whatsapp:hover {
    background: var(--success-100);
    border-color: var(--success-100);
    color: var(--success-ink);
}

/* Encabezado del perfil de CLIENTE (y de la vista pública) y del perfil de
   EMPLEADO: avatar de iniciales + nombre en la display + dirección/teléfono con
   su icono. Lo comparten `renderClientProfile` y `renderEmployeeProfile`. */
.profile-header {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}
.profile-header .avatar {
    flex: none;
    width: 72px;
    height: 72px;
    border-radius: var(--radius-lg);
    background: var(--brand-soft);
    color: var(--brand-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    border: 1px solid var(--border);
}
.profile-header .details {
    min-width: 0;
}
.profile-header .details h2 {
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: var(--text);
}
.profile-header .details p {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-sm);
    color: var(--text-soft);
    margin-top: 3px;
}
.profile-header .details p > i {
    color: var(--text-faint);
    font-size: var(--fs-xs);
}

/* ── BLOQUE «COMPARTIR PERFIL» Y AVISOS DE SOLO LECTURA ──
   Los usa el perfil de cliente con sesión (enlace público que genera el admin)
   y la VISTA PÚBLICA. Reemplazan los `style` en línea que traía el marcado:
   eran la única parte de la app con colores literales dentro del JS. */
.share-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.share-row input {
    flex: 1;
    min-width: 0;
    font-family: var(--font-ui);
    font-size: var(--fs-sm);
    padding: var(--space-2) var(--space-3);
    min-height: 44px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-raised);
    color: var(--text-soft);
}
.share-row .btn {
    flex: none;
    min-height: 44px;
}
.share-note,
.readonly-foot {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: var(--space-2);
    line-height: 1.5;
}
.readonly-note {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--info-100);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text);
    font-size: var(--fs-sm);
    line-height: 1.5;
}
.readonly-note i {
    color: var(--info-ink);
    margin-top: 3px;
}
.readonly-foot {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    text-align: center;
}

.balance-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin-bottom: 18px;
}
.balance-card {
    background: var(--surface-raised);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-2);
    text-align: center;
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
}
.balance-card .number {
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
.balance-card .label {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-top: 2px;
}
/* TINTAS y no los tonos medios: `--amber-500` (#E9A23B) sobre la tarjeta clara mide
   2.17:1, igual que el caso documentado de los KPIs del panel. */
.balance-card.green .number { color: var(--brand-ink); }
.balance-card.orange .number { color: var(--amber-ink); }
.balance-card.red .number { color: var(--danger-ink); }

/* Cabecera de sección de las páginas de perfil (cliente y empleado): título a la
   izquierda, acción a la derecha. La usan `renderClientProfile`,
   `renderClientPayments` y `renderEmployeeProfile`. */
.section-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-6) 0 var(--space-3);
}
.section-toolbar h3 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-lg);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}
/* Mínimo táctil: fuera del topbar, de la tarjeta de trabajo y del modal, `.btn`
   no trae `min-height`, y estos botones («Agregar», «Registrar pago») quedaban
   en ~24px de alto. */
.section-toolbar .btn-sm {
    min-height: 44px;
    padding: 0 var(--space-4);
    border-radius: 999px;
    border: none;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.payment-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.payment-item {
    background: var(--surface-raised);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
}
.payment-item .left {
    flex: 1;
    min-width: 0;
}
.payment-item .amount {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-lg);
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--success-ink);
}
.payment-item .date {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: 2px;
}
.payment-item .delete {
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-sunken);
    color: var(--danger-ink);
    cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast);
}
.payment-item .delete:hover {
    border-color: var(--danger-ink);
    color: var(--danger-ink);
}

.property-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--brand-soft);
    color: var(--brand-ink);
    padding: 3px 10px;
    border-radius: 999px;
    font-size: var(--fs-xs);
    font-weight: 600;
}

.property-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.property-item {
    background: var(--surface-raised);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    box-shadow: var(--shadow-sm);
    border: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
}
.property-item .property-info {
    flex: 1;
    min-width: 0;
}
.property-item .property-name {
    font-weight: 600;
    font-size: var(--fs-md);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.property-item .property-address {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: 2px;
}
.property-item .property-actions {
    display: flex;
    gap: var(--space-2);
}
.property-item .property-actions button {
    width: 44px;
    height: 44px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-sunken);
    color: var(--text-soft);
    cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast),
                background var(--transition-fast);
    display: flex;
    align-items: center;
    justify-content: center;
}
.property-item .property-actions button.edit-property:hover {
    background: var(--brand-soft);
    border-color: var(--brand);
    color: var(--brand-ink);
}
.property-item .property-actions button.delete-property:hover {
    background: var(--danger-100);
    border-color: var(--danger-ink);
    color: var(--danger-ink);
}

/* ── DETALLE (hoja modal del trabajo, perfil) ────────────────────────────────
   `.detail-row` es el `kv` del prototipo: etiqueta en versalitas a la izquierda y
   valor a la derecha, con separador punteado. Lo comparten la hoja de detalle y
   las filas del perfil, así que el cambio vale para las dos. */
.detail-head {
    margin-bottom: var(--space-4);
}
.detail-title {
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -.01em;
    color: var(--text);
}
.detail-sub {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: 2px;
}
.detail-rows {
    display: block;
}
.detail-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding: 9px 0;
    border-bottom: 1px dashed var(--border);
}
.detail-row:last-child {
    border-bottom: 0;
}
.detail-row .label {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
}
.detail-row .value {
    font-size: var(--fs-sm);
    font-weight: 600;
    text-align: right;
    color: var(--text);
}
.detail-row .value.is-due { color: var(--danger-ink); }
.detail-row .value.is-paid { color: var(--success-ink); }
.detail-status {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-xl);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.detail-status.is-pending { background: var(--amber-100); color: var(--amber-ink); }
.detail-status.is-done { background: var(--success-100); color: var(--success-ink); }
.detail-section {
    margin-top: var(--space-4);
}
.detail-section h4 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-xs);
    font-weight: 750;
    letter-spacing: .06em;
    text-transform: uppercase;
    margin-bottom: var(--space-3);
    color: var(--text-faint);
}
.detail-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    min-height: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--surface-sunken);
    color: var(--text-soft);
    font-size: 0.6875rem;
}
.detail-text {
    font-size: var(--fs-md);
    color: var(--text-soft);
    line-height: 1.55;
}
.detail-empty {
    font-size: var(--fs-sm);
    color: var(--text-faint);
}
.whatsapp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    padding: 12px;
    border-radius: var(--radius-sm);
    background: #25d366;
    color: var(--paper-0);
    border: none;
    font-weight: 700;
    font-size: 0.9rem;
    cursor: pointer;
    margin-top: 14px;
    text-decoration: none;
}
.whatsapp-btn i { font-size: 1.2rem; }

.photo-upload-wrapper {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
}
.photo-upload-wrapper .photo-box {
    width: 70px;
    height: 70px;
    border-radius: 8px;
    border: 1.5px dashed var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.6rem;
    color: var(--text-soft);
    cursor: pointer;
    transition: 0.2s;
    background: var(--surface-sunken);
    flex-direction: column;
    gap: 2px;
    position: relative;
    overflow: hidden;
}
.photo-upload-wrapper .photo-box:hover {
    border-color: var(--brand);
}
.photo-upload-wrapper .photo-box img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.photo-upload-wrapper .photo-box .remove-photo {
    position: absolute;
    top: 2px;
    right: 2px;
    background: rgba(0, 0, 0, 0.6);
    color: var(--paper-0);
    border: none;
    border-radius: 50%;
    width: 18px;
    height: 18px;
    font-size: 0.5rem;
    cursor: pointer;
}

.selected-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.selected-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--brand-soft);
    color: var(--brand-strong);
    padding: 4px 10px;
    border-radius: 30px;
    font-size: 0.75rem;
    font-weight: 600;
}
.selected-tag button {
    background: none;
    border: none;
    color: var(--brand);
    cursor: pointer;
    font-size: 0.8rem;
    padding: 0;
    width: 16px;
    height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ═══ BUSCADOR ═══════════════════════════════════════════════════════════════
   El `.search` del prototipo: caja pastilla con icono al inicio y anillo de foco
   en el contenedor (`:focus-within`), porque el `<input>` va sin borde ni outline
   propios para que el campo entero se lea como un solo control.

   `min-height: 44px` en el INPUT —no solo en la caja— es obligatorio: el arnés
   mide los `input` como controles táctiles (WCAG 2.5.5) y con el `min-height: 42px`
   del prototipo el buscador nuevo sería un ofensor NUEVO en `jobs` y en `mobile`.
   El `::placeholder` fija su color a propósito: el gris por defecto del navegador
   no está en el sistema de tokens y quedaba por debajo del mínimo medible. */
.search-field {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 46px;
    padding: 0 var(--space-4);
    margin: 0 0 var(--space-4);
    background: var(--surface-raised);
    border: 1.5px solid var(--border);
    border-radius: var(--radius-xl);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.search-field:focus-within {
    border-color: var(--brand);
    box-shadow: 0 0 0 4px var(--ring);
}
.search-field > i {
    flex: none;
    font-size: var(--fs-sm);
    color: var(--text-faint);
}
.search-input {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 44px;
    border: 0;
    background: transparent;
    outline: none;
    font-family: var(--font-ui);
    font-size: var(--fs-md);
    color: var(--text);
}
.search-input::placeholder {
    color: var(--text-soft);
}

/* ═══ PESTAÑAS DE FILTRO (TRABAJOS) ══════════════════════════════════════════
   El `.filters` + `.fchip` del prototipo. Convive con `.search-field`: las dos
   filas se apilan y el filtro por estado se combina con el texto buscado.

   `min-height: 44px` resuelve los ofensores `jobs/touch-targets/button.filter-btn@35`
   y `mobile/touch-targets/button.filter-btn@26` de la línea base: el alto era lo
   único que estaba por debajo del mínimo (WCAG 2.5.5). Las tintas son las del
   sistema (inactiva: `--text-soft` sobre la superficie, activa: `--on-brand`
   sobre `--brand`), y el fondo deja de ser transparente para que la pestaña se
   lea como control y no como texto suelto. */
.filter-tabs {
    display: flex;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    flex-wrap: wrap;
}
.filter-tabs .filter-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 var(--space-4);
    border-radius: var(--radius-xl);
    border: 1.5px solid var(--border);
    background: var(--surface-raised);
    font-family: var(--font-ui);
    font-size: var(--fs-xs);
    font-weight: 650;
    color: var(--text-soft);
    cursor: pointer;
    transition: background-color var(--transition-fast), border-color var(--transition-fast),
                color var(--transition-fast);
}
.filter-tabs .filter-btn.active {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--on-brand);
}
.filter-tabs .filter-btn:hover:not(.active) {
    border-color: var(--border-strong);
    color: var(--text);
}

/* ═══ TARJETAS DE TIPO DE TRABAJO ════════════════════════════════════════════
   El `.type-row` del prototipo: caja con el icono del catálogo al inicio, nombre
   y descripción en el medio (con los usos en el historial) y la botonera de
   iconos al final. Se conservan `.jobtype-list`/`#jobTypeList`, `.jobtype-item`,
   `data-jobtype-id` y los `data-action` de los botones: los lee
   `bindJobTypeCardActions`. Los botones suben a 44×44 por el mismo mínimo táctil
   que los de las listas de personas (la página no está en ningún scope del
   arnés, pero el mínimo es del sistema, no de la medición). */
.jobtype-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.jobtype-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}
.jobtype-item .jobtype-icon {
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-sm);
    background: var(--amber-100);
    color: var(--amber-ink);
    display: grid;
    place-items: center;
    font-size: var(--fs-md);
}
.jobtype-item .jobtype-info {
    flex: 1 1 auto;
    min-width: 0;
}
.jobtype-item .jobtype-name {
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.jobtype-item .jobtype-desc {
    margin-top: 2px;
    font-size: var(--fs-xs);
    color: var(--text-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.jobtype-item .jobtype-desc b {
    color: var(--text);
    font-weight: 700;
}
.jobtype-item .jobtype-actions {
    display: flex;
    gap: var(--space-1);
    flex: none;
}
.jobtype-item .jobtype-actions button {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1.5px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-faint);
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast),
                border-color var(--transition-fast);
}
.jobtype-item .jobtype-actions button:hover {
    background: var(--surface-sunken);
    border-color: var(--border);
    color: var(--text);
}
.jobtype-item .jobtype-actions button.edit:hover {
    background: var(--brand-soft);
    border-color: var(--border-strong);
    color: var(--brand-ink);
}
.jobtype-item .jobtype-actions button.delete:hover {
    background: var(--danger-100);
    border-color: var(--danger-100);
    color: var(--danger-ink);
}

/* ============ PWA Install Banner ============ */
#pwaInstallBanner {
    position: fixed;
    left: 50%;
    bottom: calc(72px + var(--safe-bottom));
    transform: translate(-50%, 20px);
    background: var(--surface-raised);
    border: 1px solid var(--canopy-500);
    border-radius: 14px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
    padding: 10px 12px;
    z-index: 1000;
    width: calc(100% - 24px);
    max-width: 440px;
    opacity: 0;
    transition: opacity 0.3s ease, transform 0.3s ease;
    pointer-events: none;
}
#pwaInstallBanner.show {
    opacity: 1;
    transform: translate(-50%, 0);
    pointer-events: auto;
}
.pwa-banner-inner {
    display: flex;
    align-items: center;
    gap: 10px;
}
.pwa-banner-inner > i.fas.fa-tree {
    font-size: 1.4rem;
    color: var(--brand);
    flex-shrink: 0;
}
.pwa-banner-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
}
.pwa-banner-text strong {
    font-size: 0.88rem;
    color: var(--brand-strong);
}
.pwa-banner-text span {
    font-size: 0.7rem;
    color: var(--text-soft);
}
/* Tercer uso de `--on-brand` sobre `--brand` (ver la nota de `.btn-primary`):
   mismo par, mismo token, mismo blanco en claro. */
#pwaInstallBtn {
    background: var(--brand);
    color: var(--on-brand);
    border: none;
    padding: 8px 16px;
    border-radius: 20px;
    font-weight: 600;
    font-size: 0.8rem;
    cursor: pointer;
    flex-shrink: 0;
    transition: 0.2s;
}
#pwaInstallBtn:hover { background: var(--brand-strong); }
#pwaInstallClose {
    background: none;
    border: none;
    color: var(--text-soft);
    cursor: pointer;
    font-size: 0.9rem;
    padding: 4px;
    flex-shrink: 0;
}
#pwaInstallClose:hover { color: var(--danger-500); }
@media (min-width: 900px) {
    #pwaInstallBanner {
        bottom: 24px;
    }
}

/* ===================== PÁGINA DE AYUDA (in-app) =====================
   Traducción del bloque «22. AYUDA E INSTALACIÓN» del prototipo. Tres cambios de
   fondo además del aspecto:

   · El `.help-hero` tenía un `linear-gradient` con DOS literales de verde claro
     detrás del `h1` y del párrafo. Es exactamente el patrón que el arnés marca
     como `contrast-sin-medir` —con un gradiente detrás, el color medido es el que
     hay DEBAJO, no el que se pinta donde cae el texto— y el resto del sistema ya
     lo había retirado en la Task 7. Pasa a un relleno plano de marca.
   · Los `.platform-icon` pintaban el glifo en `#fff` sobre el color de marca del
     fabricante (`#3ddc84`, `#0078d4`, `#000`): blanco sobre verde Android mide
     1.6:1. Ahora son tintes del sistema con su tinta, y los colores de marca
     quedan donde el prototipo los usa de verdad: como color del ICONO del
     navegador en las tarjetas de compatibilidad.
   · `.note` y `.note.danger` usaban `#fff8e1` y `#ffebee` literales; pasan a los
     tintes `--amber-100` / `--danger-100`. */

.help-wrap {
    max-width: 720px;
    margin: 0 auto;
    padding: var(--space-2) var(--space-1) var(--space-8);
}
.help-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.help-logo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-lg);
    letter-spacing: -0.01em;
    color: var(--brand-strong);
}
.help-logo i {
    font-size: var(--fs-xl);
    color: var(--brand);
}
.help-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 var(--space-4);
    background: var(--surface-raised);
    color: var(--text-soft);
    border: 1.5px solid var(--border);
    text-decoration: none;
    font-family: var(--font-ui);
    font-weight: 600;
    font-size: var(--fs-sm);
    border-radius: 999px;
    cursor: pointer;
    transition: background-color var(--transition-fast), border-color var(--transition-fast),
                color var(--transition-fast);
}
.help-back:hover {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--on-brand);
}

.help-hero {
    background: var(--brand-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-5) var(--space-4);
    margin-bottom: var(--space-4);
}
.help-eyebrow {
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--brand-ink);
    margin-bottom: var(--space-2);
}
.help-hero h1 {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--text);
    margin-bottom: var(--space-2);
}
.help-hero p {
    font-size: var(--fs-md);
    line-height: 1.55;
    color: var(--text-soft);
}
.help-hero b {
    color: var(--brand-ink);
}

/* Tarjeta de instalación: texto a la izquierda, acción a la derecha. */
.install-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    padding: var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}
.install-card-text {
    min-width: 0;
}
.install-card-title {
    font-weight: 700;
    font-size: var(--fs-md);
    color: var(--text);
}
.install-card-sub {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: 2px;
}

.help-section {
    margin-bottom: var(--space-6);
}
.help-section > h2 {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text);
    margin-bottom: var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border);
}
.help-section > h2 .platform-icon {
    flex: none;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    font-size: var(--fs-md);
    background: var(--surface-sunken);
    color: var(--text-soft);
}
.icon-android {
    background: var(--success-100);
    color: var(--success-ink);
}
.icon-windows {
    background: var(--info-100);
    color: var(--info-ink);
}
.icon-ios {
    background: var(--surface-sunken);
    color: var(--text);
}
.icon-browsers {
    background: var(--amber-100);
    color: var(--amber-ink);
}

.help-lede {
    font-size: var(--fs-md);
    line-height: 1.55;
    color: var(--text-soft);
    margin-bottom: var(--space-3);
}
.help-rolehint {
    display: block;
    margin-top: var(--space-2);
    font-weight: 600;
    color: var(--brand-ink);
}

.step-list {
    list-style: none;
    counter-reset: step;
    padding: 0;
}
.step-list li {
    position: relative;
    padding: var(--space-3) var(--space-3) var(--space-3) calc(var(--space-4) + 34px);
    margin-bottom: var(--space-2);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    font-size: var(--fs-md);
    line-height: 1.55;
    color: var(--text);
    counter-increment: step;
}
.step-list li::before {
    content: counter(step);
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    width: 26px;
    height: 26px;
    background: var(--brand);
    color: var(--on-brand);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.step-list b {
    color: var(--brand-ink);
}
/* OJO: `.note` NO puede ser `display: flex`. Su contenido es TEXTO con `<b>`
   adentro («También puede aparecer un <b>banner automático</b>…»), y en un
   contenedor flex cada nodo de texto y cada `<b>` pasan a ser un ítem propio: la
   frase se parte en columnas separadas por el `gap`. El icono va en línea, dentro
   del flujo del texto. (Los otros avisos —`.notif-note`, `.readonly-note`,
   `.sa-risk`— sí pueden ser flex: tienen un único hijo con el texto.) */
.note {
    font-size: var(--fs-sm);
    line-height: 1.5;
    color: var(--text);
    margin-top: var(--space-2);
    padding: var(--space-3) var(--space-4);
    background: var(--amber-100);
    border: 1px solid var(--border);
    border-left: 3px solid var(--amber-ink);
    border-radius: var(--radius-sm);
}
.note > i {
    color: var(--amber-ink);
    margin-right: 6px;
}
.note.danger {
    background: var(--danger-100);
    border-left-color: var(--danger-ink);
}
.note.danger > i {
    color: var(--danger-ink);
}
.browsers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.browser-card {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    text-align: center;
    box-shadow: var(--shadow-sm);
}
.browser-card .b-icon {
    font-size: var(--fs-2xl);
    margin-bottom: 6px;
}
.browser-card .b-name {
    display: block;
    font-weight: 700;
    font-size: var(--fs-sm);
    color: var(--text);
}
.browser-card .b-platforms {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-top: 4px;
    line-height: 1.4;
}
/* «No compatible» sin `opacity`: bajar la opacidad del bloque entero baja también
   el contraste del texto, que es justo lo que no se puede hacer. Se dice con el
   borde, el fondo y la chapa del nombre. */
.browser-card.no {
    background: var(--surface-sunken);
    border-style: dashed;
}
.browser-card.no .b-name::after {
    content: ' ⚠️';
}
.browser-card.no .b-platforms {
    color: var(--text-faint);
}

.install-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 0 var(--space-5);
    background: var(--brand);
    color: var(--on-brand);
    border: none;
    border-radius: 999px;
    font-family: var(--font-ui);
    font-size: var(--fs-md);
    font-weight: 600;
    cursor: pointer;
    box-shadow: var(--shadow-md);
    transition: background-color var(--transition-fast), transform var(--transition-fast);
}
.install-btn:hover:not(:disabled) {
    background: var(--brand-strong);
    transform: translateY(-1px);
}
.install-btn:disabled {
    opacity: 0.6;
    cursor: default;
    transform: none;
}
.install-status {
    font-size: var(--fs-sm);
    color: var(--text-soft);
    margin-top: var(--space-2);
    min-height: 1.2em;
    line-height: 1.5;
}
.help-footer {
    text-align: center;
    font-size: var(--fs-xs);
    color: var(--text-faint);
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}

/* ===================== REPORTES ===================== */
/* Traducción del prototipo «Bosque editorial» (§15). La grilla pasa de dos
   columnas fijas de ~500px a `auto-fill` (3 columnas útiles a 1440px) y la
   tarjeta de una columna a una FILA: chip de icono, texto, chevron.

   Dos desvíos deliberados y medidos del prototipo:
     · El chip del icono es NEUTRO (`--surface-sunken`, como el `.report-ico` del
       prototipo) en vez del tinte por informe que calculaba `hexAlpha` en JS: el
       color de la tinta ya identifica el informe, y el tinte quedaba con el verde
       viejo para los ocho.
     · El mínimo de columna es 280px y no los 240px del prototipo: las
       descripciones de la app son más largas y a 240px el texto quedaba en tres
       renglones.
   Las tintas de la chapita miden 4.6:1–9.3:1 según el informe, en los dos temas. */

.reports-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.report-card {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast);
}
.report-card:hover,
.report-card:focus-visible {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
}
/* Foco visible propio: `outline: none` en la versión anterior dejaba la tarjeta
   sin señal de foco para quien navega con teclado. */
.report-card:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
.report-icon {
    width: 46px;
    height: 46px;
    flex: none;
    border-radius: var(--radius-md);
    display: grid;
    place-items: center;
    font-size: var(--fs-lg);
    background: var(--surface-sunken);
}
.report-info {
    flex: 1;
    min-width: 0;
}
.report-title {
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--text);
    line-height: 1.3;
}
.report-desc {
    margin-top: 2px;
    font-size: var(--fs-xs);
    color: var(--text-soft);
    line-height: 1.4;
}
.report-arrow {
    flex: none;
    font-size: var(--fs-xs);
    color: var(--text-faint);
}
/* Línea de contexto al pie de la grilla (y aviso para quien no es administrador).
   No es un `.empty-state`: acá SÍ hay datos, y el panel punteado de Task 8 —icono
   grande incluido— para una línea informativa pesaba más que la grilla. */
.report-hint {
    margin-top: var(--space-4);
    font-size: var(--fs-xs);
    color: var(--text-faint);
}

/* ===================== REPORTES DETALLE ===================== */
/* El detalle del prototipo: cabecera con chip de icono, fila de KPIs con la
   etiqueta arriba y el número en `--font-display`, secciones SIN tarjeta (título
   con barra de acento, contenido apoyado en el lienzo) y cada tabla dentro de su
   propio contenedor con filete.

   Sin degradados en ningún bloque: un `linear-gradient` en el fondo de un
   contenedor deja SIN MEDIR el par de contraste de todo el texto que cae encima,
   y eso es una falla registrada (`contrast-sin-medir`), no un aprobado. Los
   números de KPI van con las TINTAS (`--*-ink`), que es el papel para el que
   existen: a 22px/600 el mínimo AA sigue siendo 4.5:1 (el umbral de «texto
   grande» empieza en 24px, o 18.66px con peso ≥ 700), y miden 5.7:1–9.0:1. */

.report-detail {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
.report-detail-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}
.report-detail-icon {
    width: 52px;
    height: 52px;
    flex: none;
    border-radius: var(--radius-md);
    display: grid;
    place-items: center;
    font-size: var(--fs-xl);
    background: var(--surface-sunken);
}
.report-detail-meta {
    min-width: 0;
}
/* Título en la display del sistema, un paso por debajo del topbar (`--fs-xl`)
   para no competir con el título de la pantalla que ya muestra la cabecera. */
.report-detail-head h3 {
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -.02em;
    line-height: 1.2;
    color: var(--text);
}
.report-detail-head p {
    margin-top: 2px;
    font-size: var(--fs-sm);
    color: var(--text-soft);
}
.report-detail-foot {
    display: flex;
}
/* El «Volver a reportes» del pie del informe es el MISMO caso que
   `.section-toolbar .btn-sm` (ver su comentario): fuera del topbar, de la tarjeta
   de trabajo y del modal, `.btn-sm` no trae `min-height` y quedaba en 21px de
   alto. No lo medía ninguna corrida porque ningún scope abría un detalle de
   informe; lo destapó el scope `report-detail` de la Task 13. */
.report-detail-foot .btn-sm {
    min-height: 44px;
    padding: 0 var(--space-4);
    border-radius: 999px;
    font-size: var(--fs-sm);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.report-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-3);
}
.report-kpi {
    padding: var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.report-kpi-label {
    font-size: var(--fs-xs);
    font-weight: 750;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-faint);
}
.report-kpi-value {
    margin-top: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.report-kpi-note {
    margin-top: 3px;
    font-size: var(--fs-xs);
    color: var(--text-soft);
}

.report-section h4 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    /* 15px: un paso más que los 13px del prototipo, porque el cuerpo de tabla de
       la app es 12px y a 13px el título de la sección no se despegaba. */
    font-size: var(--fs-md);
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--text);
}
.report-section h4::before {
    content: '';
    width: 3px;
    height: 15px;
    border-radius: 2px;
    background: var(--brand);
}

.report-table-wrap {
    overflow-x: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    -webkit-overflow-scrolling: touch;
}
.report-table {
    width: 100%;
    min-width: 560px;
    border-collapse: collapse;
    font-size: var(--fs-xs);
}
/* Encabezado neutro con filete. El par es `--text-faint` sobre `--surface-sunken`
   (5.5:1 en claro y 5.8:1 en oscuro): el `--brand` sobre `--brand-soft` de la
   versión anterior teñía toda la tabla de verde y competía con los KPIs. */
.report-table th {
    text-align: left;
    padding: 11px var(--space-3);
    background: var(--surface-sunken);
    color: var(--text-faint);
    font-weight: 750;
    font-size: var(--fs-xs);
    text-transform: uppercase;
    letter-spacing: .09em;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
}
.report-table td {
    padding: 11px var(--space-3);
    color: var(--text);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.report-table tbody tr:last-child td {
    border-bottom: 0;
}
.report-table tbody tr.alt {
    background: var(--surface-sunken);
}
.report-table tbody tr:hover {
    background: var(--brand-soft);
}

.report-bars {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.report-bar-row {
    display: grid;
    grid-template-columns: 100px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
}
.report-bar-label {
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--text-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* La pista es `--border` y no `--surface-sunken`: las barras ya viven sobre el
   lienzo (`--surface-sunken`), así que una pista del mismo color desaparecía. */
.report-bar-track {
    height: 10px;
    border-radius: 5px;
    background: var(--border);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.report-bar-fill {
    height: 100%;
    border-radius: 5px;
    min-width: 2px;
    transition: width var(--transition-normal);
}
/* Un valor de CERO no deja punto: el `min-width` existe para que un valor chico
   se vea, y sobre 0 dibujaba una barra que no está. */
.report-bar-fill.is-zero {
    min-width: 0;
}
.report-bar-value {
    text-align: right;
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-soft);
    white-space: nowrap;
}
.report-bar-duo {
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.report-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-top: var(--space-3);
    font-size: var(--fs-xs);
    color: var(--text-soft);
}
.report-legend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.report-legend i {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 3px;
}
/* Cumplimiento por empleado: el porcentaje va FUERA de la barra. Encima del
   relleno quedaba sobre dos fondos a la vez y no había forma de medirlo. */
.report-progress {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 120px;
}
.report-progress-track {
    flex: 1;
    height: 7px;
    border-radius: 4px;
    background: var(--border);
    overflow: hidden;
}
.report-progress-fill {
    height: 100%;
    border-radius: 4px;
    background: var(--brand);
}
.report-progress-pct {
    min-width: 34px;
    text-align: right;
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-soft);
}
/* Chapita del prototipo (`.chip`): tinte tenue del semántico + su tinta. Los
   cuatro pares usados miden 5.1:1–6.1:1 en claro y 6.1:1–7.4:1 en oscuro. */
.report-chip {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 0 var(--space-2);
    border-radius: var(--radius-xl);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    background: var(--surface-sunken);
    color: var(--text-soft);
}
.report-chip-pago {
    background: var(--success-100);
    color: var(--success-ink);
}
.report-chip-trabajo {
    background: var(--info-100);
    color: var(--info-ink);
}

/* ============================================================
   Historial de eventos de un trabajo (línea de tiempo)

   Traducción del `.tl` del prototipo. Dos desvíos deliberados y medidos:
     · La línea vertical es de COLOR PLANO (`--border-strong`) y no el gradiente
       del prototipo: un `linear-gradient` detrás de texto vuelve el par
       inmedible para la auditoría de contraste (`contrast-sin-medir`), y esa es
       una falla registrada, no un aprobado.
     · Los colores del punto y del tipo llegan por `style` desde `ui.js` con las
       TINTAS del sistema (`--*-ink`), que es el papel para el que existen.
   ============================================================ */
.history-count {
    font-size: var(--fs-xs);
    color: var(--text-soft);
    margin-bottom: var(--space-2);
}
.history-empty {
    padding: var(--space-6) 0;
}
.history-timeline {
    position: relative;
    padding-left: var(--space-6);
    max-height: 60vh;
    overflow-y: auto;
}
.history-timeline::before {
    content: '';
    position: absolute;
    left: 15px;
    top: var(--space-2);
    bottom: var(--space-2);
    width: 2px;
    background: var(--border-strong);
}
.history-item {
    position: relative;
    padding-bottom: var(--space-4);
}
.history-dot {
    position: absolute;
    left: calc(-1 * var(--space-6) + 4px);
    top: 0;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: var(--fs-xs);
    background: var(--surface);
    border: 1.5px solid var(--border);
    box-shadow: var(--shadow-sm);
    z-index: 1;
}
.history-body {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
}
.history-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}
.history-type {
    font-size: var(--fs-xs);
    font-weight: 750;
    text-transform: uppercase;
    letter-spacing: .04em;
}
.history-time {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    white-space: nowrap;
}
.history-summary {
    font-size: var(--fs-sm);
    color: var(--text);
    line-height: 1.45;
    margin-top: 3px;
}
.history-actor {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    margin-top: 3px;
}
.history-changes {
    margin-top: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    border: 1px dashed var(--border);
}
.history-change-row {
    display: flex;
    gap: var(--space-2);
    font-size: var(--fs-xs);
    line-height: 1.3;
    padding: 3px 0;
    flex-wrap: wrap;
}
.history-change-key {
    font-weight: 600;
    color: var(--text-faint);
    min-width: 80px;
}
.history-change-val {
    color: var(--text);
    word-break: break-word;
}

/* ===================== PÁGINA PERFIL ===================== */
/* Traducción del bloque «21. PERFIL» del prototipo (`parqueapp-rediseno.html`):
   `.profile-hero` —avatar de INICIALES + nombre en `--font-display` + fila de
   chips— y secciones con la cabecera a la izquierda y la acción a la derecha.

   Dos correcciones de accesibilidad, además del aspecto:

   · Los chips usan las TINTAS (`--brand-ink`, `--amber-ink`) y no los tonos
     medios: `.profile-unverified` pintaba `--amber-500` (#E9A23B) sobre `#FFF3E0`
     —1.9:1, ilegible— y ambos colores eran literales fuera del sistema.
   · Los botones de las cabeceras de sección reciben `min-height: 44px`. No
     alcanza con que `.btn` exista: fuera del topbar, de la tarjeta de trabajo y
     del modal, `.btn` no tiene `min-height` ninguno, así que al volverse visibles
     en escritorio (ver `rendering.js:renderProfilePage`) medían ~24px de alto. */

.profile-page-header {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) 0;
    margin-bottom: var(--space-2);
}

.profile-page-header .profile-avatar {
    width: 80px;
    height: 80px;
    border-radius: var(--radius-lg);
    background: var(--brand-soft);
    color: var(--brand-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    flex-shrink: 0;
    border: 1px solid var(--border);
}

.profile-page-header .profile-meta {
    flex: 1;
    min-width: 0;
}

.profile-page-header .profile-meta h2 {
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: var(--text);
    margin-bottom: var(--space-2);
}

/* ── CHIPS DEL ENCABEZADO DE PERFIL ──
   La fila de chips la comparten el perfil propio (`.profile-page-header`) y el
   perfil de cliente / la vista pública (`.profile-header`), así que las clases
   son SUELTAS y no cuelgan de ninguno de los dos encabezados. */
.profile-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.profile-chip,
.profile-role,
.profile-verified,
.profile-unverified,
.profile-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1.4;
}

/* Chip neutro: dato de contexto que no es ni un estado ni un rol (p. ej. la
   cantidad de trabajos en el encabezado del perfil de cliente). */
.profile-chip {
    background: var(--surface-sunken);
    border-color: var(--border);
    color: var(--text-soft);
}

.profile-role {
    background: var(--brand-soft);
    border-color: var(--border);
    color: var(--brand-ink);
}

.profile-verified {
    background: var(--success-100);
    color: var(--success-ink);
}
.profile-unverified {
    background: var(--amber-100);
    color: var(--amber-ink);
}
.profile-status {
    background: var(--brand-soft);
    color: var(--brand-ink);
}
.profile-status.is-off {
    background: var(--danger-100);
    color: var(--danger-ink);
}

.profile-page-header .profile-phone {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: var(--space-1);
    font-size: var(--fs-sm);
    color: var(--text-soft);
}

.profile-details {
    display: flex;
    flex-direction: column;
}

.profile-detail-card {
    background: var(--surface-raised);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    padding: var(--space-1) var(--space-4);
}
.profile-detail-card .detail-row:last-of-type {
    border-bottom: none;
}
.profile-hint {
    font-size: var(--fs-sm);
    color: var(--text-soft);
    line-height: 1.5;
    padding: var(--space-1) 0 var(--space-4);
}

/* Botonera del pie del perfil. Sin tope de ancho: bajo 1200px llena la columna
   (alineada con las tarjetas de arriba) y desde 1200px vive en la columna lateral
   de 360px, así que nunca se lee como una barra. */
.profile-actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-6);
}
.profile-actions .btn {
    min-height: 44px;
    padding: 0 var(--space-4);
    font-size: var(--fs-sm);
    font-weight: 600;
}
/* Mínimo táctil (WCAG 2.5.5) de las acciones de las cabeceras de sección. */
.profile-details .section-header .btn {
    min-height: 44px;
    padding: 0 var(--space-4);
    font-size: var(--fs-sm);
    font-weight: 600;
    flex: none;
}

/* input-wrap dentro del modal (icono + input + toggle) */
.modal .input-wrap {
    position: relative;
    display: flex;
    align-items: center;
}
.modal .input-wrap .input-icon {
    position: absolute;
    left: 12px;
    color: var(--text-soft);
    font-size: 0.85rem;
    pointer-events: none;
}
.modal .input-wrap input {
    padding-left: 36px;
    padding-right: 40px;
}
.modal .input-wrap .toggle-password {
    position: absolute;
    right: 8px;
    background: none;
    border: none;
    color: var(--text-soft);
    cursor: pointer;
    padding: 6px;
    font-size: 0.85rem;
}
.modal .input-wrap .toggle-password:hover {
    color: var(--brand);
}

/* ===================== SUPERADMIN =====================
   Traducción del bloque «23. SUPERADMIN» del prototipo (`parqueapp-rediseno.html`):
   encabezado con el título en la display, fila de KPIs (las mismas `.stat-card`
   del panel de Inicio, así el número mide lo mismo en las dos pantallas), lista de
   empresas con avatar de iniciales y acciones, y equipo expandible.

   Clases NUEVAS: el marcado anterior usaba `.card` / `.card-body` con `style` en
   línea, y `.card` no tiene ninguna regla en el sistema (la tarjeta de empresa se
   veía como un div pelado). Ninguna de estas clases la comparte otra página. */

.sa-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-5);
}
.sa-hero-text {
    min-width: 0;
}
.sa-hero-text h2 {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--text);
}
.sa-hero-text p {
    margin-top: var(--space-2);
    max-width: 62ch;
    font-size: var(--fs-md);
    color: var(--text-soft);
}
.sa-hero-side {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}
.sa-hero-date {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
}
.sa-hero .btn {
    min-height: 44px;
    padding: 0 var(--space-4);
    font-size: var(--fs-sm);
    font-weight: 600;
}

.company-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.company-card {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-4);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.company-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}
.company-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}
.company-avatar {
    flex: none;
    width: 46px;
    height: 46px;
    border-radius: var(--radius-md);
    background: var(--info-100);
    color: var(--info-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: var(--fs-md);
    font-weight: 600;
    letter-spacing: -0.02em;
}
.company-info {
    flex: 1;
    min-width: 0;
}
.company-name {
    font-size: var(--fs-base);
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.01em;
    overflow-wrap: anywhere;
}
.company-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 3px;
    font-size: var(--fs-sm);
    color: var(--text-soft);
    overflow-wrap: anywhere;
}
.company-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--success-100);
    color: var(--success-ink);
    font-size: var(--fs-xs);
    font-weight: 700;
    white-space: nowrap;
}
.company-chip.is-off {
    background: var(--amber-100);
    color: var(--amber-ink);
}

.company-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    justify-content: flex-end;
}
/* Mínimo táctil de las tres acciones de la empresa (`.btn` no trae `min-height`
   fuera del topbar, la tarjeta de trabajo y el modal). */
.company-actions .btn {
    min-height: 44px;
    padding: 0 var(--space-4);
    font-size: var(--fs-sm);
    font-weight: 600;
}
.company-actions .btn.is-danger {
    color: var(--danger-ink);
}
.company-actions .btn.is-danger:hover {
    border-color: var(--danger-ink);
    color: var(--danger-ink);
    background: var(--danger-100);
}

.company-stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
    font-size: var(--fs-sm);
    color: var(--text-soft);
}
.company-stats i {
    color: var(--text-faint);
    margin-right: 4px;
}

.company-emps {
    margin-top: var(--space-3);
    padding: var(--space-3);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.company-emps-title {
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: var(--space-2);
}
.company-emps-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.emp-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
}
.emp-name {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--text);
    font-weight: 600;
    overflow-wrap: anywhere;
}
.emp-name i {
    color: var(--brand-ink);
}
.emp-side {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    justify-content: flex-end;
}
.emp-phone,
.emp-role {
    font-size: var(--fs-xs);
    color: var(--text-faint);
    white-space: nowrap;
}

.sa-risk {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-4);
    background: var(--amber-100);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text);
    font-size: var(--fs-sm);
    line-height: 1.5;
}
.sa-risk i {
    color: var(--amber-ink);
    margin-top: 3px;
}


/* ═══ SEGMENTADO, CHIPS Y PUNTO DE AVISO (rediseño móvil, Task 3) ═════════════
   Piezas compartidas por las tareas siguientes. Referencia: `.seg`, `.chip` y
   `.dotbadge` del prototipo, con los tokens del repo y 44px de alto táctil. */

/* Segmentado de dos o tres opciones (Lista / Agenda). */
.seg {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 3px;
    padding: 3px;
    margin-bottom: var(--space-4);
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface-sunken);
}
.seg > button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 var(--space-3);
    border: none;
    border-radius: 9px;
    background: transparent;
    color: var(--text-soft);
    font-family: inherit;
    font-size: var(--fs-base);
    font-weight: 600;
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}
.seg > button[aria-pressed="true"] {
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-sm);
}
.seg > button:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* Chip de filtro: botón con contador opcional (`.n`). */
.chip {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    padding: 0 14px;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-soft);
    font-family: inherit;
    font-size: var(--fs-base);
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}
.chip .n {
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--text-soft);
}
.chip[aria-pressed="true"] {
    border-color: var(--text);
    background: var(--text);
    color: var(--surface);
}
.chip[aria-pressed="true"] .n {
    color: inherit;
}
.chip:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* Punto de aviso con conteo, sobre un botón `position: relative`. El aro
   (`--dot-ring`) recorta el punto del fondo del botón. */
.dotbadge {
    position: absolute;
    top: 2px;
    right: 2px;
    display: grid;
    place-items: center;
    min-width: 19px;
    height: 19px;
    padding: 0 5px;
    border: 2px solid var(--dot-ring, var(--surface));
    border-radius: 999px;
    background: var(--danger-fill);
    color: var(--paper-0);
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
}
.dotbadge[hidden] {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .seg > button,
    .chip {
        transition: none;
    }
}

/* ═══ HUB «MÁS» (rediseño móvil, Task 4) ══════════════════════════════════════
   Referencia: `.tiles`, `.tile` y `.row` del prototipo. Los arma `openMoreMenu`
   (ui.js) dentro de `#moreMenuList`. */

.more-menu-section {
    margin: var(--space-4) 0 var(--space-2);
    padding: 0 var(--space-1);
    color: var(--text-soft);
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.more-menu-section:first-child {
    margin-top: 0;
}

/* Tonos de los íconos (`.lead`). */
.tone-plum { background: var(--plum-100); color: var(--plum-ink); }
.tone-amber { background: var(--amber-100); color: var(--amber-ink); }
.tone-info { background: var(--info-100); color: var(--info-ink); }
.tone-danger { background: var(--danger-100); color: var(--danger-ink, var(--danger-fill)); }

/* Mosaicos: 2 columnas en móvil, 4 desde la tablet. */
.tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    min-height: 44px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.tile .lead {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 11px;
}
.tile b {
    font-size: var(--fs-base);
}
.tile .tile-desc {
    color: var(--text-soft);
    font-size: var(--fs-sm);
    line-height: 1.35;
}
.tile .badge {
    position: absolute;
    top: 12px;
    right: 12px;
    padding: 1px 7px;
    border-radius: 9px;
    background: var(--danger-fill);
    color: var(--paper-0);
    font-size: var(--fs-sm);
    font-weight: 700;
}
.tile:focus-visible,
.list-rows .row:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
@media (hover: hover) {
    .tile:hover {
        border-color: var(--border-strong);
    }
    .list-rows button.row:hover {
        background: var(--surface-sunken);
    }
}
@media (min-width: 600px) {
    .tiles {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* Lista de filas (Cuenta). */
.list-rows {
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
}
.list-rows .row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 10px 14px;
    border: none;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    text-align: left;
}
.list-rows button.row {
    cursor: pointer;
}
.list-rows .row + .row {
    border-top: 1px solid var(--border);
}
.list-rows .row .lead {
    display: grid;
    flex: none;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    background: var(--brand-soft);
    color: var(--brand);
}
.list-rows .row .grow {
    flex: 1;
    min-width: 0;
}
.list-rows .row .grow b {
    display: block;
    font-weight: 600;
}
.list-rows .row .grow span {
    display: block;
    color: var(--text-soft);
    font-size: var(--fs-sm);
}
.list-rows .row .chev {
    color: var(--text-faint);
}
.list-rows .row .seg {
    flex: 0 1 190px;
    min-width: 0;
    margin-bottom: 0;
}
/* A 360px la fila (icono + etiqueta + segmentado) no entra con los 12px de
   relleno de `.seg > button`: «Oscuro» quedaba cortado contra el borde de la hoja. */
.list-rows .row .seg > button {
    padding: 0 var(--space-1);
}
.list-rows .row-danger .grow b {
    color: var(--danger-ink, var(--danger-fill));
}

/* ═══ LISTA DE TRABAJOS: TARJETA COMPACTA Y AGRUPADO POR DÍA (Task 5) ════════
   Referencia: `.job`, `.day-h` y `.list-sep` del prototipo. La tarjeta pasa a una
   fila (cuerpo + botón rápido de completar); las reglas de `.job-header`,
   `.job-cols` y `.job-actions` de más arriba quedan para las otras vistas. */

.job-card.job-compact {
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
    cursor: pointer;
}
.job-card.job-compact.late::before { background: var(--danger-fill); }
.job-card.job-compact .job-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.job-card.job-compact .job-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}
.job-card.job-compact .job-line .job-title {
    min-width: 0;
    overflow-wrap: anywhere;
}
.job-card.job-compact .job-sub {
    overflow-wrap: anywhere;
}
.job-card.job-compact .job-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 2px var(--space-3);
    color: var(--text-soft);
    font-size: var(--fs-sm);
}
.job-card.job-compact .job-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    overflow-wrap: anywhere;
}
.job-card.job-compact .job-meta-item.job-price { color: var(--text); font-weight: 600; }
.job-card.job-compact .job-meta-item.is-due { color: var(--danger-ink); font-weight: 600; }
.job-card.job-compact .job-meta-item.is-paid { color: var(--success-ink); font-weight: 600; }
.job-card.job-compact .status-badge.late {
    background: var(--danger-100);
    color: var(--danger-ink);
}

/* Botón rápido «completar»: 44×44, a la derecha de la fila. */
.job-card.job-compact .job-action-complete {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border: 1px solid var(--success-ink);
    border-radius: 50%;
    background: var(--success-100);
    color: var(--success-ink);
    font-size: var(--fs-base);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}
.job-card.job-compact .job-action-complete:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
@media (hover: hover) {
    .job-card.job-compact .job-action-complete:hover {
        background: var(--success-ink);
        color: var(--surface);
    }
}

/* Cabecera de día y separador de «Anteriores». */
.day-h {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin: var(--space-4) 0 var(--space-2);
    color: var(--text-soft);
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.day-h:first-child { margin-top: 0; }
.day-h.today { color: var(--brand); }
.day-h .day-h-date {
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
}
.list-sep {
    margin: var(--space-6) 0 var(--space-2);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    color: var(--text-soft);
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* Un día = una grilla de tarjetas: 1 columna, 2 desde la PC ancha. */
.day-group {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
}
.day-group > .job-card { margin-bottom: 0; }
@media (min-width: 1200px) {
    .day-group { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.chip[hidden] {
    display: none;
}

/* ═══ DETALLE DEL TRABAJO CON BARRA DE ACCIONES (Task 6) ═════════════════════
   Referencia: `SCREENS.job`, `.kv`, `.money`, `.prog`, `.photos`, `.ph`, `.wa`,
   `.timeline`, `.ev` y `.actionbar` del prototipo. El pie fijo es el
   `.form-actions` sticky de la hoja (`#jobDetailActions`). */

#jobDetailActions [hidden],
.detail-link[hidden] { display: none; }

/* El título visible es el del trabajo; el `h2` queda solo para el lector de pantalla. */
.modal-overlay.is-detail .modal h2 {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* La X de la cabecera: pegada arriba a la derecha aunque la hoja scrollee. */
.detail-close {
    position: sticky;
    top: 0;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    margin: 0 0 -44px auto;
    border: none;
    border-radius: 50%;
    background: var(--surface-sunken);
    color: var(--text-soft);
    cursor: pointer;
}
.detail-close:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
.modal-overlay.is-detail .detail-head { padding-right: 52px; }

.detail-head .pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.d-pill {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-xl);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    background: var(--surface-sunken);
    color: var(--text-soft);
}
.d-pill.pending { background: var(--amber-100); color: var(--amber-ink); }
.d-pill.completed { background: var(--success-100); color: var(--success-ink); }
.d-pill.late,
.d-pill.due { background: var(--danger-100); color: var(--danger-ink); }
.detail-title { font-size: var(--fs-xl); }
.detail-sub { font-size: var(--fs-sm); }

/* Filas clave-valor: Cliente, Propiedad, Asignado a. */
.kv-list {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    overflow: hidden;
}
.kv {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    border: none;
    background: transparent;
    color: inherit;
    font-family: inherit;
    text-align: left;
    text-decoration: none;
}
.kv + .kv { border-top: 1px solid var(--border); }
.kv > i:first-child { color: var(--text-faint); margin-top: 3px; }
.kv .k { display: block; font-size: var(--fs-sm); color: var(--text-soft); }
.kv .v { display: block; font-weight: 500; color: var(--text); overflow-wrap: anywhere; }
.kv .grow { flex: 1; min-width: 0; }
.kv-link { min-height: 44px; cursor: pointer; align-items: center; }
.kv-link > i:first-child { margin-top: 0; }
.kv-link .chev { color: var(--text-faint); }
.kv-aside { color: var(--brand-ink); font-weight: 600; font-size: var(--fs-sm); }
.kv-link:focus-visible,
.wa:focus-visible,
.ph.add:focus-visible,
.detail-link:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

.card.money,
.detail-card {
    margin-top: var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
}
.detail-section .detail-card { margin-top: 0; }
.money { display: flex; flex-direction: column; gap: var(--space-3); }
.money .trio {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
}
.money .trio span { display: block; font-size: var(--fs-sm); color: var(--text-soft); }
.money .trio b {
    font-size: var(--fs-lg);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.money .trio b.is-due { color: var(--danger-ink); }
.money .trio b.is-paid { color: var(--success-ink); }
.prog {
    height: 8px;
    border-radius: 5px;
    overflow: hidden;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
}
.prog i {
    display: block;
    height: 100%;
    border-radius: 5px;
    background: var(--success-fill);
}

/* Fotos: grilla de 3; la última celda es «Agregar». */
.photos {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
}
.ph {
    position: relative;
    margin: 0;
    aspect-ratio: 1;
    border-radius: 12px;
    overflow: hidden;
    background: var(--surface-sunken);
}
.ph img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ph figcaption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 2px 6px;
    font-size: var(--fs-xs);
    font-weight: 600;
    background: var(--surface-raised);
    color: var(--text);
}
.ph.add {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-height: 44px;
    border: 1.5px dashed var(--border-strong);
    background: var(--surface);
    color: var(--text-soft);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
}
.ph .photo-thumb-delete { position: absolute; top: 0; right: 0; width: 44px; height: 44px; }

.wa {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 44px;
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--success-100);
    color: var(--success-ink);
    text-decoration: none;
    font-weight: 600;
}
.wa > i:first-child { font-size: 1.4rem; }
.wa .grow { flex: 1; min-width: 0; }
.wa .s { display: block; font-size: var(--fs-sm); font-weight: 500; }

.detail-link {
    margin-left: auto;
    min-height: 44px;
    padding: 0 var(--space-2);
    border: none;
    background: transparent;
    color: var(--brand-ink);
    font: inherit;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
}
.detail-section h4:has(.detail-link) { min-height: 44px; }

/* Línea de tiempo (últimos 3 eventos). */
.timeline { display: flex; flex-direction: column; }
.ev {
    position: relative;
    display: flex;
    gap: var(--space-3);
    padding-bottom: var(--space-4);
}
.ev:last-child { padding-bottom: 0; }
.ev::before {
    content: "";
    position: absolute;
    left: 15px;
    top: 32px;
    bottom: 2px;
    width: 2px;
    background: var(--border);
}
.ev:last-child::before { display: none; }
.ev .dot {
    display: grid;
    flex: none;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
}
.ev .grow { flex: 1; min-width: 0; padding-top: 5px; }
.ev .t { font-weight: 600; color: var(--text); }
.ev .s { font-size: var(--fs-sm); color: var(--text-soft); overflow-wrap: anywhere; }

/* Barra de acciones: Completar/Reabrir/Foto ocupan el ancho; Editar y Más son
   cuadrados de 48px. */
.detail-actions .btn { min-height: 48px; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); }
.detail-actions .btn-sq { flex: none; width: 48px; padding: 0; }

/* La hoja de «Más acciones» va por encima del detalle (`#modalOverlay` = 100). */
.more-menu-overlay.over-modal { z-index: 110; }

@media (prefers-reduced-motion: reduce) {
    .ev .dot, .detail-close { transition: none; }
}

/* `flow-root`: el margen negativo del pie sticky no se cuela fuera del detalle
   (si no, el pie quedaba 24px por encima del borde inferior de la hoja). */
#jobDetail { display: flow-root; }

/* El `sticky` se ancla al borde del contenido de la hoja (descuenta su padding
   inferior). Sin padding abajo, el pie queda pegado al borde de la ventana; el
   aire de abajo lo pone el padding del propio pie. */
.modal-overlay.is-detail .modal { padding-bottom: 0; }
.modal-overlay.is-detail #jobDetailActions { margin-bottom: 0; }

/* ═══ INICIO (Task 7) ═════════════════════════════════════════════════════════
   Referencia: `.hello`, `.hero` (con `.hcell`), `.kpis`/`.kpi`, `.note.danger`,
   `.timeline`/`.ev` del prototipo. Colores solo de tokens; el `.hero` base (arriba)
   pone la superficie plana y se extiende con la barra de avance y las celdas. */

.hello { margin-bottom: var(--space-4); }
.hello .hello-eyebrow {
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-soft);
}
.hello h2 {
    margin-top: 4px;
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.015em;
    line-height: 1.08;
    text-wrap: balance;
    color: var(--text);
}

.hero .hero-big {
    position: relative;
    z-index: 1;
    margin-top: 4px;
    max-width: none;
    font-family: var(--font-display);
    font-size: var(--fs-3xl);
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--hero-text);
}
.hero .hero-big small {
    margin-left: 6px;
    font-family: var(--font-ui, inherit);
    font-size: var(--fs-base);
    font-weight: 500;
    color: var(--hero-text-soft);
}
.hero .hero-big.hero-big-sm {
    font-size: var(--fs-2xl);
    line-height: 1.15;
    text-wrap: balance;
}
.hero .hero-bar {
    position: relative;
    z-index: 1;
    height: 8px;
    margin: var(--space-3) 0 var(--space-4);
    border-radius: 5px;
    background: var(--hero-chip-bg);
    overflow: hidden;
}
.hero .hero-bar i {
    display: block;
    height: 100%;
    border-radius: 5px;
    background: var(--hero-text-soft);
}
.hero .hrow {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
}
.hero .hcell {
    display: block;
    min-height: 44px;
    padding: 10px 12px;
    border: 1px solid var(--hero-chip-border);
    border-radius: var(--radius-md);
    background: var(--hero-chip-bg);
    color: var(--hero-text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.hero .hcell span {
    display: block;
    font-size: var(--fs-xs);
    color: var(--hero-text-soft);
}
.hero .hcell b {
    font-size: var(--fs-md, var(--fs-base));
    font-variant-numeric: tabular-nums;
}
.hero .hcell:focus-visible {
    outline: 2px solid var(--hero-text);
    outline-offset: 2px;
}
@media (hover: hover) {
    .hero button.hcell:hover { border-color: var(--hero-text-soft); }
}

/* Próximo trabajo del operario. */
.hero.next-job { display: grid; gap: var(--space-3); }
.hero.next-job .hero-big { margin-top: 0; }
.hero .hero-place {
    position: relative;
    z-index: 1;
    display: flex;
    gap: 10px;
    align-items: flex-start;
    color: var(--hero-text);
}
.hero .hero-place i { margin-top: 3px; color: var(--hero-text-soft); }
.hero .hero-place b { display: block; }
.hero .hero-place span { display: block; font-size: var(--fs-sm); color: var(--hero-text-soft); }
.hero .hero-desc { margin: 0; max-width: none; }
.hero .hcell.hcell-action {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: center;
    position: relative;
    z-index: 1;
    text-align: center;
    text-decoration: none;
}
.hero .hcell.hcell-primary {
    border-color: var(--hero-text-soft);
    background: var(--hero-text-soft);
    color: var(--hero-bg);
}

/* Aviso de atrasados: botón con aspecto de nota. */
button.note {
    display: block;
    width: 100%;
    margin-bottom: var(--space-4);
    min-height: 44px;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

/* KPIs: 2 columnas en móvil, 4 desde la tablet (`responsive.css`). */
.kpis {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: var(--space-4);
}
.kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 44px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.kpi .l {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-sm);
    color: var(--text-soft);
}
.kpi .v {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.kpi .n { font-size: var(--fs-xs); color: var(--text-soft); }
.kpi .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.kpi .dot.kpi-amber { background: var(--amber-ink); }
.kpi .dot.kpi-ok { background: var(--success-ink); }
.kpi .dot.kpi-info { background: var(--info-ink); }
.kpi .dot.kpi-plum { background: var(--plum-ink); }
.kpi:focus-visible,
.note:focus-visible,
.section-link:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
@media (hover: hover) {
    .kpi:hover { border-color: var(--border-strong); }
}

/* Enlace de cabecera de sección («Agenda», «Reporte»…). */
.section-header .section-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 var(--space-2);
    border: none;
    background: none;
    color: var(--brand-ink);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
}

.home-card {
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
}
.list-rows .row .amt-due {
    flex: none;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--danger-ink);
}
.list-rows .row .lead {
    font-size: var(--fs-sm);
    font-weight: 700;
}
.home-main > .section-header:first-child,
.home-side > .section-header:first-child { margin-top: 0; }
.home-grid { display: block; }

/* Eventos de «Actividad reciente»: cada uno abre su trabajo. */
.ev.ev-link {
    width: 100%;
    min-height: 44px;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.ev.ev-link .t,
.ev.ev-link .s { display: block; }
.ev.ev-link:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* Las tarjetas del panel no pueden ensanchar la columna: sin `minmax(0, 1fr)` la
   pista implícita crece al contenido (`nowrap` del título) y desborda a 360px. */
.home-main .cards-grid,
#dashboardContent > .cards-grid {
    grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 900px) {
    .home-main .cards-grid,
    #dashboardContent > .cards-grid {
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 430px), 1fr));
    }
}

/* ═══ CLIENTES: LISTA Y FICHA (rediseño móvil, Task 9) ═══════════════════════
   Referencia: `.row`, `.prof`, `.quick-acts`/`.qa`, `.money` y `.share` del
   prototipo. Solo tokens: ningún color literal. */

/* Filtros por saldo de la lista. */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
}

.client-list {
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
}
.client-row + .client-row {
    border-top: 1px solid var(--border);
}
.client-open {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    min-height: 64px;
    padding: var(--space-3) var(--space-4);
    border: none;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.client-open:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}
.client-row .avatar {
    display: grid;
    flex: none;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: var(--brand-soft);
    color: var(--brand-ink);
    font-family: var(--font-display);
    font-size: var(--fs-base);
    font-weight: 700;
}
.client-text {
    flex: 1;
    min-width: 0;
}
.client-name,
.client-sub {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.client-name { font-weight: 600; }
.client-sub { color: var(--text-soft); font-size: var(--fs-sm); }
.client-row .amt-due,
.client-row .amt-ok {
    flex: none;
    font-size: var(--fs-sm);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.client-row .amt-due { color: var(--danger-ink); }
.client-row .amt-ok { color: var(--success-ink); }

/* Ficha. Una columna en el celular; dos desde 1200px (ver responsive.css). */
.client-layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.client-side,
.client-main {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}
.client-side .profile-header,
.client-side .card.money {
    margin: 0;
}
.client-layout .card.money { margin-top: 0; }
.quick-acts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
}
.qa {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-height: 64px;
    padding: var(--space-3) var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--brand-ink);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}
.qa.is-off {
    color: var(--text-soft);
    cursor: default;
}
.qa:focus-visible,
.share-view:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
.client-layout .seg { margin-bottom: 0; }
/* `.btn-sm` base mide 0.65rem (10,4px): ilegible en «Copiar», «Editar cliente» y
   «Eliminar» de la ficha. Se sube al tamaño pequeño del sistema (13px). */
.client-layout .btn-sm {
    font-size: var(--fs-sm);
    font-weight: 600;
}
.client-tab-panel[hidden] { display: none; }
.client-tab-panel .section-toolbar:first-child { margin-top: 0; }
.client-jobs {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
/* Vista pública: miniaturas de las fotos del trabajo, pegadas a su tarjeta. */
.client-job-photos {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: calc(var(--space-2) * -1);
}
.client-job-photos .photo-thumb { flex: none; width: 72px; height: 72px; }
.client-job-photos .photo-thumb img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
}

.share-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
}
.share-card .share-note { margin-top: 0; }
.share-title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.share-view {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    align-self: flex-start;
    min-height: 44px;
    color: var(--brand-ink);
    font-size: var(--fs-sm);
    font-weight: 600;
}
.client-owner-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.client-side .profile-actions { margin-top: 0; }
.client-owner-actions .btn {
    min-height: 44px;
}

/* ═══ FORMULARIOS DE ALTA (Task 10) ══════════════════════════════════════════
   `.two` pone dos campos lado a lado (fecha y hora); `.pick` agrupa chips de
   elección (tipo de trabajo, operarios, atajos de monto). */
.two {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.pick {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.pick[hidden] {
    display: none;
}
#jobForm .form-group > .pick {
    margin-bottom: 4px;
}

/* «Registrar pago» dentro de la tarjeta de dinero del detalle (Task 10). */
.money [data-action="register-payment"] {
    width: 100%;
    min-height: 44px;
    margin-top: 12px;
    /* Botón secundario (`btn sec sm` del prototipo): borde, fondo de superficie y
       texto normal. NO es primario: la acción principal del detalle es
       «Completar». `.btn-submit` solo se estiliza dentro del modal y de las
       pantallas de acceso, así que el aspecto se define acá, completo. */
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md, 12px);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: var(--fs-md);
    font-weight: 600;
    cursor: pointer;
}
@media (hover: hover) {
    .money [data-action="register-payment"]:hover {
        background: var(--surface-sunken);
    }
}

/* ═══ EQUIPO, TIPOS, REPORTES, ALERTAS, PERFIL Y SUPERADMIN (Task 12) ════════
   Referencia: `.list`, `.row`, `.sw`, `.prof`, `.kpis` y `<details class="card">`
   del prototipo. Todo sale de tokens: ningún color literal. */

.tone-ok { background: var(--success-100); color: var(--success-ink); }

/* Interruptor. La etiqueta mide 56×44 (el área táctil); la pista visible es de
   46×28 y va centrada. El `<input>` real cubre toda la etiqueta, invisible. */
.sw {
    position: relative;
    display: inline-block;
    flex: none;
    width: 56px;
    height: 44px;
}
.sw input {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.sw span {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 46px;
    height: 28px;
    margin: -14px 0 0 -23px;
    border-radius: 15px;
    background: var(--text-faint);
    transition: background-color var(--transition-fast);
}
.sw span::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--paper-0);
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition-fast);
}
.sw input:checked + span { background: var(--brand); }
.sw input:checked + span::after { transform: translateX(18px); }
.sw input:disabled { cursor: not-allowed; }
.sw input:disabled + span { opacity: 0.5; }
.sw input:focus-visible + span {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .sw span,
    .sw span::after { transition: none; }
}

/* Equipo: fila con cuerpo (abre el perfil) + interruptor. Pisa la tarjeta vieja
   `.emp-row` que usa el panel del superadmin (esa vive en `.company-emps-list`). */
.list-rows .emp-row {
    gap: 0;
    min-height: 64px;
    padding: 0 var(--space-2) 0 0;
    border: none;
    border-radius: 0;
    background: transparent;
    font-size: inherit;
}
.list-rows .emp-row + .emp-row { border-top: 1px solid var(--border); }
.emp-open {
    display: flex;
    flex: 1;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
    min-height: 64px;
    padding: var(--space-3) var(--space-2) var(--space-3) var(--space-4);
    border: none;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.emp-open:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}
.emp-row .avatar {
    display: grid;
    flex: none;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: var(--brand-soft);
    color: var(--brand-ink);
    font-family: var(--font-display);
    font-size: var(--fs-base);
    font-weight: 700;
}
.emp-row.is-off .avatar {
    background: var(--surface-sunken);
    color: var(--text-soft);
}
.emp-row .grow b,
.emp-row .grow .meta {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.list-rows .emp-row .grow .meta .is-inactive {
    display: inline;
    color: var(--danger-ink);
    font-weight: 700;
}
.list-rows.user-list,
.list-rows.jobtype-list,
.list-rows.reports-list,
.list-rows.emp-actions,
.list-rows.push-row,
.profile-details .list-rows {
    margin-bottom: var(--space-4);
}
.list-rows.emp-actions { margin-top: var(--space-4); }
.list-rows .row > .grow { text-align: left; }
.list-rows button.row-danger { min-height: 56px; }

/* Perfil de operario: tres KPIs. */
.kpis.kpis-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.kpis-3 .kpi,
#superadminContent .kpi { cursor: default; }

/* Tipos de trabajo dentro de la lista de filas: sin el marco de tarjeta. */
.list-rows .jobtype-item {
    flex-wrap: nowrap;
    gap: var(--space-3);
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}
.list-rows .jobtype-item + .jobtype-item { border-top: 1px solid var(--border); }
.list-rows .jobtype-item .jobtype-actions { flex: none; }
.list-rows.jobtype-list { gap: 0; }

/* Informes dentro de la lista de filas. */
.reports-list .report-card {
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    transform: none;
    cursor: pointer;
}
.reports-list .report-card:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
    transform: none;
    box-shadow: none;
}
@media (hover: hover) {
    .reports-list .report-card:hover {
        transform: none;
        box-shadow: none;
        background: var(--surface-sunken);
    }
}
@media (min-width: 900px) {
    /* Dos columnas: las filas se separan con un hilo de 1px sobre el fondo. */
    .list-rows.reports-list {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1px;
        background: var(--border);
    }
    .reports-list .report-card,
    .reports-list .report-card + .report-card {
        border-top: none;
        background: var(--surface);
    }
}

/* Superadmin: cada empresa es un `<details>`. */
.company-card { padding: 0; }
.company-card > summary {
    list-style: none;
}
.company-card > summary::-webkit-details-marker { display: none; }
.company-head {
    align-items: center;
    min-height: 64px;
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
}
.company-card > summary:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
    border-radius: var(--radius-lg);
}
.company-head .company-chip { flex: none; }
.company-chev {
    flex: none;
    color: var(--text-faint);
}
@media (prefers-reduced-motion: no-preference) {
    .company-chev { transition: transform var(--transition-fast); }
}
.company-card[open] .company-chev { transform: rotate(180deg); }
.company-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: 0 var(--space-4) var(--space-4);
}
.company-body .company-meta { margin-top: 0; }
.company-body .company-stats {
    margin-top: 0;
    padding-top: var(--space-3);
}
.company-body .company-emps { margin-top: 0; }
.company-body .company-actions { justify-content: flex-start; }
@media (min-width: 600px) {
    #superadminContent .kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Hoja de borrado de empresa. */
#deleteCompanyForm .note { margin-bottom: var(--space-4); }
#deleteCompanyConfirm:disabled {
    background: var(--surface-sunken);
    color: var(--text-soft);
    cursor: not-allowed;
}

/* Fix round 1 (Task 12) ─ alta desde el celular y filas angostas. */

/* «Nuevo operario» / «Nuevo tipo de trabajo»: en el celular el topbar está
   oculto, así que la entrada vive al pie de la lista. A >=900 el topbar ya trae
   su «Nuevo» y la fila se esconde para no duplicarlo. */
.list-rows.row-new-wrap { margin-top: var(--space-4); }
.list-rows .row-new { cursor: pointer; min-height: 56px; }
.list-rows .row-new .grow b { color: var(--brand-ink); }
@media (min-width: 900px) {
    .list-rows.row-new-wrap { display: none; }
}

/* El cuerpo de la fila de Equipo necesita poder encogerse para que el ellipsis
   del nombre y de la meta funcione con nombres largos. */
.emp-open .grow { min-width: 0; }

/* Tipos a 360px: el ícono y las dos acciones de 44px dejan el nombre angosto;
   las acciones bajan a una segunda línea, alineadas a la derecha. */
@media (max-width: 599.98px) {
    .list-rows .jobtype-item { flex-wrap: wrap; }
    .list-rows .jobtype-item .jobtype-info { flex: 1 1 0; min-width: 0; }
    .list-rows .jobtype-item .jobtype-actions { flex: 1 1 100%; justify-content: flex-end; }
}
