/*
 * This is free software — do whatever you want with it.
 * Developed by Franck LEFEVRE for K1 (https://k1info.com),
 * aided by his team of kind and fun robots.
 *
 * Please use the enormous power of this software to do good things
 * for things and people, always making sure it harms nothing and no one.
 */

/**
 * Inlux Web — Base layout and structural styles.
 * Color variables are defined in each theme's theme.css.
 *
 * 2026-04-02 — Refactored: extracted color variables to per-theme CSS files.
 *   Layout, spacing, and structural rules remain here.
 */

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

body {
    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
                 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
    background: var(--bg);
    color: var(--text);
    height: 100vh;
    overflow: hidden;
}

/* --- Screens --- */
.screen { display: flex; flex-direction: column; height: 100vh; position: relative; }
.screen[hidden] { display: none; }

/* --- Login --- */
#login-screen { justify-content: center; align-items: center; }

.login-box {
    background: var(--surface);
    padding: 2rem;
    border-radius: var(--radius);
    width: 340px;
    text-align: center;
}
.login-box .login-logo {
    display: block; margin: 0 auto 1rem; height: 40px; width: auto;
    filter: var(--logo-filter);
}
.login-box h1 { margin-bottom: 0.25rem; color: var(--login-title-color); }
.login-box .subtitle { color: var(--login-subtitle-color); margin-bottom: 1.5rem; font-size: 0.9rem; }
.login-box input {
    display: block; width: 100%; padding: 0.6rem; margin-bottom: 0.75rem;
    border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--input-bg); color: var(--text); font-size: 1rem;
}
.login-box button {
    width: 100%; padding: 0.6rem; border: none; border-radius: var(--radius);
    background: var(--accent); color: var(--btn-text); font-size: 1rem; cursor: pointer;
    transition: background 0.2s, opacity 0.2s;
}
.login-box button:hover { opacity: 0.9; }
.error { color: var(--accent); margin-top: 0.5rem; font-size: 0.85rem; }
/* 2026-04-16 — Discrete version footer on the login box (backend + frontend). */
.login-versions {
    margin-top: 1.25rem;
    color: var(--login-subtitle-color);
    font-size: 0.75rem;
    opacity: 0.7;
    letter-spacing: 0.02em;
}
.login-versions-sep { margin: 0 0.4rem; }

/* --- Chat header --- */
header {
    display: flex; align-items: center; gap: 1rem;
    padding: 0.75rem 1rem; background: var(--header-bg);
    border-bottom: 1px solid var(--border-color);
}
header .header-logo { height: 28px; width: auto; filter: var(--logo-filter); }
.header-user { font-size: 0.75rem; color: var(--text-muted); margin-left: 0.4rem; }
header h1 { font-size: 1.1rem; flex: 1; }
header #user-name { color: var(--text-muted); font-size: 0.85rem; }
header button {
    padding: 0.3rem 0.8rem; border: 1px solid var(--border-color); border-radius: var(--radius);
    background: transparent; color: var(--text-muted); cursor: pointer; font-size: 0.8rem;
    transition: background 0.2s, color 0.2s;
}

/* 2026-04-07 — Chat layout: sidebar + main area */
#chat-screen { flex-direction: row; }
#fab-sidebar {
    width: 220px; min-width: 220px; background: var(--surface);
    border-right: 1px solid var(--border-color);
    display: flex; flex-direction: column; overflow: hidden;
    transition: width 0.2s, min-width 0.2s;
}
#fab-sidebar.collapsed { width: 0; min-width: 0; border-right: none; }
#sidebar-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border-color);
}
#sidebar-header .header-logo { height: 24px; }
.sidebar-toggle-btn {
    background: none; border: none; color: var(--text-muted); cursor: pointer;
    padding: 0.2rem; border-radius: var(--radius);
}
.sidebar-toggle-btn:hover { color: var(--text); }
#fab-list { flex: 1; overflow-y: auto; padding: 0.3rem 0; }
.fab-list-item {
    padding: 0.5rem 0.8rem; cursor: pointer; font-size: 0.88rem;
    border-left: 3px solid transparent; transition: all 0.15s;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fab-list-item:hover { background: var(--bg); }
.fab-list-item.active {
    background: var(--bg); border-left-color: var(--accent); font-weight: 600;
}

#chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; position: relative; }
#chat-main > header { flex-shrink: 0; }

.current-fab-name { font-weight: 600; font-size: 0.95rem; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Burger menu button */
.burger-btn {
    background: none; border: 1px solid var(--border-color); border-radius: var(--radius);
    color: var(--text-muted); cursor: pointer; padding: 0.3rem 0.5rem;
    transition: background 0.2s;
}
.burger-btn:hover { background: var(--accent); color: var(--btn-text); }

/* Burger dropdown menu */
.burger-menu {
    position: absolute; top: 44px; right: 0.5rem; z-index: 200;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); box-shadow: 0 4px 16px rgba(0,0,0,0.3);
    min-width: 200px; padding: 0.3rem 0;
}
.burger-menu[hidden] { display: none; }
.burger-section { padding: 0.4rem 0.8rem; }
.burger-user { font-size: 0.85rem; color: var(--text-muted); }
.burger-divider { height: 1px; background: var(--border-color); margin: 0.2rem 0; }
.burger-item {
    display: flex; align-items: center; gap: 0.5rem; width: 100%;
    padding: 0.45rem 0.8rem; border: none; background: none;
    color: var(--text); cursor: pointer; font-size: 0.88rem;
    text-align: left; transition: background 0.15s;
}
.burger-item:hover { background: var(--accent); color: var(--btn-text); }
.burger-item[hidden] { display: none; }
.burger-item svg { flex-shrink: 0; }
.burger-item-danger { color: #dc3545; }
.burger-item-danger:hover { background: #dc3545; color: #fff; }

/* Responsive: collapse sidebar on small screens */
@media (max-width: 768px) {
    #fab-sidebar { position: absolute; z-index: 50; height: 100%; }
    #fab-sidebar.collapsed { width: 0; min-width: 0; }
}

/* --- Chat content wrapper — centered responsive column --- */
/* 2026-04-02 — Messages and input centered with max-width for readability
   on wide screens; fills available width on narrow viewports. */
#messages {
    flex: 1; overflow-y: auto; padding: 1rem;
    display: flex; flex-direction: column; align-items: center;
}

#messages-inner {
    width: 100%; max-width: 800px;
}

.message { margin-bottom: 1rem; max-width: 80%; line-height: 1.5; }

.message.user {
    margin-left: auto; background: var(--primary);
    padding: 0.6rem 1rem; border-radius: var(--radius) var(--radius) 4px var(--radius);
    white-space: pre-wrap; color: var(--btn-text);
}

.message.assistant {
    background: var(--surface); padding: 0.6rem 1rem;
    border-radius: var(--radius) var(--radius) var(--radius) 4px;
}

/* 2026-04-14 — Timestamp on every message */
.message-time {
    display: block; font-size: 0.65rem; color: var(--text-muted);
    opacity: 0.6; margin-bottom: 0.15rem;
}
.message.tool .message-time { display: inline; margin-right: 0.4rem; margin-bottom: 0; }
.message-body { display: block; }

.message.tool {
    font-size: 0.8rem; color: var(--text-muted); background: transparent;
    border-left: 2px solid var(--accent); padding-left: 0.5rem; max-width: 90%;
}

/* 2026-05-06 (v1.2.19) — Platform notice banner. Used by the upload
 * route when the LLM is unavailable but the files were stored
 * successfully, and by the WebSocket error path on transient LLM
 * failures (overloaded, rate_limit, timeout). Visually distinct from
 * a FAB reply (no avatar bubble, yellow accent) so the user
 * understands this is a platform message, not the FAB speaking. */
/* 2026-08-19 (v1.2.170) — Bandeau de liaison coupee.
 * Meme parti pris chromatique que `.platform-notice` : un accent ambre pose
 * en rgba par-dessus `var(--surface)`, JAMAIS une couleur de fond en dur —
 * plusieurs themes de cette interface sont CLAIRS, et un fond sombre code en
 * dur y rendrait le texte illisible.
 * Ancre en bas d'ecran plutot qu'en haut : le regard est sur la zone de
 * saisie, qui vient de griser sans explication. */
#bandeau-reseau {
    position: fixed; left: 50%; transform: translateX(-50%);
    bottom: 1.25rem; z-index: 1000;
    max-width: min(560px, calc(100vw - 2rem));
    padding: 0.7rem 0.95rem;
    border-radius: var(--radius);
    border: 1px solid rgba(180, 83, 9, 0.35);
    border-left: 4px solid #b45309;
    background: var(--surface); color: var(--text);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    font-size: 0.88rem; line-height: 1.45;
}
#bandeau-reseau > div + div {
    margin-top: 0.4rem; color: var(--text-muted);
}
#bandeau-reseau[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
    #bandeau-reseau { animation: bandeau-reseau-entree 0.18s ease-out; }
}
@keyframes bandeau-reseau-entree {
    from { opacity: 0; transform: translate(-50%, 6px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

.message.platform-notice {
    max-width: 95%; padding: 0.7rem 0.9rem;
    border-radius: var(--radius); border-left: 4px solid #b45309;
    background: rgba(180, 83, 9, 0.08); color: var(--text);
    font-size: 0.9rem;
}
.message.platform-notice--warning { border-left-color: #b45309; }

/* 2026-08-24 (v1.2.172) — Reglages a valeurs multiples (chaine de secours LLM).
   Remplace un <select multiple>, qui ne montrait ni ce qui etait choisi ni dans
   quel ORDRE, et qui exigeait Ctrl+clic sans le dire. */
.iset-choices {
    display: flex; flex-direction: column; gap: 0.3rem;
    padding: 0.4rem 0.5rem; margin-bottom: 0.75rem;
    border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--input-bg);
}
.iset-choice {
    display: flex; align-items: center; gap: 0.45rem;
    font-size: 0.9rem; cursor: pointer;
}
.iset-choice input { cursor: pointer; }
/* Le rang rend la cascade LISIBLE : 1 est essaye avant 2. Sans lui, une liste
   de cases cochees ne dit pas dans quel ordre elles seront tentees. */
.iset-rank {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.25rem; height: 1.25rem; padding: 0 0.25rem;
    border-radius: 999px; background: var(--accent, #2563eb); color: #fff;
    font-size: 0.72rem; font-weight: 600;
}
.platform-notice-header {
    display: flex; align-items: center; gap: 0.4rem;
    font-weight: 600; margin-bottom: 0.35rem; color: #92400e;
}
.platform-notice-body { line-height: 1.45; }
.platform-notice-files {
    margin-top: 0.55rem; padding-top: 0.4rem;
    border-top: 1px dashed rgba(180, 83, 9, 0.3);
    font-size: 0.83rem; color: var(--text-muted);
}
.platform-notice-files em { color: var(--text); }

/* --- Markdown content in assistant messages --- */
.message.assistant p { margin: 0.4em 0; }
.message.assistant ul, .message.assistant ol { margin: 0.4em 0 0.4em 1.5em; }
.message.assistant li { margin: 0.2em 0; }
.message.assistant h1, .message.assistant h2, .message.assistant h3 {
    margin: 0.8em 0 0.3em; font-weight: 600;
}
.message.assistant h1 { font-size: 1.3em; }
.message.assistant h2 { font-size: 1.15em; }
.message.assistant h3 { font-size: 1.05em; }

.message.assistant strong { font-weight: 600; }
.message.assistant em { font-style: italic; }

.message.assistant code {
    background: var(--code-bg); padding: 0.15em 0.35em; border-radius: 4px;
    font-family: 'Fira Code', 'Consolas', monospace; font-size: 0.9em;
}
.message.assistant pre {
    background: var(--code-bg); padding: 0.8em; border-radius: var(--radius);
    overflow-x: auto; margin: 0.5em 0;
}
.message.assistant pre code {
    background: none; padding: 0; font-size: 0.85em; line-height: 1.4;
}

.message.assistant table {
    border-collapse: collapse; margin: 0.5em 0; font-size: 0.9em; width: 100%;
}
.message.assistant th, .message.assistant td {
    border: 1px solid var(--border-color); padding: 0.4em 0.6em; text-align: left;
}
.message.assistant th { background: var(--primary); font-weight: 600; color: var(--btn-text); }

.message.assistant blockquote {
    border-left: 3px solid var(--accent); padding-left: 0.8em;
    color: var(--text-muted); margin: 0.5em 0;
}

.message.assistant a { color: var(--link-color); text-decoration: none; }
.message.assistant a:hover { text-decoration: underline; }

/* --- File download cards --- */
.file-card {
    display: inline-flex; align-items: center; gap: 0.5rem;
    background: var(--surface); border: 1px solid var(--border-color); border-radius: var(--radius);
    padding: 0.5rem 0.8rem; margin: 0.3rem 0; cursor: pointer;
    text-decoration: none; color: var(--text); font-size: 0.85rem;
    transition: background 0.2s;
}
.file-card:hover { background: var(--file-card-hover); }
.file-card svg { flex-shrink: 0; }
.file-card .file-name { font-weight: 500; }
.file-card .file-type { color: var(--text-muted); font-size: 0.75rem; }

/* --- File upload preview --- */
#file-preview {
    display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0.4rem;
    border-bottom: 1px solid var(--border-color);
}
#file-preview .file-chip {
    display: flex; align-items: center; gap: 0.3rem;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: 12px; padding: 0.2rem 0.6rem; font-size: 0.8rem;
}
#file-preview .file-chip button {
    background: none; border: none; color: var(--text-muted); cursor: pointer;
    font-size: 1rem; line-height: 1; padding: 0 0.2rem;
}

/* --- Input area — centered to match message column --- */
#input-area {
    display: flex; justify-content: center;
    padding: 0.75rem 1rem; background: var(--header-bg); border-top: 1px solid var(--border-color);
}

#input-area-inner {
    display: flex; align-items: flex-end; gap: 0.5rem;
    width: 100%; max-width: 800px;
}

#attach-btn {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; cursor: pointer; color: var(--text-muted);
    border-radius: var(--radius); transition: color 0.2s;
}
#attach-btn:hover { color: var(--text); }

#input-wrapper { flex: 1; display: flex; flex-direction: column; }

#message-input {
    width: 100%; padding: 0.6rem; border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--input-bg); color: var(--text); font-size: 1rem;
    resize: none; font-family: inherit;
    /* 2026-06-30 (v1.2.78) — Deterministic line-height so the JS auto-grow
       caps at exactly 20 lines; scroll once past the cap. */
    line-height: 1.4; overflow-y: auto;
    transition: border-color 0.2s;
}

#send-btn {
    padding: 0.6rem 1.2rem; border: none; border-radius: var(--radius);
    background: var(--accent); color: var(--btn-text); cursor: pointer; font-size: 1rem;
    height: 36px; transition: background 0.2s, opacity 0.2s;
}
#send-btn:hover { opacity: 0.9; }
#send-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* 2026-08-08 (v1.2.149) — Stop. Outlined rather than filled: it is not the
   primary action, and a solid red button next to Send invites the wrong click.
   Uses theme variables only — several themes are LIGHT, so a hardcoded dark
   fallback would be unreadable on them. */
#stop-btn {
    padding: 0.6rem 1rem; border: 1px solid var(--border-color);
    border-radius: var(--radius); background: transparent;
    color: var(--text-muted); cursor: pointer; font-size: 0.9rem;
    height: 36px; transition: color 0.2s, border-color 0.2s, opacity 0.2s;
}
#stop-btn:hover { color: var(--text); border-color: var(--accent); }
/* Disabled = "Stopping…" is already in flight. It stays VISIBLE (the turn is
   still running until a safe boundary) but inert, so a second click cannot
   read as "it didn't work, click harder". */
#stop-btn:disabled { opacity: 0.55; cursor: default; }
#stop-btn[hidden] { display: none; }

/* A conversation with a turn in flight — including the ones not on screen.
   Inline after the label, NOT pushed right with `margin-left: auto`: the row is
   a block with nowrap + text-overflow ellipsis, not a flex container, and
   turning it into one would break both the ellipsis and the collapsed avatar
   rail. Inline-block also means it simply follows the avatar when the label is
   hidden in studio mode. */
.fab-busy-dot { display: none; }
.fab-list-item.busy .fab-busy-dot {
    display: inline-block; width: 6px; height: 6px; border-radius: 50%;
    background: var(--accent); margin-left: 0.4rem;
    vertical-align: middle;
    animation: activity-pulse 1.6s ease-in-out infinite;
}

/* --- Message footer (model + token usage) --- */
/* 2026-04-03 — Shown under assistant messages after completion */
.message-footer {
    font-size: 0.7rem; color: var(--text-muted); margin-top: 0.5rem;
    padding-top: 0.4rem; border-top: 1px solid var(--border-color);
    opacity: 0.7; font-style: italic;
}

/* --- Marque de repli de modele (v1.2.175) --- */
/* Posee sur le MESSAGE, pas sur la session : c'est le message qu'on relit et
   qu'on juge. Discrete par construction — elle doit se voir quand on cherche
   pourquoi une reponse detonne, sans crier a chaque tour d'une panne longue.
   `var(--warning, #b45309)` avec son repli LITTERAL : `--warning` n'est declaree
   dans aucun theme — les deux seuls autres usages du depot portent deja ce
   repli, et une variable nue n'aurait simplement rien rendu. Copier la forme en
   place plutot que le nom qui semble juste. */
.message.message--fallback {
    border-left: 3px solid var(--warning, #b45309);
}
.fallback-badge {
    font-size: 0.7rem; color: var(--warning, #b45309);
    margin-top: 0.4rem; opacity: 0.9; cursor: help;
}

/* --- Model indicator/selector in header --- */
.model-indicator {
    font-size: 0.75rem; color: var(--text-muted);
    background: var(--surface); padding: 0.15rem 0.5rem;
    border-radius: 10px; border: 1px solid var(--border-color);
}
.model-selector {
    font-size: 0.75rem; color: var(--text);
    background: var(--surface); padding: 0.2rem 0.4rem;
    border-radius: 10px; border: 1px solid var(--border-color);
    cursor: pointer; max-width: 260px;
}
.model-selector[hidden] { display: none; }

/* --- Show tools toggle --- */
/* 2026-04-14 — Checkbox to show/hide tool call messages in chat */
.show-tools-label {
    display: inline-flex; align-items: center; gap: 0.3rem;
    font-size: 0.75rem; color: var(--text-muted); cursor: pointer;
    margin-right: 0.3rem;
}
/* 2026-04-21 (v1.2.6) — Make the [hidden] attribute actually hide the
   label. The `.show-tools-label` rule above sets `display:inline-flex`,
   which wins over the UA stylesheet's `[hidden] { display:none }` at
   equal specificity (author beats UA). Without this explicit override,
   setting `hidden=true` from JS had no visual effect — the toggle
   stayed visible for user-only roles despite v1.2.5. */
.show-tools-label[hidden] { display: none; }
.show-tools-label input[type="checkbox"] {
    display: inline-block; width: auto; margin: 0; cursor: pointer;
}
.hide-tools .message.tool { display: none; }

/* --- Clear button --- */
.clear-btn {
    font-size: 0.8rem; padding: 0.25rem 0.6rem;
    background: transparent; border: 1px solid var(--border-color);
    color: var(--text-muted); cursor: pointer; border-radius: var(--radius);
}
.clear-btn:hover { background: var(--accent); color: var(--btn-text); border-color: var(--accent); }

/* --- Scroll to bottom button --- */
.scroll-bottom-btn {
    position: absolute; bottom: 80px; right: 2rem; z-index: 10;
    width: 36px; height: 36px; border-radius: 50%;
    background: var(--accent); color: var(--btn-text);
    border: none; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
    opacity: 0.85; transition: opacity 0.2s;
}
.scroll-bottom-btn:hover { opacity: 1; }
.scroll-bottom-btn[hidden] { display: none; }

/* 2026-04-17 — History navigation: search panel + date banner + load-more */
.history-date-input { display: none; }
.history-date-banner {
    flex-shrink: 0; display: flex; align-items: center; gap: 0.75rem;
    padding: 0.4rem 1rem;
    /* v1.2.159 — voile translucide : `--hover-bg` n'est defini par aucun
       theme, le repli clair opaque effacait le texte en theme sombre. */
    background: var(--hover-bg, rgba(128, 128, 128, 0.10));
    border-bottom: 1px solid var(--border-color);
    font-size: 0.85rem; color: var(--text-muted);
}
.history-date-banner[hidden] { display: none; }
.return-present-btn {
    font-size: 0.78rem; padding: 0.2rem 0.55rem;
    background: var(--accent); color: var(--btn-text);
    border: none; border-radius: var(--radius); cursor: pointer;
}
.return-present-btn:hover { filter: brightness(1.1); }

.load-more-btn {
    display: block; margin: 0 auto 1rem;
    padding: 0.35rem 1rem; font-size: 0.8rem;
    background: transparent; color: var(--text-muted);
    border: 1px dashed var(--border-color); border-radius: var(--radius);
    cursor: pointer;
}
.load-more-btn:hover { background: var(--hover-bg, rgba(128, 128, 128, 0.10)); color: var(--text); }
.load-more-btn[disabled] { opacity: 0.6; cursor: wait; }

.history-search-panel {
    /* 2026-04-17 (v2.8.9) — Sit below the chat header instead of over it.
       The header is ~53px (0.75rem × 2 padding + ~28px logo + 1px border);
       3.5rem gives a safe margin and matches what the user sees visually. */
    position: absolute; top: 3.5rem; right: 0; bottom: 0;
    width: 340px; max-width: 85vw;
    background: var(--bg); border-left: 1px solid var(--border-color);
    display: flex; flex-direction: column;
    box-shadow: -4px 0 10px rgba(0,0,0,0.08); z-index: 20;
}
.history-search-panel[hidden] { display: none; }
.history-search-header {
    flex-shrink: 0; display: flex; gap: 0.5rem; align-items: center;
    padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border-color);
}
#history-search-input {
    flex: 1; padding: 0.4rem 0.6rem; font-size: 0.9rem;
    border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--bg); color: var(--text);
}
.history-search-close {
    background: transparent; border: none; font-size: 1.4rem; line-height: 1;
    cursor: pointer; color: var(--text-muted); padding: 0 0.3rem;
}
.history-search-close:hover { color: var(--text); }
.history-search-status {
    flex-shrink: 0; padding: 0.4rem 0.8rem;
    font-size: 0.78rem; color: var(--text-muted);
    border-bottom: 1px solid var(--border-color);
}
.history-search-status:empty { display: none; }
.history-search-results { flex: 1; overflow-y: auto; }
.history-search-result {
    padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border-color);
    cursor: pointer; font-size: 0.83rem;
}
.history-search-result:hover { background: var(--hover-bg, rgba(128, 128, 128, 0.10)); }
.history-search-result .hs-meta {
    font-size: 0.72rem; color: var(--text-muted); margin-bottom: 0.2rem;
    display: flex; justify-content: space-between;
}
.history-search-result .hs-snippet {
    color: var(--text); line-height: 1.35;
    overflow: hidden; text-overflow: ellipsis;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}
.history-search-result .hs-snippet mark {
    background: var(--accent); color: var(--btn-text);
    padding: 0 2px; border-radius: 2px;
}
.history-search-highlight { animation: hsFlash 2s ease-out; }
@keyframes hsFlash {
    0% { background: rgba(255, 200, 0, 0.5); }
    100% { background: transparent; }
}

/* --- File notification card (in chat) --- */
.file-notification-card {
    display: inline-flex; align-items: center; gap: 0.6rem;
    background: var(--surface); border: 1px solid var(--accent);
    border-radius: var(--radius); padding: 0.6rem 1rem;
    margin: 0.5rem 0; cursor: pointer; transition: background 0.2s;
    max-width: 80%;
}
.file-notification-card:hover { background: var(--primary); }
.file-notification-card:hover .file-notification-meta { color: var(--btn-text); opacity: 0.8; }
.file-notification-icon { font-size: 1.4rem; }
.file-notification-name { font-weight: 600; font-size: 0.9rem; }
.file-notification-meta { font-size: 0.75rem; color: var(--text-muted); }

/* --- Typing indicator (deprecated — replaced by activity-indicator) --- */
.typing-indicator { color: var(--text-muted); font-style: italic; font-size: 0.85rem; }

/* ==========================================================================
   2026-04-03 — Init phase messages and activity indicator
   ========================================================================== */

/* --- Init messages in chat --- */
.message.init {
    font-size: 0.85rem; color: var(--text-muted);
    padding: 0.4rem 0.8rem; max-width: 90%;
    background: transparent; border-left: 2px solid var(--accent);
}

.init-indicator {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent); margin-right: 0.3rem; vertical-align: middle;
    animation: init-pulse 1s ease-in-out infinite;
}

.init-done {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    background: #28a745; margin-right: 0.3rem; vertical-align: middle;
}

@keyframes init-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

/* --- Activity indicator (pulsing dot next to send button) --- */
.activity-indicator {
    display: inline-block; width: 10px; height: 10px; border-radius: 50%;
    background: var(--accent); margin-left: 0.3rem; flex-shrink: 0;
    animation: activity-pulse 1.2s ease-in-out infinite;
    align-self: center;
}

.activity-indicator.stale {
    animation: activity-pulse 2.5s ease-in-out infinite;
    opacity: 0.4;
}

.activity-indicator[hidden] { display: none; }

@keyframes activity-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.3; transform: scale(0.7); }
}

/* --- Disabled input state --- */
#message-input:disabled {
    opacity: 0.5; cursor: not-allowed;
}

/* ==========================================================================
   2026-04-03 — Profile, Admin, and Form styles for user CRUD screens
   ========================================================================== */

/* --- Form container (centered column) --- */
.form-container {
    flex: 1; overflow-y: auto; padding: 1.5rem;
    display: flex; flex-direction: column; align-items: center;
}

.form-card {
    background: var(--surface); border-radius: var(--radius);
    padding: 1.5rem 2rem; width: 100%; max-width: 600px;
}

.form-card.admin-card { max-width: 800px; }

/* 2026-04-17 (v2.8.23) — Interlocutor edit card at 50% width. The fields
   are short (email, display_name, roles, LLM grants) — full-width is
   wasteful, 50% stays comfortable to read on any screen. */
.form-card.interlocutor-card {
    width: 50%;
    min-width: 520px;
    max-width: 1100px;
}

/* 2026-04-17 (v2.8.9) — FAB edit card: wide layout like Browse Files.
   80% of viewport, centered, capped on huge screens so the labels stay
   within a comfortable reading distance of the inputs on the right.
   2026-04-17 (v2.8.11) — Extra padding + vertical rhythm so labels breathe
     from the edges and h3 sections don't feel stacked on top of each other. */
.form-card.fab-card {
    width: 80%;
    max-width: 1600px;
    padding: 2rem 2.5rem 2.25rem;
}
.form-card.fab-card h3 {
    margin: 2rem 0 0.75rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--border-color);
}
.form-card.fab-card h3:first-of-type {
    border-top: none;
    padding-top: 0;
    margin-top: 1.5rem;
}
.form-card.fab-card label {
    margin-top: 0.85rem;
    margin-bottom: 0.3rem;
}
.form-card.fab-card > form > label:first-of-type { margin-top: 0; }
.form-card.fab-card input,
.form-card.fab-card textarea,
.form-card.fab-card select {
    margin-bottom: 0.25rem;  /* label margin-top provides the main gap */
}
.form-card.fab-card .form-hint { margin-bottom: 0.5rem; }
.form-card.fab-card .form-actions { margin-top: 1.75rem; }

.form-card h2 { margin-bottom: 1rem; font-size: 1.2rem; }
.form-card h3 { margin: 1.2rem 0 0.5rem; font-size: 1rem; color: var(--text-muted); }

.form-card label {
    display: block; margin-bottom: 0.25rem; font-size: 0.85rem;
    color: var(--text-muted); font-weight: 500;
}

.form-card input,
.form-card textarea,
.form-card select {
    display: block; width: 100%; padding: 0.5rem; margin-bottom: 0.75rem;
    border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--input-bg); color: var(--text); font-size: 0.9rem;
    font-family: inherit;
}

.form-card input:disabled {
    opacity: 0.6; cursor: not-allowed;
}

.form-card textarea { resize: vertical; }

.form-actions {
    display: flex; gap: 0.75rem; margin-top: 1rem;
    justify-content: flex-start;
}

.btn-primary {
    padding: 0.5rem 1.2rem; border: none; border-radius: var(--radius);
    background: var(--accent); color: var(--btn-text); cursor: pointer;
    font-size: 0.9rem; transition: opacity 0.2s;
}
.btn-primary:hover { opacity: 0.9; }

/* 2026-04-07 — Secondary button (outline style, used for Cancel/Back/Export) */
.btn-secondary {
    padding: 0.5rem 1.2rem; border: 1px solid var(--border-color); border-radius: var(--radius);
    background: transparent; color: var(--text); cursor: pointer;
    font-size: 0.9rem; transition: all 0.2s;
}
.btn-secondary:hover { background: var(--accent); color: var(--btn-text); border-color: var(--accent); }

.btn-danger {
    padding: 0.5rem 1.2rem; border: none; border-radius: var(--radius);
    background: #dc3545; color: #fff; cursor: pointer;
    font-size: 0.9rem; transition: opacity 0.2s;
}
.btn-danger:hover { opacity: 0.9; }

.form-message {
    margin-top: 0.75rem; font-size: 0.85rem; padding: 0.4rem 0.8rem;
    border-radius: var(--radius);
}
.form-message.success { color: #28a745; }
.form-message.error { color: var(--accent); }

.profile-usage {
    display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.75rem;
}
.profile-usage-stat {
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); padding: 0.5rem 0.8rem; text-align: center;
}
.profile-usage-stat .stat-value { font-size: 1.2rem; font-weight: 700; }
.profile-usage-stat .stat-label { font-size: 0.7rem; color: var(--text-muted); }

/* --- Admin toolbar --- */
.admin-toolbar {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 1rem;
}
.admin-toolbar h2 { margin-bottom: 0; }

/* --- Shared proposals --- */
.proposal-card {
    background: var(--surface); border: 1px solid var(--accent);
    border-radius: var(--radius); padding: 0.75rem; margin-bottom: 0.5rem;
}
.proposal-header {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 0.4rem;
}
.proposal-author { font-weight: 600; font-size: 0.85rem; }
.proposal-date { font-size: 0.75rem; color: var(--text-muted); }
.proposal-content {
    font-size: 0.83rem; white-space: pre-wrap; max-height: 120px;
    overflow-y: auto; margin-bottom: 0.5rem; line-height: 1.4;
}
.proposal-actions { display: flex; gap: 0.4rem; }

/* --- FAB edit permissions grid --- */
/* 2026-04-07 — Permissions/roles grid: label left, checkbox right, aligned */
.ae-perms-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 0.15rem 1rem; margin-bottom: 0.75rem;
}
.ae-perm-item {
    display: flex; align-items: center; justify-content: space-between;
    font-size: 0.85rem; padding: 0.25rem 0.4rem;
    border-bottom: 1px solid var(--border-color);
}
.ae-perm-item:last-child { border-bottom: none; }
.ae-perm-item label { cursor: pointer; flex: 1; order: -1; }
.ae-perm-item input { cursor: pointer; width: auto; height: auto; margin: 0; flex-shrink: 0; }

/* 2026-05-07 (v1.2.20) — Per-FAB Knowledge Base section in the
 * admin FAB edit page. Categories listed as collapsible groups,
 * files as cards with title / summary / keyword chips. */
.kb-category {
    margin-top: 0.5rem;
    padding: 0.4rem 0.6rem;
    background: var(--surface);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
}
.kb-category-name {
    margin: 0 0 0.3rem 0;
    font-size: 0.95rem;
    color: var(--text-muted);
    font-family: monospace;
}
.kb-file-list { list-style: none; padding: 0; margin: 0; }
.kb-file {
    padding: 0.4rem 0.5rem;
    margin: 0.25rem 0;
    background: var(--bg);
    border-radius: var(--radius);
    border: 1px solid var(--border-color);
}
.kb-file-row {
    display: flex; align-items: center; gap: 0.5rem;
    flex-wrap: wrap;
}
.kb-file-name {
    font-family: monospace; font-size: 0.78rem;
    color: var(--text-muted);
}
.kb-file-edited {
    font-size: 0.85rem; color: var(--accent);
}
.kb-file-summary {
    margin-top: 0.2rem;
    font-size: 0.82rem;
    color: var(--text);
    line-height: 1.4;
}
.kb-file-keywords {
    margin-top: 0.25rem;
    display: flex; gap: 0.25rem; flex-wrap: wrap;
}
.kb-kw {
    font-size: 0.72rem;
    padding: 0.05rem 0.35rem;
    background: var(--surface);
    border-radius: 0.25rem;
    color: var(--text-muted);
}
.kb-file-actions {
    margin-top: 0.35rem;
    display: flex; gap: 0.3rem;
}

/* 2026-05-07 (v1.2.22) — Knowledge Base list scrollable. The list
 * can grow tall once a FAB has dozens of reference files; cap its
 * height so the upload zone and the rest of the form stay reachable
 * without endless page-scroll. The internal scroller appears on
 * overflow only. */
#ae-knowledge {
    max-height: 420px;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    padding: 0.4rem;
    background: var(--bg);
}
#ae-knowledge:empty { display: none; }

/* 2026-05-07 (v1.2.22) — Tabbed layout for the FAB edit form. The
 * form had grown to ~270 lines of stacked sections; tabs group them
 * by usage frequency. Visual style mirrors Inlux's Management tabs
 * for consistency: pill buttons, accent border on active. */
.fab-tabs-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-bottom: 1rem;
    border-bottom: 2px solid var(--border-color);
    padding-bottom: 0;
}
.fab-tab {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    color: var(--text-muted);
    padding: 0.5rem 0.85rem;
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    border-radius: var(--radius) var(--radius) 0 0;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.fab-tab:hover {
    color: var(--text);
    background: var(--surface);
}
.fab-tab.active {
    color: var(--text);
    border-bottom-color: var(--accent);
    background: var(--surface);
}
.fab-tab-content {
    /* Each tab has its own area; non-active tabs are hidden via the
     * hidden attribute. Padding keeps section spacing comfortable. */
    padding-top: 0.25rem;
}

/* 2026-04-06 — Profile fields and data permissions rows */
.profile-field-row {
    display: flex; align-items: center; gap: 0.4rem;
    padding: 0.25rem 0; font-size: 0.88rem;
}
.profile-field-key {
    min-width: 120px; font-weight: 600; color: var(--text-muted);
}
.profile-field-value { flex: 1; }
.profile-add-field {
    display: flex; gap: 0.3rem; margin-top: 0.3rem;
}
.profile-add-field input { flex: 1; }
.btn-small {
    padding: 0.15rem 0.5rem; font-size: 0.8rem; min-width: auto;
}
.form-hint {
    font-size: 0.82rem; color: var(--text-muted); margin: 0.2rem 0 0.5rem;
}

/* 2026-04-10 — Data sharing: FAB selector tabs + permission table */
.sharing-fab-tabs {
    display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.5rem;
}
.sharing-fab-tab {
    padding: 0.3rem 0.7rem; border: 1px solid var(--border-color);
    border-radius: var(--radius); background: var(--surface);
    color: var(--text-muted); font-size: 0.82rem; cursor: pointer;
    transition: all 0.15s;
}
.sharing-fab-tab:hover { border-color: var(--accent); color: var(--text); }
.sharing-fab-tab.active {
    background: var(--accent); color: #fff; border-color: var(--accent);
}
.sharing-badge {
    display: inline-block; min-width: 1.1em; padding: 0 0.3em;
    border-radius: 999px; background: rgba(255,255,255,0.3);
    font-size: 0.7rem; text-align: center; margin-left: 0.2em;
}
.sharing-table {
    width: 100%; border-collapse: collapse;
    font-size: 0.85rem; margin-bottom: 0.5rem;
}
.sharing-table th, .sharing-table td {
    padding: 0.3rem 0.4rem; text-align: left;
    border-bottom: 1px solid var(--border-color);
}
.sharing-table th { font-weight: 600; color: var(--text-muted); font-size: 0.8rem; }
.sharing-field-name { font-weight: 600; }
.sharing-sel { font-size: 0.82rem; padding: 0.15rem 0.2rem; }

/* 2026-04-07 — LLM catalog cards */
.llm-card {
    padding: 0.6rem 0; border-bottom: 1px solid var(--border-color);
}
.llm-card:last-child { border-bottom: none; }
.llm-card-header { display: flex; justify-content: space-between; align-items: baseline; }
.llm-card-name { font-weight: 600; font-size: 0.95rem; }
.llm-card-meta { font-size: 0.8rem; color: var(--text-muted); }
.llm-card-desc { font-size: 0.85rem; margin: 0.2rem 0; }
.llm-card-comment { font-size: 0.82rem; color: var(--text-muted); font-style: italic; margin: 0.1rem 0; }
.llm-card-footer { display: flex; align-items: center; gap: 0.8rem; margin-top: 0.3rem; font-size: 0.82rem; }
.llm-card-score { font-weight: 600; }
.llm-card-reports { color: var(--text-muted); }
.llm-ref-link { font-size: 0.78rem; margin-left: 0.3rem; }
.llm-reports { font-size: 0.82rem; margin-bottom: 0.3rem; }
.llm-report-row { padding: 0.15rem 0; color: var(--text-muted); }
.llm-report-link:hover { color: var(--accent); }
.test-detail { font-size: 0.78rem; color: var(--text-muted); margin-left: 1.5rem; margin-top: 0.1rem; white-space: pre-wrap; }

/* 2026-04-07 — Integrated test results in LLM edit */
.llm-test-score { font-size: 0.9rem; margin: 0.5rem 0; }
.llm-test-row { font-size: 0.84rem; padding: 0.15rem 0; }
.test-pass { color: #16a34a; font-weight: 600; font-size: 0.78rem; }
.test-fail { color: #dc3545; font-weight: 600; font-size: 0.78rem; }
.test-error { font-size: 0.78rem; color: #dc3545; margin-left: 1.5rem; }

/* 2026-04-07 — Documentation popup */
/* 2026-08-04 (v1.2.137) — 400px fixed was a functional absence at 40 entries:
   the last section started below the fold and there was no way to narrow the
   list. The box now uses the viewport, the filter stays pinned at the top, and
   only the list scrolls under it. */
.docs-popup {
    z-index: 100;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); box-shadow: 0 4px 16px rgba(0,0,0,0.3);
    min-width: 320px; max-width: 480px;
    max-height: min(70vh, 640px);
    display: flex; flex-direction: column;
    padding: 0.5rem 0;
}
.docs-popup-filter-wrap { padding: 0 0.6rem 0.4rem; flex: 0 0 auto; }
.docs-popup-filter {
    width: 100%; box-sizing: border-box;
    padding: 0.35rem 0.5rem; font-size: 0.85rem;
    background: var(--bg); color: var(--text);
    border: 1px solid var(--border-color); border-radius: var(--radius);
}
#docs-popup-body { overflow-y: auto; flex: 1 1 auto; }
/* The sub-directory a class-1 doc lives in (research/, tool_guides/). Uses
   theme variables only — several shipped themes are LIGHT. */
.docs-popup-group {
    display: inline-block; margin-right: 0.4rem; padding: 0 0.3rem;
    font-size: 0.72rem; border-radius: 3px;
    color: var(--text-muted); border: 1px solid var(--border-color);
}
.docs-popup-title {
    font-weight: 600; font-size: 0.85rem; padding: 0.3rem 0.8rem;
    color: var(--text-muted); border-bottom: 1px solid var(--border-color);
    margin-bottom: 0.2rem;
}
.docs-popup-item {
    padding: 0.4rem 0.8rem; cursor: pointer; font-size: 0.88rem;
    transition: background 0.15s;
}
.docs-popup-item:hover { background: var(--accent); color: var(--btn-text); }
.docs-popup-loading { padding: 0.5rem 0.8rem; font-size: 0.85rem; color: var(--text-muted); }
/* 2026-04-29 (v1.2.14) — Sections in the docs popup, one per
   doc class (public, FAB-attached, private, admin). Section title
   uses the same muted style as docs-popup-title but lighter, since
   it's now a sub-heading rather than the popup's own title. */
.docs-popup-section + .docs-popup-section { margin-top: 0.3rem; padding-top: 0.3rem; border-top: 1px solid var(--border-color); }
.docs-popup-section-title {
    font-weight: 600; font-size: 0.78rem; padding: 0.25rem 0.8rem 0.15rem;
    color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;
}

/* 2026-04-07 — Grant rows in FAB sharing section.
   2026-04-18 (v2.8.28) — rows now mix user + FAB grants; the FAB badge
   distinguishes the two. Revoke button is discreet red on hover. */
.ae-user-row {
    display: flex; align-items: center; justify-content: space-between;
    font-size: 0.83rem; padding: 0.2rem 0;
}
.ae-grant-type-fab {
    display: inline-block;
    padding: 0 0.35rem;
    border-radius: 3px;
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--btn-text);
    background: var(--accent);
    margin-left: 0.3rem;
    vertical-align: 1px;
}
.ae-grant-revoke-btn {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    padding: 0 0.4rem;
    border-radius: 3px;
    font-size: 0.8rem;
    cursor: pointer;
    margin-left: 0.3rem;
}
.ae-grant-revoke-btn:hover {
    /* phantom-var-ok — la couleur du texte est fixee ICI (#fff) : le fond
       rouge n'entre donc jamais en conflit avec le texte du theme. */
    color: #fff;
    background: var(--danger, #dc2626);
    border-color: var(--danger, #dc2626);
}

/* --- Admin tabs --- */
.admin-tab { /* reuses .sys-tab styles */ }

/* --- FAB list cards --- */
.fab-card {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.6rem 0; border-bottom: 1px solid var(--border-color);
}
.fab-card:last-child { border-bottom: none; }
.fab-card-info { flex: 1; }
.fab-card-name { font-weight: 600; }
.fab-card-meta { font-size: 0.75rem; color: var(--text-muted); }

/* --- Admin user table --- */
#admin-user-table {
    width: 100%; border-collapse: collapse; font-size: 0.9rem;
}
#admin-user-table th,
#admin-user-table td {
    text-align: left; padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-color);
}
#admin-user-table th {
    font-weight: 600; color: var(--text-muted); font-size: 0.8rem;
    text-transform: uppercase; letter-spacing: 0.03em;
}
#admin-user-table td .action-btn {
    background: none; border: 1px solid var(--border-color); border-radius: var(--radius);
    padding: 0.25rem 0.6rem; cursor: pointer; color: var(--text);
    font-size: 0.8rem; margin-right: 0.3rem; transition: background 0.2s;
}
#admin-user-table td .action-btn:hover { background: var(--primary); color: var(--btn-text); }

/* --- Storage list --- */
.storage-list {
    border: 1px solid var(--border-color); border-radius: var(--radius);
    max-height: 200px; overflow-y: auto; font-size: 0.85rem;
}
.storage-list .storage-empty {
    padding: 0.75rem; color: var(--text-muted); text-align: center;
}
.storage-item {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.4rem 0.75rem; border-bottom: 1px solid var(--border-color);
}
.storage-item:last-child { border-bottom: none; }

/* --- 2026-04-17 (v2.8.23) — Scheduled actions read-only table on
   FAB edit + Interlocutor edit screens. Compact, fixed header, prompt
   column ellipsizes (full text in title tooltip). */
.schedules-list { font-size: 0.82rem; }
.schedules-table {
    width: 100%;
    border-collapse: collapse;
}
.schedules-table thead th {
    text-align: left;
    padding: 0.4rem 0.5rem;
    border-bottom: 2px solid var(--border-color);
    font-size: 0.72rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.schedules-table tbody td {
    padding: 0.45rem 0.5rem;
    border-bottom: 1px solid var(--border-color);
    vertical-align: top;
}
.schedules-table tbody td:first-child {
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.schedules-table tbody tr:last-child td { border-bottom: none; }
.schedules-table code {
    background: var(--input-bg);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 0.78rem;
}
/* 2026-06-19 (inlux-web v1.2.68) — Scroll-bounded schedules list + an
   "afficher les inactives" toggle. A long FAB schedule list no longer makes
   a tall page (mirrors .exchanges-scroll); inactive rows are hidden by
   default via a wrapper class and revealed by the checkbox. Header stays
   sticky on scroll (opaque --surface bg — --card-bg renders white-on-white,
   cf. v1.2.25). */
.schedules-scroll {
    max-height: 22rem;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: 4px;
}
.schedules-scroll .schedules-table thead th {
    position: sticky;
    top: 0;
    background: var(--surface);
    z-index: 1;
}
.schedules-scroll.hide-inactive .sched-row-inactive { display: none; }
.schedules-controls {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.5rem;
    flex-wrap: wrap;
}
.schedules-controls .sched-inactive-toggle {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.storage-item .file-name { flex: 1; word-break: break-all; }
.storage-item .file-size { color: var(--text-muted); margin-left: 1rem; white-space: nowrap; }
.storage-item .file-download {
    margin-left: 0.5rem; color: var(--link-color); cursor: pointer;
    text-decoration: none; font-size: 0.8rem;
}
.storage-item .file-download:hover { text-decoration: underline; }

/* --- 2026-04-18 (v2.8.30 / inlux-web v1.0.5) — Recent exchanges table
   on FAB edit screen. Reuses .schedules-table styling; only the message
   column needs its own ellipsis + click-to-drilldown link styling.
   2026-04-18 (v1.0.6) — Scroll-bounded container (no tall pages), narrow
   metadata columns so the Message column claims the remaining width. */
.exchanges-scroll {
    max-height: 18rem;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: 4px;
}
/* Column-sizing trick: width:1% + white-space:nowrap shrinks each
   metadata column to its content. The Message column has no such
   constraint, so it expands to fill the rest of the table. */
.exchanges-table .ex-date,
.exchanges-table .ex-from,
.exchanges-table .ex-to,
.exchanges-table .ex-dir,
.exchanges-table .ex-channel {
    width: 1%;
    white-space: nowrap;
}
.exchanges-table .ex-content {
    width: auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* max-width keeps the ellipsis kicking in even on wide screens. */
    max-width: 0;
}
.exchanges-table .ex-session-link {
    background: none;
    border: none;
    padding: 0;
    color: var(--link-color);
    cursor: pointer;
    font: inherit;
    text-decoration: underline dotted;
}
.exchanges-table .ex-session-link:hover { text-decoration: underline; }

/* Drilldown modal — native <dialog> with a sober panel. The scroll lives
   inside .drilldown-thread, not on the dialog itself, so the header stays
   pinned when the thread is long. */
.drilldown-dialog {
    max-width: 720px;
    width: 90vw;
    max-height: 80vh;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0;
    /* 2026-05-11 (v1.2.25) — was `var(--card-bg, #fff)` +
       `var(--text-color, inherit)`, both phantom variables that no
       theme defined. On the Inlux dark default this produced a #fff
       fallback background with text inherited from body (#eee) — near-
       white-on-white, unreadable. Use the real theme vars --surface +
       --text. */
    background: var(--surface);
    color: var(--text);
}
.drilldown-dialog::backdrop { background: rgba(0, 0, 0, 0.45); }
.drilldown-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border-color);
}
.drilldown-header h3 { margin: 0; font-size: 1rem; }
.drilldown-header h3 span {
    font-family: monospace;
    color: var(--text-muted);
    font-size: 0.85rem;
}
.drilldown-close {
    background: none; border: none; font-size: 1.4rem;
    cursor: pointer; line-height: 1; padding: 0 0.3rem;
    color: var(--text-muted);
}
.drilldown-close:hover { color: var(--text); }
.drilldown-thread {
    padding: 0.75rem 1rem;
    overflow-y: auto;
    max-height: calc(80vh - 3rem);
}
.drilldown-msg {
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 6px;
    border: 1px solid var(--border-color);
    background: var(--input-bg, #f7f7f7);
}
/* v1.2.2 — Soft alternating tints for drilldown readability.
   Cool blue for what the FAB (this side of the admin card) said,
   warm amber for what the interlocutor (user or peer FAB) said.
   Low alpha so they overlay cleanly on top of any theme background
   without fighting the theme's own colour scheme. Themes can
   override --drilldown-fab-bg / --drilldown-peer-bg if they want
   stronger tones — here we default to "très doux" as Franck asked. */
.drilldown-msg.role-user {
    background: var(--drilldown-peer-bg, rgba(217, 119, 6, 0.08));
}
.drilldown-msg.role-assistant {
    background: var(--drilldown-fab-bg, rgba(59, 130, 246, 0.08));
}
/* v1.1.2 (Inlux v2.10.7) — thinking-step rows are the LLM's internal
   reasoning before a tool call. Not what the interlocutor received.
   Grey out + italic tag so the admin reads them as "thought", distinct
   from the actual reply. Override the role-assistant background. */
/* v1.2.159 — `--bg-muted` n'est defini par AUCUN theme : le repli `#eceff1`
   s'appliquait donc toujours, y compris en sombre ou `--text` vaut `#eee`.
   Resultat mesure : #eee sur #eceff1, soit ~1.05:1 de contraste — les
   reponses des FABs etaient litteralement invisibles dans l'historique.
   Meme piege qu'en v1.2.25 (`--card-bg`/`--text-color`), deuxieme fois.
   On passe au voile translucide, patron deja utilise 15 lignes plus haut
   pour --drilldown-fab-bg : il se superpose a n'importe quel fond de theme
   au lieu d'en imposer un. Un theme peut toujours definir --bg-muted. */
.drilldown-msg.drilldown-msg-thinking,
.drilldown-msg.role-assistant.drilldown-msg-thinking {
    background: var(--bg-muted, rgba(128, 128, 128, 0.14));
    opacity: 0.85;
    border-style: dashed;
}
.drilldown-msg-thinking-tag {
    font-style: italic;
    color: var(--text-muted);
    font-weight: normal;
}
.drilldown-msg-meta {
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
}
.drilldown-msg-content { white-space: pre-wrap; word-break: break-word; }

/* v1.1.2 — Same treatment in the Recent Exchanges list table. */
.exchanges-table tr.ex-thinking-step {
    /* v1.2.159 — meme correctif que .drilldown-msg-thinking : voile
       translucide au lieu du gris clair opaque, illisible en theme sombre. */
    background: var(--bg-muted, rgba(128, 128, 128, 0.14));
    opacity: 0.8;
    font-style: italic;
}

/* --- Header navigation buttons alignment --- */
header button { margin-left: 0.3rem; }
header #profile-btn,
header #admin-btn,
header #dev-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}
/* 2026-04-03 — Ensure hidden attribute overrides display:flex on nav buttons */
header #admin-btn[hidden],
header #dev-btn[hidden] { display: none; }

/* --- Files screen --- */
header #files-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}

.files-breadcrumb {
    font-size: 0.8rem; color: var(--text-muted); flex: 1;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.files-grid {
    display: grid; gap: 0.5rem;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.files-item {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.6rem 0.8rem; border: 1px solid var(--border-color);
    border-radius: var(--radius); cursor: pointer;
    transition: background 0.2s; text-decoration: none; color: var(--text);
}
.files-item:hover { background: var(--primary); color: var(--btn-text); }

.files-item-icon { flex-shrink: 0; opacity: 0.7; }
.files-item-info { flex: 1; min-width: 0; }
.files-item-name {
    font-weight: 500; font-size: 0.9rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.files-item-meta { font-size: 0.75rem; color: var(--text-muted); }
.files-item:hover .files-item-meta { color: inherit; opacity: 0.8; }

.files-dir-icon { color: var(--accent); }

/* 2026-05-20 (v1.2.31) — List layout for the Files screen.
   Replaces the auto-fill grid that was truncating long names.
   Each row spans full width, three columns: name (flexes),
   size (fixed-ish), modified (fixed-ish), all visible without
   ellipsis. Container scrolls vertically if the list grows
   beyond viewport. Header row stays sticky at the top. */
.files-list {
    display: flex; flex-direction: column;
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    overflow: hidden;
    max-height: calc(100vh - 220px);  /* leaves room for screen header + page padding */
    overflow-y: auto;
}
.files-list-header,
.files-row {
    display: grid;
    /* 2026-05-21 (v1.2.32) — 4th col for the delete button. */
    grid-template-columns: 1fr 7rem 12rem 2.5rem;
    gap: 0.8rem;
    align-items: center;
    padding: 0.5rem 0.8rem;
}
.files-list-header {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    background: var(--surface);
    border-bottom: 1px solid var(--border-color);
    position: sticky; top: 0; z-index: 1;
}
.files-row {
    font-size: 0.88rem;
    border-bottom: 1px solid var(--border-color);
    cursor: pointer;
    transition: background 0.15s;
}
.files-row:last-child { border-bottom: none; }
.files-row:hover { background: var(--surface); }
.files-row.files-dir:hover { background: rgba(127,127,127,0.08); }
.files-col-name {
    display: flex; align-items: center; gap: 0.6rem;
    min-width: 0;  /* allow shrinking for very long names ; wrap below */
    word-break: break-all;
    overflow-wrap: anywhere;
}
.files-row-name { flex: 1; }
.files-row-icon { flex-shrink: 0; opacity: 0.85; }
.files-col-size {
    font-size: 0.82rem;
    color: var(--text-muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.files-col-date {
    font-size: 0.82rem;
    color: var(--text-muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 2026-05-21 (v1.2.32) — Indexed/raw badge + delete button. */
.files-indexed-badge,
.files-raw-badge {
    flex-shrink: 0;
    font-size: 0.9rem;
    margin-right: 0.1rem;
    opacity: 0.85;
}
.files-col-actions {
    display: flex;
    justify-content: flex-end;
}
.files-delete-btn {
    background: transparent;
    border: 1px solid transparent;
    padding: 0.15rem 0.4rem;
    border-radius: var(--radius);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, background 0.15s, border 0.15s;
    font-size: 0.95rem;
    color: var(--text-muted);
}
.files-row:hover .files-delete-btn { opacity: 0.7; }
.files-delete-btn:hover {
    opacity: 1;
    background: rgba(220, 38, 38, 0.1);
    border-color: rgba(220, 38, 38, 0.3);
}

/* Narrow viewport: drop the date + actions column to keep readable. */
@media (max-width: 640px) {
    .files-list-header,
    .files-row {
        grid-template-columns: 1fr 6rem 2.5rem;
    }
    .files-col-date { display: none; }
    .files-delete-btn { opacity: 1; }  /* always visible on touch */
}

.files-empty {
    text-align: center; color: var(--text-muted); padding: 2rem; font-size: 0.9rem;
}

.files-back-link {
    display: inline-flex; align-items: center; gap: 0.3rem;
    color: var(--link-color); cursor: pointer; font-size: 0.85rem;
    margin-bottom: 0.75rem; text-decoration: none;
}
.files-back-link:hover { text-decoration: underline; }

/* --- Dashboard --- */
header #dashboard-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}
header #dashboard-btn[hidden] { display: none; }

header #model-test-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}
header #model-test-btn[hidden] { display: none; }

header #sysadmin-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}
header #sysadmin-btn[hidden] { display: none; }

/* Sysadmin tabs */
.sys-tabs {
    display: flex; gap: 0.2rem; background: var(--surface);
    border-radius: var(--radius); padding: 0.2rem; margin: 0 0.5rem;
}
.sys-tab {
    padding: 0.3rem 0.6rem; border: none; border-radius: var(--radius);
    background: transparent; color: var(--text-muted); cursor: pointer;
    font-size: 0.8rem; transition: all 0.15s;
}
.sys-tab.active { background: var(--accent); color: var(--btn-text); }
.sys-tab:hover:not(.active) { color: var(--text); }

/* Progress bar */
.sys-progress { height: 8px; background: var(--border-color); border-radius: 4px; overflow: hidden; }
.sys-progress-fill { height: 100%; border-radius: 4px; transition: width 0.3s; }
.sys-progress-fill.green { background: #16a34a; }
.sys-progress-fill.orange { background: #f59e0b; }
.sys-progress-fill.red { background: #dc2626; }

/* Traffic chart (pure CSS bar chart) */
.traffic-chart {
    display: flex; align-items: flex-end; gap: 2px; height: 150px;
    background: var(--code-bg); border-radius: var(--radius);
    padding: 0.5rem 0.5rem 1.5rem; position: relative;
    border: 1px solid var(--border-color);
}
.traffic-bar {
    flex: 1; min-width: 4px; background: var(--accent); border-radius: 2px 2px 0 0;
    position: relative; transition: height 0.3s;
}
.traffic-bar:hover { opacity: 0.8; }
.traffic-bar:hover::after {
    content: attr(data-tooltip);
    position: absolute; bottom: calc(100% + 4px); left: 50%;
    transform: translateX(-50%); background: var(--surface);
    border: 1px solid var(--border-color); border-radius: 4px;
    padding: 2px 6px; font-size: 0.7rem; white-space: nowrap;
    color: var(--text); z-index: 5;
}
.traffic-labels {
    display: flex; justify-content: space-between;
    position: absolute; bottom: 2px; left: 0.5rem; right: 0.5rem;
    font-size: 0.6rem; color: var(--text-muted);
}

/* Sysadmin process/container cards */
.sys-process {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.4rem 0; border-bottom: 1px solid var(--border-color);
    font-size: 0.85rem;
}
.sys-process:last-child { border-bottom: none; }
.sys-status { font-weight: 600; font-size: 0.75rem; padding: 0.1rem 0.4rem; border-radius: 8px; }
.sys-status.online, .sys-status.active, .sys-status.running { background: #16a34a; color: #fff; }
.sys-status.stopped, .sys-status.inactive { background: #dc2626; color: #fff; }
.sys-status.unknown { background: #6b7280; color: #fff; }
.sys-action-btn {
    padding: 0.15rem 0.4rem; border: 1px solid var(--border-color);
    border-radius: var(--radius); background: none; color: var(--text-muted);
    cursor: pointer; font-size: 0.7rem;
}
.sys-action-btn:hover { background: var(--accent); color: var(--btn-text); }

.mt-test-row {
    display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0;
    border-bottom: 1px solid var(--border-color); font-size: 0.85rem;
}
.mt-test-row:last-child { border-bottom: none; }
.mt-badge {
    display: inline-block; padding: 0.15rem 0.5rem; border-radius: 10px;
    font-size: 0.75rem; font-weight: 600; min-width: 40px; text-align: center;
}
.mt-badge.pass { background: #16a34a; color: #fff; }
.mt-badge.fail { background: #dc2626; color: #fff; }
.mt-test-name { font-weight: 600; min-width: 140px; }
.mt-test-time { color: var(--text-muted); min-width: 60px; }
.mt-test-detail { color: var(--text-muted); font-size: 0.8rem; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.mt-score {
    font-size: 1.4rem; font-weight: 700; margin-bottom: 0.5rem;
}

.mt-report-item {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.4rem 0; border-bottom: 1px solid var(--border-color);
    font-size: 0.85rem; cursor: pointer;
}
.mt-report-item:hover { color: var(--accent); }
.mt-report-item:last-child { border-bottom: none; }

.dashboard-grid {
    display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    width: 100%; max-width: 900px;
}

/* 2026-06-15 (v1.2.51) — System pages regrouped into 4 groups of titled
   sections (Overview / Activity / Infrastructure / Operations). */
.sys-section { margin-bottom: 1.8rem; }
.sys-section-title {
    font-size: 1.05rem; font-weight: 600; margin: 0 0 .7rem;
    padding-bottom: .35rem; border-bottom: 1px solid var(--border-color);
    color: var(--text-secondary, var(--text-color));
}
.sys-block { width: 100%; max-width: 900px; }
/* Scrollable sub-panel (e.g. Schedules list) — bounded "sub-window". */
.sched-scroll { max-height: 65vh; overflow-y: auto; border: 1px solid var(--border-color);
    border-radius: var(--radius); }
.sched-scroll table { margin: 0; }
.sched-scroll thead th { position: sticky; top: 0; background: var(--surface); z-index: 1; }

.dash-card {
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); padding: 1rem;
}
.dash-card-label {
    font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase;
    letter-spacing: 0.04em; margin-bottom: 0.3rem;
}
.dash-card-value {
    font-size: 1.6rem; font-weight: 700; color: var(--text);
}
.dash-card-sub {
    font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem;
}

.dash-section {
    grid-column: 1 / -1; /* Full width */
}
.dash-section h3 {
    font-size: 0.9rem; color: var(--text-muted); margin-bottom: 0.5rem;
}

/* 2026-04-08 — Unified dashboard/system table style (themed, like sched-table) */
.dash-table {
    width: 100%; border-collapse: collapse; font-size: 0.84rem;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); overflow: hidden;
}
.dash-table th {
    font-weight: 600; color: var(--btn-text); font-size: 0.75rem;
    text-transform: uppercase; letter-spacing: 0.03em;
    background: var(--accent); padding: 0.5rem 0.6rem;
    text-align: left;
}
.dash-table td {
    text-align: left; padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--border-color);
}
.dash-table tr:last-child td { border-bottom: none; }
.dash-table tr:hover td { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }

/* 2026-04-08 — Schedules table: wider, responsive, themed */
.sched-table {
    width: 100%; border-collapse: collapse; font-size: 0.84rem;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius); overflow: hidden;
}
.sched-table th {
    font-weight: 600; color: var(--btn-text); font-size: 0.75rem;
    text-transform: uppercase; letter-spacing: 0.03em;
    background: var(--accent); padding: 0.5rem 0.6rem;
    text-align: left;
}
.sched-table td {
    padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--border-color);
    vertical-align: top;
}
.sched-table tr:last-child td { border-bottom: none; }
.sched-table tr:hover td { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
.sched-prompt { max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-cron { font-family: 'Fira Code', monospace; font-size: 0.78rem; color: var(--accent); }
.sched-status-active { color: #16a34a; font-weight: 600; }
.sched-status-done { color: var(--text-muted); }
.sched-status-error { color: #dc3545; font-weight: 600; }
.sched-next { font-weight: 600; }
.sched-result { font-size: 0.78rem; color: var(--text-muted); max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-agent { color: var(--accent); font-weight: 600; }
@media (max-width: 900px) {
    .sched-table { font-size: 0.78rem; }
    .sched-table th, .sched-table td { padding: 0.3rem 0.4rem; }
    .sched-prompt { max-width: 150px; }
}

/* --- History viewer --- */
header #history-btn {
    display: flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
}

.hist-row {
    display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.5rem 0;
    border-bottom: 1px solid var(--border-color); font-size: 0.83rem;
}
.hist-row:last-child { border-bottom: none; }
.hist-role {
    display: inline-block; min-width: 65px; padding: 0.1rem 0.4rem;
    border-radius: 8px; font-size: 0.7rem; font-weight: 600; text-align: center;
    flex-shrink: 0;
}
.hist-role.user { background: var(--primary); color: var(--btn-text); }
.hist-role.assistant { background: var(--surface); border: 1px solid var(--border-color); }
.hist-role.tool { background: transparent; color: var(--text-muted); border: 1px solid var(--border-color); }
.hist-role.forget { background: #6b7280; color: #fff; text-decoration: line-through; opacity: 0.5; }
.hist-content {
    flex: 1; color: var(--text); word-break: break-word;
    max-height: 150px; overflow-y: auto; white-space: pre-wrap;
    font-size: 0.82rem; line-height: 1.4;
    scrollbar-width: thin;
    scrollbar-color: var(--text-muted) transparent;
}
/* Webkit scrollbar for history cells */
.hist-content::-webkit-scrollbar { width: 6px; }
.hist-content::-webkit-scrollbar-thumb { background: var(--text-muted); border-radius: 3px; }
.hist-content.forgotten { opacity: 0.4; text-decoration: line-through; }
.hist-time { color: var(--text-muted); font-size: 0.7rem; white-space: nowrap; flex-shrink: 0; }
.hist-btn {
    padding: 0.15rem 0.4rem; border: 1px solid var(--border-color); border-radius: var(--radius);
    background: none; color: var(--text-muted); cursor: pointer; font-size: 0.7rem;
    flex-shrink: 0; transition: all 0.2s;
}
.hist-btn:hover { background: var(--accent); color: var(--btn-text); border-color: var(--accent); }
.hist-tool-result { font-size: 0.78rem; color: var(--text-muted); font-style: italic; }
.hist-btn.restore { border-color: #16a34a; color: #16a34a; }
.hist-btn.restore:hover { background: #16a34a; color: #fff; }

/* 2026-04-09 — Agent mode toggle removed (mode system deleted) */

/* ==========================================================================
   2026-04-03 — Developer logs screen
   ========================================================================== */

.dev-controls {
    display: flex; gap: 0.4rem; align-items: center; flex: 1;
    justify-content: flex-end; flex-wrap: wrap;
}
.dev-controls select,
.dev-controls input[type="text"] {
    padding: 0.25rem 0.4rem; border: 1px solid var(--border-color);
    border-radius: var(--radius); background: var(--input-bg);
    color: var(--text); font-size: 0.8rem;
}
.dev-search-input { width: 140px; }
.dev-auto-label {
    font-size: 0.8rem; color: var(--text-muted);
    display: flex; align-items: center; gap: 0.2rem;
}
.dev-controls .btn-primary { font-size: 0.8rem; padding: 0.25rem 0.6rem; }

/* --- Split pane layout --- */
.dev-split {
    flex: 1; display: flex; flex-direction: column; overflow: hidden;
}

.log-container {
    flex: 1; overflow: auto; background: var(--code-bg);
    margin: 0; padding: 0; min-height: 60px;
}

.dev-divider {
    height: 5px; background: var(--border-color); cursor: row-resize;
    flex-shrink: 0; transition: background 0.15s;
}
.dev-divider:hover, .dev-divider.active {
    background: var(--accent);
}

.dev-prompt-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.3rem 0.75rem; background: var(--surface);
    border-bottom: 1px solid var(--border-color);
    font-size: 0.8rem; font-weight: 600; color: var(--text-muted);
}

.prompt-output {
    font-size: 0.75rem; line-height: 1.4; color: var(--text);
}

.log-output {
    padding: 0.75rem; margin: 0; font-size: 0.78rem; line-height: 1.5;
    font-family: 'Fira Code', 'Consolas', monospace;
    white-space: pre-wrap; word-break: break-all;
    color: var(--text);
}

/* Log line coloring by tag */
.log-line { display: block; }
.log-line:hover { background: rgba(255,255,255,0.03); }
.log-tag { font-weight: 600; }
.log-ts { color: var(--text-muted); }
.log-tag-ERROR { color: #ef4444; }
.log-tag-WARNING { color: #f59e0b; }
.log-tag-API { color: #60a5fa; }
.log-tag-AUTH { color: #a78bfa; }
.log-tag-MCP { color: #34d399; }
.log-tag-SESSION { color: #38bdf8; }
.log-tag-ENGINE { color: #fb923c; }
.log-tag-DB { color: #e879f9; }
.log-tag-CONFIG { color: #94a3b8; }
.log-tag-MQTT { color: #2dd4bf; }
.log-tag-LLM { color: #fbbf24; }
.log-tag-FILE { color: #4ade80; }
.log-tag-TOOL { color: #f472b6; }
.log-id { color: var(--text-muted); }

/* 2026-04-08 — FIP Clone wizard (FAB Identity Pack) */
.clone-steps {
    display: flex; align-items: center; gap: 0.4rem;
    margin-bottom: 1.5rem; font-size: 0.85rem;
    border-bottom: 1px solid var(--border-color); padding-bottom: 0.8rem;
}
.clone-step {
    padding: 0.3rem 0.7rem; border-radius: var(--radius);
    color: var(--text-muted); font-weight: 500;
}
.clone-step.active {
    background: var(--primary); color: var(--btn-text); font-weight: 600;
}
.clone-step.done {
    color: #16a34a; font-weight: 600;
}
.clone-step-sep { color: var(--text-muted); font-size: 0.75rem; }

/* Drop zone for file upload */
.clone-dropzone {
    border: 2px dashed var(--border-color); border-radius: var(--radius);
    padding: 2rem; text-align: center; cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
    color: var(--text-muted); margin: 0.5rem 0;
}
.clone-dropzone:hover,
.clone-dropzone.dragover {
    border-color: var(--primary); background: rgba(var(--primary-rgb, 100,100,255), 0.05);
}
.clone-dropzone-icon { font-size: 2rem; margin-bottom: 0.5rem; }
.clone-dropzone-text { font-size: 0.9rem; }
.clone-dropzone-hint { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.3rem; }

/* Analysis review cards */
.fip-section {
    margin: 1rem 0; padding: 0.8rem;
    border: 1px solid var(--border-color); border-radius: var(--radius);
    background: var(--bg);
}
.fip-section-title {
    font-weight: 600; font-size: 0.9rem; margin-bottom: 0.5rem;
    display: flex; align-items: center; gap: 0.4rem;
}
.fip-badge {
    display: inline-block; padding: 0.1rem 0.4rem; border-radius: 3px;
    font-size: 0.72rem; font-weight: 600; text-transform: uppercase;
}
.fip-badge-ready { background: #16a34a; color: #fff; }
.fip-badge-warning { background: #f59e0b; color: #000; }
.fip-badge-error { background: #dc3545; color: #fff; }
.fip-badge-unmapped { background: #6b7280; color: #fff; }
.fip-badge-skip { background: var(--surface); color: var(--text-muted); border: 1px solid var(--border-color); }

/* File/tool inventory table */
/* 2026-04-10 — Responsive: overflow-x for wide tables, word-break for long paths */
.fip-table {
    width: 100%; border-collapse: collapse; font-size: 0.82rem;
    table-layout: auto;
}
.fip-table th, .fip-table td {
    padding: 0.3rem 0.5rem; text-align: left;
    border-bottom: 1px solid var(--border-color);
    word-break: break-word; max-width: 400px;
}
.fip-section { overflow-x: auto; }
.fip-table th {
    font-weight: 600; color: var(--text-muted); font-size: 0.78rem;
    text-transform: uppercase;
}
.fip-table tr:last-child td { border-bottom: none; }

/* Warning/info banners */
.fip-warnings {
    padding: 0.5rem 0.7rem; border-radius: var(--radius);
    background: rgba(245, 158, 11, 0.1); border-left: 3px solid #f59e0b;
    font-size: 0.82rem; margin: 0.5rem 0;
}
.fip-warnings li { margin: 0.2rem 0; }

/* Prompt preview (collapsible) */
.fip-prompt-preview {
    font-size: 0.8rem; white-space: pre-wrap;
    background: var(--bg); padding: 0.5rem;
    border-radius: var(--radius); max-height: 120px;
    overflow: auto; color: var(--text-muted);
}

/* Reconstruction notes */
.fip-notes {
    font-size: 0.82rem; font-style: italic; color: var(--text-muted);
    padding: 0.5rem; border-left: 3px solid var(--primary);
    margin: 0.5rem 0;
}

/* Success result card */
.fip-success {
    text-align: center; padding: 1.5rem;
}
.fip-success-icon { font-size: 3rem; margin-bottom: 0.5rem; }
.fip-success-title { font-size: 1.2rem; font-weight: 600; margin-bottom: 0.3rem; }
.fip-success-details { font-size: 0.85rem; color: var(--text-muted); }

/* --- 2026-04-17 — FAB file browser (full-width screen, like MQTT test) ---
   2026-04-17 (v2.8.7) — Panel is now a direct child of the screen (no
     .form-container wrapper). flex:1 takes the remaining vertical space
     after the header; width fills the viewport; inner columns get explicit
     flex-basis so the viewer always keeps most of the page width. */
.ae-browse-panel {
    display: flex;
    gap: 1.5rem;
    flex: 1;
    min-height: 0;      /* needed so children can overflow without pushing */
    width: 80%;         /* 2026-04-17 — breathing room on wide screens */
    max-width: 1600px;
    margin: 0 auto;     /* centered */
    padding: 1rem 0 1.5rem;
    box-sizing: border-box;
}
.ae-browse-tree {
    /* 2026-04-17 (v2.8.12) — Widened from 320 → 480 px so filenames are
       rarely truncated (icon + name + date + size + trash icon adds ~170 px
       of non-name chrome per row, which left too little for the name). */
    flex: 0 0 480px;
    min-width: 320px;
    overflow-y: auto;
    font-size: 0.82rem;
    border-right: 1px solid var(--border-color);
    padding-right: 1rem;
}
.ae-browse-viewer {
    flex: 1 1 auto;
    min-width: 0;       /* allow shrink so <pre> with long lines doesn't push */
    overflow: auto;
    font-size: 0.9rem;
    padding-left: 0.5rem;
}
.ae-browse-viewer-empty {
    color: var(--text-muted);
    padding: 2rem;
    text-align: center;
}
.ae-browse-viewer pre {
    background: var(--input-bg);
    padding: 0.75rem;
    border-radius: var(--radius);
    overflow-x: auto;
    font-size: 0.8rem;
    line-height: 1.5;
}
.ae-browse-viewer .md-rendered {
    line-height: 1.6;
}
/* Tree items */
.browse-section {
    font-weight: 600;
    margin: 0.75rem 0 0.25rem;
    color: var(--accent);
    font-size: 0.85rem;
}
.browse-section:first-child { margin-top: 0; }
.browse-dir {
    cursor: pointer;
    padding: 0.15rem 0;
    user-select: none;
}
.browse-dir::before {
    content: "▸ ";
    display: inline-block;
    width: 1em;
    transition: transform 0.15s;
}
.browse-dir.open::before { content: "▾ "; }
.browse-dir-children { margin-left: 1rem; }
.browse-dir-children.collapsed { display: none; }
/* 2026-04-17 (v2.8.11) — Files become a flex row with name + modified
   timestamp + size + trash icon. Name takes flex:1 with ellipsis so long
   names don't wreck the layout. Trash icon appears on row hover. */
.browse-file {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.2rem 0.3rem 0.2rem 1em;
    cursor: pointer;
    border-radius: 3px;
    min-width: 0;
}
.browse-file:hover { background: var(--input-bg); }
.browse-file.active { background: var(--accent); color: var(--btn-text); }
.browse-file-icon { flex: 0 0 auto; }
.browse-file-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.browse-file-mod {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 0.7rem;
    font-family: ui-monospace, monospace;
}
.browse-file-size {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 0.72rem;
}
.browse-file.active .browse-file-mod,
.browse-file.active .browse-file-size { color: var(--btn-text); opacity: 0.8; }
.browse-file-del {
    flex: 0 0 auto;
    background: transparent;
    border: none;
    padding: 2px 4px;
    border-radius: 3px;
    color: var(--text-muted);
    cursor: pointer;
    opacity: 0;          /* hidden until row is hovered */
    transition: opacity 0.1s, color 0.1s, background 0.1s;
    display: flex;
    align-items: center;
}
.browse-file:hover .browse-file-del { opacity: 1; }
.browse-file-del:hover { color: var(--danger, #dc2626); background: rgba(220, 38, 38, 0.1); }
.browse-file-del:disabled { opacity: 0.5; cursor: wait; }
.browse-download-link {
    display: inline-block;
    margin-top: 0.5rem;
    color: var(--accent);
    cursor: pointer;
    text-decoration: underline;
}

/* 2026-05-13 (v1.2.26, Inlux v2.12.67+) — Skills & Credentials tab. */
.ae-skills-list { display: flex; flex-direction: column; gap: 0.5rem; }
.ae-skill-row {
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    padding: 0.5rem 0.7rem;
    background: var(--surface);
    font-size: 0.85rem;
}
.ae-skill-head { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.ae-skill-slug {
    font-size: 0.75rem;
    color: var(--text-muted);
    background: rgba(127,127,127,0.1);
    padding: 0 0.3rem;
    border-radius: 3px;
}
/* v1.2.185 (Inlux v2.12.576) — Le prix d'une skill, en jetons. Deux nombres
   cote a cote : ce qui part a chaque tour, et ce qui n'est lu qu'a l'usage. */
.skill-row-cost { font-size: 0.78rem; font-variant-numeric: tabular-nums; margin-top: 0.25rem; }

.ae-skill-cost {
    margin-left: auto;
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #8a8a9a);
    white-space: nowrap;
}
.ae-skill-cost-total {
    margin: 0 0 0.6em;
    padding: 0.5em 0.7em;
    border: 1px solid var(--border-color, #333);
    border-radius: 6px;
    background: var(--surface, #16213e);
    font-variant-numeric: tabular-nums;
}

.ae-skill-version {
    font-size: 0.7rem;
    color: var(--text-muted);
}
.ae-skill-desc { margin: 0.2rem 0; color: var(--text-muted); font-size: 0.8rem; }
.ae-skill-creds { margin: 0.2rem 0 0.3rem 0; font-size: 0.78rem; color: var(--text-muted); }
.ae-skill-creds code {
    background: rgba(127,127,127,0.08);
    padding: 0 0.25rem;
    border-radius: 2px;
}
.ae-skill-uninstall {
    background: transparent;
    color: var(--text-muted);
    border: none;
    padding: 0;
    font-size: 0.78rem;
    cursor: pointer;
    text-decoration: underline;
}
.ae-skill-uninstall:hover { color: var(--danger, #dc2626); }

.ae-required-creds {
    margin-bottom: 0.6rem;
    font-size: 0.82rem;
}
.ae-required-cred-row {
    padding: 0.2rem 0;
    border-bottom: 1px dashed var(--border-color);
}
.ae-required-cred-row:last-child { border-bottom: none; }
.ae-cred-set {
    margin-left: 0.5rem;
    color: var(--accent);
    font-size: 0.75rem;
}
.ae-cred-missing {
    margin-left: 0.5rem;
    color: var(--danger, #dc2626);
    font-size: 0.75rem;
}

.ae-creds-list { display: flex; flex-direction: column; gap: 0.3rem; }
.ae-cred-row {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.3rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    background: var(--surface);
    font-size: 0.83rem;
}
.ae-cred-head { display: flex; gap: 0.5rem; align-items: baseline; }
.ae-cred-value {
    color: var(--text-muted);
    font-size: 0.78rem;
    font-family: monospace;
}
/* 2026-07-30 (v1.2.134) — « set by <someone else> » marker on a credential
   row. Theme variables only : several shipped themes are LIGHT, so a
   hardcoded colour here would render dark-on-dark or vanish outright. */
.ae-cred-author {
    margin-left: 0.5rem;
    color: var(--text-muted);
    font-size: 0.72rem;
    font-style: italic;
}
.ae-cred-actions { display: flex; gap: 0.5rem; }
.btn-link {
    background: transparent;
    color: var(--text-muted);
    border: none;
    padding: 0;
    font-size: 0.78rem;
    cursor: pointer;
    text-decoration: underline;
}
.btn-link:hover { color: var(--accent); }
.ae-cred-delete-btn:hover { color: var(--danger, #dc2626); }

.ae-catalog-row {
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    padding: 0.5rem 0.7rem;
    margin-bottom: 0.4rem;
    background: var(--surface);
    cursor: pointer;
    font-size: 0.85rem;
}
.ae-catalog-row:hover { background: rgba(127,127,127,0.06); }
.ae-scope-private {
    display: inline-block;
    padding: 0 0.35rem;
    margin-left: 0.4rem;
    border-radius: 3px;
    font-size: 0.65rem;
    background: rgba(127,127,127,0.15);
    color: var(--text-muted);
    text-transform: uppercase;
}

/* ── Studio canvas (backend v2.12.238) ────────────────────────────────────
   Lot 2 (v1.2.89): the canvas lives as a RIGHT COLUMN of the chat screen —
   conversation + live dashboard side by side — toggled by `.studio-mode` on
   #chat-screen. The FAB paints declarative widgets (canvas tool → `widget`
   WS event → canvas.js). Theme-driven, desktop-first. */
#canvas-column { display: none; }                 /* hidden until studio-mode */
#chat-screen.studio-mode #canvas-column {
    display: flex;
    flex-direction: column;
    /* v1.2.103 — width driven by the splitter (CSS var); default 46%. */
    flex: 0 0 var(--studio-canvas-w, 46%);
    min-width: 340px;
    background: var(--bg);
    position: relative;
    overflow: hidden;
}
/* The conversation fills whatever the splitter leaves it. */
#chat-screen.studio-mode #chat-main { flex: 1 1 auto; min-width: 380px; }

/* v1.2.103 — draggable boundary between chat and studio (studio-mode only). */
#studio-splitter { display: none; }
#chat-screen.studio-mode #studio-splitter {
    display: block;
    flex: 0 0 6px;
    cursor: col-resize;
    background: var(--border-color);
    position: relative;
    z-index: 3;
    touch-action: none;
    transition: background 0.15s ease;
}
#chat-screen.studio-mode #studio-splitter:hover,
#studio-splitter.dragging { background: var(--accent); }

#canvas-column-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.85rem;
    border-bottom: 1px solid var(--border-color);
    background: var(--header-bg);
}
.canvas-col-title {
    font-weight: 600; color: var(--text); flex: 1;
    font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em;
}
/* v1.2.105 — GridStack manages the tile layout (drag + 2D resize); the pane is
   just the scroll container it lays out inside. */
.canvas-pane {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem;
}
/* the item box GridStack sizes — our card fills it, body scrolls inside */
.canvas-pane .grid-stack-item-content {
    inset: 0;
    display: flex;
    overflow: visible;
}
.canvas-pane .grid-stack-item-content > .canvas-widget {
    flex: 1;
    height: 100%;
    min-height: 0;
}
.canvas-empty {
    position: absolute;
    left: 50%; top: 55%;
    transform: translate(-50%, -50%);
    max-width: 320px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
    pointer-events: none;
}
.canvas-pulse { animation: canvasPulse 0.5s ease; }
@keyframes canvasPulse { from { box-shadow: inset 0 0 0 2px var(--accent); } to { box-shadow: none; } }

.canvas-widget {
    background: var(--surface);
    border: 1px solid var(--border-color);
    border-radius: var(--radius);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.canvas-widget-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-color);
    background: var(--header-bg);
    cursor: grab;                 /* v1.2.102 — the header is the drag handle */
}
.canvas-widget-head:active { cursor: grabbing; }
/* v1.2.102 — grip affordance: signals the tile can be dragged by its header */
.canvas-widget-grip {
    color: var(--text-muted); font-size: 0.85rem; line-height: 1;
    letter-spacing: -1px; user-select: none; opacity: 0.55;
}
.canvas-widget-head:hover .canvas-widget-grip { opacity: 1; }
.canvas-widget-head { flex-shrink: 0; }   /* head fixed, body scrolls (v1.2.105) */
.canvas-widget-title { font-weight: 600; color: var(--text); flex: 1; font-size: 0.9rem; }
.canvas-widget-type {
    font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--text-muted); border: 1px solid var(--border-color);
    border-radius: 999px; padding: 0.05rem 0.5rem;
}
.canvas-widget-x {
    background: none; border: none; color: var(--text-muted);
    font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 0 0.15rem;
}
.canvas-widget-x:hover { color: var(--accent); }
.canvas-widget-body { padding: 0.85rem; color: var(--text); overflow: auto; flex: 1; min-height: 0; }

/* kpi */
.kpi-value { font-size: 2.2rem; font-weight: 700; color: var(--text); line-height: 1.1; }
.kpi-label { color: var(--text-muted); font-size: 0.85rem; margin-top: 0.25rem; }
.kpi-delta { margin-top: 0.4rem; font-size: 0.85rem; font-weight: 600; }
.kpi-up { color: #3fb950; } .kpi-down { color: var(--accent); }

/* table */
.canvas-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.canvas-table th, .canvas-table td {
    text-align: left; padding: 0.35rem 0.6rem;
    border-bottom: 1px solid var(--border-color); white-space: nowrap;
}
.canvas-table th { color: var(--text-muted); font-weight: 600; }

.canvas-placeholder { color: var(--text-muted); font-size: 0.85rem; }
.canvas-placeholder pre {
    background: var(--code-bg); padding: 0.6rem; border-radius: 6px;
    overflow-x: auto; margin-top: 0.4rem; font-size: 0.75rem;
}
.canvas-err { color: var(--accent); font-size: 0.85rem; }

/* Lot 2 (v1.2.90) — chart (Vega-Lite) fit + loading state.
   NB: the FAB sidebar is kept VISIBLE in studio mode — hiding it removed the
   only way to switch FABs (the collapse/expand affordance is width-0 + a JS-
   toggled expand button my rule bypassed). A compact avatar-only rail is a
   later polish; never break FAB switching. */
.canvas-chart-loading { color: var(--text-muted); font-size: 0.85rem; }
.canvas-widget-body .vega-embed { width: 100%; }
.canvas-widget-body .vega-embed svg { max-width: 100%; height: auto; }
.canvas-widget-body summary { display: none; }

/* Lot 2 (v1.2.93) — compact FAB avatar rail in studio mode: the sidebar shrinks
   to clickable initials so switching FABs survives while the canvas gets space.
   `.fab-ava` is hidden in normal mode (the list shows full labels as before). */
.fab-ava { display: none; }
#chat-screen.studio-mode #fab-sidebar { width: 58px; min-width: 58px; }
#chat-screen.studio-mode #sidebar-header .header-user,
#chat-screen.studio-mode #sidebar-collapse-btn { display: none; }
#chat-screen.studio-mode #sidebar-header { justify-content: center; padding: 0.5rem 0; }
#chat-screen.studio-mode #sidebar-header .header-logo { margin: 0; }
#chat-screen.studio-mode .fab-label { display: none; }
#chat-screen.studio-mode .fab-list-item {
    justify-content: center;
    padding: 0.3rem;
}
#chat-screen.studio-mode .fab-ava {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px; height: 36px;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--border-color);
    color: var(--text);
    font-weight: 600;
    text-transform: uppercase;
}
#chat-screen.studio-mode .fab-list-item.active .fab-ava {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent);
}

/* Lot 3 (v1.2.97) — doc + image widget renderers. */
.canvas-img { max-width: 100%; height: auto; display: block; border-radius: 6px; }
.canvas-doc-frame { width: 100%; height: 420px; border: none; border-radius: 6px; background: #fff; }
.canvas-doc-text {
    max-height: 420px; overflow: auto; margin: 0;
    white-space: pre-wrap; word-break: break-word; font-size: 0.78rem;
    background: var(--code-bg); padding: 0.6rem; border-radius: 6px; color: var(--text);
}
.canvas-doc-download {
    background: var(--surface); border: 1px solid var(--border-color);
    color: var(--text); border-radius: 6px; padding: 0.5rem 0.8rem; cursor: pointer;
    font-size: 0.85rem;
}
.canvas-doc-download:hover { border-color: var(--accent); }

/* Interactive widgets (v1.2.99) — buttons: the first click→FAB return channel. */
.canvas-btn-text { margin-bottom: 0.6rem; color: var(--text); font-size: 0.9rem; }
.canvas-btn-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.canvas-btn {
    background: var(--accent); color: var(--btn-text, #fff); border: none;
    border-radius: 6px; padding: 0.45rem 0.9rem; cursor: pointer; font-size: 0.85rem;
}
.canvas-btn:hover:not(:disabled) { filter: brightness(1.12); }
.canvas-btn:disabled { opacity: 0.55; cursor: default; }
.canvas-btn-clicked { outline: 2px solid var(--text); outline-offset: 1px; }

/* Interactive widgets (v1.2.100) — slider: a themed value control. */
.canvas-slider { display: flex; flex-direction: column; gap: 0.45rem; }
.canvas-slider-head { display: flex; justify-content: space-between; align-items: baseline; }
.canvas-slider-label { color: var(--text); font-size: 0.88rem; }
.canvas-slider-value { color: var(--accent); font-weight: 600; font-size: 1.05rem; }
.canvas-slider-input { width: 100%; accent-color: var(--accent); cursor: pointer; }

/* Interactive widgets (v1.2.101) — input: a free-text field (untrusted). */
.canvas-input { display: flex; flex-direction: column; gap: 0.4rem; }
.canvas-input-label { color: var(--text); font-size: 0.85rem; }
.canvas-input-row { display: flex; gap: 0.5rem; align-items: flex-end; }
.canvas-input-field {
    flex: 1; background: var(--input-bg, var(--bg)); color: var(--text);
    border: 1px solid var(--border-color); border-radius: 6px;
    padding: 0.45rem 0.6rem; font-size: 0.85rem; font-family: inherit; resize: vertical;
}
.canvas-input-field:focus { outline: none; border-color: var(--accent); }
.canvas-input-submit {
    background: var(--accent); color: var(--btn-text, #fff); border: none;
    border-radius: 6px; padding: 0.45rem 0.9rem; cursor: pointer; font-size: 0.85rem;
}
.canvas-input-submit:disabled { opacity: 0.55; }

/* Interactive widgets (v1.2.103) — select: a constrained dropdown. */
.canvas-select { display: flex; flex-direction: column; gap: 0.4rem; }
.canvas-select-label { color: var(--text); font-size: 0.85rem; }
.canvas-select-field {
    background: var(--input-bg, var(--surface)); color: var(--text);
    border: 1px solid var(--border-color); border-radius: 6px;
    padding: 0.45rem 0.6rem; font-size: 0.85rem; font-family: inherit;
    cursor: pointer;
}
.canvas-select-field:focus { outline: none; border-color: var(--accent); }

/* Interactive widgets (v1.2.104) — form: several fields submitted as one block. */
.canvas-form { display: flex; flex-direction: column; gap: 0.7rem; }
.canvas-form-title { font-weight: 600; color: var(--text); font-size: 0.9rem; }
.canvas-form-field { display: flex; flex-direction: column; gap: 0.3rem; }
.canvas-form-label { color: var(--text-muted); font-size: 0.8rem; }
.canvas-form-submit { align-self: flex-start; margin-top: 0.2rem; }

/* pulse — a kept fire (a keep_impulse the FAB chose to reveal). v1.2.107.
   A warm "ember" card: toward chip, intention, a live countdown. The glow is
   themed off --accent so it reads on light and dark themes alike. */
.canvas-pulse {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    padding: 0.7rem 0.8rem;
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
    background:
        radial-gradient(120% 80% at 0% 0%,
            color-mix(in srgb, var(--accent) 12%, transparent), transparent 70%),
        var(--surface);
}
.canvas-pulse.pulse-pending { animation: pulse-breathe 3.6s ease-in-out infinite; }
@keyframes pulse-breathe {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 22%, transparent); }
    50%      { box-shadow: 0 0 10px 1px color-mix(in srgb, var(--accent) 30%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
    .canvas-pulse.pulse-pending { animation: none; }
}
.pulse-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pulse-glyph { font-size: 1rem; line-height: 1; }
.pulse-toward {
    font-size: 0.8rem; font-weight: 600; color: var(--accent);
    padding: 0.05rem 0.45rem;
    border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
    border-radius: 999px;
}
.pulse-state {
    margin-left: auto; font-size: 0.72rem; letter-spacing: 0.02em;
    text-transform: uppercase; color: var(--text-muted);
}
.pulse-intention {
    color: var(--text); font-size: 0.92rem; line-height: 1.45;
    white-space: pre-wrap;
}
.pulse-countdown {
    font-size: 0.8rem; color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.pulse-countdown.pulse-due { color: var(--accent); font-weight: 600; }
/* fired / cooled: the fire is answered — dim the border accent, no breathing. */
.canvas-pulse.pulse-fired { border-left-color: color-mix(in srgb, var(--accent) 60%, var(--text-muted)); }
.canvas-pulse.pulse-cooled { border-left-color: var(--border-color); opacity: 0.82; }
.canvas-pulse.pulse-cooled .pulse-intention { color: var(--text-muted); }

/* timeline (v2.12.261) — a chronological thread of dated entries.
   Theme-var only, so it reads correctly in light and dark themes. */
.canvas-timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.canvas-timeline::before {
    content: ""; position: absolute; left: 5px; top: 4px; bottom: 4px;
    width: 2px; background: var(--border-color);
}
.tl-item { position: relative; padding: 0 0 0.9rem 1.5rem; }
.tl-item:last-child { padding-bottom: 0; }
.tl-dot {
    position: absolute; left: 0; top: 3px; box-sizing: border-box;
    width: 12px; height: 12px; border-radius: 50%;
    background: var(--surface); border: 2px solid var(--text-muted);
}
.tl-when {
    display: block; font-size: 0.7rem; text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--text-muted); margin-bottom: 0.1rem;
}
.tl-title { font-weight: 600; color: var(--text); font-size: 0.9rem; line-height: 1.3; }
.tl-detail { color: var(--text-muted); font-size: 0.82rem; margin-top: 0.15rem; line-height: 1.4; }
.timeline-empty { color: var(--text-muted); font-size: 0.85rem; font-style: italic; }
/* kind markers — milestone strongest, event the default, note the faintest */
.tl-milestone .tl-dot { border-color: var(--accent); background: var(--accent); }
.tl-decision  .tl-dot { border-color: var(--accent); }
.tl-event     .tl-dot { border-color: var(--text-muted); }
.tl-note      .tl-dot { border-color: var(--border-color); background: var(--border-color); }

/* graph (v2.12.262) — relational map, force-directed SVG.
   Node kinds reuse the categorical chart palette; theme-var for the rest. */
.canvas-graph { width: 100%; height: auto; display: block; overflow: visible; }
.ge-line { stroke: var(--border-color); stroke-width: 1.2; }
.ge-label { fill: var(--text-muted); font-size: 8px; text-anchor: middle; }
.gn-dot { stroke: var(--surface); stroke-width: 1.5; fill: var(--text-muted); }
.gn-label { fill: var(--text); font-size: 9px; dominant-baseline: middle; }
.gn-dot.gn-person  { fill: var(--accent); }
.gn-dot.gn-fab     { fill: #a371f7; }
.gn-dot.gn-project { fill: #3fb950; }
.gn-dot.gn-org     { fill: #d29922; }
.gn-dot.gn-default { fill: var(--text-muted); }
.graph-empty { color: var(--text-muted); font-size: 0.85rem; font-style: italic; }

/* mindmap (v2.12.263) — collaborative-thinking space. Theme-var only.
   Free-text node boxes (author-tinted), typed edges with the emphasis rule:
   expected-flow faint, tension bold. */
.canvas-mindmap { width: 100%; height: auto; display: block; overflow: visible; }
/* v2.12.271 — the box is sized to its text in JS (_mmFit); `overflow: auto`
   (was `hidden`) is the honest last resort: if a text still exceeds even a
   hand-resized box, it stays REACHABLE by scrolling instead of being silently
   beheaded. No scrollbar shows when the content fits, which is now the norm. */
.mm-node {
    box-sizing: border-box; width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center; text-align: center;
    padding: 3px 6px; font-size: 10px; line-height: 1.2; overflow: auto;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border-color); border-left-width: 3px; border-radius: 6px;
    word-break: break-word; hyphens: auto;
}
/* authorship — the trace of who placed the node (left edge, subtle tint) */
.mm-node.mm-fab          { border-left-color: var(--accent); }
.mm-node.mm-interlocutor { border-left-color: #3fb950; }
/* edges — flow is faint (position already carries it), tension stands out */
.mm-edge         { stroke: var(--text-muted); stroke-width: 1.3; }
.mm-edge-flow    { stroke: var(--border-color); stroke-width: 1; opacity: 0.6; }
.mm-edge-tension { stroke: var(--accent); stroke-width: 2; }
.mm-arrowhead    { fill: var(--text-muted); }
.mm-edge-label   { fill: var(--text-muted); font-size: 8px; text-anchor: middle; }
/* inline editing (B.1) + drag to move (B.2) — click a node to rewrite it,
   drag it to reposition. */
.mm-node.mm-editable { cursor: grab; }
.mm-node.mm-editable:hover { border-color: var(--accent); }
.mm-node.mm-editable:focus { cursor: text; outline: 2px solid var(--accent); outline-offset: 1px; }
.mm-node.mm-dragging { cursor: grabbing; opacity: 0.9; box-shadow: 0 2px 8px rgba(0,0,0,0.3); }
/* resize grip (v2.12.271) — a corner triangle. It is a CUE ONLY: `pointer-events:
   none` because the HTML inside a foreignObject wins hit-testing over an SVG
   sibling whatever the paint order (an SVG grip is simply unclickable, verified).
   The grab is handled by the node div on a corner hot-zone in screen px. */
.mm-grip { fill: var(--text-muted); opacity: 0.4; pointer-events: none; }
.mm-node.mm-resizing { opacity: 0.9; box-shadow: 0 2px 8px rgba(0,0,0,0.3); }

/* alert (v2.12.268) — a proactive watcher. Theme-var + the app's level palette. */
.canvas-alert { border-left: 3px solid var(--border-color); border-radius: var(--radius);
    padding: 0.6rem 0.75rem; background: var(--surface); }
.alert-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.alert-glyph { font-size: 1rem; line-height: 1; }
.alert-label { font-weight: 600; color: var(--text); flex: 1; }
.alert-state { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.alert-detail { margin-top: 0.35rem; color: var(--text); font-size: 0.85rem; }
.alert-since { margin-top: 0.3rem; color: var(--text-muted); font-size: 0.75rem; }
.canvas-alert.alert-watching { border-left-color: var(--text-muted); }
.canvas-alert.alert-watching .alert-glyph { animation: alert-breathe 3.6s ease-in-out infinite; }
@keyframes alert-breathe { 0%,100% { opacity: 0.45; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .canvas-alert.alert-watching .alert-glyph { animation: none; } }
.canvas-alert.alert-triggered { animation: alert-flash 0.6s ease; }
@keyframes alert-flash { from { box-shadow: inset 0 0 0 2px currentColor; } to { box-shadow: none; } }
.canvas-alert.alert-info     { border-left-color: var(--accent); }
.canvas-alert.alert-warning  { border-left-color: #d29922; }
.canvas-alert.alert-critical { border-left-color: #f85149; }
.canvas-alert.alert-warning .alert-state,
.canvas-alert.alert-critical .alert-state { color: var(--text); font-weight: 600; }
.canvas-alert.alert-resolved { opacity: 0.72; border-left-color: #3fb950; }
/* add controls (Increment B.1b) — + node / + link */
.mm-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem;
    margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--border-color); }
.mm-tool-btn { font-size: 0.72rem; padding: 0.15rem 0.5rem; cursor: pointer; line-height: 1.3;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border-color); border-radius: 5px; }
.mm-tool-btn:hover { border-color: var(--accent); color: var(--accent); }
.mm-tool-sel, .mm-tool-kind { font-size: 0.72rem; padding: 0.12rem 0.3rem; max-width: 7.5rem;
    background: var(--input-bg, var(--surface)); color: var(--text);
    border: 1px solid var(--border-color); border-radius: 5px; }
.mm-tool-arrow { color: var(--text-muted); font-size: 0.75rem; }

/* 2026-08-06 (v1.2.141 / Inlux v2.12.399) — Exposition et fin de service des
   fiches LLM. Uniquement des variables de theme : plusieurs themes livres sont
   CLAIRS, une couleur en dur y serait illisible. Les teintes d'alerte sont les
   seules valeurs fixes, parce qu'elles doivent rester lisibles sur les deux. */
.llm-card-usage { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.35rem; }
.llm-badge {
    font-size: 0.7rem; padding: 0.1rem 0.45rem; border-radius: 999px;
    background: var(--surface); color: var(--text-muted);
    border: 1px solid var(--border);
}
.llm-badge-fabs { color: var(--text); font-weight: 600; }
.llm-badge-idle { opacity: 0.65; font-style: italic; }
.llm-badge-eos  { border-color: #b8860b; color: #b8860b; }
.llm-badge-soon { border-color: #d97706; color: #d97706; font-weight: 600; }
.llm-badge-dead { border-color: #dc2626; color: #dc2626; font-weight: 600; }

/* 2026-08-06 (v1.2.142) — Registre des LLM en tableau. Uniquement des variables
   de theme : plusieurs themes livres sont CLAIRS. Le conteneur defile
   horizontalement pour lui seul — le corps de page ne doit jamais defiler
   lateralement, meme avec onze colonnes. */
.llm-table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.llm-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.llm-table th, .llm-table td {
    padding: 0.45rem 0.6rem; text-align: left; vertical-align: top;
    border-bottom: 1px solid var(--border);
}
/* v1.2.143 — `nowrap` partout poussait la largeur intrinseque a ~1500 px. Seules
   les colonnes qu'une cesure rendrait illisibles le gardent : les nombres, les
   badges d'echeance et les boutons. Les deux colonnes de texte respirent. */
.llm-table td:nth-child(1), .llm-table td:nth-child(2) { white-space: normal; min-width: 9rem; }
.llm-table th, .llm-table td:nth-child(n+3) { white-space: nowrap; }
.llm-table td code { word-break: break-all; }
.llm-table thead th {
    position: sticky; top: 0; background: var(--surface); z-index: 1;
    font-weight: 600; color: var(--text-muted); font-size: 0.78rem;
}
.llm-table tbody tr:hover { background: var(--surface); }
.llm-t-sortable { cursor: pointer; user-select: none; }
.llm-t-sortable:hover { color: var(--text); }
.llm-t-num { text-align: right; font-variant-numeric: tabular-nums; }
.llm-t-strong { font-weight: 700; color: var(--text); }
.llm-t-name { font-weight: 600; }
.llm-t-sub { font-size: 0.72rem; color: var(--text-muted); margin-top: 0.1rem; }
.llm-t-muted { color: var(--text-muted); }
.llm-t-ok { color: #16a34a; }
.llm-t-inactive { opacity: 0.5; }
.llm-t-act { white-space: nowrap; }
.llm-t-act .btn-small { margin-left: 0.25rem; }
.llm-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 0.35rem; }
.llm-dot-ok { background: #16a34a; }
.llm-dot-ko { background: #dc2626; }

/* v1.2.143 — Le plafond de 800 px vaut pour les formulaires, pas pour un
   tableau de donnees. Bascule par onglet, posee depuis _activateAdminTab. */
.form-card.admin-card.admin-card-wide { max-width: none; }

/* ===================================================================== */
/* v1.2.144 (Inlux v2.12.402/403) — System > Health.                     */
/* Theme variables only, except the status hues: several shipped themes  */
/* are LIGHT, so the colours are mid-tones readable on both, and they    */
/* are the ONLY thing carrying meaning here — never rely on them alone,  */
/* every line also states its status in words.                           */
/* ===================================================================== */
.health-header {
    display: flex; justify-content: space-between; align-items: center;
    flex-wrap: wrap; gap: 0.6rem;
    padding: 0.6rem 0.8rem; margin-bottom: 0.8rem;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius);
}
.health-kpi { font-weight: 700; font-variant-numeric: tabular-nums; }
.health-h {
    margin: 1.2rem 0 0.5rem; font-size: 0.9rem; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.04em;
}
.health-line {
    border: 1px solid var(--border-color); border-left-width: 4px;
    border-radius: var(--radius); padding: 0.6rem 0.8rem;
    margin-bottom: 0.5rem; background: var(--surface);
}
.health-line-head {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
}
.health-dot {
    display: inline-block; width: 9px; height: 9px; border-radius: 50%;
    flex: 0 0 auto;
}
.health-cat {
    font-size: 0.72rem; color: var(--text-muted);
    border: 1px solid var(--border-color); border-radius: 999px;
    padding: 0.05rem 0.45rem;
}
.health-fresh { margin-left: auto; font-size: 0.72rem; color: var(--text-muted); }
.health-summary { margin-top: 0.35rem; color: var(--text); }
.health-fix { margin-top: 0.25rem; font-size: 0.85rem; color: var(--text-muted); }
.health-actions { margin-top: 0.5rem; display: flex; gap: 0.4rem; flex-wrap: wrap; }
.health-snooze-badge {
    font-size: 0.72rem; border-radius: 999px; padding: 0.05rem 0.5rem;
    border: 1px dashed var(--border-color); color: var(--text-muted);
}
/* The burger dot: present enough to notice, quiet enough not to nag. */
.burger-dot {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    /* phantom-var-ok — pastille de 8 px sans texte : aucun contraste
       texte/fond en jeu, seulement sa visibilite propre. */
    background: var(--warning, #b45309); margin-left: 0.4rem;
}

/* v1.2.145 — La couche explicative de System > Health. Repliee par defaut :
   une explication qu'on ne peut pas refermer devient du bruit a la deuxieme
   lecture, et un ecran bruyant ne se lit plus du tout. */
.health-why { margin-top: 0.5rem; }
.health-why > summary {
    cursor: pointer; font-size: 0.8rem; color: var(--link-color, #5ba4f5);
    user-select: none;
}
.health-why > summary:hover { text-decoration: underline; }
.health-why-body {
    margin-top: 0.4rem; padding: 0.5rem 0.7rem;
    border-left: 2px solid var(--border-color);
    font-size: 0.86rem; line-height: 1.5; color: var(--text-muted);
}
.health-why-body p { margin: 0 0 0.5rem; }
.health-why-body p:last-child { margin-bottom: 0; }
/* Les limites ne sont pas une note de bas de page : c'est la moitie honnete
   de l'explication, donc elle se lit aussi bien que le reste. */
.health-limits { color: var(--text); }

/* v1.2.176 — « Qui est concerné » : la preuve d'un contrôle, rendue.
   Repliée comme l'explication — un tableau déplié en permanence sur chaque
   ligne noierait l'écran, et un écran noyé ne se lit plus. Le tableau défile
   dans son propre conteneur : une preuve large ne doit jamais faire défiler
   la page entière. */
.health-who { margin-top: 0.5rem; }
.health-who > summary {
    cursor: pointer; font-size: 0.8rem; color: var(--link-color, #5ba4f5);
    user-select: none;
}
.health-who > summary:hover { text-decoration: underline; }
.health-who-body { margin-top: 0.4rem; overflow-x: auto; }
table.health-evidence {
    border-collapse: collapse; font-size: 0.8rem; width: 100%;
    font-variant-numeric: tabular-nums;
}
table.health-evidence th, table.health-evidence td {
    text-align: left; padding: 0.25rem 0.6rem 0.25rem 0;
    border-bottom: 1px solid var(--border-color); white-space: nowrap;
}
table.health-evidence th { color: var(--text-muted); font-weight: 600; }
.health-evidence-more {
    font-size: 0.78rem; color: var(--text-muted); margin: 0.35rem 0 0;
    font-style: italic;
}

/* v1.2.147 (Inlux v2.12.408) — Catalogue de skills, onglet Management. */
.skill-row {
    border: 1px solid var(--border-color); border-radius: var(--radius);
    padding: 0.6rem 0.8rem; margin-bottom: 0.5rem; background: var(--surface);
}
.skill-row-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.skill-row-desc { margin-top: 0.3rem; color: var(--text-muted); font-size: 0.88rem; }
.skill-row-keys { margin-top: 0.4rem; display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: center; }
.skill-badge {
    font-size: 0.7rem; border-radius: 999px; padding: 0.05rem 0.5rem;
    border: 1px solid var(--border-color); color: var(--text-muted);
}
/* Un skill livre puis modifie ici : l'information qui rend le bouton
   « revenir a la version livree » comprehensible. */
.skill-badge-diverged { border-style: dashed; color: var(--text); }
.skill-badge-local { border-color: var(--link-color, #5ba4f5); }
.skill-key {
    font-size: 0.72rem; padding: 0.05rem 0.4rem; border-radius: var(--radius);
    background: var(--code-bg); color: var(--text-muted);
}
/* Un identifiant secret se distingue d'un simple parametre : c'est ce que
   l'audit de demarrage regarde, et ce qu'on ne doit jamais afficher. */
.skill-key-secret { color: var(--text); border: 1px solid var(--border-color); }
.skill-editor input[type="text"], .skill-editor input:not([type]),
.skill-editor textarea { width: 100%; }
.skill-editor textarea { font-family: monospace; font-size: 0.82rem; }
.skill-cfg-row { display: flex; gap: 0.4rem; align-items: center; margin-bottom: 0.3rem; }
.skill-cfg-row .skill-cfg-name { flex: 0 0 14rem; font-family: monospace; }
.skill-cfg-row .skill-cfg-desc { flex: 1; }
.skill-cfg-secret { font-size: 0.78rem; color: var(--text-muted); white-space: nowrap; }
.skill-ed-actions { margin-top: 0.9rem; display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }

/* v1.2.150 — Ecran document adressable. Meme largeur de lecture que la
   popup qu'il remplace, mais dans la page, donc avec une URL. Couleurs par
   variables uniquement : plusieurs themes d'Inlux sont CLAIRS, un repli
   sombre en dur y serait illisible. */
.doc-body {
    /* v1.2.151 — `.screen` est un flex COLONNE de hauteur 100vh. Sans
       `flex: 1` + `overflow-y: auto`, ce bloc deborde du conteneur et le
       contenu long est simplement COUPE : la page ne defile pas. `min-height:
       0` est indispensable — sans lui, un enfant flex refuse de retrecir
       sous sa hauteur de contenu et l'overflow ne s'active jamais. */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    width: 100%;
    max-width: 900px; margin: 0 auto; padding: 1.5rem 1.5rem 4rem;
    line-height: 1.65; color: var(--text);
}
.doc-body h1, .doc-body h2, .doc-body h3 { color: var(--text); margin-top: 1.8rem; }
.doc-body pre {
    background: var(--bg); border: 1px solid var(--border-color);
    border-radius: var(--radius); padding: 0.8rem; overflow-x: auto;
}
.doc-body code { background: var(--bg); padding: 0.1rem 0.3rem; border-radius: 3px; }
.doc-body pre code { background: none; padding: 0; }

/* 2026-08-18 (v1.2.168) — Références entre documents.
   `.doc-xref` : un lien vers un autre document du corpus. Il garde le style
   de lien du thème ; le soulignement pointillé le distingue d'un lien
   sortant, parce que « ça ouvre un autre document ici » et « ça quitte
   l'application » ne se répondent pas de la même façon.
   `.doc-xref-dead` : une référence qui ne résout pas. Elle est SIGNALÉE
   plutôt que rendue cliquable-vers-nulle-part — le lecteur doit distinguer
   « pas de lien » de « lien cassé », et l'auteur du document doit pouvoir
   le voir sans lire le source. */
.doc-body a.doc-xref { text-decoration-style: dotted; text-underline-offset: 2px; }
.doc-body a.doc-xref code { background: none; padding: 0; color: inherit; }
.doc-body .doc-xref-dead {
    text-decoration: line-through;
    text-decoration-color: var(--danger, currentColor);
    opacity: 0.75;
    cursor: help;
}
.doc-body table { border-collapse: collapse; margin: 1rem 0; display: block; overflow-x: auto; }
.doc-body th, .doc-body td { border: 1px solid var(--border-color); padding: 0.4rem 0.7rem; }
.doc-body blockquote {
    border-left: 3px solid var(--accent); margin: 1rem 0; padding-left: 1rem;
    color: var(--text-muted);
}
.doc-body img { max-width: 100%; }

/* v1.2.153 — « Keep me signed in », sur l'ecran de connexion. Alignee a
   gauche et discrete : c'est un choix, pas un appel a l'action. */
.login-remember {
    display: flex; align-items: center; gap: 0.5rem;
    margin: -0.25rem 0 0.75rem; font-size: 0.85rem;
    color: var(--text-muted); cursor: pointer; user-select: none;
}
.login-remember input { width: auto; margin: 0; cursor: pointer; }

/* v1.2.156 — Detail d'un courrier sortant. Le corps est du texte brut envoye
   a un tiers : `pre` + retour a la ligne pour le rendre tel quel, et une
   hauteur bornee pour qu'un long message ne repousse pas la liste. */
.om-detail {
    width: 100%; max-width: 900px; margin-top: 1rem; padding: 1rem;
    background: var(--surface); border: 1px solid var(--border-color);
    border-radius: var(--radius);
}
.om-detail h4 { margin: 0 0 0.4rem; }
.om-body {
    white-space: pre-wrap; word-break: break-word;
    max-height: 45vh; overflow-y: auto; margin: 0.6rem 0 0;
    padding: 0.8rem; background: var(--bg); border-radius: var(--radius);
    font-size: 0.88rem; line-height: 1.5;
}

/* 2026-09-11 (v1.2.182 / Inlux v2.12.570) — Origine d'un interlocuteur.
   Les comptes NES D'UN MESSAGE entrent dans la liste d'administration. La
   marque doit se lire sans crier : ce n'est pas un avertissement, c'est une
   provenance. Couleurs du theme uniquement — certains themes sont CLAIRS,
   une teinte ecrite en dur y deviendrait illisible. */
.admin-origin-badge {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0 0.35rem;
    border-radius: 3px;
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--text-muted);
    border: 1px solid var(--border);
    background: transparent;
    white-space: nowrap;
}
#admin-origin-summary {
    display: flex; align-items: center; flex-wrap: wrap; gap: 0.2rem;
}
