/* ═══════════════════════════════════════════════════════════════════════════
   responsive.css — Puntos de corte y comportamiento adaptativo del SHELL

   Móvil primero: los valores base viven en `layout.css`. Acá están los cortes:

     · ≤400px  ..... móvil angosto (el objetivo de referencia es 360×640)
     · ≥900px  ..... escritorio: la cabecera se vuelve barra lateral, la barra
                     inferior desaparece y aparece el topbar con el título
     · ≥1400px ..... escritorio ancho: más aire en el lienzo

   El corte de 900px NO es arbitrario y no se puede mover "para que combine":
   `app.js` tiene `DESKTOP_BREAKPOINT = 900` y con él mueve la navegación en el
   DOM (el nav al pie del marco en móvil, dentro de la barra lateral en
   escritorio) y `ui.js` decide con el mismo número qué ítems van en la barra
   inferior. Si el CSS y el JS no coinciden, el JS mueve el DOM a un lugar que
   el CSS no espera y el shell se ve partido en dos.

   El plegado de la barra lateral es la clase `.collapsed` SOBRE `#sidebar`
   (que es el propio `.app-header`): la lee y la escribe `initSidebarToggle`
   (app.js) y se persiste en `localStorage`. El nombre no se cambia.

   Qué queda acá además del shell: la presentación de escritorio de las PÁGINAS
   (tarjetas de trabajo, KPIs, modal, calendario, perfil, informes, toasts…).
   Esas reglas NO son de esta tarea: son de `components.css` y las reescriben las
   Tasks 7–11. Se intentó retirarlas en la Task 5 y el arnés lo rechazó con razón:
   al desaparecer, los botones de acción de la tarjeta de trabajo pasaron de 30px
   a 24px de alto y cambiaron los perfiles de contraste medidos, o sea tres fallas
   NUEVAS (`touch-targets/button.btn@24`, `contrast/div.stat-number@28.8/700`,
   `contrast/span.status-badge.pending@9.6/700`). Se restauraron byte a byte.

   Lo que hay que saber al portar una página (Tasks 7–11): esta hoja se carga
   DESPUÉS de `components.css`, así que una regla de acá con el mismo selector
   GANA (es lo que documentó la revisión de la Task 3: `responsive.css` pisaba
   `.job-card .job-title`). Al reescribir un bloque de `components.css` hay que
   mirar antes si ese selector tiene su versión de escritorio acá; si el rediseño
   necesita otra cosa, la regla a cambiar es la de acá o hay que subir la
   especificidad del selector nuevo, y eso se decide en esas tareas.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══ 1. MÓVIL ANGOSTO (≤400px) ═════════════════════════════════════════════
   A 360px el ancho de la cabecera es el recurso más escaso: marca + interruptor
   de rol + Ayuda + Salir tienen que entrar sin desborde horizontal. */

@media (max-width: 400px) {

    .app-header {
        gap: var(--space-2);
        padding-left: var(--space-3);
        padding-right: var(--space-3);
    }
    .app-header .logo {
        gap: var(--space-2);
        font-size: var(--fs-base);
    }
    .app-header .logo i {
        font-size: 1.2rem;
    }
    /* A 360px la campana le deja ~67px a la marca y «ParqueApp» necesita ~86:
       salía recortado («Parque…»). Se degrada a solo el logo y el nombre queda
       para el lector de pantalla (mismo recorte que `.visually-hidden`). */
    #sidebar:not(.collapsed) .logo-text {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
    .header-actions {
        gap: var(--space-1);
    }

    /* KPIs y tarjeta de trabajo a 360px: las dos columnas de KPIs y el mínimo
       táctil de los botones de acción ya vienen de `components.css`; acá solo se
       aprieta el aire. Los números NO bajan de `--fs-3xl`: son de una o dos
       cifras y el prototipo mantiene 36px hasta el corte de escritorio. */
    .stats-grid {
        gap: var(--space-2);
    }
    .stat-card {
        padding: var(--space-3);
    }
    /* Una sola columna de fichas: con 360px de ancho, dos columnas de
       etiqueta + valor truncan el valor a un par de letras. */
    .job-card .job-cols {
        grid-template-columns: 1fr;
    }
    .job-card {
        padding: var(--space-3);
    }
    .job-card .job-when {
        width: 46px;
    }
    /* Listas de personas a 360px: los tres botones de 44×44 (el mínimo táctil, que
       NO se baja) más el avatar de 46px dejan al nombre unos 70px, o sea dos letras
       y puntos suspensivos. La botonera pasa a un segundo renglón alineado a la
       derecha y el nombre conserva el ancho completo de la fila. */
    .user-card,
    .jobtype-item {
        flex-wrap: wrap;
    }
    .user-card .actions,
    .jobtype-item .jobtype-actions {
        flex: 1 1 100%;
        justify-content: flex-end;
    }
    .jobtype-item .jobtype-icon {
        width: 36px;
        height: 36px;
    }
    /* Informes a 360px (Task 10). Los cuatro bloques que había acá se REESCRIBEN,
       no se retiran. `.reports-grid` a una columna ya lo resuelve el `auto-fill`
       con mínimo 280px de components.css; lo que sí cambia a este ancho es:
         · Los KPIs pasan a DOS columnas: apilados, los cuatro de la fila empujaban
           el primer gráfico por debajo del pliegue (el detalle se abría con una
           columna de tarjetas y nada más). El número baja un paso a `--fs-lg`
           para que «$362.000» no toque los bordes de una tarjeta de ~158px.
         · La fila de las barras es una GRILLA de tres columnas: se achica la de la
           etiqueta y se acorta la separación, en vez de los `width` fijos de
           80px/70px que la versión anterior le peleaba a un `flex`. */
    .report-kpis {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .report-kpi {
        padding: var(--space-3);
    }
    .report-kpi-value {
        font-size: var(--fs-lg);
    }
    .report-bar-row {
        grid-template-columns: 62px minmax(0, 1fr) auto;
        gap: var(--space-2);
    }
}

/* ═══ 2. ESCRITORIO (≥900px) ════════════════════════════════════════════════ */

@media (min-width: 900px) {


    /* ── 2.1 MARCO: de columna de teléfono a ventana completa ── */

    #app {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
        width: 100%;
        max-width: none;
        height: 100%;
        margin: 0;
        border-radius: 0;
        box-shadow: none;
        background: var(--surface-sunken);
        overflow: hidden;
    }

    /* ── 2.2 BARRA LATERAL ──
       #sidebar ES `.app-header`: en escritorio este elemento deja de ser la
       cabecera horizontal y pasa a ser la columna. */

    .app-header {
        grid-column: 1;
        grid-row: 1;
        display: flex;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: 0;
        width: 272px;                      /* = `sidebar` del prototipo */
        min-width: 272px;
        max-width: 272px;
        height: 100%;
        padding: 0;
        border-bottom: none;
        border-right: 1px solid var(--border);
        background: var(--surface);
        /* Fondo SÓLIDO a propósito: con el degradado anterior, el audit de
           contraste no puede resolver el color detrás del texto y todos los
           rótulos del sidebar quedaban `contrast-sin-medir` (la entrada más
           grande de la línea base). */
        overflow: hidden;                   /* el que scrollea es el nav */
        transition: width var(--transition-normal), min-width var(--transition-normal),
            max-width var(--transition-normal);
    }

    #sidebar.collapsed {
        width: 72px;                       /* riel de íconos (spec: 72px) */
        min-width: 72px;
        max-width: 72px;
    }

    /* ── 2.3 CABECERA DE LA BARRA LATERAL (marca + plegado) ── */

    .sidebar-head {
        flex: none;
        gap: var(--space-2);
        padding: var(--space-4) var(--space-4) var(--space-3);
    }

    .app-header .logo {
        flex: 1 1 auto;
        gap: var(--space-3);
        font-size: var(--fs-lg);
        margin-bottom: 0;
    }

    /* La marca: cuadro con el árbol (el `.side-mark` del prototipo). */
    .app-header .logo i {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        border-radius: 13px;
        background: var(--brand);
        color: var(--on-brand);
        font-size: 1.15rem;
        box-shadow: var(--shadow-md);
    }

    .app-header .logo-tag {
        display: block;
        font-family: var(--font-ui);
        font-size: 10px;
        font-weight: 700;
        letter-spacing: .1em;
        line-height: 1.4;
        text-transform: uppercase;
        color: var(--text-faint);
    }

    .sidebar-toggle {
        display: flex;
    }
    /* Riel plegado: la marca (40px) y el botón de plegado (44px, mínimo táctil)
       NO entran en una fila de 88px. Van apilados y centrados, y el botón sigue
       visible: si se escondiera (como en el prototipo), no habría forma de
       desplegar el sidebar otra vez. */
    #sidebar.collapsed .sidebar-head {
        flex-direction: column;
        justify-content: center;
        gap: var(--space-2);
        padding: var(--space-4) var(--space-2) var(--space-3);
    }
    #sidebar.collapsed .sidebar-toggle {
        margin: 0;
    }
    /* El ícono del plegado apunta al lado hacia el que se pliega. */
    #sidebar.collapsed .sidebar-toggle i::before {
        content: "\f054";                  /* fa-chevron-right */
    }
    #sidebar.collapsed .logo-txt {
        display: none;
    }

    /* ── 2.4 INTERRUPTOR DE ROL ── */

    .header-actions {
        flex: none;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        margin-bottom: 0;
        padding: var(--space-2) var(--space-4) var(--space-4);
    }

    .app-header .role-toggle {
        justify-content: space-between;
        padding: var(--space-2) var(--space-3);
        border-radius: var(--radius-sm);
        font-size: var(--fs-xs);
    }
    #sidebar.collapsed .header-actions {
        padding: var(--space-1) var(--space-2) var(--space-2);
    }
    /* Riel compacto: a 1024×768 los 9 ítems del jefe tienen que entrar sin que la
       barra scrollee (ningún target baja de 44px: se recorta solo el aire entre
       bloques). */
    #sidebar.collapsed .sidebar-head {
        padding: var(--space-2) var(--space-2) var(--space-1);
    }
    #sidebar.collapsed .bottom-nav {
        padding: var(--space-2);
    }
    #sidebar.collapsed .sidebar-footer {
        padding: var(--space-2);
    }
    /* En el riel el interruptor queda como un disco de 44px centrado, no como
       una píldora del ancho completo. */
    #sidebar.collapsed .role-toggle {
        justify-content: center;
        width: 44px;
        min-width: 44px;
        height: 44px;
        min-height: 44px;
        margin: 0 auto;
        padding: 0;
        border-radius: 50%;
    }
    #sidebar.collapsed .role-toggle .role-emoji {
        display: none;
    }
    #sidebar.collapsed .role-toggle.boss .toggle-indicator,
    #sidebar.collapsed .role-toggle.employee .toggle-indicator {
        transform: none;
    }

    /* ── 2.5 NAVEGACIÓN VERTICAL ──
       En móvil la barra inferior; en escritorio, la lista del sidebar.
       `min-height: 0` + `overflow-y: auto` son los que dejan que la navegación
       scrollee sola y el pie del sidebar siga siendo alcanzable en ventanas
       bajas (1440×600): sin esto, el pie se sale de la ventana. */

    .bottom-nav {
        flex: 1 1 auto;
        flex-direction: column;
        justify-content: flex-start;
        align-items: stretch;
        gap: 2px;
        min-height: 0;
        padding: var(--space-3) var(--space-3) var(--space-4);
        margin: 0;
        background: transparent;
        border-top: none;
        overflow-x: hidden;
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-width: thin;
        scrollbar-color: var(--border) transparent;
        position: relative;
        z-index: auto;
    }

    .bottom-nav::-webkit-scrollbar {
        width: 6px;
    }
    .bottom-nav::-webkit-scrollbar-track {
        background: transparent;
    }
    .bottom-nav::-webkit-scrollbar-thumb {
        background: var(--border);
        border-radius: 999px;
    }
    .bottom-nav::-webkit-scrollbar-thumb:hover {
        background: var(--border-strong);
    }

    .bottom-nav .nav-item {
        flex: none;
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
        gap: var(--space-3);
        width: 100%;
        min-width: 0;
        min-height: 44px;
        padding: 0 var(--space-3);
        border: 1px solid transparent;
        border-radius: var(--radius-sm);
        color: var(--text-soft);
        font-size: var(--fs-sm);
        font-weight: 600;
        text-align: left;
        transition: background-color var(--transition-fast), color var(--transition-fast),
            border-color var(--transition-fast);
    }

    .bottom-nav .nav-item i {
        width: 20px;
        flex-shrink: 0;
        font-size: 1.05rem;
        text-align: center;
        opacity: .9;
        transition: none;
    }

    .bottom-nav .nav-item:hover {
        background: var(--surface-raised);
        border-color: var(--border);
        color: var(--text);
    }
    .bottom-nav .nav-item:hover i {
        opacity: 1;
    }

    .bottom-nav .nav-item.active {
        background: var(--brand-soft);
        border-color: transparent;
        color: var(--brand-ink);
        font-weight: 600;
    }
    .bottom-nav .nav-item.active i {
        transform: none;
        opacity: 1;
    }

    /* Marcador del ítem activo: barra lateral corta, dentro del propio ítem
       (el `::before` de la barra inferior es la barra de arriba: hay que
       reposicionarlo entero, no alcanza con cambiarle el color). */
    .bottom-nav .nav-item.active::before {
        top: 50%;
        left: 0;
        width: 3px;
        height: 22px;
        transform: translateY(-50%);
        border-radius: 999px;
        background: var(--brand);
    }

    /* En el riel el ítem se centra: sin esto el ícono queda pegado a la
       izquierda en una columna de 88px. */
    #sidebar.collapsed .bottom-nav .nav-item {
        justify-content: center;
        padding: 0;
    }

    .bottom-nav .nav-label {
        flex: 1 1 auto;
        min-width: 0;
        font-size: var(--fs-sm);
        font-weight: 600;
        letter-spacing: 0;
        color: inherit;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    #sidebar.collapsed .bottom-nav .nav-label {
        display: none;
    }

    .bottom-nav .nav-item .nav-badge {
        position: static;
        margin-left: auto;
        padding: 0 6px;
        border: none;
        flex-shrink: 0;
    }
    #sidebar.collapsed .bottom-nav .nav-item .nav-badge {
        position: absolute;
        top: var(--space-2);
        right: var(--space-2);
        margin-left: 0;
        min-width: 16px;
        height: 16px;
        padding: 0 4px;
        font-size: 9px;
    }

    /* ── 2.6 BOTÓN «AGREGAR TRABAJO» ──
       En móvil es el círculo flotante del centro. En escritorio ya NO es un ítem
       del nav —`updateNavVisibility` lo oculta y el alta vive en el bloque CTA de
       abajo—, así que estas reglas solo rigen para la barra inferior. */

    .bottom-nav .nav-item-add {
        width: 100%;
        min-width: 0;
        min-height: 44px;
        margin-top: var(--space-2);
        padding: 0 var(--space-3);
        border-color: transparent;
        background: var(--brand);
        color: var(--on-brand);
        font-weight: 600;
    }
    .bottom-nav .nav-item-add:hover {
        background: var(--brand-strong);
        border-color: transparent;
        color: var(--on-brand);
    }
    /* El CTA «Agregar» del riel queda como disco, alineado con los íconos. */
    #sidebar.collapsed .bottom-nav .nav-item-add {
        justify-content: center;
        width: 44px;
        min-width: 44px;
        margin-top: var(--space-2);
        margin-right: auto;
        margin-left: auto;
        padding: 0;
        border-radius: 50%;
    }

    .bottom-nav .nav-item-add .nav-add-circle {
        width: 20px;
        height: 20px;
        margin-top: 0;
        flex-shrink: 0;
        background: transparent;
        color: var(--on-brand);
        font-size: 1rem;
        box-shadow: none;
    }
    .bottom-nav .nav-item-add.active .nav-add-circle,
    .bottom-nav .nav-item-add:active .nav-add-circle {
        transform: none;
        background: transparent;
    }

    .bottom-nav .nav-item-add .nav-label {
        position: static;
        flex: 1 1 auto;
        min-width: 0;
    }

    /* ── 2.7 BOTÓN «MÁS» ──
       No se muestra en escritorio: con el sidebar están todos los destinos.
       `updateNavVisibility` (ui.js) también lo oculta con `style.display`. */

    .bottom-nav .nav-item-more {
        display: none;
    }

    /* ── 2.7b RÓTULOS DE GRUPO DEL NAV ──
       `.side-group` del prototipo. Separan los destinos por área de trabajo
       (Gestión / Análisis / Cuenta / Global); el `margin` superior es el mismo
       del prototipo y no un `gap`, porque el nav es una columna con `gap: 2px` y
       un margen propio da la separación entre bloques sin tocar el ritmo interno
       de cada uno. */

    .nav-group-label {
        display: block;
        margin: var(--space-3) 0 2px;
        padding: 0 var(--space-3);
        font-size: 10px;
        font-weight: 700;
        letter-spacing: .1em;
        text-transform: uppercase;
        color: var(--text-faint);
    }
    #sidebar.collapsed .nav-group-label {
        display: none;
    }

    /* ── 2.8 PIE DE LA BARRA LATERAL (Ayuda / Salir) ── */

    .app-header .sidebar-footer {
        display: flex;
        flex-direction: column;
        gap: var(--space-1);
        flex: none;
        padding: var(--space-3) var(--space-3) var(--space-4);
        margin: 0;
        border-top: 1px solid var(--border);
    }

    .app-header .sidebar-version {
        display: block;
        padding: 0 var(--space-3) var(--space-2);
        font-size: 10px;
        font-weight: 600;
        letter-spacing: .04em;
        color: var(--text-faint);
        text-align: left;
        white-space: nowrap;
    }
    #sidebar.collapsed .sidebar-version {
        display: none;
    }
    /* La versión solo existe cuando el service worker la informa (`app.js`
       `renderVersion`): vacía no tiene que dejar un renglón en blanco. */
    .app-header .sidebar-version:empty {
        display: none;
    }

    .app-header .sidebar-foot-btn {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        gap: var(--space-3);
        width: 100%;
        height: auto;
        min-height: 44px;
        padding: 0 var(--space-3);
        border: 1px solid transparent;
        border-radius: var(--radius-sm);
        background: transparent;
        color: var(--text-soft);
        font-family: inherit;
        font-size: var(--fs-sm);
        font-weight: 600;
        text-align: left;
        cursor: pointer;
        text-decoration: none;
        transition: background-color var(--transition-fast), color var(--transition-fast),
            border-color var(--transition-fast);
    }
    .app-header .sidebar-foot-btn:hover {
        background: var(--surface-raised);
        border-color: var(--border);
        color: var(--text);
    }
    .app-header .sidebar-foot-btn i {
        width: 20px;
        flex-shrink: 0;
        font-size: 1rem;
        text-align: center;
    }
    .app-header .sidebar-foot-btn .foot-label {
        display: inline;
        white-space: nowrap;
    }
    #sidebar.collapsed .sidebar-foot-btn {
        justify-content: center;
        padding: 0;
    }
    #sidebar.collapsed .sidebar-foot-btn .foot-label {
        display: none;
    }

    /* ── 2.9 ÁREA DE CONTENIDO ── */

    .app-body {
        grid-column: 2;
        grid-row: 1;
        display: flex;
        flex-direction: column;
        flex: 1 1 auto;
        min-width: 0;
        min-height: 0;
        overflow: hidden;
        position: relative;
    }

    /* TOPBAR: barra fija con el título de la página. El título va en Fraunces
       (`--font-display`), que es lo que le da la identidad editorial. */
    .app-topbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-6);
        flex-shrink: 0;
        min-height: 64px;
        padding: var(--space-3) var(--space-7);
        background: var(--surface);
        border-bottom: 1px solid var(--border);
        position: relative;
        z-index: 5;
    }
    .app-topbar .topbar-subtitle:empty {
        display: none;
    }
    .app-topbar .topbar-actions:empty {
        display: none;
    }
    /* Los botones de acción del topbar conservan su tamaño anterior (el que
       medía el arnés) y solo se les garantiza el mínimo táctil: son del sistema
       de botones de `components.css`, y cambiarlos de tamaño mueve el id de
       `touch-targets` de las pantallas de Trabajos y Clientes (el id lleva el
       alto medido). Subirlos a 44px resuelve el ofensor en vez de moverlo. */
    .app-topbar .topbar-actions .btn {
        flex: none;
        min-height: 44px;
        font-size: 0.85rem;
        padding: 9px 18px;
        border-radius: 10px;
        font-weight: 600;
    }

    /* El topbar ya muestra el título: las cabeceras internas de cada página
       (marcadas con `.page-header`) se ocultan para no repetirlo.
       TRAMPA GLOBAL, DOCUMENTADA A PROPÓSITO (Task 13, E): esto no distingue
       «cabecera de título» de «contenedor que casualmente lleva esta clase», y con
       `!important` no hay forma de recuperarlo desde la página. Ya se cobró tres
       acciones que quedaban INALCANZABLES en escritorio (Task 11), y por eso las
       cabeceras de sección del rediseño usan `.section-header` y NO `.page-header`.
       REGLA: `.page-header` sólo para el encabezado de título de una página, y
       NUNCA sobre un contenedor que lleve acciones, filtros o controles: si tiene
       que verse en los dos anchos, va `.section-header`. */
    .page-header {
        display: none !important;
    }

    .main-content {
        flex: 1 1 auto;
        min-height: 0;
        max-width: none;
        margin: 0;
        padding: var(--space-6) var(--space-6) var(--space-8);
        background: var(--surface-sunken);
        border-radius: 0;
        box-shadow: none;
        border-left: none;
        overflow-y: auto;
        height: auto;
    }
    .main-content > .page {
        padding: 0;
        max-width: none;
    }

    /* ── 2.10 MENÚ «MÁS» ──
       Es una hoja inferior en móvil; en escritorio se centra como un diálogo
       (igual que el resto de las hojas del prototipo). */

    .more-menu-overlay {
        align-items: center;
        padding: var(--space-6);
    }
    .more-menu {
        max-width: 620px;
        max-height: 86vh;
        border-bottom: 1px solid var(--border);
        border-radius: var(--radius-xl);
    }

    /* ── STAT CARDS (KPIs del panel de Inicio) ──
       `auto-fit` y no `repeat(5, …)`: la fila del jefe tiene 5 KPIs y la del
       empleado 3, y `superadmin.js` usa la misma grilla con 5. Las pistas vacías
       se colapsan solas, así que las tres filas quedan parejas. El número baja a
       `--fs-2xl` porque con cinco columnas el de 36px no entra en 150px. */
    .stats-grid {
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: var(--space-4);
        margin-bottom: var(--space-6);
    }

    .stat-card:hover {
        transform: translateY(-2px);
        box-shadow: var(--shadow-md);
        border-color: var(--border-strong);
    }

    .stat-card .stat-number {
        font-size: var(--fs-2xl);
    }

    /* ── JOB CARDS ──
       Solo el aire y el alto táctil de escritorio: el aspecto (tarjeta, barra de
       estado, bloque de fecha, fichas) vive en `components.css`, porque esta
       hoja se carga DESPUÉS y una regla de acá con el mismo selector GANA. */
    .job-card {
        padding: var(--space-5);
        margin-bottom: var(--space-4);
    }
    .job-card:hover {
        transform: translateY(-1px);
        box-shadow: var(--shadow-md);
        border-color: var(--border-strong);
    }

    .job-card .job-cols {
        gap: var(--space-3) var(--space-5);
    }

    /* 0.78rem/600 y no `--fs-sm`: el id del perfil de contraste lleva el tamaño y
       el peso, así que el valor se deja literal para que la medida en escritorio
       sea la misma que ya estaba en la línea base. El mínimo táctil vive en el
       alto y el ancho (`min-height`/`min-width`), que es lo que mide
       `touch-targets`. El `contrast-sin-medir` de `.btn-success` NO venía de acá
       sino del gradiente de más abajo, y se corrigió ahí. */
    .job-card .job-actions .btn {
        font-size: 0.78rem;
        padding: 0 var(--space-4);
    }
    .job-card .job-actions .btn:hover {
        transform: translateY(-1px);
        box-shadow: var(--shadow-sm);
    }

    /* `.btn-primary` llevaba un `linear-gradient` acá y era el mismo defecto que se
       corrigió en `.btn-success`: con un gradiente detrás, la auditoría no puede
       resolver el color que se pinta donde cae el texto, y eso es una falta de
       medición —`contrast-sin-medir/button.btn.btn-primary@13.6/600`, el botón
       «Nuevo» de la topbar de Trabajos y Clientes—, no un aprobado.
       Se fija el color en las DOS direcciones: el shorthand `background:
       linear-gradient(…)` que había acá reseteaba `background-color` a
       `transparent`, así que quitar solo `background-image` daba blanco sobre
       blanco (1.00:1, medido: una falla NUEVA peor que la que arregla). Con
       `--brand` (#14512F) el par se mide: blanco sobre #14512F = 9.34:1, AA.
       La tinta pasa a `--on-brand`, que en tema claro es el mismo blanco (no mueve
       ninguna medida) y en tema oscuro es la tinta profunda que el sistema define
       para el relleno de marca: `#fff` sobre `--brand` oscuro (#6FBF8F) mediría
       2.20:1, o sea un botón primario ilegible en modo oscuro. */
    .btn-primary {
        background-image: none;
        background-color: var(--brand);
        color: var(--on-brand);
    }
    .btn-primary:hover {
        background-image: none;
        background-color: var(--brand-strong);
        color: var(--on-brand);
    }
    /* `.btn-success` SÍ llevaba gradiente acá, y era la causa raíz de
       `contrast-sin-medir/button.btn.btn-success@12.5/600` —el botón «Completar»
       de la tarjeta—: la auditoría no puede resolver el color que se pinta donde
       cae el texto, y esa falta de medición es una desviación registrada, no un
       aprobado. Al retirarlo hay que fijar el color a mano, y en las DOS
       direcciones: el shorthand `background: linear-gradient(…)` que había en
       esta misma regla reseteaba `background-color` a `transparent`, así que
       quitar solo `background-image` daba blanco sobre blanco (1.00:1, una falla
       NUEVA peor que la que arregla).
       Con `--success-500` (#2E7D5B) el par se mide: blanco sobre #2E7D5B = 5.00:1
       y pasa AA. */
    .btn-success {
        background-image: none;
        background-color: var(--success-500);
    }
    /* `.btn-danger` llevaba acá un `linear-gradient` de escritorio que el
       rediseño dejó atrás: sobre `@media (min-width: 900px)` el mismo botón
       «Eliminar» pintaba el degradado de Material (#c62828 → #e53935) y por
       debajo pintaba `var(--danger-500)` desde `components.css`. Se retira, y con él
       los dos últimos literales de color de este bloque (`#c62828`, `#e53935`,
       congelados en la línea base como `css/no-literal-colors/responsive.css/…`).
       El shorthand reseteaba además `background-color` a `transparent`.
       No movía ninguna medida de contraste —el control es SÓLO ícono, sin nodo de
       texto, así que la auditoría de texto no tiene ahí ningún par que medir: por
       eso vivió hasta ahora sin que nadie lo viera, y por eso el «0 pares sobre
       gradiente» del informe es un 0 de pares DE TEXTO—, pero sí mejora la
       relación del glifo: `#fff` sobre `--danger-500` (#C0392B) es 5.44:1, contra
       3.98:1 en el extremo claro del degradado (#e53935). Y deja el mismo botón
       pintado igual en los dos anchos. */
    .btn-outline {
        /* `#d1d5db` / `#6b7280` eran literales fuera del sistema y, además, el
           texto quedaba en 4.37:1 sobre `--surface-sunken` (#F7F3EC) —por debajo
           del 4.5:1 de AA— en cuanto un botón «outline» quedara visible en el
           cuerpo de una página. Con los tokens del sistema el par mide 6.83:1 y
           el borde coincide con el del resto de las tarjetas. */
        border: 1.5px solid var(--border-strong);
        color: var(--text-soft);
    }
    .btn-outline:hover {
        border-color: var(--brand);
        color: var(--brand);
        background: var(--brand-soft);
    }

    /* Sin bloque de `.job-card .status-badge`: la chapita se define una sola vez
       en `components.css` (12px/700 para todos los anchos). El bloque que había
       acá la medía 10.9px y ese par estaba en la línea base a 1.97:1; dejarlo
       pisaría, por orden de carga, los colores nuevos del mismo selector. */

    .job-card .photo-preview img {
        width: 64px;
        height: 64px;
        border-radius: 10px;
    }

    /* ── PROPIEDADES Y PAGOS ──
       `.user-card` y `.jobtype-item` SALIERON de este bloque (Task 8): su
       presentación vive entera en `components.css` y esta hoja se carga DESPUÉS,
       así que la versión de acá con el mismo selector la pisaba —el rediseño no se
       veía por encima del breakpoint—.

       `.property-item` y `.payment-item` se REESCRIBEN en la Task 11 (son las
       listas del perfil de cliente, incluida la vista pública): conservan su aire
       de escritorio —18px/22px de relleno, 14px de radio, la elevación del
       `:hover`— pero los literales `#e5e7eb`, `#fff`, `#d1d5db`, `#111827` y el
       `rgba(0,0,0,.06)` de la sombra pasan a los tokens del sistema. */
    .property-item,
    .payment-item {
        padding: 18px 22px;
        border-radius: 14px;
        border: 1px solid var(--border);
        background: var(--surface-raised);
        transition: border-color var(--transition-normal), box-shadow var(--transition-normal),
                    transform var(--transition-normal);
    }
    .property-item:hover,
    .payment-item:hover {
        transform: translateY(-1px);
        box-shadow: var(--shadow-md);
        border-color: var(--border-strong);
    }

    .property-item .property-actions button {
        border-radius: var(--radius-md);
    }

    .property-item .property-name {
        font-size: var(--fs-base);
        font-weight: 600;
        color: var(--text);
    }

    /* Lo único que se ajusta en escritorio para las listas nuevas: el aire. La
       tarjeta, el avatar, las tintas, el `:hover` y el mínimo táctil de 44px de los
       botones vienen de `components.css`. */
    .user-card,
    .jobtype-item {
        padding: var(--space-4) var(--space-5);
    }

    /* ── FILTER TABS ──
       Igual que arriba: el aspecto (pastilla, mínimo táctil de 44px, tintas) vive
       en `components.css`. Se retiró el `box-shadow` con un rgba literal del
       estado activo: el relleno de marca ya distingue la pestaña y el literal no
       aportaba nada que no estuviera en el sistema de tokens. */
    .filter-tabs {
        gap: var(--space-2);
        margin: 0 0 var(--space-4);
    }
    .filter-tabs .filter-btn {
        padding: 0 var(--space-5);
    }

    /* ── NOTIFICATIONS ──
       REESCRITO (Task 11), no retirado: si se quita, el bloque de
       `components.css` aplica igual (esta hoja pierde su regla y no hay nada que
       la pise), pero los literales `#fff` / `#e5e7eb` / `#d1d5db` /
       `rgba(0,0,0,0.04)` que había acá desaparecen en vez de quedar. El alto del
       chip de icono se mantiene en 38px a propósito: es el valor que ya tenía. */
    .notif-item {
        padding: var(--space-4);
        border-radius: var(--radius-md);
    }
    .notif-item .notif-icon {
        width: 38px;
        height: 38px;
        border-radius: var(--radius-sm);
    }

    /* ── PROFILE ── */
    .profile-header {
        background: var(--surface-raised);
        padding: var(--space-6);
        border-radius: var(--radius-lg);
        border: 1px solid var(--border);
        box-shadow: var(--shadow-md);
        margin-bottom: var(--space-5);
    }
    .profile-header .avatar {
        width: 76px;
        height: 76px;
        border-radius: var(--radius-lg);
        font-size: var(--fs-2xl);
    }
    .profile-header .details h2 {
        font-family: var(--font-display);
        font-size: var(--fs-xl);
        font-weight: 600;
        letter-spacing: -0.02em;
        color: var(--text);
    }

    .balance-grid {
        gap: var(--space-4);
        margin-bottom: var(--space-5);
    }
    .balance-card {
        padding: var(--space-5) var(--space-4);
        border-radius: var(--radius-md);
        border: 1px solid var(--border);
    }
    .balance-card:hover {
        transform: translateY(-1px);
        box-shadow: var(--shadow-md);
    }
    .balance-card .number {
        font-size: var(--fs-xl);
    }

    /* REESCRITAS en la Task 11: el título de sección de los perfiles usa
       `--fs-lg`/700 (el mismo del `.section-header` que dejó la Task 7) y los
       botones recuperan su forma de pastilla. El `min-height: 44px` que hace que
       estos botones sean táctiles vive en `components.css` y NO se repite acá: una
       declaración de las dos partes es una que se puede olvidar. */
    .section-toolbar {
        margin: var(--space-6) 0 var(--space-3);
    }
    .section-toolbar h3 {
        font-size: var(--fs-lg);
        font-weight: 700;
        letter-spacing: -0.01em;
    }
    .section-toolbar .btn-sm {
        padding: 0 var(--space-5);
        border-radius: 999px;
        font-size: var(--fs-sm);
    }

    /* ── PAYMENT / PROPERTY ── */
    .payment-list,
    .property-list {
        gap: var(--space-3);
    }
    .payment-item,
    .property-item {
        border-radius: var(--radius-md);
    }
    .payment-item .amount {
        font-size: var(--fs-xl);
    }

    .jobtype-list {
        gap: 10px;
    }
    .jobtype-item {
        border-radius: 12px;
    }

    /* ── EMPTY STATE ── */
    .empty-state {
        padding: 60px 40px;
    }
    .empty-state i {
        font-size: 3.5rem;
    }
    .empty-state p {
        font-size: 1rem;
    }

    /* ── MODAL ──
       Este bloque quedó sin migrar cuando se rediseñó el resto de la hoja: sus
       tintas seguían siendo literales de la paleta vieja, que en el tema oscuro
       quedan casi del color de la hoja (`--surface-raised`, #13291E). Medido a
       1440px con la hoja «Nuevo trabajo» abierta:

         `.modal h2`          #111827 sobre #13291E → 1.15:1 ❌ (ilegible)
         `.form-group label`  #374151 sobre #13291E → 1.49:1 ❌ (ilegible)

       Con los tokens semánticos los dos pares miden AA en los DOS temas:

         `.modal h2`          `--text`      claro #12160F 18.30:1 · oscuro #EAF2EC 13.50:1
         `.form-group label`  `--text-soft` claro #5C5346  7.55:1 · oscuro #A3B8AA  7.33:1

       En tema claro las dos tintas SÍ cambian de valor computado (#111827 →
       #12160F y #374151 → #5C5346: del gris frío de la paleta vieja al neutro
       cálido del sistema); es el precio de usar los tokens y las dos siguen por
       encima de AA. Los detalles están en
       `.superpowers/sdd/2026-09-13-rediseno-interfaz/task-13c-report.md`.

       POR QUÉ NADIE LO VIO: ningún scope del arnés abre un modal —`dark` se queda
       en Inicio—, así que estos pares nunca entraron a la medición de contraste.
       El agujero es de COBERTURA, no de medición: la línea base tiene 0 fallas.
       No se agrega un scope por esto (cambiaría la línea base); la medición de
       esta corrección se hizo a mano, con los ratios del informe. */
    .modal-overlay {
        align-items: center;
        justify-content: center;
        padding: 24px;
        background: rgba(0, 0, 0, 0.4);
        backdrop-filter: blur(8px);
    }

    .modal {
        border-radius: 20px;
        max-width: 580px;
        max-height: 88vh;
        width: 100%;
        padding: 32px 36px 38px;
        box-shadow: 0 24px 64px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0,0,0,0.05);
        animation: dialogIn 0.3s cubic-bezier(0.16, 1, 0.3, 1);
    }
    @keyframes dialogIn {
        from { transform: translateY(24px) scale(0.97); opacity: 0; }
        to { transform: translateY(0) scale(1); opacity: 1; }
    }

    .modal .modal-handle {
        display: none;
    }

    .modal h2 {
        font-size: 1.35rem;
        margin-bottom: 24px;
        font-weight: 800;
        color: var(--text);
    }

    .modal .form-group label {
        font-size: 0.82rem;
        font-weight: 600;
        color: var(--text-soft);
    }

    .modal .form-group input,
    .modal .form-group select,
    .modal .form-group textarea {
        font-size: 0.95rem;
        padding: 12px 16px;
        border-radius: 12px;
        border: 1.5px solid #d1d5db;
        transition: 0.2s;
    }
    .modal .form-group input:focus,
    .modal .form-group select:focus,
    .modal .form-group textarea:focus {
        border-color: #2e7d32;
        box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.12);
    }

    .modal .form-actions {
        gap: 12px;
        margin-top: 24px;
    }
    .modal .form-actions .btn {
        padding: 14px;
        font-size: 0.95rem;
        border-radius: 12px;
        font-weight: 700;
    }

    /* ── TOAST ── */
    .toast-container {
        max-width: 480px;
    }

    .toast {
        font-size: 0.9rem;
        padding: 16px 24px;
        border-radius: 14px;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
    }

    /* ── DETAIL ROWS ──
       El tamaño de la letra de la etiqueta y del valor sale de `components.css`
       (`.detail-row .label` / `.value`); acá solo se le da más aire a la fila. */
    .detail-row {
        padding: var(--space-3) 0;
    }

}

/* ═══ 3. ESCRITORIO ANCHO (≥1400px) ═════════════════════════════════════════ */

@media (min-width: 1400px) {

    .app-topbar {
        padding-left: var(--space-8);
        padding-right: var(--space-8);
    }
    .main-content {
        padding: var(--space-7) var(--space-8) var(--space-9);
    }

    .main-content > .page {
        padding: 32px 24px 40px;
        max-width: none;
    }

    /* KPIs y tarjeta de trabajo en escritorio ancho: más aire, sin tocar el
       tamaño de la letra. El número de KPI se queda en `--fs-2xl` (el corte de
       900px ya lo bajó) y el título en `--fs-md`; moverlos acá cambiaría los ids
       de contraste sin ninguna ganancia. */
    .stats-grid {
        gap: var(--space-5);
    }

    .stat-card {
        padding: var(--space-5);
    }

    .job-card {
        padding: var(--space-5) var(--space-6);
    }
    .job-card .job-cols {
        gap: var(--space-4) var(--space-6);
    }

    .modal {
        max-width: 640px;
        padding: 36px 42px 42px;
    }
}


/* ═══ AGENDA EN DOS COLUMNAS (Task 8) ═══════════════════════════════════════
   A partir de 1200px el calendario y la lista del día van lado a lado, mitad y
   mitad. Con la barra lateral, cada columna deja a la grilla más de 44px por día
   (con el gap de 2px). */
@media (min-width: 1200px) {
    .agenda-layout {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: start;
        gap: var(--space-6);
    }
}


/* ═══ SHELL RESPONSIVO, NAVEGACIÓN POR ROL Y HOJAS (rediseño móvil, Task 3) ═══
   Va al FINAL a propósito: pisa con la misma especificidad los bloques de 900px
   y 1400px de arriba (el diálogo de 580/640px pasa a 560px, el marco de 480px
   deja de limitar a la tablet). Puntos de corte, siempre en `min-width`:
     600px  tablet: barra con ítems de ancho fijo, hojas como diálogo
     900px  lateral (`DESKTOP_BREAKPOINT` de app.js, no se mueve)
     1200px PC ancha: la lateral vuelve a desplegarse (app.js, `applySidebarRail`) */

/* Columna de contenido centrada (`.content-col` va en cada `#mainContent > .page`).
   Móvil: ancho completo con el gutter de `.main-content`. */
.main-content > .page.content-col {
    width: 100%;
    margin-inline: auto;
}

@media (min-width: 600px) {

    /* El marco de 480px era el teléfono; desde la tablet ocupa todo el ancho. */
    #app {
        max-width: none;
        box-shadow: none;
    }

    .main-content > .page.content-col {
        max-width: 720px;
    }

    /* ── Hojas: de hoja inferior a diálogo centrado de 560px ── */
    .modal-overlay,
    .more-menu-overlay {
        align-items: center;
        justify-content: center;
        padding: var(--space-6);
    }
    .modal,
    .more-menu {
        width: 100%;
        max-width: 560px;
        border-radius: var(--radius-xl);
    }
    .modal {
        animation: sheetDialogIn 0.28s cubic-bezier(0.16, 1, 0.3, 1);
    }
    .more-menu {
        border-bottom: 1px solid var(--border);
        animation: sheetDialogIn 0.28s cubic-bezier(0.16, 1, 0.3, 1);
    }
}

@keyframes sheetDialogIn {
    from { transform: translateY(16px) scale(0.98); opacity: 0; }
    to { transform: translateY(0) scale(1); opacity: 1; }
}

/* Barra inferior de la tablet vertical: ítems de ancho fijo, centrados, con
   rótulo legible. Arriba de 900px la barra es la lateral. */
@media (min-width: 600px) and (max-width: 899.98px) {
    .bottom-nav {
        justify-content: center;
    }
    .bottom-nav .nav-item {
        flex: 1 1 0;
        max-width: 120px;
    }
    .bottom-nav .nav-label {
        font-size: var(--fs-xs);
    }
}

@media (min-width: 900px) {
    .main-content > .page.content-col {
        max-width: 960px;
    }
}

@media (min-width: 1200px) {
    .main-content > .page.content-col {
        max-width: 1200px;
    }
}

/* ── Hojas: cuerpo con scroll y botones de acción fijos abajo ──
   Todas miden como máximo el 92% del alto de la ventana (`dvh`: el alto REAL con
   la barra del navegador). `.modal` ya scrollea (`overflow-y: auto`); los
   botones se pegan al borde inferior con `position: sticky` y le ponen fondo
   propio para tapar lo que pasa por detrás. */
.modal,
.more-menu {
    max-height: 92dvh;
}
.modal {
    --sheet-pad-x: 20px;
    --sheet-pad-b: calc(24px + var(--safe-bottom));
    max-width: none;
    padding: 24px var(--sheet-pad-x) var(--sheet-pad-b);
}
@media (min-width: 600px) {
    /* Los paddings de la hoja a ≥600 viven acá, DESPUÉS de la definición base de
       arriba (la misma especificidad: la última gana). */
    .modal {
        max-width: 560px;
        --sheet-pad-x: 28px;
        --sheet-pad-b: 28px;
    }
}
.modal .form-actions {
    position: sticky;
    bottom: 0;
    z-index: 1;
    margin-inline: calc(-1 * var(--sheet-pad-x));
    margin-bottom: calc(-1 * var(--sheet-pad-b));
    padding: var(--space-3) var(--sheet-pad-x) var(--sheet-pad-b);
    border-top: 1px solid var(--border);
    background: var(--surface-raised);
}

@media (prefers-reduced-motion: reduce) {
    .modal,
    .more-menu {
        animation: none;
    }
}

/* Controles de formulario de las hojas: 44px de alto táctil en todos los anchos
   (el arnés los midió en 41 y 43px apenas hubo un scope que abriera la hoja). */
.modal .form-group input:not([type="checkbox"]):not([type="radio"]),
.modal .form-group select {
    min-height: 44px;
}

/* ── Riel de íconos (lateral plegada de 72px): los rótulos se ocultan SIN salir
   del árbol de accesibilidad ──
   Con `display: none` los botones del riel quedaban SIN nombre (solo un ícono) y
   el tema no se podía elegir. Se usa el mismo recorte de `.visually-hidden`
   (layout.css): el texto no se pinta pero lo leen el lector de pantalla y el
   arnés de contraste. El tema se vuelve un disco de 44px con el `<select>`
   transparente encima: el foco lo dibuja el contenedor (`:focus-within`). */
@media (min-width: 900px) {
    #sidebar.collapsed .logo-txt,
    #sidebar.collapsed .bottom-nav .nav-label,
    #sidebar.collapsed .sidebar-foot-btn .foot-label,
    #sidebar.collapsed .role-toggle .role-emoji {
        position: absolute;
        display: block;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }

    #sidebar.collapsed .theme-field {
        position: relative;
        display: flex;
        justify-content: center;
        width: 44px;
        height: 44px;
        margin: 0 auto;
        padding: 0;
        gap: 0;
        border-radius: 50%;
    }
    #sidebar.collapsed .theme-field .theme-select {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        opacity: 0;
    }
    #sidebar.collapsed .theme-field:focus-within {
        outline: 2px solid var(--brand);
        outline-offset: 2px;
    }
}

/* Los rótulos de grupo no entran en el riel: se recortan como el resto de los
   rótulos (siguen en el árbol de accesibilidad). `!important` porque
   `updateNavVisibility` les fija `style.display = 'block'` en línea y la regla
   de `display: none` de arriba nunca los alcanzaba: se veían cortados. */
@media (min-width: 900px) {
    #sidebar.collapsed .nav-group-label {
        position: absolute;
        display: block !important;
        width: 1px;
        height: 1px;
        min-height: 0;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}

/* ── Detalle del trabajo como panel lateral (Task 6) ──
   Desde 900px, con la barra lateral visible, el detalle no tapa la pantalla con
   un diálogo: es un panel de 440px, a alto completo, anclado a la derecha. */
@media (min-width: 900px) {
    #modalOverlay.is-detail {
        align-items: stretch;
        justify-content: flex-end;
        padding: 0;
    }
    #modalOverlay.is-detail #modalPanel {
        width: 440px;
        max-width: 440px;
        height: 100dvh;
        max-height: 100dvh;
        border-radius: 0;
        --sheet-pad-x: 24px;
        --sheet-pad-b: 24px;
        padding: 24px var(--sheet-pad-x) 0;
        animation: sheetPanelIn 0.28s cubic-bezier(0.16, 1, 0.3, 1);
    }
    #modalOverlay.is-detail .modal-handle { display: none; }
}
@keyframes sheetPanelIn {
    from { transform: translateX(24px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    #modalOverlay.is-detail #modalPanel { animation: none; }
}

/* ── Inicio (Task 7) ──
   KPIs en una fila de 4 desde la tablet; desde 1200px el panel se parte en una
   columna principal (Hoy, Esta semana) y una lateral (Saldos, Actividad). */
@media (min-width: 600px) {
    .kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
    .home-grid {
        display: grid;
        grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
        gap: var(--space-6);
        align-items: start;
    }
}


/* ═══ FICHA DEL CLIENTE EN DOS COLUMNAS (Task 9) ═════════════════════════════
   A partir de 1200px el perfil (datos, accesos, dinero y enlace) queda a la
   izquierda y las pestañas a la derecha, que es la que crece. */
@media (min-width: 1200px) {
    .client-layout {
        display: grid;
        grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
        align-items: start;
        gap: var(--space-6);
    }
}
