/* ==========================================================================
   GaragIO — hoja de estilos propia
   Sistema de diseño v3 «Solar White» (docs/ux/sistema-diseno.md) sobre
   Bootstrap 5.3. Mobile-first 360px. WCAG 2.2 AA.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens del sistema de diseño (v3 «Solar White» — aprobados por el usuario,
      docs/arquitectura.md). Modo claro elevado, acento coral, radios generosos.
   -------------------------------------------------------------------------- */
:root {
  /* Fondos */
  --bg-page:        #F4F6F9;   /* gris muy claro frío */
  --bg-surface:     #FFFFFF;
  --bg-surface-alt: #F8F9FB;

  /* Acento: coral oscuro */
  --color-primary:      #C13209;  /* 5.5:1 sobre blanco, verificado AA */
  --color-primary-dark: #A12807;  /* hover */
  --color-primary-text: #FFFFFF;

  /* Textos */
  --text-main:    #111827;
  --text-muted:   #6B7280;       /* 4.6:1 sobre blanco — solo >=14px; NUNCA sobre --bg-page */
  --border-color: #E5E7EB;

  /* Profundidad */
  --shadow-card:  0 2px 16px rgba(17, 24, 39, 0.08), 0 1px 0 rgba(0,0,0,0.04);
  --shadow-card-hover: 0 6px 24px rgba(17, 24, 39, 0.12), 0 2px 4px rgba(0, 0, 0, 0.06);
  --shadow-float: 0 8px 24px rgba(193,50,9,0.20), 0 2px 8px rgba(0,0,0,0.10);
  /* Sombras puntuales tokenizadas (HU-50 modo oscuro): la barra inferior, el
     marco interno de las fotos y la sombra del badge sobre la foto. Antes eran
     rgba(17,24,39,X) fijas (tono claro) que se diluían sobre fondos oscuros. */
  --shadow-bottom-bar: 0 -2px 8px rgba(17, 24, 39, 0.08);
  --shadow-photo-inset: inset 0 0 0 1px rgba(17, 24, 39, 0.06);
  --shadow-photo-badge: 0 1px 4px rgba(17, 24, 39, 0.25);
  --radius-card: 1.25rem;   /* 20px */
  --radius-btn:  0.75rem;   /* 12px */

  /* Estados de plan */
  --state-ok:      #065F46;  --state-ok-bg:      #D1FAE5;
  --state-warning: #92400E;  --state-warning-bg: #FEF3C7;
  --state-danger:  #B91C1C;  --state-danger-bg:  #FEE2E2;
  /* Estado informativo (HU-33: badge «En espera» de Telegram).
     #1E40AF sobre #DBEAFE = 7.2:1 — supera AA (P-19b §8). */
  --state-info:    #1E40AF;  --state-info-bg:    #DBEAFE;
  /* Estado «Silenciado» (HU-45, UX §0): plan activo y con fecha cuyos avisos
     están pausados (notification_enabled=False). #374151 sobre #F3F4F6 = 9.2:1
     — supera AA con holgura. Gris neutro, deliberadamente apagado. */
  --state-muted:   #374151;  --state-muted-bg:   #F3F4F6;

  /* Errores y éxito */
  --color-error:   #B91C1C;  --color-error-bg:   #FEE2E2;
  --color-success: #065F46;  --color-success-bg: #D1FAE5;

  /* Badge numérico de avisos (HU-25): píldora roja sólida con texto blanco.
     Token propio porque --state-danger se usa también como COLOR DE TEXTO sobre
     fondos tintados; en oscuro ese token se aclara (texto sobre tinte) y el
     badge sólido necesita seguir siendo un rojo fuerte con texto claro. */
  --nav-badge-bg:   var(--state-danger);
  --nav-badge-text: #FFFFFF;

  /* Superficies del flujo OCR (ADR-011): tarjetas de método y panel de
     consentimiento IA. Tokenizadas (antes #DEE2E6/#FFF5F3/#F8F9FA/#FFF8F7/
     #495057) para que tengan equivalente oscuro y no queden «rotas». */
  --ocr-card-border:        #DEE2E6;
  --ocr-card-selected-bg:   #FFF5F3;
  --ocr-card-disabled-bg:   #F8F9FA;
  --ai-consent-bg:          #FFF8F7;
  --ai-consent-text:        #495057;  /* 8.6:1 sobre #FFF8F7 (AAA, ux-ui) */
  /* Velo del degradado de afordancia del rail de pestañas (seg-control--five).
     Asume el color de superficie de fondo; en oscuro se sustituye por el slate. */
  --scroll-fade-rgb: 255, 255, 255;

  /* Bootstrap overrides (btn-primary, focus rings...) */
  --bs-primary:     #C13209;
  --bs-primary-rgb: 193, 50, 9;

  --bottom-bar-height: 64px;

  /* Desktop Premium v4 (>=lg): fixed sidebar + per-screen section topbar. */
  --sidebar-width: 240px;
  --section-topbar-height: 60px;
  --content-padding-desktop: 2rem;

  /* Placa de matrícula (it. 4, spec A.2). Contraste verificado:
     número #111827 sobre #FFFFFF = 17.9:1; letra país #FFFFFF sobre azul UE
     #003399 = 10.8:1. Ambos superan AA. */
  --plate-bg:#FFFFFF; --plate-text:#111827; --plate-border:#9CA3AF;
  --plate-band-bg:#003399; --plate-band-text:#FFFFFF; --plate-radius:4px;
}

/* Token derivado de la regla AA del sistema: --text-muted (#6B7280) sobre
   --bg-page (#F4F6F9) da ~4.0:1 y NO pasa AA. El texto secundario que cae
   directamente sobre el fondo de página usa este gris más oscuro: #565F6E
   sobre #F4F6F9 da 4.8:1 (verificado AA para texto normal). */
:root {
  --text-secundario-en-pagina: #565F6E;
}

/* --------------------------------------------------------------------------
   1-OSCURO. Paleta «Midnight Garage» (modo oscuro, HU-50)
   --------------------------------------------------------------------------
   Tema oscuro documentado en docs/ux/sistema-diseno.md («slate + ámbar» como
   posible tema futuro). Se resuelve SOLO por tokens: estas reglas REDEFINEN los
   mismos custom properties que :root, así que TODO componente que use los tokens
   (fondos, superficies, texto, bordes, acento coral, estados vigente/próximo/
   vencido/silenciado/info, badges, sombras, estimación predictiva…) cambia sin
   tocar su CSS. El acento coral se ACLARA (#FF6B3D) porque el coral oscuro v3
   (#C13209) no contrasta sobre slate; el texto del botón primario pasa a un
   marrón muy oscuro para mantener AA sobre el coral claro.

   Activación (base.html, server-side, anti-FOUC):
     · [data-theme="dark"]                         → siempre oscuro.
     · [data-theme="auto"] + prefers-color-scheme:dark → oscuro según el sistema.
   El claro vive en :root (por defecto) y cubre data-theme="light" y el "auto"
   con el sistema en claro.

   Contrastes WCAG 2.2 AA verificados (script de comprobación, todos ≥ 4.5:1):
     texto principal #F1F5F9 / superficie #1A222C ...... 14.6:1
     texto principal #F1F5F9 / página #0F141A .......... 16.9:1
     texto atenuado  #9CA8B6 / superficie #1A222C ...... 6.6:1
     texto atenuado  #9CA8B6 / sup. alt #222C38 ........ 5.9:1
     secundario      #AEB9C6 / página #0F141A .......... 9.3:1
     acento coral    #FF6B3D / superficie #1A222C ...... 5.7:1
     acento coral    #FF6B3D / página #0F141A .......... 6.5:1
     texto botón     #1A120D / coral #FF6B3D ............ 6.5:1
     vigente  #6EE7B7 / tinte #0E2A22 / superficie ..... 10.0 / 10.5:1
     próximo  #FCD34D / tinte #2E2206 / superficie ..... 10.8 / 11.1:1
     vencido  #FCA5A5 / tinte #2E1416 / superficie ...... 9.0 / 8.5:1
     info     #93C5FD / tinte #11233F / superficie ...... 8.7 / 8.9:1
     silenciado #CBD5E1 / tinte #232C38 ................. 9.5:1
     badge avisos texto #FFFFFF / rojo #B91C1C ......... 6.5:1
   -------------------------------------------------------------------------- */
/* Variables oscuras: se aplican a data-theme="dark" SIEMPRE; el bloque @media de
   más abajo las replica para data-theme="auto" cuando el sistema pide oscuro.
   Se usa :root[data-theme="dark"] (0,2,0) para que estos tokens GANEN a los de
   :root (0,1,0); definir variables aquí no compite con las reglas de componente
   (que solo consumen las variables ya resueltas en el root). */
:root[data-theme="dark"] {
  /* Fondos */
  --bg-page:        #0F141A;   /* slate profundo */
  --bg-surface:     #1A222C;
  --bg-surface-alt: #222C38;

  /* Acento: coral aclarado para slate */
  --color-primary:      #FF6B3D;
  --color-primary-dark: #FF8052;  /* hover: un punto más claro sobre oscuro */
  --color-primary-text: #1A120D;  /* texto sobre el coral claro (6.5:1 AA) */

  /* Textos */
  --text-main:    #F1F5F9;
  --text-muted:   #9CA8B6;       /* 6.6:1 sobre superficie, 5.9:1 sobre sup-alt */
  --border-color: #33414F;
  --text-secundario-en-pagina: #AEB9C6;  /* 9.3:1 sobre la página */

  /* Profundidad: sombras más marcadas (la luz tenue del modo oscuro necesita
     más opacidad para separar superficies del fondo). */
  --shadow-card:  0 2px 16px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(0, 0, 0, 0.3);
  --shadow-card-hover: 0 8px 28px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.4);
  --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4);
  /* Sombras puntuales en oscuro: negro más opaco para separar superficies y, en
     los marcos internos de foto, un hilo CLARO (no oscuro) que sí se ve sobre el
     slate y separa fotos oscuras del borde de la tarjeta. */
  --shadow-bottom-bar:  0 -2px 12px rgba(0, 0, 0, 0.6);
  --shadow-photo-inset: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
  --shadow-photo-badge: 0 1px 6px rgba(0, 0, 0, 0.7);

  /* Estados de plan: texto claro sobre tinte oscuro del mismo matiz. */
  --state-ok:      #6EE7B7;  --state-ok-bg:      #0E2A22;
  --state-warning: #FCD34D;  --state-warning-bg: #2E2206;
  --state-danger:  #FCA5A5;  --state-danger-bg:  #2E1416;
  --state-info:    #93C5FD;  --state-info-bg:    #11233F;
  --state-muted:   #CBD5E1;  --state-muted-bg:   #232C38;

  /* Errores y éxito (alias semánticos de danger/ok). */
  --color-error:   #FCA5A5;  --color-error-bg:   #2E1416;
  --color-success: #6EE7B7;  --color-success-bg: #0E2A22;

  /* Badge de avisos: la píldora sigue siendo un rojo SÓLIDO fuerte con texto
     blanco (6.5:1), NO el rosa claro de --state-danger (que aquí es texto). */
  --nav-badge-bg:   #B91C1C;
  --nav-badge-text: #FFFFFF;

  /* Superficies del flujo OCR / consentimiento IA en oscuro. */
  --ocr-card-border:        #33414F;
  --ocr-card-selected-bg:   #2A1C16;  /* lavado coral oscuro */
  --ocr-card-disabled-bg:   #161D26;
  --ai-consent-bg:          #241A16;  /* lavado coral oscuro */
  --ai-consent-text:        #D5DDE6;  /* ~10:1 sobre #241A16 */
  --scroll-fade-rgb: 26, 34, 44;      /* = --bg-surface (#1A222C) */

  /* Placa de matrícula: la placa europea es físicamente blanca; se mantiene
     legible (número oscuro sobre blanco) pero su borde se adapta al tema. */
  --plate-border: #5A6B7D;

  /* Bootstrap overrides: el coral claro y su rgb para focus rings / enlaces. */
  --bs-primary:     #FF6B3D;
  --bs-primary-rgb: 255, 107, 61;
  --bs-link-color-rgb: 255, 107, 61;
  --bs-link-hover-color-rgb: 255, 128, 82;
}

/* "auto": sigue al sistema. Solo cuando el SO pide oscuro se aplica la paleta;
   en claro, :root manda. Se reutiliza el MISMO mapa (copiado) para no depender
   de herencia entre selectores distintos. */
@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --bg-page:        #0F141A;
    --bg-surface:     #1A222C;
    --bg-surface-alt: #222C38;

    --color-primary:      #FF6B3D;
    --color-primary-dark: #FF8052;
    --color-primary-text: #1A120D;

    --text-main:    #F1F5F9;
    --text-muted:   #9CA8B6;
    --border-color: #33414F;
    --text-secundario-en-pagina: #AEB9C6;

    --shadow-card:  0 2px 16px rgba(0, 0, 0, 0.45), 0 1px 0 rgba(0, 0, 0, 0.3);
    --shadow-card-hover: 0 8px 28px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.4);
    --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4);
    --shadow-bottom-bar:  0 -2px 12px rgba(0, 0, 0, 0.6);
    --shadow-photo-inset: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
    --shadow-photo-badge: 0 1px 6px rgba(0, 0, 0, 0.7);

    --state-ok:      #6EE7B7;  --state-ok-bg:      #0E2A22;
    --state-warning: #FCD34D;  --state-warning-bg: #2E2206;
    --state-danger:  #FCA5A5;  --state-danger-bg:  #2E1416;
    --state-info:    #93C5FD;  --state-info-bg:    #11233F;
    --state-muted:   #CBD5E1;  --state-muted-bg:   #232C38;

    --color-error:   #FCA5A5;  --color-error-bg:   #2E1416;
    --color-success: #6EE7B7;  --color-success-bg: #0E2A22;

    --nav-badge-bg:   #B91C1C;
    --nav-badge-text: #FFFFFF;

    --ocr-card-border:        #33414F;
    --ocr-card-selected-bg:   #2A1C16;
    --ocr-card-disabled-bg:   #161D26;
    --ai-consent-bg:          #241A16;
    --ai-consent-text:        #D5DDE6;
    --scroll-fade-rgb: 26, 34, 44;

    --plate-border: #5A6B7D;

    --bs-primary:     #FF6B3D;
    --bs-primary-rgb: 255, 107, 61;
    --bs-link-color-rgb: 255, 107, 61;
    --bs-link-hover-color-rgb: 255, 128, 82;
  }
}

/* Esquema de color nativo: que los controles del navegador (scrollbars, inputs
   de fecha/número, autofill) adopten el modo correcto en cada tema. */
[data-theme="dark"] { color-scheme: dark; }
[data-theme="light"] { color-scheme: light; }
:root[data-theme="auto"] { color-scheme: light dark; }

/* --------------------------------------------------------------------------
   1b. Puente con Bootstrap 5.3: el CSS compilado de Bootstrap lleva su azul
   en cada componente, así que el coral se inyecta vía sus variables locales.
   -------------------------------------------------------------------------- */
:root {
  --bs-body-bg: var(--bg-page);
  --bs-body-color: var(--text-main);
  --bs-border-color: var(--border-color);
  --bs-secondary-color: var(--text-muted); /* .text-muted con el token v3 */
  --bs-link-color: var(--color-primary);
  --bs-link-color-rgb: 193, 50, 9;
  --bs-link-hover-color: var(--color-primary-dark);
  --bs-link-hover-color-rgb: 161, 40, 7;
  --bs-border-radius: var(--radius-btn);
}

body {
  background-color: var(--bg-page);
  color: var(--text-main);
}

.btn {
  --bs-btn-border-radius: var(--radius-btn);
}

.btn-primary {
  --bs-btn-bg: var(--color-primary);
  --bs-btn-border-color: var(--color-primary);
  --bs-btn-color: var(--color-primary-text);
  --bs-btn-hover-bg: var(--color-primary-dark);
  --bs-btn-hover-border-color: var(--color-primary-dark);
  --bs-btn-hover-color: var(--color-primary-text);
  --bs-btn-active-bg: var(--color-primary-dark);
  --bs-btn-active-border-color: var(--color-primary-dark);
  --bs-btn-active-color: var(--color-primary-text);
  --bs-btn-disabled-bg: var(--color-primary);
  --bs-btn-disabled-border-color: var(--color-primary);
  --bs-btn-disabled-color: var(--color-primary-text);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}

.btn-outline-primary {
  --bs-btn-color: var(--color-primary);
  --bs-btn-border-color: var(--color-primary);
  --bs-btn-hover-bg: var(--color-primary);
  --bs-btn-hover-border-color: var(--color-primary);
  --bs-btn-hover-color: var(--color-primary-text);
  --bs-btn-active-bg: var(--color-primary-dark);
  --bs-btn-active-border-color: var(--color-primary-dark);
  --bs-btn-active-color: var(--color-primary-text);
  --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}

/* Tarjeta genérica de Bootstrap (login, perfil): radio y sombra del sistema */
.card {
  --bs-card-border-radius: var(--radius-card);
  --bs-card-inner-border-radius: calc(var(--radius-card) - 1px);
  --bs-card-border-color: var(--border-color);
  box-shadow: var(--shadow-card);
}

/* Modal de confirmación: misma profundidad que las tarjetas */
.modal-content {
  border-radius: var(--radius-card);
}

/* Mensajes flash con los tokens de estado v2 (Bootstrap trae su propia paleta) */
.alert-success {
  --bs-alert-color: var(--color-success);
  --bs-alert-bg: var(--color-success-bg);
  --bs-alert-border-color: var(--color-success-bg);
}

.alert-danger {
  --bs-alert-color: var(--color-error);
  --bs-alert-bg: var(--color-error-bg);
  --bs-alert-border-color: var(--color-error-bg);
}

.alert-warning {
  --bs-alert-color: var(--state-warning);
  --bs-alert-bg: var(--state-warning-bg);
  --bs-alert-border-color: var(--state-warning-bg);
}

/* --------------------------------------------------------------------------
   2. Layout: hueco para la barra inferior en páginas autenticadas
   -------------------------------------------------------------------------- */
main.with-bottom-bar {
  /* La barra (64px) no debe tapar el último elemento del contenido */
  padding-bottom: 72px;
}

/* --------------------------------------------------------------------------
   3. Botones (altura táctil mínima 48px) y foco visible
   -------------------------------------------------------------------------- */
.btn-primary,
.btn-outline-primary,
.btn-outline-danger {
  min-height: 48px;
  font-weight: 600;
  /* Centrado vertical real del texto: con min-height mayor que la altura
     natural del contenido, sin flex el texto de un <a class="btn"> queda
     pegado arriba. Esto centra TODOS los botones del sistema (barra de
     acción, estado vacío, formularios). */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
}

/* Foco de teclado bien visible en toda la interfaz (WCAG 2.4.7) */
.btn:focus-visible,
.bottom-bar__item:focus-visible,
.back-link:focus-visible,
.subtle-link:focus-visible,
.action-row:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  box-shadow: none;
}

/* --------------------------------------------------------------------------
   4. Formularios
   -------------------------------------------------------------------------- */
.form-control {
  min-height: 48px;
  border-color: var(--border-color);
}

.form-control:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 0.25);
}

.form-label {
  font-size: 0.875rem;
  font-weight: 500;
}

.form-control.is-invalid {
  border-color: var(--color-error);
}

.invalid-feedback {
  color: var(--color-error);
  font-size: 0.875rem;
}

/* Los contenedores de error llevan d-block (necesario dentro de input-group)
   y se ocultan con el atributo hidden; sin esta regla, el !important de
   .d-block ganaría a hidden y el hueco vacío quedaría visible. */
.invalid-feedback.d-block[hidden] {
  display: none !important;
}

/* Botón «ojo» de mostrar/ocultar contraseña: área táctil mínima 44×44px */
.eye-button {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-color: var(--border-color);
  color: var(--text-muted);
}

.eye-button:hover {
  color: var(--text-main);
  background-color: var(--bg-surface-alt);
}

/* Campos visualmente deshabilitados durante el envío (readonly para que
   sus valores SÍ viajen en el POST, a diferencia de disabled) */
.field-submitting {
  background-color: var(--bg-surface-alt);
  pointer-events: none;
}

/* Nota fija de requisito (P-02 y P-05): va directamente sobre --bg-page,
   por eso usa el gris-azul AA y no --text-muted (regla de contraste v2) */
.requirement-note {
  color: var(--text-secundario-en-pagina);
  font-size: 0.875rem;
}

/* --------------------------------------------------------------------------
   5. Enlace de acción discreta («Cancelar», «Volver»): área táctil 44px
   -------------------------------------------------------------------------- */
.subtle-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 1rem;
  /* Suele caer directamente sobre --bg-page: gris-azul AA, no --text-muted */
  color: var(--text-secundario-en-pagina);
  text-decoration: none;
}

.subtle-link:hover {
  color: var(--text-main);
  text-decoration: underline;
}

/* --------------------------------------------------------------------------
   6. Header secundario (sub-pantallas con «Volver»): 56px
   -------------------------------------------------------------------------- */
.secondary-header {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 56px;
  padding: 0 0.5rem;
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
}

.secondary-header .screen-title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
}

.back-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 0.5rem;
  color: var(--color-primary);
  text-decoration: none;
  font-weight: 500;
}

.back-link:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

/* Header de primer nivel (sin «Volver») */
.main-header {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: 0 1rem;
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
  /* It. 4 (spec PARTE B): el trigger de idioma se ancla a la derecha sin
     empujar el título; este se queda a la izquierda y consume el resto. */
  gap: 0.5rem;
}

.main-header .screen-title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  /* Empuja el trigger de idioma (si lo hay) al extremo derecho del header. */
  margin-right: auto;
  /* Permite que el título ceda espacio al botón de acción (P-11 móvil) sin
     desbordar el header en pantallas estrechas. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Acción opcional del header de primer nivel (P-11 móvil → «Mis vencimientos»,
   UX §1). btn-sm con objetivo táctil garantizado de 44px y sin partir líneas. */
.main-header__action {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 44px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   7. Barra de navegación inferior (solo usuario autenticado)
   -------------------------------------------------------------------------- */
.bottom-bar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 1030;
  display: flex;
  height: var(--bottom-bar-height);
  background-color: var(--bg-surface);
  border-top: 1px solid var(--border-color);
  box-shadow: var(--shadow-bottom-bar);
}

.bottom-bar__item {
  /* flex-basis:0 + reparto equitativo: con 4 ítems cada uno ocupa 1/4 del ancho
     (≈90px a 360px, ≈80px a 320px). min-width:0 permite que la celda se encoja
     por debajo del ancho de su contenido para que el reparto siga siendo exacto. */
  flex: 1 1 0;
  min-width: 0;
  /* Posición relativa para anclar el badge de avisos (.nav-badge--bottom-bar,
     posicionado en absoluto). */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.125rem;
  padding: 0 0.125rem; /* respiro lateral mínimo entre etiquetas con 4 ítems */
  height: 100%; /* 64px > 44px de área táctil mínima */
  /* Etiquetas de 0.625rem: --text-muted queda justo a ese cuerpo (regla v2),
     se usa el gris-azul más oscuro también sobre superficie blanca */
  color: var(--text-secundario-en-pagina);
  text-decoration: none;
  font-size: 0.625rem;
}

/* La etiqueta nunca se parte en dos líneas (rompería la altura de la barra) ni
   desborda: una sola línea, centrada y recortada con elipsis si no cupiera. */
.bottom-bar__item span {
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.bottom-bar__item .bi {
  font-size: 24px;
  line-height: 1;
}

.bottom-bar__item:hover {
  color: var(--text-main);
}

.bottom-bar__item--active {
  color: var(--color-primary);
}

.bottom-bar__item:focus-visible {
  outline-offset: -3px; /* el outline cabe dentro de la barra */
}

/* --------------------------------------------------------------------------
   7-bis. Badge numérico de avisos (HU-25)
   Contador rojo de planes vencidos/próximos junto al ítem «Avisos». Reutiliza
   el token de peligro existente (--state-danger #B91C1C → blanco = 7.1:1, AA).
   Tamaño mínimo 16px y números legibles en móvil (spec HU-25).
   -------------------------------------------------------------------------- */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 0.3125rem;
  border-radius: 9999px;
  background-color: var(--nav-badge-bg);
  color: var(--nav-badge-text);
  font-size: 0.75rem; /* 12px de cuerpo dentro de la píldora de 18px */
  font-weight: 700;
  line-height: 1;
}

.nav-badge--bottom-bar {
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translateX(2px); /* desplaza el badge a la derecha del icono */
  /* borde del color de la superficie: separa el badge del icono al solaparse */
  box-shadow: 0 0 0 2px var(--bg-surface);
}

/* --------------------------------------------------------------------------
   8. Mensajes flash
   -------------------------------------------------------------------------- */
.alerts-area .alert {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 56px;
  margin-bottom: 0;
  border-radius: 0;
}

/* Botón de cierre del flash: área táctil 44×44px */
.alert-close-button {
  width: 44px;
  height: 44px;
  padding: 0;
  margin-left: auto;
  background-size: 1em;
}

/* Bootstrap posiciona .btn-close en absoluto dentro de alert-dismissible;
   con flex lo integramos en el flujo y reservamos su sitio. */
.alerts-area .alert-dismissible {
  padding-right: 1rem;
}

.alerts-area .alert-dismissible .btn-close {
  position: static;
}

/* X de cierre de los modales: área táctil 44×44px (spec P-05) */
.modal-header .btn-close {
  width: 44px;
  height: 44px;
  padding: 0;
  background-size: 1em;
}

/* --------------------------------------------------------------------------
   9. FAB — botón flotante de acción (P-04). CSS de la spec iteración 2.
   -------------------------------------------------------------------------- */
.fab-action {
  position: fixed;
  bottom: calc(var(--bottom-bar-height) + 16px);
  right: 16px;
  z-index: 1020;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background-color: var(--color-primary);
  color: var(--color-primary-text);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-float);
  font-size: 24px;
  cursor: pointer;
  text-decoration: none;
}

.fab-action:hover {
  background-color: var(--color-primary-dark);
  color: var(--color-primary-text);
}

.fab-action:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   10. Tarjeta de coche (P-04). CSS de la spec iteración 2.
   -------------------------------------------------------------------------- */
.car-card {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  padding: 1rem;
  margin-bottom: 0.75rem;
  box-shadow: var(--shadow-card);
  cursor: pointer;
}

.car-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 24px;
  margin-bottom: 0.25rem;
}

.car-card__name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.125rem;
}

.car-card__meta {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0;
  /* It. 4 (spec A.3): la matrícula pasa a ser el componente plate; el meta
     se vuelve flex para alinear plate + separador + año en una fila. */
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex-wrap: wrap;
}

.car-card__divider {
  border: none;
  border-top: 1px solid var(--border-color);
  margin: 0.75rem 0;
}

.car-card__km {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.125rem;
}

.car-card__km--empty {
  font-size: 0.875rem;
  font-weight: 400;
  font-style: italic;
  color: var(--text-muted);
}

.car-card__km-meta {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0;
}

.car-card__edit-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--text-muted);
  border-radius: var(--radius-btn);
  text-decoration: none;
  margin: -0.5rem -0.25rem -0.5rem 0;
}

.car-card__edit-btn:hover {
  color: var(--color-primary);
  background-color: var(--bg-surface-alt);
}

.car-card__edit-btn:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   11. Badges de estado de plan (pill)
   -------------------------------------------------------------------------- */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;          /* icono + texto (spec it. 4 §1) */
  height: 24px;
  padding: 0.25rem 0.625rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

.status-badge--up-to-date {
  background-color: var(--state-ok-bg);
  color: var(--state-ok);
}

.status-badge--upcoming {
  background-color: var(--state-warning-bg);
  color: var(--state-warning);
}

.status-badge--overdue {
  background-color: var(--state-danger-bg);
  color: var(--state-danger);
}

/* HU-33 (P-19b §1.2) — Telegram linking-state badges, same pill as the plan
   status badges. «Pending» reuses the new info token; «unlinked» the warning
   token. The state is always shown as text too (icon + word), not by colour
   alone (WCAG 1.4.1). */
.status-badge--pending {
  background-color: var(--state-info-bg);
  color: var(--state-info);
}

.status-badge--unlinked {
  background-color: var(--state-warning-bg);
  color: var(--state-warning);
}

/* HU-45 (P-27, UX §0) — Badge «Silenciado»: el plan sigue activo y con fecha,
   pero sus avisos están pausados (notification_enabled=False). Gris neutro
   (--state-muted sobre --state-muted-bg = 9.2:1, AA). Igual que el resto, el
   estado se comunica también por texto + icono (bi-bell-slash-fill), nunca por
   color solo (WCAG 1.4.1). */
.status-badge--silenciado {
  background-color: var(--state-muted-bg);
  color: var(--state-muted);
}

/* Placeholder — reserva los 24px de altura hasta la iteración 4 (spec P-04) */
.status-badge--placeholder {
  display: inline-block;
  height: 24px;
  width: 0;
  padding: 0;
  visibility: hidden;
}

/* --------------------------------------------------------------------------
   12. Zona de peligro (P-05 edición). CSS de la spec iteración 2.
   -------------------------------------------------------------------------- */
.danger-zone {
  background-color: var(--state-danger-bg);
  border: 1px solid var(--state-danger);
  border-radius: var(--radius-card);
  padding: 1rem;
  margin-top: 2rem;
}

/* Sobre --state-danger-bg (#FEE2E2): --text-muted no pasa AA (~3.7:1); se usa
   --state-danger (#B91C1C → 7.1:1) y --text-main para texto principal. */
.danger-zone__title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--state-danger);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0 0 0.75rem;
}

.danger-zone__description {
  font-size: 0.875rem;
  color: var(--text-main);
  margin: 0 0 1rem;
}

/* --------------------------------------------------------------------------
   13. Pantalla de login (P-01)
   -------------------------------------------------------------------------- */
.login-wrapper {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.login-card {
  width: 100%;
  max-width: 420px;
}

.app-logo {
  font-size: 64px;
  line-height: 1;
  color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   14. Contenedor estrecho de formularios y listas (móvil primero,
       limitado en escritorio para no estirar las líneas)
   -------------------------------------------------------------------------- */
.narrow-container {
  width: 100%;
  max-width: 480px;
  margin-inline: auto;
  padding-inline: 1rem;
}

/* --------------------------------------------------------------------------
   15. Estado vacío
   -------------------------------------------------------------------------- */
.empty-state {
  text-align: center;
  padding: 3rem 1.5rem;
  /* El texto secundario cae directamente sobre --bg-page: gris-azul AA */
  color: var(--text-secundario-en-pagina);
}

.empty-state .bi {
  font-size: 48px;
  line-height: 1;
}

/* Variante de pantalla clave (P-04): icono 64px en color primario */
.empty-state--featured .bi {
  font-size: 64px;
  color: var(--color-primary);
}

.empty-state__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0.75rem 0 0.25rem;
}

.empty-state__text {
  font-size: 0.875rem;
  margin: 0;
}

/* Botón de acción del estado vacío: max-width 280px centrado (spec P-04) */
.empty-state__action {
  width: 100%;
  max-width: 280px;
  margin-top: 1.5rem;
}

/* --------------------------------------------------------------------------
   16. Fila de acción en listas (p. ej. «Cambiar contraseña» en Perfil)
   -------------------------------------------------------------------------- */
.action-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 48px;
  padding: 0.5rem 1rem;
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  color: var(--text-main);
  text-decoration: none;
}

/* La fila «Idioma» de Perfil (it. 4, spec B.6) usa un <button> que abre el
   offcanvas; se normaliza a 100% de ancho y texto a la izquierda. */
button.action-row {
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

button.action-row:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.action-row:hover {
  background-color: var(--bg-surface-alt);
  color: var(--text-main);
}

.action-row .bi-chevron-right {
  color: var(--text-muted);
}

/* Etiqueta de la fila con icono guía (Perfil): icono atenuado + texto. */
.action-row__label {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
}

.action-row__label .bi {
  color: var(--text-muted);
  font-size: 1.125rem;
  flex-shrink: 0;
}

.action-row:hover .action-row__label .bi {
  color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   17. HU-17 — Foto del coche en la tarjeta de lista (P-04)
   Spec: docs/ux/addendum-hu17-foto-coche.md («CSS listo para copiar»).
   Layout de dos columnas: miniatura 56×56 a la izquierda + cuerpo a la derecha.
   -------------------------------------------------------------------------- */
.car-card__layout {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.car-card__photo-wrap {
  flex-shrink: 0;
}

.car-card__photo {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-btn);
  object-fit: cover;
  object-position: center;
  display: block;
  /* Marco interno sutil (Solar White): despega la miniatura clara del fondo
     de la tarjeta sin alterar su tamaño. Token por tema (HU-50): hilo oscuro en
     claro, hilo claro en oscuro. */
  box-shadow: var(--shadow-photo-inset);
}

.car-card__photo--placeholder {
  background-color: var(--bg-surface-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Icono del placeholder en coral atenuado (coherente con el hero del detalle). */
  color: var(--color-primary);
  opacity: 0.45;
  font-size: 24px;
}

.car-card__body {
  flex: 1;
  min-width: 0; /* permite el truncado del nombre dentro del flex */
}

/* --------------------------------------------------------------------------
   18. P-06 — Cabecera del coche en el detalle
   Spec: docs/ux/iteracion-3-detalle-historiales.md + addendum-hu17.
   La tarjeta + el banner 16:9 (o placeholder) arriba.
   -------------------------------------------------------------------------- */
.car-detail-header {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 1rem;
  margin: 1rem;
}

/* Hero (Solar White): la foto del coche se trata como banner protagonista.
   Envuelve el banner 16:9 y el badge de estado, que se superpone en la esquina
   superior derecha. Se extiende a los bordes de la tarjeta compensando su
   padding (margin negativo) y redondea solo las esquinas superiores (20px). */
.car-detail-header__hero {
  position: relative;
  width: calc(100% + 2rem);
  margin: -1rem -1rem 0.75rem -1rem;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  overflow: hidden;
}

.car-detail-header__photo {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center;
  display: block;
  /* Borde interno sutil: separa fotos claras del borde de la tarjeta sin
     alterar el tamaño (inset shadow, no afecta al layout). Token por tema (HU-50). */
  box-shadow: var(--shadow-photo-inset);
}

.car-detail-header__photo--placeholder {
  background-color: var(--bg-surface-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Icono del placeholder en coral atenuado (Solar White). */
  color: var(--color-primary);
  opacity: 0.45;
  font-size: 56px;
}

/* Badge de estado superpuesto sobre el hero (esquina superior derecha). El
   parcial _badge_estado.html queda intacto; este wrapper lo posiciona y le da
   un fondo translúcido para legibilidad sobre cualquier foto. */
.car-detail-header__hero .status-badge:not(.status-badge--placeholder) {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 1;
  box-shadow: var(--shadow-photo-badge);
}

/* Si no hay planes activos el badge es el placeholder invisible: no debe
   reservar hueco dentro del hero ni romper el banner. */
.car-detail-header__hero .status-badge--placeholder {
  position: absolute;
}

/* Datos del coche bajo el banner. Mismos cuerpos/pesos que .car-card__*
   (sistema de diseño: 700 para valores, km como dato protagonista). */
.car-detail-header__name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.125rem;
}

.car-detail-header__meta {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0;
  /* It. 4 (spec A.4): plate --detail + separador + año en una fila. */
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.car-detail-header__divider {
  border: none;
  border-top: 1px solid var(--border-color);
  margin: 0.75rem 0;
}

.car-detail-header__km {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.125rem;
}

.car-detail-header__km--empty {
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--text-muted);
  margin: 0;
}

.car-detail-header__km-meta {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0;
}

/* Lápiz de editar (44×44) en el header secundario del detalle. Análogo a
   otros botones-icono; flota a la derecha sin afectar a login/perfil. */
.edit-car-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin-left: auto; /* empuja el lápiz al extremo derecho del header */
  color: var(--text-muted);
  border-radius: var(--radius-btn);
  text-decoration: none;
}

.edit-car-button:hover {
  color: var(--color-primary);
  background-color: var(--bg-surface-alt);
}

.edit-car-button:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   19. P-06 — Segmented control de secciones (Mantenimientos / Lecturas)
   Spec: docs/ux/iteracion-3-detalle-historiales.md («CSS nuevo»).
   -------------------------------------------------------------------------- */
.seg-control {
  display: flex;
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  margin: 0 1rem 0.75rem;
}

.seg-tab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  border: none;
  background: transparent;
  transition: background-color 0.15s, color 0.15s;
}

.seg-tab--active {
  background-color: var(--color-primary);
  color: var(--color-primary-text);
  font-weight: 600;
  pointer-events: none;
}

.seg-tab:not(.seg-tab--active):hover {
  background-color: var(--bg-surface-alt);
  color: var(--text-main);
}

.seg-tab:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
}

/* --------------------------------------------------------------------------
   19b. P-10b — Conmutador de modalidad del plan (HU-30, dos opciones)
   Spec: docs/ux/p-10b-planes-solo-fecha.md §2. Variante de .seg-control para
   uso DENTRO de un formulario: dos <label> con un <input type=radio> oculto.
   Clona .seg-control / .seg-tab (mismos tokens) sin romper la base.
   -------------------------------------------------------------------------- */
.seg-control--dos {
  /* Análoga a .seg-control--cinco: rejilla de dos columnas iguales. El margen
     lateral de .seg-control no aplica aquí (vive dentro del .form-section). */
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin: 0;
}

/* .seg-tab--radio: replica el aspecto de .seg-tab pero como <label> que envuelve
   un radio (operabilidad por teclado nativa). El radio va .visually-hidden. */
.seg-tab--radio {
  cursor: pointer;
  /* El <label> ya recibe display:flex y la altura de .seg-tab. */
}

.seg-tab--radio.seg-tab--active {
  /* La base .seg-tab--active aplica pointer-events:none (válido para los <a>
     del tablist); en un radio debe seguir siendo pulsable para alternar. */
  pointer-events: auto;
}

/* Foco visible sobre el label cuando el radio interno lo recibe (WCAG 2.4.7).
   :has() es la vía moderna; el fallback :focus-within cubre navegadores sin
   :has (el radio está dentro del label, así que :focus-within también acierta). */
.seg-tab--radio:focus-within {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
}

.seg-tab--radio:has(input:focus-visible) {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
}

/* Ayuda contextual de la modalidad (role=note): texto secundario bajo el
   conmutador, sin el margen extra del .form-text base. */
.mode-help {
  margin-top: 0.5rem;
  margin-bottom: 0;
}

/* --------------------------------------------------------------------------
   20. P-06 — Barra de acción contextual fija (64px)
   Spec: docs/ux/iteracion-3-detalle-historiales.md. La sub-pantalla no lleva
   barra de navegación inferior; esta barra ocupa su lugar con el botón
   primario de la pestaña activa. El <main> reserva su hueco con .with-action-bar.
   -------------------------------------------------------------------------- */
main.with-action-bar {
  /* La barra (64px fixed) no debe tapar el último elemento del contenido.
     Reserva análoga a .with-bottom-bar (72px para la barra de 64px). */
  padding-bottom: 80px;
}

/* Pestaña «Info» (it. 5a): no renderiza barra de acción contextual, así que
   los 80px reservados sobran. El modificador recupera la separación inferior
   estándar de página sin romper el resto de pestañas (deuda #2 del backend). */
main.with-action-bar--no-bar {
  padding-bottom: 1rem;
}

.context-action-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 64px;
  background-color: var(--bg-surface);
  border-top: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  padding: 0 1rem;
  z-index: 1020;
}

.context-action-bar .btn {
  width: 100%;
  /* Centrado vertical real del texto: el botón es un <a> con py-3; sin flex,
     la línea base lo deja ligeramente alto dentro de la barra de 64px. */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --------------------------------------------------------------------------
   21. P-06 — Filas del historial (mantenimientos y lecturas)
   Spec: docs/ux/iteracion-3-detalle-historiales.md («CSS nuevo»).
   -------------------------------------------------------------------------- */
.history-list {
  margin: 0;
  padding: 0;
}

.reading-row {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
}

/* Fila de mantenimiento: bloque clicable completo → edición (HU-24).
   Mismo patrón de afordancia que .plan-row (sin subrayado, foco visible). */
.maintenance-row {
  display: block;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
  text-decoration: none;
  color: inherit;
}

.maintenance-row:last-child {
  border-bottom: none;
}

.maintenance-row:hover {
  background-color: var(--bg-surface-alt);
}

.maintenance-row:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

.reading-row--maintenance {
  background-color: var(--bg-surface-alt);
}

.history-row__header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

.history-row__type {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.history-row__km {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
}

.history-row__date {
  font-size: 0.875rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.history-row__meta {
  font-size: 0.875rem;
  color: var(--text-muted);
}

.history-row__price {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin-top: 0.125rem;
}

.history-row__source {
  font-size: 0.75rem;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.125rem;
}

/* Botón «Cargar más»: 48px de alto (área táctil), ancho completo. */
.load-more-button {
  min-height: 48px;
}

/* Línea de fin de paginación: cae sobre --bg-page → gris-azul AA (regla v2). */
.pagination-end {
  font-size: 0.75rem;
  color: var(--text-secundario-en-pagina) !important;
  text-align: center;
  padding: 0.75rem 1rem;
}

/* --------------------------------------------------------------------------
   22. P-07/P-08 — Advertencia de retroceso de km
   Spec: docs/ux/iteracion-3-detalle-historiales.md («CSS nuevo»).
   El campo km usa borde ámbar (--state-warning #92400E, 5.5:1 sobre blanco),
   NO is-invalid.
   -------------------------------------------------------------------------- */
.form-control.km-warning {
  border-color: var(--state-warning); /* #92400E, 5.5:1 sobre blanco */
  border-width: 2px;
}

.form-control.km-warning:focus {
  box-shadow: 0 0 0 0.25rem rgba(146, 64, 14, 0.25);
}

.warning-block {
  background-color: var(--state-warning-bg);
  border: 1px solid var(--state-warning);
  border-radius: var(--radius-btn);
  padding: 0.75rem;
  margin-bottom: 1rem;
  color: var(--state-warning);
}

.warning-block__title {
  font-size: 0.875rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.375rem;
}

.warning-block__text {
  font-size: 0.875rem;
  margin-bottom: 0.75rem;
}

.warning-block .form-check-label {
  font-size: 0.875rem;
  line-height: 1.4;
  cursor: pointer;
}

.warning-block .form-check {
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-left: 0;
}

.warning-block .form-check-input {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  margin: 0;
}

/* --------------------------------------------------------------------------
   23. P-05 — Sección de foto del formulario de coche (HU-17)
   Spec: docs/ux/addendum-hu17-foto-coche.md («CSS listo para copiar»).
   -------------------------------------------------------------------------- */
/* La sección «Vencimientos» (HU-43, P-05b) usa <fieldset class="form-section">
   con <legend class="form-section-title">. Se neutraliza el borde/padding
   nativo del fieldset (algunos navegadores no lo resetean) para que se vea
   como una sección plana, igual que el resto del formulario. */
.form-section {
  min-width: 0;     /* evita el desbordamiento de fieldset en flex/grid */
  margin: 0;
  padding: 0;
  border: 0;
}

.form-section-title {
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin: 0 0 0.75rem;
  /* <legend> trae font-size grande y float por defecto: se normaliza para que
     se vea idéntico al título de la sección de foto (que es un <h2>). */
  float: none;
  width: auto;
  padding: 0;
}

.current-photo-preview {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.current-photo-preview__img {
  width: 80px;
  height: 80px;
  border-radius: var(--radius-btn);
  object-fit: cover;
  object-position: center;
  border: 1px solid var(--border-color);
  flex-shrink: 0;
}

.current-photo-preview__label {
  font-size: 0.875rem;
  color: var(--text-muted);
}

.remove-photo {
  margin-bottom: 0.75rem;
}

/* Área táctil 44px del checkbox «Quitar la foto actual» (WCAG 2.5.8). */
.remove-photo .form-check-input {
  width: 20px;
  height: 20px;
  margin-top: 0;
}

.remove-photo .form-check-label {
  min-height: 44px;
  display: flex;
  align-items: center;
  font-size: 0.875rem;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   24. P-09 — Gestión de tipos de mantenimiento (HU-12)
   Spec: docs/ux/iteracion-3-p09-tipos-mantenimiento.md («CSS nuevo»).
   «Mis tipos» (editable) + «Tipos de serie» (colapsable, solo lectura).
   -------------------------------------------------------------------------- */

/* Tarjeta que envuelve el bloque «Mis tipos» (cabecera + filas / estado vacío). */
.types-list-wrapper {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  margin: 0 1rem 1rem;
  overflow: hidden;
}

/* Cabecera del bloque: «Mis tipos (N)». */
.types-header {
  display: flex;
  align-items: baseline;
  gap: 0.375rem;
  padding: 0.75rem 1rem;
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
}

.types-header__title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-main);
}

.types-header__counter {
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* Fila de un tipo propio (activo). */
.own-type-row {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
}

/* Última fila sin doble borde con el cierre de la tarjeta. */
.own-type-row:last-child {
  border-bottom: none;
}

/* Variante inactiva: fondo de sección y texto atenuado en itálica. */
.own-type-row--inactive {
  background-color: var(--bg-surface-alt);
}

.own-type-row__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

.own-type-row__indicator {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
}

.own-type-row__name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.own-type-row--inactive .own-type-row__name {
  font-weight: 400;
  font-style: italic;
  color: var(--text-muted);
}

.own-type-row__description {
  font-size: 0.875rem;
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-bottom: 0.25rem;
}

.own-type-row__actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-shrink: 0;
}

/* Botones de acción de la fila: área táctil mínima 44px (WCAG 2.5.8). El
   form de «Reactivar» no debe romper la maquetación flex de las acciones. */
.own-type-row__actions .btn,
.own-type-row__actions .btn-sm {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.own-type-row__actions form {
  margin: 0;
  display: inline-flex;
}

/* Tarjeta del bloque «Tipos de serie» (colapsable). */
.factory-block {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  margin: 0 1rem 1rem;
  overflow: hidden;
}

/* Cabecera-disparador del <details>: chevron que rota al abrir. */
.factory-block-summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  background-color: var(--bg-surface-alt);
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  min-height: 44px;
  user-select: none;
}

.factory-block-summary::-webkit-details-marker {
  display: none;
}

.factory-block-summary .bi-chevron-down {
  margin-left: auto;
  transition: transform 0.2s ease;
}

details[open] .factory-block-summary .bi-chevron-down {
  transform: rotate(180deg);
}

.factory-block-summary:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

/* Badge «De serie» (pill informativa, solo lectura). */
.factory-badge {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-muted);
  background-color: var(--bg-surface-alt);
  border: 1px solid var(--border-color);
  border-radius: 9999px;
  padding: 0.125rem 0.5rem;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Fila de un tipo global (de serie). */
.global-type-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
}

.global-type-row:last-child {
  border-bottom: none;
}

.global-type-row .bi-lock {
  color: var(--text-muted);
  flex-shrink: 0;
}

.global-type-row__name {
  font-size: 1rem;
  font-weight: 400;
  color: var(--text-muted);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Estado vacío de «Mis tipos» dentro de la tarjeta: sobre superficie blanca,
   por eso el texto secundario puede usar --text-muted (regla AA). */
.types-list-wrapper .empty-state {
  color: var(--text-muted);
}

.types-list-wrapper .empty-state .bi-tag {
  color: var(--color-primary);
}

/* --------------------------------------------------------------------------
   25. P-08 — Enlace «Gestionar mis tipos de mantenimiento» bajo el select
   Spec: docs/ux/iteracion-3-p09-tipos-mantenimiento.md (acceso doble a P-09).
   Enlace discreto coherente con .subtle-link, con icono y área táctil 44px.
   -------------------------------------------------------------------------- */
.manage-types-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 44px;
  margin-top: 0.25rem;
  color: var(--color-primary);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
}

.manage-types-link:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

.manage-types-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-btn);
}

/* --------------------------------------------------------------------------
   26. Iteración 4 — Planes de mantenimiento (HU-13)
   Spec: docs/ux/iteracion-4-planes.md (§1, §2). Filas de plan en la pestaña
   «Planes» de P-06 + segmented control de 3 pestañas. Tokens v3 «Solar White».
   -------------------------------------------------------------------------- */

/* Fila de plan: bloque clicable completo → edición del plan. */
.plan-row {
  display: block;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
  text-decoration: none;
  color: inherit;
}

.plan-row:last-child {
  border-bottom: none;
}

.plan-row:hover {
  background-color: var(--bg-surface-alt);
}

.plan-row:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

.plan-row__header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.5rem;
  margin-bottom: 0.375rem;
}

.plan-row__type {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  display: flex;
  align-items: center;
  gap: 0.375rem;
  flex: 1;
  min-width: 0;
}

.plan-row__rule {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0 0 0.25rem;
}

.plan-row__due {
  font-size: 0.875rem;
  color: var(--text-main);
  font-weight: 500;
  margin: 0 0 0.125rem;
}

.plan-row__due-note {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0;
}

/* HU-30 / P-10b §5 — Acciones de la fila de un plan solo-fecha.
   En estos planes la fila es un <div> (no un <a>) con botones explícitos
   «Editar» y «Renovar», para no anidar interactivos dentro de un enlace. */
.plan-row__actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.625rem;
}

/* Botones de acción de la fila: área táctil mínima 44px (WCAG 2.5.8) y reparto
   equitativo del ancho en móvil. .btn-outline-* ya aporta min-height 48px.
   HU-26 añade «Registrar ahora» (.plan-row__register) con el mismo dimensionado:
   en la pestaña Planes acompaña a «Editar» (planes por intervalos vencidos/
   próximos); en el panel de avisos va solo (plan por intervalos) o se sustituye
   por «Renovar» (plan solo-fecha). */
.plan-row__edit,
.plan-row__renew,
.plan-row__register {
  flex: 1;
  min-height: 44px;
}

/* Panel de avisos (HU-26): cuando la fila lleva acción rápida, deja de ser un
   <a> y pasa a ser un <div> (no se anidan interactivos dentro de un enlace).
   El tipo de plan se convierte en un enlace en línea a la pestaña Planes del
   coche; mantiene la afordancia de fila (sin subrayado salvo en hover/foco). */
.plan-row__type-link {
  text-decoration: none;
  color: var(--text-main);
}

.plan-row__type-link:hover {
  text-decoration: underline;
}

.plan-row__type-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   Panel de avisos (P-11 / HU-15). Reutiliza .history-list + .plan-row +
   .status-badge de la pestaña Planes para que cada aviso se lea idéntico al
   detalle del coche. Solo añade el marco por coche (cabecera clicable que
   enlaza a la pestaña Planes) y la introducción. Mobile-first.
   -------------------------------------------------------------------------- */
.alerts-panel__intro {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0 0 1rem;
}

/* Grupo por coche: tarjeta que envuelve la cabecera del coche + sus filas de
   plan, con el mismo lenguaje visual que .car-card (radio, sombra, borde). */
.alerts-car-group {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  margin-bottom: 0.75rem;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* Cabecera del coche: enlace completo a la pestaña Planes del detalle. Área
   táctil cómoda (>=56px), foco visible, sin subrayado (afordancia de fila). */
.alerts-car-group__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 56px;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  text-decoration: none;
  color: inherit;
}

.alerts-car-group__header:hover {
  background-color: var(--bg-surface-alt);
}

.alerts-car-group__header:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

.alerts-car-group__car {
  min-width: 0;
}

.alerts-car-group__name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.125rem;
}

.alerts-car-group__meta {
  font-size: 0.875rem;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.alerts-car-group__chevron {
  color: var(--text-muted);
  font-size: 1.25rem;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Placa de matrícula visual (it. 4, spec A.2/A.5). Solar White, WCAG 2.2 AA.
   Variantes: --compact (lista P-04), --detail (P-06 y previsualización P-05),
   --eu (con banda azul) / --other (blanca lisa, sin banda, para 'OTRO').
   -------------------------------------------------------------------------- */
.plate{display:inline-flex;align-items:stretch;background-color:var(--plate-bg);border:1.5px solid var(--plate-border);border-radius:var(--plate-radius);overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.18),inset 0 1px 0 rgba(255,255,255,0.8);vertical-align:middle;flex-shrink:0}
.plate__band{display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:var(--plate-band-bg);color:var(--plate-band-text);padding:0 3px}
.plate__country{font-weight:700;line-height:1;letter-spacing:0.5px;text-transform:uppercase;color:var(--plate-band-text)}
.plate__number-wrap{display:flex;align-items:center;justify-content:center;padding:0 6px}
.plate__number{font-family:ui-monospace,"Courier New",Courier,monospace;font-weight:700;color:var(--plate-text);text-transform:uppercase;letter-spacing:1px;line-height:1;white-space:nowrap}
.plate--compact{height:26px}
.plate--compact .plate__band{width:16px;min-width:16px}
.plate--compact .plate__country{font-size:9px;letter-spacing:0}
.plate--compact .plate__number-wrap{padding:0 5px}
.plate--compact .plate__number{font-size:0.75rem;letter-spacing:1.5px}
.plate--detail{height:38px}
.plate--detail .plate__band{width:24px;min-width:24px}
.plate--detail .plate__country{font-size:13px;letter-spacing:0.5px}
.plate--detail .plate__number-wrap{padding:0 8px}
.plate--detail .plate__number{font-size:1rem;letter-spacing:2px}
.plate--other .plate__number-wrap{padding:0 8px}

/* Previsualización en el formulario (spec A.5): plate --detail + etiqueta. */
.plate-preview{display:flex;align-items:center;gap:0.75rem;margin:0.5rem 0 1rem}
.plate-preview__label{font-size:0.75rem;color:var(--text-muted);margin:0;white-space:nowrap}

/* --------------------------------------------------------------------------
   Selector de idioma (6 idiomas, it. 4, spec PARTE B). Triple acceso (header,
   login, perfil) + offcanvas bottom sheet compartido. Solar White, WCAG 2.2 AA.
   Contrastes verificados: nombre 17.9:1, activo coral 5.5:1, código activo 5.5:1.
   -------------------------------------------------------------------------- */
.lang-trigger{display:flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0 8px;background-color:var(--bg-surface-alt);border:1.5px solid var(--border-color);border-radius:8px;cursor:pointer;flex-shrink:0}
.lang-trigger:hover{background-color:var(--border-color)}
.lang-trigger:focus-visible{outline:3px solid var(--color-primary);outline-offset:2px}
.lang-trigger[aria-expanded="true"]{background-color:var(--color-primary);border-color:var(--color-primary)}
.lang-trigger__code{font-size:0.75rem;font-weight:700;letter-spacing:0.5px;color:var(--text-main);line-height:1}
.lang-trigger[aria-expanded="true"] .lang-trigger__code{color:var(--color-primary-text)}
.lang-offcanvas{height:auto;max-height:70vh;border-radius:16px 16px 0 0;border-top:1px solid var(--border-color)}
.lang-offcanvas .offcanvas-header{border-bottom:1px solid var(--border-color);padding:1rem 1rem 1rem 1.25rem}
.lang-offcanvas .offcanvas-title{font-size:1rem;font-weight:600;color:var(--text-main);display:flex;align-items:center;gap:0.5rem;margin:0}
.lang-offcanvas__body{padding:0.5rem 0;overflow-y:auto}
.lang-offcanvas__list{list-style:none;margin:0;padding:0}
.lang-offcanvas__form{margin:0}
.lang-offcanvas__option{display:flex;align-items:center;gap:0.75rem;width:100%;min-height:56px;padding:0 1.25rem;background:transparent;border:none;text-align:left;cursor:pointer;color:var(--text-main);font-size:1rem;font-weight:400}
.lang-offcanvas__option:hover{background-color:var(--bg-surface-alt)}
.lang-offcanvas__option:focus-visible{outline:3px solid var(--color-primary);outline-offset:-3px;z-index:1;position:relative}
.lang-offcanvas__option--active{color:var(--color-primary);font-weight:600}
.lang-offcanvas__check{display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;font-size:1rem;color:var(--color-primary)}
.lang-offcanvas__name{flex:1}

/* --------------------------------------------------------------------------
   27. Iteración 5a — Pestaña «Info»: Notas personales (HU-20) y Ficha técnica
   (HU-22) en P-06.
   Spec: docs/ux/iteracion-5a-notas-info.md (§«CSS nuevo» + segmented control
   de 4 pestañas). Tokens v3 «Solar White», mobile-first 360px, WCAG 2.2 AA.
   -------------------------------------------------------------------------- */

/* Tab rail de 5 pestañas (Mantenimientos / Lecturas / Planes / Info / Documentos),
   spec v2 §1. Las 5 no caben fijas en 360px: patrón desplazable (overflow-x con
   scroll-snap, sin scrollbar visible). Pestaña activa = subrayado coral 3px +
   texto coral 600 (NO fondo relleno). Reemplaza a --three/--four (eliminados).
   Estos selectores son MÁS específicos que la base .seg-control / .seg-tab, así
   que ganan: se anula el borde/radio/overflow:hidden de la base y el fondo
   relleno del .seg-tab--active base. A 360px: 4 pestañas visibles (88px c/u) +
   asomo de la 5.ª, que invita al desplazamiento horizontal. */
/* Contenedor con forma de tarjeta: mismos márgenes laterales (1rem) que el resto
   de superficies para corregir la desalineación full-bleed; el radio recorta las
   pestañas y position:relative ancla el gradiente de afordancia de scroll. */
.seg-control--five {
  display: flex;
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden; /* el radio recorta las pestañas */
  margin: 0 1rem 0.75rem; /* mismo margen lateral que las tarjetas */
  position: relative; /* para el gradiente de afordancia */
}

/* Carril interno: el contenedor del scroll horizontal con scroll-snap, sin
   barra de scroll visible (el desplazamiento sigue activo). */
.seg-control--five__rail {
  display: flex;
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; /* Firefox: sin barra de scroll visible */
  width: 100%;
}

/* WebKit/Blink: ocultar la barra de scroll del carril. */
.seg-control--five__rail::-webkit-scrollbar {
  display: none;
}

.seg-control--five .seg-tab {
  flex: 0 0 auto;
  min-width: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  scroll-snap-align: start;
  background: transparent;
  border: none;
  border-bottom: 3px solid transparent;
  padding: 0 0.75rem;
  transition: color 0.15s, border-color 0.15s;
  position: relative;
}

.seg-control--five .seg-tab--active {
  background-color: transparent; /* anula el relleno coral de la base */
  color: var(--color-primary);
  font-weight: 600;
  border-bottom-color: var(--color-primary);
  pointer-events: none;
}

.seg-control--five .seg-tab:not(.seg-tab--active):hover {
  color: var(--text-main);
  background-color: var(--bg-surface-alt);
}

.seg-control--five .seg-tab:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px; /* anillo dentro del borde redondeado, sin recorte */
  z-index: 1;
  border-radius: 4px;
}

/* Afordancia de scroll: degradado a la derecha que insinúa contenido oculto.
   En >=768px las pestañas reparten ancho y no hay scroll, así que se oculta. */
.seg-control--five::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 48px;
  height: 100%;
  background: linear-gradient(
    to right,
    rgba(var(--scroll-fade-rgb), 0) 0%,
    rgba(var(--scroll-fade-rgb), 0.92) 100%
  );
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  pointer-events: none;
  z-index: 2;
  transition: opacity 0.2s;
}

@media (min-width: 768px) {
  .seg-control--five .seg-tab {
    flex: 1;
    min-width: 0;
    padding: 0 1rem;
  }

  .seg-control--five::after {
    display: none;
  }
}

/* Tarjeta-sección de la pestaña Info («Notas personales» y «Ficha técnica»):
   misma profundidad que el resto de superficies del sistema. Márgenes laterales
   de 1rem (alineados con la cabecera y el segmented control) y separación
   vertical entre ambas tarjetas. */
.info-section-card {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 1rem;
  margin: 0 1rem 0.75rem;
}

/* Cabecera de cada tarjeta-sección: título (con icono) + botón «Editar» que
   se ancla a la derecha. */
.info-section-header {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.75rem;
}

.info-section-header__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin: 0;
}

.info-section-header__title .bi {
  color: var(--color-primary);
}

/* Botón «Editar» de cada sección: área táctil mínima 44×44px (WCAG 2.5.8).
   El min-height de 44px convive con el de 48px de .btn-primary porque éste es
   un .btn-outline-secondary, que no recibe esa regla. */
.info-section-header__edit {
  min-height: 44px;
  min-width: 44px;
  padding: 0.375rem 0.75rem;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* .btn-outline-secondary de Bootstrap usa un gris (#6c757d) que no llega a AA
   sobre blanco; se reasigna al token de texto principal con borde del sistema
   para que «Editar» sea legible y coherente con Solar White. */
.info-section-header__edit.btn-outline-secondary {
  --bs-btn-color: var(--text-main);
  --bs-btn-border-color: var(--border-color);
  --bs-btn-hover-bg: var(--bg-surface-alt);
  --bs-btn-hover-border-color: var(--color-primary);
  --bs-btn-hover-color: var(--color-primary);
  --bs-btn-active-bg: var(--bg-surface-alt);
  --bs-btn-active-border-color: var(--color-primary);
  --bs-btn-active-color: var(--color-primary);
  font-weight: 500;
}

.info-section-header__edit:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  box-shadow: none;
}

/* --- Sección «Notas personales» (HU-20): modo lectura --- */
.personal-notes__text {
  font-size: 1rem;
  color: var(--text-main);
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Estado vacío de notas: itálica muted (0.875rem). Sobre superficie blanca,
   --text-muted cumple AA. .fst-italic/.text-muted de Bootstrap ya aplican,
   esta regla solo fija el cuerpo y elimina el margen. */
.personal-notes__empty {
  font-size: 0.875rem;
  margin: 0;
}

/* --- Sección «Ficha técnica» (HU-22): modo lectura --- */
.technical-data {
  margin: 0;
}

.technical-data__pair {
  margin-bottom: 0.75rem;
}

.technical-data__pair:last-of-type {
  margin-bottom: 0;
}

.technical-data__label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 0.125rem;
}

.technical-data__value {
  font-size: 1rem;
  color: var(--text-main);
  margin: 0;
}

.technical-data__value--empty {
  font-style: italic;
  color: var(--text-muted);
}

/* Estado vacío de la ficha completa: itálica muted (0.875rem). */
.technical-data__empty {
  font-size: 0.875rem;
  margin: 0;
}

/* --- Flash inline (éxito/error de guardado, role="alert") --- */
/* Aviso compacto dentro de la tarjeta-sección (no es la barra global de
   .alerts-area). Verde de éxito del sistema sobre su fondo (AA verificado). */
.inline-flash {
  font-size: 0.875rem;
  border-radius: var(--radius-btn);
  padding: 0.5rem 0.75rem;
  margin: 0 0 0.75rem;
}

.inline-flash--success {
  color: var(--color-success);
  background-color: var(--color-success-bg);
}

.inline-flash--error {
  color: var(--color-error);
  background-color: var(--color-error-bg);
}

/* --- Edición inline: campos y acciones --- */
/* Bloque de un campo del formulario de ficha (label + input + ayuda/error). */
.form-field {
  margin-bottom: 0.75rem;
}

.form-field .form-text {
  margin-top: 0.25rem;
}

/* Acciones de la edición inline: «Guardar» (primario, ancho completo, 48px) y
   «Cancelar» (enlace, 44px). En columna y centradas para el patrón móvil. */
.info-section-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
  margin-top: 1rem;
}

/* «Cancelar» (.btn-link): área táctil mínima 44px y color de enlace del
   sistema; el .btn-primary ya recibe sus 48px de la sección 3. */
.info-section-actions .btn-link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary);
  font-weight: 500;
}

.info-section-actions .btn-link:hover {
  color: var(--color-primary-dark);
}

/* --- Enlaces externos al pie de la tarjeta «Ficha técnica», siempre visibles ---
   Contenedor con los enlaces de recambios y despiece, más el desplegable de
   aceite recomendado (.oil-selector). Los enlaces planos comparten el mismo
   tratamiento visual; el contenedor gestiona la separación con la ficha de arriba
   y la disposición (columna en móvil, fila desde tablet). */
.external-links {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  border-top: 1px solid var(--border-color);
  margin-top: 0.75rem;
  padding-top: 0.25rem;
}

.parts-link,
.parts-diagram-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-primary);
  text-decoration: none;
  padding: 0.5rem 0;
  min-height: 44px;
}

.parts-link:hover,
.parts-diagram-link:hover {
  text-decoration: underline;
  color: var(--color-primary-dark);
}

.parts-link:focus-visible,
.parts-diagram-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Desde tablet (≥768px) los enlaces se disponen en fila, alineados a la
   izquierda y con separación generosa; flex-wrap permite que el tercero baje
   de línea si no cabe en pantallas estrechas dentro de este rango. */
@media (min-width: 768px) {
  .external-links {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.5rem;
  }
}

/* --- Desplegable de aceite recomendado (<details> nativo) ---
   Sustituye al antiguo enlace plano .oil-link. El <summary> es el
   disparador (mismo aspecto visual que los enlaces planos hermanos) y al abrir
   despliega los enlaces por marca. El marcador nativo se oculta y se usa un
   chevron propio que rota, siguiendo el patrón de .factory-block-summary. */
.oil-selector {
  width: 100%;
}

.oil-selector__trigger {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 44px;
  padding: 0.5rem 0;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-primary);
  cursor: pointer;
  user-select: none;
  text-decoration: none;
}

.oil-selector__trigger::-webkit-details-marker {
  display: none;
}

.oil-selector__trigger:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

.oil-selector__trigger:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.oil-selector__chevron {
  margin-left: auto;
  transition: transform 0.2s ease;
  font-size: 1rem;
}

.oil-selector[open] .oil-selector__chevron {
  transform: rotate(180deg);
}

.oil-selector__brands {
  display: flex;
  flex-direction: column;
  padding-left: 1.625rem;
  padding-top: 0.25rem;
}

.oil-selector__brand-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 44px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-primary);
  text-decoration: none;
}

.oil-selector__brand-link .bi {
  font-size: 0.8125rem;
}

.oil-selector__brand-link:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

.oil-selector__brand-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Desde tablet (≥768px) el desplegable se integra en la fila de enlaces: ocupa
   solo lo necesario y las marcas se alinean a la izquierda sin sangría. */
@media (min-width: 768px) {
  .oil-selector {
    flex: 0 0 auto;
    width: auto;
  }

  .oil-selector__trigger {
    width: auto;
  }

  .oil-selector__chevron {
    margin-left: 0.25rem;
  }

  .oil-selector__brands {
    padding-left: 0;
    width: max-content;
  }
}

/* --- Indicador de carga htmx (spinner mientras viaja el POST de guardado) --- */
/* htmx alterna .htmx-request en el elemento que dispara la petición. El span
   .htmx-indicator del botón «Guardar» se oculta en reposo y aparece (inline)
   solo durante la petición. Lo dejamos como spinner de Bootstrap visible. */
.htmx-indicator {
  display: none;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  display: inline-flex;
}

/* El span es .visually-hidden (texto «Guardando» para lectores). Durante la
   petición mostramos un spinner visible sin sacar el texto del flujo accesible:
   se añade un ::before con el spinner girando de Bootstrap. */
.htmx-request .info-section-actions .btn-primary::before {
  content: "";
  display: inline-block;
  width: 1rem;
  height: 1rem;
  margin-right: 0.5rem;
  border: 0.15em solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: garagio-spin 0.75s linear infinite;
}

@keyframes garagio-spin {
  to { transform: rotate(360deg); }
}

/* Mientras se envía, el botón «Guardar» no admite más clics (evita doble POST)
   sin cambiar su color (sigue siendo primario, no «disabled» visual). */
.htmx-request .info-section-actions .btn-primary {
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   28. Iteración v2 — Pestaña «Documentos» (P-06 / P-11), consulta VIN (NHTSA)
   y neumáticos equivalentes.
   Spec: docs/ux/iteracion-v2-pestanas-documentos-vin-neumaticos.md.
   Tokens v3 «Solar White», mobile-first 360px, WCAG 2.2 AA.
   -------------------------------------------------------------------------- */

/* Estado vacío de «Documentos» (spec v2 §2): icono coral a 48px (el tamaño
   base ya es 48px; aquí solo se aplica el color primario, como pide la spec). */
.empty-state--documents .bi {
  color: var(--color-primary);
}

/* --- Pestaña «Documentos»: lista de filas (spec v2 §2) --- */
/* Cada fila: cabecera (icono por extensión + tipo), descripción y fecha
   opcionales, y acciones «Ver» / «Eliminar». Sin márgenes laterales propios:
   ya viven dentro del #panel-tab, que reserva el gutter de la página. */
.document-row {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-surface);
}

.document-row:first-child {
  border-top: 1px solid var(--border-color);
}

.document-row__header {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

/* Icono de tipo de archivo: coral del sistema, tamaño legible en la fila. */
.document-row__header .bi {
  color: var(--color-primary);
  font-size: 1.25rem;
  line-height: 1.4;
  flex-shrink: 0;
}

.document-row__type {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-main);
  flex: 1;
}

.document-row__description {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0 0 0.125rem;
  word-break: break-word;
}

.document-row__date {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin: 0 0 0.5rem;
}

.document-row__actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Área táctil mínima 44px (WCAG 2.5.8). Sobrescribe el min-height de 48px de
   .btn-outline-primary/-danger para estas acciones de fila más compactas. */
.document-row__actions .btn {
  min-height: 44px;
  font-size: 0.875rem;
  padding: 0.375rem 0.875rem;
}

/* --- Consulta VIN / NHTSA (spec v2 §3): VIN + botón «Consultar» en línea --- */
/* El grupo es flex (lo declara la plantilla con utilidades de Bootstrap); aquí
   se asegura que el botón no se encoja y conserve su altura táctil junto al
   input de 48px. El VIN vive FUERA de #bloque-ficha-campos para no perderse en
   el swap htmx de la consulta. */
.vin-field-group .btn-outline-secondary {
  --bs-btn-color: var(--text-main);
  --bs-btn-border-color: var(--border-color);
  --bs-btn-hover-bg: var(--bg-surface-alt);
  --bs-btn-hover-border-color: var(--color-primary);
  --bs-btn-hover-color: var(--color-primary);
  --bs-btn-active-bg: var(--bg-surface-alt);
  --bs-btn-active-border-color: var(--color-primary);
  --bs-btn-active-color: var(--color-primary);
  min-height: 48px;
  flex-shrink: 0;
  white-space: nowrap;
  font-weight: 500;
}

.vin-field-group .btn-outline-secondary:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  box-shadow: none;
}

/* Indicador «Consultando…»: durante la petición htmx, htmx pone .htmx-request
   en el botón. Se oculta el texto «Consultar» y se muestra spinner + «Consultando…».
   El botón queda inerte (sin doble disparo) y mantiene su tamaño. */
.vin-field-group .btn-outline-secondary .lookup-text {
  display: inline;
}

.vin-field-group .btn-outline-secondary .looking-up-text {
  display: none;
  align-items: center;
  gap: 0.375rem;
}

.htmx-request.vin-field-group .btn-outline-secondary .lookup-text,
.vin-field-group .btn-outline-secondary.htmx-request .lookup-text {
  display: none;
}

.htmx-request.vin-field-group .btn-outline-secondary .looking-up-text,
.vin-field-group .btn-outline-secondary.htmx-request .looking-up-text {
  display: inline-flex;
}

.vin-field-group .btn-outline-secondary.htmx-request {
  pointer-events: none;
}

/* --- Autorrelleno multi-fuente de la ficha (ADR-009, doc UX) --- */

/* Nota de expectativas bajo el campo VIN: siempre visible en edición. Deja claro
   que «sin datos» es normal en ES/EU (no es un error de la app). Borde izq. e
   icono en gris para un aviso informativo sobrio, sin alarma de color. */
.autofill-note {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  background-color: var(--bg-surface-alt);
  border-left: 3px solid var(--border-color);
  border-radius: 0.375rem;
  padding: 0.625rem 0.75rem;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-main);
  line-height: 1.5;
}

.autofill-note .bi {
  color: var(--text-muted);
  flex-shrink: 0;
  margin-top: 0.125rem;
}

/* Reusable «loading» state for any button: while the htmx request is in flight,
   htmx adds .htmx-request to the button. The «Consultar» label hides and the
   spinner + «Consultando…» label shows. The button becomes inert (no double
   submit). Not scoped to .vin-field-group so it works for any .btn variant
   (e.g. the .btn-primary «Leer datos»). */
.loading-btn .lookup-text {
  display: inline;
}

.loading-btn .looking-up-text {
  display: none;
  align-items: center;
  gap: 0.375rem;
}

.loading-btn.htmx-request .lookup-text {
  display: none;
}

.loading-btn.htmx-request .looking-up-text {
  display: inline-flex;
}

.loading-btn.htmx-request {
  pointer-events: none;
}

/* Campos que el servidor rellenó automáticamente (.autofilled-field en el
   .form-field): resaltado sutil con borde izq. y fondo tenue de éxito. Usa los
   tokens --color-success (#065F46) y --color-success-bg (#D1FAE5) ya definidos
   en :root; el texto del input mantiene --text-main sobre fondo tenue (AA). No
   se comunica el estado SOLO por color: hay banner role=alert + texto a11y. */
.autofilled-field .form-control {
  border-left: 3px solid var(--color-success);
  background-color: var(--color-success-bg);
}

/* Estados durante la consulta htmx (la plantilla pone el input readonly y el
   botón disabled vía hx-on). Acotado al grupo del VIN para no afectar a otros
   inputs readonly de la app. Foco visible global intacto. */
.vin-field-group .btn-outline-secondary[disabled],
.vin-field-group .btn-outline-secondary:disabled {
  cursor: not-allowed;
  opacity: 0.75;
}

.vin-field-group .form-control[readonly] {
  background-color: var(--bg-surface-alt);
  color: var(--text-muted);
  cursor: not-allowed;
}

/* Banner de estado NHTSA (éxito / sin resultados / error): los .alert ya toman
   los tokens del sistema (sección 1). Separación inferior dentro del bloque. */
#bloque-ficha-campos > .alert {
  margin-bottom: 0.75rem;
}

/* --- Neumáticos equivalentes (spec v2 §4): bloque en ficha modo lectura --- */
.tire-equiv {
  background-color: var(--bg-surface-alt);
  border: 1px solid var(--border-color);
  border-radius: 0.5rem;
  padding: 0.75rem;
  margin-top: 0.375rem;
  margin-bottom: 0.75rem;
}

/* Disparador del <details>: oculta el marcador nativo y usa un chevron propio
   que pasa de apuntar a la derecha (cerrado) a apuntar abajo (abierto). El
   focus-visible usa offset NEGATIVO para no desbordar el radio del contenedor. */
.tire-equiv__summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.375rem 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
}

.tire-equiv__summary::-webkit-details-marker {
  display: none;
}

.tire-equiv__summary:hover {
  color: var(--text-main);
}

.tire-equiv__summary:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  border-radius: 4px;
}

.tire-equiv__chevron {
  font-size: 0.875rem;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.tire-equiv[open] .tire-equiv__chevron {
  transform: rotate(90deg);
}

.tire-equiv__list {
  list-style: none;
  padding: 0;
  margin: 0 0 0.5rem;
  margin-top: 0.375rem;
}

.tire-equiv__list li {
  font-size: 0.875rem;
  color: var(--text-main);
  padding: 0.125rem 0;
}

.tire-equiv__note {
  font-size: 0.75rem;
  font-style: italic;
  color: var(--text-muted);
  margin: 0;
}

/* --------------------------------------------------------------------------
   28. Flujo «Leer documento» (OCR, ADR-010, doc UX «leer-documento-ocr»).
   Ganchos del parcial _seccion_ficha.html y _selector_documento_ocr.html.
   Estilo mínimo y coherente con el resto del formulario de ficha.
   -------------------------------------------------------------------------- */

/* Divisor «o» (spec sección 1): separa el grupo VIN + «Rellenar automáticamente»
   del botón «Leer documento». Línea a ambos lados del texto «o», discreto, con
   los tokens del sistema. Es aria-hidden (decorativo). */
.or-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.75rem 0;
  color: var(--text-muted);
  font-size: 0.875rem;
}

.or-divider::before,
.or-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border-color);
}

/* Contenedor del panel selector (fieldset + radios + botones). Encaje coherente
   con los .form-field del formulario (mismo margen inferior) y reseteo del
   <fieldset> (sin borde/padding nativos) para que herede el ritmo del form. */
.ocr-document-selector {
  border: 0;
  margin: 0 0 0.75rem;
  padding: 0;
  min-width: 0; /* evita el desbordamiento del <fieldset> en móvil */
}

/* La <legend> usa .form-label, pero por defecto un <legend> ocupa el 100% y no
   respeta el cuerpo de etiqueta; se normaliza al ritmo de los demás labels. */
.ocr-document-selector legend.form-label {
  float: none;
  width: auto;
  margin-bottom: 0.5rem;
}

/* Estado vacío del OCR (spec sección 3): sin documentos elegibles. Coherente
   con el patrón .empty-state (mismo padding/centrado/jerarquía e icono muted
   de 48px). Se agrupan los selectores para reutilizar exactamente los valores
   del patrón existente; solo cambia el color del texto secundario: este estado
   vive DENTRO de la tarjeta blanca (#bloque-ficha-campos), no sobre --bg-page,
   así que --text-muted sí cumple AA aquí (a diferencia de .empty-state). */
.empty-state-ocr {
  text-align: center;
  padding: 3rem 1.5rem;
  color: var(--text-muted);
}

.empty-state-ocr .bi {
  font-size: 48px;
  line-height: 1;
}

.empty-state-ocr__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0.75rem 0 0.25rem;
}

.empty-state-ocr__text {
  font-size: 0.875rem;
  margin: 0 0 1.5rem;
}

/* --------------------------------------------------------------------------
   29. Hybrid OCR flow (ADR-011): method radio-cards + AI consent panel.
   Spec: ux-ui hybrid OCR. Rendered INSIDE #bloque-ficha-campos (white surface),
   so --text-muted meets AA here (it sits on white, not on --bg-page). Contrasts
   already validated by ux-ui (AA/AAA). Tokens v3 «Solar White», mobile-first.
   -------------------------------------------------------------------------- */

/* Method choice as a vertical stack of radio-cards inside <fieldset>/<legend>.
   The <legend> is visually hidden (the document selector already names the
   block); the cards themselves are the visible labels. */
.ocr-method-selector {
  border: 0;
  margin: 0 0 0.75rem;
  padding: 0;
  min-width: 0; /* prevents the <fieldset> from overflowing on mobile */
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Radio-card: the whole <label> is the touch target. The radio <input> stays
   visually-hidden (NOT display:none, so it keeps keyboard focus and a11y) and
   the card reflects its checked/focus state via :has(). */
.method-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 72px; /* comfortable touch area (WCAG 2.5.8) */
  padding: 16px;
  background-color: var(--bg-surface);
  border: 1px solid var(--ocr-card-border);
  border-radius: 8px;
  cursor: pointer;
  /* The 2px selected border must not shift the layout: compensate with an inner
     transparent ring kept at the same thickness in both states. */
  transition: background-color 0.15s, border-color 0.15s;
}

/* Selected state: coral border + tinted background (ux-ui). */
.method-card:has(input[type="radio"]:checked) {
  background-color: var(--ocr-card-selected-bg);
  border: 2px solid var(--color-primary);
  /* Keep the inner box stable when the border grows 1px → 2px. */
  padding: 15px;
}

/* Keyboard focus: visible ring around the whole card (the radio is hidden, so
   the focus indicator must live on the card). WCAG 2.4.7 / 2.4.11. */
.method-card:has(input[type="radio"]:focus-visible) {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* Disabled method (AI option without an API key): muted, non-interactive. */
.method-card--disabled {
  background-color: var(--ocr-card-disabled-bg);
  opacity: 0.6;
  cursor: not-allowed;
}

.method-card--disabled:has(input[type="radio"]:checked) {
  /* A disabled card never adopts the selected styling. */
  background-color: var(--ocr-card-disabled-bg);
  border: 1px solid var(--ocr-card-border);
  padding: 16px;
}

/* Leading icon of each card (decorative; the text carries the meaning). */
.method-card__icon {
  flex-shrink: 0;
  font-size: 1.25rem;
  line-height: 1.4;
  color: var(--color-primary);
}

.method-card--disabled .method-card__icon {
  color: var(--text-muted);
}

.method-card__body {
  flex: 1;
  min-width: 0; /* allows the description to wrap inside the flex row */
}

/* Title row: method name + optional «Recomendado» badge. */
.method-card__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
}

.method-card__description {
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0.125rem 0 0;
  line-height: 1.5;
}

/* «Recomendado» badge: coral pill on the recommended (local) method. */
.recommended-tag {
  display: inline-flex;
  align-items: center;
  background-color: var(--color-primary);
  color: var(--color-primary-text);
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 4px;
  white-space: nowrap;
}

/* «Ya diste tu consentimiento» badge on the AI card: success green + check. */
.method-card__consented {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-top: 0.375rem;
  color: var(--color-success); /* #065F46, AA on white */
  font-size: 0.8125rem;
  font-weight: 600;
}

.method-card__consented .bi {
  font-size: 0.875rem;
}

/* AI consent panel (ADR-011 §6.3 / RGPD): left coral rule, tinted surface. */
.ai-consent-panel {
  background-color: var(--ai-consent-bg);
  border-left: 4px solid var(--color-primary);
  border-radius: 8px;
  padding: 20px 16px;
}

.ai-consent-panel__title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 18px;
  font-weight: 600;
  color: var(--text-main);
  margin: 0 0 0.5rem;
}

.ai-consent-panel__title .bi {
  color: var(--color-primary);
  flex-shrink: 0;
}

/* Title is focused after the htmx swap (tabindex=-1): no default outline jump. */
.ai-consent-panel__title:focus {
  outline: none;
}

.ai-consent-panel__title:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Always-visible summary. #495057 on #FFF8F7 ≈ 8.6:1 (AAA, verified by ux-ui);
   tokenizado en --ai-consent-text para tener equivalente AA en oscuro. */
.ai-consent-panel__summary {
  font-size: 15px;
  line-height: 1.6;
  color: var(--ai-consent-text);
  margin: 0 0 0.75rem;
}

/* Collapsible legal detail («Ver más información»). The native marker is hidden
   and a coral chevron is used, matching the other <details> in the app. */
.ai-consent-panel__detail {
  margin-bottom: 1rem;
}

.ai-consent-panel__detail-summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 44px; /* touch area (WCAG 2.5.8) */
  padding: 0.375rem 0;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-primary);
  cursor: pointer;
  user-select: none;
}

.ai-consent-panel__detail-summary::-webkit-details-marker {
  display: none;
}

.ai-consent-panel__detail-summary:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

.ai-consent-panel__detail-summary:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.ai-consent-panel__detail-summary .bi {
  transition: transform 0.2s ease;
}

.ai-consent-panel__detail[open] .ai-consent-panel__detail-summary .bi {
  transform: rotate(180deg);
}

/* Legal body inside the detail: kept readable, slightly smaller than the
   summary. #495057 on #FFF8F7 (AAA, verified by ux-ui). */
.ai-consent-panel__detail p {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ai-consent-text);
  margin: 0 0 0.5rem;
}

.ai-consent-panel__detail p:last-child {
  margin-bottom: 0;
}

.ai-consent-panel__detail a {
  color: var(--color-primary);
}

/* Consent checkbox row: comfortable touch area, never pre-checked. */
.ai-consent-panel .form-check {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  min-height: 44px;
  padding-left: 0;
  margin-bottom: 0.5rem;
}

.ai-consent-panel .form-check-input {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  margin: 0.125rem 0 0;
}

.ai-consent-panel .form-check-label {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--text-main);
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   30. Legal pages (privacy policy). Readable long-form prose on the page
   background. The privacy policy is reached from the AI consent link and may
   be opened by an unauthenticated visitor too. Tokens v3, mobile-first.
   -------------------------------------------------------------------------- */
.legal-page {
  /* Slightly wider than the form container: long-form text needs more room,
     but capped so the line length stays comfortable to read. */
  max-width: 640px;
}

.legal-page h2 {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 1rem;
}

.legal-page h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  margin: 1.5rem 0 0.375rem;
}

.legal-page p {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--text-main);
  margin: 0 0 0.75rem;
}

/* Draft notice at the top of the legal page: informative ámbar block (uses the
   warning state tokens; --state-warning #92400E reaches AA on its tinted bg). */
.legal-draft-notice {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  background-color: var(--state-warning-bg);
  border-left: 4px solid var(--state-warning);
  border-radius: var(--radius-btn);
  padding: 0.75rem;
  margin-bottom: 1.5rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--state-warning);
}

.legal-draft-notice .bi {
  flex-shrink: 0;
  margin-top: 0.125rem;
}

/* ==========================================================================
   31. Desktop UX MVP (ux-ui «improve PC without breaking mobile»).
   Mobile-first is preserved: NOTHING below md (768px) changes here. All the
   desktop rules live behind md/lg/xl breakpoints (Bootstrap 5 scale:
   md>=768, lg>=992, xl>=1200). Tokens v3 «Solar White». WCAG 2.2 AA.
   -------------------------------------------------------------------------- */

/* --- MVP-2: adaptive content container -----------------------------------
   Single wrapper that grows the readable width on wider viewports while
   staying centred. Replaces .narrow-container on the list/profile and
   wraps the detail components. Mobile stays at the narrow 480px width. */
.app-container {
  width: 100%;
  max-width: 480px;
  margin-inline: auto;
  padding-inline: 1rem;
}

@media (min-width: 768px) {
  .app-container {
    max-width: 720px;
  }
}

@media (min-width: 992px) {
  .app-container {
    max-width: 960px;
    padding-inline: 1.5rem;
  }
}

@media (min-width: 1200px) {
  .app-container {
    max-width: 1120px;
    padding-inline: 2rem;
  }
}

/* Detail wrapper: its children (.car-detail-header, .seg-control,
   .info-section-card, .*-row lists…) carry their own lateral margins on
   mobile, so the wrapper stays transparent below lg (no own padding/max-width
   that would double the gutter). From lg it limits and centres the column and
   neutralises the children's lateral margins so they breathe inside it. */
.app-container--detail {
  max-width: none;
  padding-inline: 0;
}

@media (min-width: 992px) {
  .app-container--detail {
    max-width: 960px;
    padding-inline: 1.5rem;
  }

  .app-container--detail > .car-detail-header,
  .app-container--detail > .seg-control,
  .app-container--detail .info-section-card,
  .app-container--detail .types-list-wrapper,
  .app-container--detail .factory-block {
    margin-inline: 0;
  }
}

@media (min-width: 1200px) {
  .app-container--detail {
    max-width: 1120px;
    padding-inline: 2rem;
  }
}

/* --- v4-3: cars grid ------------------------------------------------------
   Single column on <md (no change); 2 columns from md, 3 from lg, 4 from xl
   (Desktop Premium v4). The cards keep their own .car-card margin-bottom
   on mobile; inside the grid the row-gap takes over, so the trailing margin is
   dropped from md upwards. */
@media (min-width: 768px) {
  .car-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
  }

  .car-grid .car-card {
    margin-bottom: 0;
  }
}

@media (min-width: 992px) {
  .car-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.25rem;
  }
}

@media (min-width: 1200px) {
  .car-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* --- v4-5: vertical car cards (>=lg) -------------------------------------
   On mobile the card keeps its lateral-thumbnail layout (.car-card__layout
   is a flex row, no change). From lg the layout turns into a vertical column:
   the photo becomes a 16:9 hero on top (rounded top corners) and the body sits
   below it. The chevron/edit affordance is dropped on PC (the whole card is the
   link target via app.js). */
@media (min-width: 992px) {
  .car-grid .car-card {
    padding: 0;
    overflow: hidden;
  }

  .car-grid .car-card__layout {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  /* Photo as a full-width 16:9 hero with only the top corners rounded. */
  .car-grid .car-card__photo-wrap {
    flex-shrink: 1;
    width: 100%;
  }

  .car-grid .car-card__photo {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
  }

  .car-grid .car-card__photo--placeholder {
    font-size: 48px;
  }

  /* Body padding restored inside the now-padless card. */
  .car-grid .car-card__body {
    padding: 1rem;
  }
}

/* --- v4-1: desktop sidebar (>=lg) ----------------------------------------
   Hidden below lg; the mobile bottom bar (.bottom-bar) is the primary
   navigation there. From lg it is a fixed 240px left rail and the bottom bar is
   hidden; the page content is shifted right via body padding. */
.sidebar {
  display: none;
}

@media (min-width: 992px) {
  .sidebar {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-width);
    z-index: 1040;
    overflow-y: auto;
    background-color: var(--bg-surface);
    border-right: 1px solid var(--border-color);
  }

  /* Brand header (56px) with bottom border. The coral car icon + «GaragIO». */
  .sidebar__brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 56px;
    padding: 0 1.25rem;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-main);
    text-decoration: none;
    font-size: 1.125rem;
    font-weight: 700;
    flex-shrink: 0;
  }

  .sidebar__brand .bi {
    font-size: 1.5rem;
    color: var(--color-primary);
    line-height: 1;
  }

  .sidebar__brand:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: -3px;
  }

  /* Navigation: column of items, takes the remaining height so the user footer
     can be pushed to the bottom. */
  .sidebar__nav {
    display: flex;
    flex-direction: column;
    padding: 0.75rem 0.5rem;
    gap: 0.125rem;
    flex: 1 1 auto;
  }

  .sidebar__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 48px;
    padding: 0 1rem;
    border-radius: var(--radius-btn);
    color: var(--text-secundario-en-pagina);
    text-decoration: none;
    font-size: 0.9375rem;
    font-weight: 500;
  }

  .sidebar__item .bi {
    font-size: 1.25rem;
    line-height: 1;
    flex-shrink: 0;
  }

  .sidebar__item:hover {
    background-color: var(--bg-surface-alt);
    color: var(--text-main);
  }

  /* Active item: tinted coral background, coral text 600, 3px coral rule on the
     left edge. El tinte usa el rgb del acento (--bs-primary-rgb), que cambia con
     el tema; en oscuro sube la opacidad para que la franja se perciba sobre el
     slate (un 7% sería casi invisible). */
  .sidebar__item--active {
    background-color: rgba(var(--bs-primary-rgb), 0.07);
    color: var(--color-primary);
    font-weight: 600;
  }

  [data-theme="dark"] .sidebar__item--active {
    background-color: rgba(var(--bs-primary-rgb), 0.16);
  }

  .sidebar__item--active::before {
    content: "";
    position: absolute;
    inset: 0.375rem auto 0.375rem 0;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background-color: var(--color-primary);
  }

  .sidebar__item:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: 2px;
  }

  /* HU-25 badge inside a sidebar item: pushed to the right edge of the rail.
     The base .nav-badge (red pill) is shared with the bottom bar; here it only
     needs the right alignment. */
  .sidebar__item .nav-badge {
    margin-left: auto;
  }

  /* Quick theme switcher row above the user footer. The trigger keeps its own
     44×44 box; the row just adds the lateral padding/separator of the rail. */
  .sidebar__theme {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    border-top: 1px solid var(--border-color);
    flex-shrink: 0;
  }

  /* User footer: avatar (initials) + name, anchored at the bottom. */
  .sidebar__user {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    min-height: 56px;
    padding: 0 1rem;
    border-top: 1px solid var(--border-color);
    color: var(--text-main);
    text-decoration: none;
    flex-shrink: 0;
  }

  .sidebar__user:hover {
    background-color: var(--bg-surface-alt);
  }

  .sidebar__user:focus-visible {
    outline: 3px solid var(--color-primary);
    outline-offset: -3px;
  }

  .sidebar__avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background-color: var(--color-primary);
    color: var(--color-primary-text);
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
  }

  .sidebar__user-name {
    font-size: 0.875rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* The authenticated content is shifted right to clear the fixed sidebar
     (.with-session is set on <body> only when the user is logged in, so the
     unauthenticated login split-screen is NOT shifted). The bottom bar is
     hidden and the page no longer reserves its bottom space. */
  body.with-session {
    padding-left: var(--sidebar-width);
  }

  .bottom-bar {
    display: none;
  }

  main.with-bottom-bar {
    padding-bottom: 1rem;
  }
}

/* --- v4-2: section topbar (>=lg) -----------------------------------------
   60px sticky bar inside the content area (right of the sidebar), rendered per
   screen. Not rendered on <lg (the mobile headers stay). Title on the left,
   actions on the right. */
.section-topbar {
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: var(--section-topbar-height);
  padding: 0 var(--content-padding-desktop);
  background-color: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
  position: sticky;
  top: 0;
  z-index: 1030;
}

.section-topbar__title {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

.section-topbar__title .screen-title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.section-topbar__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* The action buttons in the topbar are compact (not the 48px tall block of
   forms): 44px touch area is enough here. */
.section-topbar__actions .btn {
  min-height: 44px;
}

/* --- v4 (FAB): from md there is no bottom bar offset to clear -------------
   On >=md the bottom bar is either hidden (>=lg) or visually irrelevant to the
   FAB anchoring; the offset is dropped and it is pinned at 1.5rem. From lg the
   FAB is hidden entirely (the «+ Añadir coche» action lives in the section
   topbar). */
@media (min-width: 768px) {
  .fab-action {
    bottom: 1.5rem;
  }
}

@media (min-width: 992px) {
  .fab-action {
    display: none;
  }
}

/* --- v4-3/4: detail header two-column layout + button placement (>=lg) ----
   Fixes the two user complaints: the photo no longer gets cropped (4:3 column
   that fills the height) and the action buttons are well placed (the contextual
   button moves into the data column; the fixed bottom action bar is hidden). */
@media (min-width: 992px) {
  .car-detail-header {
    display: grid;
    grid-template-columns: 360px 1fr;
    padding: 0;
    overflow: hidden;
  }

  /* Photo column: the hero spans the full height of the card at 4:3, with only
     the left corners rounded. Reset the mobile negative margins/radius. */
  .car-detail-header__hero {
    width: auto;
    margin: 0;
    height: 100%;
    border-radius: var(--radius-card) 0 0 var(--radius-card);
  }

  .car-detail-header__hero .car-detail-header__photo {
    aspect-ratio: 4 / 3;
    height: 100%;
    border-radius: var(--radius-card) 0 0 var(--radius-card);
  }

  /* Data column: padding 2rem, vertical flex, action button pinned to the foot. */
  .car-detail-header__data-column {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 2rem;
  }

  /* The contextual primary action at the foot of the data column. */
  .car-detail-header__action {
    margin-top: 1.5rem;
  }

  .car-detail-header__action .btn {
    width: auto;
    min-width: 240px;
  }

  /* Buttons fix: the fixed bottom action bar is hidden on PC and the <main> no
     longer reserves its 80px hole. */
  .context-action-bar {
    display: none;
  }

  main.with-action-bar {
    padding-bottom: 1rem;
  }
}

/* --- v4-6: login split-screen (>=lg) -------------------------------------
   On <lg the wrapper is a no-op (single column) and the existing login is
   intact. From lg it becomes two columns: a coral brand panel + the login card
   without its own shadow/border. */
@media (min-width: 992px) {
  .login-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100vh;
  }

  /* Brand panel: coral background, white text. Contrast white on coral
     (#FFFFFF on #C13209) ≈ 5.5:1, verified AA. */
  .login-split__brand {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 2rem;
    background-color: var(--color-primary);
    color: var(--color-primary-text);
    text-align: center;
  }

  .login-split__logo {
    font-size: 80px;
    line-height: 1;
    color: var(--color-primary-text);
  }

  .login-split__title {
    font-size: 2rem;
    font-weight: 700;
  }

  .login-split__subtitle {
    font-size: 1.125rem;
    /* Token-driven so it stays AA in both themes (HU-50 modo oscuro). En claro
       --color-primary-text=#FFFFFF sobre coral #C13209 = 5.6:1; en oscuro
       #1A120D sobre coral aclarado #FF6B3D = 6.5:1. El antiguo
       rgba(255,255,255,0.85) caía a 2.4:1 sobre el coral claro del tema oscuro. */
    color: var(--color-primary-text);
    max-width: 24ch;
  }

  /* Right panel: the login card loses its shadow/border (the split is the
     visual container now). */
  .login-split__panel {
    min-height: 100vh;
  }

  .login-split__panel .login-card {
    box-shadow: none;
    border: none;
  }
}

/* --- v4-7: form / profile widths (>=lg) ----------------------------------
   On <lg these keep the narrow mobile width (no change). The car form widens to
   680px and the profile narrows to ~520px, both centred. */
@media (min-width: 992px) {
  .narrow-container--form-width {
    max-width: 680px;
  }

  .app-container--profile {
    max-width: 520px;
  }
}

/* --- v4 (login subtitle): mobile keeps the muted small subtitle ----------
   (no change below lg). */

/* --- MVP-5: enriched hover/focus (pointer devices only) ------------------
   The lift (translateY) lives inside @media (hover:hover) so touch devices
   never get a stuck hover state; it is also disabled by reduced-motion below. */
.car-card {
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}

@media (hover: hover) {
  .car-card:hover {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-1px);
  }
}

/* Subtle transitions on the interactive rows/links (existing selectors only). */
.maintenance-row,
.reading-row,
.plan-row,
.document-row,
.back-link,
.edit-car-button {
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* --------------------------------------------------------------------------
   HU-34 — Public self-registration (P-20)
   -------------------------------------------------------------------------- */

/* Honeypot trap (ADR-014 §6.1): rendered in the DOM (bots fill it) but kept
   off-screen for humans. NOT display:none / visibility:hidden / type=hidden,
   because bots skip those; off-screen positioning is the standard honeypot
   technique. The field also carries aria-hidden + tabindex=-1 so screen readers
   ignore it and the keyboard cannot focus it. */
.honeypot-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* hCaptcha widget wrapper (ADR-014 §4): the provider's iframe is ~300px wide.
   overflow-x: hidden stops it from forcing horizontal scroll on the 360px
   layout; the fieldset/legend give the widget an accessible name. */
.hcaptcha-field {
  overflow-x: hidden;
  /* The widget injects an <iframe>/<div>; cap its box to the card width. */
  max-width: 100%;
}

.hcaptcha-field .h-captcha {
  /* Center the iframe within the card and avoid a flush-left look on mobile. */
  display: flex;
  justify-content: center;
}

/* --------------------------------------------------------------------------
   HU-33 / P-19b §8 — Notifications section of the profile (Telegram).
   Mobile-first; reuses existing tokens. Touch targets >= 44px and a visible
   focus ring (3px coral) on every interactive element.
   -------------------------------------------------------------------------- */

/* Subsection subtitle: uppercase muted label that separates «Channels» from
   «Telegram». The <hr> between subsections already draws the divider; this is
   just the heading style (it is a real <h2> for the document outline). */
.notif-section__titulo {
  margin: 0 0 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Each toggle row: the Bootstrap form-switch plus its description note. */
.notif-toggle {
  /* Comfortable vertical rhythm; the switch itself is >=44px tall via padding. */
  padding-block: 0.5rem;
  margin-bottom: 0.25rem;
  min-height: 44px;
}

.notif-toggle .form-check-input {
  /* Larger switch for an easy touch target (Bootstrap default is ~2em wide). */
  width: 2.5em;
  height: 1.4em;
  margin-top: 0.1em;
  cursor: pointer;
}

.notif-toggle .form-check-input:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.notif-toggle .form-check-label {
  font-weight: 600;
  cursor: pointer;
}

/* Description / «link your account to enable this» note under a toggle. */
.notif-toggle__nota {
  margin: 0.1rem 0 0;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* Telegram state line (holds the status badge). */
.notif-telegram__estado {
  margin: 0 0 0.75rem;
}

/* «Pending» hint: explains that the user must refresh after sending the code. */
.notif-telegram__espera-hint {
  margin: 0 0 0.75rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* --- Link-code modal (P-19b §2) --- */
.vincular-codigo__pasos {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.vincular-codigo__pasos li {
  margin-bottom: 0.25rem;
}

.vincular-codigo__pasos a {
  margin-left: 0.25rem;
}

/* The code block: large monospace value + Copy button, full-width and centred
   so it reads well at 360px. */
.vincular-codigo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1rem;
  background-color: var(--bg-surface-alt);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-btn);
}

.vincular-codigo__valor {
  /* Big, monospaced, fully selectable by hand (in addition to the Copy button). */
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.25em;
  color: var(--text-main);
  user-select: all;
  /* Keep the wide letter-spacing from pushing the last digit off-centre. */
  padding-left: 0.25em;
}

.vincular-codigo__copiar {
  /* Touch target >= 44px. */
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.vincular-codigo__copiar:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* Expiry note under the code. */
.notif-telegram__caducidad {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 1rem 0 0;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   HU-56 / P-19d (ADR-021) — Suscripción a calendario (iCal): campo de URL de
   solo lectura + botón Copiar, e instrucciones de suscripción colapsables.
   Reutiliza los tokens del sistema (Solar White v3 + tema oscuro por tokens),
   por lo que el contraste AA y el modo oscuro se resuelven solos.
   -------------------------------------------------------------------------- */

/* Fila URL + Copiar: en una sola línea en >=480px, apilada en móvil estrecho. */
.calendar-feed-url {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0.5rem;
}

.calendar-feed-url .form-control {
  /* La URL es larga: el campo ocupa el espacio sobrante y nunca baja de 12rem. */
  flex: 1 1 12rem;
  min-width: 0;
  /* Monoespaciada para que el enlace secreto se lea sin ambigüedad. */
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.875rem;
}

/* El botón Copiar: área táctil >=44px de alto y ancho cómodo en móvil. */
.calendar-feed-url__copiar {
  flex: 0 0 auto;
  min-height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.calendar-feed-url__copiar:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* A 360px el botón pasa a ancho completo bajo el campo (objetivo táctil grande). */
@media (max-width: 479.98px) {
  .calendar-feed-url__copiar {
    flex-basis: 100%;
  }
}

/* Instrucciones colapsables: <details> nativo estilado como tarjeta suave. */
.calendar-feed-help {
  border: 1px solid var(--border-color);
  border-radius: var(--radius-btn);
  background-color: var(--bg-surface-alt);
  overflow: hidden;
}

.calendar-feed-help__summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.75rem 1rem;
  font-weight: 600;
  color: var(--text-main);
  cursor: pointer;
  /* Quita el triángulo nativo: usamos el icono de Bootstrap a la izquierda. */
  list-style: none;
}

.calendar-feed-help__summary::-webkit-details-marker {
  display: none;
}

.calendar-feed-help__summary .bi {
  color: var(--color-primary);
}

.calendar-feed-help__summary:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

.calendar-feed-help__body {
  padding: 0 1rem 1rem;
}

/* Lista de definición de las apps: nombre (negrita) + pasos. */
.calendar-feed-help__list dt {
  font-weight: 700;
  color: var(--text-main);
  margin-top: 0.5rem;
}

.calendar-feed-help__list dd {
  margin: 0.1rem 0 0;
  font-size: 0.875rem;
  /* --text-muted (#6B7280) pasa AA solo sobre superficie clara; aquí el fondo
     es --bg-surface-alt, así que usamos el color de cuerpo principal. */
  color: var(--text-main);
}

/* --------------------------------------------------------------------------
   HU-32 (UX spec §6) — Compartir un coche: acordeón, lista de colaboradores
   y badge «Compartido por X». Reutiliza tokens del sistema (Solar White v3).
   -------------------------------------------------------------------------- */

/* Acordeón «Compartir este coche»: tarjeta blanca entre la cabecera y el rail. */
.sharing-accordion {
  display: block;
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  margin-bottom: 1rem;
  overflow: hidden;
}

/* Disparador nativo (<button>): 48px de alto > 44px de área táctil. */
.sharing-accordion__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  min-height: 48px;
  padding: 0.75rem 1rem;
  background: transparent;
  border: 0;
  color: var(--text-main);
  font-size: 1rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.sharing-accordion__title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.sharing-accordion__title .bi {
  color: var(--color-primary);
}

/* Chevron a la derecha: rota 180° cuando el panel está abierto. */
.sharing-accordion__icon-right {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform 0.2s ease;
}

.sharing-accordion__toggle[aria-expanded="true"] .sharing-accordion__icon-right {
  transform: rotate(180deg);
}

.sharing-accordion__toggle:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

/* Cuerpo del acordeón: visible solo cuando el panel NO tiene [hidden]. */
.sharing-accordion__body {
  padding: 0 1rem 1rem;
  border-top: 1px solid var(--border-color);
  padding-top: 1rem;
}

/* Subtítulo de sección (mayúsculas, atenuado). --text-muted sobre blanco = AA. */
.sharing-section__subtitle {
  margin: 0 0 0.25rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.sharing-section__subtitle--list {
  margin-top: 1.5rem;
}

.sharing-section__help {
  margin: 0 0 0.75rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* Lista de colaboradores con acceso. */
.sharing-collab-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.sharing-collab-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem;
  background-color: var(--bg-surface-alt);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-btn);
}

.sharing-collab-row__info {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0; /* permite truncar el email largo */
}

.sharing-collab-row__avatar {
  flex-shrink: 0;
  font-size: 1.75rem;
  color: var(--text-muted);
}

.sharing-collab-row__name {
  margin: 0;
  font-weight: 600;
  color: var(--text-main);
}

.sharing-collab-row__email {
  margin: 0;
  font-size: 0.875rem;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sharing-collab-row__date {
  margin: 0.125rem 0 0;
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* Botón «Revocar»: outline danger, área táctil mínima. */
.sharing-collab-row__revoke {
  flex-shrink: 0;
  min-height: 44px;
}

/* Estado vacío de la lista de colaboradores. */
.sharing-collab-list__empty {
  margin: 0;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* Pill «Compartido por X»: informativa (--state-info sobre --state-info-bg =
   7.2:1, supera AA). Nunca solo color: icono + texto + aria-label. */
.badge-compartido {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem 0.625rem;
  border-radius: 9999px;
  background-color: var(--state-info-bg);
  color: var(--state-info);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Contenedores de la pill en la tarjeta de la lista y en la cabecera del detalle. */
.car-card__shared-by {
  margin: 0.5rem 0 0;
}

.car-detail-header__shared-by {
  margin: 0.5rem 0 0;
}

/* ==========================================================================
   P-27 — Panel «Mis vencimientos» (HU-44/HU-45, UX §3)
   --------------------------------------------------------------------------
   UN único DOM responsive (no se duplican IDs htmx): cada coche es una
   .tarjeta-vencimientos cuyas tres celdas (.fila-vencimiento, id
   "celda-{coche}-{tipo}") son los fragmentos que htmx intercambia por
   outerHTML. El fragmento devuelto SIEMPRE es un <div class="fila-vencimiento">
   (lo fija el backend), por eso la presentación tabular de escritorio se
   resuelve con CSS Grid sobre esos div, NO con <table>/<td> (un swap de un
   <div> dentro de una tabla rompería la estructura). La semántica accesible
   la aportan <section aria-label> y los role="group" aria-label de cada celda.
   Mobile-first: tarjetas apiladas en móvil; rejilla horizontal en >=lg.
   ========================================================================== */
.vencimientos-panel__intro {
  font-size: 0.875rem;
  color: var(--text-secundario-en-pagina);
  margin: 0 0 1rem;
}

.tarjeta-vencimientos {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  margin-bottom: 1rem;
  overflow: hidden;
}

.tarjeta-vencimientos__cabecera {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
}

.tarjeta-vencimientos__nombre {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tarjeta-vencimientos__meta {
  font-size: 0.875rem;
  color: var(--text-muted);   /* sobre --bg-surface (blanco): AA */
  flex-shrink: 0;
}

/* El enlace al detalle se empuja al extremo derecho de la cabecera. */
.tarjeta-vencimientos__enlace-detalle {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin-left: auto;
  color: var(--text-muted);
  text-decoration: none;
  flex-shrink: 0;
}

.tarjeta-vencimientos__enlace-detalle:hover {
  color: var(--color-primary);
}

.tarjeta-vencimientos__enlace-detalle:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  border-radius: var(--radius-btn);
}

/* Celda de vencimiento: en móvil es una fila apilada (tipo arriba con el
   conmutador, dato abajo). Es el contenedor que htmx intercambia. */
.fila-vencimiento {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-color);
  cursor: pointer;
  transition: background-color 0.1s ease;
}

.fila-vencimiento:last-child {
  border-bottom: none;
}

.fila-vencimiento:hover {
  background-color: var(--bg-surface-alt);
}

.fila-vencimiento:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
}

.fila-vencimiento__cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 44px;
}

.fila-vencimiento__tipo {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-main);
}

.fila-vencimiento__dato {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.fila-vencimiento__fecha {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-main);
}

.fila-vencimiento__vacia {
  font-size: 0.875rem;
  color: var(--text-muted);   /* sobre --bg-surface: AA */
}

.fila-vencimiento__dias {
  font-size: 0.75rem;
  /* Texto micro sobre la superficie blanca de la tarjeta. */
  color: var(--text-secundario-en-pagina);
}

/* En edición la fila deja de ser clicable y se eleva ligeramente. */
.fila-vencimiento--editando {
  cursor: default;
  background-color: var(--bg-surface-alt);
}

.fila-vencimiento--editando:hover {
  background-color: var(--bg-surface-alt);
}

/* htmx marca la fila en vuelo: se atenúa y bloquea más clics (evita doble
   envío del conmutador o reapertura de la edición). */
.fila-vencimiento.htmx-request {
  opacity: 0.5;
  pointer-events: none;
}

/* Conmutador 🔔/🔕: objetivo táctil 44×44, redondo, sin fondo. */
.btn-conmutador-aviso {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  min-width: 44px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 50%;
  color: var(--color-primary);
  font-size: 1.125rem;
  line-height: 1;
  transition: background-color 0.1s ease;
  flex-shrink: 0;
}

.btn-conmutador-aviso:hover {
  background-color: var(--bg-surface-alt);
}

.btn-conmutador-aviso:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.btn-conmutador-aviso--silenciado {
  color: var(--text-muted);   /* sobre --bg-surface: AA */
}

/* «+ Añadir fecha»: enlace de acción con objetivo táctil de 44px. */
.btn-anadir-fecha {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-primary);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.btn-anadir-fecha:hover {
  text-decoration: underline;
}

.btn-anadir-fecha:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-btn);
}

/* Edición inline: el input ocupa el ancho y las acciones se alinean debajo. */
.edicion-inline {
  padding-top: 0.25rem;
}

.edicion-inline .form-control {
  margin-bottom: 0.5rem;
}

.edicion-inline__acciones {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}

.edicion-inline__acciones .btn {
  min-height: 44px;
}

/* --- Escritorio (>=lg): presentación tabular ----------------------------
   La cabecera de la tarjeta (coche + matrícula + enlace) ocupa una franja y
   las tres celdas se reparten en una rejilla de 3 columnas iguales. Cada
   celda mantiene su id htmx y su role="group"; solo cambia la disposición. */
@media (min-width: 992px) {
  .tarjeta-vencimientos__cabecera {
    /* La matrícula se separa del nombre con un punto medio decorativo. */
    padding: 1rem 1.25rem;
  }

  .tarjeta-vencimientos__cuerpo {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }

  .fila-vencimiento {
    border-bottom: none;
    border-right: 1px solid var(--border-color);
    padding: 1rem 1.25rem;
    /* La fecha/badge/días quedan debajo del tipo, alineados a la izquierda. */
    justify-content: flex-start;
  }

  .fila-vencimiento:last-child {
    border-right: none;
  }

  /* La franja superior de cada columna (tipo + conmutador) se mantiene a la
     misma altura aunque una celda esté vacía y otra con badge. */
  .fila-vencimiento__cabecera {
    min-height: 44px;
  }

  .fila-vencimiento__dato {
    margin-top: 0.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .car-card:hover {
    transform: none !important;
  }
}

/* --------------------------------------------------------------------------
   ADR-019 — Recordatorios predictivos por uso (HU-47 / HU-49)
   Tratamiento visual de la ESTIMACIÓN: siempre debe leerse como aproximada,
   nunca como un vencimiento confirmado. Dos superficies:
     1) Línea secundaria en la fila de plan por km (pestaña Planes, P-06).
     2) Sección «Estimación de uso» en el detalle/edición del plan (P-10).
   Tokens v3 «Solar White». La pill «Est.» reutiliza los tokens de estado
   «Próximo» (warning ámbar, #92400E sobre #FEF3C7 → 6.7:1 AA).
   -------------------------------------------------------------------------- */

/* 1) Línea de estimación dentro de la fila de plan (cae sobre --bg-surface,
   blanco: --text-muted #6B7280 a 0.875rem cumple AA 4.6:1). Discreta, por
   debajo de la regla y el vencimiento ciertos, para que no compita con ellos. */
.plan-row__estimate {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.375rem;
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0.25rem 0 0;
}

/* Pill «Est.»: marca inequívoca de estimación. Mismos tokens que el badge
   «Próximo» para coherencia con el estado que dispara (warning ámbar). */
.plan-row__estimate-tag {
  flex: 0 0 auto;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.1875rem 0.4375rem;
  border-radius: 999px;
  background-color: var(--state-warning-bg);
  color: var(--state-warning);
}

.plan-row__estimate-text {
  min-width: 0;
}

/* El ritmo (~X km/mes) en un tono aún más leve y tamaño micro: dato de apoyo. */
.plan-row__estimate-pace {
  white-space: nowrap;
}

/* Estado sin datos (HU-49): mismo tono discreto, sin pill (no hay nada que
   estimar), con un enlace accionable a registrar una lectura. */
.plan-row__estimate--none {
  align-items: center;
}

.plan-row__estimate-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;          /* objetivo táctil WCAG 2.5.8 */
  padding: 0 0.25rem;
  font-weight: 600;
  color: var(--color-primary);   /* #C13209 sobre blanco → 5.5:1 AA */
  text-decoration: none;
}

.plan-row__estimate-link:hover {
  color: var(--color-primary-dark);
  text-decoration: underline;
}

.plan-row__estimate-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 6px;
}

/* 2) Sección «Estimación de uso» (P-10): tarjeta de superficie propia para que
   destaque del fondo de página sin competir con la zona de peligro. */
.usage-estimate {
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 1rem 1.25rem;
  margin-top: 2rem;
}

.usage-estimate__title {
  display: flex;
  align-items: center;
  gap: 0.4375rem;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 0.75rem;
}

.usage-estimate__title .bi {
  color: var(--color-primary);
  font-size: 1.125rem;
}

/* Pill «Est.» de la cabecera de la sección: misma señal que en la fila. */
.usage-estimate__tag {
  margin-left: auto;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.1875rem 0.4375rem;
  border-radius: 999px;
  background-color: var(--state-warning-bg);
  color: var(--state-warning);
}

/* Lista de hechos clave: etiqueta + valor en parejas. Una sola columna en
   móvil; el valor en 700 (jerarquía de dato del sistema de diseño). */
.usage-estimate__facts {
  margin: 0 0 0.75rem;
}

.usage-estimate__fact {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.375rem 0;
  border-bottom: 1px solid var(--border-color);
}

.usage-estimate__fact:last-child {
  border-bottom: none;
}

.usage-estimate__label {
  font-size: 0.875rem;
  color: var(--text-muted);   /* sobre --bg-surface (blanco): 4.6:1 AA */
}

.usage-estimate__value {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--text-main);
  margin: 0;
  text-align: right;
}

/* Nota de incertidumbre: cae sobre --bg-surface, así que --text-muted vale. */
.usage-estimate__note {
  font-size: 0.8125rem;
  color: var(--text-muted);
  margin: 0;
}

/* Caso ya vencido: tono de estado «Vencido» pero sutil (texto, sin fondo). */
.usage-estimate__overdue {
  font-size: 0.875rem;
  color: var(--state-danger);   /* #B91C1C sobre blanco → 6:1 AA */
  margin: 0;
}

/* Caso sin datos (HU-49): mensaje honesto + botón a registrar lectura. */
.usage-estimate__none {
  font-size: 0.875rem;
  color: var(--text-main);
  margin: 0 0 1rem;
}

.usage-estimate__action {
  width: 100%;
  min-height: 48px;
}

@media (min-width: 992px) {
  .usage-estimate__action {
    width: auto;
  }
}

/* ==========================================================================
   OSCURO — ajustes de componente que NO se resuelven solo con tokens.
   La inmensa mayoría del tema oscuro se logra redefiniendo los custom
   properties (bloque «1-OSCURO»). Aquí quedan los pocos casos en que una regla
   usa una opacidad/RGB fijos que en oscuro se perciben distinto. Se duplica el
   selector para data-theme="dark" (siempre) y para data-theme="auto" bajo
   prefers-color-scheme:dark (sigue al sistema), igual que el mapa de tokens.
   ========================================================================== */

/* Sidebar: la franja de activo sube de opacidad para verse sobre slate (la
   versión clara es rgba(.,0.07), casi invisible en oscuro). El selector base
   vive dentro de @media (min-width:992px), así que aquí también para mantener
   la especificidad de cascada. */
@media (min-width: 992px) {
  :root[data-theme="auto"] .sidebar__item--active {
    /* En auto, solo si el SISTEMA pide oscuro (ver @media de abajo). El valor
       claro por defecto (0.07) lo aporta la regla base. */
    background-color: rgba(var(--bs-primary-rgb), 0.07);
  }
}

@media (min-width: 992px) and (prefers-color-scheme: dark) {
  :root[data-theme="auto"] .sidebar__item--active {
    background-color: rgba(var(--bs-primary-rgb), 0.16);
  }
}

/* Conmutador rápido de tema (segmented de 3 opciones en el perfil + acceso
   directo en sidebar/cabecera). Reutiliza el lenguaje del selector de idioma y
   del segmented control; tokens del sistema, por lo que ya cambia con el tema.
   Solo necesita su propio layout. Mobile-first, WCAG 2.2 AA. */
.theme-quick {
  position: relative;
  flex-shrink: 0;
}

/* Disparador del menú rápido: mismo tamaño/forma que .lang-trigger (44×44). */
.theme-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 8px;
  background-color: var(--bg-surface-alt);
  border: 1.5px solid var(--border-color);
  border-radius: 8px;
  color: var(--text-main);
  cursor: pointer;
}

.theme-trigger .bi {
  font-size: 1.125rem;
  line-height: 1;
}

.theme-trigger:hover {
  background-color: var(--border-color);
}

.theme-trigger:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.theme-trigger[aria-expanded="true"] {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-primary-text);
}

/* Bottom sheet del conmutador rápido: clona el lang-offcanvas. */
.theme-offcanvas {
  height: auto;
  max-height: 70vh;
  border-radius: 16px 16px 0 0;
  border-top: 1px solid var(--border-color);
}

.theme-offcanvas .offcanvas-header {
  border-bottom: 1px solid var(--border-color);
  padding: 1rem 1rem 1rem 1.25rem;
}

.theme-offcanvas .offcanvas-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-main);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.theme-offcanvas__body {
  padding: 0.5rem 0;
  overflow-y: auto;
}

.theme-offcanvas__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.theme-offcanvas__form {
  margin: 0;
}

.theme-offcanvas__option {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 56px;
  padding: 0 1.25rem;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  color: var(--text-main);
  font-size: 1rem;
  font-weight: 400;
}

.theme-offcanvas__option:hover {
  background-color: var(--bg-surface-alt);
}

.theme-offcanvas__option:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
  position: relative;
}

.theme-offcanvas__option--active {
  color: var(--color-primary);
  font-weight: 600;
}

/* Icono guía de cada opción (sol/luna/auto): coral cuando está activa. */
.theme-offcanvas__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  flex-shrink: 0;
  font-size: 1.125rem;
  color: var(--text-muted);
}

.theme-offcanvas__option--active .theme-offcanvas__icon {
  color: var(--color-primary);
}

.theme-offcanvas__name {
  flex: 1;
}

/* Check de la opción activa, al final de la fila (como el selector de idioma). */
.theme-offcanvas__check {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  font-size: 1rem;
  color: var(--color-primary);
}

/* --- Conmutador del PERFIL: 3 botones segmentados (Claro/Oscuro/Automático) ---
   Variante de .seg-control (mismos tokens) usada DENTRO del formulario de
   preferencias. Cada opción es un <label> que envuelve un radio .visually-hidden
   (operabilidad por teclado nativa), igual patrón que .seg-tab--radio. */
.theme-segmented {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  background-color: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  overflow: hidden;
  margin: 0;
}

.theme-segmented__option {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  min-height: 64px;            /* objetivo táctil holgado (WCAG 2.5.8) */
  padding: 0.5rem 0.25rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-muted);
  cursor: pointer;
  text-align: center;
  border-right: 1px solid var(--border-color);
}

.theme-segmented__option:last-child {
  border-right: none;
}

.theme-segmented__option .bi {
  font-size: 1.25rem;
  line-height: 1;
}

.theme-segmented__option:hover {
  background-color: var(--bg-surface-alt);
  color: var(--text-main);
}

/* Estado seleccionado: relleno coral + texto sobre coral (como .seg-tab--active). */
.theme-segmented__option--active {
  background-color: var(--color-primary);
  color: var(--color-primary-text);
  font-weight: 600;
}

.theme-segmented__option--active:hover {
  background-color: var(--color-primary-dark);
  color: var(--color-primary-text);
}

/* Foco visible sobre la opción cuando su radio interno lo recibe (WCAG 2.4.7). */
.theme-segmented__option:has(input:focus-visible) {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
}

.theme-segmented__option:focus-within {
  outline: 3px solid var(--color-primary);
  outline-offset: -3px;
  z-index: 1;
}

/* --------------------------------------------------------------------------
   38. P-08 — Adjuntos del mantenimiento (HU-51..HU-55, ADR-020)
   Spec backend funcional; aquí el estilado, miniaturas, modal e i18n.
   Sistema de diseño v3 «Solar White» + tema oscuro «Midnight Garage»: TODO por
   tokens, así que claro y oscuro funcionan sin reglas duplicadas. Contraste AA;
   objetivos táctiles ≥ 44px (WCAG 2.5.8).
   -------------------------------------------------------------------------- */

/* --- Control de subida: caja discreta con la microcopy de límites --------- */
/* Vive dentro del formulario de alta/edición (.attachments-upload es un
   <fieldset class="form-section">; el reset de fieldset ya lo da .form-section).
   La caja agrupa visualmente la ayuda + tipo + archivos. */
.attachments-upload__box {
  background-color: var(--bg-surface-alt);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-card);
  padding: 1rem;
}

/* Microcopy de límites: cae sobre --bg-surface-alt (claro #F8F9FB / oscuro
   #222C38). --text-muted pasa AA sobre ambas superficies de superficie-alt. */
.attachments-upload__hint {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-muted);
  margin: 0 0 0.75rem;
}

.attachments-upload__hint .bi {
  color: var(--color-primary);
  font-size: 1rem;
  line-height: 1.45;
  flex-shrink: 0;
}

/* --- Lista de adjuntos existentes (en edición) ---------------------------- */
.attachment-list {
  border-top: 1px solid var(--border-color);
}

/* Cada adjunto: miniatura/icono + cuerpo (nombre, tipo, fecha) + acciones.
   Mobile-first: las acciones bajan a una segunda línea a la derecha. */
.attachment-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border-color);
}

/* Miniatura (imágenes) o icono (PDF/otros): cuadrado de 56px, enlace que abre
   el servido protegido en pestaña nueva. Es un objetivo táctil de 56×56. */
.attachment-item__media {
  flex-shrink: 0;
  display: block;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-btn);
  overflow: hidden;
  text-decoration: none;
}

.attachment-item__media:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

.attachment-item__thumb {
  width: 56px;
  height: 56px;
  object-fit: cover;
  object-position: center;
  display: block;
  background-color: var(--bg-surface-alt);
  /* Marco interno por tema (hilo oscuro en claro, claro en oscuro): despega la
     miniatura del fondo de la tarjeta sin alterar su tamaño. */
  box-shadow: var(--shadow-photo-inset);
}

/* Icono de fichero (PDF / otro) dentro del mismo cuadro de 56px. */
.attachment-item__icon {
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--bg-surface-alt);
  color: var(--text-muted);
  box-shadow: var(--shadow-photo-inset);
}

.attachment-item__icon .bi {
  font-size: 28px;
  line-height: 1;
}

/* El PDF se distingue con el coral del sistema (igual que los iconos de la
   pestaña Documentos). En oscuro el coral se aclara solo (token). */
.attachment-item__icon--pdf {
  color: var(--color-primary);
}

/* Cuerpo: nombre (puede partir) + meta (tipo · fecha). min-width:0 permite el
   recorte del nombre largo dentro del flex. */
.attachment-item__body {
  flex: 1 1 12rem;
  min-width: 0;
}

.attachment-item__name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-main);
  word-break: break-word;
}

/* El nombre es también enlace al servido protegido (además de la miniatura). */
.attachment-item__name-link {
  color: inherit;
  text-decoration: none;
}

.attachment-item__name-link:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

.attachment-item__name-link:focus-visible {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: 2px;
}

.attachment-item__meta {
  font-size: 0.8125rem;
  color: var(--text-muted);
  margin-top: 0.125rem;
}

.attachment-item__sep {
  margin: 0 0.25rem;
}

/* Acciones «Ver» / «Eliminar»: a la derecha, objetivo táctil 44px. En móvil
   estrecho la fila envuelve y las acciones ocupan el ancho disponible. */
.attachment-item__actions {
  display: flex;
  gap: 0.5rem;
  margin-left: auto;
  flex-shrink: 0;
}

.attachment-item__actions .btn {
  min-height: 44px;
  font-size: 0.875rem;
  padding: 0.375rem 0.75rem;
}

.attachment-item__actions .btn .bi {
  font-size: 1rem;
}

/* Estado vacío discreto: clip + texto sobre --bg-page (gris-azul AA). */
.attachments-empty {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--text-secundario-en-pagina);
  margin: 0;
}

.attachments-empty .bi {
  font-size: 1rem;
}

/* --- Indicador «tiene adjuntos» en las filas del historial (HU-55) -------- */
/* Píldora discreta: clip + número. Cae dentro de .maintenance-row (superficie
   blanca / slate); --text-muted pasa AA sobre ambas. El número es decorativo
   para AT (el nombre accesible lo da el aria-label de .attachment-chip). */
.history-row__attachments {
  margin-top: 0.25rem;
}

.attachment-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-muted);
}

.attachment-chip .bi {
  font-size: 0.875rem;
  line-height: 1;
}
