/* Estilos auxiliares del dashboard municipal */
/* Paleta alineada con la app mobile (constants/colors.ts):
   brand  → primary  #1F3A5F (azul oscuro)
   accent → secondary #3BA99C (verde jade)
*/

/* ─────────────────────────────────────────────────────────────
   Tokens de diseño + estilos globales.
   Movidos desde el <style> inline de base.html para habilitar una CSP
   sin 'unsafe-inline' en style-src. Los tokens (--ink-*, --brand*,
   --shadow-*) viven acá y los consumen tanto este archivo como los
   atributos style="..." de los templates.
   ───────────────────────────────────────────────────────────── */
:root {
    --ink-900:#0B1C3D; --ink-800:#12284C; --ink-700:#1E3A66;
    --ink-600:#2E4E82; --ink-500:#546A8C; --ink-400:#8A99B3;
    --ink-300:#B9C3D4; --ink-200:#DCE2ED; --ink-100:#EEF1F6;
    --ink-50:#F6F8FB;
    --brand:#14B8A6; --brand-dark:#0E8F80;
    --brand-soft:#CFF4EF; --brand-tint:#E9FAF7;
    --accent:#6366F1; --accent-soft:#E4E6FD; --accent-tint:#F0F1FE;
    --ok:#10B981; --ok-soft:#D6F5E6;
    --warn:#F59E0B; --warn-soft:#FDECCF;
    --err:#EF4444; --err-soft:#FBDADA;
    --violet:#8B5CF6; --violet-soft:#EADEFB;
    --shadow-sm:0 1px 2px rgba(11,28,61,.06),0 1px 4px rgba(11,28,61,.04);
    --shadow-md:0 4px 16px rgba(11,28,61,.08),0 2px 6px rgba(11,28,61,.04);
    --shadow-lg:0 20px 50px rgba(11,28,61,.15),0 8px 20px rgba(11,28,61,.08);
    --shadow-brand:0 10px 30px rgba(20,184,166,.35);

    /* Controles de filtro de los mapas (paneles de heatmap.html y
       works/map.html). Los aplica alpine-components.js con :style, o sea
       por CSSOM, y un estilo en el elemento le gana a cualquier utilidad:
       por eso viven como tokens, para poder repintarlos en modo oscuro
       sin tocar el JS. Estos son los valores de siempre (tema claro). */
    --fx-on-bg:#0B1C3D;      --fx-on-fg:#fff;
    --fx-off-bg:#F6F8FB;     --fx-off-fg:#2E4E82;   --fx-off-bd:#DCE2ED;
    --fx-sel-bg:#E9FAF7;     --fx-sel-fg:#0E8F80;
    --fx-idle-fg:#1E3A66;
    --fx-neutro-bg:#EEF1F6;  --fx-neutro-fg:#2E4E82;
    --fx-alta-bg:#FFF7ED;    --fx-alta-fg:#C2410C;
    --fx-media-bg:#FFFBEB;   --fx-media-fg:#B45309;
    --fx-baja-bg:#F8FAFC;    --fx-baja-fg:#475569;
    --fx-lista-on-bg:#F6F8FB;--fx-lista-on-fg:#0B1C3D;
    --fx-lista-off-fg:#8A99B3;
    --fx-atraso-bg:#FBDADA;  --fx-atraso-fg:#B91C1C;
}
body { font-family:'Inter',system-ui,sans-serif; }
.htmx-indicator { opacity:0; transition:opacity 200ms ease-in; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity:1; }
::-webkit-scrollbar { width:6px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--ink-300); border-radius:3px; }
[x-cloak] { display:none !important; }
@keyframes toast-in  { from{transform:translateX(100%);opacity:0} to{transform:translateX(0);opacity:1} }
@keyframes toast-out { from{transform:translateX(0);opacity:1} to{transform:translateX(100%);opacity:0} }
.toast-enter { animation:toast-in .3s ease-out; }
.toast-exit  { animation:toast-out .3s ease-in forwards; }
/* Indicador activo del sidebar */
.nav-active {
    background:linear-gradient(90deg,rgba(20,184,166,.18) 0%,rgba(20,184,166,0) 100%);
    color:#fff !important;
}
.nav-active::before {
    content:''; position:absolute;
    left:0; top:6px; bottom:6px;
    width:3px; border-radius:0 4px 4px 0;
    background:var(--brand);
}
/* Ícono del item activo en teal (antes era un style inline condicional). */
.nav-active i { color:var(--brand); }
/* Skip-to-content */
.skip-link {
    position:absolute; top:-99px; left:8px;
    background:var(--brand); color:#fff;
    padding:8px 14px; border-radius:0 0 8px 8px;
    font-size:13px; font-weight:600; z-index:9999;
}
.skip-link:focus { top:0; outline:2px solid var(--brand-dark); }
/* Focus visible */
*:focus-visible { outline:2px solid var(--brand); outline-offset:2px; }

/* ─────────────────────────────────────────────────────────────
   Calendario de actividad del mes (Overview)
   Diseño compacto: cada celda es pequeña; el único énfasis visual
   dentro de la grilla es el día de hoy.
   ───────────────────────────────────────────────────────────── */
.activity-wrap {
    display: flex;
    flex-direction: column;
    gap: 12px;
    /* Encapsula tanto las stats como la grilla del calendario bajo un
       mismo ancho máximo para que ambos bloques alineen horizontalmente. */
    max-width: 400px;
    margin: 0 auto;
    width: 100%;
}

.activity-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.a-stat {
    background: var(--ink-50);
    border: 1px solid var(--ink-100);
    border-radius: 10px;
    padding: 8px 10px;
}
.a-stat .lbl {
    font-size: 9px;
    text-transform: uppercase;
    color: var(--ink-400);
    font-weight: 700;
    letter-spacing: .4px;
    margin-bottom: 3px;
}
.a-stat .val {
    font-family: 'Inter', sans-serif;
    font-size: 15px;
    font-weight: 800;
    color: var(--ink-900);
    letter-spacing: -.2px;
    line-height: 1.2;
}
.a-stat .meta {
    font-size: 10px;
    color: var(--ink-500);
    margin-top: 1px;
}
.a-stat.hot  .val { color: var(--err); }
.a-stat.cool .val { color: var(--brand-dark); }

.heatcal-month {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* Hereda el ancho del ``.activity-wrap`` que ya acota a 400px. */
}
.heatcal-weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
    font-size: 9px;
    font-weight: 700;
    color: var(--ink-400);
    text-align: center;
    text-transform: uppercase;
    letter-spacing: .4px;
}
.heatcal-grid-month {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}

.heatcal-cell {
    aspect-ratio: 1;
    border-radius: 6px;
    background: var(--ink-100);
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 600;
    color: var(--ink-600);
    text-decoration: none;
    transition: transform .15s, box-shadow .15s;
}
a.heatcal-cell { cursor: pointer; }
a.heatcal-cell:hover {
    transform: scale(1.08);
    box-shadow: var(--shadow-md);
    z-index: 2;
}
.heatcal-cell .d {
    font-family: 'Inter', sans-serif;
    line-height: 1;
    pointer-events: none;
}

/* Escala de intensidad (cuantiles sobre días con datos). */
.heatcal-cell.l0 { background: var(--ink-100); color: var(--ink-500); }
.heatcal-cell.l1 { background: var(--brand-soft); color: var(--brand-dark); }
.heatcal-cell.l2 { background: #7DD9CC; color: var(--ink-900); }
.heatcal-cell.l3 { background: var(--brand); color: #fff; }
.heatcal-cell.l4 { background: var(--brand-dark); color: #fff; }
.heatcal-cell.l5 { background: #08665B; color: #fff; }

/* Relleno (antes del día 1 o después del último) — no visible. */
.heatcal-cell.empty {
    background: transparent;
    pointer-events: none;
}
/* Días futuros del mes — visibles pero atenuados y no clickeables. */
.heatcal-cell.future {
    background: var(--ink-50);
    color: var(--ink-300);
    border: 1px dashed var(--ink-200);
    pointer-events: none;
}
/* Hoy: único énfasis dentro de la grilla. Doble anillo (blanco fino interior +
   teal exterior) para que sea visible sobre cualquier nivel de intensidad
   (incluido ``l3``/``l5`` que ya tienen fondo teal). */
.heatcal-cell.today {
    box-shadow: 0 0 0 1px #fff, 0 0 0 3px var(--brand);
    font-weight: 800;
    z-index: 3;
}

.heatcal-legend {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    font-size: 10px;
    color: var(--ink-500);
    margin-top: 2px;
    gap: 12px;
    flex-wrap: wrap;
}
.heatcal-legend .scale {
    display: flex;
    align-items: center;
    gap: 3px;
    margin-left: auto;
}
.heatcal-legend .scale .lbl {
    font-size: 9px;
    color: var(--ink-400);
    margin: 0 4px;
}
.heatcal-legend .scale .sw {
    width: 10px;
    height: 10px;
    border-radius: 2px;
}

/* ─────────────────────────────────────────────────────────────
   Banner de filtro por día en la lista de denuncias
   ───────────────────────────────────────────────────────────── */
.day-filter-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-radius: 12px;
    background: var(--brand-tint);
    color: var(--brand-dark);
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 16px;
}
.day-filter-banner i { width: 14px; height: 14px; }
.day-filter-banner a {
    margin-left: auto;
    color: var(--brand-dark);
    font-weight: 700;
    text-decoration: underline;
}

/* ─────────────────────────────────────────────────────────────
   Mapa de calor (heatmap.html)
   Movido desde el <style> inline para habilitar CSP sin unsafe-inline.
   ───────────────────────────────────────────────────────────── */
/* Altura explícita para el contenedor del mapa */
.heatmap-shell {
    height: calc(100vh - 130px);
    min-height: 560px;
}
#heatmap { width: 100%; height: 100%; }
/* Deshabilitar visualmente filas de categoría cuando "Todas" está activo */
.cat-row-disabled { opacity: 0.4; pointer-events: none; }
/* Asegurar que Leaflet se vea por encima de overlays */
.leaflet-container { z-index: 1; background: var(--ink-50); }

/* ─────────────────────────────────────────────────────────────
   Mapa de obras (works/map.html)
   Los marcadores son L.divIcon y su clase se arma por concatenación
   en JS ('work-pin--' + status). Por eso estas clases viven acá y NO
   en Tailwind: el purge no ve nombres construidos en runtime, así que
   los marcadores saldrían sin color y sin ningún mensaje de error.
   El color de cada estado se declara UNA sola vez, en --pin, y lo
   consumen tanto el marcador del mapa como el punto de la leyenda:
   así no pueden divergir.
   ───────────────────────────────────────────────────────────── */
/* El alto lo fija la pagina y el mapa toma lo que sobra bajo el conmutador de
   vista: asi no hay que restar a mano la altura del conmutador. */
.works-map-page  { height: calc(100vh - 130px); min-height: 620px; }
.works-map-shell { flex: 1 1 auto; min-height: 0; }
#works-map { width: 100%; height: 100%; }

.work-pin--planned,     .work-dot--planned     { --pin: var(--ink-500); } /* neutro frío: todavía no pasó nada */
.work-pin--in_progress, .work-dot--in_progress { --pin: var(--accent);  } /* acento: es lo que se busca primero */
.work-pin--paused,      .work-dot--paused      { --pin: var(--warn);    } /* ámbar: señal de atención */
.work-pin--completed,   .work-dot--completed   { --pin: var(--ok);      } /* el mismo verde ok del dashboard */
.work-pin--cancelled,   .work-dot--cancelled   { --pin: var(--ink-300); } /* gris apagado, presente sin peso */

.work-pin {
    box-sizing: border-box;
    width: 22px; height: 22px;
    border-radius: 9999px;
    border: 2px solid #fff;
    background: var(--pin, var(--ink-400));
    box-shadow: 0 1px 3px rgba(11, 28, 61, .35);
}
.work-pin--cancelled { opacity: .8; }
/* Atrasada: un anillo que se SUMA al color del estado en vez de reemplazarlo.
   Una obra puede estar en ejecución Y atrasada, y ésa es la que hay que ver. */
.work-pin--delayed {
    box-shadow: 0 0 0 3px var(--err), 0 1px 3px rgba(11, 28, 61, .35);
}

/* Punto de color de los toggles del sidebar, que hacen de leyenda. */
.work-dot {
    width: 10px; height: 10px;
    border-radius: 9999px;
    flex-shrink: 0;
    background: var(--pin, var(--ink-400));
}
.work-dot--delayed { background: transparent; box-shadow: 0 0 0 2px var(--err) inset; }

/* ─────────────────────────────────────────────────────────────
   Pills de filtro (complaint_list.html)
   Movido desde el <style> inline para habilitar CSP sin unsafe-inline.
   ───────────────────────────────────────────────────────────── */
.pill { padding:.375rem .75rem; border-radius:9999px; font-size:.75rem; font-weight:600; transition:all .18s ease; cursor:pointer; border:0 }
.pill[data-v="all"]         { background:var(--ink-100);  color:var(--ink-600) }
.pill[data-v="all"].on      { background:var(--ink-900);  color:#fff }
.pill[data-v="submitted"]   { background:#EFF6FF;         color:#1D4ED8 }
.pill[data-v="submitted"].on{ background:#1D4ED8;         color:#fff }
.pill[data-v="in_review"]   { background:#FFFBEB;         color:#B45309 }
.pill[data-v="in_review"].on{ background:#B45309;         color:#fff }
.pill[data-v="in_progress"]   { background:#F5F3FF;       color:#5B21B6 }
.pill[data-v="in_progress"].on{ background:#5B21B6;       color:#fff }
.pill[data-v="resolved"]    { background:#ECFDF5;         color:#047857 }
.pill[data-v="resolved"].on { background:#047857;         color:#fff }
.pill[data-v="rejected"]    { background:#FEF2F2;         color:#B91C1C }
.pill[data-v="rejected"].on { background:#B91C1C;         color:#fff }
.pill[data-v="high"]        { background:#FFF7ED;         color:#C2410C }
.pill[data-v="high"].on     { background:#C2410C;         color:#fff }
.pill[data-v="medium"]      { background:#FFFBEB;         color:#B45309 }
.pill[data-v="medium"].on   { background:#B45309;         color:#fff }
.pill[data-v="low"]         { background:#F8FAFC;         color:#475569 }
.pill[data-v="low"].on      { background:#475569;         color:#fff }
.pill[data-v="urgent"]      { background:#FEF2F2;         color:#B91C1C }
.pill[data-v="urgent"].on   { background:#B91C1C;         color:#fff }
/* Categorías: tonos azules (no verdes) para mantener la familia cromática del navy base. */
.pill[data-v="brand"]       { background:#DBEAFE; color:#1E40AF }
.pill[data-v="brand"].on    { background:#1E40AF; color:#fff }
.pill.on { box-shadow:0 1px 2px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04) }

/* ─────────────────────────────────────────────────────────────
   Focus / hover declarativos (reemplazan handlers inline on*).
   El anillo de focus se hace con box-shadow (no pelea con el
   border inline de los inputs) para no necesitar !important.
   ───────────────────────────────────────────────────────────── */
.focus-ring:focus {
    outline: none;
    box-shadow: 0 0 0 1px var(--brand), 0 0 0 3px rgba(20, 184, 166, .2);
}

/* Fila clickeable de la tabla de denuncias (antes onmouseover/out). */
.row-hover { transition: background-color .15s; }
.row-hover:hover { background: var(--ink-50); }

/* Botón primario del login (antes onmouseover/out + background inline). */
.btn-auth {
    background: #14B8A6;
    box-shadow: 0 10px 30px rgba(20, 184, 166, .3);
}
.btn-auth:hover { background: #0E8F80; }
/* Estado del botón mientras el envío está en curso (guarda de doble submit). */
.btn-auth:disabled { opacity: .6; cursor: not-allowed; box-shadow: none; }
.btn-auth:disabled:hover { background: #14B8A6; }

/* Ítems del panel de notificaciones (antes onmouseover/out + background inline). */
.notif-item { background: #fff; transition: background-color .15s; }
.notif-item:hover { background: var(--ink-50); }
.notif-item.unread { background: var(--ink-200); }
.notif-item.unread:hover { background: var(--ink-300); }

/* ─────────────────────────────────────────────────────────────
   Clases componente (Fase 4): reemplazan atributos style="..." inline
   multi-propiedad, gradientes y glass que no mapean a una sola utilidad
   Tailwind. Habilitan quitar 'unsafe-inline' de style-src.
   ───────────────────────────────────────────────────────────── */
/* Card base: usada en decenas de paneles (antes el style más repetido). */
.card { box-shadow: var(--shadow-sm); border: 1px solid var(--ink-100); }

/* Gradientes de marca. */
.grad-sidebar { background: linear-gradient(180deg, #0B1C3D 0%, #0A1932 100%); }
.grad-brand   { background: linear-gradient(135deg, var(--brand) 0%, var(--accent) 100%); box-shadow: var(--shadow-brand); }
.grad-avatar  { background: linear-gradient(135deg, var(--accent) 0%, var(--violet) 100%); }
.grad-heat-legend { background: linear-gradient(90deg, #3BA99C 0%, #F59E0B 50%, #991b1b 100%); }

/* Superficies "glass" (blur + fondo translúcido). */
.glass     { background: rgba(255, 255, 255, .9); backdrop-filter: blur(12px); box-shadow: var(--shadow-sm); }
.glass-88  { background: rgba(255, 255, 255, .88); backdrop-filter: blur(12px); box-shadow: var(--shadow-sm); }
.topbar    { background: rgba(230, 238, 248, .92); backdrop-filter: blur(12px); border-bottom: 1px solid var(--ink-200); }
.loading-veil { background: rgba(230, 238, 248, .7); backdrop-filter: blur(4px); }

/* Chips / tarjetas sobre el sidebar navy (texto blanco translúcido). */
.usercard  { background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .08); }
.chip-navy { background: rgba(255, 255, 255, .12); color: rgba(255, 255, 255, .88); border: 1px solid rgba(255, 255, 255, .2); }

/* Popover de notificaciones y dropdowns sobre fondo claro. */
.popover   { background: #fff; box-shadow: var(--shadow-lg); border: 1px solid var(--ink-200); }

/* Popup del marcador de obra. El popup lo inyecta el JS por innerHTML, y la CSP
   estricta bloquea el atributo style incluso ahí, así que nada de inline. */
.work-popup { min-width: 200px; font-family: 'Inter', system-ui, sans-serif; }
.work-popup__title { display: block; font-size: 13px; font-weight: 600; color: var(--ink-900); }
.work-popup__meta { display: block; margin-top: 2px; font-size: 11px; color: var(--ink-500); }
.work-popup__delayed {
    display: inline-block; margin-top: 5px;
    padding: 1px 7px; border-radius: 9999px;
    font-size: 10px; font-weight: 600;
    background: var(--err-soft); color: #B91C1C;
}
.work-popup__link {
    display: inline-block; margin-top: 6px;
    font-size: 12px; font-weight: 600;
    color: var(--brand-dark); text-decoration: underline;
}

/* ─────────────────────────────────────────────────────────────
   Logo oficial de TerritoryOS (ícono squircle, el mismo de la app
   móvil: branding/territoryos/b-acento/icon.svg). El SVG ya trae el
   fondo navy redondeado, así que acá solo va tamaño y un anillo sutil
   para despegarlo del sidebar, que también es navy.
   ───────────────────────────────────────────────────────────── */
.brand-icon {
    width: 36px; height: 36px; flex-shrink: 0;
    border-radius: 10px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .14), 0 6px 16px rgba(0, 0, 0, .35);
}
.brand-icon-lg {
    width: 60px; height: 60px;
    border-radius: 15px;
    box-shadow: 0 10px 26px rgba(11, 28, 61, .28);
}

/* ─────────────────────────────────────────────────────────────
   Conmutador de tema (theme.js). El ícono visible depende del tema:
   luna en claro (invita a oscurecer), sol en oscuro. Lucide conserva
   las clases del <i> al reemplazarlo por <svg>.
   ───────────────────────────────────────────────────────────── */
.theme-icon-sun { display: none; }
[data-theme="dark"] .theme-icon-sun { display: block; }
[data-theme="dark"] .theme-icon-moon { display: none; }

/* Variante flotante para el login (no hay topbar). */
.theme-toggle-floating {
    position: fixed; top: 18px; right: 18px; z-index: 20;
    width: 40px; height: 40px;
    display: grid; place-items: center;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, .18);
    background: rgba(255, 255, 255, .10);
    color: #fff;
    cursor: pointer;
    transition: background-color .15s;
}
.theme-toggle-floating:hover { background: rgba(255, 255, 255, .18); }

/* ─────────────────────────────────────────────────────────────
   MODO OSCURO
   Activado por data-theme="dark" en <html> (theme.js). Reutiliza la
   paleta navy de Wirkraft/TerritoryOS: el fondo baja a un navy
   profundo y las superficies blancas pasan a navy medio; el teal de
   marca, los estados (ok/warn/err) y los pills de color se mantienen.

   Este archivo se carga DESPUÉS de tailwind.css, así que los
   selectores [data-theme="dark"] .clase ganan por especificidad a
   las utilidades sin necesidad de recompilar Tailwind ni de tocar
   los templates existentes.
   ───────────────────────────────────────────────────────────── */
html[data-theme="dark"] {
    color-scheme: dark;
    --dk-bg:        #0D1B2E;   /* fondo de página (entre navy-deep #0F2233 e ink-900) */
    --dk-surface:   #13263F;   /* tarjetas, paneles, popovers */
    --dk-surface-2: #1A3150;   /* hover, fondos neutros, inputs */
    --dk-surface-3: #24395A;   /* bordes, separadores, chips neutros */
    --dk-text:      #E6EEF8;   /* texto principal */
    --dk-text-2:    #B9C3D4;   /* texto secundario */
    --dk-muted:     #8A99B3;   /* texto atenuado, labels */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .25), 0 1px 4px rgba(0, 0, 0, .18);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, .35), 0 2px 6px rgba(0, 0, 0, .2);
    --shadow-lg: 0 20px 50px rgba(0, 0, 0, .5), 0 8px 20px rgba(0, 0, 0, .3);
}

/* Fondo y texto base */
[data-theme="dark"] body,
[data-theme="dark"] .bg-\[\#E6EEF8\],
[data-theme="dark"] .bg-\[\#1F3A5F\] {
    background-color: var(--dk-bg);
    color: var(--dk-text);
}
[data-theme="dark"] ::-webkit-scrollbar-thumb { background: var(--dk-surface-3); }

/* Superficies */
[data-theme="dark"] .bg-white { background-color: var(--dk-surface); }
[data-theme="dark"] .bg-ink-50,
[data-theme="dark"] .bg-ink-100,
[data-theme="dark"] .bg-gray-50,
[data-theme="dark"] .bg-gray-100,
[data-theme="dark"] .bg-slate-50 { background-color: var(--dk-surface-2); }
[data-theme="dark"] .bg-ink-200,
[data-theme="dark"] .bg-ink-300,
[data-theme="dark"] .bg-slate-300 { background-color: var(--dk-surface-3); }
[data-theme="dark"] .hover\:bg-ink-50:hover,
[data-theme="dark"] .hover\:bg-ink-100:hover,
[data-theme="dark"] .hover\:bg-gray-50:hover,
[data-theme="dark"] .hover\:bg-gray-100:hover { background-color: var(--dk-surface-2); }
[data-theme="dark"] .hover\:bg-ink-200:hover { background-color: var(--dk-surface-3); }
[data-theme="dark"] .bg-brand-tint,
[data-theme="dark"] .bg-brand-soft { background-color: rgba(20, 184, 166, .14); }
[data-theme="dark"] .bg-accent-tint,
[data-theme="dark"] .bg-accent-soft { background-color: rgba(99, 102, 241, .18); }
[data-theme="dark"] .shadow-\[0_0_0_2px_\#fff\] { box-shadow: 0 0 0 2px var(--dk-surface); }

/* Texto */
[data-theme="dark"] .text-ink-900,
[data-theme="dark"] .text-ink-800,
[data-theme="dark"] .text-gray-900 { color: var(--dk-text); }
[data-theme="dark"] .text-ink-700,
[data-theme="dark"] .text-ink-600,
[data-theme="dark"] .text-gray-600,
[data-theme="dark"] .text-slate-700,
[data-theme="dark"] .text-slate-600 { color: #CBD5E3; }
[data-theme="dark"] .text-ink-500,
[data-theme="dark"] .text-gray-500 { color: var(--dk-text-2); }
[data-theme="dark"] .text-ink-400,
[data-theme="dark"] .text-ink-300,
[data-theme="dark"] .text-gray-400 { color: var(--dk-muted); }
[data-theme="dark"] .hover\:text-gray-600:hover { color: var(--dk-text); }

/* Bordes y separadores */
[data-theme="dark"] .border-ink-100,
[data-theme="dark"] .border-ink-200,
[data-theme="dark"] .border-ink-300,
[data-theme="dark"] .border-gray-200,
[data-theme="dark"] .border-gray-300 { border-color: var(--dk-surface-3); }
[data-theme="dark"] .divide-ink-100 > :not([hidden]) ~ :not([hidden]),
[data-theme="dark"] .divide-ink-200 > :not([hidden]) ~ :not([hidden]),
[data-theme="dark"] .divide-gray-100 > :not([hidden]) ~ :not([hidden]),
[data-theme="dark"] .divide-gray-200 > :not([hidden]) ~ :not([hidden]) { border-color: var(--dk-surface-3); }

/* Componentes propios */
[data-theme="dark"] .card { border-color: var(--dk-surface-3); box-shadow: var(--shadow-sm); }
[data-theme="dark"] .grad-sidebar { background: linear-gradient(180deg, #08152A 0%, #060F20 100%); }
[data-theme="dark"] .topbar { background: rgba(13, 27, 46, .92); border-bottom-color: var(--dk-surface-3); }
[data-theme="dark"] .loading-veil { background: rgba(13, 27, 46, .7); }
[data-theme="dark"] .glass,
[data-theme="dark"] .glass-88 { background: rgba(19, 38, 63, .92); }
[data-theme="dark"] .popover { background: var(--dk-surface); border-color: var(--dk-surface-3); }
[data-theme="dark"] .notif-item { background: var(--dk-surface); }
[data-theme="dark"] .notif-item:hover { background: var(--dk-surface-2); }
[data-theme="dark"] .notif-item.unread { background: #1C3557; }
[data-theme="dark"] .notif-item.unread:hover { background: #244268; }
[data-theme="dark"] .row-hover:hover { background: var(--dk-surface-2); }
[data-theme="dark"] .day-filter-banner { background: rgba(20, 184, 166, .14); color: #7DD9CC; }
[data-theme="dark"] .day-filter-banner a { color: #7DD9CC; }
[data-theme="dark"] .focus-ring:focus { box-shadow: 0 0 0 1px var(--brand), 0 0 0 3px rgba(20, 184, 166, .3); }
[data-theme="dark"] .theme-toggle-floating { border-color: var(--dk-surface-3); background: var(--dk-surface); color: var(--dk-text); }
[data-theme="dark"] .theme-toggle-floating:hover { background: var(--dk-surface-2); }

/* Pills neutros (los de color conservan su semántica) */
[data-theme="dark"] .pill[data-v="all"] { background: var(--dk-surface-3); color: #CBD5E3; }
[data-theme="dark"] .pill[data-v="all"].on { background: var(--dk-text); color: var(--ink-900); }

/* Calendario de actividad (overview) */
[data-theme="dark"] .a-stat { background: var(--dk-surface-2); border-color: var(--dk-surface-3); }
[data-theme="dark"] .a-stat .val { color: var(--dk-text); }
[data-theme="dark"] .a-stat .meta { color: var(--dk-text-2); }
[data-theme="dark"] .a-stat.cool .val { color: var(--brand); }
[data-theme="dark"] .heatcal-cell,
[data-theme="dark"] .heatcal-cell.l0 { background: var(--dk-surface-2); color: var(--dk-text-2); }
[data-theme="dark"] .heatcal-cell.l1 { background: rgba(20, 184, 166, .22); color: #7DD9CC; }
[data-theme="dark"] .heatcal-cell.future { background: transparent; color: var(--dk-surface-3); border-color: var(--dk-surface-3); }
[data-theme="dark"] .heatcal-cell.today { box-shadow: 0 0 0 1px var(--dk-surface), 0 0 0 3px var(--brand); }

/* Mapas (Leaflet): fondo del contenedor mientras cargan los tiles */
[data-theme="dark"] .leaflet-container { background: var(--dk-surface-2); }
[data-theme="dark"] .work-pin { border-color: var(--dk-surface); }

/* Formularios: inputs, selects y textareas nativos */
[data-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
[data-theme="dark"] select,
[data-theme="dark"] textarea {
    background-color: var(--dk-surface-2);
    color: var(--dk-text);
    border-color: var(--dk-surface-3);
}
[data-theme="dark"] input::placeholder,
[data-theme="dark"] textarea::placeholder { color: var(--dk-muted); }

/* ── Segunda pasada del QA en oscuro ──────────────────────────────────
   Todo lo de acá salió de recorrer las 25 pantallas del panel con el
   tema oscuro puesto y medir, sobre el DOM renderizado, qué superficies
   seguían claras y qué texto quedaba por debajo de AA. Cada bloque dice
   qué pantalla lo disparó.
   ───────────────────────────────────────────────────────────────────── */

/* Aro de fondo del donut de "Por categoría" (overview.html lo pinta con
   stroke="var(--ink-100)", un atributo SVG que ninguna utilidad alcanza).
   --ink-100 sólo se usa como superficie clara, así que repintarlo acá es
   seguro: sus otros consumidores ya tienen regla propia más abajo. */
html[data-theme="dark"] { --ink-100: #1A3150; }

/* ── Chips de estado que emiten los template tags ─────────────────────
   dashboard_tags.py y works_tags.py arman los badges con la familia
   `bg-<color>-50 text-<color>-700 ring-<color>-200`. En claro son
   pasteles; sobre el navy quedaban como recortes de papel blanco. Pasan
   a ser tintes translúcidos del MISMO tono: la semántica del color se
   conserva, el brillo baja al de la escala oscura. */
[data-theme="dark"] .bg-blue-50    { background-color: rgba(59, 130, 246, .16); }
[data-theme="dark"] .bg-amber-50   { background-color: rgba(245, 158, 11, .16); }
[data-theme="dark"] .bg-orange-50  { background-color: rgba(249, 115, 22, .16); }
[data-theme="dark"] .bg-emerald-50 { background-color: rgba(16, 185, 129, .16); }
[data-theme="dark"] .bg-teal-50    { background-color: rgba(20, 184, 166, .16); }
[data-theme="dark"] .bg-cyan-50    { background-color: rgba(6, 182, 212, .16); }
[data-theme="dark"] .bg-indigo-50  { background-color: rgba(99, 102, 241, .18); }
[data-theme="dark"] .bg-violet-50  { background-color: rgba(139, 92, 246, .18); }
[data-theme="dark"] .bg-red-50     { background-color: rgba(239, 68, 68, .16); }
[data-theme="dark"] .bg-amber-100  { background-color: rgba(245, 158, 11, .20); }
[data-theme="dark"] .bg-emerald-100{ background-color: rgba(16, 185, 129, .20); }
[data-theme="dark"] .hover\:bg-red-50:hover  { background-color: rgba(239, 68, 68, .20); }
[data-theme="dark"] .hover\:bg-red-100:hover { background-color: rgba(239, 68, 68, .26); }

[data-theme="dark"] .text-blue-700    { color: #93C5FD; }
[data-theme="dark"] .text-amber-700,
[data-theme="dark"] .text-amber-800   { color: #FCD34D; }
[data-theme="dark"] .text-orange-700  { color: #FDBA74; }
[data-theme="dark"] .text-emerald-700,
[data-theme="dark"] .text-emerald-800 { color: #6EE7B7; }
[data-theme="dark"] .text-teal-700    { color: #5EEAD4; }
[data-theme="dark"] .text-cyan-700    { color: #67E8F9; }
[data-theme="dark"] .text-indigo-700  { color: #A5B4FC; }
[data-theme="dark"] .text-violet-700  { color: #C4B5FD; }
[data-theme="dark"] .text-red-700     { color: #FCA5A5; }
[data-theme="dark"] .hover\:text-red-600:hover { color: #FCA5A5; }

/* El anillo del badge viaja por --tw-ring-color, no por border-color. */
[data-theme="dark"] .ring-blue-200    { --tw-ring-color: rgba(59, 130, 246, .35); }
[data-theme="dark"] .ring-amber-200   { --tw-ring-color: rgba(245, 158, 11, .35); }
[data-theme="dark"] .ring-orange-200  { --tw-ring-color: rgba(249, 115, 22, .35); }
[data-theme="dark"] .ring-emerald-200 { --tw-ring-color: rgba(16, 185, 129, .35); }
[data-theme="dark"] .ring-teal-200    { --tw-ring-color: rgba(20, 184, 166, .35); }
[data-theme="dark"] .ring-cyan-200    { --tw-ring-color: rgba(6, 182, 212, .35); }
[data-theme="dark"] .ring-indigo-200  { --tw-ring-color: rgba(99, 102, 241, .38); }
[data-theme="dark"] .ring-violet-200  { --tw-ring-color: rgba(139, 92, 246, .38); }
[data-theme="dark"] .ring-red-200     { --tw-ring-color: rgba(239, 68, 68, .35); }
[data-theme="dark"] .ring-slate-200   { --tw-ring-color: var(--dk-surface-3); }
[data-theme="dark"] .border-red-200   { border-color: rgba(239, 68, 68, .35); }

/* Mismo criterio para los tonos "soft" del tema propio y para los hex
   sueltos que los acompañan (consultation_*, complaint_detail, login). */
[data-theme="dark"] .bg-ok-soft     { background-color: rgba(16, 185, 129, .16); }
[data-theme="dark"] .bg-warn-soft   { background-color: rgba(245, 158, 11, .16); }
[data-theme="dark"] .bg-err-soft,
[data-theme="dark"] .bg-\[\#FBDADA\] { background-color: rgba(239, 68, 68, .16); }
[data-theme="dark"] .bg-violet-soft { background-color: rgba(139, 92, 246, .18); }
[data-theme="dark"] .text-\[\#065F46\] { color: #6EE7B7; }
[data-theme="dark"] .text-\[\#92400E\] { color: #FCD34D; }
[data-theme="dark"] .text-\[\#991B1B\],
[data-theme="dark"] .text-\[\#B91C1C\] { color: #FCA5A5; }
[data-theme="dark"] .border-\[\#A7F3D0\] { border-color: rgba(16, 185, 129, .35); }
[data-theme="dark"] .border-\[\#FCA5A5\] { border-color: rgba(239, 68, 68, .35); }

/* Colores de marca y semánticos como TEXTO: sobre navy, las variantes
   oscuras (brand-dark, accent, violet, err) no llegaban a 4.5:1. El tono
   se mantiene; sube la luminosidad. Como fondo no se tocan. */
[data-theme="dark"] .text-brand-dark { color: #5EEAD4; }
[data-theme="dark"] .text-accent     { color: #A5B4FC; }
[data-theme="dark"] .text-violet     { color: #C4B5FD; }
[data-theme="dark"] .text-err        { color: #F87171; }
[data-theme="dark"] .hover\:text-brand:hover { color: #5EEAD4; }

/* Botones/superficies navy sólido: sobre el fondo oscuro desaparecían
   contra la página. Suben un escalón de la escala. */
[data-theme="dark"] .bg-ink-900 { background-color: var(--dk-surface-3); }
[data-theme="dark"] .hover\:bg-ink-800:hover { background-color: #2C4468; }

/* Pills de filtro del listado de denuncias (.pill[data-v=...]).
   Apagados: tinte translúcido + texto claro del mismo tono.
   Encendidos: se dejan como están, el color pleno ya contrasta. */
[data-theme="dark"] .pill[data-v="submitted"]   { background: rgba(59, 130, 246, .16);  color: #93C5FD; }
[data-theme="dark"] .pill[data-v="in_review"]   { background: rgba(245, 158, 11, .16);  color: #FCD34D; }
[data-theme="dark"] .pill[data-v="in_progress"] { background: rgba(139, 92, 246, .18);  color: #C4B5FD; }
[data-theme="dark"] .pill[data-v="resolved"]    { background: rgba(16, 185, 129, .16);  color: #6EE7B7; }
[data-theme="dark"] .pill[data-v="rejected"],
[data-theme="dark"] .pill[data-v="urgent"]      { background: rgba(239, 68, 68, .16);   color: #FCA5A5; }
[data-theme="dark"] .pill[data-v="high"]        { background: rgba(249, 115, 22, .16);  color: #FDBA74; }
[data-theme="dark"] .pill[data-v="medium"]      { background: rgba(245, 158, 11, .16);  color: #FCD34D; }
[data-theme="dark"] .pill[data-v="low"]         { background: var(--dk-surface-2);      color: #B9C3D4; }
[data-theme="dark"] .pill[data-v="brand"]       { background: rgba(59, 130, 246, .16);  color: #93C5FD; }
[data-theme="dark"] .pill.on { box-shadow: 0 1px 2px rgba(0, 0, 0, .35); }

/* Días futuros del calendario de actividad. En claro son un gris muy
   tenue a propósito; con --dk-surface-3 el número quedaba invisible, así
   que se sube al mismo grado de atenuación relativa que tiene en claro. */
[data-theme="dark"] .heatcal-cell.future { color: #3C5680; }

/* Notificación sin leer: su fondo es más claro que la superficie, y el
   texto atenuado se quedaba justo por debajo de AA sobre ese fondo. */
[data-theme="dark"] .notif-item.unread .text-ink-400 { color: #A3B1C8; }

/* Leaflet: la atribución y los popups los inyecta la librería con su
   propio CSS claro (mapa de calor, mapa de obras, ficha del reclamo). */
[data-theme="dark"] .leaflet-control-attribution {
    background: rgba(19, 38, 63, .85);
    color: var(--dk-text-2);
}
[data-theme="dark"] .leaflet-control-attribution a { color: #7DD9CC; }
[data-theme="dark"] .leaflet-popup-content-wrapper,
[data-theme="dark"] .leaflet-popup-tip {
    background: var(--dk-surface);
    color: var(--dk-text);
    box-shadow: var(--shadow-lg);
}
[data-theme="dark"] .leaflet-container a.leaflet-popup-close-button { color: var(--dk-text-2); }
[data-theme="dark"] .leaflet-bar a,
[data-theme="dark"] .leaflet-bar a:hover {
    background: var(--dk-surface);
    color: var(--dk-text);
    border-bottom-color: var(--dk-surface-3);
}
[data-theme="dark"] .work-popup__title { color: var(--dk-text); }
[data-theme="dark"] .work-popup__meta  { color: var(--dk-text-2); }
[data-theme="dark"] .work-popup__delayed { background: rgba(239, 68, 68, .18); color: #FCA5A5; }
[data-theme="dark"] .work-popup__link { color: #5EEAD4; }

/* Controles de filtro de los mapas (ver tokens --fx-* en :root): los
   pinta alpine-components.js con :style, que gana a cualquier utilidad.
   Acá sólo se redefinen los tokens; el JS ya los consume. */
html[data-theme="dark"] {
    --fx-on-bg:        #E6EEF8;                  --fx-on-fg:      #0B1C3D;
    --fx-off-bg:       #1A3150;                  --fx-off-fg:     #CBD5E3;
    --fx-off-bd:       #24395A;
    --fx-sel-bg:       rgba(20, 184, 166, .16);  --fx-sel-fg:     #5EEAD4;
    --fx-idle-fg:      #B9C3D4;
    --fx-neutro-bg:    #24395A;                  --fx-neutro-fg:  #CBD5E3;
    --fx-alta-bg:      rgba(249, 115, 22, .18);  --fx-alta-fg:    #FDBA74;
    --fx-media-bg:     rgba(245, 158, 11, .18);  --fx-media-fg:   #FCD34D;
    --fx-baja-bg:      #1A3150;                  --fx-baja-fg:    #B9C3D4;
    --fx-lista-on-bg:  #1A3150;                  --fx-lista-on-fg:#E6EEF8;
    --fx-lista-off-fg: #8A99B3;
    --fx-atraso-bg:    rgba(239, 68, 68, .20);   --fx-atraso-fg:  #FCA5A5;
}

/* Botón nativo de <input type="file"> (panel de resolución del reclamo). */
[data-theme="dark"] input[type="file"]::file-selector-button {
    background: var(--dk-surface-3);
    color: var(--dk-text);
    border: 1px solid var(--dk-surface-3);
    border-radius: 6px;
}

/* Selector de prioridad de la ficha del reclamo: el estado elegido se
   pinta con variantes `peer-checked:*`, que compilan a un selector propio
   y no los alcanza el override de la utilidad suelta. */
[data-theme="dark"] .peer:checked ~ .peer-checked\:bg-amber-50 { background-color: rgba(245, 158, 11, .18); }
[data-theme="dark"] .peer:checked ~ .peer-checked\:bg-red-50   { background-color: rgba(239, 68, 68, .18); }
[data-theme="dark"] .peer:checked ~ .peer-checked\:bg-slate-50 { background-color: var(--dk-surface-2); }
[data-theme="dark"] .peer:checked ~ .peer-checked\:text-amber-700 { color: #FCD34D; }
[data-theme="dark"] .peer:checked ~ .peer-checked\:text-red-700   { color: #FCA5A5; }
[data-theme="dark"] .peer:checked ~ .peer-checked\:text-slate-700 { color: #CBD5E3; }

/* La atribución de Leaflet la declara la librería como
   `.leaflet-container .leaflet-control-attribution`: hay que igualar esa
   especificidad para que el fondo blanco translúcido no gane. */
[data-theme="dark"] .leaflet-container .leaflet-control-attribution {
    background: rgba(19, 38, 63, .85);
    color: var(--dk-text-2);
}
[data-theme="dark"] .leaflet-container .leaflet-control-attribution a { color: #7DD9CC; }

/* ─────────────────────────────────────────────────────────────
   Contraste de los botones sólidos (AMBOS temas)
   El QA del modo oscuro lo destapó, pero es un problema del diseño
   base: blanco sobre el teal de marca da 2.49:1, muy por debajo del
   4.5:1 que pide AA para texto normal. Lo mismo con el verde de "ok"
   (2.54) y el ámbar de "warn" (2.15).

   El color de marca NO se toca: es el mismo que usa la app móvil. Lo
   que cambia es la etiqueta, que pasa a navy —sobre el teal da 6.76:1,
   sobre el verde 6.64 y sobre el ámbar 7.84—. El rojo destructivo es
   la excepción: en navy tampoco llega (4.47), así que ahí se oscurece
   el fondo a #DC2626, que con blanco da 4.83.

   Va como selector compuesto (.bg-x.text-white) para no tener que
   editar decenas de templates: dashboard.css carga después de
   tailwind.css y (0,2,0) le gana a la utilidad suelta.
   ───────────────────────────────────────────────────────────── */
.bg-brand.text-white,
.bg-ok.text-white,
.bg-warn.text-white   { color: var(--ink-900); }

/* El teal oscuro no alcanza AA ni con blanco (3.99) ni con navy (4.22):
   como fondo de botón se lo sube al teal pleno, que sí llega. */
.bg-brand-dark.text-white { background-color: var(--brand); color: var(--ink-900); }
.hover\:bg-brand-dark:hover { background-color: #2FD3C0; }

/* Acción destructiva: se conserva el blanco (lo que se lee como
   "peligro" es el rojo pleno) y se oscurece el fondo lo justo. */
.bg-err.text-white { background-color: #DC2626; }

/* Botón primario del login y salto al contenido: mismo criterio. */
.btn-auth { color: var(--ink-900); }
.skip-link { color: var(--ink-900); }

/* Nivel 3 del calendario de actividad: es el único de la escala con
   fondo teal pleno y número blanco (2.49). Los niveles 4 y 5 ya son
   suficientemente oscuros y se quedan en blanco. */
.heatcal-cell.l3 { color: var(--ink-900); }

/* En oscuro, el navy de la etiqueta sigue siendo el correcto: el fondo
   del botón no cambia con el tema. Sólo se fija el token por si algún
   día --ink-900 se repinta. */
[data-theme="dark"] .bg-brand.text-white,
[data-theme="dark"] .bg-ok.text-white,
[data-theme="dark"] .bg-warn.text-white,
[data-theme="dark"] .bg-brand-dark.text-white,
[data-theme="dark"] .btn-auth,
[data-theme="dark"] .skip-link,
[data-theme="dark"] .heatcal-cell.l3 { color: #0B1C3D; }
