/* ============================================================
   Sabana — sistema de diseño (spec: docs/frontend_mockups.md §3)
   Paleta semántica vía CSS custom properties en :root.
   Tailwind está en el roadmap (build JIT); aquí tokens + componentes base.
   ============================================================ */

/* Inter (subset latín, @fontsource v5). Servido localmente — ver PR-OPS-1. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/inter/Inter-Regular.woff2') format('woff2');
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/inter/Inter-Medium.woff2') format('woff2');
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/inter/Inter-SemiBold.woff2') format('woff2');
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/inter/Inter-Bold.woff2') format('woff2');
}

:root {
    --c-bg: #FAFAF9;
    --c-surface: #FFFFFF;
    --c-border: #E5E5E4;
    --c-text: #1F2937;
    --c-text-muted: #6B7280;
    --c-accent: #FF3300;
    --c-accent-hover: #CC2900;
    --c-ok: #15803D;
    --c-warn: #B45309;
    --c-error: #B91C1C;
    --c-info: #1D4ED8;

    --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;

    --fs-12: 12px;
    --fs-14: 14px;
    --fs-16: 16px;
    --fs-18: 18px;
    --fs-20: 20px;
    --fs-24: 24px;
    --fs-32: 32px;

    --r-sm: 4px;
    --r-md: 8px;
    --r-lg: 12px;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.06);
}

/* ---------- Reset mínimo ---------- */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
    background: var(--c-bg);
    color: var(--c-text);
    font-family: var(--font-sans);
    font-size: var(--fs-14);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}
a { color: var(--c-accent); text-decoration: none; }
a:hover { color: var(--c-accent-hover); text-decoration: underline; }
h1 { font-size: var(--fs-24); font-weight: 600; margin: 0 0 16px; }
h2 { font-size: var(--fs-20); font-weight: 600; margin: 0 0 12px; }
h3 { font-size: var(--fs-16); font-weight: 600; margin: 0 0 8px; }
code, pre, .mono { font-family: var(--font-mono); font-size: 13px; }

/* ---------- Layout ---------- */

.app { display: flex; min-height: 100vh; }

.sidebar {
    width: 220px;
    background: var(--c-surface);
    border-right: 1px solid var(--c-border);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
}
.sidebar .brand {
    padding: 18px 16px;
    border-bottom: 1px solid var(--c-border);
    display: flex;
    align-items: center;
    justify-content: flex-start;
}
.sidebar .brand a {
    display: inline-block;
    line-height: 0;
    color: inherit;
    text-decoration: none;
}
.sidebar .brand .logo-horizontal {
    display: block;
    width: 160px;
    height: auto;
    max-height: 40px;
}
/* Botón hamburguesa: oculto en escritorio, visible en móvil/tablet (≤900px). */
.sidebar-toggle {
    display: none;
    background: none;
    border: 0;
    cursor: pointer;
    color: var(--c-text);
    font-size: 22px;
    line-height: 1;
    padding: 4px 8px;
}
.sidebar nav { flex: 1; padding: 8px 0; }
.sidebar nav .group-sep {
    height: 1px;
    background: var(--c-border);
    margin: 8px 16px;
}
.sidebar nav a {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    color: var(--c-text);
    text-decoration: none;
    font-size: var(--fs-14);
    border-left: 2px solid transparent;
}
.sidebar nav a:hover {
    background: var(--c-bg);
    color: var(--c-text);
    text-decoration: none;
}
.sidebar nav a.active {
    border-left-color: var(--c-accent);
    background: var(--c-bg);
    font-weight: 500;
}
.sidebar nav .nav-heading {
    padding: 8px 16px 4px;
    font-size: 11px;
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 500;
}
.sidebar nav a.nav-sub {
    padding-left: 28px;
    font-size: var(--fs-14);
}
.sidebar nav a.nav-sub.nav-sub2 {
    padding-left: 44px;
    font-size: var(--fs-13, 13px);
}
/* Badge tipo notificación para la entrada Alertas del sidebar. */
.sidebar nav a .alert-badge {
    display: inline-block;
    min-width: 18px;
    padding: 0 5px;
    margin-left: 6px;
    background: var(--c-error);
    color: #fff;
    border-radius: 9px;
    font-size: 10px;
    line-height: 16px;
    text-align: center;
    font-weight: 600;
}
.sidebar .footer {
    padding: 12px 16px;
    border-top: 1px solid var(--c-border);
    font-size: var(--fs-12);
    color: var(--c-text-muted);
}
.sidebar .footer .user {
    display: flex;
    align-items: center;
    gap: 8px;
}
.sidebar .footer .avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--c-text-muted);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 12px;
    flex-shrink: 0;
}
.sidebar .footer .logout {
    margin-top: 8px;
    display: block;
    font-size: var(--fs-12);
}

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.breadcrumbs {
    padding: 12px 24px;
    border-bottom: 1px solid var(--c-border);
    font-size: var(--fs-12);
    color: var(--c-text-muted);
    background: var(--c-surface);
    /* Cabecera fija en la parte superior al hacer scroll. El sidebar
       también es sticky (top:0, height:100vh), así que ambos quedan
       siempre visibles. */
    position: sticky;
    top: 0;
    z-index: 20;
}
.breadcrumbs a { color: var(--c-text-muted); }
.breadcrumbs a:hover { color: var(--c-accent); }
.breadcrumbs .sep { margin: 0 6px; }
.content { padding: 24px; flex: 1; }

/* ---------- Cards / KPIs ---------- */

.card {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    padding: 16px;
    /* Permite que tablas/grids internos hagan scroll horizontal en vez de
       desbordar el contenedor (la `.tabla-densa` exige `min-width: 560px`
       y los grids de calendario crecen con el número de meses). PR-FE-5. */
    overflow-x: auto;
}
.card h2 { margin-top: 0; }

.kpi-grid {
    display: grid;
    /* Mínimo 260px para que las cards de horas (con texto «usado / total»
       + barra de progreso + porcentaje) no se compriman demasiado cuando
       hay 5 cards (proyectos + 3 años de horas + coste). */
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
    align-items: stretch;
}
/* Cuando el KPI va envuelto en un <a> (drill-down), ocupar toda la altura
   del grid cell para igualar con los no-clickables. */
.kpi-grid > a { display: flex; }
.kpi {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    padding: 16px;
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
}
.kpi .hint { margin-top: auto; }
.kpi .label {
    font-size: var(--fs-12);
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.kpi .value {
    font-size: var(--fs-32);
    font-weight: 600;
    margin-top: 4px;
    font-family: var(--font-mono);
}
.kpi .hint {
    font-size: var(--fs-12);
    color: var(--c-text-muted);
    margin-top: 4px;
}

/* ---------- Botones ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    /* Padding alineado con la altura de selects/inputs (padding 8px) para que
       cuando un botón se coloca al lado de un `<select>` o `<input>` ambos
       tengan exactamente la misma altura. Regla UI: controles coherentes. */
    padding: 8px 14px;
    font: 500 var(--fs-14)/1.2 var(--font-sans);
    border-radius: var(--r-sm);
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.btn:disabled, .btn.disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primario {
    background: var(--c-accent);
    color: #fff;
}
.btn-primario:hover { background: var(--c-accent-hover); color: #fff; text-decoration: none; }
.btn-secundario {
    background: var(--c-surface);
    color: var(--c-text);
    border-color: var(--c-border);
}
.btn-secundario:hover { background: var(--c-bg); }
.btn-ghost {
    background: transparent;
    color: var(--c-text);
}
.btn-ghost:hover { background: var(--c-bg); }
.btn-peligro {
    background: var(--c-error);
    color: #fff;
}
/* Modificador para acciones destructivas en botón secundario o ghost.
   Conserva el fondo (blanco / transparente) pero pinta borde y texto en
   rojo de error para que la acción quede claramente diferenciada del
   resto. Patrón definido en CLAUDE.md §Reglas de UI. */
.btn-secundario.btn-danger,
.btn-ghost.btn-danger {
    color: var(--c-error);
    border-color: var(--c-error);
}
.btn-secundario.btn-danger:hover,
.btn-ghost.btn-danger:hover {
    background: #FEF2F2;
}
/* Variante pequeña: se usa para acciones contextuales en tablas o
   subforms apretados (CLAUDE.md §Reglas de UI). El padding se mantiene
   proporcional al `.btn` base (~28px de alto) para que el step de tamaño
   no sea demasiado abrupto cuando ambos conviven. */
.btn-sm { padding: 5px 10px; font-size: var(--fs-12); }

/* ---------- Forms ---------- */

.form-row { margin-bottom: 16px; }
.form-row label {
    display: block;
    font-size: var(--fs-12);
    font-weight: 500;
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 4px;
}
/* Estilo base de los controles de formulario: garantiza que cualquier
   select / input / textarea —también fuera de un `.form-row`— siga el
   mismo formato (regla de UI: controles uniformes). `.form-row` añade
   el ancho 100% sobre esta base. */
select,
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="url"],
input[type="search"], input[type="tel"], input:not([type]),
textarea {
    padding: 8px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
    font: 400 var(--fs-14) var(--font-sans);
    background: var(--c-surface);
    color: var(--c-text);
}
.form-row input[type="text"],
.form-row input[type="email"],
.form-row input[type="password"],
.form-row input[type="number"],
.form-row input[type="date"],
.form-row input[type="url"],
.form-row input[type="search"],
.form-row input[type="tel"],
.form-row input:not([type]),
.form-row select,
.form-row textarea {
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
    font: 400 var(--fs-14) var(--font-sans);
    background: var(--c-surface);
    color: var(--c-text);
}
.form-row textarea { min-height: 80px; resize: vertical; }
.form-row input:focus, .form-row select:focus, .form-row textarea:focus {
    outline: 2px solid var(--c-accent);
    outline-offset: -1px;
    border-color: var(--c-accent);
}
.form-row .help {
    font-size: var(--fs-12);
    color: var(--c-text-muted);
    margin-top: 4px;
}
.form-row .error-msg {
    font-size: var(--fs-12);
    color: var(--c-error);
    margin-top: 4px;
}

/* Validaciones inline destacadas — uso global. Aplicar `help-error` al
   div/span con el mensaje de validación, e `input-invalid` al input que
   provoca el problema. El borde + el texto en rojo + el peso 500 hace que
   la advertencia sea inmediatamente visible (regla UI: una validación que
   no destaca es como no tenerla). */
.help-error,
.form-row .help.help-error {
    color: var(--c-error);
    font-weight: 500;
    margin-top: 4px;
    line-height: 1.35;
}
/* Modificador ámbar para avisos no bloqueantes (ej. uso de capacidad
   80-100%). Más sutil que help-error, pero suficientemente visible. */
.help-warn,
.form-row .help.help-warn {
    color: var(--c-warn);
    font-weight: 500;
    margin-top: 4px;
    line-height: 1.35;
}
.input-invalid,
.form-row input.input-invalid,
.form-row select.input-invalid,
.form-row textarea.input-invalid {
    border-color: var(--c-error);
    background: #FEF2F2;
}
.input-invalid:focus {
    outline-color: var(--c-error);
    border-color: var(--c-error);
}

/* Aviso de posible entidad duplicada (alta/edición de entidad). Caja
   compacta con variante bloqueante (roja) y sugerencia (ámbar). */
.aviso-dup {
    border: 1px solid;
    border-radius: 6px;
    padding: 8px 10px;
    font-size: var(--fs-12);
    line-height: 1.4;
}
.aviso-dup + .aviso-dup { margin-top: 6px; }
.aviso-dup.is-error {
    border-color: #FCA5A5;
    background: #FEF2F2;
    color: var(--c-error);
}
.aviso-dup.is-warn {
    border-color: #FDE68A;
    background: #FEF3C7;
    color: var(--c-warn);
}
.aviso-dup a {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
}

/* Tooltip — icono "i" de información (SVG) pegado a un título o etiqueta.
   El texto aclaratorio antes vivía como <p> debajo; ahora se condensa en
   hover. El SVG ocupa 13×13 sin border ni padding extra, así no rompe el
   layout cuando la celda contenedora es estrecha (ej. labels en .form-row
   de 140px). */
.tip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: 4px;
    color: var(--c-text-muted);
    cursor: help;
    vertical-align: -2px;
    position: relative;
    line-height: 0;
    /* Whitespace nbsp-like: evita que el icono y el texto previo se separen
       por un salto de línea en labels que aproximan el ancho disponible. */
    white-space: nowrap;
}
.tip > svg { display: block; }
.tip:hover, .tip:focus { color: var(--c-accent); outline: none; }
.tip[data-tip]::before,
.tip[data-tip]::after {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 6px);
    transform: translateX(-50%);
    pointer-events: none;
    opacity: 0;
    transition: opacity .12s ease;
    z-index: 50;
}
.tip[data-tip]::before {
    content: attr(data-tip);
    width: max-content;
    max-width: 280px;
    padding: 8px 10px;
    background: var(--c-text);
    color: #fff;
    font: 400 var(--fs-12) var(--font-sans);
    font-style: normal;
    line-height: 1.4;
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    white-space: normal;
    border-radius: var(--r-sm);
    box-shadow: 0 4px 12px rgba(0,0,0,.18);
}
.tip[data-tip]::after {
    content: '';
    border: 5px solid transparent;
    border-top-color: var(--c-text);
    bottom: calc(100% + 1px);
}
.tip[data-tip]:hover::before,
.tip[data-tip]:hover::after,
.tip[data-tip]:focus::before,
.tip[data-tip]:focus::after { opacity: 1; }

.form-actions {
    display: flex;
    gap: 8px;
    padding-top: 16px;
    border-top: 1px solid var(--c-border);
    margin-top: 24px;
}
.form-actions .btn + .btn { margin-left: 0; }
.form-actions .spacer { flex: 1; }

/* ---------- Tablas densas ---------- */

/* Wrapper de scroll horizontal para tablas que pueden desbordar (especialmente
   `.tabla-densa` con `min-width: 560px` en móvil/tablet). Aplicar siempre que
   una tabla NO esté directamente dentro de un `.card` (que ya da scroll vía
   `overflow-x: auto`). Toda tabla nueva en el proyecto debería ir envuelta —
   PR-FE-5 (2026-05-25). */
.tabla-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
}

/* Listado: contenedor de tabla con scroll vertical + horizontal y
   cabecera sticky. Se usa en los listados de entidades, proyectos,
   convocatorias y personas para que todos compartan el mismo patrón
   visual (misma altura máxima, mismo borde, misma cabecera fija). */
.tabla-listado {
    max-height: 60vh;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    max-width: 100%;
}
.tabla-listado .tabla-densa {
    border: 0;
    border-radius: 0;
}
.tabla-listado .tabla-densa thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--c-bg);
}

.tabla-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
    gap: 8px;
    flex-wrap: wrap;
}
.tabla-header h2 { margin: 0; }
.tabla-densa {
    width: 100%;
    border-collapse: collapse;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-md);
    overflow: hidden;
    /* Las tablas densas tienen muchas columnas y un mínimo razonable para
       que las celdas no se aplasten. En móvil/tablet el contenedor
       (`.card` o `.tabla-wrap`) provee scroll horizontal. */
    min-width: 560px;
}
.tabla-densa th {
    text-align: left;
    font-size: var(--fs-12);
    font-weight: 500;
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 10px 12px;
    border-bottom: 1px solid var(--c-border);
    background: var(--c-bg);
}
.tabla-densa td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--c-border);
    font-size: var(--fs-14);
    vertical-align: middle;
    height: 36px;
}
.tabla-densa tr:last-child td { border-bottom: 0; }
.tabla-densa tr:hover td { background: var(--c-bg); }
.tabla-densa td.mono, .tabla-densa td.num { font-family: var(--font-mono); }
/* Numerico: alinea header y celda a la derecha. Mayor especificidad que
   `.tabla-densa th { text-align: left }` para que `.text-right` funcione
   aplicado a headers. */
.tabla-densa th.num,
.tabla-densa th.text-right,
.tabla-densa td.num,
.tabla-densa td.text-right { text-align: right; }

/* Tabla calendario (asignaciones por mes/año, en detalle de proyecto y
   en ficha de persona). Densidad reducida un par de puntos sobre la
   `.tabla-densa` base: las celdas suelen ser numéricas y caben más
   columnas en pantalla cuando el rango cubre muchos meses. */
.tabla-calendario th {
    font-size: 11px;
    padding: 6px 8px;
}
.tabla-calendario td {
    font-size: 12px;
    padding: 6px 8px;
    height: auto;
}

.tabla-vacia {
    padding: 32px 16px;
    text-align: center;
    color: var(--c-text-muted);
    background: var(--c-surface);
    border: 1px dashed var(--c-border);
    border-radius: var(--r-md);
}

/* ---------- Badges ---------- */

.badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: var(--fs-12);
    font-weight: 500;
    border: 1px solid transparent;
}
.badge-ok { background: #DCFCE7; color: var(--c-ok); border-color: #BBF7D0; }
.badge-warn { background: #FEF3C7; color: var(--c-warn); border-color: #FDE68A; }
.badge-error { background: #FEE2E2; color: var(--c-error); border-color: #FECACA; }
.badge-info { background: #DBEAFE; color: var(--c-info); border-color: #BFDBFE; }
.badge-neutral { background: var(--c-bg); color: var(--c-text-muted); border-color: var(--c-border); }

/* Estado convocatoria → clase semántica */
.estado-borrador { background: var(--c-bg); color: var(--c-text-muted); border: 1px solid var(--c-border); }
.estado-en_ejecucion { background: #DBEAFE; color: var(--c-info, #1D4ED8); border: 1px solid #BFDBFE; }
.estado-no_concedido { background: #FEE2E2; color: var(--c-error); border: 1px solid #FECACA; }
.estado-activa { background: #DCFCE7; color: var(--c-ok); border: 1px solid #BBF7D0; }
.estado-cerrada,
.estado-cerrado { background: #F3E8FF; color: #6B21A8; border: 1px solid #E9D5FF; }
.estado-archivada,
.estado-archivado { background: var(--c-border); color: var(--c-text-muted); }

/* ---------- Tabs ---------- */

.tabs {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--c-border);
    margin-bottom: 16px;
    /* En pantallas estrechas la barra de pestañas no cabe: scroll horizontal
       en vez de desbordar o romper el layout. */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
.tabs a {
    padding: 8px 12px;
    font-size: var(--fs-14);
    color: var(--c-text-muted);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
}
.tabs a:hover { color: var(--c-text); text-decoration: none; }
.tabs a.active {
    color: var(--c-text);
    border-bottom-color: var(--c-accent);
    font-weight: 500;
}
/* Pestaña inactiva: misma posición pero no clicable y atenuada. */
.tabs .tab-disabled {
    padding: 8px 12px;
    font-size: var(--fs-14);
    color: var(--c-text-muted);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    white-space: nowrap;
    flex-shrink: 0;
    opacity: 0.5;
    cursor: not-allowed;
}

/* ---------- Login ---------- */

.login-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: var(--c-bg);
}
.login-card {
    width: 360px;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-lg);
    padding: 32px 24px 24px;
    box-shadow: var(--shadow-md);
}
.login-card .login-logo {
    display: block;
    margin: 0 auto 8px;
    width: 180px;
    height: auto;
}
.login-card .sub {
    text-align: center;
    color: var(--c-text-muted);
    font-size: var(--fs-12);
    margin-bottom: 24px;
}
.login-error {
    background: #FEE2E2;
    color: var(--c-error);
    border: 1px solid #FECACA;
    border-radius: var(--r-sm);
    padding: 8px 12px;
    font-size: var(--fs-12);
    margin-bottom: 12px;
}

/* ---------- Lista key-value compacta (fichas de datos) ---------- */

.kv-list {
    display: grid;
    /* max-content ajusta el ancho de la columna de labels al label más largo,
       evitando saltos de línea como "JORNADA ANUAL SEGÚN / CONVENIO". */
    grid-template-columns: max-content 1fr;
    gap: 8px 32px;
    margin: 0;
    padding: 0;
}
.kv-list dt {
    color: var(--c-text-muted);
    font-size: var(--fs-12);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 500;
    align-self: center;
    white-space: nowrap;
}
.kv-list dd {
    margin: 0;
    font-size: var(--fs-14);
    color: var(--c-text);
    align-self: center;
}
.kv-list dd.mono, .kv-list dd.num { font-family: var(--font-mono); }
.kv-list dd.perfil { white-space: pre-wrap; line-height: 1.5; }
.kv-list dt.full-width,
.kv-list dd.full-width { grid-column: 1 / -1; }
@media (max-width: 560px) {
    .kv-list { grid-template-columns: 1fr; gap: 2px 0; }
    .kv-list dt { margin-top: 8px; }
}

/* ---------- Modal de confirmación (sabanaConfirm) ---------- */

.sabana-modal-overlay {
    position: fixed; inset: 0;
    background: rgba(17, 24, 39, 0.5);
    display: flex; align-items: center; justify-content: center;
    z-index: 10000;
    animation: sabana-modal-fade 0.15s ease-out;
}
@keyframes sabana-modal-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}
.sabana-modal {
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--r-lg);
    padding: 24px;
    width: 92%;
    max-width: 440px;
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.2);
}
.sabana-modal-title {
    margin: 0 0 8px;
    font-size: var(--fs-18);
    font-weight: 600;
    color: var(--c-text);
}
.sabana-modal-message {
    color: var(--c-text);
    font-size: var(--fs-14);
    line-height: 1.5;
    margin-bottom: 8px;
}
.sabana-modal-detail {
    color: var(--c-text-muted);
    font-size: var(--fs-12);
    line-height: 1.5;
    margin-bottom: 16px;
    padding: 8px 12px;
    background: var(--c-bg);
    border-radius: var(--r-sm);
    white-space: pre-line;
}
.sabana-modal-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 16px;
}

/* ---------- Toasts ---------- */

.toast-container {
    position: fixed;
    bottom: 20px;
    right: 20px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 9999;
}
.toast {
    min-width: 240px;
    padding: 12px 16px;
    border-radius: var(--r-md);
    color: #fff;
    font-size: var(--fs-14);
    box-shadow: var(--shadow-md);
    animation: toast-in 0.18s ease-out;
}
.toast-ok { background: var(--c-ok); }
.toast-error { background: var(--c-error); }
.toast-info { background: var(--c-info); }
.toast-warn { background: var(--c-warn); }
@keyframes toast-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ---------- Ayudas genéricas ---------- */

.muted { color: var(--c-text-muted); }
.flex { display: flex; }
.flex.gap-8 { gap: 8px; }
.flex.gap-16 { gap: 16px; }
.flex.center { align-items: center; }
.flex.between { justify-content: space-between; }
.mt-8 { margin-top: 8px; }
.mt-16 { margin-top: 16px; }
.mt-24 { margin-top: 24px; }
.mb-8 { margin-bottom: 8px; }
.mb-16 { margin-bottom: 16px; }
.hidden { display: none !important; }
.text-right { text-align: right; }
.mono { font-family: var(--font-mono); }

/* ---------- Responsive (mobile / tablet) ---------- */

@media (max-width: 900px) {
    .app { flex-direction: column; }
    /* En móvil/tablet el sidebar es una barra fina: solo el logo y la
       hamburguesa. El nav y el footer quedan colapsados (display:none) y
       se despliegan al pulsar la hamburguesa (clase .sidebar-abierto). */
    .sidebar {
        width: 100%;
        height: auto;
        position: static;
        border-right: 0;
        border-bottom: 1px solid var(--c-border);
    }
    .sidebar .brand {
        padding: 8px 16px;
        justify-content: space-between;
        border-bottom: 0;
    }
    .sidebar-toggle { display: inline-flex; }
    .sidebar nav,
    .sidebar .footer { display: none; }
    .sidebar.sidebar-abierto {
        border-bottom: 1px solid var(--c-border);
    }
    .sidebar.sidebar-abierto .brand {
        border-bottom: 1px solid var(--c-border);
    }
    .sidebar.sidebar-abierto nav {
        display: block;
        padding: 4px 0 8px;
    }
    .sidebar.sidebar-abierto .footer {
        display: block;
        padding: 8px 16px;
    }
    .content { padding: 16px; }
    .kpi-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
    .kpi .value { font-size: var(--fs-24); }
    .split { grid-template-columns: 1fr; }
    .editor-json { height: 260px; }
    .login-card { width: 92%; max-width: 360px; }
}

@media (max-width: 560px) {
    .kpi-grid { grid-template-columns: 1fr; }
    h1 { font-size: var(--fs-20); }
    h2 { font-size: var(--fs-16); }
    .breadcrumbs { padding: 8px 16px; }
    /* `.tabla-densa { min-width: 560px }` y `.card { overflow-x: auto }` son
       ahora reglas globales (no específicas de móvil): toda tabla densa
       quiere ≥560px y el card siempre permite scroll horizontal. */
    /* PR-FE-5: muchas plantillas fijan `style="width:Npx"` en form-rows para
       que cuadren a desktop, pero en móvil esos anchos rígidos dejan media
       pantalla en blanco o, peor, hacen overflow de la fila contenedora.
       Aquí forzamos full-width para que cada campo ocupe su línea. El
       `!important` es necesario para vencer al inline style. */
    .form-row[style*="width"] {
        width: 100% !important;
        min-width: 0 !important;
    }
}

/* Cabecera del detalle de proyecto: identidad a la izquierda, cifras a la
   derecha. En pantallas estrechas se apilan en una sola columna (si no, la
   columna de identidad se aplasta a una palabra por línea y se solapa con
   las cifras). */
.cab-proyecto-aside {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    gap: 6px;
}
@media (max-width: 640px) {
    .cab-proyecto { flex-direction: column; align-items: stretch; }
    .cab-proyecto-aside {
        align-items: flex-start;
        text-align: left;
        width: 100%;
    }
}

/* Barra de edición global del proyecto — sticky al pie cuando se está
   editando. Botones a la izquierda (Cancelar/Eliminar) y a la derecha
   (Guardar y seguir / Guardar y salir), separados por un spacer. */
.barra-edicion-pie {
    position: sticky;
    bottom: 0;
    z-index: 30;
    background: var(--c-surface);
    border-top: 1px solid var(--c-border);
    box-shadow: 0 -4px 12px rgba(0,0,0,0.06);
    padding: 12px 16px;
    margin: 24px -16px 0 -16px;
}
.barra-edicion-inner {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}
.barra-edicion-inner .spacer { flex: 1; }

/* Barra de filtros — colapsable en móvil. En desktop el toggle se oculta y
   los campos se ven siempre. */
.filtros-bar { display: flex; flex-wrap: wrap; align-items: end; gap: 12px; }
.filtros-toggle { display: none; }
@media (max-width: 560px) {
    .filtros-toggle { display: inline-flex; }
    .filtros-body { width: 100%; flex-direction: column; align-items: stretch; }
    .filtros-body .form-row { width: 100%; }
}

/* ---------- Panel JSON preview ---------- */

.split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 1100px) { .split { grid-template-columns: 1fr; } }

.editor-json {
    width: 100%;
    height: 480px;
    font: 400 13px/1.45 var(--font-mono);
    padding: 12px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
    background: var(--c-surface);
    color: var(--c-text);
    resize: vertical;
}

.preview-section { margin-bottom: 16px; }
.preview-section h3 {
    font-size: var(--fs-12);
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 4px;
}
.preview-section .value { font-size: var(--fs-14); }

.validation-block {
    margin-top: 12px;
    padding: 12px;
    border-radius: var(--r-sm);
    border: 1px solid var(--c-border);
    background: var(--c-bg);
    font-size: var(--fs-12);
}
.validation-ok { border-color: #BBF7D0; background: #F0FDF4; color: var(--c-ok); }
.validation-warn { border-color: #FDE68A; background: #FFFBEB; color: var(--c-warn); }
.validation-error { border-color: #FECACA; background: #FEF2F2; color: var(--c-error); }
.validation-warn ul,
.validation-error ul { margin: 6px 0 0 18px; }
.validation-warn li,
.validation-error li { margin-bottom: 2px; }
.validation-warn code,
.validation-error code { background: rgba(0,0,0,0.04); padding: 1px 4px; border-radius: 3px; }

/* =========================================================================
   Barra horizontal para visualizar rangos de contribución [min%, max%].
   ========================================================================= */
.pct-bar {
    position: relative;
    height: 16px;
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: 999px;
    overflow: hidden;
    min-width: 160px;
}
.pct-bar-fill {
    position: absolute;
    top: 0; bottom: 0;
    background: linear-gradient(90deg, var(--c-info-bg, #DBEAFE) 0%, var(--c-info, #2563EB) 100%);
    border-radius: 999px;
}
.pct-bar-label {
    position: relative;
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--c-text-muted);
    font-family: var(--font-mono);
    margin-top: 2px;
}
.pct-bar-cell { min-width: 220px; }

/* Chips para documentos (mejor que una columna "Hash" que no aporta). */
.doc-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--c-border);
}
.doc-item:last-child { border-bottom: 0; }
.doc-item-main { min-width: 0; flex: 1; }
.doc-item-titulo { font-weight: 600; margin-bottom: 2px; }
.doc-item-meta {
    font-size: 12px;
    color: var(--c-text-muted);
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}
.doc-item-meta .chip {
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 11px;
    color: var(--c-text-muted);
}
.doc-item-meta a {
    color: var(--c-info, #2563EB);
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: bottom;
}
.doc-item-actions { display: flex; gap: 8px; flex-shrink: 0; }

/* Grupos plegables en el editor UI de convocatoria. */
.regla-grupo {
    border: 1px solid var(--c-border);
    border-radius: var(--r-sm);
    padding: 12px;
    margin-bottom: 10px;
    background: var(--c-bg);
}
.regla-grupo-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}
.regla-grupo-titulo {
    font-weight: 600;
    font-size: 13px;
    color: var(--c-text);
}
.regla-grupo .form-row { margin-bottom: 8px; }

/* Input NIF/NIE/CIF con validación visual. */
.input-nif-wrap { position: relative; }
.input-nif {
    text-transform: uppercase;
    font-family: var(--font-mono);
    letter-spacing: 0.5px;
    padding-right: 32px;
}
.input-nif.is-valid {
    border-color: var(--c-ok);
    background: #F0FDF4;
}
.input-nif.is-invalid {
    border-color: var(--c-error);
    background: #FEF2F2;
}
.input-nif-feedback {
    font-size: 11px;
    margin-top: 4px;
    color: var(--c-text-muted);
}
.input-nif-feedback.is-valid { color: var(--c-ok); }
.input-nif-feedback.is-invalid { color: var(--c-error); }

/* ───────────────────────────────────────────────────────────────────
   Cronograma / Gantt de paquetes de trabajo y actividades.
   Usado en proyectos/detalle.html como alternativa a la tabla.

   Estructura: cada fila (`.gantt-row`) es un grid con 240px de label
   + N columnas iguales (una por mes del proyecto). Las celdas de fondo
   (track) ocupan la fila completa para dar la rejilla visual. La barra
   (`.gantt-bar`) se posiciona absoluta sobre la franja de meses
   correspondiente, usando las variables CSS `--gantt-start` y
   `--gantt-span` (fracciones 0..1 que indican dónde empieza y cuánto
   ancho ocupa la barra respecto al espacio de las N columnas).
   ─────────────────────────────────────────────────────────────────── */
.gantt-row {
    display: grid;
    position: relative;
    background: var(--c-surface);
    border-left: 1px solid var(--c-border);
    border-right: 1px solid var(--c-border);
}
.gantt-row:first-of-type { border-top: 1px solid var(--c-border); border-top-left-radius: var(--r-sm); border-top-right-radius: var(--r-sm); }
.gantt-row:last-of-type  { border-bottom-left-radius: var(--r-sm); border-bottom-right-radius: var(--r-sm); }
.gantt-cell {
    border-right: 1px solid var(--c-border);
    border-bottom: 1px solid var(--c-border);
    padding: 4px 6px;
    font-size: 11px;
    min-height: 32px;
    display: flex;
    align-items: center;
    gap: 4px;
    font-family: var(--font-sans);
}
.gantt-row-act .gantt-cell { min-height: 26px; background: var(--c-bg); }
.gantt-header {
    background: var(--c-bg);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--c-text-muted);
    font-weight: 500;
    font-size: 10px;
    justify-content: center;
    text-align: center;
    min-height: 28px;
}
.gantt-label-cell {
    padding-left: 10px;
}
.gantt-row .gantt-label-cell { background: var(--c-surface); }
.gantt-row-act .gantt-label-cell { background: var(--c-bg); }
.gantt-label-act { font-style: italic; }
.gantt-track { background: transparent; }
.gantt-year-start {
    border-left: 2px solid rgba(255, 51, 0, 0.25);
}
.gantt-year-badge {
    background: var(--c-accent);
    color: white;
    font-size: 9px;
    padding: 1px 4px;
    border-radius: 2px;
    margin-left: 4px;
    font-family: var(--font-mono);
}
.gantt-bar {
    position: absolute;
    /* La fila empieza con 240px de label; el espacio restante es el
       grid de N meses. Usamos calc para posicionar la barra dentro de
       ese espacio restante. */
    left: calc(240px + var(--gantt-start, 0) * (100% - 240px));
    width: calc(var(--gantt-span, 0) * (100% - 240px));
    top: 4px;
    bottom: 4px;
    margin: 0 2px;
    padding: 3px 8px;
    border-radius: 3px;
    font-size: 11px;
    font-family: var(--font-mono);
    color: white;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-shadow: 0 1px 2px rgba(0,0,0,0.15);
    cursor: default;
    z-index: 1;
    display: flex;
    align-items: center;
}
.gantt-bar-wp {
    background: var(--c-accent);
    font-weight: 600;
}
.gantt-bar-act {
    background: #6B7280;
    font-weight: 400;
    font-size: 10px;
}

/* ──────────────────────────────────────────────────────────────────
   Checklist · matriz unificada (PR-CHK-6)
   Filas = participantes + 1 fila "Proyecto"; columnas = ítems agrupados
   por sección; celdas = botón con estado clicable que abre un popover.
   ────────────────────────────────────────────────────────────────── */
.checklist-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}
.checklist-filtros {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
}
.checklist-filtros select {
    margin-left: 6px;
}
.matriz-checklist-wrap {
    overflow-x: auto;
    border: 1px solid var(--c-border);
    border-radius: 4px;
    background: var(--c-surface);
    max-width: 100%;
}
.matriz-checklist {
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13px;
    width: max-content;
    min-width: 100%;
}
.matriz-checklist thead th {
    background: var(--c-bg);
    border-bottom: 1px solid var(--c-border);
    padding: 8px 10px;
    text-align: center;
    font-weight: 600;
    font-size: 12px;
    color: var(--c-text);
    position: sticky;
    top: 0;
    z-index: 2;
}
.matriz-checklist .matriz-th-seccion {
    background: var(--c-bg);
    color: var(--c-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
    border-bottom: 1px solid var(--c-border);
}
.matriz-checklist .matriz-th-item {
    min-width: 120px;
    max-width: 200px;
    vertical-align: bottom;
    line-height: 1.25;
}
/* Separador visual entre secciones: borde izquierdo más grueso en la
   primera celda/cabecera de cada grupo (excepto la primera sección). */
.matriz-checklist .matriz-th-seccion.seccion-start,
.matriz-checklist .matriz-th-item.seccion-start,
.matriz-checklist tbody td.matriz-celda.seccion-start {
    border-left: 2px solid var(--c-border);
}
.matriz-checklist .matriz-th-item .matriz-th-ambito {
    display: block;
    font-size: 10px;
    font-weight: 400;
    color: var(--c-text-muted);
    margin-top: 2px;
}
.matriz-checklist .matriz-corner {
    background: var(--c-bg);
    border-right: 1px solid var(--c-border);
    text-align: left;
    min-width: 220px;
    max-width: 280px;
    position: sticky;
    left: 0;
    z-index: 3;
}
.matriz-checklist tbody td {
    border-bottom: 1px solid var(--c-border);
    padding: 6px 8px;
    text-align: center;
    vertical-align: middle;
}
.matriz-checklist tbody td.matriz-fila {
    text-align: left;
    padding: 8px 12px;
    background: var(--c-surface);
    border-right: 1px solid var(--c-border);
    position: sticky;
    left: 0;
    z-index: 1;
    min-width: 220px;
}
.matriz-checklist tbody tr:hover td.matriz-fila {
    background: var(--c-bg);
}
.matriz-celda {
    min-width: 80px;
}
.matriz-celda-na {
    background: repeating-linear-gradient(
        45deg,
        transparent, transparent 6px,
        rgba(0,0,0,0.03) 6px, rgba(0,0,0,0.03) 12px
    );
}
.matriz-celda .celda-na {
    color: var(--c-text-muted);
    opacity: 0.4;
    font-size: 14px;
}
/* Paleta de estados del checklist — tonos suaves (fondo con alpha bajo +
   texto saturado). Semántica fijada por operación: ok=verde, en
   progreso=naranja, pendiente=rojo, bloqueado=marrón, N/A=gris.
   `chk-estado-*` es reutilizable: lo usan las celdas de la matriz y los
   badges/contadores del dashboard de checklist. */
/* Pill genérica para contadores de estado (combina con `chk-estado-*`). */
.chk-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
}
.chk-estado-ok {
    background: rgba(21, 128, 61, 0.13);
    color: #15803D;
    border-color: rgba(21, 128, 61, 0.35);
}
.chk-estado-en_progreso {
    background: rgba(194, 65, 12, 0.13);
    color: #C2410C;
    border-color: rgba(194, 65, 12, 0.35);
}
.chk-estado-pendiente {
    background: rgba(185, 28, 28, 0.13);
    color: #B91C1C;
    border-color: rgba(185, 28, 28, 0.35);
}
.chk-estado-bloqueado {
    background: rgba(120, 72, 40, 0.15);
    color: #784828;
    border-color: rgba(120, 72, 40, 0.4);
}
.chk-estado-na {
    background: var(--c-bg);
    color: var(--c-text-muted);
    border-color: var(--c-border);
}

.celda-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid transparent;
    background: transparent;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    transition: transform 0.08s ease, box-shadow 0.08s ease;
}
.celda-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 1px 4px rgba(0,0,0,0.18);
}
/* Punto de color del estado dentro de la pill. */
.celda-btn .celda-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}
.celda-btn .celda-clip {
    font-size: 10px;
    opacity: 0.85;
    font-weight: 400;
}
.celda-btn.estado-pendiente   { background: rgba(185, 28, 28, 0.13); color: #B91C1C; border-color: rgba(185, 28, 28, 0.35); }
.celda-btn.estado-en_progreso { background: rgba(194, 65, 12, 0.13); color: #C2410C; border-color: rgba(194, 65, 12, 0.35); }
.celda-btn.estado-bloqueado   { background: rgba(120, 72, 40, 0.15); color: #784828; border-color: rgba(120, 72, 40, 0.4); }
.celda-btn.estado-ok          { background: rgba(21, 128, 61, 0.13);  color: #15803D; border-color: rgba(21, 128, 61, 0.35); }
.celda-btn.estado-na {
    background: var(--c-bg);
    color: var(--c-text-muted);
    border-color: var(--c-border);
}
.celda-btn.estado-na .celda-dot { opacity: 0.5; }

/* Popover de celda — flotante encima de la matriz. */
.celda-popover-overlay {
    background: rgba(0,0,0,0.04);
}
.celda-popover {
    padding: 14px 16px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.18);
    border: 1px solid var(--c-border);
    background: var(--c-surface);
}
.celda-popover select,
.celda-popover input[type="text"] {
    width: 100%;
    margin-top: 4px;
}

@media (max-width: 700px) {
    .matriz-checklist .matriz-corner,
    .matriz-checklist tbody td.matriz-fila {
        min-width: 160px;
    }
    .matriz-checklist .matriz-th-item {
        min-width: 90px;
    }
}

/* ──────────────────────────────────────────────────────────────────
   Tablas ordenables en cliente — clase `tabla-ordenable`.
   Click en la cabecera ordena; el indicador refleja `aria-sort`.
   ────────────────────────────────────────────────────────────────── */
.tabla-ordenable th.th-ordenable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.tabla-ordenable th.th-ordenable:hover {
    color: var(--c-accent);
    background: var(--c-bg);
}
/* Indicador siempre visible junto al texto de la cabecera: deja claro que
   la columna es ordenable sin necesidad de hover. */
.tabla-ordenable th.th-ordenable::after {
    content: "⇅";
    margin-left: 5px;
    font-size: 11px;
    color: var(--c-text-muted);
    opacity: 0.6;
}
.tabla-ordenable th.th-ordenable:hover::after {
    color: var(--c-accent);
    opacity: 1;
}
.tabla-ordenable th[aria-sort="ascending"]::after {
    content: "▲";
    font-size: 9px;
    color: var(--c-accent);
    opacity: 1;
}
.tabla-ordenable th[aria-sort="descending"]::after {
    content: "▼";
    font-size: 9px;
    color: var(--c-accent);
    opacity: 1;
}

/* Cifra destacada en ámbar (p. ej. horas tras la baja, PR-PERS-2). */
.text-warn { color: var(--c-warn); font-weight: 600; }
