/* ══════════════════════════════════════════════════════════════════
   Shared application stylesheet — "V2 / Linear Pro" design system.

   This file is loaded by every authenticated page (login, dashboard,
   admin console, project, chat, translator, user pages). The visual
   language was migrated from the "Dashboard V2 Vanilla" reference
   theme: a dense, light-first aesthetic with a single indigo accent,
   hairline borders, soft shadows and a monospace face used for
   numbers / status pills.

   Design decision — token-driven theming:
   The V2 reference ships light-only. We expose BOTH a light and a
   dark variant of the same palette through CSS custom properties so
   the existing `data-theme` toggle (see app-shell.js) keeps working.
   Component rules below NEVER hardcode a colour — they always read a
   token, so flipping `data-theme` re-skins the whole app with zero
   per-component dark-mode overrides.

   Design decision — class names are frozen:
   Every selector that existed in the previous stylesheet is kept,
   because all ~16 shared pages and app-shell.js reference these exact
   class names. Only the visual properties changed; the markup did
   not have to. New tokens from the article-wizard namespace
   (`--ink`, `--line`, `--surface`…) are also defined here so a page
   that mixes both vocabularies still resolves every variable.
   ══════════════════════════════════════════════════════════════════ */

/* Web fonts — Geist (UI sans) + JetBrains Mono (numbers / status).
   The `@import` MUST stay the very first statement in the file:
   CSS spec requires `@import` rules to precede every other rule. */
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');

/* ── Design tokens ─────────────────────────────────────────────────
   The `:root` block is the DARK theme (the app's historical default).
   `[data-theme="light"]` overrides it with the V2 light palette.
   Both blocks define the exact same set of variable names so no
   component can read an undefined token in either mode. */
:root {
  /* Brand / status accents — shared shape, mode-specific values. */
  --primary:      #828ff5;   /* indigo, lifted for contrast on dark */
  --primary-dark: #6e7be8;
  --secondary:    #56aee0;
  --success:      #3fb970;
  --danger:       #f26464;
  --warning:      #e0962e;
  --radius:       10px;

  /* Dark surfaces — a near-black Linear-style canvas. */
  --bg:           #0c0d11;   /* app canvas */
  --bg-card:      #15161b;   /* panels, cards, sidebar, header */
  --bg-input:     #0c0d11;   /* form fields sit flush with the canvas */
  --bg-elevated:  #1c1e25;   /* table headers, hovered rows */
  --border:       #262932;   /* hairline separators */
  --text:         #f4f5f8;
  --text-muted:   #8a93a6;
  --shadow:       0 12px 32px -12px rgba(0, 0, 0, 0.72), 0 2px 6px rgba(0, 0, 0, 0.4);
  --code-bg:      #0a0b0e;
  --hover-bg:     #1c1e25;
  --active-bg:    rgba(130, 143, 245, 0.18);

  /* Soft accent fills — used by badges, pills, sidebar active state.
     On dark these are translucent so they tint the surface beneath. */
  --primary-soft: rgba(130, 143, 245, 0.16);
  --success-soft: rgba(63, 185, 112, 0.16);
  --warn-soft:    rgba(224, 150, 46, 0.18);
  --danger-soft:  rgba(242, 100, 100, 0.16);

  /* ── Article-wizard token namespace ──
     The wizard (`articles-theme.css` + modules/articles/index.html)
     speaks a different variable vocabulary. We alias it onto the V2
     palette here so any page that loads only style.css still resolves
     these names. `articles-theme.css` re-declares them with its own
     values when it is the active stylesheet. */
  --surface:      var(--bg-card);
  --bg-2:         var(--bg-elevated);
  --bg-subtle:    var(--bg-elevated);
  --ink:          var(--text);
  --ink-2:        #c4c9d4;
  --muted:        var(--text-muted);
  --muted-2:      #6b7384;
  --line:         var(--border);
  --line-2:       #1f222a;
  --line-3:       #2f333d;
  --primary-2:    var(--primary);
  --primary-ink:  #c7ccff;
  --accent:       #e8804f;
  --accent-soft:  rgba(232, 128, 79, 0.16);
  --violet:       var(--primary);
  --shadow-sm:    0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md:    var(--shadow);
  --r-sm:         7px;
  --r-md:         10px;
  --r-lg:         12px;
  --r-xl:         16px;

  /* Type faces. Geist for UI, JetBrains Mono for tabular numerals
     and status chips. `--serif` deliberately points at the sans
     stack: the V2 system has no serif voice. */
  --sans:  "Geist", "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:  "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --serif: var(--sans);
}

/* Light theme — the native V2 "Linear Pro" palette. */
[data-theme="light"] {
  --primary:      #5e6ad2;
  --primary-dark: #4e5abf;
  --secondary:    #3d9bd8;
  --success:      #1f9d55;
  --danger:       #dc2626;
  --warning:      #b45309;

  --bg:           #fafafa;
  --bg-card:      #ffffff;
  --bg-input:     #fafafa;
  --bg-elevated:  #f4f5f8;
  --border:       #eceef2;
  --text:         #0b0e14;
  --text-muted:   #8a93a6;
  --shadow:       0 12px 32px -14px rgba(20, 14, 50, 0.18), 0 2px 6px rgba(20, 14, 50, 0.05);
  --code-bg:      #f4f5f8;
  --hover-bg:     #f4f5f8;
  --active-bg:    #eef0ff;

  --primary-soft: #eef0ff;
  --success-soft: #dcfce7;
  --warn-soft:    #fef3c7;
  --danger-soft:  #fee2e2;

  --ink-2:        #4b5266;
  --muted-2:      #a6aebf;
  --line-2:       #f4f5f8;
  --line-3:       #e2e5ec;
  --primary-ink:  #2d3284;
  --accent:       #e2552c;
  --accent-soft:  #ffe9df;
  --shadow-sm:    0 1px 2px rgba(20, 14, 50, 0.05);
}

/* Smooth theme transition — only the elements whose colours actually
   flip get a transition, to avoid a global repaint cost. */
body, .sidebar, .app-topbar, .card, .form-control, .table th, .table td,
.modal-card, .badge, .file-list, .file-preview, .crawl-log, .domain-chip,
.project-card, .sidebar-link, .btn-ghost, .header, .header-action,
.user-dropdown, .notif-dropdown {
  transition: background-color 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}

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

body {
  font-family: var(--sans);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  line-height: 1.55;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ── Layout ────────────────────────────────────────────────────────── */
.container { max-width: 1100px; margin: 0 auto; padding: 0 1.5rem; }

/* ── Cards ─────────────────────────────────────────────────────────── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  /* V2 cards lean on the hairline border, not a heavy drop shadow. */
  box-shadow: none;
}

/* ── Buttons ───────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.95rem;
  border-radius: 8px;
  /* Default button = neutral surface with a hairline border (the V2
     "secondary" affordance). Modifier classes override below. */
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  line-height: 1.4;
  transition: background 0.14s, border-color 0.14s, color 0.14s;
  text-decoration: none;
}
.btn:hover { background: var(--hover-bg); }
.btn-primary { background: var(--primary); color: #fff; border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-dark); border-color: var(--primary-dark); }
.btn-danger  { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover { filter: brightness(0.93); }
/* Ghost = chrome-free; used for secondary modal actions and icon rows. */
.btn-ghost   { background: transparent; color: var(--text-muted); border-color: transparent; }
.btn-ghost:hover { background: var(--hover-bg); color: var(--text); }
.btn-sm { padding: 0.3rem 0.7rem; font-size: 0.78rem; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* ── Forms ─────────────────────────────────────────────────────────── */
.form-group { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 1rem; }
.form-group label { font-size: 0.82rem; color: var(--text-muted); font-weight: 500; }
.form-control {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 0.55rem 0.85rem;
  font-family: inherit;
  font-size: 0.86rem;
  transition: border-color 0.14s, box-shadow 0.14s;
  outline: none;
  width: 100%;
}
/* Focus ring — a 3px soft halo in the brand colour, the V2 signature. */
.form-control:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.form-control::placeholder { color: var(--text-muted); }

/* ── Badges ────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  font-family: var(--mono);
  letter-spacing: 0.01em;
}
/* Role + state badges all share the soft-fill + saturated-ink recipe.
   The ink colour token (e.g. --primary) is light-tinted on dark and
   fully saturated on light, so one rule reads well in both modes. */
.badge-admin   { background: var(--primary-soft); color: var(--primary); }
.badge-user    { background: var(--primary-soft); color: var(--primary); }
.badge-client  { background: var(--success-soft); color: var(--success); }
.badge-active  { background: var(--success-soft); color: var(--success); }
.badge-inactive{ background: var(--danger-soft);  color: var(--danger); }

/* ── Alerts ────────────────────────────────────────────────────────── */
.alert {
  padding: 0.7rem 0.95rem;
  border-radius: 8px;
  font-size: 0.85rem;
  margin-bottom: 1rem;
}
.alert-error   { background: var(--danger-soft);  border: 1px solid var(--danger);  color: var(--danger); }
.alert-success { background: var(--success-soft); border: 1px solid var(--success); color: var(--success); }
.alert-info    { background: var(--primary-soft); border: 1px solid var(--primary); color: var(--primary); }

/* ── Spinner ───────────────────────────────────────────────────────── */
.spinner {
  width: 20px; height: 20px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Table ─────────────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.table th {
  background: var(--bg-elevated);
  padding: 0.7rem 1rem;
  text-align: left;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
}
.table td { padding: 0.7rem 1rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tr:hover td { background: var(--hover-bg); }

/* ── Navbar ────────────────────────────────────────────────────────── */
.navbar {
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  padding: 1rem 0;
  position: sticky;
  top: 0;
  z-index: 100;
}
.navbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.navbar-brand {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
}
.navbar-user { display: flex; align-items: center; gap: 1rem; }

/* ── Progress bar ──────────────────────────────────────────────────── */
.progress { background: var(--border); border-radius: 999px; height: 6px; overflow: hidden; }
.progress-bar {
  height: 100%;
  background: var(--primary);
  border-radius: 999px;
  transition: width 0.3s;
}

/* ── Chat bubbles ──────────────────────────────────────────────────── */
.message { display: flex; gap: 0.75rem; margin-bottom: 1.25rem; align-items: flex-start; }
.message.user { flex-direction: row-reverse; }

.message-avatar {
  width: 34px; height: 34px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1rem;
  flex-shrink: 0;
}
.message.user .message-avatar { background: var(--primary); color: #fff; }
.message.bot  .message-avatar { background: var(--bg-elevated); border: 1px solid var(--border); }

.message-bubble {
  max-width: 72%;
  padding: 0.75rem 1rem;
  border-radius: 12px;
  font-size: 0.88rem;
  line-height: 1.6;
}
.message.user .message-bubble {
  background: var(--primary);
  color: #fff;
  border-radius: 12px 4px 12px 12px;
}
.message.bot .message-bubble {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px 12px 12px 12px;
}

.message-sources {
  font-size: 0.74rem;
  color: var(--text-muted);
  margin-top: 0.4rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.source-link {
  color: var(--primary);
  text-decoration: none;
  background: var(--primary-soft);
  padding: 0.12rem 0.5rem;
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 0.72rem;
}
.source-link:hover { text-decoration: underline; }

/* ── Typing indicator ──────────────────────────────────────────────── */
.typing { display: flex; gap: 5px; align-items: center; padding: 0.5rem; }
.typing span {
  width: 7px; height: 7px;
  background: var(--text-muted);
  border-radius: 50%;
  animation: bounce 1.2s infinite;
}
.typing span:nth-child(2) { animation-delay: 0.2s; }
.typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes bounce { 0%,60%,100% { transform: translateY(0); } 30% { transform: translateY(-7px); } }

/* ── Stats cards ───────────────────────────────────────────────────── */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; }
.stat-card { text-align: center; padding: 1.5rem; }
.stat-value {
  font-size: 1.9rem;
  font-weight: 600;
  color: var(--text);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.stat-label {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-top: 0.3rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}

/* ── Scrollbar ─────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 7px; height: 7px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* ── Login page ────────────────────────────────────────────────────── */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(ellipse at 50% -10%, var(--primary-soft), transparent 55%),
    var(--bg);
}
.login-card { width: 100%; max-width: 410px; }
.login-logo {
  font-size: 2.2rem;
  text-align: center;
  margin-bottom: 0.5rem;
}
.login-title {
  font-size: 1.4rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  text-align: center;
  margin-bottom: 0.25rem;
}
.login-subtitle { color: var(--text-muted); text-align: center; font-size: 0.86rem; margin-bottom: 2rem; }

/* ── App shell with sidebar ───────────────────────────────────────── */
.app-shell { display: flex; min-height: 100vh; }
.sidebar {
  width: 240px;
  background: var(--bg-card);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  flex-shrink: 0;
  transition: width 0.22s ease;
  z-index: 90;
}
/* Sidebar collapsed (icons only) */
.sidebar.collapsed { width: 64px; }
.sidebar.collapsed .sidebar-brand-text,
.sidebar.collapsed .sidebar-section,
.sidebar.collapsed .sidebar-link span:not(.sidebar-icon),
.sidebar.collapsed .sidebar-link .arrow,
.sidebar.collapsed .sidebar-foot,
.sidebar.collapsed .submenu-toggle .arrow,
.sidebar.collapsed details > div.config-submenu,
.sidebar.collapsed details > div.ai-search-submenu { display: none; }
.sidebar.collapsed .sidebar-link,
.sidebar.collapsed .submenu-toggle {
  justify-content: center;
  padding: 0.5rem;
}
.sidebar.collapsed .sidebar-brand { justify-content: center; padding: 1rem 0.5rem; }
.sidebar.collapsed details > summary { padding: 0; }

/* ── Sidebar « AI Search » submenu (V2 grouped layout) ────────────────
   Lives at the shared layer because the markup is owned by
   `app-shell.js:PROJECT_NAV_HTML`. Every page using
   `initAppShell({navScope:'project'})` inherits these rules for free.
   Native browser disclosure triangle is hidden ; our `.arrow` span is
   the visual indicator and rotates 90° when the <details> is open. */
.submenu-toggle {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.5rem 0.65rem;
  border-radius: 7px;
  color: var(--text-muted);
  font-size: 0.88rem;
  cursor: pointer;
  user-select: none;
}
.submenu-toggle:hover { background: var(--hover-bg); color: var(--text); }
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }
.arrow {
  display: inline-block; transition: transform 0.15s;
  font-size: 0.7rem; margin-left: auto;
}
details[open] > summary .arrow { transform: rotate(90deg); }
.ai-search-submenu { padding-left: 1.2rem; }
/* Highlight the AI Search header in full ink when any child below
   is active — helps the user spot the active group at a glance. */
details:has(.sidebar-link.active) > .submenu-toggle {
  color: var(--text);
}

.sidebar-brand {
  padding: 0 1.1rem;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  display: flex; align-items: center; gap: 0.55rem;
  border-bottom: 1px solid var(--border);
  height: 56px;
  white-space: nowrap;
  overflow: hidden;
}
.sidebar-nav { flex: 1; padding: 0.75rem 0.5rem; overflow-y: auto; }
.sidebar-section {
  font-size: 0.65rem;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
  padding: 0.7rem 0.6rem 0.3rem;
  letter-spacing: 0.07em;
}
.sidebar-link {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.5rem 0.65rem;
  border-radius: 7px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.85rem;
  margin-bottom: 0.1rem;
  cursor: pointer;
  white-space: nowrap;
}
.sidebar-link:hover { background: var(--hover-bg); color: var(--text); }
.sidebar-link.active { background: var(--active-bg); color: var(--primary); font-weight: 500; }
/* Holds either an emoji glyph or a V2 SVG icon (swapped in by
   app-shell.js applyNavIcons) — flex-centred so both align cleanly. */
.sidebar-icon {
  width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.95rem;
  flex-shrink: 0;
  color: var(--text-muted);
}
.sidebar-link.active .sidebar-icon,
.sidebar-link:hover .sidebar-icon { color: inherit; }
.sidebar-icon svg { display: block; }
.sidebar-foot {
  padding: 0.85rem 1rem;
  border-top: 1px solid var(--border);
  font-size: 0.76rem;
  color: var(--text-muted);
}
.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* ── Header ─────────────────────────────────────────────────────────── */
.header {
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  padding: 0 1rem;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 80;
  gap: 1rem;
}
.header-left, .header-right { display: flex; align-items: center; gap: 0.4rem; }
.header-title { font-size: 0.95rem; font-weight: 600; letter-spacing: -0.01em; color: var(--text); }
.header-subtitle { font-size: 0.74rem; color: var(--text-muted); }
.header-action {
  background: transparent;
  border: 1px solid transparent;
  width: 34px; height: 34px;
  border-radius: 7px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted);
  font-size: 0.95rem;
  position: relative;
}
.header-action:hover { background: var(--hover-bg); color: var(--text); }

/* Topbar "+ Nouveau projet" / "+ Nouvel article" CTAs — the V2
   reference template puts them at the very right of the header,
   between the notifications and the user. The ghost variant uses a
   plain hairline border ; the primary variant inverts (indigo bg). */
.header-cta {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  height: 32px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.header-cta:hover { background: var(--hover-bg); border-color: var(--text-muted); }
.header-cta.primary {
  background: var(--primary, #5E6AD2);
  border-color: var(--primary, #5E6AD2);
  color: white;
}
.header-cta.primary:hover { filter: brightness(1.08); }
/* On narrow viewports, drop the label to keep the icon-only chip. */
@media (max-width: 1100px) { .header-cta span { display: none; } }
@media (max-width: 720px)  { .header-cta { display: none; } }
.header-action.has-badge::after {
  content: ''; position: absolute;
  top: 7px; right: 8px;
  width: 7px; height: 7px;
  background: var(--danger);
  border-radius: 50%;
  border: 2px solid var(--bg-card);
}

/* User trigger */
.user-trigger {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.25rem 0.5rem 0.25rem 0.3rem;
  border-radius: 8px;
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text);
  font-size: 0.83rem;
}
.user-trigger:hover { background: var(--hover-bg); }
.user-avatar {
  width: 28px; height: 28px;
  border-radius: 7px;
  background: linear-gradient(135deg, #ffc58e, #e2552c);
  color: #fff;
  font-weight: 600;
  font-size: 0.74rem;
  display: flex; align-items: center; justify-content: center;
  text-transform: uppercase;
  flex-shrink: 0;
}
.user-trigger-name { font-weight: 500; }
.user-trigger-role { font-size: 0.68rem; color: var(--text-muted); }

/* Dropdowns */
.dropdown-anchor { position: relative; }
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); right: 0;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  min-width: 240px;
  padding: 0.35rem;
  z-index: 200;
  display: none;
}
.dropdown-menu.open { display: block; }
.dropdown-header {
  padding: 0.55rem 0.7rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.3rem;
}
.dropdown-header strong { display: block; font-size: 0.88rem; }
.dropdown-header span { font-size: 0.76rem; color: var(--text-muted); }
.dropdown-item {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  color: var(--text);
  font-size: 0.84rem;
  cursor: pointer;
  background: transparent;
  border: none;
  width: 100%;
  text-align: left;
  text-decoration: none;
  font-family: inherit;
}
.dropdown-item:hover { background: var(--hover-bg); }
.dropdown-item .icon { width: 18px; text-align: center; color: var(--text-muted); }
.dropdown-divider { height: 1px; background: var(--border); margin: 0.3rem 0; }

/* Notifications dropdown */
.notif-dropdown { width: 320px; max-height: 400px; overflow-y: auto; }
.notif-empty {
  padding: 2rem 1rem; text-align: center; color: var(--text-muted);
  font-size: 0.84rem;
}

.app-content { padding: 1.5rem; flex: 1; }
/* The breadcrumb bar (feature 046) is injected as the content column's first
   child and brings its own top padding, so the column's full 1.5rem top padding
   leaves an oversized gap below the header. Tighten the top padding only when the
   bar leads the column; non-breadcrumb pages keep the 1.5rem. */
.app-content:has(> .page-crumbbar) { padding-top: 0.5rem; }

/* Mobile : sidebar overlay */
@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    left: 0; top: 0;
    transform: translateX(-100%);
    box-shadow: var(--shadow);
  }
  .sidebar.mobile-open { transform: translateX(0); }
  .sidebar.collapsed { width: 240px; transform: translateX(-100%); }
  .sidebar.collapsed.mobile-open { transform: translateX(0); }
  .sidebar.collapsed .sidebar-brand-text,
  .sidebar.collapsed .sidebar-section,
  .sidebar.collapsed .sidebar-link span:not(.sidebar-icon),
  .sidebar.collapsed .sidebar-foot { display: block; }
  .sidebar.collapsed .sidebar-link { justify-content: flex-start; padding: 0.5rem 0.65rem; }
  .sidebar-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 85;
    display: none;
  }
  .sidebar-overlay.show { display: block; }
}

/* ── Modal ────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(8, 9, 14, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
  padding: 1rem;
  backdrop-filter: blur(3px);
}
.modal-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  width: 100%;
  max-width: 520px;
  box-shadow: var(--shadow);
  max-height: 90vh;
  overflow-y: auto;
}
.modal-card.modal-md { max-width: 640px; }
.modal-card.modal-lg { max-width: 820px; }
.modal-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 1rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--border);
}
.modal-title { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; }
.modal-close {
  background: none; border: none; color: var(--text-muted); cursor: pointer;
  font-size: 1.35rem; line-height: 1; padding: 0.1rem 0.4rem; border-radius: 6px;
}
.modal-close:hover { color: var(--text); background: var(--hover-bg); }
.modal-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.2rem; }

/* ── Project cards ────────────────────────────────────────────────── */
.project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 1rem; }
.project-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.15rem;
  display: flex; flex-direction: column;
  transition: border-color 0.14s, box-shadow 0.14s;
  cursor: pointer;
  position: relative;
}
.project-card:hover { border-color: var(--primary); box-shadow: var(--shadow); }
.project-card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.4rem; }
.project-card-title { font-size: 0.98rem; font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; }
.project-card-sector {
  display: inline-block;
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 0.68rem;
  font-weight: 600;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  margin-bottom: 0.5rem;
}
.project-card-desc {
  font-size: 0.82rem;
  color: var(--text-muted);
  line-height: 1.5;
  flex: 1;
  margin-bottom: 0.85rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.project-card-foot {
  display: flex; justify-content: space-between; align-items: center;
  padding-top: 0.6rem;
  /* Token-driven so the divider tracks the active theme (the old
     rule hardcoded a dark-only slate colour). */
  border-top: 1px solid var(--border);
  font-size: 0.73rem;
  color: var(--text-muted);
}
.project-actions { display: flex; gap: 0.3rem; }
.project-actions .btn { padding: 0.25rem 0.55rem; font-size: 0.72rem; }
.empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-muted);
}
.empty-state-icon { font-size: 2.4rem; margin-bottom: 0.5rem; opacity: 0.45; }

/* ── Page header ──────────────────────────────────────────────────── */
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.page-header-title { font-size: 1.3rem; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 0.2rem; }
.page-header-sub { color: var(--text-muted); font-size: 0.84rem; }

/* ── Filter bar ───────────────────────────────────────────────────── */
.filter-bar {
  display: flex; gap: 0.5rem; flex-wrap: wrap;
  margin-bottom: 1.2rem;
}
.filter-bar .form-control { width: auto; max-width: 250px; }

/* ── Code blocks ──────────────────────────────────────────────────── */
code, pre {
  font-family: var(--mono);
}
pre, .code-block {
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 8px;
}


/* ──────────────────────────────────────────────────────────────────
   RTL support (Phase 5.A — Arabic & co.)
   ──────────────────────────────────────────────────────────────────
   Most of the layout uses flexbox + logical properties (gap, padding)
   so it flips automatically when `<html dir="rtl">` is set by
   i18n.js. The rules below target the ~handful of places where we
   used hardcoded `left/right` properties or `text-align: left` —
   each rule mirrors the original so RTL users see the same visual
   structure on the other side.

   Triggered by `<html dir="rtl">` (set by `_applyDirection` in
   `i18n.js`). Falls back to LTR otherwise — no impact on existing
   FR/EN/RU layouts. */

/* (1) Sidebar — original had `border-right` to separate from the
   content. Mirror so the visible separator stays on the side that
   borders the main content. */
[dir="rtl"] .sidebar {
  border-right: none;
  border-left: 1px solid var(--border);
}

/* (2) Header dropdowns — anchored to the right in LTR (e.g. user
   menu, language picker). Flip so they sit on the LEFT in RTL,
   matching the user-icon position which auto-flips via flexbox. */
[dir="rtl"] .header .dropdown-menu {
  right: auto;
  left: 0;
}

/* (3) Modal close button — top-right corner in LTR. Mirror so it
   stays on the corner closest to the reading direction's end. */
[dir="rtl"] .modal-close {
  right: auto;
  left: 8px;
}

/* (4) Mobile sidebar overlay — slides in from the LEFT in LTR.
   In RTL it should slide in from the RIGHT to match the sidebar's
   new position. */
[dir="rtl"] .sidebar.mobile-open {
  left: auto;
  right: 0;
}

/* (5) Text alignment — explicit `text-align: left` rules (markdown
   paragraphs + table cells) flip to follow reading direction. */
[dir="rtl"] .markdown-body,
[dir="rtl"] .table th,
[dir="rtl"] .table td {
  text-align: right;
}

/* (6) Numbers + monospace stay LTR inside RTL paragraphs (e.g.
   usage counters "5 / 1 000 tk", prices "990,00 ₽"). Without the
   `unicode-bidi: isolate` + `direction: ltr` override, digits get
   reversed inside RTL flow which is unreadable. Applied only to
   elements most likely to carry numeric / ASCII content. */
[dir="rtl"] .usage-current-over-limit,
[dir="rtl"] .badge-unlimited,
[dir="rtl"] .badge-metered,
[dir="rtl"] code,
[dir="rtl"] pre {
  unicode-bidi: isolate;
  direction: ltr;
  display: inline-block;
}

/* (7) Form inputs — text content follows reading direction, but
   intrinsically-LTR fields (email, URL, number, tel) stay LTR
   because their content is ASCII-only. Without this, an email
   field would render the cursor on the right and read e.g.
   "moc.elpmaxe@resu" which is unusable. */
[dir="rtl"] .form-control { text-align: right; }
[dir="rtl"] input[type="email"],
[dir="rtl"] input[type="url"],
[dir="rtl"] input[type="number"],
[dir="rtl"] input[type="tel"],
[dir="rtl"] input[type="password"] {
  text-align: left;
  direction: ltr;
}


/* ══════════════════════════════════════════════════════════════════
   V2 application shell — sidebar + topbar
   ──────────────────────────────────────────────────────────────────
   The whole shell (sidebar nav, workspace switcher, user menu,
   topbar with breadcrumbs / search / language switcher) is injected
   by `app-shell.js` into the `.sidebar` and `#app-header` elements
   every authenticated page already provides. These rules reproduce
   the "Dashboard V2 Vanilla" reference layout. All colours are
   tokens, so the light / dark toggle re-skins the shell for free.
   ══════════════════════════════════════════════════════════════════ */

/* The sidebar is a 4-zone vertical flex column:
   brand (fixed) · workspace switcher (fixed) · nav (scrolls) ·
   user row (pinned to the bottom). */
.sidebar { padding: 0; gap: 0; }

/* ── Brand zone ── */
.sidebar-brand { gap: 0.5rem; }
.sb-brand-mark {
  width: 24px; height: 24px;
  border-radius: 7px;
  background: var(--primary);
  color: #fff;
  display: grid; place-items: center;
  font-family: var(--mono);
  font-weight: 700; font-size: 0.72rem;
  flex-shrink: 0;
}
.sidebar-brand-text { flex: 1; overflow: hidden; text-overflow: ellipsis; }
/* Collapse toggle — sits at the end of the brand row. When the
   sidebar is collapsed it expands to cover the whole brand cell so
   the only affordance left (the chevron) is easy to hit. */
.sb-collapse {
  margin-left: auto;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: 6px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  flex-shrink: 0;
}
.sb-collapse:hover { background: var(--hover-bg); color: var(--text); }
.sb-collapse .ico-expand { display: none; }

/* ── Workspace (project) switcher ── */
.sb-ws { position: relative; padding: 0.6rem 0.5rem 0.2rem; }
.sb-ws-trigger {
  width: 100%;
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  color: var(--text);
  font-family: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}
.sb-ws-trigger:hover { background: var(--hover-bg); }
.sb-ws.is-open .sb-ws-trigger { border-color: var(--primary); }
.sb-ws-av {
  width: 18px; height: 18px;
  border-radius: 5px;
  background: linear-gradient(135deg, #ffc58e, #e2552c);
  flex-shrink: 0;
  display: grid; place-items: center;
  color: #fff; font-family: var(--mono); font-size: 0.6rem; font-weight: 700;
}
.sb-ws-name {
  flex: 1; min-width: 0;
  font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: left;
}
.sb-ws-plan {
  font-size: 0.6rem; font-weight: 700;
  font-family: var(--mono);
  padding: 0.05rem 0.3rem;
  background: var(--primary-soft);
  color: var(--primary);
  border-radius: 4px;
}
.sb-ws-chev { color: var(--text-muted); transition: transform 0.18s; flex-shrink: 0; }
.sb-ws.is-open .sb-ws-chev { transform: rotate(180deg); }

/* Workspace popup — `position: fixed`, anchored by JS to the
   trigger so it never gets clipped by the sidebar's overflow. */
.sb-ws-menu {
  position: fixed;
  width: 270px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 0.35rem;
  z-index: 300;
  display: none;
}
.sb-ws.is-open .sb-ws-menu { display: block; }
.sb-ws-head {
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 700; color: var(--text-muted);
  padding: 0.5rem 0.5rem 0.3rem;
}
.sb-ws-search {
  display: flex; align-items: center; gap: 0.4rem;
  margin: 0.2rem 0.15rem 0.35rem;
  padding: 0.35rem 0.5rem;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 7px;
}
.sb-ws-search input {
  flex: 1; min-width: 0;
  border: none; outline: none; background: transparent;
  font-family: inherit; font-size: 0.78rem; color: var(--text);
}
.sb-ws-item {
  display: grid; grid-template-columns: 26px 1fr 16px;
  gap: 0.5rem; align-items: center;
  padding: 0.4rem 0.5rem;
  border-radius: 7px;
  cursor: pointer;
}
.sb-ws-item:hover { background: var(--hover-bg); }
.sb-ws-item.is-current { background: var(--active-bg); }
.sb-ws-item .av {
  width: 26px; height: 26px;
  border-radius: 6px;
  display: grid; place-items: center;
  color: #fff; font-family: var(--mono);
  font-size: 0.66rem; font-weight: 700;
}
.sb-ws-item .name {
  font-size: 0.8rem; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-ws-item .sub {
  font-size: 0.68rem; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-ws-item .check { color: var(--primary); opacity: 0; }
.sb-ws-item.is-current .check { opacity: 1; }
.sb-ws-empty { padding: 0.8rem 0.5rem; text-align: center; font-size: 0.76rem; color: var(--text-muted); }
.sb-ws-sep { height: 1px; background: var(--border); margin: 0.3rem -0.35rem; }

/* ── Nav ── */
.sidebar-nav { flex: 1; padding: 0.5rem 0.5rem 0.75rem; }
.sidebar-section {
  display: flex; align-items: center; justify-content: space-between;
}

/* ── User row (pinned bottom) ── */
.sb-user {
  position: relative;
  display: flex; align-items: center; gap: 0.5rem;
  margin: 0 0.5rem;
  padding: 0.6rem 0.4rem;
  border-top: 1px solid var(--border);
}
.sb-user-info { flex: 1; min-width: 0; line-height: 1.2; }
.sb-user-name {
  font-size: 0.8rem; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-user-role { font-size: 0.68rem; color: var(--text-muted); }
.sb-user-dots {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 6px;
  border: none; background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  flex-shrink: 0;
}
.sb-user-dots:hover,
.sb-user.is-open .sb-user-dots { background: var(--hover-bg); color: var(--text); }

/* User menu popup — `position: fixed`, anchored by JS above the row. */
.sb-user-menu {
  position: fixed;
  width: 230px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 0.35rem;
  z-index: 300;
  display: none;
}
.sb-user.is-open .sb-user-menu { display: block; }
.sb-user-menu .head {
  display: flex; gap: 0.55rem;
  padding: 0.5rem 0.5rem 0.65rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.25rem;
}
.sb-user-menu .head .avatar {
  width: 34px; height: 34px;
  border-radius: 8px;
  background: linear-gradient(135deg, #ffc58e, #e2552c);
  color: #fff;
  display: grid; place-items: center;
  font-size: 0.78rem; font-weight: 600;
  flex-shrink: 0;
}
.sb-user-menu .head .who { min-width: 0; flex: 1; }
.sb-user-menu .head .name { font-size: 0.82rem; font-weight: 600; }
.sb-user-menu .head .mail {
  font-size: 0.68rem; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-user-menu .head .badge { margin-top: 0.25rem; }
.sb-user-menu .item {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.45rem 0.5rem;
  border-radius: 6px;
  font-size: 0.8rem;
  color: var(--text);
  cursor: pointer;
  background: transparent; border: none; width: 100%; text-align: left;
  font-family: inherit;
  text-decoration: none;
}
.sb-user-menu .item:hover { background: var(--hover-bg); }
.sb-user-menu .item .ico { width: 16px; text-align: center; color: var(--text-muted); flex-shrink: 0; }
.sb-user-menu .item.danger,
.sb-user-menu .item.danger .ico { color: var(--danger); }
.sb-user-menu .item.danger:hover { background: var(--danger-soft); }
.sb-user-menu .sep { height: 1px; background: var(--border); margin: 0.3rem -0.35rem; }

/* ── Collapsed sidebar — hide every label, keep icons centred ── */
.sidebar.collapsed .sb-brand-mark { display: grid; }
.sidebar.collapsed .sb-ws { padding: 0.4rem 0.5rem 0.2rem; }
.sidebar.collapsed .sb-ws-trigger { justify-content: center; padding: 0.35rem; }
.sidebar.collapsed .sb-ws-name,
.sidebar.collapsed .sb-ws-plan,
.sidebar.collapsed .sb-ws-chev,
.sidebar.collapsed .sb-user-info,
.sidebar.collapsed .sb-user-dots { display: none; }
.sidebar.collapsed .sb-user { justify-content: center; }
.sidebar.collapsed .sb-collapse .ico-collapse { display: none; }
.sidebar.collapsed .sb-collapse .ico-expand { display: block; }

/* ── Topbar (injected into `#app-header`, class `.header`) ── */
.crumbs {
  display: flex; align-items: center; gap: 0.4rem;
  font-size: 0.8rem; color: var(--text-muted);
  min-width: 0;
}
.crumbs strong {
  color: var(--text); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.crumbs .sep { color: var(--border); }
.crumbs .root { white-space: nowrap; }
/* Centre search affordance — opens the platform search (decorative
   for now: a non-interactive cue matching the V2 layout). */
.tb-search {
  flex: 1; max-width: 360px;
  margin: 0 auto;
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.4rem 0.65rem;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text-muted);
  font-size: 0.78rem;
}
.tb-search .kbd {
  margin-left: auto;
  padding: 0.05rem 0.3rem;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--mono); font-size: 0.62rem;
}
@media (max-width: 900px) { .tb-search { display: none; } }
/* The topbar hamburger is a mobile-only affordance — on desktop the
   collapse chevron lives in the sidebar brand instead. */
#sidebar-toggle-mobile { display: none; }
@media (max-width: 768px) { #sidebar-toggle-mobile { display: flex; } }

/* ── Language switcher (topbar) ── */
.lang { position: relative; }
.lang-trigger {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--border);
  background: var(--bg-card);
  border-radius: 7px;
  color: var(--text);
  font-family: inherit; font-size: 0.76rem; font-weight: 500;
  cursor: pointer;
}
.lang-trigger:hover { background: var(--hover-bg); }
.lang.is-open .lang-trigger { border-color: var(--primary); }
.lang-flag {
  width: 18px; height: 18px;
  border-radius: 50%;
  overflow: hidden;
  display: grid; place-items: center;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.08) inset;
  flex-shrink: 0;
}
.lang-flag svg { width: 100%; height: 100%; display: block; }
/* Shows the full native language name ("Français"), not the code. */
.lang-code { font-size: 0.76rem; color: var(--text); font-weight: 500; }
.lang-chev { color: var(--text-muted); transition: transform 0.18s; }
.lang.is-open .lang-chev { transform: rotate(180deg); }
.lang-menu {
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 230px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 0.35rem;
  z-index: 300;
  display: none;
  max-height: 340px; overflow-y: auto;
}
.lang.is-open .lang-menu { display: block; }
.lang-section {
  font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 700; color: var(--text-muted);
  padding: 0.4rem 0.5rem 0.25rem;
}
.lang-item {
  display: grid; grid-template-columns: 20px 1fr 14px;
  gap: 0.5rem; align-items: center;
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.8rem;
}
.lang-item:hover { background: var(--hover-bg); }
.lang-item .lang-flag { width: 20px; height: 20px; }
.lang-item .check { color: var(--primary); opacity: 0; }
.lang-item.is-current .check { opacity: 1; }

/* RTL — mirror the topbar popups + sidebar popups to the other edge. */
[dir="rtl"] .lang-menu { right: auto; left: 0; }

/* ── Admin LLM des articles (Phase « LLM Failover ») ──────────────────
   Per-step fallback chain editor : a list of « hops » (provider+model
   pairs) the admin can drag-to-reorder, add, and remove. Layout is a
   compact CSS grid so a hop fits cleanly in a single row even on
   narrow viewports. */
.artllm-step-card .artllm-hops {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 0.3rem;
}
/* Phase F UI polish — flex layout (was a too-tight 5-col grid that
   collapsed visually when the inner selects fought for space). The
   handle group is fixed left, the two comboboxes take the middle in a
   2-col mini-grid with proper breathing room, the « Retirer » button
   sits on the right with a real text label, not a 28px square.
   Selectors are scoped to .artllm-step-card to lift specificity
   above any generic dashboard rules that may have crept in. */
.artllm-step-card .artllm-hop {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface, #fff);
  transition: background .12s ease, border-color .12s ease, opacity .12s ease;
}
.artllm-step-card .artllm-hop:hover {
  border-color: var(--primary);
}

.artllm-step-card .artllm-hop-head {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* The two combos share the middle, each takes half. `min-width: 0` on
   the grid item is the standard fix so flex children can shrink below
   their content's intrinsic width (otherwise long model names blow up
   the layout). */
.artllm-step-card .artllm-hop-fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 14px;
  flex: 1 1 auto;
  min-width: 0;
}
/* Phase F: drag targets the wrapper now (so the stats chip strip
   moves with its hop on reorder), but the inner .artllm-hop is the
   visual surface, so we mirror the cue on both. */
.artllm-hop-wrap {
  display: block;
}
.artllm-hop-wrap.dragging,
.artllm-hop.dragging {
  opacity: 0.4;
}
.artllm-hop-wrap.drop-above > .artllm-hop,
.artllm-hop.drop-above {
  /* Show where the dragged hop would land — soft purple bar above. */
  border-top: 2px solid var(--primary);
  padding-top: 4px;
}

/* Phase F « LLM Failover » — counter chip strip under each hop.
   Three pills + a success-rate suffix, all on one line. Kept small
   so a card with 5 hops still fits the viewport without scrolling. */
.artllm-hop-stats {
  display: flex;
  align-items: center;
  gap: 6px;
  /* Indent so the chips line up under the fields (= past the handle +
     number group on the left of the hop). The number is approximate
     because the handle group's gap is small — eyeballed for visual
     alignment with the combobox column. */
  padding: 4px 14px 8px 76px;
  font-size: 0.72rem;
  color: var(--text-muted);
  flex-wrap: wrap;
}
.artllm-hop-stats-empty {
  font-style: italic;
  opacity: 0.6;
}
.artllm-stat {
  padding: 1px 6px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.04);
  font-variant-numeric: tabular-nums;
}
.artllm-stat-ok {
  color: #16a34a;
  background: rgba(34, 197, 94, 0.10);
}
.artllm-stat-failover {
  color: #d97706;
  background: rgba(245, 158, 11, 0.10);
}
.artllm-stat-exhausted {
  color: #dc2626;
  background: rgba(239, 68, 68, 0.10);
}
.artllm-stat-rate {
  /* The aggregate rate is informational — render it without a chip. */
  opacity: 0.75;
}
.artllm-hop-handle {
  color: var(--text-muted);
  cursor: grab;
  user-select: none;
  text-align: center;
  font-size: 14px;
  line-height: 1;
}
.artllm-hop-handle:active {
  cursor: grabbing;
}
.artllm-hop-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.05);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
}
/* Bigger, label-bearing « Retirer » button — replaces the 28px ×
   square that was hard to hit and unclear out of context. */
.artllm-hop-del {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  height: 38px;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.artllm-hop-del:hover {
  color: var(--danger, #d93b3b);
  border-color: var(--danger, #d93b3b);
  background: rgba(217, 59, 59, 0.08);
}
.artllm-hop-del-icon {
  font-size: 14px;
  line-height: 1;
}
/* On narrow screens the text disappears, the icon remains tappable. */
@media (max-width: 720px) {
  .artllm-hop-del-label { display: none; }
  .artllm-hop-del { padding: 0; width: 38px; justify-content: center; }
}

/* ── Searchable combobox ────────────────────────────────────────────
   Custom select : a styled button + a popup with a search input and a
   filterable option list. Used for provider and model on the LLM
   failover form because both lists can grow long (esp. model). */
.artllm-combo {
  position: relative;
  min-width: 0;
}
.artllm-combo-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 9px 12px;
  height: 38px;
  font-size: 0.88rem;
  text-align: left;
  color: var(--text);
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.artllm-combo-btn:hover {
  border-color: var(--primary);
}
.artllm-combo.is-open > .artllm-combo-btn {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(106, 70, 193, 0.12);
}
.artllm-combo-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}
.artllm-combo-caret {
  color: var(--text-muted);
  font-size: 11px;
  flex-shrink: 0;
}

.artllm-combo-popup {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 1500; /* Above modal backdrops on this page. */
  display: flex;
  flex-direction: column;
  max-height: 320px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.10);
}
/* CRITICAL : without this, our `display: flex` above wins over the
   browser's default UA rule `[hidden] { display: none }`, so setting
   `popup.hidden = true` in JS does NOTHING visually and EVERY popup
   stays open forever. Explicit attribute-selector with !important so
   no future rule can accidentally un-hide it. */
.artllm-combo-popup[hidden] {
  display: none !important;
  overflow: hidden;
}
.artllm-combo-search {
  width: 100%;
  padding: 10px 12px;
  font-size: 0.88rem;
  color: var(--text);
  background: var(--surface, #fff);
  border: none;
  border-bottom: 1px solid var(--border);
  outline: none;
}
.artllm-combo-list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  max-height: 260px;
}
.artllm-combo-opt {
  padding: 8px 12px;
  font-size: 0.88rem;
  color: var(--text);
  cursor: pointer;
}
.artllm-combo-opt:hover,
.artllm-combo-opt.is-active {
  background: rgba(0, 0, 0, 0.04);
}
.artllm-combo-opt.is-selected {
  background: rgba(106, 70, 193, 0.08);
  color: var(--primary);
  font-weight: 600;
}
.artllm-combo-opt.is-hidden {
  display: none;
}
.artllm-combo-empty {
  padding: 12px;
  font-size: 0.85rem;
  color: var(--text-muted);
  text-align: center;
}
.artllm-add-hop {
  font-size: 0.82rem;
}
.artllm-add-hop:disabled {
  cursor: not-allowed;
}

/* ════════════════════════════════════════════════════════════════════
   Site-template ARCHETYPES (feature 032, P5)
   --------------------------------------------------------------------
   The active template's archetype is set as `data-archetype` on <html>
   by app-shell.js:applyArchetype(). It changes ONLY the shell layout —
   the nav CONTENT (entries, routes, i18n, role gating) is unchanged and
   still comes from GET /api/menu. Absent / "left-sidebar" = today's look
   (no rule below matches) ⇒ zero regression (spec FR-016/FR-017, SC-003).
   ════════════════════════════════════════════════════════════════════ */

/* Archetype layouts are a DESKTOP concept. Below 769px every archetype falls
   back to the standard off-canvas drawer (the mobile media query above owns
   `.sidebar`), so the hamburger keeps working — we therefore gate ALL archetype
   layout rules behind `min-width: 769px` and never override the mobile drawer. */
@media (min-width: 769px) {
  /* ── top-nav : the FAITHFUL two-row horizontal bar (feature 032 P7). ──
     The light CSS reflow that used to live here (turning the vertical
     `.sidebar` into a horizontal strip) was replaced by a deliberate,
     pixel-faithful rebuild of the maquette `docs/horizontal-menu-template/`.
     That rebuild lives in its own stylesheet `assets/css/topnav-archetype.css`
     (fully scoped under `html[data-archetype="top-nav"]`, injected by
     app-shell.js) plus the runtime builder `buildTopNav()` in app-shell.js,
     which constructs a real `<header class="topnav">` two-row chrome and HIDES
     `.sidebar` / `#app-header`. Nothing top-nav-specific remains in this file
     so the two implementations can't fight. compact / minimal stay CSS-only. */

  /* ── compact : a denser left sidebar (same structure, tighter). ── */
  html[data-archetype="compact"] .sidebar { width: 200px; }
  html[data-archetype="compact"] .sidebar-nav { padding: 0.5rem 0.4rem; }
  html[data-archetype="compact"] .submenu-toggle,
  html[data-archetype="compact"] .sidebar-link { padding: 0.32rem 0.5rem; font-size: 0.82rem; }

  /* ── minimal : slimmer chrome — hide the workspace switcher, tighter nav. ── */
  html[data-archetype="minimal"] .sb-ws { display: none; }
  html[data-archetype="minimal"] .sidebar { width: 216px; }
  html[data-archetype="minimal"] .sidebar-nav { padding-top: 0.4rem; }
}

/* ── Searchable font combobox (feature 032 fonts phase) ──────────────────
   A filterable dropdown used by the site-template editor's « Police » field;
   each option is rendered in its OWN typeface (font-family set inline) so the
   admin previews the font before choosing. */
.st-combo { position: relative; }
.st-combo-list {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 300;
  margin-top: 2px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  max-height: 260px; overflow-y: auto;
}
.st-combo-opt { padding: 7px 10px; cursor: pointer; font-size: 0.95rem; }
.st-combo-opt:hover,
.st-combo-opt.active { background: var(--hover-bg, rgba(127, 127, 127, 0.12)); }
.st-combo-opt[aria-selected="true"] { font-weight: 600; }
.st-combo-empty { padding: 8px 10px; color: var(--text-muted); font-size: 0.85rem; }
