/*
 * Decaio — capa propia sobre Nocturne (nocturne.css): nocturne.css sigue definiendo la forma
 * de los componentes (.btn, .card, .table...) y los nombres de los tokens; esta hoja redefine
 * los VALORES de esos tokens (identidad de marca propia, ver openspec/changes/
 * deca-identidad-visual/design.md) y añade lo que Nocturne no cubre: fuentes autoalojadas,
 * tema claro/oscuro, composición de página por superficie, iconos y utilidades.
 */

/* — fuentes autoalojadas, sin CDN (independencia del proyecto) —
   Inter: UI, formularios, texto largo. Space Grotesk: titulares, rutas, cifras grandes.
   JetBrains Mono: referencias de porte, matrículas, códigos, pesos — datos, no prosa. */
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/assets/fonts/Inter-Regular.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("/assets/fonts/Inter-Medium.woff2") format("woff2");
}
@font-face {
    font-family: "Inter";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("/assets/fonts/Inter-SemiBold.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("/assets/fonts/SpaceGrotesk-Medium.woff2") format("woff2");
}
@font-face {
    font-family: "Space Grotesk";
    font-style: normal;
    font-weight: 600 700;
    font-display: swap;
    src: url("/assets/fonts/SpaceGrotesk-Bold.woff2") format("woff2");
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/assets/fonts/JetBrainsMono-Regular.woff2") format("woff2");
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("/assets/fonts/JetBrainsMono-Medium.woff2") format("woff2");
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("/assets/fonts/JetBrainsMono-SemiBold.woff2") format("woff2");
}

/* — tema: claro por defecto (también sin JS), oscuro nativo de Nocturne bajo data-tema —
   el atributo va en <html>, no en <body>, para poder fijarlo antes del primer pintado
   (el <body> aún no existe cuando corre el script anti-flash del <head>). */
:root {
    /* Titulares/rutas/cifras grandes en Space Grotesk (var(--font-heading) ya la usan h1-h4,
       .btn, .card-title, .dialog-title y .nav-brand en nocturne.css - se hereda sin tocar
       ninguna de esas reglas). 600 no existe como instancia estática de Space Grotesk: el
       @font-face de "Bold" declara font-weight: 600 700, así que una petición de 600 resuelve
       a ese mismo fichero (700 real), sin negrita sintética del navegador. */
    --font-heading: "Space Grotesk", "Inter", system-ui, sans-serif;
    --font-heading-weight: 600;
    /* Nocturne no define una familia monoespaciada; referencias de porte, matrículas, códigos
       y pesos ya llevan .tabular-nums en todas las vistas - se reutiliza ese mismo hook. */
    --font-mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
    /* Escala de espaciado y radio de la identidad de marca (múltiplos de 4), ver design.md de
       deca-identidad-visual - mismos nombres de token que nocturne.css, valores nuevos, así
       que ninguna regla que ya use var(--space-N)/var(--radius-N) necesita tocarse. */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-6: 24px;
    --space-8: 32px;
    --radius-sm: 7px;
    --radius-md: 10px;
    /* --radius-lg se queda en los 14px de nocturne.css: no cambia. */
    --color-bg: #f4f2fb;
    --color-surface: #ffffff;
    --color-text: #201c3d;
    --color-accent: #6e5fd8;
    --color-accent-300: #4c3fb0;
    --color-accent-contrast: #ffffff;
    --color-divider: #e2ddf5;
    --shadow-sm: 0 1px 2px rgba(32, 28, 61, .06), 0 1px 1px rgba(32, 28, 61, .04);
    --shadow-md: 0 1px 2px rgba(32, 28, 61, .06), 0 1px 1px rgba(32, 28, 61, .04);
    --shadow-lg: 0 8px 24px rgba(32, 28, 61, .14), 0 2px 6px rgba(32, 28, 61, .08);
    /* Nocturne no define estados de éxito/error; se añaden aquí, no existen en el sistema. */
    --color-danger: #b3261e;
    --color-success: #1e6b3c;
    /* Colores de estado del porte (Sin DeCA/Emitido/Recibido/Caducado), ver .tag-sin-deca y
       compañía más abajo - no existen en Nocturne, que solo tenía accent/neutral genéricos. */
    --color-estado-sin-deca: #8a8aa0;
    --color-estado-sin-deca-soft: #eeeef5;
    --color-estado-emitido: #3b6fd9;
    --color-estado-emitido-soft: #e7eefc;
    --color-estado-recibido: #2f9e63;
    --color-estado-recibido-soft: #e4f6ec;
    --color-estado-caducado: #d6484a;
    --color-estado-caducado-soft: #fbe9e9;
}
html[data-tema="claro"] {
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-6: 24px;
    --space-8: 32px;
    --radius-sm: 7px;
    --radius-md: 10px;
    --color-bg: #f4f2fb;
    --color-surface: #ffffff;
    --color-text: #201c3d;
    --color-accent: #6e5fd8;
    --color-accent-300: #4c3fb0;
    --color-accent-contrast: #ffffff;
    --color-divider: #e2ddf5;
    --shadow-sm: 0 1px 2px rgba(32, 28, 61, .06), 0 1px 1px rgba(32, 28, 61, .04);
    --shadow-md: 0 1px 2px rgba(32, 28, 61, .06), 0 1px 1px rgba(32, 28, 61, .04);
    --shadow-lg: 0 8px 24px rgba(32, 28, 61, .14), 0 2px 6px rgba(32, 28, 61, .08);
    --color-danger: #b3261e;
    --color-success: #1e6b3c;
    --color-estado-sin-deca: #8a8aa0;
    --color-estado-sin-deca-soft: #eeeef5;
    --color-estado-emitido: #3b6fd9;
    --color-estado-emitido-soft: #e7eefc;
    --color-estado-recibido: #2f9e63;
    --color-estado-recibido-soft: #e4f6ec;
    --color-estado-caducado: #d6484a;
    --color-estado-caducado-soft: #fbe9e9;
}
html[data-tema="oscuro"] {
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-6: 24px;
    --space-8: 32px;
    --radius-sm: 7px;
    --radius-md: 10px;
    --color-bg: #161230;
    --color-surface: #1e1a3c;
    --color-text: #f1eefc;
    --color-accent: #9a8cf0;
    --color-accent-300: #b7acf5;
    --color-accent-contrast: #181233;
    --color-divider: #332c5c;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
    --shadow-md: 0 1px 2px rgba(0, 0, 0, .3);
    --shadow-lg: 0 12px 28px rgba(0, 0, 0, .45);
    --color-danger: #ff6b60;
    --color-success: #5fd68a;
    --color-estado-sin-deca: #a3a3ba;
    --color-estado-sin-deca-soft: #26233f;
    --color-estado-emitido: #7ba3f2;
    --color-estado-emitido-soft: #1d2a48;
    --color-estado-recibido: #6bcc9a;
    --color-estado-recibido-soft: #1b3327;
    --color-estado-caducado: #e88486;
    --color-estado-caducado-soft: #3a2129;
}
/* .tag-accent/.tag-neutral (trazabilidad: "creación" vs resto de eventos - significado sin
   relación con el estado del porte, ver .tag-sin-deca y compañía más abajo) heredan ahora el
   color de marca vía --color-accent en vez de la rampa fija de Nocturne, para que sigan
   coherentes con el resto de la identidad tras el rebrand. */
:root, html[data-tema="claro"] {
    --tag-accent-bg: color-mix(in srgb, var(--color-accent) 16%, var(--color-surface));
    --tag-accent-text: var(--color-accent-300);
    --tag-neutral-bg: var(--color-neutral-200);
    --tag-neutral-text: var(--color-neutral-800);
}
html[data-tema="oscuro"] {
    --tag-accent-bg: color-mix(in srgb, var(--color-accent) 22%, var(--color-surface));
    --tag-accent-text: var(--color-accent-300);
    --tag-neutral-bg: var(--color-neutral-800);
    --tag-neutral-text: var(--color-neutral-100);
}
.tag-accent { background: var(--tag-accent-bg); color: var(--tag-accent-text); }
.tag-neutral { background: var(--tag-neutral-bg); color: var(--tag-neutral-text); }

/* — estado del porte, un color distinto por valor (antes recibido/caducado compartían el
   mismo gris de .tag-neutral, indistinguibles entre sí) — ver estado_tag_clase() en
   src/View/helpers.php. Propias del estado del porte, sin relación con .tag-accent/.tag-neutral
   (trazabilidad). — */
.tag-sin-deca { background: var(--color-estado-sin-deca-soft); color: var(--color-estado-sin-deca); }
.tag-emitido { background: var(--color-estado-emitido-soft); color: var(--color-estado-emitido); }
.tag-recibido { background: var(--color-estado-recibido-soft); color: var(--color-estado-recibido); }
.tag-caducado { background: var(--color-estado-caducado-soft); color: var(--color-estado-caducado); }

body { font-family: "Inter", var(--font-body); }

/* — jerarquía de 3 pesos de botón (ver design.md, Decisión 2): nocturne.css define
   .btn-primary solo con color/border (contorno) - aquí se le añade relleno sólido, con hover
   y active oscureciendo/aclarando el propio relleno (no un tinte sobre transparente, que es
   lo que hacen los estados de nocturne.css pensados para el contorno). .btn-secondary y
   .btn-ghost no necesitan redefinirse: ya son contorno y texto en nocturne.css, solo heredan
   los nuevos tokens de color. */
.btn-primary {
    background: var(--color-accent);
    color: var(--color-accent-contrast);
    border-color: var(--color-accent);
}
.btn-primary:hover { background: var(--color-accent-300); border-color: var(--color-accent-300); }
.btn-primary:active { background: var(--color-accent-300); border-color: var(--color-accent-300); }
/* nocturne.css ya define .btn svg { display: block; } (sin tamaño) - lo completa aquí. */
.btn svg { width: 16px; height: 16px; }

/* — avisos flash (no es un componente de Nocturne) — */
.flash { padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); margin-bottom: var(--space-4); }
.flash-error { background: color-mix(in srgb, var(--color-danger) 12%, var(--color-surface)); color: var(--color-danger); border: 1px solid color-mix(in srgb, var(--color-danger) 35%, transparent); }
.flash-success { background: color-mix(in srgb, var(--color-success) 12%, var(--color-surface)); color: var(--color-success); border: 1px solid color-mix(in srgb, var(--color-success) 35%, transparent); }
.aviso { background: color-mix(in srgb, var(--color-danger) 12%, var(--color-surface)); color: var(--color-danger); border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4); font-size: 13px; }
/* — variante informativa (no es un error): política de borrado lógico, notas operativas —
   antes era solo un <p class="text-muted"> al pie de la tabla, con el mismo peso visual que
   cualquier otro texto secundario, fácil de pasar por alto. */
.aviso-info {
    display: flex; gap: var(--space-2); align-items: flex-start;
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface)); color: var(--color-text);
    border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4); font-size: 12px;
}
.aviso-info svg { flex: none; width: 16px; height: 16px; margin-top: 1px; color: var(--color-accent); }

/* — agrupación de formularios largos: Nocturne no define fieldset/legend ni un grid de 2
   columnas para campos — son composición del formulario del art. 6, no un componente. — */
fieldset {
    border: none; background: var(--color-surface); border-radius: var(--radius-md);
    padding: var(--space-4); margin: 0 0 var(--space-4);
}
fieldset > .field:last-child { margin-bottom: 0; }
legend {
    font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: color-mix(in srgb, var(--color-text) 55%, transparent); padding: 0 var(--space-1); margin-bottom: var(--space-2);
}
.field { margin-bottom: var(--space-4); }
/* — marca visual de obligatoriedad: los opcionales ya lo dicen en el propio texto de la
   etiqueta ("(opcional)"), a los obligatorios les falta cualquier señal — un asterisco en
   acento en la etiqueta de todo control con el atributo `required`, sin tocar cada vista.
   El segundo selector cubre el input una vez combobox.js lo envuelve en .combo (deja de
   ser hermano directo del label, pasa a ser su descendiente). — */
.field > label:has(+ :required)::after,
.field > label:has(+ .combo :required)::after { content: " *"; color: var(--color-accent); }
.form-grid { display: grid; grid-template-columns: 1fr; gap: 0 var(--space-4); }
/* Container query, no @media: el ancho real disponible depende del sidebar (196px) y de si la
   página es un formulario centrado y más estrecho - el viewport por sí solo no lo dice (ver
   .pagina-formulario* y .app-main-content más abajo). */
@container (min-width: 560px) {
    .form-grid { grid-template-columns: 1fr 1fr; }
}

/* — tablas clave/valor (detalle de porte, tarjeta pública): columna de etiqueta atenuada — */
.table td.label { color: color-mix(in srgb, var(--color-text) 55%, transparent); width: 35%; }

/* — el scroll horizontal, si hace falta, es de la tabla, nunca de la página entera — */
.tabla-scroll { overflow-x: auto; }

/* — barra de envío fija al pie de un formulario largo (varios fieldset): sin esto, el
   botón de guardar solo aparece tras el último bloque y obliga a un scroll largo de ida
   y vuelta para llegar a él. `position: fixed` (no sticky: tiene que estar visible desde
   el principio del formulario, no solo al llegar a su posición natural al final) anclada
   al pie del área de contenido - descuenta el ancho del sidebar en escritorio, a todo lo
   ancho en móvil donde el sidebar es un cajón fuera de flujo. — */
.barra-acciones {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
    display: flex; justify-content: center; align-items: center; gap: var(--space-3); flex-wrap: wrap;
    padding: var(--space-3) var(--space-6);
    background: var(--color-surface); border-top: 1px solid var(--color-divider);
    box-shadow: var(--shadow-md);
}
.barra-acciones .btn { margin: 0; }
/* el peso visual (min-width) es cosa de la acción primaria - un "Cancelar" secundario al
   lado no necesita el mismo ancho forzado, sobre todo en formularios de edición. */
.barra-acciones .btn-primary { min-width: 200px; }
@media (min-width: 641px) { .barra-acciones { left: 196px; } }
/* espacio de sobra al final del formulario para que el último campo no quede tapado
   tras la barra fija cuando se hace scroll hasta el fondo. */
.pagina-formulario:has(.barra-acciones), .pagina-formulario-ancha:has(.barra-acciones) { padding-bottom: 76px; }

/* — tablas de datos (listados con muchas columnas): en escritorio, tabla normal dentro de
   .tabla-scroll; en móvil el scroll horizontal esconde la acción principal fuera de pantalla,
   así que cada fila pasa a ser una tarjeta apilada (thead oculto, cada td se etiqueta con
   `data-label` a partir del <th> de su columna). Aplicar la clase `.tabla-responsive` en el
   <table> solo a listados de muchas columnas - las tablas clave/valor (detalle de porte,
   tarjeta pública) ya son de 2 columnas y no lo necesitan. — */
@media (max-width: 640px) {
    .tabla-responsive thead { display: none; }
    .tabla-responsive, .tabla-responsive tbody, .tabla-responsive tr { display: block; width: 100%; }
    .tabla-responsive tbody tr {
        background: none; border: 1px solid var(--color-divider); border-radius: var(--radius-md);
        padding: var(--space-2) var(--space-3); margin-bottom: var(--space-3);
    }
    .tabla-responsive tbody tr:last-child { margin-bottom: 0; }
    .tabla-responsive tbody tr:hover { background: none; }
    .tabla-responsive td { display: block; padding: var(--space-2) 0; border-bottom: 1px solid var(--color-divider); }
    .tabla-responsive td:last-child { border-bottom: none; }
    .tabla-responsive td[data-label] {
        display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); text-align: right;
    }
    .tabla-responsive td[data-label]::before {
        content: attr(data-label); font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
        color: color-mix(in srgb, var(--color-text) 60%, transparent); text-align: left; flex: none;
    }
}

/* — code inline (código de entrega), Nocturne no define uno — */
code { background: var(--tag-neutral-bg); color: var(--tag-neutral-text); padding: .1em .35em; border-radius: 3px; font-size: .9em; font-family: var(--font-mono); }

/* — separación entre tarjetas hermanas: Nocturne no define espaciado entre .card
   consecutivas (solo el padding interno de cada una), así que sin esto quedan pegadas
   entre sí en cualquier pantalla con varias (detalle de porte, entrega al conductor,
   incidencias...). — */
.card + .card { margin-top: var(--space-6); }

/* — enlace público / de entrega: se corta visualmente con elipsis (puede pasar de 70
   caracteres) en vez de desbordar, con un botón "Copiar" siempre accesible junto a él en
   vez de obligar a seleccionar el texto a mano, ver [data-copiar] más abajo. — */
.enlace-copiable { display: flex; align-items: center; gap: var(--space-2); max-width: 100%; min-width: 0; }
.enlace-truncado {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 0%;
    font-size: 13px; color: color-mix(in srgb, var(--color-text) 75%, transparent);
}
.enlace-copiable .btn { flex: none; }

/* — fila de resumen de solo lectura (enlace/fecha/código de un documento ya generado):
   etiqueta atenuada encima, valor debajo - mismo lenguaje visual que .field > label de los
   formularios, para que una pantalla de "solo consulta" no desentone de una de "editar". — */
.campo-resumen { margin-bottom: var(--space-3); max-width: 100%; min-width: 0; }
.campo-resumen-k {
    display: block; font-size: 12px; margin-bottom: 5px;
    color: color-mix(in srgb, var(--color-text) 70%, transparent);
}

/* — registros inactivos del CRUD — */
.inactivo { opacity: 0.5; }

/* — cifras: tabular-nums para fechas, importes, matrículas y códigos — */
.tabular-nums { font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
.mono { font-family: var(--font-mono); }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* — entrada de pantalla — */
@keyframes deca-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.deca-in { animation: deca-in .22s ease both; }

/* — composición: cabecera del backoffice (sin relleno, tipografía + conmutador de tema) — */
.app-header {
    display: flex; align-items: center; gap: var(--space-6);
    padding: var(--space-3) var(--space-6);
    border-bottom: 1px solid var(--color-divider);
}
.app-header .brand { display: flex; align-items: center; margin-right: auto; }
.app-header .brand .logo-cabecera { height: 40px; width: auto; display: block; }
.app-header .brand-sub { font-size: 12px; color: color-mix(in srgb, var(--color-text) 55%, transparent); margin-left: var(--space-2); }
.tema-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; flex: none;
    background: transparent; border: 1px solid var(--color-divider); border-radius: var(--radius-md);
    color: var(--color-text); padding: 0; cursor: pointer;
}
.tema-toggle:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
.tema-toggle svg { width: 18px; height: 18px; display: block; }
/* El icono muestra a qué tema se pasa al pulsar (no el tema actual): en claro, luna -> "pulsa
   para pasar a oscuro"; en oscuro, sol -> "pulsa para pasar a claro". Lo decide el atributo que
   ya fija el script anti-flash antes del primer pintado - sin esto, un solo frame con los dos
   iconos a la vez o con el que no toca. */
.tema-toggle .icono-sol { display: none; }
html[data-tema="oscuro"] .tema-toggle .icono-sol { display: block; }
html[data-tema="oscuro"] .tema-toggle .icono-luna { display: none; }

/* — botón de menú (hamburguesa): solo existe visualmente por debajo de 640px, ver media query
   más abajo. En escritorio el sidebar va siempre visible, no hace falta abrirlo. — */
.menu-toggle {
    display: none; background: transparent; border: 1px solid var(--color-divider); border-radius: var(--radius-md);
    color: var(--color-text); font-size: 16px; line-height: 1; padding: var(--space-2) var(--space-3); cursor: pointer;
}
.menu-toggle:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

/* — composición: sidebar de navegación del backoffice — */
.app-shell { display: flex; align-items: stretch; min-height: 0; position: relative; }
.sidebar-backdrop { display: none; }
.app-sidebar {
    width: 250px; flex: none; padding: var(--space-3) var(--space-3) var(--space-6) var(--space-6);
    display: flex; flex-direction: column; gap: 2px;
}
.app-sidebar .sidebar-kicker {
    font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
    color: color-mix(in srgb, var(--color-text) 55%, transparent);
    padding: var(--space-2) var(--space-3);
}
.app-sidebar a {
    display: flex; align-items: center; gap: var(--space-2);
    text-align: left; padding: var(--space-2) var(--space-3); font-size: 14px;
    border-radius: var(--radius-md); text-decoration: none; color: var(--color-text);
}
.app-sidebar a svg { width: 18px; height: 18px; flex: none; }
.app-sidebar a:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }
.app-sidebar a[aria-current="page"] {
    background: color-mix(in srgb, var(--color-accent) 14%, transparent); color: var(--color-accent);
}
.app-sidebar .sidebar-footer {
    margin-top: auto; padding: var(--space-3) var(--space-3);
    font-size: 11px; line-height: 1.5; color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.app-sidebar form { margin: 0; }
.app-sidebar .btn-ghost { width: 100%; justify-content: flex-start; }

/* — en móvil el sidebar fijo de 196px no cabe: pasa a cajón oculto, abierto con la hamburguesa — */
@media (max-width: 640px) {
    .menu-toggle { display: inline-flex; align-items: center; justify-content: center; }
    .app-sidebar {
        position: fixed; inset: 0 25vw 0 0; width: auto; max-width: 320px; z-index: 50;
        background: var(--color-surface); box-shadow: var(--shadow-lg);
        padding: var(--space-6) var(--space-4);
        transform: translateX(-100%); transition: transform .22s ease;
        overflow-y: auto;
    }
    .app-sidebar.abierto { transform: translateX(0); }
    .sidebar-backdrop {
        display: block; position: fixed; inset: 0; z-index: 40;
        background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
        opacity: 0; pointer-events: none; transition: opacity .22s ease;
    }
    .sidebar-backdrop.abierto { opacity: 1; pointer-events: auto; }
}

.app-main { flex: 1; min-width: 0; padding: var(--space-3) var(--space-6) var(--space-8) var(--space-3); }
/* Contenedor de paso, a todo el ancho disponible del main: cada vista decide su propio ancho y
   si va centrada o alineada a la izquierda con las clases de abajo, aplicadas a su elemento raíz -
   así una tabla (ancha, pegada a la izquierda, "asimétrico" per SPEC_UI_PDF.md) y un formulario
   (más estrecho, centrado en el espacio disponible) pueden convivir sin que este contenedor
   compartido de layout.php tenga que saber cuál es cuál. */
.app-main-content { width: 100%; }

/* — listados y páginas de detalle: alineados a la izquierda, con aire a la derecha — */
.contenido-ancho { max-width: 900px; container-type: inline-size; }

/* — formularios: centrados en el espacio disponible, no pegados al sidebar. container-type
   aquí (no en .app-main-content) para que .form-grid responda al ancho real de la página de
   formulario (640/860px), no al del contenedor de paso a todo lo ancho del main. — */
.pagina-formulario { max-width: 640px; margin-inline: auto; container-type: inline-size; }
.pagina-formulario-ancha { max-width: 860px; margin-inline: auto; container-type: inline-size; }

/* — composición: app del conductor (móvil, centrada) — */
.marco {
    position: relative; overflow: hidden;
    width: 100%; max-width: 360px; min-height: 70vh; background: var(--color-surface);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
    padding: var(--space-8) var(--space-6); display: flex; flex-direction: column;
}

/* — franja de marca + fila con el nombre del transportista: la única pantalla que ve alguien
   ajeno a la oficina no llevaba ningún elemento de marca (ver design.md, sección "pantalla
   del conductor"). La franja se ancla al borde superior real del .marco (overflow:hidden de
   arriba absorbe que quede por encima del padding). — */
.marco .franja-marca {
    position: absolute; top: 0; left: 0; right: 0; height: 5px;
    background: linear-gradient(90deg, var(--color-accent), var(--color-estado-recibido));
}
.marca-fila { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); color: var(--color-accent); }
.marca-fila .logo-cabecera { height: 34px; width: auto; display: block; flex: none; }
.marca-fila .marca-empresa { font-size: 12px; color: color-mix(in srgb, var(--color-text) 55%, transparent); margin-left: auto; }

/* — stepper de 3 pasos (Emitido → Recibido → Entregado): sustituye al chip "Porte activo",
   que solo decía que el porte estaba activo, no en qué punto - ver
   deca-conductor/porte-activo-ui (solo "recibido" llega a esta pantalla). — */
.stepper { display: flex; align-items: center; margin: var(--space-1) 0 var(--space-4); }
.stepper .paso { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); flex: 1; position: relative; }
.stepper .paso .nodo { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; z-index: 1; }
.stepper .paso.hecho .nodo { background: var(--color-estado-recibido); color: #fff; }
.stepper .paso.actual .nodo { background: var(--color-accent); color: var(--color-accent-contrast); box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 20%, transparent); }
.stepper .paso.pendiente .nodo { background: var(--color-bg); color: color-mix(in srgb, var(--color-text) 55%, transparent); border: 1px solid var(--color-divider); }
.stepper .paso .etiqueta { font-size: 10.5px; color: color-mix(in srgb, var(--color-text) 55%, transparent); font-weight: 600; }
.stepper .paso .linea { position: absolute; top: 11px; left: -50%; width: 100%; height: 2px; background: var(--color-divider); z-index: 0; }
.stepper .paso.hecho .linea, .stepper .paso.actual .linea { background: var(--color-estado-recibido); }
.stepper .paso:first-child .linea { display: none; }

/* — ruta origen→destino como un carril con dos puntos (mismo lenguaje visual que las apps de
   reparto), en vez de "Origen → Destino" en una sola línea de texto plano. — */
.ruta-vis { display: flex; gap: var(--space-2); align-items: flex-start; margin-bottom: var(--space-1); }
.ruta-vis .carril { display: flex; flex-direction: column; align-items: center; padding-top: 6px; }
.ruta-vis .carril .punto { width: 8px; height: 8px; border-radius: 50%; background: var(--color-accent); }
.ruta-vis .carril .punto.fin { background: var(--color-estado-recibido); }
.ruta-vis .carril .segmento { width: 2px; flex: 1; background: var(--color-divider); margin: 3px 0; min-height: 20px; }
.ruta-vis .direcciones { font-family: var(--font-heading); font-weight: var(--font-heading-weight); font-size: 15.5px; line-height: 1.35; }

/* — "Reportar incidencia" es un btn-ghost como "Salir", pero necesita distinguirse como una
   acción de aviso (no es una acción neutra como salir) sin pesar tanto como QR/PDF. — */
.btn-aviso { color: var(--color-danger); }
.btn-aviso:hover { background: color-mix(in srgb, var(--color-danger) 10%, transparent); }

/* — composición: tarjeta pública de inspección — */
.contenedor-publico { width: 100%; max-width: 520px; }

/* — combobox: sustituye al <datalist> nativo sobre input[list], ver combobox.js —
   la lista de sugerencias queda anclada al input, no al .field completo, así el
   ancho coincide exactamente con el input aunque el field tenga más contenido. */
.combo { position: relative; }
.combo-lista {
    position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30;
    margin: 0; padding: var(--space-2); list-style: none; max-height: 240px; overflow-y: auto;
    background: var(--color-surface); border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.combo-opcion {
    display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3);
    padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
    font-size: 14px; cursor: pointer;
}
.combo-opcion:hover, .combo-opcion.marcada { background: color-mix(in srgb, var(--color-accent) 12%, transparent); }
.combo-opcion-etiqueta { font-size: 12px; color: color-mix(in srgb, var(--color-text) 55%, transparent); white-space: nowrap; }

/* — formulario de alta plegado bajo un <summary> con aspecto de botón (mismo patrón que
   "+ Nuevo porte"/"+ Nueva plantilla"): separa visualmente "consultar el historial" de
   "crear uno nuevo", antes convivían siempre expandidos en la misma tarjeta. — */
.detalle-incidencia summary { list-style: none; width: fit-content; }
.detalle-incidencia summary::-webkit-details-marker { display: none; }
.detalle-incidencia[open] summary { margin-bottom: var(--space-4); }

/* — foto de incidencia: miniatura en la fila + <dialog> nativo a tamaño completo, en vez
   de "Ver foto" como enlace ciego que navega fuera de la página a otra pestaña. — */
.miniatura-incidencia {
    width: 32px; height: 32px; object-fit: cover; border-radius: var(--radius-sm);
    vertical-align: middle; margin-right: var(--space-2);
}
dialog.lightbox {
    position: fixed; margin: auto; border: none; padding: 0; background: transparent;
    max-width: 90vw; max-height: 90vh;
}
dialog.lightbox::backdrop { background: color-mix(in srgb, var(--color-neutral-900) 60%, transparent); }
dialog.lightbox img { display: block; max-width: 90vw; max-height: 90vh; border-radius: var(--radius-md); }
dialog.lightbox [data-lightbox-cerrar] {
    position: absolute; top: var(--space-2); right: var(--space-2); z-index: 1;
    background: var(--color-surface); box-shadow: var(--shadow-md);
}
