:root {
    /* ── Palette del marchio omneres ──────────────────────────────────────────
       Navy #0F172A · Deep Green #2F6B63 · Sage #B7CBBE · Amber #F2B705
       Light Gray #E7E9ED · Ivory #F7F6F2 */
    --omneres-navy: #0f172a;
    --omneres-green: #2f6b63;
    --omneres-sage: #b7cbbe;
    --omneres-amber: #f2b705;
    --omneres-light-gray: #e7e9ed;
    --omneres-ivory: #f7f6f2;

    --primary: #2f6b63;
    --primary-dark: #275650;
    --primary-light: #649a8f;
    --secondary: #0f172a;
    --accent: #f2b705;
    --success: #10b981;
    --warning: #f2b705;
    --danger: #e11d48;
    --info: #74927f;
    --dark: #0f172a;
    /* Neutri del marchio: dall'ivory al navy, un'unica rampa */
    --gray-50: #f7f6f2;
    --gray-100: #f0f0eb;
    --gray-200: #e7e9ed;
    --gray-300: #d3d8de;
    --gray-400: #a7b0bb;
    --gray-500: #78828f;
    --gray-600: #58626f;
    --gray-700: #3d4655;
    --gray-800: #232d3e;
    --gray-900: #0f172a;

    /* Shadows */
    --shadow-sm: 0 1px 2px 0 rgb(15 23 42 / 0.05);
    --shadow: 0 1px 3px 0 rgb(15 23 42 / 0.1), 0 1px 2px -1px rgb(15 23 42 / 0.1);
    --shadow-md: 0 4px 6px -1px rgb(15 23 42 / 0.1), 0 2px 4px -2px rgb(15 23 42 / 0.1);
    --shadow-lg: 0 10px 15px -3px rgb(15 23 42 / 0.1), 0 4px 6px -4px rgb(15 23 42 / 0.1);
    --shadow-xl: 0 20px 25px -5px rgb(15 23 42 / 0.1), 0 8px 10px -6px rgb(15 23 42 / 0.1);

    /* Transitions */
    --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
    --transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
    --transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1);

    /* Border radius */
    --radius-sm: 0.375rem;
    --radius: 0.5rem;
    --radius-lg: 0.75rem;
    --radius-xl: 1rem;
}

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

body {
    font-family: 'Satoshi', 'Inter', 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: linear-gradient(180deg, var(--omneres-ivory) 0%, var(--gray-100) 100%);
    color: var(--gray-800);
    min-height: 100vh;
    line-height: 1.6;
}

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

/* Modern Navbar */
.navbar {
    background: rgba(255, 255, 255, 0.95) !important;
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--gray-200);
    padding: 0.75rem 0;
    box-shadow: var(--shadow-sm);
}

.navbar-brand {
    font-weight: 700;
    font-size: 1.5rem;
    color: var(--primary) !important;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    transition: transform var(--transition-base);
}

.navbar-brand:hover {
    transform: translateX(2px);
}

.navbar-brand i {
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.nav-link {
    color: var(--gray-600) !important;
    font-weight: 500;
    padding: 0.5rem 1rem !important;
    border-radius: var(--radius);
    transition: all var(--transition-base);
    position: relative;
    overflow: hidden;
}

.nav-link::before {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 0;
    height: 2px;
    background: var(--primary);
    transform: translateX(-50%);
    transition: width var(--transition-base);
}

.nav-link:hover {
    color: var(--primary) !important;
    background: var(--gray-50);
}

.nav-link.active {
    color: var(--primary) !important;
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    color: white !important;
}

.nav-link.active i {
    color: white !important;
}

.navbar-text {
    color: var(--gray-600);
    font-weight: 500;
}

/* Modern Cards */
.card {
    background: white;
    border: none;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    transition: all var(--transition-base);
    overflow: hidden;
}

.card:hover {
    box-shadow: var(--shadow-lg);
}

.card-header {
    background: linear-gradient(135deg, var(--gray-50) 0%, white 100%);
    border-bottom: 1px solid var(--gray-200);
    padding: 1.25rem;
    font-weight: 600;
}

.card-body {
    padding: 1.5rem;
}

/* Dashboard Cards */
.dashboard-card {
    background: white;
    border-radius: var(--radius-lg);
    padding: 1.5rem;
    position: relative;
    overflow: hidden;
    transition: all var(--transition-base);
    box-shadow: var(--shadow);
}

.dashboard-card::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%);
}

.dashboard-card:hover {
    box-shadow: var(--shadow-xl);
}

.dashboard-card h5 {
    color: var(--gray-600);
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.5rem;
}

.dashboard-card h2 {
    font-size: 2.5rem;
    font-weight: 700;
    background: linear-gradient(135deg, var(--gray-800) 0%, var(--gray-600) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    margin-bottom: 0.5rem;
}

.dashboard-card small {
    color: var(--gray-500);
    font-size: 0.875rem;
}

/* Color variations for dashboard cards */
.dashboard-card.primary::before { background: linear-gradient(90deg, var(--primary) 0%, var(--primary-light) 100%); }
.dashboard-card.success::before { background: linear-gradient(90deg, var(--success) 0%, #34d399 100%); }
.dashboard-card.info::before { background: linear-gradient(90deg, var(--info) 0%, #b7cbbe 100%); }
.dashboard-card.warning::before { background: linear-gradient(90deg, var(--warning) 0%, #f8ce45 100%); }
.dashboard-card.danger::before { background: linear-gradient(90deg, var(--danger) 0%, #fb7185 100%); }
.dashboard-card.secondary::before { background: linear-gradient(90deg, var(--secondary) 0%, #649a8f 100%); }

/* Modern Tables */
.table {
    border-collapse: separate;
    border-spacing: 0;
}

.table thead th {
    background: var(--gray-50);
    color: var(--gray-700);
    font-weight: 600;
    font-size: 0.875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 1rem;
    border-bottom: 2px solid var(--gray-200);
    white-space: nowrap;
    position: sticky;
    top: 0;
    z-index: 10;
}

.table thead th[onclick], 
.table thead th[style*="cursor: pointer"] {
    cursor: pointer;
    user-select: none;
    transition: all var(--transition-base);
}

.table thead th[onclick]:hover,
.table thead th[style*="cursor: pointer"]:hover {
    background: var(--gray-100);
    color: var(--primary);
}

.table tbody tr {
    transition: all var(--transition-base);
    border-bottom: 1px solid var(--gray-100);
}

.table tbody tr:hover {
    background: var(--gray-50);
    box-shadow: var(--shadow-sm);
}

.table tbody td {
    padding: 1rem;
    color: var(--gray-700);
    vertical-align: middle;
}

.table-responsive {
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow);
}

/* Modern Badges */
.badge {
    font-weight: 600;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    letter-spacing: 0.025em;
    text-transform: uppercase;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}

.bg-primary { background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%) !important; }
.bg-success { background: linear-gradient(135deg, var(--success) 0%, #34d399 100%) !important; }
.bg-info { background: linear-gradient(135deg, var(--info) 0%, #b7cbbe 100%) !important; }
.bg-warning { background: linear-gradient(135deg, var(--warning) 0%, #f8ce45 100%) !important; color: white !important; }
.bg-danger { background: linear-gradient(135deg, var(--danger) 0%, #fb7185 100%) !important; }
.bg-secondary { background: linear-gradient(135deg, var(--gray-500) 0%, var(--gray-400) 100%) !important; }

/* Modern Buttons */
.btn {
    font-weight: 600;
    padding: 0.625rem 1.25rem;
    border-radius: var(--radius);
    border: none;
    transition: all var(--transition-base);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    letter-spacing: 0.025em;
    box-shadow: var(--shadow-sm);
}

.btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

.btn:active {
    transform: translateY(0);
}

.btn-primary {
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
    color: white;
}

.btn-primary:hover {
    background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
    color: white;
}

.btn-secondary {
    background: var(--gray-200);
    color: var(--gray-700);
}

.btn-secondary:hover {
    background: var(--gray-300);
    color: var(--gray-800);
}

.btn-success {
    background: linear-gradient(135deg, var(--success) 0%, #34d399 100%);
    color: white;
}

.btn-danger {
    background: linear-gradient(135deg, var(--danger) 0%, #fb7185 100%);
    color: white;
}

.btn-info {
    background: linear-gradient(135deg, var(--info) 0%, #b7cbbe 100%);
    color: white;
}

.btn-warning {
    background: linear-gradient(135deg, var(--warning) 0%, #f8ce45 100%);
    color: white;
}

.btn-sm {
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
}

.btn-outline-secondary {
    background: transparent;
    border: 2px solid var(--gray-300);
    color: var(--gray-600);
}

.btn-outline-secondary:hover {
    background: var(--gray-100);
    border-color: var(--gray-400);
    color: var(--gray-700);
}

.btn-outline-light {
    background: rgba(255, 255, 255, 0.1);
    border: 2px solid rgba(255, 255, 255, 0.3);
    color: white;
}

.btn-outline-light:hover {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.5);
    color: white;
}

/* Modern Forms */
.form-label {
    color: var(--gray-700);
    font-weight: 600;
    font-size: 0.875rem;
    margin-bottom: 0.5rem;
    display: block;
    letter-spacing: 0.025em;
}

.form-control,
.form-select {
    border: 2px solid var(--gray-200);
    border-radius: var(--radius);
    padding: 0.625rem 0.875rem;
    font-size: 0.875rem;
    transition: all var(--transition-base);
    background: white;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
    outline: none;
}

.form-control::placeholder {
    color: var(--gray-400);
}

.input-group {
    position: relative;
    display: flex;
    align-items: stretch;
    width: 100%;
}

.input-group .form-control {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.input-group .btn {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

.input-group-text {
    background: var(--gray-100);
    border: 2px solid var(--gray-200);
    border-left: none;
    color: var(--gray-600);
    padding: 0.625rem 0.875rem;
    font-size: 0.875rem;
}

.form-check-input {
    width: 1.25rem;
    height: 1.25rem;
    border: 2px solid var(--gray-300);
    border-radius: var(--radius-sm);
    transition: all var(--transition-base);
}

.form-check-input:checked {
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
    border-color: var(--primary);
}

/* Modern Modals */
.modal-content {
    border: none;
    border-radius: var(--radius-xl);
    overflow: hidden;
    box-shadow: var(--shadow-xl);
}

.modal-header {
    background: linear-gradient(135deg, var(--gray-50) 0%, white 100%);
    border-bottom: 1px solid var(--gray-200);
    padding: 1.5rem;
}

.modal-title {
    font-weight: 700;
    color: var(--gray-800);
    font-size: 1.25rem;
}

.modal-body {
    padding: 1.5rem;
}

.modal-footer {
    background: var(--gray-50);
    border-top: 1px solid var(--gray-200);
    padding: 1rem 1.5rem;
}

/* Login Page */
.login-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--secondary) 0%, var(--primary) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.login-overlay::before {
    content: '';
    position: absolute;
    width: 200%;
    height: 200%;
    background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
    animation: backgroundMove 20s linear infinite;
}

@keyframes backgroundMove {
    0% { transform: translate(0, 0); }
    100% { transform: translate(-30px, -30px); }
}

.login-overlay .card {
    position: relative;
    z-index: 1;
    animation: slideInUp 0.5s ease-out;
}

@keyframes slideInUp {
    from {
        opacity: 0;
        transform: translateY(30px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Pagination */
.pagination {
    gap: 0.25rem;
}

.page-link {
    border: none;
    color: var(--gray-600);
    font-weight: 500;
    padding: 0.5rem 0.875rem;
    border-radius: var(--radius);
    transition: all var(--transition-base);
}

.page-link:hover {
    background: var(--gray-100);
    color: var(--primary);
}

.page-item.active .page-link {
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
    color: white;
}

.page-item.disabled .page-link {
    color: var(--gray-400);
    background: var(--gray-50);
}

/* Loading & Spinners */
.spinner-border {
    border-width: 3px;
}

.spinner-border-sm {
    width: 1rem;
    height: 1rem;
    border-width: 2px;
}

.loading-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(5px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 9999;
}

/* Sort Indicators */
.sort-indicator {
    display: inline-block;
    margin-left: 0.5rem;
    opacity: 0.5;
    transition: opacity var(--transition-base);
}

th:hover .sort-indicator {
    opacity: 1;
}

.sorted-asc::after,
.sorted-desc::after {
    content: '';
    display: inline-block;
    width: 0;
    height: 0;
    margin-left: 0.5rem;
    vertical-align: middle;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
}

.sorted-asc::after {
    border-bottom: 6px solid var(--primary);
}

.sorted-desc::after {
    border-top: 6px solid var(--primary);
}

/* Alerts */
.alert {
    border: none;
    border-radius: var(--radius);
    padding: 1rem 1.25rem;
    font-size: 0.875rem;
    box-shadow: var(--shadow-sm);
}

.alert-info {
    background: linear-gradient(135deg, rgba(6, 182, 212, 0.1) 0%, rgba(34, 211, 238, 0.1) 100%);
    color: var(--info);
    border-left: 4px solid var(--info);
}

.alert-danger {
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.1) 0%, rgba(248, 113, 113, 0.1) 100%);
    color: var(--danger);
    border-left: 4px solid var(--danger);
}

/* Custom Scrollbar */
::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: var(--gray-100);
    border-radius: var(--radius);
}

::-webkit-scrollbar-thumb {
    background: var(--gray-400);
    border-radius: var(--radius);
    transition: background var(--transition-base);
}

::-webkit-scrollbar-thumb:hover {
    background: var(--gray-500);
}

/* Animations */
@keyframes spin {
    to { transform: rotate(360deg); }
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.fade-in {
    animation: fadeIn var(--transition-base);
}

/* Responsive Design */
@media (max-width: 768px) {
    .navbar-brand {
        font-size: 1.25rem;
    }
    
    .dashboard-card h2 {
        font-size: 2rem;
    }
    
    .table {
        font-size: 0.8125rem;
    }
    
    .btn {
        padding: 0.5rem 1rem;
        font-size: 0.8125rem;
    }
}

/* Utility Classes */
.text-gradient {
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.hover-scale {
    transition: transform var(--transition-base);
}

.hover-scale:hover {
    transform: scale(1.05);
}

.overflow-visible {
    overflow: visible !important;
}

.glass-effect {
    background: rgba(255, 255, 255, 0.8);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.2);
}

/* Call Status Colors */
.status-answer { 
    background: linear-gradient(135deg, var(--success) 0%, #34d399 100%) !important; 
}
.status-busy { 
    background: linear-gradient(135deg, var(--warning) 0%, #f8ce45 100%) !important; 
}
.status-noanswer { 
    background: linear-gradient(135deg, var(--gray-500) 0%, var(--gray-400) 100%) !important; 
}
.status-cancel { 
    background: linear-gradient(135deg, var(--danger) 0%, #fb7185 100%) !important; 
}
.status-congestion { 
    background: linear-gradient(135deg, #fd7e14 0%, #fb923c 100%) !important; 
}

/* Sidebar Enhancements */
.sidebar {
    background: rgba(253, 253, 251, 0.95);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

.sidebar-brand-icon {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 0.5rem;
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.sidebar-brand-icon svg {
    width: 1rem;
    height: 1rem;
    color: white;
}

.sidebar-brand-text {
    font-size: 0.9375rem;
    font-weight: 700;
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

/* Profile avatar with gradient */
.profile-avatar {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 9999px;
    background: linear-gradient(135deg, var(--secondary) 0%, var(--primary) 100%);
    color: white;
    font-size: 0.6875rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* Page transition */
.page-enter {
    opacity: 0;
    transform: translateY(8px);
}

.page-enter-active {
    opacity: 1;
    transform: translateY(0);
    transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Card header accent */
.card-accent {
    height: 3px;
    background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
}

/* Table row hover enhancement */
.table tbody tr {
    transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
}

.table tbody tr:hover {
    background: var(--gray-50);
}

.table tbody tr:active {
    background: var(--gray-100);
}

/* Smooth snackbar animation */
.snackbar-enter {
    opacity: 0;
    transform: translateY(1rem);
}

.snackbar-enter-active {
    opacity: 1;
    transform: translateY(0);
    transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

.snackbar-leave-active {
    opacity: 0;
    transform: translateY(1rem);
    transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* App loading skeleton */
.skeleton {
    background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-50) 50%, var(--gray-100) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.5s ease-in-out infinite;
    border-radius: var(--radius);
}

@keyframes skeleton-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Dark mode support — class-based, matches Tailwind darkMode: 'class' */
.dark .sidebar {
    background: rgba(15, 23, 42, 0.95);
}

.dark .table tbody tr:hover {
    background: rgba(255, 255, 255, 0.03);
}

.dark .table tbody tr:active {
    background: rgba(255, 255, 255, 0.05);
}

.dark .skeleton {
    background: linear-gradient(90deg, var(--gray-800) 25%, var(--gray-700) 50%, var(--gray-800) 75%);
    background-size: 200% 100%;
}
/* ==========================================================================
   Knowledge base — Documenti (ingest) e Assistente (chat sui documenti)
   Motivo grafico condiviso: binari a tacche di 1px + voce monospaziata.
   Tutto namespaced .kb-* per non toccare il resto dell'app.
   ========================================================================== */

.kb-page {
    --kb-surface: #ffffff;
    --kb-hair: #e7e9ed;
    --kb-ink: #0f172a;
    --kb-ink-soft: #58626f;
    --kb-ink-mute: #a7b0bb;
    --kb-accent: #2f6b63;
    --kb-derived: #74927f;
}

.dark .kb-page {
    --kb-surface: #0f172a;
    --kb-hair: #3d4655;
    --kb-ink: #f7f6f2;
    --kb-ink-soft: #d3d8de;
    --kb-ink-mute: #94a3b8;
    --kb-accent: #93bab1;
    --kb-derived: #b7cbbe;
}

/* --- Scrollbar sottile per i pannelli di lavoro ------------------------- */
.kb-scroll { scrollbar-width: thin; scrollbar-color: var(--kb-hair) transparent; }
.kb-scroll::-webkit-scrollbar { width: 8px; height: 8px; }
.kb-scroll::-webkit-scrollbar-track { background: transparent; }
.kb-scroll::-webkit-scrollbar-thumb { background: var(--kb-hair); border-radius: 99px; border: 2px solid transparent; background-clip: content-box; }
.kb-scroll::-webkit-scrollbar-thumb:hover { background: var(--kb-ink-mute); background-clip: content-box; }

/* --- Binario della pipeline di ingest ---------------------------------- */
.kb-flow {
    background-image: linear-gradient(90deg, transparent 0%, currentColor 45%, currentColor 55%, transparent 100%);
    background-size: 260% 100%;
    background-repeat: no-repeat;
    animation: kb-flow 1.5s linear infinite;
}

@keyframes kb-flow {
    0%   { background-position: -60% 0; }
    100% { background-position: 160% 0; }
}

/* --- Nastro dei chunk: una tacca per chunk, altezza = caratteri --------- */
.kb-ribbon {
    display: flex;
    align-items: flex-end;
    gap: 2px; /* 2px di superficie: separa le tacche senza disegnare bordi */
    height: 44px;
    padding-top: 4px;
}

.kb-ribbon-tick {
    flex: 1 1 0;
    min-width: 3px;
    max-width: 24px; /* resta una tacca, non diventa una barra */
    border-radius: 4px 4px 0 0; /* estremo dato arrotondato, quadro sulla base */
    transition: opacity 120ms ease, transform 120ms ease;
    cursor: pointer;
}

.kb-ribbon-tick:hover { transform: scaleY(1.06); transform-origin: bottom; }
.kb-ribbon-tick:focus-visible { outline: 2px solid var(--kb-accent); outline-offset: 2px; }

/* --- Zona di rilascio file --------------------------------------------- */
.kb-drop {
    border: 1.5px dashed var(--kb-hair);
    border-radius: 14px;
    transition: border-color 150ms ease, background-color 150ms ease;
}

/* --- Ingresso in scena delle schede fonte ------------------------------ */
.kb-rise { animation: kb-rise 260ms cubic-bezier(0.22, 1, 0.36, 1) both; }

@keyframes kb-rise {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* --- Cursore di scrittura in streaming --------------------------------- */
.kb-caret {
    display: inline-block;
    width: 2px;
    height: 1.05em;
    margin-left: 2px;
    vertical-align: text-bottom;
    background: var(--kb-derived);
    animation: kb-caret 1s steps(2, start) infinite;
}

@keyframes kb-caret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* --- Prosa della risposta e del markdown del documento ----------------- */
.kb-prose {
    color: var(--kb-ink);
    font-size: 0.9375rem;
    line-height: 1.7;
    overflow-wrap: break-word;
}

.kb-prose > *:first-child { margin-top: 0; }
.kb-prose > *:last-child { margin-bottom: 0; }
.kb-prose p { margin: 0 0 0.85em; }
.kb-prose h1, .kb-prose h2, .kb-prose h3, .kb-prose h4, .kb-prose h5, .kb-prose h6 {
    margin: 1.5em 0 0.5em;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -0.01em;
}
.kb-prose h1 { font-size: 1.3rem; }
.kb-prose h2 { font-size: 1.15rem; }
.kb-prose h3 { font-size: 1.02rem; }
.kb-prose h4, .kb-prose h5, .kb-prose h6 { font-size: 0.95rem; }
.kb-prose ul, .kb-prose ol { margin: 0 0 0.85em; padding-left: 1.35em; }
.kb-prose ul { list-style: disc; }
.kb-prose ol { list-style: decimal; }
.kb-prose li { margin: 0.2em 0; }
.kb-prose li > ul, .kb-prose li > ol { margin: 0.25em 0 0.35em; }
.kb-prose a { color: var(--kb-accent); text-decoration: underline; text-underline-offset: 2px; }
.kb-prose strong { font-weight: 700; }
.kb-prose del { opacity: 0.6; }
.kb-prose hr { margin: 1.4em 0; border: 0; border-top: 1px solid var(--kb-hair); }
.kb-prose blockquote {
    margin: 0 0 0.9em;
    padding: 0.1em 0 0.1em 0.9em;
    border-left: 2px solid var(--kb-hair);
    color: var(--kb-ink-soft);
}
.kb-prose code {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.855em;
    padding: 0.12em 0.34em;
    border-radius: 5px;
    background: rgba(47, 107, 99, 0.09);
    color: #275650;
}
.dark .kb-prose code { background: rgba(183, 203, 190, 0.16); color: #d0dfd5; }
.kb-prose pre {
    margin: 0 0 0.9em;
    padding: 0.85rem 1rem;
    border-radius: 10px;
    background: #0f172a;
    color: #e7e9ed;
    overflow-x: auto;
    font-size: 0.82rem;
    line-height: 1.6;
}
.dark .kb-prose pre { background: #020617; border: 1px solid var(--kb-hair); }
.kb-prose pre code { background: none; color: inherit; padding: 0; font-size: inherit; }
.kb-prose pre[data-lang]::before {
    content: attr(data-lang);
    display: block;
    margin-bottom: 0.5rem;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.62rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #78828f;
}
.kb-table-wrap { margin: 0 0 0.9em; overflow-x: auto; }
.kb-prose table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }
.kb-prose th, .kb-prose td { padding: 0.45rem 0.7rem; border-bottom: 1px solid var(--kb-hair); }
.kb-prose th {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.68rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--kb-ink-mute);
    white-space: nowrap;
}
.kb-prose tbody tr:last-child td { border-bottom: 0; }

/* Risposta in corso: la prosa resta leggibile mentre arriva a token. */
.kb-prose-streaming p:last-child { margin-bottom: 0; }

/* --- Banco di carico: la coda di ingest agganciata al banco di lavoro ---
   Stesso alfabeto dei binari: barre da 3px, angoli appena smussati, voce mono.
   Corpo (header), lotto (banco) e documento (riga) sono lo stesso oggetto a
   tre livelli di zoom. */
.kb-dock {
    box-shadow: 0 -14px 34px -24px rgba(15, 23, 42, 0.5);
    animation: kb-dock-in 240ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.dark .kb-dock { box-shadow: 0 -14px 34px -20px rgba(0, 0, 0, 0.85); }

@keyframes kb-dock-in {
    from { transform: translateY(14px); opacity: 0; }
    to   { transform: none; opacity: 1; }
}

/* --- Avanzamento: la stessa tacca del binario, riempita ----------------- */
.kb-bar {
    height: 3px;
    border-radius: 2px;
    background: var(--kb-hair);
    overflow: hidden;
}

.kb-bar > span {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--kb-accent);
    transition: width 160ms linear;
}

.kb-bar-ok   > span { background: #2f6b63; }
.kb-bar-fail > span { background: #e11d48; }
.dark .kb-bar-ok   > span { background: #93bab1; }
.dark .kb-bar-fail > span { background: #fb7185; }

/* --- Velo di rilascio: il drop vale su tutta la pagina ------------------ */
.kb-veil {
    position: absolute;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    background: color-mix(in srgb, var(--kb-surface) 78%, transparent);
    backdrop-filter: blur(2px);
}

.kb-veil-card {
    padding: 2.25rem 2.75rem;
    text-align: center;
    border: 2px dashed var(--kb-accent);
    border-radius: 18px;
    background: color-mix(in srgb, var(--kb-accent) 7%, var(--kb-surface));
}

/* --- Selezione multipla: casella quadra, come la strumentazione --------- */
.kb-check {
    appearance: none;
    -webkit-appearance: none;
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    border: 1.5px solid var(--kb-ink-mute);
    border-radius: 4px;
    background-color: var(--kb-surface);
    background-position: center;
    background-repeat: no-repeat;
    background-size: 11px 11px;
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
}

.kb-check:hover { border-color: var(--kb-accent); }

.kb-check:checked,
.kb-check:indeterminate {
    background-color: var(--kb-accent);
    border-color: var(--kb-accent);
}

.kb-check:checked {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
}

.kb-check:indeterminate {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round'><line x1='6' y1='12' x2='18' y2='12'/></svg>");
}

.kb-check:focus-visible { outline: 2px solid var(--kb-accent); outline-offset: 2px; }
.kb-check:disabled { opacity: 0.35; cursor: default; }

/* --- Scorciatoia da tastiera dichiarata accanto al campo ---------------- */
.kb-kbd {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.625rem;
    line-height: 1;
    padding: 0.25rem 0.35rem;
    border: 1px solid var(--kb-hair);
    border-bottom-width: 2px;
    border-radius: 5px;
    color: var(--kb-ink-mute);
    background: var(--kb-surface);
}

/* --- Etichette di stato: la voce che dice come sta una cosa -------------
   Un solo corpo per tutte le etichette in maiuscoletto: stato dell'ingest,
   visto, segnale che ha risposto, esito di una riga in coda. Prima erano sei
   misure diverse nella stessa pagina. Il colore lo decide chi la usa. */
.kb-mark {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.625rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.25;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

/* --- Riga in lavorazione: la barra respira senza spostare nulla --------- */
.kb-pending { position: relative; overflow: hidden; }

.kb-pending::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--kb-accent) 9%, transparent), transparent);
    animation: kb-flow 1.8s linear infinite;
    pointer-events: none;
}

/* --- Catalogazione: il chip è la sintassi della ricerca -----------------
   Un tag si legge come lo si scrive: `#nome`, voce monospaziata, corpo neutro.
   Il segno a sinistra dice CHI l'ha assegnato — pieno una persona, cerchiato il
   classificatore — e sotto le proposte una barra da 2px dichiara la confidenza.
   Una proposta della macchina non deve mai somigliare a una decisione presa.
   La tinta (--kb-tag-hue, derivata dal nome) vive solo nel segno: cento tag su
   una pagina restano leggibili, e lo stesso tag si riconosce ovunque compaia. */
.kb-tag {
    --kb-tag-hue: 215;
    --kb-tag-ink: hsl(var(--kb-tag-hue) 62% 42%);
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    max-width: 15rem;
    padding: 0.2rem 0.55rem;
    border: 1px solid var(--kb-hair);
    border-radius: 6px;
    background: var(--kb-surface);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.6875rem;
    line-height: 1.35;
    color: var(--kb-ink-soft);
    white-space: nowrap;
    vertical-align: middle;
}

.dark .kb-tag { --kb-tag-ink: hsl(var(--kb-tag-hue) 70% 68%); }

.kb-tag > .kb-tag-name { overflow: hidden; text-overflow: ellipsis; }

/* Il segno di provenienza: pieno = assegnato da una persona. */
.kb-tag::before {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 2px;
    background: var(--kb-tag-ink);
    box-shadow: inset 0 0 0 1px var(--kb-tag-ink);
}

/* Cerchiato = proposto dal classificatore, ancora da confermare.
   Il segno resta l'unica differenza sul chip: la confidenza è un numero, e vive
   dov'è utile giudicarla (il riquadro delle proposte), non come tacca sul chip.
   Una tacca qui somiglierebbe alla barra di frequenza del registro, che vuol dire
   tutt'altro: una forma, un significato. */
.kb-tag-auto::before { background: transparent; }

/* Chip attivo: il tag sta filtrando l'elenco. */
.kb-tag-on {
    border-color: var(--kb-tag-ink);
    background: color-mix(in srgb, var(--kb-tag-ink) 12%, var(--kb-surface));
    color: var(--kb-ink);
    font-weight: 500;
}

.kb-tag-button { cursor: pointer; transition: border-color 120ms ease, background-color 120ms ease; }
.kb-tag-button:hover { border-color: var(--kb-tag-ink); }

/* La crocetta di rimozione resta dentro il chip, senza allargarlo. */
.kb-tag-x {
    flex: 0 0 auto;
    margin-right: -0.15rem;
    padding: 0 0.1rem;
    color: var(--kb-ink-mute);
    cursor: pointer;
    transition: color 120ms ease;
}

.kb-tag-x:hover { color: #e11d48; }
.dark .kb-tag-x:hover { color: #fb7185; }

/* --- Registro del vocabolario ------------------------------------------
   I tag come distribuzione, non come nuvola: una riga per tag, il conteggio
   allineato a destra e una tacca la cui lunghezza è la frequenza. Si legge
   quanto pesa ogni voce del catalogo, non solo che esiste. */
.kb-ledger-row {
    position: relative;
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    width: 100%;
    padding: 0.3rem 0.4rem 0.4rem;
    border-radius: 6px;
    cursor: pointer;
    text-align: left;
    transition: background-color 120ms ease;
}

.kb-ledger-row:hover { background: color-mix(in srgb, var(--kb-ink) 5%, transparent); }

.kb-ledger-row::after {
    content: "";
    position: absolute;
    left: 0.4rem;
    bottom: 0.15rem;
    height: 2px;
    width: calc(var(--kb-ledger-share, 0) * (100% - 0.8rem));
    border-radius: 1px;
    background: hsl(var(--kb-tag-hue, 215) 62% 42%);
    opacity: 0.35;
}

.dark .kb-ledger-row::after { background: hsl(var(--kb-tag-hue, 215) 70% 68%); opacity: 0.4; }
.kb-ledger-row-on::after { opacity: 0.9; }

/* --- Suggerimenti del token `#` in scrittura ---------------------------- */
.kb-suggest {
    position: absolute;
    z-index: 40;
    left: 0;
    right: 0;
    margin-top: 0.35rem;
    max-height: 15rem;
    overflow-y: auto;
    padding: 0.25rem;
    border: 1px solid var(--kb-hair);
    border-radius: 10px;
    background: var(--kb-surface);
    box-shadow: 0 12px 28px -18px rgba(15, 23, 42, 0.55);
}

.dark .kb-suggest { box-shadow: 0 12px 28px -14px rgba(0, 0, 0, 0.8); }

.kb-suggest-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0.35rem 0.5rem;
    border-radius: 6px;
    cursor: pointer;
    text-align: left;
}

.kb-suggest-row-on { background: color-mix(in srgb, var(--kb-accent) 12%, transparent); }

/* =======================================================================
   Archivio documenti: la ricerca dichiara sé stessa
   -----------------------------------------------------------------------
   Regola di tinta di tutta la sezione: il BLU (--kb-accent) è ciò che ha
   scelto una persona — filtro attivo, riga aperta, selezione. Il CIANO
   (--kb-derived) è ciò che ha trovato la macchina — punteggio vettoriale,
   passaggio pertinente, proposta del classificatore. Non si scambiano mai.
   ======================================================================= */

/* --- Menu a tendina dei filtri: cento cartelle e cento tag non occupano
   spazio in pagina, si aprono solo quando li si consulta ----------------- */
.kb-menu { position: relative; }

.kb-menu-panel {
    position: absolute;
    z-index: 30;
    top: calc(100% + 0.4rem);
    left: 0;
    width: 20rem;
    max-width: min(22rem, calc(100vw - 2rem));
    max-height: min(26rem, 60vh);
    overflow-y: auto;
    padding: 0.6rem;
    border: 1px solid var(--kb-hair);
    border-radius: 12px;
    background: var(--kb-surface);
    box-shadow: 0 18px 44px -22px rgba(15, 23, 42, 0.45), 0 2px 6px -2px rgba(15, 23, 42, 0.12);
    animation: kb-menu-in 120ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.dark .kb-menu-panel { box-shadow: 0 18px 44px -18px rgba(0, 0, 0, 0.8); }
.kb-menu-panel-right { left: auto; right: 0; }

/* Sopra il pulsante: nel compositore un menu che scende finirebbe fuori pagina. */
.kb-menu-panel-up {
    top: auto;
    bottom: calc(100% + 0.4rem);
    animation-name: kb-menu-in-up;
}

@keyframes kb-menu-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

@keyframes kb-menu-in-up {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}

/* Il bottone di un filtro attivo si vede che è attivo anche da chiuso. */
.kb-filter {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--kb-hair);
    border-radius: 8px;
    background: var(--kb-surface);
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--kb-ink-soft);
    cursor: pointer;
    transition: border-color 120ms ease, background-color 120ms ease, color 120ms ease;
}

.kb-filter:hover { border-color: color-mix(in srgb, var(--kb-ink) 25%, transparent); color: var(--kb-ink); }

.kb-filter-on {
    border-color: color-mix(in srgb, var(--kb-accent) 55%, transparent);
    background: color-mix(in srgb, var(--kb-accent) 9%, var(--kb-surface));
    color: color-mix(in srgb, var(--kb-accent) 78%, var(--kb-ink));
}

.kb-filter-count {
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.625rem;
    padding: 0 0.3rem;
    border-radius: 99px;
    background: color-mix(in srgb, var(--kb-accent) 16%, transparent);
    color: color-mix(in srgb, var(--kb-accent) 85%, var(--kb-ink));
}

/* --- Riga dello stato: l'archivio dichiara la propria interrogazione ---- */
.kb-chipf {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.15rem 0.3rem 0.15rem 0.5rem;
    border: 1px solid color-mix(in srgb, var(--kb-accent) 40%, transparent);
    border-radius: 99px;
    background: color-mix(in srgb, var(--kb-accent) 8%, transparent);
    font-size: 0.6875rem;
    color: color-mix(in srgb, var(--kb-accent) 80%, var(--kb-ink));
    max-width: 15rem;
}

.kb-chipf-x {
    display: inline-flex;
    height: 1rem;
    width: 1rem;
    align-items: center;
    justify-content: center;
    border-radius: 99px;
    font-size: 0.8rem;
    line-height: 1;
    color: inherit;
    opacity: 0.65;
    cursor: pointer;
}

.kb-chipf-x:hover { opacity: 1; background: color-mix(in srgb, var(--kb-accent) 18%, transparent); }

/* La riga che dichiara l'interrogazione: alta sempre uguale, così scegliere una
   cartella o un tag non fa scendere l'elenco di qualche pixel. I gettoni che vi
   compaiono — briciole, tag, filtri — hanno tutti la stessa misura. */
.kb-statusline { min-height: 1.75rem; }

/* --- Percorso: le briciole sono anche bersagli di rilascio -------------- */
.kb-crumb {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    max-width: 14rem;
    padding: 0.15rem 0.4rem;
    border-radius: 6px;
    font-size: 0.6875rem;
    color: var(--kb-ink-soft);
    cursor: pointer;
}

.kb-crumb:hover { background: color-mix(in srgb, var(--kb-ink) 6%, transparent); color: var(--kb-ink); }
.kb-crumb-on { font-weight: 700; color: var(--kb-ink); cursor: default; }
.kb-crumb-on:hover { background: none; }
.kb-crumb-drop { background: color-mix(in srgb, var(--kb-accent) 18%, transparent); box-shadow: inset 0 0 0 2px var(--kb-accent); }

/* --- L'elenco è un registro: la riga non cambia con la selezione --------
   Altezza, carattere e colonne dipendono da quanto spazio ha l'elenco, non
   da cosa è selezionato: aprire il dettaglio restringe l'elenco, non ne
   riscrive la tipografia. Perciò le soglie si misurano sull'elenco stesso
   (container query) e non sulla finestra. Le colonne che non entrano si
   ripiegano nella riga dei fatti sotto il nome, e la riga resta alta uguale
   sia che sia una cartella, un documento in lavorazione o un esito di
   ricerca: un registro con le righe che ballano non si legge. */
.kb-list {
    container-type: inline-size;
    container-name: kblist;
    --kb-row-h: 3.4rem;
    /* Dove comincia il nome: bordo + casella + bollo. Ciò che si apre sotto una
       riga si allinea al nome, non al bordo della pagina. */
    --kb-name-indent: 4.8rem;
}

.kb-under {
    margin-left: var(--kb-name-indent);
    margin-right: 1rem;
}

.kb-item {
    position: relative;
    border-bottom: 1px solid var(--kb-hair);
    transition: background-color 110ms ease;
}

.kb-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: var(--kb-row-h);
    padding: 0.4rem 1rem 0.4rem 0.75rem;
    text-align: left;
}

/* La testata del registro c'è sempre e ha sempre lo stesso carattere: cambia
   l'etichetta delle colonne, mai il corpo, il maiuscoletto o l'altezza. */
.kb-head {
    min-height: 2.35rem;
    padding-top: 0;
    padding-bottom: 0;
}

.kb-item-on { background: color-mix(in srgb, var(--kb-accent) 8%, transparent); }
.kb-item-mark { background: color-mix(in srgb, var(--kb-ink) 5%, transparent); }
.kb-item:hover:not(.kb-item-on) { background: color-mix(in srgb, var(--kb-ink) 3.5%, transparent); }
.kb-item-cursor { box-shadow: inset 2px 0 0 0 var(--kb-accent); }
.kb-item-drop { background: color-mix(in srgb, var(--kb-accent) 16%, transparent); box-shadow: inset 0 0 0 2px var(--kb-accent); }

/* Il filo sul bordo sinistro segna il documento aperto nel pannello. */
.kb-item-on::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--kb-accent);
}

/* Le colonne dei fatti: nascoste finché l'elenco non ha la larghezza per
   dirle senza mentire. Nessuna cella può far crescere la riga. */
.kb-col { display: none; min-width: 0; overflow: hidden; }

/* I tag stanno su una riga sola: a capo sposterebbero tutto l'elenco. La
   sfumatura sul taglio dice che ce n'è ancora, invece di troncarne uno a metà. */
.kb-col-tags > div { flex-wrap: nowrap; }
.kb-col-tags {
    mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
}

/* Lo stato c'è a ogni larghezza, sempre in fondo alla riga e allineato a
   destra: è l'ultima cosa che si legge di un documento. Interlinea corta e
   nessun ritorno a capo, così due etichette non alzano la riga. */
.kb-col-status {
    display: flex;
    min-width: 0;
    align-items: center;
    justify-content: flex-end;
    gap: 0.4rem;
    line-height: 1.25;
    white-space: nowrap;
}

/* Stessa colonna, per le cartelle: lì non c'è uno stato, ci sono i comandi. */
.kb-col-actions {
    display: flex;
    min-width: 0;
    align-items: center;
    justify-content: flex-end;
    gap: 0.25rem;
}

/* Il posto della casella di selezione dove la casella non c'è: le cartelle
   allineano il nome esattamente come i documenti. */
.kb-check-space { display: block; width: 15px; }

/* La striscia dell'ingest e il pulsante di spostamento dicono la stessa cosa
   a due larghezze: mai insieme, mai nessuno dei due. La regola che nasconde
   sta su due classi perché deve battere il `display` dei bottoni di Tailwind,
   che è iniettato dopo questo foglio. */
.kb-strip { display: none; width: 100%; }

/* I fatti senza colonna stanno sotto il nome: appena la colonna esiste,
   spariscono da lì. Lo stesso dato non compare mai due volte nella riga. */
.kb-fact-col,
.kb-fact-folder { display: inline; }

/* Prima soglia: entrano i fatti che orientano — dove sta il documento e come
   è catalogato. */
@container kblist (min-width: 36rem) {
    .kb-row { grid-template-columns: auto minmax(0, 1.7fr) minmax(0, 0.9fr) minmax(0, 1.1fr) 7rem; }
    .kb-col-tags,
    .kb-col-where { display: block; }
    .kb-fact-folder { display: none; }
    .kb-strip { display: block; }
    .kb-row .kb-narrow-only { display: none; }
    /* Con la colonna larga lo stato si impila: parola, visto, striscia. */
    .kb-col-status {
        flex-direction: column;
        align-items: flex-end;
        justify-content: center;
        gap: 0.2rem;
    }
}

/* Seconda soglia: entrano i fatti che si contano, incolonnati e tabellari. */
@container kblist (min-width: 56rem) {
    .kb-row { grid-template-columns: auto minmax(0, 2.4fr) minmax(0, 1.15fr) minmax(0, 1.35fr) 4.5rem 5.5rem 7rem; }
    .kb-col-chunks,
    .kb-col-size { display: block; }
    .kb-fact-col { display: none; }
}

/* Il bollo dell'estensione: dice che tipo di file si sta leggendo. */
.kb-ext {
    display: inline-flex;
    height: 1.75rem;
    width: 1.75rem;
    flex: none;
    align-items: center;
    justify-content: center;
    border-radius: 7px;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.5625rem;
    font-weight: 600;
    text-transform: uppercase;
}

/* Il bollo della cartella: stesso posto e stessa misura del bollo del file,
   ma vuoto — una cartella non ha un tipo, ha un contenuto. */
.kb-ext-folder {
    border: 1px dashed color-mix(in srgb, var(--kb-ink) 20%, transparent);
    color: var(--kb-ink-mute);
}

/* --- Pertinenza: quanto vale un esito, e per quale segnale --------------
   Barra ciano perché il numero non è una scelta di chi cerca: è la risposta
   dell'indice. La quota vettoriale sta sotto quella complessiva, così si
   vede a colpo d'occhio se ha risposto il testo o l'embedding. */
.kb-meter {
    position: relative;
    height: 3px;
    width: 100%;
    min-width: 3rem;
    border-radius: 99px;
    background: color-mix(in srgb, var(--kb-ink) 10%, transparent);
    overflow: hidden;
}

.kb-meter > span {
    position: absolute;
    inset: 0 auto 0 0;
    border-radius: 99px;
    background: var(--kb-derived);
}

.kb-meter-text > span { background: color-mix(in srgb, var(--kb-ink-mute) 70%, transparent); }

/* Il passaggio che ha risposto: si legge, e da lì si apre il chunk. */
.kb-passage {
    border-left: 2px solid color-mix(in srgb, var(--kb-derived) 55%, transparent);
    padding-left: 0.65rem;
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--kb-ink-soft);
    cursor: pointer;
    /* Due righe: quanto basta a giudicare l'esito senza sfrattare gli altri. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.kb-passage:hover { border-left-color: var(--kb-derived); color: var(--kb-ink); }
.kb-passage mark { background: color-mix(in srgb, var(--kb-derived) 22%, transparent); color: inherit; border-radius: 3px; padding: 0 2px; }

/* --- Il visto: un timbro, non un'etichetta -----------------------------
   L'approvazione è un atto, e si legge come tale: blocco squadrato, voce
   monospaziata in maiuscolo, tacca d'angolo come il resto della pagina.
   Inclinato solo quando qualcuno ha davvero timbrato; in attesa resta un
   contorno tratteggiato e diritto, perché non c'è ancora nessun atto.
   Il colore arriva da fuori (currentColor): lo stato lo decide chi lo usa. */
.kb-seal {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    padding: 0.55rem 0.9rem;
    border: 1.5px solid currentColor;
    border-radius: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.1;
    text-transform: uppercase;
    letter-spacing: 0.18em;
}

.kb-seal small {
    font-size: 0.58rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    opacity: 0.75;
}

.kb-seal::after {
    content: "";
    position: absolute;
    top: 3px;
    right: 3px;
    width: 4px;
    height: 4px;
    background: currentColor;
    opacity: 0.55;
}

.kb-seal-stamped { transform: rotate(-1.5deg); }
.kb-seal-open { border-style: dashed; }
.kb-seal-open::after { opacity: 0.3; }

/* --- Dettaglio: un pannello che si chiude, non una seconda pagina -------
   Sotto xl scorre sopra l'elenco con velo; da xl si affianca e si può
   allargare trascinando il bordo. L'elenco resta la spina dorsale. */
.kb-sheet {
    display: flex;
    flex-direction: column;
    background: var(--kb-surface);
    min-height: 0;
}

/* Sotto i 1024px la scheda è a tutto schermo: la regola sta in fondo al foglio,
   nella sezione mobile, perché lì misura anche il vetro e le tacche di sicurezza. */

@media (min-width: 1024px) {
    /* Affiancato: la larghezza salvata vale, ma l'elenco non scende mai sotto un terzo. */
    .kb-sheet { position: relative; flex: none; max-width: 66%; border-left: 1px solid var(--kb-hair); }
    .kb-sheet-wide { position: absolute; inset: 0; z-index: 20; width: auto !important; max-width: none; border-left: 0; }
}

.kb-scrim {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(15, 23, 42, 0.35);
    backdrop-filter: blur(1px);
}

@media (min-width: 1024px) { .kb-scrim { display: none; } }

/* Maniglia di larghezza: 6px di presa, invisibile finché non serve. */
.kb-grip {
    position: absolute;
    top: 0;
    bottom: 0;
    left: -3px;
    width: 6px;
    cursor: col-resize;
    z-index: 25;
}

.kb-grip:hover, .kb-grip-on { background: color-mix(in srgb, var(--kb-accent) 45%, transparent); }
@media (max-width: 1023.98px) { .kb-grip { display: none; } }

/* --- Selezione: la barra galleggia, non ruba righe all'elenco ----------- */
.kb-selbar {
    position: sticky;
    bottom: 0.75rem;
    z-index: 15;
    margin: 0 auto;
    width: fit-content;
    max-width: calc(100% - 1.5rem);
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--kb-hair);
    border-radius: 12px;
    background: var(--kb-surface);
    box-shadow: 0 16px 40px -20px rgba(15, 23, 42, 0.45);
    animation: kb-menu-in 140ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.dark .kb-selbar { box-shadow: 0 16px 40px -16px rgba(0, 0, 0, 0.8); }

/* --- Finestra modale per le azioni in blocco --------------------------- */
.kb-modal {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 1rem;
    overflow-y: auto;
    background: rgba(15, 23, 42, 0.4);
}

.kb-modal-card {
    width: 100%;
    max-width: 44rem;
    margin: 2.5rem auto;
    border: 1px solid var(--kb-hair);
    border-radius: 14px;
    background: var(--kb-surface);
    box-shadow: 0 30px 70px -30px rgba(15, 23, 42, 0.6);
    animation: kb-menu-in 160ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* --- Focus visibile su tutta la strumentazione della pagina ------------- */
.kb-page :focus-visible { outline: 2px solid var(--kb-accent); outline-offset: 2px; border-radius: 6px; }

/* --- Rispetto delle preferenze di movimento ---------------------------- */
@media (prefers-reduced-motion: reduce) {
    .kb-flow, .kb-caret, .kb-rise, .kb-dock, .kb-pending::after { animation: none !important; }
    .kb-ribbon-tick, .kb-bar > span { transition: none; }
    .kb-caret { opacity: 1; }
    .kb-menu-panel, .kb-selbar, .kb-modal-card { animation: none; }
}

/* ==========================================================================
   IL MARCHIO
   --------------------------------------------------------------------------
   omneres: una o in tre archi per Know. Own. Act., logotipo minuscolo
   in Satoshi e palette navy, verde e avorio.
   ========================================================================== */

/* Il logotipo: Satoshi Bold, crenatura stretta, tutto minuscolo. Il segno gli
   sta accanto alla stessa altezza dell'occhio medio, non della maiuscola. */
.brand-lockup {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    min-width: 0;
}

.brand-lockup-mark { gap: 0; }

.brand-lockup .brand-mark {
    width: 1.28em;
    height: 1.28em;
}

.brand-lockup .brand-word {
    font-family: 'Satoshi', 'Inter', system-ui, sans-serif;
    font-weight: 700;
    letter-spacing: -0.03em;
    font-size: 1em;
}

/* Il segno prende l'inchiostro dal contesto (`currentColor`): su ivory è navy,
   su navy è ivory. L’arco centrale resta verde in entrambi i casi — è l'unica costante
   cromatica del marchio. */
.brand-mark .brand-ring { stroke: currentColor; }
.brand-mark .brand-flow { stroke: var(--omneres-green); }
.dark .brand-mark .brand-flow { stroke: var(--omneres-sage); }

/* Il payoff resta in inglese, su una sola riga. */
.brand-payoff {
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: 0.08em;
    white-space: nowrap;
    color: var(--gray-700);
}
.dark .brand-payoff { color: var(--gray-300); }

/* Elemento grafico: le onde del marchio, ancorate in basso a sinistra come
   sulla copertina. Decorative: `aria-hidden` lato markup, nessun hit test. */
.brand-waves {
    position: absolute;
    left: 0;
    bottom: 0;
    width: min(560px, 78%);
    pointer-events: none;
    user-select: none;
    opacity: 0.85;
}
.dark .brand-waves { opacity: 0.5; }

/* Pattern: trattini in diagonale a densità bassa, per i fondali quieti. */
.brand-pattern {
    background-image: url("./brand/omneres-dots.svg");
    background-repeat: repeat;
    background-size: 24px 24px;
}
.dark .brand-pattern { opacity: 0.55; }

/* Superficie di marca: l'ivory è il fondale di default, non il bianco puro. */
.brand-surface { background: var(--omneres-ivory); }
.dark .brand-surface { background: var(--omneres-navy); }

/* Selezione e anello di fuoco parlano la stessa lingua dell'accento. */
::selection {
    background: rgba(47, 107, 99, 0.20);
    color: var(--omneres-navy);
}
.dark ::selection {
    background: rgba(183, 203, 190, 0.28);
    color: var(--omneres-ivory);
}

:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}
.dark :focus-visible { outline-color: var(--omneres-sage); }

/* L'ambra è l'accento raro: la si usa per un solo elemento per schermata. */
.brand-accent-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
    background: var(--omneres-amber);
    flex-shrink: 0;
}

/* ==========================================================================
   LO STESSO STRUMENTO, TENUTO IN UNA MANO
   --------------------------------------------------------------------------
   Il telefono non è una versione ridotta dell'applicazione: è la stessa
   strumentazione — fili da 1px, voce monospaziata, verde profondo per ciò che
   sceglie una persona e sage per ciò che trova la macchina — impugnata con un
   pollice.
   Perciò qui non nasce nessun alfabeto nuovo: cambiano il vetro (quanto ne c'è
   davvero, e dove la tastiera lo copre), i bersagli (un dito non è un cursore) e
   il posto dei pannelli (una tendina che scende finirebbe fuori schermo: sale
   dal basso, dove arriva il pollice).

   Convenzioni di questo foglio:
   · `--app-h`     altezza utile del vetro, misurata da src/viewport.js
   · `--kbd-inset` quanto ne copre la tastiera
   · `.is-touch`   il puntatore è un dito
   · `.kbd-open`   la tastiera è aperta
   · soglia unica  1024px: sotto, una colonna; sopra, il banco di lavoro
   ========================================================================== */

:root {
    /* Bersaglio comodo per un pollice. 40px è il minimo che si prende senza
       guardare; i gettoni troppo piccoli per crescere allargano l'area con un
       pseudo-elemento, non il proprio corpo. */
    --tap: 2.5rem;
    --safe-t: env(safe-area-inset-top, 0px);
    --safe-b: env(safe-area-inset-bottom, 0px);
    --safe-l: env(safe-area-inset-left, 0px);
    --safe-r: env(safe-area-inset-right, 0px);
    /* Altezza della barra di navigazione mobile, notch escluso. */
    --topbar-h: 3.25rem;
}

/* --- Igiene di base ----------------------------------------------------- */

html {
    /* Ruotare il telefono non deve reimpaginare il testo (iOS lo fa da solo). */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    /* La pagina non rimbalza: sono i pannelli interni a scorrere. */
    overscroll-behavior-y: none;
}

/* Con il menù o un pannello aperto la pagina sotto non scorre. */
html.scroll-locked, html.scroll-locked body { overflow: hidden; }

/* L'altezza utile: da 1024px in su una pagina, sotto un guscio.
   ---------------------------------------------------------------------------
   Sul banco di lavoro l'altezza si dichiara con un numero (`dvh`) e la pagina
   scorre: nessuna barra del browser va e viene, quel numero è vero.
   Su un telefono no. Ci abbiamo provato due volte — prima con la misura del visual
   viewport (`--app-h`), poi con `dvh` — e in entrambi i casi su Firefox per Android
   la misura era più grande del vetro visibile: il documento diventava alto ~60px
   più del visibile, scorreva a vuoto, e compariva una barra di scorrimento su tutto
   il sito. Il difetto non era l'unità scelta: era **dichiarare un'altezza**.

   --- Sotto i 1024px l'app è un guscio fisso, non una pagina ---------------
   Nessuna altezza dichiarata con un numero: `position: fixed; inset: 0` fa
   calcolare il riquadro al motore, e `overflow: hidden` sul documento fa sì che
   una barra di scorrimento di pagina **non possa esistere** — su qualunque
   browser, anche se la sua idea di «alto quanto lo schermo» è sbagliata. Scorrono
   i pannelli interni, che è ciò che un'app fa.
   `max-height: var(--app-h)` è la rifinitura: il visual viewport è l'unica misura
   che per definizione è il visibile, quindi se il motore fosse più generoso (o si
   aprisse la tastiera) il guscio si taglia lì. Se quella misura mancasse o
   mentisse, resta comunque vero che il documento non scorre. */
.app-shell { min-height: 100vh; min-height: 100dvh; }
.kb-viewport { height: 100vh; height: 100dvh; }
.app-page { min-height: 100vh; min-height: 100dvh; }
.app-minvh { min-height: 100vh; min-height: 100dvh; }
.app-fill { min-height: 100vh; min-height: 100dvh; }

@media (max-width: 1023.98px) {
    html, body {
        height: 100%;
        overflow: hidden;
        overscroll-behavior: none;
    }

    .app-shell {
        position: fixed;
        inset: 0;
        min-height: 0;
        max-height: var(--app-h, none);
    }

    /* L'unico pannello che scorre al posto della pagina: lo scorrimento resta
       inerziale come quello nativo. */
    .app-shell > main { -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }

    /* Dentro un guscio con un'altezza definita, «tutto lo spazio» si dice con una
       percentuale: nessuna unità di vetro, nessuna misura da rifare. */
    .kb-viewport { height: 100%; }
    .app-page { min-height: 100%; }
    .app-fill { min-height: 100%; }
}

/* --- Il dito non ha hover ----------------------------------------------
   Metà della strumentazione si scopre passando il mouse: la casella di
   selezione di una riga, il pulsante di spostamento, la crocetta di un
   commento. Su un telefono quel gesto non esiste, quindi quei comandi
   semplicemente non ci sarebbero. Dove non c'è hover, si vedono. */
@media (hover: none) {
    [class*="group-hover:opacity-100"],
    [class*="focus-within:opacity-100"] { opacity: 1 !important; }

    /* Nessun effetto che resti appiccicato dopo il tocco. */
    .btn:hover { transform: none; }
    .hover-scale:hover { transform: none; }
    .navbar-brand:hover { transform: none; }
}

/* --- Bersagli da pollice ------------------------------------------------ */
.is-touch button,
.is-touch [role="button"],
.is-touch a,
.is-touch input,
.is-touch select,
.is-touch textarea,
.is-touch label {
    /* Niente ritardo di 300ms e nessun lampo grigio al tocco. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

.is-touch .kb-icon-btn { height: var(--tap); width: var(--tap); }
.is-touch .kb-ghost,
.is-touch .kb-solid,
.is-touch .kb-filter,
.is-touch .kb-seg,
.is-touch .kb-tab,
.is-touch .nav-link,
.is-touch .btn-primary,
.is-touch .btn-secondary,
.is-touch .btn-danger { min-height: var(--tap); }

/* Un comando di sola icona non deve essere più stretto che alto. */
.is-touch .kb-ghost,
.is-touch .kb-solid { min-width: var(--tap); justify-content: center; }

.is-touch .kb-crumb { min-height: 2rem; }
.is-touch .kb-field,
.is-touch .form-input,
.is-touch .form-select,
.is-touch select,
.is-touch textarea { min-height: var(--tap); }

/* Il marchio nella barra è un collegamento: alto quanto la barra, non quanto l'immagine. */
.app-topbar a, .app-topbar button { min-height: var(--tap); }

/* Gettoni che non possono crescere senza riscrivere la riga: cresce l'area
   sensibile, non il segno. */
.is-touch .kb-chipf-x,
.is-touch .kb-tag-x,
.is-touch .kb-check,
.is-touch .btn-xs-primary,
.is-touch .btn-xs-danger,
.is-touch .btn-xs-gray { position: relative; }

.is-touch .kb-chipf-x::after,
.is-touch .kb-tag-x::after,
.is-touch .kb-check::after,
.is-touch .btn-xs-primary::after,
.is-touch .btn-xs-danger::after,
.is-touch .btn-xs-gray::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, var(--tap));
    height: max(100%, var(--tap));
    transform: translate(-50%, -50%);
}

/* La casella di selezione di una riga: 15px si vedono, 24px si prendono — il minimo
   di WCAG 2.2 AA. Non arriva a 40px perché una casella dentro un registro denso
   comincerebbe a somigliare a un pulsante: sbagliare la mira apre la riga, che è il
   gesto principale e non distrugge niente.
   (Un `::after` che allarghi l'area non serve a nulla qui: gli pseudo-elementi non
   valgono sugli elementi vuoti come `input`.) */
.is-touch .kb-check { width: 24px; height: 24px; background-size: 16px 16px; }
.is-touch .kb-check-space { width: 24px; }

/* Il bollo dell'estensione e la data sotto il timbro: 9px in mano non si leggono. */
.is-touch .kb-ext { font-size: 0.625rem; }
.is-touch .kb-seal small { font-size: 0.6875rem; }

/* Il nastro dei chunk: l'altezza di una tacca è un dato (i caratteri del chunk),
   quindi non può crescere. Cresce l'area sensibile, che sale a tutta l'altezza del
   nastro: si tocca sopra la tacca, non la tacca. Restano il lettore con avanti e
   indietro e l'indice delle sezioni come navigazione principale. */
.is-touch .kb-ribbon { height: 52px; }
.is-touch .kb-ribbon-tick { position: relative; min-width: 8px; }

.is-touch .kb-ribbon-tick::after {
    content: "";
    position: absolute;
    left: -1px;
    right: -1px;
    bottom: 0;
    height: 52px;
}

/* Un gettone di tag è anche un comando (filtra l'elenco): 23px non si prendono. */
.is-touch .kb-tag { min-height: 26px; }

/* I comandi dentro una riga del registro — il nome della cartella che ci porta,
   il passaggio che apre il chunk — sono alti quanto il testo che li scrive. */
.is-touch .kb-row button:not(.kb-icon-btn),
.is-touch .kb-item > button { min-height: 24px; }

/* I comandi in voce monospaziata dentro una riga di testo — la traccia dei tool,
   «con sottocartelle», i conteggi che aprono un elenco — sono alti quanto il testo.
   Restano dove sono, con l'altezza minima di WCAG. */
.is-touch button.kb-num,
.is-touch a.kb-num {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
}

/* --- Campi: 16px, altrimenti iOS ingrandisce da solo -------------------
   Safari su iPhone zooma la pagina quando si mette a fuoco un campo con testo
   sotto i 16px, e non torna indietro. Sotto la soglia del banco di lavoro tutti
   i campi parlano a 16px: nessuno zoom involontario, nessun `user-scalable=no`
   (che toglierebbe anche lo zoom con due dita). */
@media (max-width: 1023.98px) {
    /* `!important` non è pigrizia: le utility di Tailwind (`text-xs`, `text-[13px]`)
       sono iniettate dopo questo foglio e hanno la stessa specificità di `.kb-field`,
       quindi vincerebbero. E sotto i 16px iOS ingrandisce la pagina e non torna:
       è l'unico caso in cui la misura del carattere non è una scelta grafica. */
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    select,
    textarea,
    .kb-field,
    .form-input,
    .form-select { font-size: 16px !important; }

    /* Il compositore della chat resta il testo che si legge scrivendo. */
    .kb-composer textarea { line-height: 1.5; }
}

/* --- Scorrimento orizzontale: tabelle e binari ------------------------- */
[class*="overflow-x-auto"], .kb-rail {
    -webkit-overflow-scrolling: touch;
    /* Firefox disegna una barra piena dove gli altri ne mostrano una sovrapposta:
       sottile, così una tabella che scorre non guadagna un bordo grigio. */
    scrollbar-width: thin;
}

/* Il binario dei filtri: una fila che si spinge col pollice invece di
   quattro righe di gettoni che mangiano l'elenco. Stesso motivo dei binari a
   tacche del resto della pagina, orizzontale. */
.kb-rail {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
}

@media (max-width: 639.98px) {
    .kb-rail {
        overflow-x: auto;
        overflow-y: hidden;
        flex-wrap: nowrap;
        scrollbar-width: none;
        margin: 0 -1rem;
        /* Il gettone tagliato sul bordo dice che il binario continua. Niente
           `mask-image`: creerebbe un blocco contenitore per i pannelli
           `position: fixed` che vivono qui dentro, e il foglio dal basso finirebbe
           tagliato dallo scorrimento del binario. */
        padding: 0 1rem 2px;
        scroll-padding-right: 1rem;
    }
    .kb-rail::-webkit-scrollbar { display: none; }
    .kb-rail > * { flex: 0 0 auto; }
}

/* --- Tendine che diventano fogli dal basso -----------------------------
   Un pannello da 20rem ancorato al suo pulsante, su uno schermo da 360px,
   finisce fuori dal vetro o sotto il pollice. Sale dal basso, alto quanto
   serve, e si chiude toccando fuori. */
@media (max-width: 639.98px) {
    .kb-menu-panel,
    .kb-menu-panel-right,
    .kb-menu-panel-up {
        position: fixed;
        top: auto;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 70;
        width: auto;
        max-width: none;
        bottom: var(--kbd-inset, 0px);
        max-height: min(72dvh, calc(var(--app-h, 100dvh) - 3.5rem));
        padding: 0.85rem 1rem calc(1rem + var(--safe-b));
        border-width: 1px 0 0;
        border-radius: 18px 18px 0 0;
        box-shadow: 0 -22px 55px -28px rgba(15, 23, 42, 0.55);
        animation-name: kb-sheet-up;
    }

    /* Dentro un foglio si tocca col pollice: le righe sono alte come un bersaglio. */
    .kb-menu-panel button,
    .kb-menu-panel label { min-height: var(--tap); }

    /* La presa: dice che il foglio si chiude tirandolo verso il basso. */
    .kb-menu-panel::before {
        content: "";
        display: block;
        width: 2.25rem;
        height: 4px;
        margin: -0.15rem auto 0.7rem;
        border-radius: 99px;
        background: var(--kb-hair);
    }

    .dark .kb-menu-panel { box-shadow: 0 -22px 55px -24px rgba(0, 0, 0, 0.85); }
}

@keyframes kb-sheet-up {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}

/* Il velo del foglio: tocco fuori = chiuso. Vive fuori da `.kb-menu`, così il
   gestore che chiude i menù lo riconosce come "fuori". */
.kb-sheet-scrim {
    position: fixed;
    inset: 0;
    z-index: 65;
    background: rgba(15, 23, 42, 0.32);
}

@media (min-width: 640px) { .kb-sheet-scrim { display: none; } }

/* --- Barra di navigazione mobile ---------------------------------------
   La stessa voce delle pagine: un'etichetta monospaziata in maiuscoletto dice
   dove si è, un filo da 1px la separa dal contenuto. Non è mobilia
   dell'applicazione: è la testata dello strumento. */
.app-topbar {
    position: sticky;
    top: 0;
    z-index: 45;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    height: calc(var(--topbar-h) + var(--safe-t));
    padding: var(--safe-t) max(0.5rem, var(--safe-r)) 0 max(0.5rem, var(--safe-l));
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--gray-200);
}

.dark .app-topbar {
    background: rgba(15, 23, 42, 0.92);
    border-bottom-color: #334155;
}

.app-topbar-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    position: relative;
    height: var(--tap);
    width: var(--tap);
    border-radius: 12px;
    color: var(--gray-600);
    cursor: pointer;
    transition: background-color 120ms ease, color 120ms ease;
}

.app-topbar-btn:hover { background: var(--gray-100); color: var(--gray-800); }
.dark .app-topbar-btn { color: #d3d8de; }
.dark .app-topbar-btn:hover { background: rgba(183, 203, 190, 0.16); color: #f7f6f2; }

/* Il numero delle notifiche non lette, sul pulsante. */
.app-topbar-badge {
    position: absolute;
    top: 0.35rem;
    right: 0.3rem;
    min-width: 1.05rem;
    height: 1.05rem;
    padding: 0 0.2rem;
    border-radius: 99px;
    background: #f43f5e;
    color: #fff;
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.625rem;
    font-weight: 600;
    line-height: 1.05rem;
    text-align: center;
}

/* --- Cassetto della navigazione ----------------------------------------
   Sotto i 1024px la colonna di sinistra non sta in pagina: entra da sinistra
   quando la si chiama, con il suo filo sul bordo. Sopra, resta la colonna
   fissa di sempre — questa regola non la tocca. */
@media (max-width: 1023.98px) {
    .app-sidebar {
        /* `absolute` e non `fixed`: il blocco contenitore è il guscio, che è già
           esattamente il vetro visibile. Niente altezze da ricalcolare. */
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 60;
        width: min(19rem, 86vw);
        padding-top: var(--safe-t);
        padding-bottom: var(--safe-b);
        padding-left: var(--safe-l);
        transform: translateX(-101%);
        /* Chiuso non è solo fuori vista: `visibility` lo toglie anche al Tab, così
           la tastiera non finisce dentro un cassetto che non si vede. */
        visibility: hidden;
        transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1), visibility 220ms;
        box-shadow: 24px 0 60px -32px rgba(15, 23, 42, 0.55);
        will-change: transform;
    }

    .app-sidebar.is-open { transform: none; visibility: visible; }

    .app-scrim {
        position: absolute;
        inset: 0;
        z-index: 55;
        background: rgba(15, 23, 42, 0.4);
        backdrop-filter: blur(1px);
        animation: fadeIn 160ms ease both;
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-sidebar { transition: none; }
    .app-scrim { animation: none; }
    .kb-menu-panel { animation: none; }
}

/* --- Foglio delle notifiche (mobile) ----------------------------------- */
.app-notif-sheet {
    position: fixed;
    left: 0;
    right: 0;
    top: calc(var(--topbar-h) + var(--safe-t));
    z-index: 50;
    display: flex;
    flex-direction: column;
    max-height: min(70dvh, calc(var(--app-h, 100dvh) - var(--topbar-h) - 2rem));
    background: #fff;
    border-bottom: 1px solid var(--gray-200);
    box-shadow: 0 18px 40px -26px rgba(15, 23, 42, 0.5);
    animation: kb-menu-in 140ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.dark .app-notif-sheet { background: #0f172a; border-bottom-color: #334155; }

/* --- Snackbar sopra la barra di casa ----------------------------------- */
.app-snackbar { bottom: calc(1.5rem + var(--safe-b)); }
.kbd-open .app-snackbar { bottom: calc(1rem + var(--kbd-inset, 0px)); }

/* ==========================================================================
   Knowledge base su telefono
   ========================================================================== */

/* --- Il dettaglio del documento: una scheda a tutto schermo ------------- */
@media (max-width: 1023.98px) {
    .kb-sheet {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 45;
        max-height: var(--app-h, none);
        width: 100% !important;
        max-width: 100%;
        padding-top: var(--safe-t);
        box-shadow: -24px 0 60px -30px rgba(15, 23, 42, 0.5);
    }

    /* L'ultima riga di un pannello non finisce sotto la barra di casa. */
    .kb-sheet > *:last-child { padding-bottom: var(--safe-b); }

    /* L'identità del documento (nome, fatti, tag, comandi, pipeline) è alta 500px:
       su un telefono lascerebbe novanta pixel alla scheda che si è chiesto di aprire.
       Si ferma a metà scheda e scorre per conto suo; le linguette e il contenuto
       tengono l'altra metà. */
    .kb-sheet-head { max-height: 45%; overflow-y: auto; overscroll-behavior: contain; }
}

/* --- Il registro su una colonna sola -----------------------------------
   A 375px il nome e lo stato non stanno sulla stessa riga: «Verbale riunione del
   comitato…» diventava «Verbale riunion…» per fare posto a «IN ELABORAZIONE».
   Lo stato scende sotto il nome — dove già stanno i fatti senza colonna — e il
   nome si prende tutta la larghezza. L'ordine di lettura non cambia: nome, poi
   fatti, poi stato. */
@media (max-width: 639.98px) {
    .kb-list { --kb-row-h: 3.5rem; --kb-name-indent: 4.4rem; }

    .kb-row {
        grid-template-columns: auto minmax(0, 1fr);
        align-items: start;
        /* `align-content: start` tiene le due righe attaccate: con lo spazio in più
           distribuito, lo stato scivolava in fondo e la riga sembrava vuota in mezzo. */
        align-content: start;
        gap: 0.15rem 0.65rem;
        padding-top: 0.5rem;
        padding-bottom: 0.5rem;
    }

    /* La casella resta allineata al nome, non al centro di due righe. */
    .kb-row > input.kb-check { margin-top: 0.55rem; }

    .kb-col-status,
    .kb-col-actions {
        grid-column: 2;
        justify-content: flex-start;
        flex-wrap: wrap;
        gap: 0.15rem 0.5rem;
    }

    /* Nella testata il nome della colonna dello stato non serve: la colonna non c'è. */
    .kb-head { min-height: 2.6rem; align-items: center; }
    .kb-head > input.kb-check { margin-top: 0; }
    .kb-head .kb-col-status { display: none; }
}

/* --- Barra della selezione e banco di carico --------------------------- */
.kb-selbar { bottom: calc(0.75rem + var(--safe-b)); }
.kb-dock { padding-bottom: var(--safe-b); }

@media (max-width: 639.98px) {
    /* Una selezione di venti documenti ha sei comandi: in una riga sola non
       stanno, e la barra non deve diventare una pagina. Scorre. */
    .kb-selbar {
        width: auto;
        max-width: calc(100% - 1rem);
        margin: 0 0.5rem;
    }
    .kb-selbar > div { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
    .kb-selbar > div::-webkit-scrollbar { display: none; }
    .kb-selbar > div > * { flex: 0 0 auto; }

    /* La coda di ingest: la lista resta consultabile senza coprire l'elenco. */
    .kb-dock .kb-dock-list { max-height: 40dvh; }
}

/* --- Finestre modali: a tutto vetro, non una cartolina in mezzo -------- */
@media (max-width: 639.98px) {
    .kb-modal { padding: 0; align-items: flex-end; }

    .kb-modal-card {
        margin: 0;
        max-width: none;
        max-height: calc(var(--app-h, 100dvh) - var(--safe-t) - 1.5rem);
        overflow-y: auto;
        border-radius: 18px 18px 0 0;
        border-width: 1px 0 0;
        padding-bottom: calc(1.5rem + var(--safe-b));
    }
}

/* --- Compositore della chat -------------------------------------------- */
.kb-composer { padding-bottom: calc(0.75rem + var(--safe-b)); }
/* Con la tastiera aperta la barra di casa è coperta: quello spazio non serve, e la
   casella di scrittura si accorcia perché la conversazione resti visibile. */
.kbd-open .kb-composer { padding-bottom: 0.6rem; }
.kbd-open .kb-composer textarea { max-height: 5rem; }

@media (min-width: 640px) {
    .kb-composer { padding-bottom: calc(1rem + var(--safe-b)); }
}

/* L'ambito su una riga sola che scorre: tre righe di gettoni sopra la tastiera
   lascerebbero due righe di conversazione. */
@media (max-width: 639.98px) {
    /* Due classi: le utility di Tailwind (`flex-wrap`) arrivano dopo questo foglio. */
    .kb-composer .kb-scope-row,
    .kb-composer .kb-scope-row nav {
        flex-wrap: nowrap;
    }

    .kb-composer .kb-scope-row {
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: none;
    }
    .kb-scope-row::-webkit-scrollbar { display: none; }
    .kb-scope-row > * { flex: 0 0 auto; }
    /* Il selettore resta l'ultimo del binario, non "a destra" (il pannello che apre è
       `position: fixed`: lo scorrimento non lo taglia). */
    .kb-composer .kb-scope-row > .kb-menu { margin-left: 0.25rem; }

    /* Una riga da 16px più il respiro: il segnaposto qui è corto (l'ambito per
       esteso sta scritto sopra), e la casella cresce da sola mentre si scrive. */
    .kb-composer textarea { min-height: 2.75rem; }
}

/* Mentre si scrive, la testata della chat lascia il posto alla conversazione: con
   la tastiera aperta restano 300px di vetro, e 146px di titolo sono metà risposta. */
@media (max-width: 1023.98px) {
    .kbd-open .kb-chat-head { display: none; }
}

/* --- Vetro basso: telefono in orizzontale ------------------------------
   In orizzontale un telefono è larghissimo e alto 390px: la larghezza dice
   «mostra tutto», l'altezza dice il contrario. Titolo della pagina e peso del
   corpus non valgono quattro righe di conversazione o di elenco. Due classi,
   perché la soglia `sm:` di Tailwind arriva dopo questo foglio. */
@media (max-height: 560px) and (max-width: 1023.98px) {
    .kb-page .kb-page-title,
    .kb-page .kb-page-facts { display: none; }
}

/* --- Cronologia delle conversazioni: cassetto sotto i 1024px ----------- */
@media (max-width: 1023.98px) {
    .kb-sessions {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 50;
        width: min(19rem, 86vw) !important;
        max-height: var(--app-h, none);
        padding-top: var(--safe-t);
        padding-bottom: var(--safe-b);
        box-shadow: 24px 0 60px -32px rgba(15, 23, 42, 0.55);
    }

    .kb-sessions-scrim {
        position: fixed;
        inset: 0;
        z-index: 46;
        background: rgba(15, 23, 42, 0.4);
    }

    /* In un cassetto ogni riga è un bersaglio. */
    .kb-sessions button { min-height: var(--tap); }
}

/* --- Prosa e tabelle nelle risposte ------------------------------------ */
@media (max-width: 639.98px) {
    .kb-prose { font-size: 0.9375rem; }
    /* Un blocco di codice non allarga la pagina: scorre dentro il suo riquadro. */
    .kb-prose pre { font-size: 0.78rem; }
    .kb-tag { max-width: 11rem; }
}

/* --- Barra di scorrimento: su tocco è sovrapposta, non serve spazio ---- */
@media (max-width: 1023.98px) {
    ::-webkit-scrollbar { width: 6px; height: 6px; }
}
