/* Paleta y tipografía — mismos tokens que la maqueta (seguimiento-obra-preview.html), para que la
   herramienta real se vea consistente con lo que venimos probando y aprobando ahí. */
@import url('https://fonts.googleapis.com/css2?family=Barlow+Semi+Condensed:wght@600;700&family=Public+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@500;600&display=swap');

:root {
  --ink: #1a2233;
  --ink-soft: #55606e;
  --ink-faint: #8792a0;
  --surface: #f5f2eb;
  --surface-card: #ffffff;
  --surface-sunken: #ece7db;
  --line: #ddd7c8;
  --line-soft: #e8e3d6;
  --steel: #2b4a66;
  --steel-dark: #1e3448;
  --accent: #c1791e;
  --accent-soft: #f0dcc0;
  --pendiente: #98a2a8;
  --en_curso: #c1791e;
  --terminado: #2b6cb0;
  --certificado: #2e8b57;
  --abonado: #6d4fa8;
  --vencido: #ae3f35;
  --vencido-bg: #f7e3e0;
  --focus: #2b6cb0;
  --shadow: 0 1px 2px rgba(26,34,51,.06), 0 4px 14px rgba(26,34,51,.05);
  --radius: 10px;
  /* Alias de compatibilidad con nombres viejos que puedan quedar en algún estilo en línea. */
  --text-muted: var(--ink-soft);
  --border: var(--line);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: "Public Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--steel); }

h1, h2, h3 {
  font-family: "Barlow Semi Condensed", "Public Sans", sans-serif;
  font-weight: 700;
  letter-spacing: .01em;
  margin: 0;
}
h1 { font-size: 1.5rem; margin: 0 0 4px; }
h2 { font-size: 1.1rem; margin: 0 0 12px; color: var(--ink); }
.subtitle { color: var(--ink-soft); margin: 0 0 20px; font-size: 0.92rem; }
.muted { color: var(--ink-soft); font-size: 0.85rem; }

.mono { font-family: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace; font-variant-numeric: tabular-nums; }

/* ---------- Topbar ---------- */
.topbar {
  background: linear-gradient(180deg, var(--steel), var(--steel-dark));
  color: #f2f5f8;
  padding: 14px 22px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px;
  box-shadow: var(--shadow);
}
.topbar .id { display: flex; align-items: center; gap: 10px; }
.topbar .id .mark {
  height: 38px; padding: 4px 10px; border-radius: 7px;
  background: #ffffff;
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.topbar .id .mark img { height: 100%; width: auto; display: block; }
.topbar .id .txt { line-height: 1.2; }
.topbar .id .txt .name { font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: 1.08rem; }
.topbar .id .txt .sub { font-size: .74rem; color: #c7d3dd; letter-spacing: .02em; }

.topbar .controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.topbar .controls .who { font-size: .84rem; color: #dbe4ee; }

.reset-btn {
  background: transparent;
  border: 1px solid rgba(255,255,255,.28);
  color: #e7ecf0;
  border-radius: 8px;
  padding: 7px 12px;
  font-size: .8rem;
  text-decoration: none;
}
.reset-btn:hover { background: rgba(255,255,255,.1); }

/* ---------- Campanita de notificaciones (ver includes/notificaciones.php) ---------- */
.campanita-wrap { position: relative; }
.campanita-btn {
  position: relative;
  background: transparent;
  border: 1px solid rgba(255,255,255,.28);
  color: #e7ecf0;
  border-radius: 8px;
  width: 38px; height: 38px;
  font-size: 1.05rem;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.campanita-btn:hover { background: rgba(255,255,255,.1); }
.campanita-btn.has-alert { animation: campanita-ring 2.4s ease-in-out infinite; }
@keyframes campanita-ring {
  0%, 96%, 100% { transform: rotate(0); }
  97% { transform: rotate(-12deg); }
  98% { transform: rotate(10deg); }
  99% { transform: rotate(-6deg); }
}
.campanita-badge {
  position: absolute; top: -5px; right: -5px;
  background: var(--vencido);
  color: #fff;
  font-size: .68rem;
  font-weight: 700;
  line-height: 1;
  min-width: 17px; height: 17px;
  border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 4px;
  box-shadow: 0 0 0 2px var(--steel-dark);
}
/* El atributo hidden por sí solo no alcanza: la regla de arriba (display:flex, por clase) le gana
   en especificidad a la regla nativa del navegador para [hidden] (display:none, por atributo). */
.campanita-badge[hidden] { display: none; }
.campanita-panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  width: min(360px, 90vw);
  max-height: min(70vh, 480px);
  overflow-y: auto;
  background: var(--surface-card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow), 0 12px 32px rgba(20,26,33,.28);
  z-index: 400;
  padding: 6px;
}
.campanita-panel-titulo {
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-faint); padding: 8px 10px 4px;
}
.campanita-grupo + .campanita-grupo { margin-top: 4px; border-top: 1px solid var(--line-soft); padding-top: 4px; }
.campanita-item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; border-left: 3px solid var(--line); border-radius: 8px;
  padding: 8px 10px; cursor: pointer;
  font-family: inherit; color: var(--ink); text-decoration: none;
}
.campanita-item:hover { background: var(--surface-sunken); }
.campanita-item .texto { font-size: .82rem; font-weight: 600; }
.campanita-item .sub { font-size: .74rem; color: var(--ink-soft); margin-top: 2px; }
/* "Exclusiva" = nadie más que el dueño puede resolverla ahora mismo (ver
   capacidad_es_exclusiva_del_actor en includes/notificaciones.php). Mismo lenguaje visual que
   .banner (fondo accent-soft + acento accent) para que se lea como "esto depende de vos, si no lo
   hacés vos no lo hace nadie" — distinto de las que también le tocan a otro rol del equipo. */
.campanita-item.exclusiva { background: var(--accent-soft); border-left-color: var(--accent); }
.campanita-item.exclusiva:hover { background: var(--accent-soft); filter: brightness(0.97); }
.campanita-empty { padding: 22px 12px; text-align: center; font-size: .84rem; color: var(--ink-faint); }
@media (max-width: 640px) {
  .campanita-panel { position: fixed; top: 62px; right: 8px; left: 8px; width: auto; }
}

.menu-toggle {
  background: transparent;
  border: 1px solid rgba(255,255,255,.28);
  color: #e7ecf0;
  border-radius: 8px;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1rem;
  line-height: 1;
  flex: none;
  padding: 0;
}
.menu-toggle:hover { background: rgba(255,255,255,.1); }

/* ---------- Layout — el menú va pegado al margen izquierdo y todo ocupa el 100% del ancho
   disponible (sin un "max-width" central que deje franjas vacías a los costados). ---------- */
.shell { display: flex; align-items: flex-start; width: 100%; }
.main { flex: 1; min-width: 0; }
.wrap { padding: 22px 24px 70px; }

/* ---------- Menú lateral ---------- */
.sidebar {
  flex: none; width: 220px;
  padding: 20px 12px 40px;
  border-right: 1px solid var(--line);
  position: sticky; top: 0;
  align-self: flex-start;
  max-height: 100vh; overflow-y: auto; overflow-x: hidden; white-space: nowrap;
  transition: width .16s ease, padding .16s ease;
}
.sidebar.collapsed { width: 0; padding-left: 0; padding-right: 0; border-right: none; }
.sidebar-item {
  display: block; width: 100%; text-align: left;
  background: none; border: none; color: var(--ink-soft);
  border-radius: 7px; padding: 9px 12px; font-size: .88rem; font-weight: 600;
  margin-bottom: 2px; text-decoration: none;
}
.sidebar-item:hover:not(.active) { background: var(--surface-sunken); color: var(--ink); }
.sidebar-item.active { background: var(--steel); color: #fff; }
.sidebar-group { margin-top: 14px; }
/* Título de grupo desplegable (Felipe, 05/09: "agregale los desplegables a los titulos, porque ya
   son muchas cosas y hay que hacer mucho scroll") — antes era un <div>, ahora un <button> de ancho
   completo para que TODO el renglón del título sea zona de toque, no solo el texto. El chevron
   rota con .collapsed (ver includes/footer.php para el JS que togglea la clase y la recuerda por
   grupo en localStorage) y con eso alcanza para ocultar/mostrar .sidebar-group-items más abajo. */
.sidebar-group-title {
  display: flex; align-items: center; justify-content: space-between; gap: 6px; width: 100%;
  background: none; border: none; cursor: pointer; font-family: inherit;
  color: var(--ink-faint); font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; padding: 6px 12px;
}
/* El fondo hay que fijarlo acá explícito (no alcanza con solo el color): la regla genérica
   "button:hover, .btn:hover { background: var(--steel-dark) }" de más abajo tiene MÁS especificidad
   CSS que ".sidebar-group-title" sola (un elemento+pseudo-clase gana a una sola clase) — sin este
   background acá, ese fondo azul oscuro de "botón" se colaba al pasar el mouse por el título de un
   grupo, aunque en el resto de estados (sin hover) la clase sí le ganaba bien al elemento genérico.
   Encontrado con Playwright al probar la Fase 26 (el mouse quieto sobre el botón recién tocado). */
.sidebar-group-title:hover { background: var(--surface-sunken); color: var(--ink-soft); }
.sidebar-group-chevron { flex: none; font-size: .7rem; transition: transform .15s ease; }
.sidebar-group.collapsed .sidebar-group-chevron { transform: rotate(-90deg); }
.sidebar-group.collapsed .sidebar-group-items { display: none; }

@media (max-width: 780px) {
  /* .shell tiene align-items:flex-start (necesario en desktop para que el sidebar no se estire
     a la altura del contenido) — pero en columna eso hace que .main se achique a "fit-content"
     en vez de ocupar el ancho disponible, así que un <select> con una opción larga (ej. nombre de
     material) lo puede desbordar y arrastrar a toda la página con él. align-items:stretch acá
     hace que .main (y .sidebar, que ya fuerza su propio 100% más abajo) llenen el ancho real. */
  .shell { flex-direction: column; align-items: stretch; }
  .main { width: 100%; }
  .sidebar {
    width: 100%; position: static; max-height: none; overflow-y: visible;
    border-right: none; border-bottom: 1px solid var(--line);
    display: flex; flex-wrap: wrap; gap: 4px; padding: 12px 16px;
  }
  .sidebar-item { width: auto; margin-bottom: 0; }
  /* Cada grupo con título ocupa su propio renglón (display:block corta la línea), en vez de
     mezclarse suelto entre los demás chips — así el título queda como una "solapa" propia y sus
     ítems se pliegan/despliegan como una fila aparte debajo, sin desarmar el resto del menú. */
  .sidebar-group { margin: 0; display: block; width: 100%; }
  .sidebar-group-title {
    display: inline-flex; width: auto; background: var(--surface-sunken); border-radius: 999px;
    padding: 6px 12px; margin: 2px 0;
  }
  .sidebar-group-items { display: flex; flex-wrap: wrap; gap: 4px; padding: 2px 0 8px 4px; }
  .topbar { flex-direction: column; align-items: flex-start; }
  /* .sidebar.collapsed (más arriba) solo pone en 0 el padding izq/der y el border-right — pensado
     para el desktop, donde el menú es una columna angosta al costado. En mobile el menú es una
     franja horizontal con padding arriba/abajo (12px) y border-bottom propios, que esa regla no
     toca, así que al "cerrar" el menú quedaba una franja vacía con esa altura. display:none lo
     saca del todo en vez de tratar de poner en 0 cada propiedad una por una. */
  .sidebar.collapsed { display: none; }
}
/* ---------- Tarjetas / tablas ---------- */
.card { background: var(--surface-card); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); padding: 18px 20px; margin-bottom: 18px; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 11px 8px; border-bottom: 1px solid var(--line-soft); font-size: .9rem; vertical-align: top; }
th { color: var(--ink-faint); font-weight: 600; font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; }
tr:last-child td { border-bottom: none; }
/* Celda de acciones (varios botones en una fila) que en desktop no queremos que se corten en dos
   líneas — en mobile, dentro de .table-cards, la regla ".table-cards td { white-space: normal }"
   pisa esto por mayor especificidad, así los botones se acomodan en varias líneas en vez de
   forzar scroll horizontal. */
.td-nowrap { white-space: nowrap; }

/* Fase 27 — Galería de Fotos de Obra: mismo criterio de grilla responsive que .recinto-grid, con
   tarjetas más angostas porque lo que manda acá es la foto, no el texto. */
.fotos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.foto-card {
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.foto-card img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--surface-sunken); }
/* Fase 27.2 — la miniatura pasó de <a target="_blank"> a un <button> que abre el modal genérico
   (ver openModal() en includes/footer.php): reset de los estilos de botón para que se vea IGUAL
   que antes (sin borde ni fondo propio), con cursor de "clickeable" y sin franja de foco fea al
   tocar en mobile. */
.foto-card-thumb { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
/* Ojo (mismo bug que Fase 18/26): la regla general "button:hover { background: var(--steel-dark) }"
   (assets/style.css, más abajo) tiene más especificidad que ".foto-card-thumb" sola y pintaría un
   fondo oscuro sólido atrás de la miniatura al pasar el mouse -- se pisa acá mismo, explícito. */
.foto-card-thumb:hover { background: none; }
.foto-card-thumb:hover img { opacity: .92; }
.foto-card-body { padding: 8px 10px 10px; }
.foto-card-recinto { font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: .82rem; color: var(--steel); }
.foto-card-leyenda { font-size: .82rem; margin: 3px 0; }
/* Foto grande dentro del modal (ver el <template> de cada tarjeta en fotos.php). */
.foto-modal-body img { display: block; width: 100%; max-height: 70vh; object-fit: contain; border-radius: 8px; background: var(--surface-sunken); }
.foto-modal-leyenda { margin: 10px 0 0; font-size: .88rem; }
.foto-card-meta { font-size: .7rem; color: var(--ink-faint); }
/* Fase 27.3 — botón "Borrar" (solo visible para quien subió la foto o un rol administrativo, ver
   fotos_obra_puede_borrar() en includes/fotos_obra.php). */
.foto-card-borrar { margin-top: 8px; }

.recinto-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.recinto-card {
  display: block;
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 16px 18px 14px;
  text-decoration: none;
  color: var(--ink);
  box-shadow: var(--shadow);
  transition: border-color .15s;
}
.recinto-card:hover { border-color: var(--steel); }
.recinto-card strong { font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: 1.05rem; }
.recinto-card .m2 { color: var(--ink-soft); font-size: 0.85rem; margin: 2px 0 10px; }

.progress-bar { height: 9px; border-radius: 6px; background: var(--surface-sunken); overflow: hidden; margin-bottom: 6px; }
.progress-bar > span { display: block; height: 100%; background: var(--steel); }
.progress-pct { font-family: "IBM Plex Mono", monospace; font-size: 0.86rem; font-weight: 600; color: var(--steel); }
/* Fila con el % de avance (+ m² que corresponden a ese %) a la izquierda, y cantidad de tareas
   (+ vencidas, si hay) a la derecha — igual info que el "row2" de la tarjeta de recinto en la
   maqueta, con nuestras propias clases para no tocar .progress-bar/.progress-pct ya existentes. */
.progress-pct-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.m2-avanzado { font-weight: 600; font-size: .74rem; color: var(--ink-faint); }
.recinto-cnt { font-size: .74rem; color: var(--ink-faint); white-space: nowrap; }

/* ---------- Badges / pills de estado ---------- */
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}
.badge-alerta { background: var(--vencido-bg); color: var(--vencido); border: 1px solid var(--vencido); }

.badge-low { display: inline-block; font-size: .68rem; font-weight: 700; padding: 2px 8px; border-radius: 10px; white-space: nowrap; }
.badge-low-warn { color: var(--en_curso); background: color-mix(in srgb, var(--en_curso) 16%, transparent); }
.badge-low-crit { color: var(--vencido); background: var(--vencido-bg); }

/* ---------- status-pill (solo lectura) / status-select (editable, coloreado por su propio valor) ---------- */
.status-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .78rem; font-weight: 600; padding: 4px 10px; border-radius: 20px;
  border: 1px solid transparent;
}
.status-pill .dot { width: 7px; height: 7px; border-radius: 50%; }
.status-pill[data-estado="pendiente"] { background: color-mix(in srgb, var(--pendiente) 16%, transparent); color: var(--pendiente); border-color: color-mix(in srgb, var(--pendiente) 45%, transparent); }
.status-pill[data-estado="en_curso"] { background: color-mix(in srgb, var(--en_curso) 16%, transparent); color: var(--en_curso); border-color: color-mix(in srgb, var(--en_curso) 45%, transparent); }
.status-pill[data-estado="terminado"] { background: color-mix(in srgb, var(--terminado) 16%, transparent); color: var(--terminado); border-color: color-mix(in srgb, var(--terminado) 45%, transparent); }
.status-pill[data-estado="pendiente"] .dot { background: var(--pendiente); }
.status-pill[data-estado="en_curso"] .dot { background: var(--en_curso); }
.status-pill[data-estado="terminado"] .dot { background: var(--terminado); }

select.status-select { border-width: 2px; font-weight: 600; width: auto; }
select.status-select[data-estado="pendiente"] { border-color: var(--pendiente); background: color-mix(in srgb, var(--pendiente) 22%, var(--surface-card)); }
select.status-select[data-estado="en_curso"] { border-color: var(--en_curso); background: color-mix(in srgb, var(--en_curso) 16%, var(--surface-card)); }
select.status-select[data-estado="terminado"] { border-color: var(--terminado); background: color-mix(in srgb, var(--terminado) 16%, var(--surface-card)); }
/* Select de etapa (imprimación/enduido/terminación) dentro de una tarea "En curso" — va justo
   debajo del select de estado, en el mismo .field, más chico para no competir visualmente.
   Nombres de etapa largos ("Enduido rayado de superficie...") hacían que un <select> con
   width:auto (heredado de select.status-select) se dimensionara por su contenido y se saliera
   de la columna, corriendo también la de Responsable — por eso acá se fuerza al ancho de la
   columna con una regla del mismo peso (select.etapa-select) que gana por venir después. */
select.etapa-select { width: 100%; max-width: 100%; margin-top: 6px; font-size: .78rem; }

/* Fila completa de la tabla de tareas coloreada según estado (igual que en la maqueta) — un tinte
   muy sutil de fondo sobre toda la fila, más un acento de borde izquierdo en la celda del nombre
   de la tarea, para que el estado se lea de un vistazo sin tener que mirar el select/pill. */
tr.row-estado-pendiente { background: color-mix(in srgb, var(--pendiente) 11%, transparent); }
tr.row-estado-en_curso { background: color-mix(in srgb, var(--en_curso) 9%, transparent); }
tr.row-estado-terminado { background: color-mix(in srgb, var(--terminado) 9%, transparent); }
tr.row-estado td.task-name { border-left: 4px solid transparent; }
tr.row-estado-pendiente td.task-name { border-left-color: var(--pendiente); }
tr.row-estado-en_curso td.task-name { border-left-color: var(--en_curso); }
tr.row-estado-terminado td.task-name { border-left-color: var(--terminado); }

/* ---------- stat-box: recuadro "hundido" (fondo distinto al de la tarjeta que lo contiene) —
   para números de contexto secundario (cuenta corriente, consumo de material), a diferencia de
   .stat-tile (fondo de tarjeta, con borde y sombra), que se usa para los números principales
   (tickers de Inicio/Recintos). ---------- */
.stat-box { background: var(--surface-sunken); border-radius: 8px; padding: 10px 12px; text-align: center; }
.stat-box .v { font-family: "IBM Plex Mono", monospace; font-weight: 600; font-size: 1.05rem; }
.stat-box .k { font-size: .7rem; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }

/* ---------- Paleta categórica (recintos/esquemas en los gráficos de avance diario) ---------- */
:root {
  --cat1: #2a78d6; --cat2: #eb6834; --cat3: #1baf7a; --cat4: #eda100; --cat5: #e87ba4; --cat6: #008300;
}

/* ---------- Avance diario (gráficos + actividad) ---------- */
.chart-wrap { width: 100%; overflow-x: auto; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 10px 16px; margin-top: 6px; padding: 0 2px; }
.legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: .78rem; color: var(--ink-soft); }
.legend-item i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }
.activity-day { padding: 10px 18px 4px; }
.activity-day:first-child { padding-top: 14px; }
.activity-day h4 { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); font-weight: 700; margin: 0 0 4px; }
.log { padding: 6px 18px 16px; }
.log-entry { font-size: .8rem; color: var(--ink-soft); padding: 7px 0; border-bottom: 1px dashed var(--line-soft); display: flex; gap: 10px; flex-wrap: wrap; }
.log-entry:last-child { border-bottom: none; }
.log-entry .t { font-family: "IBM Plex Mono", monospace; color: var(--ink-faint); white-space: nowrap; font-size: .74rem; flex: none; min-width: 110px; font-weight: 600; }
.log-empty { font-size: .82rem; color: var(--ink-faint); padding: 4px 18px 16px; }
.card-h { padding: 14px 18px; border-bottom: 1px solid var(--line-soft); display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin: -18px -20px 14px; }
.card-h h2 { font-size: 1.05rem; margin: 0; }

/* ---------- Modal genérico (usado por "Ver detalle" en Por Esquema) ---------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15, 19, 26, .55);
  display: flex; align-items: center; justify-content: center; padding: 24px;
  z-index: 50;
}
.modal-box {
  background: var(--surface-card); border-radius: 12px; box-shadow: var(--shadow);
  max-width: 760px; width: 100%; max-height: 84vh; display: flex; flex-direction: column; overflow: hidden;
}
.modal-h {
  padding: 14px 18px; border-bottom: 1px solid var(--line-soft);
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
}
.modal-h h2 { font-size: 1rem; }
.modal-h p { margin: 4px 0 0; font-size: .8rem; color: var(--ink-soft); }
.modal-close {
  /* padding:0 y flex-centering pisan el padding:9px 16px + display:inline-block del botón
     genérico (más abajo en este archivo) — con eso la "✕" quedaba corrida dentro del
     cuadradito de 28×28 en vez de centrada. */
  background: none; border: 1px solid var(--line); border-radius: 6px; color: var(--ink-soft);
  width: 28px; height: 28px; padding: 0; font-size: .95rem; line-height: 1; cursor: pointer; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
}
.modal-close:hover { background: none; border-color: var(--steel); color: var(--ink); }
.modal-body { padding: 14px 18px 18px; overflow-y: auto; }
.modal-body h3 { font-size: .82rem; margin: 14px 0 6px; }
.modal-body h3:first-child { margin-top: 0; }
.modal-body table { width: 100%; }
.modal-body th, .modal-body td { padding: 7px 10px; font-size: .8rem; }
.modal-note { font-size: .78rem; color: var(--ink-soft); margin: 0 0 10px; }
.row-excluida { opacity: .55; }
.row-excluida td { text-decoration: line-through; }
/* Felipe, 03/09: "el boton de 'Ver detalle' en AVANCE POR ESQUEMA casi no se ve, habria que darle
   mas forma de boton y cuando pase el mouse por arriba resalte". Antes era texto subrayado sin
   recuadro (a propósito, para esquivar el hover oscuro genérico de "button" — ver la nota vieja que
   quedaba acá abajo), pero terminaba pasando desapercibido dentro del párrafo. Ahora es un botón
   secundario chico de verdad (mismo criterio que .btn-secondary), con su propio hover que resalta
   sin volverse oscuro/ilegible. */
.esquema-detalle-link {
  background: var(--surface-card);
  border: 1px solid var(--steel);
  color: var(--steel);
  padding: 3px 10px;
  border-radius: 6px;
  font-size: .76rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  display: inline-block;
  vertical-align: middle;
  margin-left: 4px;
}
.esquema-detalle-link:hover { background: var(--surface-sunken); color: var(--steel-dark); border-color: var(--steel-dark); }

/* ---------- Formularios ---------- */
select, input[type=date], input[type=text], input[type=email], input[type=password], input[type=number], textarea {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 0.88rem;
  font-family: inherit;
  background: var(--surface-card);
  color: var(--ink);
}
textarea { min-height: 60px; resize: vertical; }

.field { margin-bottom: 14px; }
.field label { display: block; font-size: 0.85rem; margin-bottom: 4px; color: var(--ink-soft); }
/* input[type=file] no tiene un ancho fijo — el navegador arma su botón + el nombre del archivo
   elegido (o "Ningún archivo seleccionado") con el ancho que haga falta, y por default eso se
   sale de la caja angosta de un .field dentro de un .task-row-form, chocando con el campo o botón
   de al lado. Felipe, feedback del 27/08: "en el adjunto... se choca con el botón". Mismo criterio
   que .avatar-file-field ya usaba, generalizado acá a CUALQUIER .field con un adjunto, en toda la
   app. */
.field input[type="file"] { display: block; width: 100%; max-width: 100%; font-size: .76rem; }

/* Felipe, 02/09: "seria bueno que en el login te de la posibilidad de 'Mostrar contraseña' para
   ver lo que uno esta escribiendo" — botón de texto (mismo reset que .esquema-detalle-link) flotado
   adentro del campo, a la derecha; el input le deja lugar con padding-right. */
.password-field { position: relative; }
.password-field input[type="password"], .password-field input[type="text"] { padding-right: 70px; }
.password-field .password-toggle {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  background: none; border: none; padding: 4px 6px; color: var(--steel);
  font-size: .78rem; font-weight: 600; cursor: pointer; text-decoration: underline;
}
.password-field .password-toggle:hover { background: none; color: var(--steel-dark); }

/* Felipe, 02/09: "Quisiera que la contraseña se pueda resetear y escribirla en Usuarios" — el
   campo + botón de la columna Contraseña, uno al lado del otro dentro de la celda de la tabla (no
   necesitan tanto ancho como .task-row-form, que es para formularios de varios campos). */
.password-reset-form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.password-reset-input { width: auto; flex: 1 1 120px; min-width: 90px; font-size: .82rem; padding: 6px 8px; }

.task-row-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
/* min-width:0 es necesario porque el default de un flex item es min-width:auto, que en un
   <select> se calcula como el ancho de su option más larga (ej. nombres de materiales largos) —
   sin esto, el select nunca se achica por debajo de ese ancho y desborda la fila en mobile,
   aunque tenga width:100% y flex-shrink. */
.task-row-form .field { margin-bottom: 0; flex: 1 1 160px; min-width: 0; }
.task-row-form .field.grow { flex: 2 1 220px; min-width: 0; }
/* Va DESPUÉS de la regla base de .task-row-form (arriba) a propósito: una @media más temprana en
   el archivo pierde contra una regla sin @media que aparece más abajo, aunque el media-query
   matchee — el orden en la cascada es por posición en el archivo, no por especificidad de la
   condición. Así que este override de mobile tiene que ir al final para ganar. */
@media (max-width: 560px) {
  .task-row-form { flex-direction: column; align-items: stretch; }
  /* En columna, el eje principal del flex pasa a ser vertical — el flex-basis:160px/220px de
     arriba (pensado como ANCHO mínimo cuando la fila es horizontal) se interpreta entonces como
     ALTURA mínima, y cada campo quedaba con ~160/220px de alto aunque el control real ocupara la
     mitad, dejando un hueco enorme debajo de cada uno. flex-basis:auto acá hace que la altura
     salga del contenido real. */
  .task-row-form .field, .task-row-form .field.grow { flex: 1 1 auto; }
}

/* ---------- Planilla de tareas por recinto en mobile: de tabla a "tarjetas" ----------
   Por debajo de ~700px, una tabla de 5 columnas (Tarea/Estado/Responsable/Fecha/Comentario) no
   entra sin scroll horizontal o celdas ilegibles. El <table class="table-tareas"> de recinto.php
   pasa cada <tr class="row-estado ..."> a un bloque tipo tarjeta: se oculta el <thead> (ya no hay
   columnas que alinear) y cada campo muestra su propia etiqueta (data-label, mismo texto que tenía
   la columna) arriba del valor — tanto en la fila editable (.field) como en la de solo lectura (td
   suelto). El tinte de fondo por estado y el acento de color siguen funcionando porque sigue siendo
   la MISMA fila (tr.row-estado-*), solo que ahora se dibuja como bloque en vez de fila de tabla. */
@media (max-width: 700px) {
  .table-tareas thead { display: none; }
  .table-tareas, .table-tareas tbody { display: block; width: 100%; }
  .table-tareas tr.row-estado {
    display: block;
    border: 1px solid var(--line-soft);
    border-radius: 10px;
    margin-bottom: 12px;
    overflow: hidden;
  }
  .table-tareas tr.row-estado:last-child { margin-bottom: 0; }
  .table-tareas td { display: block; width: auto; border-bottom: none; padding: 8px 14px; }
  .table-tareas td[colspan] { padding: 4px 14px 14px; }
  .table-tareas td.task-name { padding: 12px 14px 8px; font-weight: 600; }
  /* El acento de color pasa de la celda del nombre (una sola línea corta) a los 4px izquierdos de
     toda la tarjeta — se ve mejor como borde del bloque entero. Misma especificidad que la regla
     de desktop (tr.row-estado td.task-name) más el prefijo .table-tareas, así gana sin depender
     del orden en el archivo. */
  .table-tareas tr.row-estado td.task-name { border-left: none; }
  .table-tareas tr.row-estado { border-left: 4px solid transparent; }
  .table-tareas tr.row-estado-pendiente { border-left-color: var(--pendiente); }
  .table-tareas tr.row-estado-en_curso { border-left-color: var(--en_curso); }
  .table-tareas tr.row-estado-terminado { border-left-color: var(--terminado); }
  .table-tareas .field[data-label]::before,
  .table-tareas td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ink-faint);
    margin-bottom: 4px;
  }
}

/* ---------- Cualquier otra tabla en mobile: de tabla a "tarjetas" ----------
   Generalización de .table-tareas de arriba, para tablas que NO tienen tr.row-estado (Usuarios,
   Compras, y cualquier otra que lo necesite): agregar class="table-cards" a la <table> y
   data-label="..." a cada <td> (mismo texto que el <th> de esa columna). No depende de una clase
   particular en el <tr> — cualquier fila del <tbody> pasa a bloque, así también sirve para una
   fila de detalle expandible con colspan (ej. "Ver detalle" de Compras) sin tocar nada más.
   Felipe, feedback del 28/08: la tabla de Usuarios se sale de la pantalla en el celu, y pidió que
   Compras se vea como tarjetas igual que las tareas de los recintos. */
@media (max-width: 700px) {
  .table-cards thead { display: none; }
  .table-cards, .table-cards tbody { display: block; width: 100%; }
  .table-cards tbody tr {
    display: block;
    border: 1px solid var(--line-soft);
    border-radius: 10px;
    margin-bottom: 12px;
    overflow: hidden;
  }
  .table-cards tbody tr:last-child { margin-bottom: 0; }
  /* El atributo HTML `hidden` normalmente alcanza solo con display:none del navegador (especificidad
     muy baja) — la regla de arriba (.table-cards tbody tr { display:block }) es más específica y lo
     pisaba, así que una fila "hidden" (el detalle colapsado de "Ver detalle" en Compras) se seguía
     viendo igual, apenas se abría la página, sin importar el estado del botón. Felipe, feedback del
     28/08: "Cuando toco el botón Ver detalle o Cerrar en Compras en mobile no funciona bien". */
  .table-cards tbody tr[hidden] { display: none; }
  .table-cards td {
    display: block; width: auto; border-bottom: none; padding: 8px 14px;
    white-space: normal; /* pisa cualquier white-space:nowrap puesto para el layout de desktop */
  }
  .table-cards td[colspan] { padding: 10px 14px 14px; }
  .table-cards .field[data-label]::before,
  .table-cards td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ink-faint);
    margin-bottom: 4px;
  }
}

/* ---------- Botones ---------- */
button, .btn {
  background: var(--steel);
  color: #fff;
  border: none;
  padding: 9px 16px;
  border-radius: 7px;
  font-size: 0.88rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}
button:hover, .btn:hover { background: var(--steel-dark); }
.btn-secondary { background: var(--surface-card); color: var(--steel); border: 1px solid var(--steel); }
.btn-secondary:hover { background: var(--surface-sunken); }
.btn-danger { background: var(--vencido); }
.btn-danger:hover { background: #8f322a; }
.btn-sm { padding: 5px 10px; font-size: .76rem; border-radius: 6px; }

button:focus-visible, select:focus-visible, input:focus-visible, a:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.flash { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.9rem; }
.flash-ok { background: color-mix(in srgb, var(--certificado) 16%, var(--surface-card)); color: #1e5c3d; }
.flash-error { background: var(--vencido-bg); color: var(--vencido); }

/* ---------- Bot de Soporte (chat) — Felipe, 28/08: "lo ponemos como un Bot en donde cualquiera
   puede preguntar y vos... le respondes". Burbujas simples, sin JS de por medio (cada pregunta es
   un <form> normal que recarga la página, mismo criterio que el resto de la herramienta) — así se
   evita el tipo de bug de "no responde en mobile" que ya tuvimos con un toggle a medida. */
.chat-box { display: flex; flex-direction: column; gap: 10px; max-height: 480px; overflow-y: auto; padding: 4px 2px; margin-bottom: 14px; }
.chat-empty { color: var(--ink-faint); font-size: .88rem; padding: 8px 2px; }
.chat-msg { max-width: 82%; padding: 10px 14px; border-radius: 14px; font-size: .92rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: break-word; }
.chat-msg .quien { display: block; font-size: .66rem; opacity: .75; margin-bottom: 3px; text-transform: uppercase; letter-spacing: .04em; }
.chat-msg-user { align-self: flex-end; background: var(--steel); color: #fff; border-bottom-right-radius: 4px; }
.chat-msg-bot { align-self: flex-start; background: var(--surface-sunken); color: var(--ink); border-bottom-left-radius: 4px; }
.chat-propuesta { align-self: flex-start; max-width: 82%; background: var(--surface-card); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; margin-top: -2px; }
.chat-propuesta .cat { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint); }
.chat-propuesta .tit { font-weight: 700; margin: 2px 0 4px; }
.chat-propuesta .desc { font-size: .86rem; color: var(--ink-soft); margin-bottom: 10px; white-space: pre-wrap; }

/* ---------- Josema: ícono flotante del asistente, en TODAS las páginas (ver includes/footer.php
   -> bot_widget_html() en includes/bot.php). Felipe, 28/08 (segunda vuelta): "quisiera que este
   afuera como un icono de un robot flotante, abajo en el margen derecho" — mismo patrón de
   abrir/cerrar que .campanita-* de arriba, reutiliza .chat-box/.chat-msg/.chat-propuesta para la
   conversación en sí. */
.josema-wrap { position: fixed; right: 18px; bottom: 18px; z-index: 490; }
.josema-btn {
  width: 56px; height: 56px;
  border-radius: 999px;
  background: var(--steel);
  color: #fff;
  border: none;
  font-size: 1.6rem;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: var(--shadow), 0 12px 32px rgba(20,26,33,.28);
}
.josema-btn:hover { background: var(--steel-dark); }
.josema-panel {
  position: absolute; right: 0; bottom: calc(100% + 12px);
  width: min(380px, 92vw);
  max-height: min(78vh, 620px);
  overflow-y: auto;
  background: var(--surface-card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow), 0 12px 32px rgba(20,26,33,.28);
  z-index: 510;
  padding: 14px;
}
.josema-panel-titulo { font-size: 1rem; font-weight: 700; }
.josema-panel-subtitulo { font-size: .78rem; color: var(--ink-soft); margin-bottom: 8px; }
.josema-panel .chat-box { max-height: 46vh; }
.josema-form { display: flex; gap: 8px; }
.josema-form input[type="text"] { flex: 1; }
/* Felipe, 03/09: micrófono "mantener apretado para grabar, soltar para enviar" (ver footer.php,
   Pointer Events) — touch-action:none evita que el navegador interprete el toque sostenido como
   scroll/zoom, y user-select:none evita que el celular muestre su selección de texto o lupita en
   vez de dejar que el gesto llegue entero a nuestro código. display:flex centra el ícono SVG
   (antes era un emoji de texto, que se autocentraba solo). */
.josema-mic-btn { flex: 0 0 auto; padding: 5px 10px; line-height: 1; display: flex; align-items: center; justify-content: center; touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* Fase 17: el botón tiene DOS íconos <svg> adentro (mic + "enviar", ver bot_mensaje_html()) y
   footer.php alterna cuál se ve con el atributo `hidden` (setCandado()). A diferencia de un <div>
   o un <tr>, la regla nativa del navegador para [hidden] (display:none) no se aplica de forma
   confiable a elementos <svg> -- sin esto, quedaban los DOS íconos superpuestos y visibles todo el
   tiempo, con o sin el atributo puesto (mismo tipo de bug ya encontrado antes para
   .josema-record-ui/.josema-estado, solo que ahí eran <div>, no <svg>). */
.josema-mic-btn svg[hidden] { display: none; }
.josema-mic-btn.josema-mic-escuchando { background: var(--vencido); animation: josema-pulso 1.1s ease-in-out infinite; }
/* Felipe, 03/09 (segunda vuelta): modo "candado" (manos libres) -- un solo toque para arrancar a
   grabar sin mantener apretado, ver footer.php. Color distinto (--steel, no --vencido) para que se
   note que es un estado diferente al de "mantenido apretado ahora mismo": acá el dedo ya se soltó
   y la grabación sigue sola hasta el próximo toque. */
.josema-mic-btn.josema-mic-candado { background: var(--steel); animation: josema-pulso 1.1s ease-in-out infinite; }
@keyframes josema-pulso {
  0%, 100% { box-shadow: 0 0 0 0 rgba(174, 63, 53, .55); }
  50% { box-shadow: 0 0 0 7px rgba(174, 63, 53, 0); }
}
/* Felipe, 29/08: ni "grabando" (audio para Josema) ni "pensando" (esperando la respuesta real del
   modelo) se notaban antes — este renglón, entre el historial de mensajes y el formulario, muestra
   un texto + un puntito animado mientras cualquiera de los dos está en curso (ver footer.php). El
   caso de "grabando" ahora usa su propia fila más completa (.josema-record-ui, más abajo) — este
   renglón genérico sigue vivo para "pensando" / "transcribiendo" / permiso de micrófono denegado. */
.josema-estado { display: flex; align-items: center; gap: 7px; font-size: .78rem; color: var(--ink-soft); padding: 0 2px 8px; }
.josema-estado .punto { width: 8px; height: 8px; border-radius: 999px; background: currentColor; flex: none; animation: josema-titilar 1s ease-in-out infinite; }
.josema-estado.josema-escuchando { color: var(--vencido); }
@keyframes josema-titilar { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

/* Fase 9.5 — Felipe, 29/08: "quisiera que el micrófono se vea así como en WhatsApp, que cuando uno
   habla se vea. Y lo mismo para cuando responde Josema con audio". .wavebar es la unidad compartida
   por los dos casos (grabando / escuchando) — footer.php arma la fila de barras y les cambia la
   altura en vivo leyendo el audio real (Web Audio API), esto solo define su aspecto. */
.josema-wave { display: flex; align-items: center; gap: 2px; height: 22px; flex: 1 1 auto; min-width: 0; }
.josema-wave .wavebar { flex: 1 1 auto; width: 3px; max-width: 4px; border-radius: 999px; background: var(--ink-faint); height: 10%; transition: height 90ms linear; }

/* Fila que reemplaza al aviso de solo texto mientras se está grabando un audio para Josema.
   Encontrado al revisar la Fase 16 (no reportado por Felipe): esta fila (y .josema-estado, más
   arriba) se ocultan con el atributo `hidden` desde JS, pero `display: flex` acá gana en
   especificidad a la regla nativa del navegador para [hidden] (display:none, por atributo) — el
   mismo problema que ya está resuelto en otros lados de este archivo (buscar ".campanita-badge" o
   "tr[hidden]"), solo que a esta fila y a .josema-estado se les había pasado por alto. Sin este
   agregado, la fila de grabación (con su "0:00" y la ola plana) quedaba SIEMPRE visible en el panel
   de Josema, incluso sin estar grabando nada. */
.josema-record-ui { display: flex; align-items: center; gap: 8px; padding: 2px 2px 10px; }
.josema-record-ui[hidden], .josema-estado[hidden] { display: none; }
.josema-record-timer { font-family: "IBM Plex Mono", monospace; font-size: .78rem; color: var(--vencido); flex: none; min-width: 30px; }
.josema-record-ui .wavebar { background: var(--vencido); }

/* Fase 9.4/9.5: nota de voz con la respuesta hablada de Josema — reemplaza al botón fijo "🔊
   Escuchar" que había antes; ahora es play/pausa + la ola moviéndose en vivo + el tiempo restante,
   más parecido a una nota de voz real. */
.josema-voice-bar { display: flex; align-items: center; gap: 8px; margin-top: 4px; padding: 6px 10px; background: var(--surface-sunken); border-radius: 999px; max-width: 260px; }
.josema-voice-play { flex: none; width: 30px; height: 30px; padding: 0; border-radius: 999px; font-size: .82rem; line-height: 1; display: flex; align-items: center; justify-content: center; }
.josema-voice-bar .wavebar { background: var(--steel); }
.josema-voice-time { font-family: "IBM Plex Mono", monospace; font-size: .72rem; color: var(--ink-soft); flex: none; }
@media (max-width: 640px) {
  .josema-wrap { right: 12px; bottom: 12px; }
  .josema-panel { position: fixed; left: 10px; right: 10px; bottom: 84px; width: auto; }
  .josema-panel .chat-box { max-height: 38vh; }
}

/* ---------- Notificación flotante ("toast") de una confirmación/guardado — Felipe, 27/08: la
   notificación inline corría todo el contenido de abajo y, como cada acción recarga la página,
   el navegador volvía siempre al principio, obligando a hacer scroll de nuevo hasta donde se
   estaba. .flash-toast saca la notificación del flujo normal (no empuja nada) y flota abajo,
   centrada, apagándose sola — la posición de scroll se restaura aparte (ver footer.php). Solo se
   agrega esta clase a los mensajes de una sola vez (flash_get()); los avisos permanentes de "modo
   lectura" siguen con el .flash de siempre, fijos en su lugar. */
.flash-toast {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 500;
  margin: 0;
  box-shadow: 0 8px 24px rgba(20, 26, 33, .22);
  width: max-content;
  max-width: min(90vw, 480px);
  animation: flash-toast-in .18s ease-out both, flash-toast-out .4s ease-in 4.2s forwards;
}
@keyframes flash-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes flash-toast-out {
  from { opacity: 1; }
  to { opacity: 0; visibility: hidden; }
}
@media (max-width: 560px) {
  .flash-toast { bottom: 12px; max-width: calc(100vw - 24px); }
}

/* Toast "push simulado" (ver push_flash_set/push_flash_get en includes/notificaciones.php):
   muestra, a quien acaba de disparar una acción, una demostración de lo que le llegaría al
   PRÓXIMO responsable a su celular una vez que Web Push esté conectado de verdad — a propósito
   con otro lenguaje visual (arriba, tipo notificación de teléfono) que el flash-toast de "se
   guardó" (abajo, centrado), para que no se confundan. Misma animación por CSS que .flash-toast:
   no necesita JS, se apaga sola. */
.push-toast {
  position: fixed; top: 14px; left: 50%;
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--surface-card); color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  width: min(360px, 92vw);
  box-shadow: 0 10px 28px rgba(20,26,33,.28);
  z-index: 600;
  animation: push-toast-in .22s ease-out both, push-toast-out .4s ease-in 4.2s forwards;
}
@keyframes push-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(-16px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes push-toast-out {
  from { opacity: 1; }
  to { opacity: 0; visibility: hidden; }
}
.push-toast-icon { font-size: 1.3rem; line-height: 1; flex: none; margin-top: 1px; }
.push-toast-app { font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint); }
.push-toast-title { font-size: .87rem; font-weight: 700; margin-top: 2px; }
.push-toast-msg { font-size: .8rem; color: var(--ink-soft); margin-top: 2px; }
@media (max-width: 560px) {
  .push-toast { width: calc(100vw - 24px); }
}

/* ---------- Login ---------- */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, var(--steel), var(--steel-dark));
  padding: 20px;
}
.login-card {
  background: var(--surface-card);
  border-radius: 12px;
  padding: 34px 30px;
  max-width: 380px;
  width: 100%;
  box-shadow: var(--shadow);
}
.login-card h1 { color: var(--ink); font-size: 1.3rem; }
.login-card .subtitle { margin-bottom: 22px; }
.login-logo { display: block; height: 46px; width: auto; margin: 0 auto 14px; }

/* ---------- Stats / tickers ---------- */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stat-tile {
  background: var(--surface-card);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px;
  box-shadow: var(--shadow);
  text-align: center;
}
.stat-tile .num { font-family: "IBM Plex Mono", monospace; font-size: 1.5rem; font-weight: 600; line-height: 1; color: var(--ink); }
.stat-tile .lbl { font-size: .76rem; color: var(--ink-soft); margin-top: 4px; text-transform: uppercase; letter-spacing: .04em; }

/* Felipe, 02/09: los tickets de "Por Recintos" (Tareas totales/Terminadas/Vencidas/Próximas a
   vencer) pasan de <div> a <button> para poder hacer clic y ver la lista de tareas de cada uno —
   la regla genérica "button, .btn" de más abajo pone fondo sólido y texto blanco; esto la resetea
   para que se sigan viendo IGUAL que antes (fondo de tarjeta, texto oscuro), más un cursor/hover
   que avisa que ahora son clicables (mismo criterio que .recinto-card:hover). */
.stat-tile-btn { display: block; width: 100%; font: inherit; cursor: pointer; }
/* Felipe, 03/09: "en Por Recintos cuando paso el mouse por arriba de tareas totales, terminadas,
   etc, se ve muy oscuro" — mismo problema de fondo que .esquema-detalle-link (ver más abajo en este
   archivo): el hover genérico de "button" pinta var(--steel-dark) detrás, y acá nada lo estaba
   pisando, así que la tarjeta entera se oscurecía con el número/texto (que se quedan en var(--ink),
   pensados para el fondo claro de siempre) casi ilegibles encima. */
.stat-tile-btn:hover { border-color: var(--steel); background: var(--surface-sunken); }

/* ---------- Esquemas / stock ---------- */
.capa-row { padding: 10px 0; border-top: 1px solid var(--line-soft); margin-top: 10px; }
.capa-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.capa-head h3 { font-family: "Public Sans", sans-serif; font-weight: 700; font-size: .94rem; margin: 0; }

.tag-fuente { font-size: .66rem; padding: 2px 9px; border-radius: 10px; font-weight: 700; letter-spacing: .02em; white-space: nowrap; }
.tag-fuente-sourced { background: color-mix(in srgb, var(--certificado) 16%, transparent); color: var(--certificado); }
.tag-fuente-estimado { background: color-mix(in srgb, var(--en_curso) 16%, transparent); color: var(--en_curso); }
.tag-fuente-tbd { background: var(--surface-sunken); color: var(--ink-soft); }

.warn-box {
  background: var(--vencido-bg); border: 1px solid var(--vencido); color: var(--ink);
  border-radius: 8px; padding: 9px 12px; font-size: .84rem; margin: 8px 0;
}

.log-entry { font-size: .84rem; color: var(--ink-soft); padding: 7px 0; border-bottom: 1px dashed var(--line-soft); display: flex; gap: 10px; }
.log-entry:last-child { border-bottom: none; }
.log-entry .t { font-family: "IBM Plex Mono", monospace; color: var(--ink-faint); white-space: nowrap; font-size: .76rem; }

/* ---------- Certificación ---------- */
.cert-card { border: 1px solid var(--line-soft); border-radius: 10px; padding: 14px 16px; margin-bottom: 14px; }
.cert-card:last-child { margin-bottom: 0; }
.cert-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }
.cert-head strong { font-family: "Barlow Semi Condensed", sans-serif; font-weight: 700; font-size: 1rem; }
.cert-montos { font-size: .84rem; margin: 10px 0; color: var(--ink-soft); }
.cert-meta { font-size: .78rem; margin: 8px 0; color: var(--ink-faint); }
.cert-actions { margin-top: 8px; }
.cert-email { margin-top: 10px; font-size: .82rem; color: var(--ink-soft); }
.cert-email summary { cursor: pointer; color: var(--steel); }
.cert-email pre { white-space: pre-wrap; background: var(--surface-sunken); border-radius: 8px; padding: 10px; font-size: .78rem; margin-top: 6px; }

/* ---------- Fase 2: avatar de empleado (Empleados / Mi Perfil) ---------- */
.avatar { border-radius: 50%; object-fit: cover; display: block; border: 1px solid var(--line); background: var(--surface-sunken); }
.avatar-fallback { border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--accent); background: var(--accent-soft); border: 1px solid var(--line); }
.avatar-file-field { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.avatar-file-field input[type="file"] { font-size: .72rem; max-width: 150px; }
.avatar-file-field label { display: flex; align-items: center; gap: 4px; font-size: .74rem; color: var(--ink-soft); }

/* ---------- Fase 4: Compras — secciones de acción coloreadas por estado (mismo criterio que
   compraSeccionHtml() en la maqueta: cada acción vive en su propia caja, para no confundir
   "Guardar" con "Agregar presupuesto" con "Marcar comprada") ---------- */
.compra-seccion { margin: 0 0 10px; padding: 10px 12px; border-radius: 8px; }
.compra-seccion .compra-seccion-titulo { font-size: .76rem; text-transform: uppercase; letter-spacing: .02em; }
.compra-fila-expandida { background: var(--surface-sunken); }
/* Algunos navegadores (Safari viejo) no aplican bien [hidden] a un <tr> por el display:table-row
   del user-agent — se lo dejamos explícito para que "Cerrar" oculte la fila de verdad. */
tr[hidden] { display: none; }

/* ---------- Fase 4: Orden de Compra — documento formal, mismas clases .oc-* que la maqueta.
   Colores fijos (no var(--...)) y fondo blanco siempre, sin importar el tema claro/oscuro: puede
   terminar impreso o en manos de un proveedor por fuera de la app. ---------- */
.oc-doc {
  max-width: 720px; margin: 0 auto; background: #fff; color: #1a2233; border-radius: 12px;
  padding: 26px 30px 30px; font-family: Arial, Helvetica, sans-serif; border: 1px solid var(--line);
}
.oc-toolbar { display: flex; justify-content: center; gap: 8px; max-width: 720px; margin: 16px auto 0; flex-wrap: wrap; }
.oc-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.oc-head-left { display: flex; align-items: center; gap: 12px; }
.oc-logo { height: 52px; width: auto; display: block; }
.oc-empresa { font-size: 1.05rem; font-weight: 700; }
.oc-empresa-sub { font-size: .8rem; color: #5a6472; }
.oc-head-right { text-align: right; }
.oc-titulo { font-size: 1.15rem; font-weight: 700; letter-spacing: .03em; }
.oc-numero { font-size: .92rem; font-weight: 600; color: #2b6cb0; margin-top: 2px; }
.oc-fecha { font-size: .8rem; color: #5a6472; margin-top: 2px; }
.oc-rule { border: none; border-top: 2px solid #1a2233; margin: 16px 0 18px; }
.oc-proveedor { margin-bottom: 16px; }
.oc-label { color: #5a6472; font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; }
.oc-proveedor-nombre { font-size: 1.05rem; font-weight: 700; margin-top: 2px; }
.oc-contacto { font-size: .8rem; color: #5a6472; margin-top: 4px; }
.oc-iva-nota { font-size: .78rem; color: #5a6472; margin: -8px 0 16px; }
.oc-tabla { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
.oc-tabla th { text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; color: #5a6472; padding: 8px 10px; border-bottom: 2px solid #1a2233; }
.oc-tabla td { padding: 10px; border-bottom: 1px solid #ccd2da; font-size: .9rem; vertical-align: top; }
.oc-muted { color: #5a6472; font-size: .8rem; }
.oc-monto { text-align: right; font-weight: 600; white-space: nowrap; }
.oc-total-label { text-align: right; font-weight: 700; border-bottom: none !important; padding-top: 12px !important; }
.oc-total-monto { text-align: right; font-weight: 700; font-size: 1.1rem; border-bottom: none !important; padding-top: 12px !important; }
.oc-meta { border-collapse: collapse; }
.oc-meta td { padding: 4px 10px 4px 0; font-size: .85rem; border: none; }
.oc-meta .oc-label { width: 140px; padding-top: 4px; }
.oc-firma { margin-top: 56px; display: flex; gap: 40px; }
.oc-firma div { flex: 1; border-top: 1px solid #1a2233; padding-top: 6px; text-align: center; font-size: .8rem; color: #5a6472; }
.oc-footer { margin-top: 30px; font-size: .72rem; color: #8891a0; }

/* Mobile: la Orden de Compra es un documento pensado para verse igual impreso — el encabezado
   pasa a apilarse. La tabla de ítems (normalmente una sola fila: Concepto/Cantidad/Detalle/Monto,
   4 columnas) NO alcanza a entrar ni con scroll horizontal — adentro del modal el contenido queda
   en ~270px de ancho, y un scroll ahí es fácil de no notar (cortaba la última columna a la mitad,
   sin ninguna pista de que había más para el costado). Primera vuelta: se probó con
   .oc-tabla-wrap { overflow-x:auto } + min-width en la tabla — Felipe, feedback del 28/08 después
   de probarlo: seguía viéndose mal. Ahora la fila de ítems se apila como mini tarjeta (mismo
   criterio que .table-cards, con los colores fijos del documento — no usa var(--...), ver nota
   arriba). El pie (Subtotal/IVA/Total) ya era de 2 columnas nomás, así que solo pasa a fila
   flex (label a la izquierda, monto a la derecha) en vez de apilarse. */
@media (max-width: 640px) {
  .oc-doc { padding: 16px; }
  .oc-head { flex-direction: column; }
  .oc-head-right { text-align: left; }
  .oc-tabla-wrap { overflow-x: visible; }
  .oc-tabla { min-width: 0; }
  .oc-tabla, .oc-tabla tbody { display: block; width: 100%; }
  .oc-tabla thead { display: none; }
  .oc-tabla tbody tr { display: block; border-bottom: 1px solid #ccd2da; padding-bottom: 6px; margin-bottom: 8px; }
  .oc-tabla tbody td {
    display: block; width: auto; border-bottom: none; padding: 5px 0;
  }
  .oc-tabla tbody td[data-label]::before {
    content: attr(data-label);
    display: block; font-size: .68rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .04em; color: #8891a0; margin-bottom: 2px;
  }
  .oc-tabla tfoot tr { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .oc-tabla tfoot td { display: block; width: auto; border-bottom: none; }
  .oc-tabla tfoot td.oc-total-label { text-align: left; }
  .oc-firma { flex-direction: column; gap: 22px; margin-top: 34px; }
}

/* Imprimir/descargar la OC desde el modal genérico (#modalRoot): "truco de imprimir un solo
   elemento" — se apaga todo lo que NO sea el modal abierto, y el modal pasa a fluir como una
   página normal en vez de quedar centrado/recortado a la ventana. Mismo criterio que
   #ordenCompraOverlay en la maqueta, generalizado al modal genérico ya existente en la app. */
@media print {
  body > *:not(#modalRoot) { display: none !important; }
  .modal-backdrop { position: static !important; inset: auto; background: none !important; padding: 0 !important; display: block !important; }
  .modal-box { max-width: none !important; max-height: none !important; box-shadow: none !important; border-radius: 0 !important; }
  .modal-close, .no-print { display: none !important; }
}
