:root {
  --primary: #0047FF;
  --primary-dark: #0033CC;
  --primary-light: #3B82F6;
  --primary-gradient: linear-gradient(135deg, #3B82F6, #0033CC);
  --sidebar-bg: #07102B;
  --sidebar-hover: #0D1F4A;
  --sidebar-active: #0047FF;
  --surface: #FFFFFF;
  --surface-2: #F5F7FF;
  --surface-3: #EEF2FF;
  --border: #E2E8F0;
  --text: #0F172A;
  --text-secondary: #475569;
  --text-muted: #94A3B8;
  --success: #10B981;
  --warning: #F59E0B;
  --danger: #EF4444;
  --info: #3B82F6;
  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 1px 3px rgba(0,0,0,.08), 0 4px 16px rgba(0,0,0,.06);
  --shadow-md: 0 4px 6px rgba(0,0,0,.07), 0 10px 40px rgba(0,0,0,.1);
  --shadow-lg: 0 20px 60px rgba(0,71,255,.15);
  --transition: .2s cubic-bezier(.4,0,.2,1);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* El `display` de la hoja del navegador para [hidden] lo pisa cualquier clase
   nuestra (.btn, .lightbox-nav...), así que el atributo se refuerza aquí. */
[hidden] { display: none !important; }

html { font-size: 15px; }

body {
  font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
  background: var(--surface-2);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }

h1 { font-size: 1.5rem; font-weight: 700; }
h2 { font-size: 1.25rem; font-weight: 600; }
h3 { font-size: 1rem; font-weight: 600; }
a { color: var(--primary); text-decoration: none; }

/* ── Buttons ── */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 20px; border-radius: 4px;
  font-size: .875rem; font-weight: 600; cursor: pointer;
  border: none; transition: var(--transition); text-decoration: none;
  white-space: nowrap;
}
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { filter: brightness(1.1); }
.btn-secondary { background: var(--surface-3); color: var(--primary); }
.btn-secondary:hover { filter: brightness(.96); }
.btn-ghost { background: var(--surface-3); color: var(--text-secondary); border: 1px solid var(--border); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-ghost.btn-icon { background: transparent; border: none; }
.btn-ghost.btn-icon:hover { background: var(--surface-2); }
.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(1.1); }
.btn-sm { padding: 6px 14px; font-size: .8rem; }
.btn-icon { padding: 8px; border-radius: 4px; }
.btn:disabled { opacity: .55; cursor: not-allowed; }

/* ── Inputs ── */
.input-group { display: flex; flex-direction: column; gap: 6px; }
.input-group label { font-size: .8rem; font-weight: 600; color: var(--text-secondary); letter-spacing: .4px; }
.input-hint { font-size: .72rem; color: var(--text-muted); line-height: 1.4; }
.input, select.input, textarea.input {
  padding: 11px 14px; border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); font-size: .9rem; color: var(--text);
  background: var(--surface); transition: var(--transition); outline: none; width: 100%;
  font-family: inherit;
}
.input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(0,71,255,.1); }
.form-fields { display: flex; flex-direction: column; gap: 18px; }
.input-with-eye { position: relative; }
.input-with-eye .input { padding-right: 42px; }
.input-eye {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border: none; border-radius: 6px;
  background: none; color: var(--text-muted); cursor: pointer; transition: var(--transition);
}
.input-eye:hover { background: var(--surface-2); color: var(--text-secondary); }
.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: .875rem; }
.checkbox-row input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--primary); cursor: pointer; }

/* ── Form page (crear/editar de página completa) ── */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.form-grid .span2 { grid-column: span 2; }
.form-page-header { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.form-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 16px; }

/* ── Cards ── */
.card { background: var(--surface); border-radius: var(--radius); border: 1px solid var(--border); padding: 20px; }
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; gap: 12px; flex-wrap: wrap; }
/* Cabecera con más de un control a la derecha (un filtro y el botón de alta). */
.card-header-tools { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.card + .card { margin-top: 16px; }
/* Un contenedor de tarjetas (las que se repintan solas) debe mantener el mismo
   ritmo vertical: el div intermedio no puede romper el `.card + .card`. */
.card + .card-stack > .card:first-child,
.card-stack + .card { margin-top: 16px; }

/* ── Card grid (listados en tarjetas) ── */
/* `min(100%, 280px)`: con `minmax(280px, ...)` a secas la pista conserva sus
   280px en una pantalla de 320px y la tarjeta desborda a lo ancho. */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 16px; }
.card-grid > .card { margin-top: 0; }
.card-clickable { cursor: pointer; transition: border-color .15s; }
.card-clickable:hover { border-color: var(--primary); }

/* Rótulo que separa dos bloques de una misma pantalla (tarjetas arriba,
   listado abajo). Va en versales y en gris: nombra el grupo sin competir con
   los títulos de las tarjetas que tiene debajo. */
.section-title { margin: 26px 0 12px; font-size: .78rem; font-weight: 600; color: var(--text-muted);
                 text-transform: uppercase; letter-spacing: .06em; }
.section-title:first-child { margin-top: 0; }

/* ── Stats grid (dashboard) ── */
/* La tarjeta es una pieza de color, no una tarjeta blanca más: rótulo arriba,
   cifra grande debajo y el ícono en un círculo a la derecha. El color lo pone
   quien la crea (`--stat-bg`) y sigue siendo el semántico de cada estado —
   verde completada, rojo con novedad — para que la lectura de un vistazo
   coincida con la de las insignias del resto de la app. */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 16px; margin-bottom: 16px; }
.stat-card {
  position: relative; overflow: hidden;
  background: var(--stat-bg, var(--primary-gradient));
  border-radius: var(--radius); border: 0; padding: 18px 20px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  color: #fff; box-shadow: var(--shadow);
}
/* La onda de fondo: una elipse muy ancha asomando por abajo. Es decoración,
   así que va detrás del contenido y no captura el puntero. */
.stat-card::after {
  content: ''; position: absolute; z-index: 0; pointer-events: none;
  left: -25%; bottom: -155%; width: 150%; aspect-ratio: 1 / .62;
  border-radius: 50%; background: rgba(255,255,255,.1);
  transform: rotate(-6deg);
}
.stat-card .stat-texts { position: relative; z-index: 1; min-width: 0; }
.stat-card .stat-label { font-size: .72rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: rgba(255,255,255,.92); }
.stat-card .stat-value { font-size: 2rem; font-weight: 800; line-height: 1.15; margin-top: 4px; }
.stat-card .stat-icon {
  position: relative; z-index: 1; flex-shrink: 0;
  width: 48px; height: 48px; border-radius: 50%;
  background: rgba(255,255,255,.2); color: #fff;
  display: flex; align-items: center; justify-content: center;
}

/* ── Badge ── */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 99px; font-size: .75rem; font-weight: 600; }
.badge-blue { background: #EEF2FF; color: var(--primary); }
.badge-green { background: #ECFDF5; color: var(--success); }
.badge-yellow { background: #FFFBEB; color: var(--warning); }
.badge-red { background: #FEF2F2; color: var(--danger); }
.badge-gray { background: var(--surface-3); color: var(--text-secondary); }
.badge-dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }

/* ── Avatar ── */
.avatar { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: .8rem; flex-shrink: 0; background: var(--primary-gradient); color: #fff; }
.avatar-lg { width: 44px; height: 44px; font-size: .95rem; }
.avatar-sm { width: 28px; height: 28px; font-size: .7rem; }

/* ── App shell / sidebar ── */
/* `100dvh` además de `100vh`: en el navegador móvil la barra de URL se recoge
   al desplazar y con `100vh` el pie de la app queda cortado. El `100vh` se
   deja como respaldo para los navegadores sin `dvh`. */
.app-shell { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }
.sidebar { width: 240px; flex-shrink: 0; background: var(--sidebar-bg); display: flex; flex-direction: column; overflow: hidden; transition: width var(--transition); }
/* Plegado a mano con el botón de la topbar: solo íconos. En móvil esta clase
   no manda — ahí el sidebar es un cajón deslizante (ver bloque responsive). */
.sidebar.collapsed { width: 72px; }
.sidebar.collapsed .sidebar-logo-text,
.sidebar.collapsed .nav-label,
.sidebar.collapsed .nav-section-label,
.sidebar.collapsed .user-info { display: none; }
.sidebar.collapsed .sidebar-logo,
.sidebar.collapsed .user-pill { justify-content: center; }
/* Anclado a los bordes de un sidebar de 72px el menú de usuario sería
   ilegible: se suelta del borde derecho y toma su propio ancho. */
.sidebar.collapsed .user-menu { right: auto; width: 210px; }
/* Fondo oscuro del cajón. Solo existe en móvil (ver bloque responsive). */
.sidebar-backdrop { display: none; }
.sidebar-logo { padding: 16px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid rgba(255,255,255,.07); flex-shrink: 0; }
.sidebar-logo-mark { width: 32px; height: 32px; border-radius: 9px; background: var(--primary-gradient); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 800; flex-shrink: 0; }
.sidebar-logo-text { font-size: 1.05rem; font-weight: 800; color: #fff; white-space: nowrap; overflow: hidden; }
.sidebar-nav { flex: 1; overflow-y: auto; padding: 12px 8px; }
.nav-section-label { padding: 8px 10px 4px; font-size: .65rem; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; color: rgba(255,255,255,.3); }
.nav-item { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: var(--radius-sm); color: rgba(255,255,255,.6); text-decoration: none; font-size: .8125rem; font-weight: 500; cursor: pointer; transition: var(--transition); white-space: nowrap; }
.nav-item:hover { background: var(--sidebar-hover); color: #fff; }
.nav-item.active { background: var(--sidebar-active); color: #fff; box-shadow: 0 4px 12px rgba(0,71,255,.4); }
.nav-item svg { flex-shrink: 0; }
.sidebar-footer { padding: 12px 8px; border-top: 1px solid rgba(255,255,255,.07); position: relative; }
.user-pill { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm); cursor: pointer; transition: var(--transition); }
.user-pill:hover { background: var(--sidebar-hover); }
.user-info { overflow: hidden; flex: 1; }
.user-info .name { font-size: .85rem; font-weight: 600; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-info .role { font-size: .72rem; color: rgba(255,255,255,.4); white-space: nowrap; }
.user-menu { position: absolute; bottom: calc(100% + 6px); left: 8px; right: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: 0 -4px 16px rgba(0,0,0,.15); z-index: 200; overflow: hidden; }
.user-menu-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; font-size: .875rem; color: var(--text); cursor: pointer; transition: background .15s; }
.user-menu-item:hover { background: var(--surface-3); }
.user-menu-danger { color: #ef4444 !important; }
.user-menu-danger:hover { background: rgba(239,68,68,.08) !important; }

.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.topbar { height: 60px; background: var(--surface); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 24px; gap: 16px; flex-shrink: 0; }
.topbar-title { font-weight: 700; font-size: 1rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.toggle-sidebar { flex-shrink: 0; }
.topbar-spacer { flex: 1; }
.page { flex: 1; overflow-y: auto; padding: 24px; }

/* ── Filter pills ── */
.filter-bar { display: flex; gap: 6px; margin-bottom: 16px; flex-wrap: wrap; }
.filter-pill { padding: 5px 14px; border-radius: 99px; font-size: .8rem; font-weight: 600; cursor: pointer; border: 1.5px solid var(--border); background: var(--surface); color: var(--text-secondary); white-space: nowrap; transition: var(--transition); }
.filter-pill:hover { border-color: var(--primary); color: var(--primary); }
.filter-pill.active { border-color: var(--primary); background: #EEF2FF; color: var(--primary); }

/* ── Tables ── */
/* `.table-wrap` solo maneja el scroll horizontal; el borde/fondo/radio los da
   `.card` (o `.table-card` si la tabla no está ya dentro de una) para que la
   barra de paginación quede dentro de la misma caja, como en OmniPRIT. */
.table-card { background: var(--surface); border-radius: var(--radius); border: 1px solid var(--border); overflow: hidden; }
.table-wrap { overflow-x: auto; }
table { width: max-content; min-width: 100%; border-collapse: collapse; font-size: .875rem; }
thead th { padding: 10px 16px; text-align: left; font-size: .75rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; border-bottom: 1px solid var(--border); background: var(--surface-2); white-space: nowrap; }
tbody td { padding: 13px 16px; border-bottom: 1px solid var(--border); color: var(--text); white-space: nowrap; }
tbody tr:hover td { background: var(--surface-2); }
tbody tr:last-child td { border-bottom: none; }
/* El pie de tabla (totales) repite el padding de tbody: sin él las cifras
   quedan 16px corridas respecto a la columna que suman. */
tfoot td { padding: 13px 16px; border-top: 1px solid var(--border); color: var(--text); white-space: nowrap; }
/* Columna de acciones fija a la derecha al hacer scroll horizontal — se
   reconoce por los botones que contiene, no por ser la última columna (una
   tabla sin acciones no debe quedar con la última columna fija). */
.table-wrap thead:has(~ tbody td:last-child :is(button, .btn)) th:last-child,
.table-wrap tbody td:last-child:has(:is(button, .btn)) { position: sticky; right: 0; z-index: 2; box-shadow: -2px 0 6px rgba(0,0,0,.06); text-align: center; }
.table-wrap thead:has(~ tbody td:last-child :is(button, .btn)) th:last-child { background: var(--surface-2); }
.table-wrap tbody td:last-child:has(:is(button, .btn)) { background: var(--surface); }
.table-wrap tbody tr:hover td:last-child:has(:is(button, .btn)) { background: var(--surface-2); }
.table-wrap tbody td:last-child:has(:is(button, .btn)) > div { justify-content: center; }
/* Si la columna de acciones queda fija al hacer scroll horizontal, la celda
   equivalente del pie tiene que quedarse fija también: si no, el total se
   despega de su fila al desplazar. */
.table-wrap:has(tbody td:last-child :is(button, .btn)) tfoot td:last-child {
  position: sticky; right: 0; z-index: 2; background: var(--surface); box-shadow: -2px 0 6px rgba(0,0,0,.06);
}
.row-link { cursor: pointer; }
/* Asa para reordenar filas (actividades del subproyecto). `touch-action: none`
   no es cosmético: sin él, arrastrar con el dedo desplaza la página en vez de
   mover la fila y no se puede reordenar desde el celular. */
.col-drag { width: 1%; padding-left: 12px; padding-right: 0; }
.drag-handle {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 4px; border-radius: 6px; color: var(--text-muted);
  cursor: grab; touch-action: none; user-select: none;
}
.drag-handle:hover { color: var(--text-secondary); background: var(--surface-2); }
tbody tr.dragging { opacity: .55; }
tbody tr.dragging .drag-handle { cursor: grabbing; }
tbody tr.dragging td { background: var(--surface-2); }
.row-actions { display: flex; gap: 6px; }
.empty-state { padding: 48px 24px; text-align: center; color: var(--text-muted); }

/* ── Paginación ── */
.pg-bar { display: flex; align-items: center; gap: 16px; padding: 10px 16px; border-top: 1px solid var(--border); font-size: .8rem; color: var(--text-muted); flex-wrap: wrap; }
.pg-info { margin-right: auto; }
.pg-size { display: flex; align-items: center; gap: 6px; }
.pg-size select { padding: 3px 6px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: .8rem; background: var(--surface); color: var(--text); cursor: pointer; }
.pg-nav { display: flex; align-items: center; gap: 2px; }
.pg-nav span { padding: 0 8px; font-size: .82rem; }
.pg-nav button { width: 28px; height: 28px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: var(--transition); }
.pg-nav button:hover:not(:disabled) { background: var(--surface-2); }
.pg-nav button:disabled { opacity: .35; cursor: not-allowed; }

/* ── Línea de tiempo del proyecto (modal) ── */
/* Las tres columnas (nombre · fechas · pista) se declaran una sola vez, en la
   rejilla, y la superposición de la cuadrícula se alinea con ellas midiendo
   desde las mismas variables. */
.tl { --tl-name: 200px; --tl-dates: 100px; --tl-gap: 12px;
  /* `--tl-track-min` lo fija el JS con las casillas de la escala elegida: si
     no caben, el gráfico crece y se desplaza en vez de apretarlas. */
  min-width: calc(var(--tl-name) + var(--tl-dates) + var(--tl-gap) * 2 + var(--tl-track-min, 400px)); }
/* La pista necesita ancho real para que las barras se distingan: si no cabe,
   se desplaza a lo horizontal en vez de comprimirse. */
.tl-scroll { overflow-x: auto; padding-bottom: 4px; }
.tl-head, .tl-row { display: grid; grid-template-columns: var(--tl-name) var(--tl-dates) 1fr; gap: var(--tl-gap); align-items: center; }
.tl-head { padding-bottom: 6px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.tl-head-cell { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); }
.tl-row { padding: 4px 0; position: relative; z-index: 1; }
.tl-name { min-width: 0; display: flex; flex-direction: column; }
.tl-name-main { font-size: .8rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-name-sub { font-size: .7rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-dates { font-size: .73rem; color: var(--text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Cabecera en dos niveles: arriba la unidad gruesa (mes, o año si la escala ya
   es mensual) y abajo la casilla de la escala elegida. Así el rótulo fino no
   tiene que repetir el mes en cada celda. Cada caja se posiciona sobre la misma
   escala que las barras, de modo que el rótulo cae encima del tramo que nombra. */
.tl-months { position: relative; height: 22px; }
.tl-month { position: absolute; top: 0; bottom: 0; display: flex; align-items: center; justify-content: center;
  font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-secondary); border-left: 1px solid var(--border); overflow: hidden; }
.tl-month:first-child { border-left: none; }
.tl-ticks { position: relative; height: 20px; }
.tl-tick { position: absolute; top: 0; bottom: 0; display: flex; align-items: center; justify-content: center;
  border-left: 1px solid var(--border); overflow: hidden; }
.tl-tick:first-child { border-left: none; }
.tl-tick.fuerte { border-left-color: var(--text-muted); }
.tl-tick.finde { background: var(--surface-2); }
/* El rótulo se recorta solo: una casilla estrecha muestra menos texto en vez
   de desbordar sobre la vecina. */
.tl-tick span { font-size: .66rem; font-weight: 600; color: var(--text-muted);
  overflow: hidden; text-overflow: clip; white-space: nowrap; padding: 0 2px; }

/* La cuadrícula va una sola vez sobre todas las filas, no repetida en cada
   pista: son decenas de líneas idénticas. */
/* El hueco de arriba es donde se apoya el rótulo "hoy": sin él se montaba
   sobre la cabecera de meses. */
.tl-body { position: relative; padding-top: 16px; }
/* La rejilla va POR ENCIMA de las filas (z-index): debajo, el fondo de cada
   pista la tapaba y las líneas solo asomaban en los huecos entre filas. Va
   atenuada para que cruzar una barra no la parta visualmente. */
.tl-overlay { position: absolute; top: 0; bottom: 0; right: 0; z-index: 2;
  left: calc(var(--tl-name) + var(--tl-dates) + var(--tl-gap) * 2); pointer-events: none; }
.tl-gridline { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--text-muted); opacity: .18; }
/* Inicio de mes (o de año en escala mensual): la referencia gruesa. */
.tl-gridline.fuerte { background: var(--border); opacity: .9; }
/* Sábado y domingo, solo en escala diaria. Va encima como todo el overlay, así
   que el tinte es mínimo: sobre una barra tiene que notarse apenas. */
.tl-finde { position: absolute; top: 0; bottom: 0; background: rgba(15, 23, 42, .045); }
/* Punteada y fina, como en el PDF: sólida y de 2px partía en dos las barras
   que cruza. */
.tl-hoy { position: absolute; top: 0; bottom: 0; border-left: 1.5px dashed var(--danger); opacity: .65; }
.tl-hoy b { position: absolute; top: -1px; left: 3px; font-size: .62rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--danger); background: var(--surface); padding: 0 3px; }

.tl-track { position: relative; height: 30px; background: var(--surface-2); border-radius: 6px; }
.tl-bar { position: absolute; top: 50%; transform: translateY(-50%); height: 18px; border-radius: 5px; min-width: 4px;
  display: flex; align-items: center; justify-content: center; overflow: hidden; }
.tl-bar span { font-size: .64rem; font-weight: 700; color: #fff; white-space: nowrap; }
/* Barra recortada por la ventana visible: el lado cortado pierde el redondeo,
   que es lo que dice "esto sigue más allá". */
.tl-bar.tl-corte-izq { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.tl-bar.tl-corte-der { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* El color va en el par barra + punto de la leyenda: con la regla solo en
   .tl-bar, los cuadritos de la leyenda salían transparentes y no explicaban
   nada. */
.tl-bar.tl-completado, .tl-dot.tl-completado { background: var(--success); }
.tl-bar.tl-en-curso, .tl-dot.tl-en-curso { background: var(--primary-gradient); }
.tl-bar.tl-proximo, .tl-dot.tl-proximo { background: var(--text-muted); opacity: .55; }
.tl-foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-top: 18px; }
.tl-nota { font-size: .78rem; color: var(--text-muted); margin-top: 10px; }

/* Barra de herramientas: detalle de la escala + ventana visible. */
.tl-toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 14px; }
.tl-seg { display: flex; align-items: center; gap: 6px; }
.tl-seg-label, .tl-rango label, .filtro-inline label { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); }
.tl-seg-btn {
  padding: 5px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text-secondary);
  font-size: .78rem; font-weight: 600; font-family: inherit; cursor: pointer; transition: var(--transition);
}
.tl-seg-btn:hover { background: var(--surface-2); color: var(--text); }
.tl-seg-btn.on { background: var(--primary); border-color: var(--primary); color: #fff; }
.tl-rango { display: flex; align-items: center; gap: 8px; }
/* Filtro en línea (cuadrilla): acota la tabla de subproyectos del proyecto y la
   línea de tiempo —con el PDF que se descarga de ella— a un grupo de trabajo. */
.filtro-inline { display: flex; align-items: center; gap: 8px; }
.filtro-inline select { width: auto; max-width: 220px; padding: 5px 8px; font-size: .78rem; }
/* Los campos de fecha se aprietan: aquí son un control auxiliar, no un
   formulario, y con el ancho normal del .input desplazan la barra entera. */
.tl-fecha { width: auto; padding: 5px 8px; font-size: .78rem; }
.tl-legend { display: flex; gap: 18px; font-size: .78rem; color: var(--text-secondary); flex-wrap: wrap; }
.tl-legend .tl-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; margin-right: 5px; vertical-align: -1px; }

/* ── Progress bar ── */
.progress { height: 8px; border-radius: 99px; background: var(--surface-3); overflow: hidden; max-width: 320px; }
.progress-fill { height: 100%; border-radius: 99px; background: var(--primary-gradient); }

/* ── Checklist ── */
.checklist { list-style: none; }
.checklist li { display: flex; align-items: flex-start; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.checklist li:last-child { border-bottom: none; }
.checklist input[type=checkbox] { width: 18px; height: 18px; margin-top: 1px; accent-color: var(--primary); cursor: pointer; flex-shrink: 0; }
.checklist label { flex: 1; font-size: .9rem; cursor: pointer; }
.checklist .meta { display: block; font-size: .75rem; color: var(--text-muted); margin-top: 2px; }

/* ── Novedades (texto + evidencia opcional) ── */
.novedad-list { list-style: none; display: flex; flex-direction: column; gap: 14px; }
.novedad { display: flex; gap: 10px; align-items: flex-start; }
.novedad-body { flex: 1; min-width: 0; }
.novedad-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: .78rem; color: var(--text-muted); }
.novedad-meta strong { color: var(--text); font-weight: 600; }
/* El botón de borrar se va al extremo para no partir la línea de datos. */
.novedad-meta > .btn { margin-left: auto; }
.novedad-texto { font-size: .9rem; color: var(--text); margin-top: 3px; white-space: pre-wrap; word-break: break-word; }
/* Miniatura fija y pequeña: confirma que hay evidencia sin que una sola
   novedad ocupe media pantalla. El nombre y tamaño van en el tooltip, y el
   detalle completo se ve al abrir el visor (_abrirVisorEvidencia). */
.novedad-thumb {
  /* El resto de la fila (avatar, meta) queda arriba — .novedad tiene
     align-items:flex-start — pero la miniatura se centra en el alto real del
     párrafo, así un texto largo no la deja pegada arriba. */
  align-self: center;
  flex-shrink: 0; display: block; width: 56px; height: 56px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; background: var(--surface-3);
}
.novedad-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.novedad-thumb-file { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: var(--text-secondary); }
.novedad-thumb:hover .novedad-thumb-file { color: var(--primary); }
.novedad-rota { opacity: .5; }

/* ── Miga de pan (proyecto › subproyecto) ── */
.crumb { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: .85rem; color: var(--text-muted); margin-top: 2px; }
.crumb a { color: var(--primary); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }
.crumb-sep { color: var(--text-muted); }

/* ── Aviso contextual dentro de una página ── */
.banner-info {
  display: flex; align-items: flex-start; gap: 10px; margin-bottom: 16px;
  padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--surface-3); color: var(--text-secondary); font-size: .82rem; line-height: 1.5;
}
.banner-info svg { flex-shrink: 0; margin-top: 1px; color: var(--primary); }

/* ── Visor de evidencias (lightbox) ── */
/* Fondo más oscuro que el de un modal normal: aquí la foto es el contenido,
   no un diálogo sobre la página. El selector lleva las dos clases a propósito:
   el elemento es `modal-overlay lightbox-overlay` y `.modal-overlay`, que se
   declara más abajo, le ganaba por orden y dejaba el visor sobre un velo
   claro — con la página de fondo asomando alrededor de la foto. */
.modal-overlay.lightbox-overlay { background: rgba(7, 16, 43, .88); backdrop-filter: blur(6px); padding: 20px; }
.lightbox {
  display: flex; flex-direction: column; width: min(1100px, 100%); max-height: 100%;
  color: #fff; transform: translateY(12px); transition: var(--transition);
}
.modal-overlay.open .lightbox { transform: translateY(0); }

.lightbox-bar { display: flex; align-items: flex-start; gap: 16px; padding-bottom: 12px; }
.lightbox-titles { flex: 1; min-width: 0; }
.lightbox-title { font-weight: 600; font-size: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lightbox-sub { font-size: .78rem; color: rgba(255,255,255,.6); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lightbox-actions { display: flex; gap: 4px; flex-shrink: 0; }
/* Los btn-ghost del sistema son oscuros: sobre el visor van en blanco. */
.lightbox-actions .btn { color: rgba(255,255,255,.75); }
.lightbox-actions .btn:hover { color: #fff; background: rgba(255,255,255,.12); }

.lightbox-stage { flex: 1; min-height: 0; display: flex; align-items: center; gap: 10px; }
.lightbox-media {
  flex: 1; min-width: 0; height: 100%; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.25); border-radius: var(--radius); overflow: hidden;
}
.lightbox-media img { max-width: 100%; max-height: calc(100vh - 190px); object-fit: contain; display: block; }
.lightbox-media iframe { width: 100%; height: calc(100vh - 190px); border: 0; background: #fff; }
.lightbox-cargando { display: flex; align-items: center; gap: 8px; padding: 60px 20px; font-size: .85rem; color: rgba(255,255,255,.7); }

.lightbox-nav {
  flex-shrink: 0; width: 42px; height: 42px; display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer; color: #fff;
  background: rgba(255,255,255,.12); transition: var(--transition);
}
.lightbox-nav:hover { background: rgba(255,255,255,.24); }

.lightbox-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding-top: 12px; font-size: .78rem; color: rgba(255,255,255,.6);
}
.lightbox-count { flex-shrink: 0; font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
  .lightbox-overlay { padding: 10px; }
  /* En pantalla chica las flechas estorban al lado: van encima de la imagen. */
  .lightbox-stage { position: relative; }
  .lightbox-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 1; background: rgba(7,16,43,.6); }
  .lightbox-nav.prev { left: 6px; }
  .lightbox-nav.next { right: 6px; }
}

/* ── Subida de evidencias (arrastrar y soltar) ── */
.ev-uploader { margin-top: 16px; display: flex; flex-direction: column; gap: 12px; }

.dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 26px 16px; text-align: center; cursor: pointer;
  border: 2px dashed var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-secondary);
  transition: var(--transition);
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--primary); color: var(--primary); outline: none; }
/* Estado mientras se arrastra un archivo encima. */
.dropzone.is-over { border-color: var(--primary); background: var(--surface-3); color: var(--primary); }
.dropzone-text { font-size: .88rem; }
.dropzone-hint { font-size: .74rem; color: var(--text-muted); }
/* Los hijos no deben capturar el drag: si no, dragleave se dispara al pasar
   sobre el texto y el resaltado parpadea. */
.dropzone > * { pointer-events: none; }

/* Estado de la captura de ubicación, encima de la cola de archivos. */
.ev-ubicacion { display: flex; align-items: center; gap: 6px; font-size: .76rem; color: var(--success); }
.ev-ubicacion.ev-ubicacion-sin { color: var(--text-muted); }
.ev-ubicacion svg { flex-shrink: 0; }

/* Enlace al mapa en la tarjeta y en el visor de una evidencia geolocalizada. */
.ev-mapa { display: inline-flex; align-items: center; gap: 3px; margin-top: 2px; font-size: .72rem; color: var(--primary); text-decoration: none; }
.ev-mapa:hover { text-decoration: underline; }
.lightbox-foot .ev-mapa { color: #fff; opacity: .8; font-size: .78rem; }
.lightbox-foot .ev-mapa:hover { opacity: 1; }

.ev-queue { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.ev-queue:empty { display: none; }  /* sin archivos en cola no debe dejar hueco */
.ev-queue li {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); font-size: .8rem; color: var(--text-secondary);
}
.ev-queue-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ev-queue-size { color: var(--text-muted); font-size: .74rem; white-space: nowrap; }

/* Descripción y botón: misma altura, alineados abajo (ninguno lleva hint). */
.ev-uploader-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.ev-uploader-row .input-group { flex: 1; min-width: 200px; }

/* ── Personal a cargo ── */
.person-list { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.person-row { display: flex; align-items: center; gap: 10px; }
.person-info { flex: 1; min-width: 0; }
.person-name { font-size: .88rem; font-weight: 600; color: var(--text); }
.person-meta { font-size: .76rem; color: var(--text-muted); }

/* ── Modal ── */
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.45); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; opacity: 0; pointer-events: none; transition: var(--transition); }
.modal-overlay.open { opacity: 1; pointer-events: all; }
.modal-box, .modal { background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 28px; width: 90%; max-width: 480px; transform: translateY(12px); transition: var(--transition); text-align: center; }
.modal-overlay.open .modal-box, .modal-overlay.open .modal { transform: translateY(0); }
.modal-icon { width: 48px; height: 48px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 14px; }
.modal-icon.danger { background: #FEF2F2; color: var(--danger); }
.modal-icon.info { background: #EEF2FF; color: var(--primary); }
.modal-title { font-weight: 700; margin-bottom: 6px; }
.modal-msg { color: var(--text-secondary); font-size: .9rem; margin-bottom: 20px; }
.modal-actions, .modal-footer { display: flex; justify-content: center; gap: 10px; }
.modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; text-align: left; }
.modal-form { text-align: left; }
.modal-form .form-fields { margin-bottom: 20px; }

/* ── Login ── */
.login-screen { min-height: 100vh; min-height: 100dvh; display: flex; align-items: stretch; background: var(--surface); }
.login-left { flex: 1; background: var(--sidebar-bg); display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px; position: relative; overflow: hidden; }
.login-left::before { content: ''; position: absolute; width: 600px; height: 600px; background: radial-gradient(circle, rgba(0,71,255,.25) 0%, transparent 70%); top: 50%; left: 50%; transform: translate(-50%, -50%); pointer-events: none; }
.login-brand { display: flex; flex-direction: column; align-items: center; gap: 20px; text-align: center; position: relative; z-index: 1; }
.login-brand-mark { width: 64px; height: 64px; border-radius: 16px; background: var(--primary-gradient); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.6rem; }
.login-brand h1 { color: #fff; font-size: 2rem; font-weight: 800; }
.login-brand h1 span { color: var(--primary-light); }
.login-tagline { color: rgba(255,255,255,.5); font-size: .95rem; max-width: 340px; line-height: 1.6; }
.login-right { width: 440px; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 56px; }
.login-form-wrap { width: 100%; }
.login-form-wrap h2 { font-size: 1.5rem; font-weight: 800; margin-bottom: 6px; }
.login-form-wrap p { color: var(--text-muted); font-size: .875rem; margin-bottom: 32px; }
.login-form-wrap .btn-primary { width: 100%; justify-content: center; padding: 13px; font-size: .95rem; margin-top: 8px; }
.login-error { background: #FEF2F2; border: 1px solid #FECACA; color: var(--danger); padding: 10px 14px; border-radius: var(--radius-sm); font-size: .85rem; display: none; margin-bottom: 16px; }
.login-error.show { display: block; }
.login-recaptcha { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 14px; font-size: .75rem; color: var(--text-muted); }

/* ── Toast ── */
.toast-wrap { position: fixed; bottom: 24px; right: 24px; display: flex; flex-direction: column; gap: 8px; z-index: 9999; }
.toast { background: var(--text); color: #fff; padding: 12px 18px; border-radius: var(--radius-sm); font-size: .85rem; font-weight: 500; box-shadow: var(--shadow-md); display: flex; align-items: center; gap: 10px; animation: slideIn .3s ease; min-width: 260px; }
.toast.success { background: var(--success); }
.toast.error { background: var(--danger); }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
.spinner-sm { display: inline-block; width: 14px; height: 14px; border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%; animation: spin .6s linear infinite; vertical-align: middle; opacity: .7; }

/* El responsive vive junto, al final del archivo (── Responsive ──). */

/* ── Costeo del subproyecto ── */
.costo-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); gap: 12px; }
.costo-tile { padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.costo-tile-label { font-size: .74rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: .03em; }
.costo-tile-valor { font-size: 1.15rem; font-weight: 700; color: var(--text); margin-top: 3px; white-space: nowrap; }
.costo-tile-pie { display: block; font-size: .72rem; color: var(--text-muted); margin-top: 3px; }
/* El saldo en rojo cuando los gastos se pasaron del costo pactado. */
.costo-tile.costo-negativo .costo-tile-valor { color: var(--danger); }
.costo-tile.costo-extra .costo-tile-valor { color: var(--warning); }
/* Separa la segunda comparación (anticipo vs. gastado) de la primera (costeo vs. previsto). */
.costo-subtitulo { font-size: .82rem; font-weight: 600; color: var(--text-secondary); margin: 18px 0 4px; }
.progress-fill.progress-danger { background: var(--danger); }

/* ═══ Responsive ═════════════════════════════════════════
   Los cortes, como en OmniPRIT:
     900px — tablet: el sidebar se reduce a íconos y los formularios de dos
             columnas pasan a una.
     768px — móvil: el sidebar deja de ocupar ancho y se vuelve un cajón que
             entra desde la izquierda sobre la página, con su fondo oscuro.
     600px — el título de una tarjeta y su botón dejan de compartir línea.
     480px — pantalla estrecha: se aprieta el aire y las rejillas van de dos.
   Todo lo que sea "solo móvil" se declara oculto arriba y se enciende aquí.
   La excepción es el visor de evidencias, que lleva su propio @media junto al
   componente porque solo reacomoda sus flechas. */

/* ── Tablet ── */
@media (max-width: 900px) {
  .login-left { display: none; }
  .login-right { width: 100%; padding: 48px 32px; }
  .sidebar { width: 72px; }
  .sidebar .sidebar-logo-text,
  .sidebar .user-info,
  .sidebar .nav-label,
  .sidebar .nav-section-label { display: none; }
  .sidebar .sidebar-logo, .sidebar .user-pill { justify-content: center; }
  .sidebar .user-menu { right: auto; width: 210px; }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .form-grid .span2 { grid-column: span 1; }
  /* Con el sidebar en modo íconos, plegarlo más no significa nada. */
  .toggle-sidebar { display: none; }
}

/* ── Móvil ── */
@media (max-width: 768px) {
  /* Sidebar → cajón deslizante. Sale del flujo para que la página use todo
     el ancho: 72px de íconos son el 20% de una pantalla de 360px. */
  .sidebar, .sidebar.collapsed {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 1100;
    width: 264px; height: 100dvh;
    transform: translateX(-105%);
    transition: transform .25s cubic-bezier(.4,0,.2,1);
  }
  .sidebar.mobile-open { transform: translateX(0); box-shadow: 12px 0 40px rgba(0,0,0,.35); }
  /* Dentro del cajón hay sitio de sobra: vuelven los textos que el corte de
     900px había escondido. */
  .sidebar .sidebar-logo-text, .sidebar .nav-label { display: inline; }
  .sidebar .user-info { display: block; }
  .sidebar .nav-section-label { display: block; }
  .sidebar .sidebar-logo, .sidebar .user-pill { justify-content: flex-start; }
  .sidebar .user-menu { right: 8px; width: auto; }
  .sidebar-backdrop {
    display: block; position: fixed; inset: 0; z-index: 1090;
    background: rgba(7,16,43,.5); opacity: 0; pointer-events: none;
    transition: opacity .25s;
  }
  .sidebar-backdrop.show { opacity: 1; pointer-events: all; }
  .toggle-sidebar { display: inline-flex; }

  /* ── Topbar y página ── */
  .topbar { height: 56px; padding: 0 10px; gap: 8px; }
  .page { padding: 12px; }
  .card { padding: 16px; }
  .card + .card, .card + .card-stack > .card:first-child, .card-stack + .card { margin-top: 12px; }

  /* 16px es el umbral bajo el cual iOS hace zoom al enfocar un campo, y del
     zoom no se vuelve solo: la página queda corrida el resto de la sesión. */
  .input, select.input, textarea.input { font-size: 16px; }

  /* ── Tablas ── */
  /* Siguen desplazándose a lo horizontal (con la columna de acciones fija),
     que es más honesto que apilar celdas y perder la comparación entre filas;
     solo se les quita aire para que quepan más columnas de una vez. */
  thead th { padding: 9px 12px; }
  tbody td, tfoot td { padding: 11px 12px; }
  .table-wrap { -webkit-overflow-scrolling: touch; }
  /* La columna del nombre (la primera, o la segunda si hay asa de reordenar)
     suele llevar nombre + descripción: sin tope, una frase
     larga estira la tabla y empuja el estado y la fecha tan lejos que hay que
     desplazarse media pantalla para ver lo que importa. Aquí sí se parte en
     varias líneas — el resto de columnas siguen en una sola. */
  tbody td:first-child:not(.col-drag), tbody td.col-drag + td { max-width: 60vw; white-space: normal; }
  /* La columna de acciones va fija a la derecha, así que su ancho se le resta
     al resto de la tabla: tres botones con el padding de escritorio se comen
     el 40% de una pantalla de 360px. */
  tbody td .row-actions { gap: 2px; }
  tbody td .row-actions .btn-icon { padding: 6px; }

  /* ── Formularios y subida de evidencias ── */
  .ev-uploader-row { align-items: stretch; }
  .ev-uploader-row .btn { justify-content: center; }
  .dropzone { padding: 20px 12px; }

  /* ── Modales ── */
  /* Casi a pantalla completa y con scroll propio: un formulario de siete
     campos no cabe en el alto de un teléfono. */
  .modal-box, .modal { width: calc(100vw - 20px); max-width: none; padding: 20px 16px; max-height: 92dvh; overflow-y: auto; }

  /* ── Visor de evidencias ── */
  .lightbox-media img { max-height: calc(100dvh - 170px); }
  .lightbox-media iframe { height: calc(100dvh - 170px); }

  /* ── Línea de tiempo del proyecto ── */
  /* Las columnas de texto se aprietan, pero la pista conserva su ancho mínimo:
     el gráfico se desplaza a lo horizontal (.tl-scroll) en vez de encogerse
     hasta que las barras dejen de distinguirse. */
  .tl { --tl-name: 128px; --tl-dates: 84px; --tl-gap: 8px; }
  .tl-name-main { font-size: .75rem; }
  .tl-legend { gap: 12px; }
  .tl-foot { justify-content: flex-start; }
  /* Escala y ventana pasan a líneas propias: en una sola no caben los tres
     botones más los dos campos de fecha. */
  .tl-toolbar { flex-direction: column; align-items: stretch; gap: 10px; }
  .tl-rango { flex-wrap: wrap; }
  .tl-fecha { flex: 1; min-width: 120px; }
  .filtro-inline select { flex: 1; max-width: none; }

  /* ── Paginación ── */
  /* El recuento pasa a su propia línea y los controles se reparten el ancho:
     apretados en una sola línea, los botones de página quedaban cortados. */
  .pg-bar { gap: 10px; justify-content: space-between; }
  .pg-info { margin-right: 0; width: 100%; }

  /* ── Toasts ── */
  /* De esquina a barra inferior: en móvil un ancho fijo de 260px se sale. */
  .toast-wrap { left: 12px; right: 12px; bottom: 12px; }
  .toast { min-width: 0; }
}

/* ── Cabeceras: título y acción dejan de compartir línea ── */
/* Corte propio, más estrecho que el de móvil: hasta 600px todavía caben el
   título y su botón en la misma fila, y estirar "Registrar actividad" a lo
   ancho de una tablet se ve desproporcionado. */
@media (max-width: 600px) {
  /* Solo cuando la acción lleva texto — un par de botones de solo ícono
     (editar/eliminar de una tarjeta) cabe de sobra al lado del título, y
     estirarlos los dejaba enormes en mitad de la tarjeta. */
  .card-header:has(.btn:not(.btn-icon)) { flex-direction: column; align-items: stretch; gap: 10px; }
  .card-header > .btn:not(.btn-icon),
  .card-header .row-actions > .btn:not(.btn-icon) { flex: 1; justify-content: center; }
  .card-header:has(.btn:not(.btn-icon)) .row-actions { width: 100%; }
  /* Igual que .row-actions: el bloque de controles ocupa el ancho y su botón
     se estira, que es lo que hacía la regla de arriba cuando el botón colgaba
     directamente de la cabecera. */
  .card-header:has(.btn:not(.btn-icon)) .card-header-tools { width: 100%; }
  .card-header .card-header-tools > .btn:not(.btn-icon) { flex: 1; justify-content: center; }
  .card-header .card-header-tools .filtro-inline { flex: 1; }
  .form-actions .btn, .modal-actions .btn, .modal-footer .btn { flex: 1; justify-content: center; }
  .form-page-header h1 { font-size: 1.15rem; }
}

/* ── Pantalla estrecha ── */
@media (max-width: 480px) {
  .page { padding: 10px; }
  .card { padding: 14px; }
  .login-right { padding: 32px 20px; }
  /* Dos por fila: una sola columna de indicadores obliga a desplazar la
     pantalla entera para ver cuatro cifras. */
  .stats-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .stat-card { padding: 14px; gap: 8px; }
  .stat-card .stat-value { font-size: 1.5rem; }
  .stat-card .stat-label { font-size: .66rem; letter-spacing: .05em; }
  .stat-card .stat-icon { width: 38px; height: 38px; }
  .stat-card .stat-icon svg { width: 18px; height: 18px; }
  .costo-tiles { grid-template-columns: 1fr 1fr; }
  .costo-tile-valor { font-size: 1rem; }
  .topbar-title { font-size: .95rem; }
  h1 { font-size: 1.25rem; }
  h2 { font-size: 1.1rem; }
}

/* ── ApeLeads: piezas propias ─────────────────────────────
   El resto de la hoja es el sistema de diseño compartido; lo de abajo son los
   componentes que solo existen en este proyecto. */

/* Barra de avance dentro de una celda de tabla: sin texto, la cifra va al lado */
.progress-mini {
  height: 6px; width: 100%; max-width: 120px;
  background: var(--surface-3); border-radius: 99px; overflow: hidden;
  margin-bottom: 4px;
}
.progress-mini > div {
  height: 100%; background: var(--primary); border-radius: 99px;
  transition: width var(--transition);
}

/* Fila de filtros: se apila sola en pantallas angostas */
.filtros { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.filtros .input-group { margin: 0; }

/* Avisos dentro de una página (no son toasts: se quedan) */
.alert-info, .alert-warning {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius-sm);
  font-size: .85rem; line-height: 1.45;
}
.alert-info { background: var(--surface-3); color: var(--text-secondary); }
.alert-info svg, .alert-warning svg { flex-shrink: 0; margin-top: 2px; }
.alert-warning { background: #FEF3C7; color: #92400E; }

.badge-orange { background: #FEF3C7; color: #92400E; }

/* Punto que late mientras el servidor está extrayendo. Es la única señal de
   que algo se mueve en una pantalla que por lo demás se ve igual. */
.latido {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--primary); margin-right: 5px;
  animation: latido 1.4s ease-in-out infinite;
}
@keyframes latido {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .35; transform: scale(.75); }
}

/* Columna de redes sociales. En gris hasta que el puntero pasa por encima: son
   cuatro iconos por fila y a todo color competirían con el nombre de la
   empresa, que es lo que de verdad se lee al recorrer la tabla. */
.redes-cell { display: flex; align-items: center; gap: 7px; }
.red-social { color: var(--text-muted); display: inline-flex; transition: color .15s, transform .15s; }
.red-social:hover { transform: translateY(-1px); }
.red-instagram:hover { color: #C13584; }
.red-facebook:hover  { color: #1877F2; }
.red-linkedin:hover  { color: #0A66C2; }
.red-whatsapp:hover  { color: #25D366; }
