/* ─────────────────────────────────────────────
   IPL CRONOS — Estilos principales
   Mobile-first, responsive, multi-navegador
   ───────────────────────────────────────────── */

/* ── Reset & Base ── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

:root {
    --color-primary: #2563EB;
    --color-primary-dark: #1d4ed8;
    --color-primary-light: #dbeafe;
    --color-success: #10B981;
    --color-success-light: #dcfce7;
    --color-danger: #EF4444;
    --color-danger-light: #fef2f2;
    --color-warning: #F59E0B;
    --color-warning-light: #fffbeb;
    --color-gray-50: #f8fafc;
    --color-gray-100: #f1f5f9;
    --color-gray-200: #e2e8f0;
    --color-gray-300: #cbd5e1;
    --color-gray-400: #94a3b8;
    --color-gray-500: #64748b;
    --color-gray-600: #475569;
    --color-gray-700: #334155;
    --color-gray-800: #1e293b;
    --color-gray-900: #0f172a;
    --radius: 8px;
    --radius-lg: 12px;
    --shadow: 0 1px 3px rgba(0,0,0,0.1);
    --shadow-lg: 0 4px 16px rgba(0,0,0,0.1);
    --nav-height: 60px;
    --header-height: 56px;
}

html {
    font-size: 16px;
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
    background: var(--color-gray-100);
    color: var(--color-gray-800);
    line-height: 1.5;
    min-height: 100vh;
    min-height: 100dvh;
    overflow-x: hidden;
}

[x-cloak] { display: none !important; }

/* ── Header ── */
.app-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--header-height);
    background: var(--color-gray-800);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    z-index: 100;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

.header-left {
    display: flex;
    align-items: center;
    gap: 8px;
}

.header-logo { font-size: 1.3rem; }
.header-title { font-size: 0.95rem; font-weight: 600; letter-spacing: 0.5px; }

.header-user {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: var(--radius);
    transition: background 0.2s;
    /* v1.1.90: cuando .header-user es <button> (por accesibilidad) reseteamos
       los estilos por defecto del navegador (border, background, color, font)
       para que se vea idéntico al <div> original. */
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
}
.header-user:hover { background: rgba(255,255,255,0.1); }
.header-user:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; }

.user-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
}

.user-name {
    font-size: 0.85rem;
    font-weight: 500;
    /* v1.3.24.2: ocultar en mobile. El nombre + avatar + campana + título
       del header no caben en pantallas estrechas (<768px) — el nombre
       empujaba la campana fuera del viewport por la derecha. En mobile
       basta con el avatar (las iniciales) para identificar al usuario;
       el nombre completo aparece en el dropdown del menú. La regla
       @media min-width:768px más abajo lo restaura en desktop. */
    display: none;
}

/* ── v1.3.22.4: Campana de pendientes — separación clara ──
   Botón 44x44 con emoji visible, badge desplazado claramente fuera del
   botón (top -6 / right -6) para que no tape el icono nunca. Wrapper
   con padding extra para que el badge no se corte por overflow. */
.header-bell {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius);
    cursor: pointer;
    border: 0;
    background: transparent;
    color: inherit;
    line-height: 1;
    transition: background 0.2s;
    padding: 0;
}
.header-bell > span[aria-hidden] {
    font-size: 1.5rem;
    line-height: 1;
}
.header-bell:hover { background: rgba(255,255,255,0.1); }
.header-bell:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; }
.header-bell-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    background: #dc2626;
    color: #fff;
    border-radius: 11px;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
    padding: 3px 6px;
    min-width: 18px;
    text-align: center;
    border: 2px solid #1e293b;
    pointer-events: none;
    box-shadow: 0 2px 4px rgba(0,0,0,0.15);
}
.header-bell-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: #fff;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    min-width: 280px;
    max-width: 340px;
    z-index: 200;
    overflow: hidden;
    border: 1px solid var(--color-gray-200);
    color: #1e293b;
}
.header-bell-dropdown-header {
    padding: 10px 14px;
    border-bottom: 1px solid var(--color-gray-200);
    font-size: 0.78rem;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: #f8fafc;
}
.header-bell-empty {
    padding: 24px 14px;
    text-align: center;
    color: #64748b;
    font-size: 0.9rem;
}
.header-bell-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    color: #1e293b;
    text-decoration: none;
    font-size: 0.88rem;
    border-bottom: 1px solid var(--color-gray-100);
    transition: background 0.15s;
}
.header-bell-item:last-child { border-bottom: 0; }
.header-bell-item:hover { background: #f1f5f9; }
.header-bell-item-icon {
    flex: 0 0 auto;
    font-size: 1.1rem;
}
.header-bell-item-text {
    flex: 1 1 auto;
    line-height: 1.35;
}
.header-bell-item-text strong { color: #dc2626; margin-right: 4px; }
.header-bell-item-arrow {
    flex: 0 0 auto;
    color: #94a3b8;
    font-size: 1.2rem;
}

/* ── Dropdown Menu ── */
.dropdown-menu {
    position: fixed;
    top: calc(var(--header-height) + 4px);
    right: 8px;
    background: #fff;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    min-width: 200px;
    z-index: 200;
    overflow: hidden;
    border: 1px solid var(--color-gray-200);
}

.dropdown-item {
    display: block;
    padding: 10px 16px;
    color: var(--color-gray-700);
    text-decoration: none;
    font-size: 0.9rem;
    transition: background 0.15s;
}
.dropdown-item:hover { background: var(--color-gray-50); }
.dropdown-divider { height: 1px; background: var(--color-gray-200); }
.text-danger { color: var(--color-danger) !important; }

/* ── v1.3.1: cabeceras de sección colapsables del menú ──
   Botón con apariencia de cabecera (gris pequeño uppercase) pero
   clicable. Hereda colores del tema; foco visible por defecto vía
   :focus-visible global más abajo.
   v1.3.2: variante "-top" para cabeceras de primer nivel (Administración,
   Gestión de equipo, Mi cuenta) — un poco más prominentes que las anidadas
   (Personal, Planificación, Configuración) para reflejar la jerarquía. */
.dropdown-section-toggle {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px 4px;
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--color-gray-300, #cbd5e1);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    background: transparent;
    border: 0;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    transition: color 0.15s;
}
.dropdown-section-toggle:hover { color: var(--color-gray-500, #64748b); }
.dropdown-section-toggle-top {
    padding: 6px 14px;
    font-size: 0.7rem;
    color: var(--color-gray-400, #94a3b8);
}
.dropdown-section-chevron {
    display: inline-block;
    width: 10px;
    font-size: 0.55rem;
    color: var(--color-gray-400, #94a3b8);
}

/* ── v1.3.6: cuadrante — celda disponible centrada con flex ──
   Necesita ser una clase (no inline en :style) porque al combinar
   x-show con :style { display:'flex', ... }, el display:flex pisa el
   display:none que x-show inyecta. Resultado: la celda "available"
   se renderiza siempre, también sobre celdas de festivo o ausencia.
   Solución: x-show controla visibility con su display:none, y la
   clase aplica display:flex solo cuando x-show no la oculta. */
.schedule-cell-available {
    padding: 6px 4px;
    border-radius: 4px;
    min-height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: 1px solid #f1f5f9;
}
.schedule-cell-available.workable {
    border: 1px dashed #fbbf24;
}
.schedule-cell-available.focused {
    outline: 2px solid #3b82f6;
}
/* v1.3.12: celda seleccionada (selección múltiple). Outline más intenso
   (azul oscuro) + tinte de fondo suave para que se distinga claramente
   de la celda enfocada. La selección tiene precedencia visual sobre el
   foco — outline:2px solid #2563eb (azul más oscuro que focused). */
.schedule-cell-available.selected {
    outline: 2px solid #2563eb;
    outline-offset: -2px;
    box-shadow: inset 0 0 0 9999px rgba(37, 99, 235, 0.08);
}
/* Si está enfocada y seleccionada a la vez, el outline de selected gana
   por especificidad (orden de declaración) — la regla .focused queda
   sobreescrita por .selected, no necesitamos !important. */

/* v1.3.12.2: bloquear selección de texto en TODA la tabla del cuadrante.
   Sin esto, Shift+click en celdas distantes seleccionaba el texto de las
   celdas intermedias junto al rectángulo, dejando el cuadrante con
   apariencia "sucia" tras la operación. La tabla no contiene texto que
   el usuario necesite copiar manualmente — los códigos de plantilla son
   accesibles desde el popover y los nombres de empleado desde la ficha
   de empleado. */
.schedule-grid {
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
}

.menu-enter { animation: slideDown 0.15s ease; }
.menu-leave { animation: slideUp 0.15s ease; }

/* ── Content Area ── */
.app-content {
    padding-top: var(--header-height);
    padding-bottom: calc(var(--nav-height) + 16px);
    min-height: 100vh;
    min-height: 100dvh;
}

/* ── Bottom Nav ── */
.app-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: var(--nav-height);
    background: #fff;
    display: flex;
    align-items: center;
    justify-content: space-around;
    border-top: 1px solid var(--color-gray-200);
    z-index: 100;
    padding-bottom: env(safe-area-inset-bottom, 0);
}

.nav-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    text-decoration: none;
    color: var(--color-gray-400);
    font-size: 0.7rem;
    padding: 6px 16px;
    border-radius: var(--radius);
    transition: color 0.2s;
    -webkit-tap-highlight-color: transparent;
}

.nav-item.active, .nav-item:hover {
    color: var(--color-primary);
}

.nav-icon { font-size: 1.3rem; }
.nav-label { font-weight: 500; }

/* ── Page containers ── */
.page { padding: 20px 16px; max-width: 600px; margin: 0 auto; overflow-x: clip; }
.page-wide { padding: 20px 16px; max-width: 1000px; margin: 0 auto; overflow-x: clip; }
.page-full { padding: 0; }

/* ── Cards ── */
.card {
    background: #fff;
    border-radius: var(--radius-lg);
    box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04);
    padding: 20px;
    margin-bottom: 16px;
    max-width: 100%;
}
/* En móvil el padding de la card baja para dar más aire interno
   (en viewports pequeños, 20px a cada lado se come demasiado espacio). */
@media (max-width: 640px) {
    .card { padding: 16px 14px; }
}

/* ── Buttons ── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 24px;
    border: none;
    border-radius: var(--radius);
    font-size: 0.95rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.2s;
    -webkit-tap-highlight-color: transparent;
    min-height: 44px;
    text-decoration: none;
}

.btn-primary { background: var(--color-primary); color: #fff; }
.btn-primary:hover { background: var(--color-primary-dark); }
.btn-success { background: var(--color-success); color: #fff; }
.btn-success:hover { background: #059669; }
.btn-danger { background: var(--color-danger); color: #fff; }
.btn-danger:hover { background: #dc2626; }
.btn-warning { background: var(--color-warning); color: #fff; }
.btn-warning:hover { background: #d97706; }
.btn-secondary { background: var(--color-gray-200); color: var(--color-gray-700); }
.btn-secondary:hover { background: var(--color-gray-300); }

/* ──────────────────────────────────────────────────────────
   Confirmación destructiva — estados del helper confirmGuard
   ────────────────────────────────────────────────────────── */

/* Botón en estado "confirmando" — rojo intenso con contador visible.
   Aplica independientemente de la clase de color original (.btn-danger,
   .btn-warning, etc.) para que el usuario vea un cambio INEQUÍVOCO. */
.btn-confirm-armed,
.btn-confirm-armed:hover {
    background: #dc2626 !important;
    color: #fff !important;
    border-color: #dc2626 !important;
    box-shadow: 0 0 0 3px rgba(220,38,38,0.15) !important;
    animation: confirmPulse 1s ease-in-out infinite;
}

/* Durante los primeros 2s (lock) el botón está :disabled vía Alpine y
   muestra cursor 'not-allowed' para indicar que NO se puede clicar aún.
   v1.3.14.7: cambiado de 'cursor: wait' (círculo girando del SO) a
   'cursor: not-allowed' (icono prohibido) por preferencia de UX —
   más coherente con cualquier otro botón disabled del proyecto y
   menos confuso (el "spinner" del cursor sugería procesamiento, pero
   en realidad es solo un bloqueo anti-doubleclick). */
.btn-confirm-locked {
    cursor: not-allowed !important;
    opacity: 0.85;
}

/* Pulso sutil para comunicar "estoy esperando tu segunda pulsación" */
@keyframes confirmPulse {
    0%, 100% { box-shadow: 0 0 0 3px rgba(220,38,38,0.15); }
    50%      { box-shadow: 0 0 0 6px rgba(220,38,38,0.25); }
}

.btn-lg {
    padding: 16px 32px;
    font-size: 1.1rem;
    border-radius: var(--radius-lg);
    min-height: 56px;
}

.btn-xl {
    padding: 20px 40px;
    font-size: 1.3rem;
    border-radius: 16px;
    min-height: 64px;
    width: 100%;
}

.btn-block { width: 100%; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Forms ── */
.form-group { margin-bottom: 12px; }

.form-group label {
    display: block;
    font-weight: 500;
    font-size: 0.85rem;
    margin-bottom: 5px;
    color: var(--color-gray-600);
}

.form-input {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    padding: 10px 14px;
    border: 1px solid var(--color-gray-300);
    border-radius: var(--radius);
    font-size: 1rem;
    font-family: inherit;
    color: var(--color-gray-800);
    background: #fff;
    transition: border-color 0.2s, box-shadow 0.2s;
    min-height: 44px;
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.06);
}

.form-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.06), 0 0 0 3px rgba(37,99,235,0.12);
}

/* Readonly y disabled: fondo gris claro, cursor default, sin foco azul */
.form-input:read-only,
.form-input:disabled {
    background: #f8fafc;
    color: #64748b;
    cursor: default;
}
.form-input:read-only:focus {
    border-color: var(--color-gray-300);
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.06);
}

/* ── Status badges ── */
.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 0.85rem;
    font-weight: 500;
}

.status-working {
    background: var(--color-success-light);
    color: #166534;
}

.status-break {
    background: var(--color-warning-light);
    color: #92400e;
}

.status-not-clocked {
    background: var(--color-gray-100);
    color: var(--color-gray-500);
}

.status-clocked-out {
    background: var(--color-primary-light);
    color: #1e40af;
}

/* ── Login Page ── */
.login-page {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: var(--color-gray-800);
}

.login-card {
    background: #fff;
    border-radius: var(--radius-lg);
    padding: 32px;
    width: 100%;
    max-width: 380px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.08), 0 8px 32px rgba(0,0,0,0.06);
}

.login-header {
    text-align: center;
    margin-bottom: 28px;
}

.login-logo { font-size: 2.5rem; margin-bottom: 8px; }
.login-title { font-size: 1.2rem; font-weight: 600; color: var(--color-gray-800); }
.login-subtitle { font-size: 0.85rem; color: var(--color-gray-500); margin-top: 4px; }

.login-error {
    background: var(--color-danger-light);
    color: #991b1b;
    padding: 10px 14px;
    border-radius: var(--radius);
    font-size: 0.85rem;
    margin-bottom: 16px;
    border: 1px solid #fca5a5;
}

.login-footer {
    text-align: center;
    margin-top: 20px;
}

.login-footer a {
    color: var(--color-primary);
    text-decoration: none;
    font-size: 0.85rem;
}

/* ── Terminal Page ── */
.terminal-page {
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--color-gray-900);
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: clamp(10px, 2vh, 24px);
    user-select: none;
    -webkit-user-select: none;
}

.terminal-clock {
    font-size: clamp(2.5rem, 11vh, 8rem);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: clamp(1px, 0.6vh, 6px);
    margin-bottom: 4px;
    text-align: center;
    line-height: 1;
}

.terminal-date {
    font-size: clamp(0.85rem, 1.8vh, 1.3rem);
    color: var(--color-gray-400);
    text-transform: capitalize;
    margin-bottom: clamp(16px, 3vh, 36px);
}

/* Numpad */
.numpad {
    background: rgba(255,255,255,0.04);
    border: 1px solid rgba(255,255,255,0.06);
    border-radius: 20px;
    padding: clamp(16px, 3vh, 32px);
    width: 100%;
    max-width: clamp(280px, 50vh, 420px);
    margin: 0 auto;
}

.numpad-display {
    text-align: center;
    margin-bottom: clamp(12px, 2vh, 20px);
}

.numpad-label {
    font-size: clamp(0.8rem, 1.4vh, 0.95rem);
    color: var(--color-gray-400);
    margin-bottom: clamp(8px, 1.2vh, 10px);
}

.numpad-dots {
    display: flex;
    justify-content: center;
    gap: clamp(10px, 1.8vh, 16px);
}

.pin-dot {
    width: clamp(14px, 2.2vh, 20px);
    height: clamp(14px, 2.2vh, 20px);
    border-radius: 50%;
    background: rgba(255,255,255,0.12);
    transition: background 0.2s, transform 0.2s;
}

.pin-dot.filled { background: var(--color-primary); transform: scale(1.15); }

.numpad-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(8px, 1.3vh, 12px);
}

.numpad-btn {
    height: clamp(48px, 9vh, 90px);
    border: none;
    border-radius: clamp(12px, 1.5vh, 16px);
    background: rgba(255,255,255,0.07);
    color: #fff;
    /* Números grandes — el terminal se usa en kiosko/tablet fija a
       40-60cm del usuario, que a menudo teclea de pie. Antes usábamos
       `clamp(1.25rem, 3vh, 2.2rem)` que en viewports medios (~720px
       alto) daba ~21px de número dentro de una caja de ~65px — ratio
       del 32%, demasiado pequeño. Ahora 2.5vh mínimo y tope a 3rem,
       con base que escala más rápido para alcanzar un ratio cómodo
       del 50-55%. */
    font-size: clamp(1.8rem, 5vh, 3rem);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, transform 0.1s;
    -webkit-tap-highlight-color: transparent;
}

.numpad-btn:hover { background: rgba(255,255,255,0.14); }
.numpad-btn:active { background: rgba(255,255,255,0.2); transform: scale(0.95); }
/* "C" y "←" son auxiliares — algo más pequeños que los dígitos para
   que la mirada del usuario vaya primero a los números. */
.numpad-btn.btn-clear { font-size: clamp(1.1rem, 3vh, 1.7rem); color: var(--color-gray-400); }

/* Terminal action buttons */
.terminal-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(10px, 2vh, 16px);
    width: 100%;
    max-width: clamp(320px, 60vh, 460px);
    margin: clamp(16px, 3vh, 28px) auto 0;
}

.terminal-btn {
    padding: clamp(16px, 3.5vh, 32px) clamp(12px, 2vh, 24px);
    border: none;
    border-radius: clamp(14px, 2vh, 20px);
    font-size: clamp(0.95rem, 1.8vh, 1.2rem);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.2s;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.3);
}

.terminal-btn-icon { font-size: clamp(1.4rem, 3.5vh, 2.5rem); }
.terminal-btn-label { font-size: clamp(0.85rem, 1.8vh, 1.2rem); font-weight: 700; letter-spacing: 0.05em; }

.terminal-btn-in { background: linear-gradient(145deg, #10b981, #059669); color: #fff; }
.terminal-btn-in:hover { background: linear-gradient(145deg, #059669, #047857); }
.terminal-btn-out { background: linear-gradient(145deg, #ef4444, #dc2626); color: #fff; }
.terminal-btn-out:hover { background: linear-gradient(145deg, #dc2626, #b91c1c); }
.terminal-btn-break-start { background: linear-gradient(145deg, #f59e0b, #d97706); color: #fff; }
.terminal-btn-break-start:hover { background: linear-gradient(145deg, #d97706, #b45309); }
.terminal-btn-break-end { background: linear-gradient(145deg, #3b82f6, #2563eb); color: #fff; }
.terminal-btn-break-end:hover { background: linear-gradient(145deg, #2563eb, #1d4ed8); }

/* Terminal confirmation */
.terminal-confirm {
    text-align: center;
    animation: fadeIn 0.4s ease;
}

.terminal-confirm-icon { font-size: clamp(3rem, 10vh, 7rem); margin-bottom: clamp(14px, 2.5vh, 24px); }
.terminal-confirm-action { font-size: clamp(1rem, 2vh, 1.5rem); color: var(--color-gray-400); margin-bottom: clamp(6px, 1.2vh, 12px); text-transform: uppercase; letter-spacing: 0.15em; }
.terminal-confirm-name { font-size: clamp(1.5rem, 4vh, 3rem); font-weight: 700; margin-bottom: clamp(12px, 2.5vh, 20px); }
.terminal-confirm-time { font-size: clamp(2.5rem, 8vh, 6rem); font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: clamp(1px, 0.3vh, 2px); }

.terminal-exit {
    position: fixed;
    bottom: 20px;
    right: 20px;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.1);
    color: var(--color-gray-500);
    padding: 8px 16px;
    border-radius: var(--radius);
    font-size: 0.75rem;
    cursor: pointer;
}

/* ── Clock page (employee remote) ── */
.clock-greeting {
    font-size: 1.1rem;
    font-weight: 500;
    color: var(--color-gray-600);
    margin-bottom: 4px;
}

.clock-time-display {
    text-align: center;
    padding: 24px 0;
}

.clock-today-time {
    font-size: 2.5rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-gray-800);
}

.clock-today-label {
    font-size: 0.85rem;
    color: var(--color-gray-500);
    margin-top: 4px;
}

.clock-actions {
    display: flex;
    gap: 12px;
    margin: 20px 0;
}

.clock-actions .btn { flex: 1; }

/* Entry list */
.entry-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-gray-100);
}
.entry-item:last-child { border-bottom: none; }

.entry-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.entry-dot-in { background: var(--color-success); }
.entry-dot-out { background: var(--color-danger); }
.entry-dot-break { background: var(--color-warning); }

.entry-time {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 50px;
}

.entry-label { color: var(--color-gray-500); font-size: 0.85rem; }

/* ── Spinner ── */
.spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--color-gray-200);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 0 auto;
}

/* ── Animations ── */
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes slideDown { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes slideUp { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-8px); } }
@keyframes notifyIn { from { opacity: 0; transform: translate(-50%, -12px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes notifyOut { from { opacity: 1; } to { opacity: 0; transform: translate(-50%, -8px); } }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.6; } }

.animate-in { animation: fadeIn 0.3s ease; }

/* ── Responsive ── */

/* Tablet / Desktop: el terminal ya es responsive por clamp(vh).
   Estas media queries antiguas basadas en ancho del viewport han sido
   retiradas porque pisaban los clamp() con valores fijos en px que no
   tenían en cuenta la ALTURA disponible — en un desktop con ventana
   ancha pero baja (~700px), forzaban terminal-clock:8rem y
   numpad-btn:90px y el contenido se salía del viewport.
   Los clamp() escalan desde móvil pequeño hasta pantalla grande. */

/* Desktop: solo afecta al resto de la app, no al terminal (terminal es responsive por clamp) */
@media (min-width: 768px) {
    .app-nav { display: none; }
    .app-content { padding-bottom: 20px; }
    .user-name { display: inline; }
}

/* Small phones: retirado. Los clamp(vh) ya garantizan mínimos táctiles
   (botones numpad nunca bajan de 48px) y proporciones correctas. */

/* Safe areas (iPhone notch) */
@supports (padding: env(safe-area-inset-bottom)) {
    .app-nav { padding-bottom: env(safe-area-inset-bottom); }
    .terminal-page { padding-bottom: env(safe-area-inset-bottom); }
}

/* ─────────────────────────────────────────────────────────
   Form grid 12-col (v1.1.76+)
   Sistema flexible para forms con anchos proporcionales al
   contenido esperado (no al label). Uso:

     <div class="form-row">
         <div class="form-col-2 form-group">Nº empleado</div>
         <div class="form-col-5 form-group">Nombre</div>
         <div class="form-col-5 form-group">Apellidos</div>
     </div>

   Principio: columnas suman 12 en escritorio. En mobile colapsa
   a 1 col. En tablet intermedia (601-780px), los anchos 1..6
   pasan a 6 cols (media fila), los 7..12 a full. Preserva
   legibilidad sin squashing en anchos estrechos.

   Convive con form-grid-2/3/cp antiguos — no romper páginas
   legacy. Todo nuevo debería usar form-row/form-col-N.
   ───────────────────────────────────────────────────────── */
.form-row {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 10px;
}
.form-row > * { min-width: 0; }

.form-col-1  { grid-column: span 1; }
.form-col-2  { grid-column: span 2; }
.form-col-3  { grid-column: span 3; }
.form-col-4  { grid-column: span 4; }
.form-col-5  { grid-column: span 5; }
.form-col-6  { grid-column: span 6; }
.form-col-7  { grid-column: span 7; }
.form-col-8  { grid-column: span 8; }
.form-col-9  { grid-column: span 9; }
.form-col-10 { grid-column: span 10; }
.form-col-11 { grid-column: span 11; }
.form-col-12 { grid-column: span 12; }

/* Tablet intermedia: los anchos chicos (≤5) conservan proporción
   pero se reagrupan. 6/7/8 se comprimen a 6, y 9+ pasan a full
   para que no queden campos minúsculos al hacer wrap. */
@media (max-width: 780px) and (min-width: 601px) {
    .form-col-1 { grid-column: span 3; }
    .form-col-2 { grid-column: span 4; }
    .form-col-3 { grid-column: span 6; }
    .form-col-4 { grid-column: span 6; }
    .form-col-5 { grid-column: span 6; }
    .form-col-6 { grid-column: span 6; }
    .form-col-7,  .form-col-8,  .form-col-9,
    .form-col-10, .form-col-11, .form-col-12 { grid-column: span 12; }
}

/* Mobile: todo full-width apilado. Fechas y CPs siempre necesitan
   mínimo el ancho real del input nativo; si van sueltos en 1 col
   ocupan 100% sin problema. */
@media (max-width: 600px) {
    .form-col-1,  .form-col-2,  .form-col-3,
    .form-col-4,  .form-col-5,  .form-col-6,
    .form-col-7,  .form-col-8,  .form-col-9,
    .form-col-10, .form-col-11, .form-col-12 { grid-column: span 12; }
}

/* Section header dentro de forms — para agrupar campos con título
   y separador visual. Coste vertical: ~36px. */
.form-section-title {
    grid-column: span 12;
    font-size: 0.95rem;
    color: #334155;
    font-weight: 600;
    margin: 8px 0 2px;
    padding-top: 10px;
    border-top: 1px dashed #e2e8f0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.form-section-title:first-child {
    border-top: none;
    padding-top: 0;
    margin-top: 0;
}
.form-section-hint {
    font-size: 0.72rem;
    color: #94a3b8;
    font-weight: 400;
}

/* ─────────────────────────────────────────────────────────
   Form grids responsivos LEGACY — mantener por compatibilidad
   hasta migrar todas las páginas al sistema form-row/form-col-N.
   ───────────────────────────────────────────────────────── */
.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.form-grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; }
.form-grid-cp { display: grid; grid-template-columns: 120px 1fr; gap: 10px; }

.form-grid-2 > *,
.form-grid-3 > *,
.form-grid-cp > * { min-width: 0; }

@media (max-width: 600px) {
    .form-grid-2 { grid-template-columns: 1fr; }
    .form-grid-3 { grid-template-columns: 1fr; }
}
@media (min-width: 601px) and (max-width: 780px) {
    .form-grid-3 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
    .form-grid-cp { grid-template-columns: 1fr; }
}

/* Listados con estilo tabla */
.list-table { border:1px solid #e2e8f0; border-radius:8px; overflow:hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 2px 8px rgba(0,0,0,0.03); }
.list-header {
    display: flex; align-items: center; gap: 12px; padding: 10px 16px;
    background: #f1f5f9; border-bottom: 1px solid #e2e8f0;
    font-size: 0.8rem; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.03em;
}
.list-row {
    display: flex; align-items: center; gap: 12px; padding: 12px 16px;
    border-bottom: 1px solid #f1f5f9; transition: background 0.15s;
}
.list-row:last-child { border-bottom: none; }
.list-row:nth-child(even) { background: #f8fafc; }
.list-row:hover { background: #f1f5f9; }
.list-empty { padding: 40px 20px; text-align: center; color: #94a3b8; font-size: 0.9rem; background: #fff; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }

/* Empleados: alternancia sutil en tarjetas */
.emp-card { transition: box-shadow 0.15s; }
.emp-card:nth-child(even) > .card { background: #f8fafc; }
.emp-card:hover > .card { box-shadow: 0 2px 12px rgba(0,0,0,0.08); }

/* ──────────────────────────────────────────────────────────
   Filas de listado responsive: escritorio en línea,
   móvil/tablet se apilan con info arriba y botones
   abajo a ancho completo.

   Uso:
     <div class="responsive-row">
        <div class="responsive-row-info">...</div>
        <div class="responsive-row-actions">...botones...</div>
     </div>

   Aplicable a admin-employees, admin-holidays, futuras tablas
   que tengan botones de acción al final de fila.
   ────────────────────────────────────────────────────────── */
.responsive-row {
    display: flex;
    align-items: center;
    gap: 12px;
}
.responsive-row-info {
    flex: 1;
    min-width: 0;                 /* evita que texto largo rompa layout */
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.responsive-row-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
    flex-wrap: wrap;
}
@media (max-width: 768px) {
    .responsive-row {
        flex-direction: column;
        align-items: stretch;
    }
    .responsive-row-actions {
        width: 100%;
        justify-content: flex-start;
        border-top: 1px solid #f1f5f9;
        padding-top: 10px;
        margin-top: 4px;
        /* Grid 2 columnas en móvil: los botones nunca compiten por un hueco
           imposible cuando hay 3 o 4 acciones. Mantiene altura razonable y
           textos legibles sin desbordar. */
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 6px;
    }
    .responsive-row-actions .btn {
        min-width: 0;
        font-size: 0.8rem;
        padding: 8px 10px;
        line-height: 1.25;
        /* Permitimos wrap a 2 líneas: "Reset contraseña" partido es preferible
           a que se salga del botón. */
        white-space: normal;
        word-break: keep-all;
    }
}
/* Pantallas muy pequeñas (<380px): 1 columna para evitar cortes raros. */
@media (max-width: 380px) {
    .responsive-row-actions {
        grid-template-columns: 1fr;
    }
}

/* Terminal: countdown bar */
@keyframes shrink { from { width: 100%; } to { width: 0%; } }

/* Depth: tablas dentro de cards */
.card table { box-shadow: inset 0 1px 3px rgba(0,0,0,0.04); }
.card table thead tr { box-shadow: 0 1px 2px rgba(0,0,0,0.06); }

/* Depth: botones primarios */
.btn-primary { box-shadow: 0 1px 3px rgba(37,99,235,0.3); }
.btn-primary:hover { box-shadow: 0 2px 6px rgba(37,99,235,0.35); }
.btn-danger { box-shadow: 0 1px 3px rgba(220,38,38,0.25); }
.btn-success { box-shadow: 0 1px 3px rgba(5,150,105,0.25); }

/* ──────────────────────────────────────────
   Utilidades reutilizables (reemplazan inline styles)
   ────────────────────────────────────────── */

/* Tarjetas de estadísticas (dashboard) */
.stat-card { padding: 16px; text-align: center; }
.stat-label { font-size: 0.8rem; color: #64748b; margin-top: 4px; }
.stat-label-small { font-size: 0.65rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 2px; font-weight: 600; }

/* Grid simétrico para 6 tarjetas de estadística del dashboard admin
   Móvil (<640): 2 col → 3 filas de 2
   Tablet (640-1024): 3 col → 2 filas de 3
   Desktop (>1024): 6 col → 1 fila de 6
   Siempre filas completas, nunca una card huérfana */
/* Grid de cards estadísticas del dashboard — 8 cards
   Móvil (<640): 2 col → 4 filas
   Tablet (640-1024): 3 col → 3 filas (última queda huérfana, aceptable)
   Laptop (1024-1440): 4 col → 2 filas
   Desktop amplio (>1440): 4 col → 2 filas (legibilidad > compactación)
   Desktop ultra (>1680): 8 col → 1 fila */
.dashboard-stats-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin-bottom: 20px;
}
/* Defensa contra overflow horizontal: grid items con min-width auto
   (default) se niegan a encogerse por debajo del ancho de su contenido
   intrínseco. Sin esto, un pill con nowrap o un texto largo puede
   forzar que el grid sea más ancho que el viewport y que la página
   entera se salga por la derecha. */
.dashboard-stats-grid > *,
.dashboard-split-grid > * {
    min-width: 0;
}
@media (min-width: 640px) {
    .dashboard-stats-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1024px) {
    .dashboard-stats-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1680px) {
    .dashboard-stats-grid { grid-template-columns: repeat(8, 1fr); gap: 10px; }
    .dashboard-stats-grid .stat-card { padding: 12px 8px; }
    .dashboard-stats-grid .stat-label { font-size: 0.72rem; line-height: 1.25; }
    .dashboard-stats-grid .stat-card > div:first-child { font-size: 1.7rem !important; }
}

/* Tarjeta de estadística clickable */
.stat-card-link {
    text-decoration: none;
    color: inherit;
    display: block;
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s;
}

/* Botón discreto/fantasma: navegación secundaria, acciones auxiliares ("← Volver", "Ver X →", "Actualizar", etc) */
.btn-ghost {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    color: #475569;
    font-size: 0.85rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s, border-color 0.15s;
}
.btn-ghost:hover {
    background: #f8fafc;
    border-color: #cbd5e1;
}
.btn-ghost:active { background: #f1f5f9; }
.btn-ghost:disabled { opacity: 0.6; cursor: default; }
.btn-ghost:disabled:hover { background: #fff; border-color: #e2e8f0; }
.stat-card-link:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 8px 20px rgba(0,0,0,0.06);
}
.stat-card-link:active {
    transform: translateY(0);
}

/* Tarjeta de estadística como botón (filtra la vista actual) */
.stat-card-btn {
    cursor: pointer;
    border: 2px solid transparent;
    background: #fff;
    font-family: inherit;
    transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
    width: 100%;
    text-align: center;
}
.stat-card-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 8px 20px rgba(0,0,0,0.06);
}
.stat-card-btn:active { transform: translateY(0); }

/* v1.1.59: Cards opcionales (avisos como "Sin pausa", "Incidencias hoy").
   Decisión responsive:
   - En DESKTOP: siempre visibles, aunque count=0, para mantener simetría
     de la fila de cards. Con count=0 se ven con aspecto neutro (gris).
   - En MÓVIL: se ocultan si data-count="0" para ahorrar espacio vertical
     — el usuario móvil no necesita ver cards vacías.
   La alternativa (x-show) ocultaba en ambos. */
@media (max-width: 767px) {
    .stat-card-optional[data-count="0"] {
        display: none;
    }
}

.stat-card-btn--active {
    box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 8px 20px rgba(0,0,0,0.06);
}
.stat-card-btn--blue.stat-card-btn--active {
    border-color: #2563eb;
    background: #eff6ff;
}
.stat-card-btn--green.stat-card-btn--active {
    border-color: #10b981;
    background: #f0fdf4;
}
.stat-card-btn--amber.stat-card-btn--active {
    border-color: #f59e0b;
    background: #fffbeb;
}
.stat-card-btn--slate.stat-card-btn--active {
    border-color: #64748b;
    background: #f1f5f9;
}
.stat-card-btn--red.stat-card-btn--active {
    border-color: #ef4444;
    background: #fef2f2;
}

/* Pills de filtro de estado */
.status-pill {
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px solid #e2e8f0;
    background: #fff;
    color: #64748b;
    font-size: 0.8rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.15s;
}
.status-pill:hover {
    background: #f1f5f9;
    border-color: #cbd5e1;
}
.status-pill-active {
    background: #2563eb;
    border-color: #2563eb;
    color: #fff;
}
.status-pill-active:hover {
    background: #1d4ed8;
    border-color: #1d4ed8;
}

/* Etiquetas de formulario pequeñas (encima del input) */
.form-label-sm { font-size: 0.75rem; color: #64748b; display: block; margin-bottom: 4px; }
.form-label-sm-req { font-size: 0.75rem; color: #64748b; display: block; margin-bottom: 4px; }
.form-label-sm-req::after { content: ' *'; color: #dc2626; }

/* Estados vacíos dentro de secciones (no standalone) */
.empty-inline { text-align: center; padding: 20px; color: #94a3b8; font-size: 0.9rem; }

/* Botones pequeños */
.btn-sm { padding: 5px 10px; font-size: 0.75rem; min-height: 30px; }
.btn-xs { padding: 4px 10px; font-size: 0.7rem; min-height: 26px; }

/* Textos auxiliares */
.text-muted { color: #94a3b8; }
.text-muted-xs { color: #94a3b8; font-size: 0.75rem; }
.text-danger-xs { color: #dc2626; font-size: 0.75rem; }

/* Layout helpers */
.col-fill { flex: 1; }
.flex-row-between { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.flex-row { display: flex; align-items: center; gap: 12px; }

/* ─────────────────────────────────────────────────────────
   .form-actions — fila de botones al final de un formulario
   Escritorio: fila horizontal, cada botón ocupa lo suyo.
   Móvil ≤480px: apilados verticalmente, primary arriba,
   cada botón ancho completo. Patrón iOS/Material bottom-sheet.
   Los botones dentro llevan sus clases normales (.btn .btn-primary,
   .btn .btn-secondary, etc.).
   ───────────────────────────────────────────────────────── */
.form-actions {
    display: flex;
    gap: 10px;
    margin-top: 8px;
    flex-wrap: wrap;
}
.form-actions .btn { flex: 1; min-width: 140px; }
@media (max-width: 480px) {
    .form-actions { flex-direction: column-reverse; }
    .form-actions .btn { flex: 1 1 auto; width: 100%; min-width: 0; }
}

/* Contenedor con scroll vertical limitado */
.scroll-y-400 { max-height: 400px; overflow-y: auto; }

/* ──────────────────────────────────────────
   Listado jornadas admin (CSS Grid puro, sin tabla)
   Mantiene alineación de columnas sin trucos HTML
   ────────────────────────────────────────── */
.jornada-head,
.jornada-row {
    display: grid;
    grid-template-columns: 1fr 80px 80px 80px 90px 100px;
    gap: 12px;
    align-items: center;
    padding: 10px 16px;
}
.jornada-head {
    background: #f8fafc;
    border-bottom: 1px solid #e2e8f0;
    font-size: 0.75rem;
    font-weight: 600;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.jornada-head > div { text-align: center; }
.jornada-head > div:first-child { text-align: left; }
.jornada-row {
    border-bottom: 1px solid #f1f5f9;
    cursor: pointer;
    transition: background 0.15s;
    font-size: 0.9rem;
}
.jornada-row:hover { background: #f1f5f9; }
.jornada-item:nth-child(even) > .jornada-row { background: #fafbfc; }
.jornada-item:nth-child(even) > .jornada-row:hover { background: #f1f5f9; }
.jornada-row > div { text-align: center; }
.jornada-row > div:first-child { text-align: left; }

/* v1.3.22.10: estados visuales para filas de incidencias.
   - .jornada-row-warn: pendiente de gestión, requiere acción del admin
     (borde lateral ámbar, fondo crema sutil)
   - .jornada-row-done: ya clasificado/justificado, acción cumplida
     (más opaco, fondo gris muy claro, sin destacar)
   - .jornada-row-rejected (v1.3.22.11): desviación marcada sin
     justificar, va al histórico con borde rojo muy sutil */
.jornada-row.jornada-row-warn {
    border-left: 4px solid #f59e0b;
    background: #fffbeb;
}
.jornada-row.jornada-row-warn:hover {
    background: #fef3c7;
}
.jornada-row.jornada-row-done {
    background: #f8fafc;
    color: #64748b;
}
.jornada-row.jornada-row-done:hover {
    background: #f1f5f9;
}
.jornada-row.jornada-row-rejected {
    border-left: 4px solid #dc2626;
    background: #fef2f2;
    color: #64748b;
}
.jornada-row.jornada-row-rejected:hover {
    background: #fee2e2;
}
.jornada-detail {
    background: #f8fafc;
    border-top: 1px solid #e2e8f0;
    border-bottom: 1px solid #e2e8f0;
    padding: 12px 20px;
}
/* ──────────────────────────────────────────
   Responsive móvil (≤640px): patrón card-style.
   Nombre/día arriba ocupando toda la fila. Debajo
   una fila compacta con entrada + salida + estado.
   Las columnas Pausa y Neto/Trabajado se ocultan
   (se ven al expandir detalle en admin-entries, o
   se acceden en escritorio). Este patrón evita que
   nombres largos como "Trinidad Rosario Mañas" se
   partan en 4 líneas o que el pill Estado se pegue
   al borde.
   ────────────────────────────────────────── */

/* Regla base de .jornada-label-mobile — oculta por defecto.
   Se activa solo dentro del @media (max-width: 640px) más abajo
   (ahí se le aplica display: block + tipografía label). En
   desktop queda oculta porque la cabecera de la tabla ya aclara
   el contenido de la columna. Esta regla va FUERA del @media y
   ANTES, para que el override dentro del media gane por cascada
   en móvil. Si se invierte el orden, en móvil el navegador
   aplicaría ambas con igual especificidad y ganaría la última
   (display: none), dejando la etiqueta invisible en todas partes. */
.jornada-label-mobile { display: none; }

@media (max-width: 640px) {
    /* Cabecera oculta en móvil: la estructura card-style
       no tiene columnas alineadas con una cabecera. Se
       entiende por contexto (hora monospace, pill de color,
       y etiquetas mini encima de cada valor). */
    .jornada-head { display: none; }

    /* ── Layout canónico de .jornada-row en móvil ──
       Desde v1.1.20, admin-entries, me-entries y me-summary
       comparten el mismo patrón card-style. Layout: grid 2×3
       (+ columna auxiliar para Estado/pill):
         Fila 1: Nombre/Día/Jornada N (full width)
         Fila 2: Entrada │ Salida │ Estado/Pill
         Fila 3: Pausa   │ Trabajado │ (vacío)
       Cada valor lleva encima una etiqueta mini ("Entrada",
       "Salida", "Pausa", "Trabajado") como label explícito.
       El admin ve los 4 datos sin tener que expandir cada fila
       — consistente con el empleado, que también los ve.
       La clase `.jornada-row--summary` se mantiene como alias
       histórico (me-entries/me-summary la llevan en el HTML)
       pero no añade estilos propios en este layout unificado. */
    .jornada-row {
        grid-template-columns: 1fr 1fr auto;
        grid-template-rows: auto auto auto;
        column-gap: 12px;
        row-gap: 8px;
        padding: 12px 14px;
        font-size: 0.85rem;
        align-items: start;
    }
    /* Fila 1: nombre/día/jornada-N ocupa las 3 columnas a lo ancho */
    .jornada-row > div:nth-child(1) {
        grid-column: 1 / -1;
        grid-row: 1;
        text-align: left;
    }
    /* Fila 2 col 1-2: Entrada + Salida con su font monospace */
    .jornada-row > div:nth-child(2) {
        grid-column: 1; grid-row: 2;
        text-align: left;
    }
    .jornada-row > div:nth-child(3) {
        grid-column: 2; grid-row: 2;
        text-align: left;
    }
    /* Fila 2 col 3: Estado/Pill pegado a la derecha */
    .jornada-row > div:nth-child(6) {
        grid-column: 3; grid-row: 2;
        text-align: right;
        align-self: center;
    }
    /* Fila 3: Pausa (col 1) + Trabajado (col 2). Col 3 vacía. */
    .jornada-row > div:nth-child(4) {
        display: block;
        grid-column: 1; grid-row: 3;
        text-align: left;
        font-size: 0.85rem;
        color: #64748b;
    }
    .jornada-row > div:nth-child(5) {
        display: block;
        grid-column: 2; grid-row: 3;
        text-align: left;
        font-size: 0.85rem;
        font-weight: 600;
    }

    /* ── Etiquetas mini encima de cada valor ──
       Patrón "label sobre value" al estilo Factorial/Sesame.
       Aclara qué representa cada número sin depender de la
       cabecera (oculta en móvil) ni de iconos emoji ambiguos. */
    .jornada-row > div:nth-child(2)::before {
        content: 'Entrada';
        display: block;
        font-size: 0.7rem;
        font-weight: 400;
        color: #94a3b8;
        letter-spacing: 0.02em;
        margin-bottom: 2px;
    }
    .jornada-row > div:nth-child(3)::before {
        content: 'Salida';
        display: block;
        font-size: 0.7rem;
        font-weight: 400;
        color: #94a3b8;
        letter-spacing: 0.02em;
        margin-bottom: 2px;
    }
    .jornada-row > div:nth-child(4)::before {
        content: 'Pausa';
        display: block;
        font-size: 0.7rem;
        font-weight: 400;
        color: #94a3b8;
        letter-spacing: 0.02em;
        margin-bottom: 2px;
    }
    .jornada-row > div:nth-child(5)::before {
        content: 'Trabajado';
        display: block;
        font-size: 0.7rem;
        font-weight: 400;
        color: #94a3b8;
        letter-spacing: 0.02em;
        margin-bottom: 2px;
    }

    /* ── Etiquetas mini condicionales ──
       Para columnas cuyo contenido es dinámico (p.ej. col 6 "Estado"
       muestra a veces un pill de extras, a veces "En curso", a veces
       "Cerrada"...), no podemos usar ::before con contenido fijo. En
       su lugar el HTML incluye un <div class="jornada-label-mobile">
       que Alpine muestra/oculta con x-show según la lógica correcta
       (p.ej. "Extras" solo si overtime_min > 0). Esta clase reutiliza
       el mismo look que los ::before de los otros labels (Entrada,
       Salida, Pausa, Trabajado) para mantener coherencia visual.
       En desktop la clase queda oculta por defecto (ver regla base
       fuera del @media, antes de este bloque) — la cabecera de la
       tabla ya aclara la columna. */
    .jornada-label-mobile {
        display: block;
        font-size: 0.7rem;
        font-weight: 400;
        color: #94a3b8;
        letter-spacing: 0.02em;
        margin-bottom: 2px;
    }
}


/* ─────────────────────────────────────────────────────────
   Pestañas estándar (.settings-tabs / .settings-tab)
   Usadas en: admin-settings. Reutilizables en cualquier pantalla
   con pestañas (informes, auditoría, etc.).

   Patrón: CSS Grid con auto-fit + minmax. Todas las pestañas siempre
   visibles — si no caben todas en una fila, saltan a una segunda
   (o tercera) fila automáticamente. Sin scroll horizontal.

     - Escritorio ancho (>=560px con 4 tabs): una fila de 4.
     - Tablet/móvil ancho intermedio: 2x2 o 3+1 según el espacio.
     - Móvil estrecho: filas de 2 o 1.

   El Grid se adapta solo a cualquier número de pestañas añadidas
   en el futuro — no hay que tocar el CSS.
   ───────────────────────────────────────────────────────── */
.settings-tabs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0;
    margin-bottom: 20px;
    background: #fff;
    border-radius: 10px;
    overflow: hidden; /* recortar el border-radius a las tabs de los bordes */
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.settings-tab {
    padding: 12px 16px;
    border: none;
    background: #fff;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 500;
    color: #64748b;
    text-align: center;
    white-space: nowrap;       /* no partir label a 2 líneas dentro de la celda */
    overflow: hidden;
    text-overflow: ellipsis;   /* si aun así no cabe, "..." (seguro raro que pase) */
    transition: color 0.15s, background 0.15s, border-bottom-color 0.15s;
    border-bottom: 3px solid transparent;
}
.settings-tab:hover {
    background: #f8fafc;
    color: #334155;
}
.settings-tab.active {
    color: #2563eb;
    border-bottom-color: #2563eb;
    background: #f8fafc;
    font-weight: 600;
}

/* Móvil: padding y font un pelín menores para optimizar el espacio por celda */
@media (max-width: 640px) {
    .settings-tab {
        padding: 12px 14px;
        font-size: 0.85rem;
    }
}


/* ─────────────────────────────────────────────────────────
   Barra de progreso countdown (terminal — pantalla confirm)
   ───────────────────────────────────────────────────────── */
@keyframes countdown-drain {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}
.countdown-bar-track {
    width: 100%;
    max-width: 280px;
    height: 4px;
    margin: 28px auto 0 auto;
    background: rgba(255, 255, 255, 0.12);
    border-radius: 2px;
    overflow: hidden;
}
.countdown-bar-fill {
    height: 100%;
    background: rgba(255, 255, 255, 0.85);
    border-radius: 2px;
    transform-origin: left center;
    /* La duración se sincroniza con el setTimeout(5000) del JS del terminal */
    animation: countdown-drain 5s linear forwards;
}


/* ─────────────────────────────────────────────────────────
   Indicador de fichaje en curso (clock remoto)
   Se inserta dentro de .clock-actions (flex horizontal), por lo que
   necesita flex:1 1 100% para ocupar todo el ancho como los botones.
   ───────────────────────────────────────────────────────── */
.clocking-indicator {
    flex: 1 1 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 32px 20px;
    min-height: 140px;
    width: 100%;
    box-sizing: border-box;
    text-align: center;
}
.clocking-indicator .spinner {
    width: 44px;
    height: 44px;
    border-width: 4px;
    border-color: rgba(37, 99, 235, 0.18);
    border-top-color: #2563eb;
    margin: 0 auto;
}
.clocking-label {
    font-size: 1.1rem;
    color: #1e293b;
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1.3;
    max-width: 90%;
    margin: 0 auto;
}
.clocking-label-sub {
    font-size: 0.8rem;
    color: #64748b;
    line-height: 1.4;
    max-width: 320px;
    margin: -6px auto 0 auto;
    font-weight: 400;
}


/* ─────────────────────────────────────────────────────────
   Modo terminal: ocupar exactamente la viewport, sin scroll.
   La clase body--terminal-mode la pone/quita el JS de index.html
   cuando Terminal.isActive() o la ruta es #/terminal.
   ───────────────────────────────────────────────────────── */
body.body--terminal-mode {
    overflow: hidden;
    background: var(--color-gray-900);
}
body.body--terminal-mode .app-content {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    min-height: 100vh;
    min-height: 100dvh;
    height: 100vh;
    height: 100dvh;
}
body.body--terminal-mode .terminal-page {
    min-height: 100vh;
    min-height: 100dvh;
    height: 100vh;
    height: 100dvh;
}

/* ─────────────────────────────────────────────────────────
   Modal bloqueante "Debes cambiar tu contraseña"
   - Cubre TODA la pantalla con fondo oscuro opaco.
   - z-index alto para quedar sobre cualquier UI.
   - No usamos :style con string en HTML porque sobrescribe
     los inline-styles (norma 12).
   ───────────────────────────────────────────────────────── */
.must-change-modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(15, 23, 42, 0.92);
    z-index: 10001;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    overflow-y: auto;
}
.must-change-modal-card {
    max-width: 440px;
    width: 100%;
    margin: 0 !important;
}

/* Grid del dashboard para bloques "Fichaje hoy" y "Eventos recientes".
   1 columna en móvil/tablet, 2 en escritorio. Antes esto estaba en inline
   :style con window.innerWidth > 900 — que rompía parser HTML y no era
   reactivo al redimensionar. */
.dashboard-split-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}
@media (min-width: 900px) {
    .dashboard-split-grid { grid-template-columns: 1fr 1fr; }
}

/* ═══════════════════════════════════════════════════════════════════
   Sistema de modales
   Patrón estándar: overlay + card con header/body/footer fijos.
   La cabecera y el footer NO scrollean; solo el body.
   Variantes de ancho: -sm / -md (default) / -lg / -xl.
   Apilamiento: -nested / -top para modales encima de otros modales.
   Uso:
     <div class="modal-overlay"><div class="modal-card modal-card-lg">
       <div class="modal-header"><h3 class="modal-title">…</h3>
         <button class="modal-close">×</button></div>
       <div class="modal-body">…contenido…</div>
       <div class="modal-footer"><button class="btn btn-primary">…</button></div>
     </div></div>
   ═══════════════════════════════════════════════════════════════════ */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.7);
    z-index: 1000;
    padding: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow-y: auto;
}
.modal-overlay-nested { z-index: 1100; }
.modal-overlay-top    { z-index: 1200; }

.modal-card {
    background: #fff;
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    max-width: 520px;
    width: 100%;
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    margin: auto;
}
.modal-card-sm { max-width: 400px; }
.modal-card-md { max-width: 640px; }
.modal-card-lg { max-width: 760px; }
.modal-card-xl { max-width: 980px; }

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid #e2e8f0;
    flex-shrink: 0;
}
.modal-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: #334155;
    margin: 0;
    line-height: 1.3;
}
.modal-subtitle {
    font-size: 0.8rem;
    color: #94a3b8;
    margin-top: 2px;
}
.modal-close {
    background: none;
    border: none;
    font-size: 1.4rem;
    color: #94a3b8;
    cursor: pointer;
    padding: 4px 8px;
    line-height: 1;
    flex-shrink: 0;
}
.modal-close:hover { color: #475569; }
.modal-close:disabled { cursor: not-allowed; opacity: 0.5; }

.modal-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 16px 20px;
}
.modal-body-center {
    text-align: center;
}

.modal-footer {
    padding: 12px 20px;
    border-top: 1px solid #e2e8f0;
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    flex-wrap: wrap;
    flex-shrink: 0;
}
.modal-footer-split { justify-content: space-between; }
.modal-footer-full  { justify-content: stretch; }
.modal-footer-full .btn { flex: 1; }

/* ─────────────────────────────────────────────────────────
   Fila de empleado dentro del desplegable de dept (v1.1.82+).
   En admin-settings > Departamentos, al expandir un dept se
   listan sus empleados. Cada fila tiene info (nombre+badges)
   y el puesto a la derecha.

   Desktop (>600px): horizontal. Info ocupa todo el espacio
   disponible con wrap de badges; puesto a la derecha con
   max-width y truncado por ellipsis si se pasa.

   Móvil (≤600px): vertical. Puesto cae debajo como segunda
   línea, pegado a la izquierda. Elimina tensión horizontal
   cuando el nombre es largo o hay muchos badges.
   ───────────────────────────────────────────────────────── */
.dept-emp-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 8px;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
}
.dept-emp-info {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 1;
    flex-wrap: wrap;
}
.dept-emp-position {
    color: #94a3b8;
    font-size: 0.75rem;
    flex-shrink: 0;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
@media (max-width: 600px) {
    .dept-emp-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }
    .dept-emp-position {
        max-width: 100%;
        padding-left: 0;
        font-size: 0.72rem;
    }
}


/* ═══════════════════════════════════════════════════════════════
   Focus visible — navegación por teclado (v1.1.90)
   ═══════════════════════════════════════════════════════════════
   Estado anterior: solo .header-user tenía :focus-visible. Al tabular
   por la interfaz (botones × de modales, enlaces del menú, botones
   primary/ghost, etc.) no había indicación visible de qué elemento
   tenía el foco — bloqueador real para usuarios de teclado y lectores
   de pantalla.

   Este bloque aplica un outline azul coherente a TODOS los elementos
   interactivos cuando reciben foco por teclado (no por click, gracias
   a :focus-visible). El offset y el color son los mismos que tiene
   .header-user para consistencia visual.

   Navegadores sin soporte para :focus-visible (muy viejos) ignoran
   la regla — no degrada la experiencia de nadie, solo mejora para
   quien puede beneficiarse.
*/
.btn:focus-visible,
.btn-ghost:focus-visible,
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-danger:focus-visible,
.modal-close:focus-visible,
.dropdown-item:focus-visible,
.form-input:focus-visible,
.form-select:focus-visible,
.stat-card-link:focus-visible,
.status-pill:focus-visible,
.status-pill-active:focus-visible,
a:focus-visible {
    outline: 2px solid #3b82f6;
    outline-offset: 2px;
}

/* El outline por defecto de inputs con foco ya viene del navegador —
   no lo quitamos. Si alguna pantalla tiene algún `outline:none` ad-hoc,
   añadirle :focus-visible por encima en esa pantalla. */

/* ─────────────────────────────────────────────────────────
   Tabla de audit log (admin-settings → pestaña Auditoría → Sección 3)
   v1.1.98.4 (Detalle de cambios + responsive)
   ───────────────────────────────────────────────────────── */

/* Detalle de cambios: en desktop el bloque de líneas ocupa el ancho
   natural de la celda. Cada línea es "campo: ANTES → DESPUÉS". */
.audit-log-table .audit-detail-cell {
    line-height: 1.55;
    max-width: 380px;
    overflow-wrap: break-word;
}
.audit-log-table .audit-change-line {
    word-break: break-word;
}

/* Tablet (601-780px): comprimir un poco la fuente y permitir scroll
   horizontal del wrapper, sin transformar la tabla. */
@media (max-width: 780px) and (min-width: 601px) {
    .audit-log-table {
        font-size: 0.76rem;
    }
    .audit-log-table .audit-detail-cell {
        max-width: 240px;
    }
}

/* Móvil (≤600px): cada <tr> se vuelve una tarjeta apilada.
   Ocultamos el <thead> y mostramos la cabecera de cada celda con
   ::before usando data-label.
   Patrón estándar usado por Sesame/Factorial en sus tablas largas. */
@media (max-width: 600px) {
    .audit-log-table {
        display: block;
    }
    .audit-log-table thead {
        display: none;
    }
    .audit-log-table tbody, .audit-log-table tr {
        display: block;
    }
    .audit-log-table tr {
        border: 1px solid #e2e8f0;
        border-radius: 8px;
        margin-bottom: 10px;
        padding: 8px 10px;
        background: #fff;
    }
    .audit-log-table td {
        display: block;
        padding: 6px 0 !important;
        border: none !important;
        white-space: normal !important;
    }
    /* Cabecera de columna como label antes del contenido */
    .audit-log-table td::before {
        content: attr(data-label);
        display: block;
        font-size: 0.65rem;
        font-weight: 600;
        color: #94a3b8;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        margin-bottom: 2px;
    }
    .audit-log-table .audit-detail-cell {
        max-width: 100%;
    }
    /* En móvil, romper línea entre antes/flecha/después si no cabe */
    .audit-log-table .audit-change-line {
        line-height: 1.6;
    }
}

/* ─────────────────────────────────────────────────────────
   Resumen para inspector (admin-settings → tab Auditoría → Sección 4)
   v1.1.99 (Sesión C — Pieza 1)
   ───────────────────────────────────────────────────────── */

.inspector-report {
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    padding: 22px 24px;
    margin-top: 8px;
}

.inspector-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 18px;
}

.inspector-item {
    display: flex;
    flex-direction: column;
    padding: 7px 0;
    border-bottom: 1px dotted #e2e8f0;
}

.inspector-label {
    font-size: 0.72rem;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 500;
}

.inspector-value {
    font-size: 0.95rem;
    color: #0f172a;
    font-weight: 500;
    margin-top: 2px;
}

@media (max-width: 600px) {
    .inspector-report {
        padding: 14px 16px;
    }
    .inspector-grid {
        grid-template-columns: 1fr;
    }
}

/* ─────────────────────────────────────────────────────────
   Navegación rápida entre secciones del tab Auditoría
   v1.1.99.3
   ───────────────────────────────────────────────────────── */

.audit-nav-sticky {
    position: sticky;
    top: 0;
    z-index: 10;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    padding: 10px 12px;
    margin: -8px -8px 12px;
    border-radius: 8px;
    border: 1px solid #e2e8f0;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 0.82rem;
}

.audit-nav-label {
    color: #94a3b8;
    font-size: 0.75rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.audit-nav-chip {
    display: inline-flex;
    align-items: center;
    padding: 5px 11px;
    border-radius: 20px;
    background: #f1f5f9;
    color: #475569;
    text-decoration: none;
    font-size: 0.8rem;
    font-weight: 500;
    border: 1px solid transparent;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    white-space: nowrap;
}

.audit-nav-chip:hover {
    background: #e2e8f0;
    color: #1e293b;
    border-color: #cbd5e1;
}

@media (max-width: 600px) {
    .audit-nav-sticky {
        padding: 8px 10px;
        gap: 6px;
    }
    .audit-nav-label {
        flex-basis: 100%;
        margin-bottom: 4px;
    }
    .audit-nav-chip {
        font-size: 0.75rem;
        padding: 4px 9px;
    }
}

/* Al imprimir el SPA (no la ventana popup), ocultar la barra de navegación */
@media print {
    .audit-nav-sticky {
        display: none;
    }
}

/* ─────────────────────────────────────────────────────────
   Botón global scroll-to-top (v1.1.99.5)
   Visible cuando window.pageYOffset > 300px.
   Oculto en modo terminal (kiosko full-screen) y al imprimir.
   ───────────────────────────────────────────────────────── */

.scroll-to-top {
    position: fixed;
    bottom: 24px;
    right: 24px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #1e293b;
    color: #fff;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.25);
    /* Oculto por defecto: invisible y no clickable hasta que JS añada .visible */
    opacity: 0;
    pointer-events: none;
    transform: translateY(8px);
    transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s;
    z-index: 100;
}

.scroll-to-top.visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.scroll-to-top:hover {
    background: #0f172a;
}

.scroll-to-top:focus-visible {
    outline: 2px solid #60a5fa;
    outline-offset: 2px;
}

.scroll-to-top svg {
    display: block;
}

/* Modo móvil: más cerca del borde y un poco más pequeño */
@media (max-width: 600px) {
    .scroll-to-top {
        bottom: 16px;
        right: 16px;
        width: 40px;
        height: 40px;
    }
}

/* Oculto en modo terminal (clock.html / terminal.html en kiosko) */
.body--terminal-mode .scroll-to-top {
    display: none;
}

/* Oculto al imprimir — no debe aparecer en PDFs */
@media print {
    .scroll-to-top {
        display: none !important;
    }
}
