/* ui/web/css/theme.css
   WUI.1: adaptat din UI/UI DEMO template.html (design DMS v1.4, autor user).
   Doar ce e nevoie pentru shell + Database (sidebar, tab bar, arbore, tabel,
   search pill, toast). Restul (PDF viewer, Settings segmented control,
   Downloader mock) vine odata cu etapele lor (WUI.2/WUI.4-6). */

/* Fix la 16px: fereastra desktop nu e un viewport de browser redimensionabil
   liber la latimi de telefon — scalarea responsive din template-ul web (care
   micsora fontul progresiv sub 1600px) facea textul ilizibil de mic la
   latimile normale de fereastra ale aplicatiei si dezincroniza ROW_HEIGHT
   din js/table.js (vezi acolo). */
/* WUI.6: `--font-scale` e persistat in prefs.json pe cheia `font_scale`,
   aceeasi cheie citita/scrisa de dialogul Qt vechi (`theme.py::
   load_font_scale`) — doar efectul e diferit (CSS var aici, QApplication
   font acolo). Implicit 1 = neschimbat. */
:root { --font-scale: 1; }
html { font-size: calc(16px * var(--font-scale)); }

:root {
  --bg-body: #1f1e1d;
  --bg-sidebar: #262624;
  --bg-card: #2d2c2a;
  --bg-hover: #35332f;
  --bg-active: #3d3b37;
  --border: #3d3b37;
  --text-primary: #f5f4ef;
  --text-muted: #a8a29e;
  --text-dim: #78716c;

  --accent: #c96442;
  --accent-hover: #da7756;
  --accent-glow: rgba(201, 100, 66, 0.15);

  --status-new: #3b82f6;
  --status-processing: #eab308;
  --status-ok: #22c55e;
  --status-review: #f97316;
  --status-error: #ef4444;

  --pdf-highlight: #ffd93d;
  --pdf-highlight-active: #ffb800;

  --sidebar-width-expanded: 15.625rem;
  --sidebar-width-collapsed: 4rem;
  --radius-sm: 0.375rem;
  --radius: 0.5rem;
  --radius-lg: 0.75rem;

  --density-padding-y: 0.5rem;
  --density-padding-x: 0.75rem;
  --density-row-height: 2.5rem;

  --font-micro: 0.6875rem;
  --font-small: 0.78125rem;
  --font-body: 0.875rem;
  --font-heading: 1rem;
  --font-title: 1.25rem;
  --font-hero: 1.75rem;
}

body.light-mode {
  --bg-body: #faf9f5;
  --bg-sidebar: #f5f4ee;
  --bg-card: #ffffff;
  --bg-hover: #efede4;
  --bg-active: #e5e2d5;
  --border: #e5e2d5;
  --text-primary: #1f1e1d;
  --text-muted: #78716c;
  --text-dim: #a8a29e;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
/* UIX.15: reset-ul de mai sus prinde si <dialog>, caruia foaia agentului ii da
   `margin: auto` tocmai ca sa-l centreze la `showModal()`. Regula de autor bate
   foaia UA, deci marginile deveneau 0 si dialogul se lipea in coltul
   stanga-sus (raportat de user 2026-09-09 pe „Confirm start", dar atingea toate
   modalele: `#ocrDialog` e folosit si de js/health.js si de `askDialog`). */
dialog[open] { margin: auto; }
dialog::backdrop { background: rgba(0, 0, 0, 0.5); }
body {
  font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, sans-serif;
  font-size: var(--font-body);
  background-color: var(--bg-body);
  color: var(--text-primary);
  height: 100vh;
  overflow: hidden;
  transition: background-color 0.2s ease, color 0.2s ease;
}
::-webkit-scrollbar { width: 0.625rem; height: 0.625rem; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 0.625rem; border: 2px solid transparent; background-clip: padding-box; }
.app-container { display: flex; height: 100%; width: 100%; position: relative; }

/* ═══ SIDEBAR ═══ */
.sidebar {
  /* UIX.51: `--sidebar-boot-width` o scrie scriptul sincron din `index.html`,
     din copia de localStorage, ÎNAINTE de prima pictare. Fara ea, bara pornea
     la latimea implicita si se corecta abia dupa `bridge.get_pref`. */
  width: var(--sidebar-boot-width, var(--sidebar-width-expanded));
  background-color: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: relative; z-index: 50;
  user-select: none; flex-shrink: 0;
}
.sidebar:not(.dragging) { transition: width 0.2s cubic-bezier(0.4, 0, 0.2, 1); }
/* UIX.51: cat tine pornirea. Fara ea, corectia de latime de dupa citirea
   preferintelor e ANIMATA — chiar asta se vedea. Scoasa din `app.js` dupa ce
   modul si latimea reale sunt puse. */
.sidebar.no-transition { transition: none !important; }
.sidebar.collapsed { width: var(--sidebar-width-collapsed) !important; }
/* UIX.51: geometria modului auto-hide, la primul cadru. Clasa e pusa de acelasi
   script sincron si scoasa de `app.js` odata ce `.autohide`/`.autohide-mode`
   sunt pe elemente — altfel padding-ul ar ramane si dupa o trecere in `push`. */
body.boot-autohide .sidebar { width: var(--sidebar-width-collapsed); }
body.boot-autohide .app-container { padding-left: var(--sidebar-width-collapsed); }

/* ═══ UIX.20: MODUL AUTO-HIDE ═══
   Cerut de user (2026-09-10) ca stare SEPARATA de cea de azi, nu ca inlocuitor:
   bara sta stransa si se deschide cand treci cu mouse-ul, PESTE continut.

   Trucul e ca latimea din LAYOUT ramane cea stransa, iar deschiderea se face
   dintr-un `position: absolute` care nu participa la flex — de-aia lista de
   fisiere si panoul PDF nu se mai ingusteaza deloc cand bara se deschide.
   Fara asta ar fi fost exact bara de azi, doar cu alt declansator.

   Latimea deschisa vine din variabila `--sidebar-open-width`, scrisa de
   `applySidebarMode()` din `app.js`: e latimea pe care userul si-a ales-o
   tragand de margine, ca modul sa nu i-o piarda. */
/* Bara iese din flux si pluteste; locul ei din layout il tine `padding-left`-ul
   containerului, exact cat latimea stransa. Asa, deschiderea nu mai misca nimic
   — fara asta ar fi fost bara de azi, doar cu alt declansator. `box-sizing:
   border-box` e global (`:73`), deci padding-ul NU mai adauga latime. */
.app-container.autohide-mode { padding-left: var(--sidebar-width-collapsed); }
/* UIX.50: `overflow: hidden` statea AICI si taia butonul-sageata, care iese
   deliberat 0.625rem in afara barei (`.sidebar-toggle-edge`, `right: -0.625rem`)
   — de-aia in auto-hide fusese ascuns cu totul, si de-aia modul parea un
   mecanism cu totul separat. Taierea pe orizontala o face oricum
   `.sidebar-scroll { overflow-x: hidden }` (:196), iar tot ce e lat inauntru
   (etichete, filtru, arbore) e deja `display: none` cat timp bara e stransa —
   deci nu se pierde nimic mutand-o de aici. */
.sidebar.autohide {
  position: absolute; top: 0; left: 0; bottom: 0;
  width: var(--sidebar-width-collapsed) !important;
  z-index: 80;
}
.sidebar.autohide:hover,
.sidebar.autohide:focus-within {
  width: var(--sidebar-open-width, var(--sidebar-width-expanded)) !important;
  box-shadow: 0.25rem 0 1.5rem rgba(0, 0, 0, 0.35);
}
/* Etichetele urmeaza aceeasi regula ca la `.collapsed`, dar comandata de hover:
   stranse sunt ascunse, deschise reapar. Fara asta, textul ar fi taiat de
   `overflow: hidden` in loc sa dispara curat. */
.sidebar.autohide .tab-btn { justify-content: center; padding: 0; }
.sidebar.autohide .tab-btn span:not(.inbox-badge) { display: none; }
.sidebar.autohide:hover .tab-btn,
.sidebar.autohide:focus-within .tab-btn { justify-content: flex-start; padding: 0 0.75rem; }
.sidebar.autohide:hover .tab-btn span:not(.inbox-badge),
.sidebar.autohide:focus-within .tab-btn span:not(.inbox-badge) { display: block; }
/* Manerul de tragere ramane ascuns: in auto-hide latimea din layout e fixa,
   deci n-ar avea ce trage. Sageata NU mai e ascunsa (UIX.50, cerut de user
   2026-09-20: „autohide = varianta AUTOMATA a aceluiasi comportament") — acum
   inchide bara pe loc, prin acelasi `.force-collapsed` pe care UIX.42 il
   foloseste dupa o selectie in arbore. Asa, vocabularul e identic in ambele
   moduri: sageata inchide, iar diferenta ramane strict ce a cerut userul —
   deschiderea vine din hover si pluteste peste lista, nu impinge. */
.sidebar.autohide + .sidebar-resize-handle { display: none; }
/* UIX.42 (raportat de user 2026-09-14): tratamentul de mai sus se oprea la
   `.tab-btn` si uita arborele Database, care avea deja perechea lui pentru
   `.sidebar.collapsed` (:221, :345) dar nu si pentru `.sidebar.autohide` — la
   Database, arborele ramanea randat la latime plina, taiat de `overflow:
   hidden` in loc sa se stranga curat ca restul barei. */
.sidebar.autohide .folder-filter-wrapper,
.sidebar.autohide .tree-view { display: none; }
.sidebar.autohide:hover .folder-filter-wrapper,
.sidebar.autohide:focus-within .folder-filter-wrapper { display: flex; }
.sidebar.autohide:hover .tree-view,
.sidebar.autohide:focus-within .tree-view { display: block; }
/* UIX.42: dupa o selectie in arbore, userul vrea inchidere IMEDIATA, nu doar
   la mouseleave (mouse-ul e inca deasupra barei chiar dupa click). `!important`
   bate regulile de `:hover`/`:focus-within` de mai sus cat timp clasa e prezenta;
   `app.js` o scoate la urmatorul `mouseleave`, ca un hover nou sa functioneze
   iar normal. */
.sidebar.autohide.force-collapsed,
.sidebar.autohide.force-collapsed:hover,
.sidebar.autohide.force-collapsed:focus-within {
  width: var(--sidebar-width-collapsed) !important;
}

.sidebar-resize-handle {
  width: 4px; flex-shrink: 0; cursor: col-resize;
  background-color: transparent;
  transition: background-color 0.15s;
}
.sidebar-resize-handle:hover, .sidebar-resize-handle.dragging { background-color: var(--accent); }
.sidebar.collapsed + .sidebar-resize-handle { display: none; }

.sidebar-toggle-edge {
  position: absolute; top: 1rem; right: -0.625rem;
  width: 1.25rem; height: 1.25rem;
  border-radius: 50%;
  background-color: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text-muted);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.75rem; z-index: 60;
  opacity: 0;
  transition: opacity 0.2s, background-color 0.15s, color 0.15s;
  padding: 0;
}
.sidebar:hover .sidebar-toggle-edge { opacity: 1; }
.sidebar-toggle-edge:hover { background-color: var(--accent); color: white; border-color: var(--accent); }

.sidebar-scroll {
  flex: 1; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column;
  padding: 0.75rem 0.5rem; gap: 0.125rem;
}

/* WUI.8: statusul bazei curente, sub tot restul barei laterale. */
.sidebar-stats {
  flex-shrink: 0;
  padding: 0.25rem 0.75rem 0;
  font-size: var(--font-micro);
  font-weight: 700;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tab-btn {
  height: 2.5rem; padding: 0 0.75rem;
  display: flex; align-items: center; gap: 0.75rem;
  background: none; border: none;
  color: var(--text-muted);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: var(--font-body); font-family: inherit;
  position: relative; transition: all 0.15s;
  width: 100%; text-align: left; flex-shrink: 0;
}
.tab-btn i { font-size: 1.25rem; min-width: 1.5rem; }
.tab-btn span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar.collapsed .tab-btn { justify-content: center; padding: 0; }
.sidebar.collapsed .tab-btn span { display: none; }
/* UIX.22: regula de deasupra ascunde ETICHETA butonului, dar insigna e tot un <span>, deci
   o matura si pe ea -- adica semnalul de necitite disparea exact in starea in care bara nu
   mai are text si el e singurul lucru care te poate anunta. Aici se intoarce, asezata peste
   coltul iconitei (`.tab-btn` e deja `position: relative`, mai sus).

   UIX.50 (raportat de user 2026-09-20: „bulina portocalie arata diferit in autohide vs
   collapsed"): blocul asta era scris DOAR pentru `.collapsed`, deci in auto-hide bulina
   ramanea pastila din flux (`.inbox-badge`, `margin-left: auto`) in loc de punctul din colt
   — acelasi tipar de omisiune ca la `UIX.42` (arborele avea perechea pentru `.collapsed`,
   nu si pentru `.autohide`). Corectia NU e o copie a declaratiilor pentru auto-hide: doua
   copii ar diverge din nou peste o luna. E acelasi bloc, cu selectorii celor trei stari in
   care bara e STRANSA, oricum ar fi ajuns acolo:
     1. stransa manual;
     2. auto-hide fara mouse pe ea (`:not(:hover):not(:focus-within)` — exact conditia
        in care regulile de latime de la `:147` o tin stransa);
     3. auto-hide strans fortat dupa un click (`.force-collapsed`, care bate `:hover`).
   Cat timp bara e DESCHISA (hover sau focus), niciunul nu se potriveste, deci bulina cade
   inapoi pe `.inbox-badge` — adica exact pastila din bara larga. Asa, „identic grafic" e o
   proprietate a structurii, nu ceva de tinut minte la urmatoarea modificare. */
.sidebar.collapsed .tab-btn span.inbox-badge,
.sidebar.autohide:not(:hover):not(:focus-within) .tab-btn span.inbox-badge,
.sidebar.autohide.force-collapsed .tab-btn span.inbox-badge {
  display: block;
  position: absolute; top: 0.25rem; right: 0.5rem;
  margin-left: 0; padding: 0 0.25rem;
  min-width: 1rem; text-align: center;
  font-size: var(--font-micro); line-height: 1rem;
  border: 2px solid var(--bg-sidebar);   /* despartitor de iconita de dedesubt */
}
.tab-btn:hover { background-color: var(--bg-hover); color: var(--text-primary); }
.tab-btn.active { background-color: var(--bg-active); color: var(--text-primary); font-weight: 600; }
.tab-btn.active::after {
  content: ''; position: absolute;
  right: -0.5rem; top: 0.5rem; bottom: 0.5rem;
  width: 3px; background-color: var(--accent);
  border-radius: 3px 0 0 3px;
}

.folder-filter-wrapper {
  padding: 0.25rem 0.25rem 0.5rem; flex-shrink: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem;
}
.folder-filter-wrapper.hidden { display: none; }
.sidebar.collapsed .folder-filter-wrapper { display: none; }

/* ═══ SEARCH PILL ═══ */
.search-pill {
  display: flex; align-items: center;
  background-color: var(--bg-body);
  border: 1.5px solid var(--border);
  border-radius: 1.25rem;
  padding: 0.375rem 0.875rem; gap: 0.625rem;
  transition: all 0.15s; width: 100%;
}
.search-pill:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.search-pill i { color: var(--text-muted); font-size: 1rem; flex-shrink: 0; }
/* Direct child only -- .opt-panel (options dropdown) also lives inside
   .search-pill, and a descendant selector here was stretching its radio/
   checkbox/number inputs to width:100% with no border, which broke their
   layout (wrapped labels, misplaced bullets). */
.search-pill > input {
  background: transparent; border: none; outline: none;
  color: var(--text-primary); font-family: inherit;
  font-size: var(--font-small); width: 100%; min-width: 0;
}
.search-pill > input::placeholder { color: var(--text-muted); }
/* Chromium draws a dropdown-arrow button on any input[list=...] (datalist) —
   suggestions still filter live as you type without it, the button just
   duplicates that with an unwanted visual. */
.search-pill > input::-webkit-calendar-picker-indicator { display: none !important; }
.search-pill > input::-webkit-list-button { display: none !important; }
.search-pill select {
  background: transparent; border: none; outline: none;
  color: var(--text-primary); font-family: inherit;
  font-weight: 600; font-size: var(--font-small);
  cursor: pointer; padding-left: 0.25rem;
  border-left: 1px solid var(--border); margin-left: 0.25rem;
}
.search-pill select option { background-color: var(--bg-card); color: var(--text-primary); }

.pill-xl { padding: 0.875rem 1.375rem; border-radius: 1.75rem; }
.pill-xl i { font-size: 1.25rem; }
.pill-xl > input { font-size: 1rem; }

.pill-lg { padding: 0.5625rem 1.125rem; border-radius: 1.5rem; max-width: 32.5rem; }
.pill-lg i { font-size: 1.125rem; }
.pill-lg input { font-size: var(--font-body); }
.pill-lg select { font-size: var(--font-small); }
#globalSearchIcon { cursor: pointer; }
#globalSearchIcon:hover { color: var(--accent); }

.pill-clear {
  flex-shrink: 0; background: transparent; cursor: pointer;
  border: none; color: var(--text-muted); padding: 0;
  display: flex; align-items: center; font-size: 0.875rem;
}
.pill-clear.hidden { display: none; }
.pill-clear:hover { color: var(--status-error); }

.pill-count {
  flex-shrink: 0; font-size: var(--font-small); white-space: nowrap;
  color: var(--text-muted);
}
.pill-count.count-danger { color: var(--status-error); }
.pill-count.count-success { color: var(--status-ok); }

.filters-chip {
  flex-shrink: 0; display: flex; align-items: center; gap: 0.375rem;
  background-color: var(--accent-glow); color: var(--accent);
  font-size: var(--font-small); font-weight: 600;
  padding: 0.125rem 0.5rem; border-radius: 1rem;
}
.filters-chip.hidden { display: none; }
.filters-chip .chip-clear {
  background: transparent; border: none; cursor: pointer; padding: 0;
  color: inherit; font-size: var(--font-micro); line-height: 1;
}
.filters-chip .chip-clear:hover { color: var(--status-error); }

/* SRCH.19 regula #5: unul per folder exclus, sub bara de cautare. */
.excluded-chips-row { display: flex; flex-wrap: wrap; gap: 0.375rem; padding: 0 1.25rem 0.5rem; }
.excluded-chips-row.hidden { display: none; }

/* ═══ SEARCH OPTIONS (advanced dropdown, gear button + floating panel) ═══ */
.opt-btn {
  flex-shrink: 0; background: transparent; cursor: pointer;
  border: none; border-left: 1px solid var(--border);
  color: var(--text-primary); font-family: inherit; font-weight: 600;
  font-size: var(--font-small); padding: 0 0.25rem 0 0.5rem; margin-left: 0.125rem;
}
.opt-btn:hover { color: var(--accent); }
.opt-panel {
  display: none; position: absolute; top: calc(100% + 0.375rem); right: 0;
  min-width: 13rem; background-color: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.35);
  padding: 0.5rem; z-index: 100; cursor: default;
}
.opt-panel.open { display: block; }
.opt-group { padding: 0.25rem 0; }
.opt-group + .opt-group { border-top: 1px solid var(--border); margin-top: 0.25rem; }
.opt-group-title { font-size: var(--font-micro); color: var(--text-dim); text-transform: uppercase; padding: 0.25rem 0.5rem; }
.opt-row {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.3125rem 0.5rem; border-radius: var(--radius-sm);
  cursor: pointer; font-size: var(--font-small);
}
.opt-row:hover { background-color: var(--bg-hover); }
.opt-row.disabled { opacity: 0.45; cursor: default; }
.opt-row.disabled:hover { background-color: transparent; }
/* SRCH.40: despartitor si rand distructiv in meniul pe randuri. Aceeasi culoare
   ca `.ocr-btn.danger`, ca stergerea sa arate la fel oriunde apare. */
.opt-sep {
  height: 1px; margin: 0.3125rem 0.25rem;
  background-color: var(--border);
}
.opt-row.danger { color: var(--status-review); }
.opt-row.danger:hover { background-color: rgba(249, 115, 22, 0.15); }
/* UIX.15: `.opt-row` e gandita pentru <label>. Pe un <button> (actiunea „Fit
   columns to width") ramaneau chenarul, fundalul si fontul agentului, deci
   randul arata ca un buton lipit intr-o lista de bife. */
button.opt-row {
  width: 100%; background: none; border: none;
  color: inherit; font: inherit; text-align: left;
}
.opt-label { flex: 1; }
.opt-spin { width: 3.25rem; background: var(--bg-body); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text-primary); font-family: inherit; padding: 0.125rem 0.25rem; }

.pill-s { padding: 0.3125rem 0.75rem; }
.pill-s i { font-size: 0.875rem; }
.pill-s input { font-size: var(--font-micro); }
.pill-s select { font-size: var(--font-micro); }

/* ═══ TREE VIEW ═══ */
.tree-view { list-style: none; flex-shrink: 0; overflow-y: auto; }
.tree-view.hidden { display: none; }
/* SRCH.45 v2: cat tine pasa partiala, tabelul arata deja primele rezultate,
   dar arborele e inca cel de la cautarea dinainte — el se poate calcula doar
   pe setul COMPLET de potriviri (SRCH.37). Se arata estompat si nu se poate
   da click pe el, ca sa nu se aleaga un folder dintr-un arbore invechit. */
.tree-view.tree-updating { opacity: 0.45; pointer-events: none; }
.sidebar.collapsed .tree-view { display: none; }
.tree-node { list-style: none; }
/* padding-left 0 dădea toate liniile de ghidaj la același x absolut (ul-ul
   copil e frate cu div.tree-item, nu descendent — nu moștenea indentul
   caret-ului), deci nivelurile se contopeau vizual într-o singură linie
   continuă. Cerut de user 2026-08-28: fiecare folder trebuie să aibă
   propria linie, decalată pe nivel, care se opreste exact la lungimea
   lui (ultimul copil), nu la fratii de acelasi nivel. padding-left aici
   e chiar unitatea de indent per-nivel — ::before se aliniaza in banda ei. */
.tree-sub { list-style: none; padding-left: 0.8125rem; position: relative; }
.tree-sub::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0.375rem;
  width: 1px; background: var(--border);
}
.tree-node.collapsed > .tree-sub { display: none; }
/* "All documents" e suma tuturor fisierelor, nu un folder — cerut de user
   2026-08-28: nu trebuie sa participe la indent/linie de ghidaj. Foldere de
   top (PDF_Downloads, RCP-RO...) raman cat mai la stanga, fara linie care
   sa "insumeze" tot continutul sub root. */
.tree-view > .tree-node > .tree-sub { padding-left: 0; }
.tree-view > .tree-node > .tree-sub::before { display: none; }
.tree-caret {
  width: 0.875rem; flex-shrink: 0; text-align: center;
  color: var(--text-muted); font-size: 0.7rem; cursor: pointer;
}
.tree-caret:hover { color: var(--text-primary); }
.tree-caret-spacer { cursor: default; }

.tree-item {
  display: flex; align-items: center;
  padding: 0.375rem 0.5rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  /* Cerut de user 2026-08-28: putin mai mic decat --font-small (0.78125rem)
     folosit in restul UI-ului — la jumatate de pas fata de --font-micro,
     scop local, nu s-a atins var-ul global (l-ar fi micsorat peste tot). */
  font-size: 0.734375rem;
  color: var(--text-primary);
  transition: background 0.12s;
  position: relative; gap: 0.25rem;
}
.tree-item:hover { background-color: var(--bg-hover); }
.tree-item.active { background-color: var(--bg-active); font-weight: 600; }
.tree-item.grayed { opacity: 0.5; }
.tree-item.grayed .tree-count { color: var(--text-dim); }

/* SRCH.19 regula #2: randul pliat pentru foldere fara rezultate -- doar
   informativ, nu e un folder pe care sa dai click. */
.tree-item.tree-folded-hint {
  cursor: default; color: var(--text-muted); font-style: italic;
}
.tree-item.tree-folded-hint:hover { background-color: transparent; }

.tree-item.root-all {
  font-weight: 600; color: var(--text-primary); margin-bottom: 0.25rem;
  border-bottom: 1px dashed var(--border); padding-bottom: 0.5rem;
}

.tree-checkbox {
  width: 0.875rem; height: 0.875rem;
  border: 1.5px solid var(--text-dim);
  border-radius: 3px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; transition: all 0.15s;
  position: relative;
}
.tree-checkbox.checked, .tree-checkbox.partial { background-color: var(--accent); border-color: var(--accent); }
.tree-checkbox.checked::after {
  content: ''; width: 3px; height: 6px;
  border: solid white; border-width: 0 2px 2px 0;
  transform: rotate(45deg) translate(-1px, -1px);
}
.tree-checkbox.partial::after { content: ''; width: 8px; height: 2px; background: white; border-radius: 1px; }

.tree-folder-icon { font-size: 1rem; color: #a78bfa; flex-shrink: 0; }
.tree-item.active .tree-folder-icon { color: var(--accent); }
.tree-item.root-all .tree-folder-icon { color: var(--accent); }
.tree-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-label-hl { background-color: var(--accent-glow); border-radius: 2px; }
/* SRCH.50: pe rândul „All documents" spațiul liber îl ia calea tăiată, nu
   eticheta fixă — ea e informația variabilă și singura care poate fi lungă.
   `min-width: 0` e obligatoriu: fără el un flex item nu coboară sub lățimea
   conținutului, deci `text-overflow` n-ar avea niciodată ce tăia. */
.tree-item.root-all .tree-label { flex: 0 0 auto; }
.tree-root-path {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--font-micro); font-weight: 400;
  color: var(--text-muted); padding-left: 0.375rem;
}
.tree-root-path::before { content: '· '; }
.tree-count { font-size: var(--font-micro); color: var(--text-muted); margin-left: auto; padding-left: 0.375rem; font-variant-numeric: tabular-nums; }
.tree-count.partial { color: var(--accent); font-weight: 600; }
.tree-count.zero { color: var(--text-dim); opacity: 0.6; }

.main-content { flex: 1; display: flex; overflow: hidden; position: relative; min-width: 0; }
.view { display: none; flex: 1; overflow: hidden; min-width: 0; }
.view.active { display: flex; }

/* ═══ DATABASE VIEW ═══ */
.database-view { flex-direction: row; min-width: 0; }
.center-pane { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.top-bar {
  height: 4rem; padding: 0 1.25rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--bg-sidebar);
  flex-shrink: 0;
}
.top-bar-search { flex: 1; max-width: 42rem; display: flex; align-items: center; gap: 0.75rem; }
.top-bar-search .search-pill { max-width: 25rem; }

/* explorer_view.py:321, 397-406 — bara de stare a ferestrei (romana, separata
   de eticheta de numarare a search_bar.py, care e engleza — vezi exceptia
   SearchPill din CLAUDE.md). :empty se ascunde ca sa nu ocupe randul inainte
   de primul search. */
.status-line {
  padding: 0.25rem 1.25rem; font-size: var(--font-small); color: var(--text-muted);
  border-bottom: 1px solid var(--border); background-color: var(--bg-body); flex-shrink: 0;
}
.status-line:empty { display: none; }
.status-line.status-danger { color: var(--status-error); }
.status-line.status-success { color: var(--status-ok); }

.filter-bar {
  padding: 0.5rem 1.25rem;
  display: flex; align-items: center; gap: 0.75rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--bg-body);
  flex-shrink: 0;
}
.filter-bar .search-pill { max-width: 20rem; }
.truncated-badge { font-size: var(--font-micro); color: var(--status-error); }

/* ═══ FILE TABLE (virtualizat: tbody are inaltime totala fixa, randurile
   vizibile sunt pozitionate absolut — vezi js/table.js) ═══ */
.table-container { flex: 1; overflow: auto; position: relative; }
.file-table {
  /* UIX.7: `min-width: max-content` = suma latimilor de coloana. Fara el,
     `table-layout: fixed` strivea la 0px orice coloana fara latime explicita
     de indata ce restul umpleau panoul (vezi js/table.js). Cu el, tabelul
     depaseste panoul si `.table-container` da scroll orizontal; cand incape,
     `width: 100%` il intinde la loc. */
  width: 100%; min-width: max-content; border-collapse: collapse;
  font-size: var(--font-small); text-align: left;
  table-layout: fixed;
}
.file-table thead { position: sticky; top: 0; z-index: 5; background-color: var(--bg-sidebar); }
.file-table th {
  padding: var(--density-padding-y) var(--density-padding-x);
  color: var(--text-muted); font-weight: 500;
  border-bottom: 1px solid var(--border);
  cursor: pointer; user-select: none;
  position: relative; white-space: nowrap; overflow: hidden;
}
.file-table th:hover { color: var(--text-primary); }
.file-table th .sort-icon { margin-left: 0.25rem; font-size: 0.625rem; opacity: 0.5; }
.file-table th.sorted .sort-icon { opacity: 1; color: var(--accent); }
.file-table th[data-align="right"] { text-align: right; }
.file-table th[data-align="center"] { text-align: center; }
.file-table th.drag-over { box-shadow: inset 2px 0 0 var(--accent); }
.col-resizer {
  position: absolute; top: 0; right: 0; bottom: 0; width: 6px;
  cursor: col-resize; user-select: none; touch-action: none;
}
/* Cerut de user 2026-08-28: fara niciun indiciu vizual la repaus, coloanele
   tabelului nu spuneau unde se poate redimensiona — trebuia ghicit. Linie
   foarte discreta (1px, var(--border)) centrata in banda de 6px, vizibila
   doar la atenta privire; accentul plin ramane rezervat pt hover/drag. */
.col-resizer::after {
  content: ''; position: absolute; top: 0.375rem; bottom: 0.375rem; left: 2px;
  width: 1px; background-color: var(--border);
}
.col-resizer:hover, .col-resizer.resizing { background-color: var(--accent); opacity: 0.5; }
.col-resizer:hover::after, .col-resizer.resizing::after { background-color: transparent; }

/* Virtualizare (WUI.1): tbody ramane un <tbody> normal — doua <tr>
   distantier (inaltime = randuri_ascunse * density-row-height) plus
   fereastra de randuri reale vizibile. Pastreaza semantica de tabel
   (aliniere coloane, sticky thead) fara positioning absolut. */
.file-table tr.row-spacer td { padding: 0; border: none; height: auto; }

.file-table tbody tr.data-row { height: var(--density-row-height); cursor: pointer; transition: background 0.1s; }
body.zebra-on .file-table tbody tr.data-row.row-odd { background-color: var(--bg-body); }
body.zebra-on .file-table tbody tr.data-row.row-even { background-color: var(--bg-card); }
/* UIX.6 (raportat de user 2026-09-04: „ctrl+click selecteaza dar vizual nu e
   nici o diferenta"): bara de 3px era singurul semn, iar dungile zebra o
   inecau — `body.zebra-on .file-table tbody tr.data-row.row-odd` are
   specificitate mai mare (0,3,3) decat regula de aici (0,3,2), deci fundalul
   randului ramanea neschimbat. De aici `!important` pe fundal.
   ORDINEA celor trei reguli conteaza: la specificitate si `!important` egale
   castiga ultima declarata. Selectia bate randul curent pe FUNDAL (randul
   curent e oricum si el selectat — se deosebeste prin `font-weight`, care nu
   e suprascris), iar hover-ul le bate pe amandoua. */
.file-table tbody tr.data-row.active-row { background-color: var(--bg-active) !important; font-weight: 500; }
.file-table tbody tr.data-row.multi-selected {
  background-color: var(--accent-glow) !important;
  box-shadow: inset 3px 0 0 var(--accent);
}
.file-table tbody tr.data-row:hover { background-color: var(--bg-hover) !important; }
.file-table td {
  padding: var(--density-padding-y) var(--density-padding-x);
  color: var(--text-primary);
  border-bottom: 1px solid var(--border);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.file-table td[data-align="right"] { text-align: right; }
/* UIX.15, cerut de user: numerele, datele, statusul si coloanele mici fixe pe
   centru; textul lung (File, Folder, Source, Engine OCR) ramane la stanga. */
.file-table td[data-align="center"] { text-align: center; }
.file-name-cell { display: flex; align-items: center; gap: 0.5rem; font-weight: 500; overflow: hidden; }
.file-name-cell span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.file-icon { font-size: 1rem; color: #ef4444; flex-shrink: 0; }
/* WATCH.26: Word/Excel capătă propriul icon (`ph-file-doc`/`ph-file-xls`, vezi
   `app.js::fileIconClass`) — roșul de mai sus rămâne al PDF-ului, nu al oricărui fișier;
   reutilizează tonurile deja definite pentru statusuri (`--status-new`/`--status-ok`), nu
   culori noi de brand introduse doar pentru asta. */
.file-icon.ph-file-doc { color: var(--status-new); }
.file-icon.ph-file-xls { color: var(--status-ok); }

.status-badge { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.125rem 0.5rem; border-radius: 0.625rem; font-size: var(--font-micro); font-weight: 600; }
.status-new { background: rgba(59, 130, 246, 0.15); color: var(--status-new); }
.status-processing { background: rgba(234, 179, 8, 0.15); color: var(--status-processing); }
.status-ok { background: rgba(34, 197, 94, 0.15); color: var(--status-ok); }
.status-review { background: rgba(249, 115, 22, 0.15); color: var(--status-review); }
.status-error { background: rgba(239, 68, 68, 0.15); color: var(--status-error); }

.empty-state-sticky {
  position: sticky; left: 0; width: 100%;
  padding: 3.75rem 1.25rem; text-align: center; color: var(--text-muted);
  display: flex; flex-direction: column; align-items: center;
}
.empty-state-sticky i { font-size: 3rem; margin-bottom: 0.75rem; opacity: 0.5; }
.empty-state-sticky h3 { font-size: var(--font-heading); margin-bottom: 0.375rem; font-weight: 500; }
.empty-state-sticky p { font-size: var(--font-small); }

/* ═══ HOME VIEW (UIX.1) ═══ — portat din `UI/UI DEMO template.html` */
.home-view {
  flex-direction: column;
  align-items: center; justify-content: center;
  padding: 2.5rem 1.25rem;
  background: radial-gradient(circle at 50% 40%, var(--accent-glow) 0%, transparent 60%);
  position: relative;   /* UIX.13: sistemul de coordonate al baloanelor */
}
.home-container {
  max-width: 40rem; width: 100%;
  display: flex; flex-direction: column;
  align-items: center; gap: 2rem;
}
.home-title {
  font-size: var(--font-hero); font-weight: 700;
  letter-spacing: -0.05em; text-align: center; line-height: 1.2;
}
/* OPS.2 E7: numele vizitatorului din browser, sub salut. */
.home-name {
  margin-top: -1.25rem; width: 16rem; max-width: 100%;
  padding: 0.4rem 0.75rem; text-align: center; font: inherit;
  color: var(--text-primary); background: transparent;
  border: 1px solid var(--border); border-radius: 999px;
}
.home-name:focus { outline: none; border-color: var(--accent); }
.home-title-editable { cursor: pointer; }
.home-search-wrapper { width: 100%; }
/* UIX.68: butonul de trimitere din New Search, dupa „Start task" din Claude desktop --
   pastila plina pe accent, vizibila doar cand campul are text. UIX.72: cerc doar cu
   sageata, fara text. */
.home-submit {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  background-color: var(--accent); color: #fff; border: none; cursor: pointer;
  width: 2rem; height: 2rem; padding: 0; border-radius: 50%;
  transition: background-color 0.15s;
}
.home-submit:hover { background-color: var(--accent-hover); }
.home-submit.hidden { display: none; }
.search-pill .home-submit i { color: inherit; font-size: 1rem; }

/* ═══ THOUGHT BUBBLES (UIX.13) ═══
   Ramele vin din `ui/web/assets/bubbles/*.png`, taiate 9-slice. `js/bubbles.js`
   scrie inline sursa, feliile si latimile de bordura — difera de la un desen la
   altul, deci n-au ce cauta aici. Regula asta tine doar ce e comun.
   Baloanele sunt hartie alba desenata cu cerneala neagra, in ambele teme: nu
   urmeaza tokenii de dark mode, fiindca desenul ar deveni o pata neagra. */
.bubble-layer {
  position: absolute; inset: 0;
  overflow: hidden; pointer-events: none;
  z-index: 5;
}
.bubble {
  position: absolute;
  box-sizing: content-box;
  width: max-content; max-width: 13rem;
  padding: 0.125rem 0.375rem;
  border-style: solid; border-color: transparent;
  color: #16181d;
  font-family: "Comic Sans MS", "Segoe Print", "Segoe UI", sans-serif;
  font-weight: 700; font-size: 0.875rem; line-height: 1.25;
  text-align: center; text-wrap: balance;
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
  will-change: opacity, transform;
}
.bubble.in { opacity: 1; }
/* UIX.49: personajul Alley Cats care "spune" balonul de langa el. */
.bubble-cat {
  position: absolute;
  width: 110px; height: auto;   /* UIX.65: doar rezerva -- bubbles.js pune latimea inline (S/M/L) */
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
  will-change: opacity, transform;
}
.bubble-cat.in { opacity: 1; }
/* Contra-oglindirea textului, cand balonul e intors ca sa-si duca coada spre
   bara de cautare. `display:block` ii da o cutie pe care `transform` o prinde. */
.bubble-text { display: block; }
.chip {
  padding: 0.375rem 0.875rem; font-size: var(--font-small);
  background-color: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 1.25rem;
  color: var(--text-muted);
  cursor: pointer; transition: all 0.15s;
  font-family: inherit;
  max-width: 18rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chip:hover { border-color: var(--accent); color: var(--text-primary); background-color: var(--bg-hover); }

/* ═══ TOAST ═══ */
.toast {
  position: fixed; bottom: 1.5rem; right: 1.5rem;
  padding: 0.75rem 1.25rem;
  background-color: var(--bg-card);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-size: var(--font-small);
  box-shadow: 0 8px 24px rgba(0,0,0,0.3);
  transform: translateY(80px);
  opacity: 0; transition: all 0.25s;
  z-index: 2000; pointer-events: none;
}
.toast.show { transform: translateY(0); opacity: 1; }

/* ═══ PDF PANE (WUI.2) ═══
   Portat aproape 1:1 din `UI DEMO template.html` (cerut explicit de user
   2026-08-27, în locul unui design construit de la zero) — nume de clase și
   structură identice unde are sens. Diferența disclosed, nu tăcută: mock-ul
   randează pagini ca text HTML la 595×842 fix (`PDF_PAGE_WIDTH/HEIGHT`
   constant); aici o pagină e un PNG real (`pdf://`, `ui/webshell/
   pdf_scheme.py`) de dimensiune variabilă — `.pdf-page-container` își ia
   proporția din imaginea încărcată, nu dintr-o constantă. Highlight-ul e un
   overlay absolut-poziționat (nu `<mark>` peste text — nu există text DOM,
   doar o imagine). */

.split-divider {
  /* UIX.12: `flex-shrink: 0` ca la `.sidebar-resize-handle`. Fara el, divizorul
     se turteste la 0px cand panourile nu incap (masurat: 4px la 1920, 0px de la
     1283 in jos) — adica exact cand ai nevoie de el ca sa tragi panoul PDF
     inapoi, nu mai ai ce apuca cu mouse-ul. */
  width: 4px; flex-shrink: 0; background-color: var(--border);
  cursor: col-resize; transition: background-color 0.15s;
}
.split-divider:hover, .split-divider.dragging { background-color: var(--accent); }

.pdf-preview-pane {
  /* UIX.4: minimul e proportional si il impune `paneMins()` din app.js;
     un `min-width` fix aici il batea si impingea panoul in afara ecranului. */
  flex: 1.2; min-width: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
  background-color: var(--bg-body);
  position: relative;
  outline: none;
}
.pdf-preview-pane:fullscreen { width: 100vw; height: 100vh; }

.pdf-toolbar {
  height: 3rem; padding: 0 0.75rem;
  background-color: var(--bg-sidebar);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.pdf-toolbar-left { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
.pdf-toolbar-center {
  display: flex; align-items: center; gap: 0.25rem;
  flex: 1; justify-content: center;
  min-width: 0;
}
.pdf-toolbar-right { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }

.pdf-btn {
  background: none; border: none;
  color: var(--text-primary); cursor: pointer;
  padding: 0.375rem 0.5rem;
  border-radius: var(--radius-sm);
  font-size: 1rem;
  display: flex; align-items: center; gap: 0.25rem;
  transition: background 0.15s; font-family: inherit;
}
/* UIX.57: containerul iconului de fit page, cand acela e SVG inline si nu glif
   de font. `1em` il leaga de `font-size`-ul butonului (deci si de `--font-scale`),
   iar `display: block` pe svg scoate spatiul de sub linia de baza, ca sa stea la
   aceeasi inaltime cu iconurile `.ph` de langa el. */
.pdf-fit-icon-page { display: flex; align-items: center; line-height: 1; }
.pdf-fit-icon-page svg { display: block; width: 1em; height: 1em; }
/* UIX.58: indiciul de iesire din fullscreen. `pointer-events: none` — e un
   mesaj, nu un control, si nu are voie sa fure un clic de pe pagina cat timp
   se stinge. Vizibil doar cat tine clasa `.visible`, pusa din `pdf.js`. */
.pdf-fullscreen-hint {
  position: absolute; bottom: 1.5rem; left: 50%; transform: translateX(-50%);
  z-index: 40; pointer-events: none;
  padding: 0.5rem 0.875rem; border-radius: var(--radius-sm);
  background: var(--bg-active); border: 1px solid var(--border);
  color: var(--text-primary); font-size: var(--font-small);
  display: flex; align-items: center; gap: 0.375rem;
  opacity: 0; visibility: hidden; transition: opacity 0.3s, visibility 0.3s;
}
.pdf-fullscreen-hint.visible { opacity: 1; visibility: visible; }
.pdf-fullscreen-hint kbd {
  font-family: inherit; font-size: inherit;
  padding: 0.0625rem 0.3125rem; border-radius: var(--radius-sm);
  background: var(--bg-body); border: 1px solid var(--border);
}

/* UIX.56: randurile din coada care se pot deschide in viewer. Doar cursorul si
   un hover — nu un buton pe rand, ca sa nu se lateasca tabelul cu o coloana de
   actiuni pentru o actiune care are deja un gest (dublu-clic). */
.ocr-table tr.queue-row-openable { cursor: pointer; }
.ocr-table tr.queue-row-openable:hover { background: var(--bg-hover); }
.pdf-btn:hover { background: var(--bg-hover); }
.pdf-btn.active { background: var(--bg-active); color: var(--accent); }
.pdf-page-input {
  width: 2.5rem; padding: 0.25rem 0.375rem;
  background: var(--bg-body);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary); font-family: inherit;
  font-size: var(--font-small);
  text-align: center; outline: none;
}
.pdf-page-input:focus { border-color: var(--accent); }
.pdf-page-info { font-size: var(--font-small); color: var(--text-muted); white-space: nowrap; }
.pdf-search-pill { max-width: 17.5rem; min-width: 10rem; }
.pdf-search-pill input:disabled { cursor: not-allowed; opacity: 0.6; }
/* SRCH.38: "Find in document" text was hard to read at the shared
   --font-small size with a --text-muted placeholder — bumped both the
   typed-text size and the placeholder contrast for this pill only, other
   search pills (top bar, filter bar) keep their current sizing. */
.pdf-search-pill > input { font-size: var(--font-body); }
.pdf-search-pill > input::placeholder { color: var(--text-primary); opacity: 0.65; }

@media (max-width: 1200px) {
  .pdf-toolbar-center { justify-content: flex-start; }
}

.pdf-viewport {
  flex: 1; display: flex;
  overflow: hidden; position: relative;
}

/* ═══ UIX.23: RAIL-UL VERTICAL ═══
   Când bara de sus nu mai încape, `pdf.js` mută aici grupurile din mijloc și
   din dreapta. Pragul NU e o constantă în px — 805 a fost prima variantă și s-a
   dovedit greșită la măsurătoare (grupul din mijloc e tăiat de la ~760px, dar
   bara raportează depășire abia la 500). E o probă pe layout, în
   `applyToolbarLayout()`; vezi ticketul UIX.23-26 pentru baleiaj.
   E coloană în layout, nu suprapunere — pagina se îngustează cu exact lățimea
   lui, deci nu acoperă nimic. Butoanele sunt aceleași noduri, reorientate. */
.pdf-side-rail {
  flex-shrink: 0;
  display: flex; flex-direction: column;
  align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.375rem;
  overflow-y: auto;
  background-color: var(--bg-sidebar);
  border-left: 1px solid var(--border);
}
.pdf-side-rail .pdf-toolbar-center,
.pdf-side-rail .pdf-toolbar-right {
  flex: none;
  flex-direction: column;
  gap: 0.375rem;
}
/* Separator între cele două grupuri coborâte, ca să nu pară o listă continuă. */
.pdf-side-rail .pdf-toolbar-right {
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  width: 100%;
}
/* „1 of 52" nu încape pe orizontală într-o coloană de 2rem — se stivuiește. */
.pdf-side-rail .pdf-page-info {
  display: flex; flex-direction: column; align-items: center;
  line-height: 1.2; white-space: normal; text-align: center;
}
.pdf-side-rail .pdf-page-input { width: 2.25rem; text-align: center; }
/* Bara de sus rămâne doar cu căutarea: îi dăm voie să se întindă. */
.pdf-preview-pane.rail-mode .pdf-toolbar-left { flex: 1; min-width: 0; }
.pdf-preview-pane.rail-mode .pdf-search-pill { flex: 1; min-width: 6rem; max-width: none; }

/* ═══ TOC PANEL — slide-over cu thumbnail-uri, nu un rail permanent ═══
   Randare leneșă via IntersectionObserver (dpi mic, `pdf://…?dpi=40`) — nu
   tot documentul dintr-o dată la deschidere (vezi UI.11 din ticket pentru
   motivul pentru care Qt-ul original evita exact asta). */
.toc-panel {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 12.5rem;
  background-color: var(--bg-sidebar);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  overflow: hidden;
  z-index: 15;
  box-shadow: 4px 0 24px rgba(0,0,0,0.35);
  transform: translateX(-100%);
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.toc-panel.open { transform: translateX(0); }

.toc-header {
  padding: 0.875rem 1rem;
  border-bottom: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--font-body); font-weight: 600;
  flex-shrink: 0;
}
.toc-body {
  flex: 1;
  overflow-y: auto;
  padding: 1rem 0.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.toc-thumbnail-wrap { display: flex; flex-direction: column; align-items: center; width: 100%; }
.toc-thumbnail {
  width: 100%; aspect-ratio: 1 / 1.4142;
  background: white;
  border-radius: 2px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: 3px solid transparent;
  transition: border-color 0.15s, transform 0.15s;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
  flex-shrink: 0;
}
.toc-thumbnail:hover { transform: translateY(-2px); }
.toc-thumbnail.active { border-color: #3b82f6; }
.toc-thumbnail img { width: 100%; height: 100%; object-fit: contain; }
.toc-thumbnail-label {
  text-align: center;
  font-size: var(--font-small);
  color: var(--text-muted);
  margin-top: 0.25rem;
  font-variant-numeric: tabular-nums;
}

.toc-backdrop {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 14;
  background: transparent;
  display: none;
}
.toc-backdrop.open { display: block; }

/* ═══ PDF CANVAS ═══ */
.pdf-content-area {
  flex: 1;
  display: flex;
  overflow: hidden;
  position: relative;
  min-width: 0;
}
.pdf-empty-state {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--text-dim); font-size: var(--font-small); text-align: center; padding: 2rem; z-index: 1;
}
.pdf-canvas-wrapper {
  flex: 1; overflow: auto;
  padding: 1.5rem 0;
  display: flex; flex-direction: column;
  /* WUI.11 (raportat de user 2026-09-16: „la zoom mare marginile stanga/dreapta
     nu sunt accesibile"). `center` simplu era cauza, si nu e o subtilitate de
     CSS, ci o margine IMPOSIBIL de atins: un flex item mai lat decat containerul
     depaseste in ambele sensuri, dar zona derulabila se naste numai in dreapta
     — `scrollLeft` nu poate cobori sub 0. Masurat in aplicatie (vezi
     `scripts/probe/proba_wui11_pan.py`), pe documentul din ticket, la un singur pas de
     zoom: panou 596px, pagina 658px, taiati 31px in stanga si 31px in dreapta;
     `scrollLeft = -99999` ramanea 0, deci cei 31px din stanga nu se vedeau
     niciodata, cu niciun mijloc. La capatul din dreapta erau deja 62px ascunsi
     in stanga. `safe` schimba alinierea in `start` exact cand ar aparea
     depasirea, deci pagina ramane centrata cat incape si devine complet
     parcurgibila cand nu mai incape. */
  align-items: safe center; gap: 1rem;
  background-color: var(--bg-body);
  scroll-behavior: smooth;
  position: relative;
  min-width: 0;
}
/* WUI.11: cursorul de „mana" apare doar cand chiar e ce panorama — pagina mai
   lata decat panoul (`pan-ready`, pus din `pdf.js`). */
.pdf-canvas-wrapper.pan-ready { cursor: grab; }
.pdf-canvas-wrapper.panning {
  cursor: grabbing;
  /* Fara asta, fiecare `scrollLeft = ...` din timpul tragerii ar fi o derulare
     ANIMATA (`scroll-behavior: smooth`, mai sus, pentru `goToPage`), adica
     pagina ar aluneca in urma mouse-ului. */
  scroll-behavior: auto;
}
/* Fără width/height în CSS, deliberat — `recalculatePdfLayout()` (pdf.js)
   le setează inline pe fiecare container, pe baza scalei curente, exact ca
   în mock (`c.style.width`/`c.style.height`). */
.pdf-page-container { position: relative; flex-shrink: 0; }
.pdf-page {
  position: absolute; inset: 0;
  background: white;
  box-shadow: 0 4px 20px rgba(0,0,0,0.25);
  border-radius: 3px;
  overflow: hidden;
}
.pdf-page-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }

/* ENG.22: panoul de text OCR. Ocupa aceeasi zona ca `.pdf-canvas-wrapper`
   (nu langa el) — pe latimile mici la care panoul PDF abia incape dupa UIX.4,
   doua coloane l-ar strivi din nou. */
.ocr-text-pane {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
  background-color: var(--bg-body);
  overflow: hidden;
}
.ocr-text-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  background-color: var(--bg-card);
  flex-shrink: 0;
}
.ocr-text-head label { font-size: var(--font-small); color: var(--text-muted); }
.ocr-text-head .ocr-input { max-width: 22rem; }
.ocr-text-head .ocr-muted { margin-left: auto; }
.ocr-text-body {
  flex: 1; overflow: auto;
  padding: 1rem 1.25rem;
  font-family: ui-monospace, "Cascadia Mono", "Consolas", monospace;
  font-size: var(--font-small);
  line-height: 1.55;
  color: var(--text-primary);
  white-space: pre-wrap;      /* textul OCR are newline-urile lui, se pastreaza */
  word-break: break-word;
}
/* UIX.25: în „fit width" rândurile lungi NU se rup — altfel `scrollWidth` ar fi
   mereu egal cu `clientWidth` și n-ar exista ce potrivi. Se micșorează fontul
   până când cel mai lung rând încape. */
.ocr-text-body.nowrap,
.ocr-text-body.nowrap .ocr-text-col-body { white-space: pre; word-break: normal; }
.ocr-text-body .ocr-text-empty { color: var(--text-dim); font-family: inherit; }
/* Modul compare: doua coloane, fiecare cu dropdown propriu. */
.ocr-text-body.compare { display: flex; gap: 1rem; padding: 0; }
.ocr-text-col { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
.ocr-text-col + .ocr-text-col { border-left: 1px solid var(--border); }
.ocr-text-col-head { padding: 0.375rem 0.75rem; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.ocr-text-col-head .ocr-input { width: 100%; }
.ocr-text-col-body { flex: 1; overflow: auto; padding: 0.75rem; white-space: pre-wrap; word-break: break-word; }
/* SRCH.32: potrivirile căutării în textul OCR. Aceleași două culori ca în
   viewerul Qt (`ocr_text_viewer.py`: _COLOR_EXACT / _COLOR_VARIANT) — galben =
   termenul tastat, portocaliu = variantă găsită prin fuzzy — și aceleași
   variabile ca dreptunghiurile de peste pagină, ca marcajul să arate la fel în
   ambele moduri ale panoului. Culoarea textului e fixată: `<mark>` are implicit
   fundal deschis cu text întunecat, iar pe tema închisă moștenirea lui
   `--text-primary` ar da text deschis pe galben. */
.ocr-text-mark {
  background-color: var(--pdf-highlight);
  color: #1f1e1d;
  border-radius: 0.125rem;
}
.ocr-text-mark.variant { background-color: var(--status-review); }
/* UIX.26: potrivirea curentă din text, aceeași culoare ca `.pdf-highlight.current`
   — e aceeași noțiune („unde stă navigarea ◀ ▶"), doar în celălalt mod al
   panoului. Textul devine deschis, fiindcă accentul e o culoare închisă. */
.ocr-text-mark.current {
  background-color: var(--accent);
  color: #ffffff;
  outline: 1px solid var(--accent);
}
.pdf-highlight-layer { position: absolute; inset: 0; pointer-events: none; }
.pdf-highlight { position: absolute; background-color: var(--pdf-highlight); opacity: 0.45; }
/* WUI.3: potrivirea curentă (cea pe care stă navigarea ◀ ▶) se vede distinct
   de restul, ca în `pdf_preview.py` vechi (HL_EXACT alpha 150 vs HL_SOURCE
   alpha 110) — altfel nu se vede unde ai ajuns pe o pagină cu multe apariții. */
.pdf-highlight.current {
  background-color: var(--accent);
  opacity: 0.65;
  outline: 1px solid var(--accent);
}
.pdf-find-count {
  font-size: var(--font-micro);
  color: var(--text-secondary);
  min-width: 3.5rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.pdf-find-count.no-match { color: var(--status-error); }
.pdf-page-number-footer {
  position: absolute; bottom: 0.375rem; right: 0.5rem;
  font-size: var(--font-micro); color: rgba(0,0,0,0.4);
  background-color: rgba(255,255,255,0.65); padding: 0 0.25rem; border-radius: 2px;
  pointer-events: none;
}

/* Decorativ, ca în mock — markerii (search-hit positions) au nevoie de
   căutarea "în fișier" din WUI.3 ca să însemne ceva; harta rămâne goală
   până atunci, nu ascunsă (structura e deja acolo pentru WUI.3). */
.pdf-scrollbar-map {
  position: absolute; right: 4px;
  top: 3.75rem; bottom: 1.25rem;
  width: 6px;
  background-color: rgba(255,255,255,0.03);
  border-radius: 3px; pointer-events: none;
}
.scroll-marker {
  position: absolute; left: 0; right: 0;
  height: 3px;
  background-color: var(--pdf-highlight);
  border-radius: 2px; opacity: 0.8;
}
.scroll-marker.active {
  background-color: var(--pdf-highlight-active);
  opacity: 1; height: 5px;
}

/* ═══ WORD SEARCH PANEL — Docked / Compact (shell only — WUI.3 builds the
   actual in-file search this displays; inputs disabled/inert until then,
   see pdf.js) ═══ */
.word-search-panel {
  background-color: var(--bg-card);
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column;
  overflow: hidden;
  flex-shrink: 0;
  transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.word-search-panel.mode-docked { width: 17.5rem; }
.word-search-panel.mode-compact { width: 8.5rem; }
.word-search-panel.collapsed {
  width: 0;
  border-left: none;
}
.word-search-panel.collapsed > * { display: none; }

.wsp-header {
  padding: 0.75rem 0.875rem;
  border-bottom: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--font-small); font-weight: 600;
  flex-shrink: 0; gap: 0.5rem;
}
.wsp-header-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wsp-header-actions { display: flex; gap: 0.25rem; align-items: center; flex-shrink: 0; }
.wsp-mode-btn {
  background: none; border: none;
  color: var(--text-muted); cursor: pointer;
  padding: 0.25rem; border-radius: var(--radius-sm);
  font-size: 0.875rem;
  transition: all 0.15s;
}
.wsp-mode-btn:hover { color: var(--text-primary); background: var(--bg-hover); }
.wsp-mode-btn.active { color: var(--accent); }

.wsp-body { flex: 1; overflow-y: auto; padding: 0.5rem; }
.wsp-meta {
  padding: 0.25rem 0.5rem 0.5rem;
  font-size: var(--font-micro); color: var(--text-muted);
}
.wsp-meta strong { color: var(--accent); }

.wsp-nav {
  display: none;
  padding: 0.375rem 0.5rem;
  border-bottom: 1px solid var(--border);
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  font-size: var(--font-small);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.word-search-panel.mode-compact .wsp-nav { display: flex; }
.wsp-nav-btn {
  background: none; border: none;
  color: var(--text-muted); cursor: pointer;
  padding: 0.125rem 0.375rem;
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  transition: all 0.15s;
}
.wsp-nav-btn:hover { color: var(--accent); background: var(--bg-hover); }

/* UIX.2: lista de rezultate. Portat 1:1 din `UI/UI DEMO template.html`
   (`.wsp-page-group` … `.wsp-snippet mark`), unde exista deja desenat —
   theme.css luase din mock doar rama panoului, nu si continutul lui. */
.wsp-page-group { margin-bottom: 0.5rem; }
.wsp-page-header {
  padding: 0.375rem 0.5rem;
  font-size: var(--font-small); font-weight: 600;
  color: var(--text-primary); cursor: pointer;
  display: flex; align-items: center; gap: 0.375rem;
  border-radius: var(--radius-sm);
}
.wsp-page-header:hover { background: var(--bg-hover); }
.wsp-page-header .caret { transition: transform 0.15s; font-size: 0.625rem; }
.wsp-page-header.expanded .caret { transform: rotate(90deg); }
.wsp-snippets { padding-left: 0.5rem; }
.word-search-panel.mode-compact .wsp-snippets { display: none; }
.word-search-panel.mode-compact .wsp-page-header .caret { display: none; }
.wsp-snippet {
  padding: 0.5rem;
  font-size: var(--font-micro); color: var(--text-muted);
  border-radius: var(--radius-sm);
  cursor: pointer;
  border-left: 2px solid transparent;
  margin: 0.125rem 0; line-height: 1.4;
}
.wsp-snippet:hover { background: var(--bg-hover); }
.wsp-snippet.active {
  background: var(--bg-hover);
  border-left-color: var(--accent);
  color: var(--text-primary);
}
.wsp-snippet mark {
  background: var(--pdf-highlight);
  color: #111; padding: 0 2px; border-radius: 2px;
}
/* SRCH.41: randul informativ „+N more on this page" — nu e o potrivire pe
   care sa poti da click, doar spune ca mai exista. */
.wsp-snippet-more { cursor: default; font-style: italic; }
.wsp-snippet-more:hover { background: transparent; }

/* ═══ OCR PROCESSING VIEW (WUI.4) ═══
   Idiomul cardurilor vine din `UI/UI DEMO template.html:791-870` (mock-ul
   userului). Mock-ul acoperea patru carduri; ecranul real are nevoie de șapte
   — vezi `docs/TICKETS/WUI.4-processing.md`, decizia #6. */
/* UIX.54: invelisul celor trei moduri ale tabului OCR Processing. E `.view`,
   deci mostenește `display: none` / `.active { display: flex }`; coloana
   inseamna „antetul sus, vederea ia restul inaltimii". Vederile dinauntru
   raman tot `.view`, comutate intre ele de `setOcrMode` -- nimic nu se schimba
   in felul cum sunt afisate, doar cine le contine. */
.ocr-shell { flex-direction: column; min-width: 0; }
/* Antetul e in afara coloanei de 900px a cardurilor, deliberat: e antetul
   TABULUI, nu al unui mod, si trebuie sa cada in acelasi loc si peste layoutul
   full-width al review-ului. `flex-shrink: 0` -- altfel o lista lunga
   dedesubt l-ar comprima. */
.ocr-page-header {
  padding: 1.5rem 3rem 1rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.ocr-page-header .ocr-title { margin: 1rem 0 0.25rem; font-size: var(--font-heading); }
.ocr-page-header .ocr-subtitle { margin-bottom: 0; }
/* Antetul aduce deja spatiul de sus -- fara asta, titlul si prima carte ar
   pleca cu 2rem in plus fata de inainte. */
.ocr-view { flex-direction: column; padding: 1.5rem 3rem 2rem; overflow-y: auto; }
.ocr-container { max-width: 56.25rem; width: 100%; margin: 0 auto; }
.ocr-title { font-size: var(--font-hero); font-weight: 700; margin-bottom: 0.5rem; letter-spacing: -0.03em; }
.ocr-subtitle { font-size: var(--font-body); color: var(--text-muted); margin-bottom: 2rem; }
.ocr-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem; margin-bottom: 1rem;
}
.ocr-card h3 {
  font-size: var(--font-heading); font-weight: 600;
  margin-bottom: 0.75rem;
  display: flex; align-items: center; gap: 0.5rem;
}
.ocr-card h3 i { color: var(--accent); }

/* APP.1: tabul About -- lista de functii pe tab-uri si istoricul pe luni. */
.about-features { display: grid; grid-template-columns: max-content 1fr; gap: 0.6rem 1.25rem; }
.about-features dt { font-weight: 600; display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; }
.about-features dt i { color: var(--accent); }
.about-features dd { margin: 0; color: var(--text-muted); line-height: 1.5; }
.about-month { font-weight: 600; margin: 1rem 0 0.4rem; }
.about-month:first-child { margin-top: 0; }
.about-list { margin: 0; padding-left: 1.25rem; color: var(--text-muted); line-height: 1.5; }
.about-list li { margin-bottom: 0.3rem; }
/* APP.4: randurile si notele doar pentru modul complet dispar in modul invitat. */
body.guest-mode .about-full { display: none; }

/* UIX.38: mini-nav cu ancore la Settings, grupat pe teme — cerut de user 2026-09-14
   ("pune setarile pe categorii... acum sunt toate gramada"). `.settings-section` n-are
   stil propriu (fundal/bordură) ca să nu dubleze vizual `.ocr-card` — doar spațiază
   grupul și dă `scroll-margin-top`, ca ancora să nu sară sub bara lipicioasă de mai sus. */
.settings-nav {
  position: sticky; top: 0; z-index: 10;
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  padding: 0.75rem 0; margin-bottom: 1rem;
  background: var(--bg-body);
  border-bottom: 1px solid var(--border);
}
.settings-nav a {
  display: inline-flex; align-items: center; gap: 0.375rem;
  padding: 0.375rem 0.75rem;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--bg-card);
  color: var(--text-muted); font-size: var(--font-small);
  text-decoration: none;
}
.settings-nav a:hover { color: var(--text-primary); border-color: var(--accent); }
/* WUI.10: sub-navul comuta acum pagini reale, nu doar sare cu ancora --
   fiecare sectiune e ascunsa pana devine cea activa. */
.settings-nav a.active {
  color: var(--text-primary); border-color: var(--accent);
  background: var(--bg-active); font-weight: 600;
}
.settings-section { scroll-margin-top: 3.5rem; display: none; }
.settings-section.active { display: block; }
.ocr-input {
  padding: 0.625rem 0.875rem;
  background: var(--bg-body);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary); font-family: inherit;
  font-size: var(--font-small); outline: none;
}
.ocr-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
.ocr-input:disabled { opacity: 0.55; cursor: not-allowed; }
/* UIX.3 (cerut de user 2026-09-04, „dropdownurile sa fie consistente ca look
   cu cele din database searches"): un `<select>` nativ isi desena propria rama
   si propria sageata, deci arata strain langa pilulele si panourile de optiuni
   din Database. Aceeasi rama/raza/fundal si acelasi inel de focus ca
   `.search-pill:focus-within`, plus un caret desenat de noi.
   Popup-ul ramane cel nativ al platformei: o lista proprie ar fi insemnat un
   component de dropdown de intretinut (tastatura, inchidere la click in afara,
   scroll) pentru exact acelasi rezultat vizual in stare inchisa. */
select.ocr-input {
  appearance: none; -webkit-appearance: none;
  padding-right: 2rem; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%23a8a29e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.625rem center;
  background-size: 0.875rem;
}
body.light-mode select.ocr-input { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%2378716c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }
select.ocr-input:hover:not(:disabled) { border-color: var(--text-dim); }
select.ocr-input option { background-color: var(--bg-card); color: var(--text-primary); }
.ocr-row { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
.ocr-row + .ocr-row { margin-top: 0.75rem; }
.ocr-row .grow { flex: 1; min-width: 0; }
/* CMP.12: „x” la capătul căii din Compare, ca la căutare (`.pill-clear`). */
.cmp-field { position: relative; display: flex; }
.cmp-field > .ocr-input { flex: 1; min-width: 0; padding-right: 2.25rem; }
.cmp-field > .pill-clear { position: absolute; right: 0.875rem; top: 50%; transform: translateY(-50%); }
.ocr-field { display: flex; flex-direction: column; gap: 0.25rem; }
.ocr-field label { font-size: var(--font-micro); color: var(--text-muted); }
.ocr-check { display: flex; align-items: center; gap: 0.5rem; font-size: var(--font-small); cursor: pointer; }
.ocr-check input { accent-color: var(--accent); cursor: pointer; }
.ocr-btn {
  padding: 0.5rem 1rem;
  background: var(--accent); color: #fff;
  border: none; border-radius: var(--radius);
  cursor: pointer; font-family: inherit;
  font-size: var(--font-small); font-weight: 600;
  display: inline-flex; align-items: center; gap: 0.375rem;
  transition: background 0.15s;
}
.ocr-btn:hover:not(:disabled) { background: var(--accent-hover); }
.ocr-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.ocr-btn.secondary { background: var(--bg-hover); color: var(--text-primary); }
.ocr-btn.danger { background: var(--status-review); }
.ocr-actions { display: flex; gap: 0.5rem; margin: 1.25rem 0; }
.ocr-progress { height: 0.5rem; background: var(--bg-body); border-radius: 4px; overflow: hidden; margin: 0.5rem 0; }
.ocr-progress-bar { height: 100%; width: 0; background: var(--accent); transition: width 0.3s; }
.ocr-muted { font-size: var(--font-small); color: var(--text-muted); }
.ocr-muted.warn { color: var(--status-review); }
.ocr-muted.bad { color: var(--danger, #ef4444); }

/* PDFDIFF.1 — avertisment (prag de asemanare, rezultat neconcludent) si tinta
   de drag & drop din tabul Compare. */
.ocr-warn { color: var(--danger, #ef4444); }
.ocr-input.drop-target { border-color: var(--accent); }
/* UIX.13: prima zona de text multi-linie din Settings. `.ocr-input` presupunea
   un `<input>` de o linie, deci fara asta textarea nu se putea redimensiona si
   isi trata inaltimea singura. */
textarea.ocr-input { resize: vertical; min-height: 6rem; line-height: 1.5; }
.ocr-muted.good { color: var(--status-ok); }
.ocr-log {
  background: var(--bg-body);
  border-radius: var(--radius);
  padding: 0.75rem;
  font-family: "Consolas", monospace;
  font-size: var(--font-micro);
  color: var(--text-muted);
  height: 12.5rem; overflow-y: auto;
  line-height: 1.6; white-space: pre-wrap;
}
.ocr-dropzone { outline: 2px dashed var(--accent); outline-offset: 2px; }

/* SPLIT.2.9 — tabel mic in interiorul unui `.ocr-card`. Nu `.file-table`:
   aceea e tabelul Explorer-ului, cu sticky/zebra/sort/drag, nimic din ce
   trebuie aici. */
.ocr-table { width: 100%; border-collapse: collapse; font-size: var(--font-small); }
.ocr-table th {
  text-align: left; font-size: var(--font-micro); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted);
  padding: var(--density-padding-y) var(--density-padding-x);
  border-bottom: 1px solid var(--border);
}
.ocr-table td {
  padding: var(--density-padding-y) var(--density-padding-x);
  border-bottom: 1px solid var(--border); vertical-align: top;
}
.ocr-table td.detail { color: var(--text-muted); word-break: break-word; }
.ocr-table .ocr-btn { padding: 0.25rem 0.6rem; font-size: var(--font-micro); }
.ocr-table td.actions { white-space: nowrap; }
/* SRCH.42 — sectiunile cozii de lucru. Tabelele stau intr-o cutie cu inaltime
   plafonata: „documente incomplete" are 111 randuri pe baza reala, iar patru
   carduri intinse cat lista lor ar face pagina imposibil de parcurs. Randurile
   raman toate acolo, doar ca in propriul scroll. */
.queue-rows { max-height: 22rem; overflow: auto; margin-bottom: 0.75rem; }
.queue-rows .ocr-table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-card);
}
.queue-empty { margin: 0.25rem 0 0; font-style: italic; }
.ocr-card h3 .inbox-badge.ocr-queue-count { margin-left: 0.5rem; }

.ocr-decision { font-weight: 600; }
.ocr-decision.accepted { color: var(--status-ok); }
.ocr-decision.rejected { color: var(--status-error); }
.ocr-decision.pending { color: var(--text-dim); font-weight: 400; }

/* WUI.5 — Inbox */
/* WATCH.1: tabul tine acum doua feed-uri, deci coloana (bara de mod + panouri),
   nu rand. Randul s-a mutat pe `.inbox-panes`, care pastreaza layoutul de
   dinainte neschimbat pentru review-ul OCR. */
.inbox-view { flex-direction: column; min-width: 0; }
.inbox-panes { display: flex; flex: 1; min-height: 0; min-width: 0; }
.inbox-badge {
  margin-left: auto; background: var(--status-review); color: #fff;
  font-size: var(--font-micro); font-weight: 700; border-radius: 999px;
  padding: 0.0625rem 0.4375rem; line-height: 1.4;
}
.inbox-list-pane {
  width: 20rem; flex-shrink: 0; border-right: 1px solid var(--border);
  display: flex; flex-direction: column; padding: 1rem; overflow: hidden;
}
.inbox-list-header { display: flex; align-items: baseline; justify-content: space-between; }
.inbox-list { list-style: none; overflow-y: auto; flex: 1; margin: 0; padding: 0; }
.inbox-list-item {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.625rem;
  border-radius: var(--radius); cursor: pointer; font-size: var(--font-small);
}
.inbox-list-item:hover { background: var(--bg-hover); }
.inbox-list-item.selected { background: var(--accent); color: #fff; }
.inbox-list-item .filename { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-detail-pane { flex: 1; min-width: 0; overflow-y: auto; padding: 1.5rem; }
.inbox-detail-empty { color: var(--text-muted); font-size: var(--font-body); }
.inbox-split { display: flex; gap: 1rem; height: 26rem; }
.inbox-pdf-box, .inbox-text-box {
  flex: 1; min-width: 0; overflow: auto; border: 1px solid var(--border);
  border-radius: var(--radius-lg); background: var(--bg-card);
}
.inbox-pdf-box { display: flex; align-items: flex-start; justify-content: center; }
.inbox-pdf-img { max-width: 100%; }
.inbox-text-box {
  padding: 0.875rem; font-family: "Consolas", monospace; font-size: var(--font-micro);
  white-space: pre-wrap; color: var(--text-primary);
}

/* ═══ WATCH.1 — feed changedetection.io ═══
   Doar token-uri deja definite, deci `body.light-mode` merge fara nicio regula
   in plus. Necitit imprumuta `--status-new` (albastrul de "fisier nou" din
   Database), nu accentul — accentul inseamna deja "selectat" in toata aplicatia. */
.watch-modes {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.75rem 1rem; border-bottom: 1px solid var(--border);
}
.watch-modes .grow { flex: 1; min-width: 0; text-align: right; }
/* UIX.21: cele doua moduri ale tabului Downloader (Downloads / File Status).
   Acelasi idiom ca `.watch-modes` de mai sus, dar FARA `border-bottom`: in
   `#downloaderView` urmeaza imediat `.dl-source-tabs`, care are deja o linie
   proprie, iar doua linii lipite arata ca o greseala. */
.dl-modes {
  display: flex; align-items: center; gap: 0.5rem;
  flex-shrink: 0;
}
/* WATCH.16: idem `.watch-modes .inbox-badge` — badge-ul de numar (ex. "Review
   (3)") lipit de textul butonului fara marginea asta. */
.dl-modes .inbox-badge { margin-left: 0.375rem; }
.watch-modes .inbox-badge { margin-left: 0.375rem; }
#downloadsModules .inbox-badge { margin-left: 0.375rem; }
/* INBOX.9: fisierele unei rulari RCP, desfacute sub randul ei */
.dl-grup-fisiere { list-style: none; margin: 0; padding: 0 0 0 1rem; }
/* Cine tine datele la zi. Discret, dar nu ascuns: cand nu sincronizeaza nimeni,
   asta e singurul loc din care afli de ce nu se mai misca nimic. */
.watch-publisher {
  flex-shrink: 0; font-size: var(--font-micro); color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 999px; padding: 0.0625rem 0.5rem;
}

/* Panoul listei e ingust (20rem implicit), deci controalele se aseaza pe randuri
   si au voie sa treaca pe urmatorul cand nu incap — nu se comprima pana devin
   ilizibile. Butonul „aprins" imprumuta acelasi idiom ca `.watch-modes`: activ =
   accent (fara `.secondary`), inactiv = secundar. */
.watch-toolbar { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.5rem; }
.watch-toolbar .grow { flex: 1 1 7rem; min-width: 0; }
/* Controalele stau peste lista, deci fiecare rand pe care il ocupa e un rand de
   fir in minus. Aceleasi butoane, la corp mic. */
.watch-toolbar.compact .ocr-btn { padding: 0.3125rem 0.5rem; font-size: var(--font-micro); }
.watch-toolbar.compact .ocr-input { padding: 0.3125rem 0.5rem; font-size: var(--font-micro); }
.watch-toolbar.compact select.ocr-input { padding-right: 1.5rem; background-position: right 0.375rem center; }
.watch-toolbar.compact .ocr-muted { font-size: var(--font-micro); text-align: right; }

.watch-sources {
  max-height: 13rem; overflow-y: auto; margin-bottom: 0.5rem; padding: 0.375rem;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-card);
}
.watch-source-row {
  display: flex; align-items: center; gap: 0.5rem; cursor: pointer;
  padding: 0.1875rem 0.25rem; border-radius: var(--radius-sm);
  font-size: var(--font-micro); color: var(--text-muted);
}
.watch-source-row:hover { background: var(--bg-hover); }
.watch-source-row span {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.watch-source-row.on { color: var(--text-primary); }

/* WATCH.9: „N files have offline OCR — Redo with Azure", deasupra listei Downloads.
   Ascuns cand niciun fisier nu e eligibil (`.hidden`, aplicat din JS). */
.downloads-azure-banner {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.75rem; margin: 0 0 0.5rem;
  background: var(--accent-glow); border: 1px solid var(--accent);
  border-radius: var(--radius); font-size: var(--font-small);
}
.downloads-azure-banner i { color: var(--accent); flex-shrink: 0; }

/* Un fir = o sursa. Randul de sus e sursa, `<ul>`-ul de dedesubt schimbarile ei
   — acelasi gest ca un thread de mail: click pe fir il deschide si il desface. */
.watch-thread { border-bottom: 1px solid var(--border); }
.watch-thread:last-child { border-bottom: none; }
.watch-thread-head {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.375rem;
  cursor: pointer; border-radius: var(--radius); font-size: var(--font-small);
}
.watch-thread-head:hover { background: var(--bg-hover); }
.watch-thread.open > .watch-thread-head { background: var(--bg-active); }
.watch-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 999px; flex-shrink: 0;
  background: var(--status-new);
}
.watch-dot.read { background: transparent; }
/* Titlu si adresa, una sub alta. Italicul si corpul mic spun deja „secundar",
   deci culoarea e `--text-muted`, nu `--text-dim` ca la `.watch-when`: pe dark,
   `--text-dim` (#78716c) la 11px inclinat, pe o cale lunga, se citeste greu. */
.watch-thread-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.watch-thread-title {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.watch-thread-url {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--font-micro); font-style: italic; color: var(--text-muted);
}
/* WATCH.17: 700 pe langa titlul deja marcat <strong> era prea greu de citit --
   redus la 600, ca la .watch-event.unread mai jos. */
.watch-thread.unread .watch-thread-title { font-weight: 600; }
/* WATCH.13: institutia (inaintea primului " - ") vine deja bold din <strong>;
   restul titlului e bold + italic, cerut explicit de user 2026-09-14. */
.watch-thread-title-rest { font-style: italic; }
/* Coloana din dreapta, oglinda celei din stanga: sus cate schimbari noi (in
   albastrul bulinei, ca sa lege cifra de buline), jos cand s-a schimbat si cand
   a fost verificata ultima oara — cu eticheta, ca „2h ago" singur nu spunea care
   din ele e. */
.watch-meta {
  display: flex; flex-direction: column; align-items: flex-end;
  flex-shrink: 0; text-align: right;
}
.watch-new { font-size: var(--font-micro); font-weight: 700; color: var(--status-new); }
.watch-when {
  color: var(--text-dim); font-size: var(--font-micro);
  flex-shrink: 0; white-space: nowrap;
}
/* Momentul schimbarii e ce cauti pe rand; verificarea e doar context. Un pas de
   culoare si greutate intre ele, nu doua randuri la fel de tari. */
.watch-when strong { color: var(--text-muted); font-weight: 700; }
.watch-thread-err { color: var(--status-error); flex-shrink: 0; }
/* WATCH.22: buton de retry pe rândul eșuat — culoarea neutră normal, accent la hover,
   ca omul să vadă că e apăsabil (nu doar un alt indicator, ca `.watch-thread-err`). */
.watch-thread-retry {
  color: var(--text-dim); flex-shrink: 0; cursor: pointer; margin-left: 0.25rem;
}
.watch-thread-retry:hover { color: var(--accent); }
/* WATCH.4: mesajele Monitorului Oficial — detaliul se citeste intreg (e instructiunea),
   deci se rupe pe randuri, nu se taie ca titlul; iconita spune felul mesajului. */
.mo-detail { font-size: var(--font-micro); color: var(--text-muted); white-space: normal; }
.mo-tip { flex-shrink: 0; color: var(--text-dim); margin-right: 0.15rem; }
.mo-tip-claude, .mo-tip-protocols, .mo-tip-saved { color: var(--accent); }
.mo-tip-report { color: var(--status-ok); }
.mo-tip-azure, .mo-tip-error { color: var(--status-error); }
/* WATCH.31: NEW / UPDATED pe rândul unei descărcări, în tonurile deja folosite pentru statusuri. */
.dl-status {
  flex-shrink: 0; font-size: var(--font-micro); font-weight: 700; letter-spacing: 0.03em;
  padding: 0.05rem 0.45rem; border-radius: 999px; border: 1px solid currentColor;
}
.dl-status-new { color: var(--status-new); background: rgba(59, 130, 246, 0.12); }
.dl-status-updated { color: var(--status-review); background: rgba(249, 115, 22, 0.12); }

.watch-events { list-style: none; margin: 0 0 0.375rem; padding: 0 0 0 1rem; }
.watch-event {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.3125rem 0.5rem; border-radius: var(--radius-sm); cursor: pointer;
  font-size: var(--font-micro); color: var(--text-muted);
}
.watch-event:hover { background: var(--bg-hover); }
.watch-event.unread { color: var(--text-primary); font-weight: 600; }
.watch-event.selected { background: var(--accent); color: #fff; }
/* Fiecare schimbare are bulina ei — citit/necitit se tine per schimbare, nu per
   sursa (cerut 2026-09-04: „ele ar trebui sa fie individuale per notificare"). */
.watch-event .watch-dot { width: 0.375rem; height: 0.375rem; }
.watch-event.selected .watch-dot { background: #fff; }
.watch-event.selected .watch-dot.read { background: transparent; }
.watch-more { padding: 0.3125rem 0.5rem; font-size: var(--font-micro); color: var(--text-dim); }

.watch-detail-head { margin-bottom: 1.25rem; }
.watch-detail-head h2 { font-size: var(--font-title); font-weight: 700; letter-spacing: -0.02em; }
.watch-tag {
  display: inline-block; background: var(--bg-hover); color: var(--text-muted);
  border-radius: 999px; padding: 0.0625rem 0.5rem; font-size: var(--font-micro);
  margin-right: 0.25rem;
}
.watch-error, .watch-summary {
  margin-top: 0.75rem; padding: 0.625rem 0.75rem; border-radius: var(--radius);
  font-size: var(--font-small); border: 1px solid var(--border);
}
.watch-error { border-color: var(--status-error); color: var(--status-error); }
.watch-summary { background: var(--bg-card); color: var(--text-muted); }

/* Diff-ul: monospace ca `.inbox-text-box`. Adaugatul verde, stersul rosu taiat —
   pe un fundal plin la fel de tare, blocul obosea, deci fundalul e doar o umbra
   de culoare, iar textul poarta culoarea. Verdele si rosul se schimba pe light
   mode: `--status-ok`/`--status-error` sunt calibrate pentru fundal inchis si
   pe alb devin greu de citit. */
.watch-diff {
  --diff-add: #4ade80; --diff-add-bg: rgba(34, 197, 94, 0.12);
  --diff-del: #e08b87; --diff-del-bg: rgba(239, 68, 68, 0.09);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--bg-card); overflow-x: auto;
  font-family: "Consolas", monospace; font-size: var(--font-small);
}
body.light-mode .watch-diff {
  --diff-add: #15803d; --diff-add-bg: rgba(34, 197, 94, 0.16);
  --diff-del: #b4524e; --diff-del-bg: rgba(239, 68, 68, 0.11);
}
.watch-diff-line {
  display: block; white-space: pre-wrap; word-break: break-word;
  padding: 0.125rem 0.75rem 0.125rem 0.5rem; border-left: 3px solid transparent;
  color: var(--text-muted); line-height: 1.5;
}
.watch-diff-line.add {
  border-left-color: var(--status-ok); background: var(--diff-add-bg);
  color: var(--diff-add);
}
.watch-diff-line.del {
  border-left-color: var(--status-error); background: var(--diff-del-bg);
  color: var(--diff-del);
  /* Taiat, dar linia mai stinsa decat textul — altfel taietura acopera literele. */
  text-decoration: line-through; text-decoration-color: rgba(239, 68, 68, 0.5);
}
.watch-diff-line.hunk {
  background: var(--bg-hover); color: var(--text-dim);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  margin: 0.25rem 0;
}
.watch-diff-empty { padding: 0.875rem; color: var(--text-muted); font-family: inherit; }

.hidden { display: none !important; }

/* ── HEALTH.1: panoul de sănătate din Settings ─────────────────────── */
.health-families {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.35rem 1rem; margin-top: 0.75rem;
}
.health-fam { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; }
.health-fam span:first-of-type { flex: 1; }
.health-cost { color: var(--text-muted); font-size: 0.85em; }

.health-family { margin-top: 1rem; border-left: 3px solid var(--border); padding-left: 0.75rem; }
.health-family h4 { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.25rem; }
.health-family h4 .health-cost { margin-left: auto; }
.health-dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; background: var(--status-ok, #3fb950); }
/* Severitatea colorează bara laterală și buluțul, nu rândul întreg: un tabel
   pe fundal roșu se citește ca „totul e stricat", când de fapt o singură
   constatare din familie a găsit ceva. */
.health-family.sev-atentie { border-left-color: var(--status-review, #d29922); }
.health-family.sev-atentie .health-dot { background: var(--status-review, #d29922); }
.health-family.sev-eroare { border-left-color: var(--status-error, #f85149); }
.health-family.sev-eroare .health-dot { background: var(--status-error, #f85149); }

.health-table { width: 100%; border-collapse: collapse; font-size: 0.92em; }
.health-table td, .health-table th { padding: 0.25rem 0.5rem; vertical-align: top; text-align: left; }
.health-table tbody tr:nth-child(odd) { background: var(--bg-hover); }
.health-table td:first-child { width: 40%; }
.health-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.health-hit .health-num { font-weight: 600; }
.health-detail { color: var(--text-muted); }
.health-err { color: var(--status-error, #f85149); }
.health-act { padding: 0.15rem 0.6rem; font-size: 0.85em; }
.health-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent, #58a6ff); text-decoration: underline; font: inherit;
}

/* SHARE.3 — modul light: ce scrie dispare, iar semnul din bara laterala nu e buton. */
body.read-only .full-only { display: none !important; }
.read-only-badge { cursor: default; opacity: 0.75; }
.read-only-badge:hover { background: transparent; }
/* SHARE.3 etapa 3: cu parola setata, semnul deschide „Unlock full mode". */
.read-only-badge.unlockable { cursor: pointer; }
.read-only-badge.unlockable:hover { opacity: 1; }
/* SHARE.3 etapa 4: punctul (stilul butonului de publicare) pulseaza cat vine copia noua. */
.read-only-badge { position: relative; }
.read-only-badge.downloading .team-publish-dot {
  background: var(--accent, #58a6ff); animation: team-publish-puls 1s ease-in-out infinite;
}

/* SHARE.3 etapa 2 — butonul de publicare din full; punctul: galben = nepublicat,
   rosu = eroare sau conflict, pulseaza cat publica. */
.team-publish { position: relative; }
.team-publish-dot {
  position: absolute; top: 6px; left: 22px; width: 7px; height: 7px; border-radius: 50%;
  background: transparent;
}
.team-publish.unpublished .team-publish-dot { background: var(--status-review, #d29922); }
.team-publish.problem .team-publish-dot { background: var(--status-error, #f85149); }
.team-publish.busy .team-publish-dot {
  background: var(--accent, #58a6ff); animation: team-publish-puls 1s ease-in-out infinite;
}
@keyframes team-publish-puls { 50% { opacity: 0.25; } }

/* SHARE.16 — panoul Publish: langa bara laterala, jos, peste continut. */
.publish-panel {
  position: fixed; left: calc(var(--sidebar-width-collapsed) + 1rem); bottom: 1rem;
  width: 30rem; max-width: calc(100vw - var(--sidebar-width-collapsed) - 2rem);
  background-color: var(--bg-card); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: var(--radius);
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.35);
  padding: 0.75rem 0.875rem; z-index: 1500; font-size: var(--font-small);
}
.publish-panel.hidden { display: none; }
.publish-panel-head { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; }
.publish-panel-head span { flex: 1; }
.publish-panel-x {
  background: transparent; border: none; color: var(--text-muted); cursor: pointer;
  padding: 0.125rem; border-radius: var(--radius-sm);
}
.publish-panel-x:hover { color: var(--text-primary); background-color: var(--bg-hover); }
.publish-panel-step { margin-top: 0.5rem; color: var(--text-primary); }
.publish-panel-meta { color: var(--text-muted); font-size: var(--font-micro); }
.publish-panel-log {
  margin: 0.5rem 0; padding: 0.5rem; max-height: 14rem; overflow: auto;
  background-color: var(--bg-body); border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--font-micro); white-space: pre-wrap; word-break: break-word;
}
.publish-panel-log:empty { display: none; }
.publish-panel-foot { display: flex; align-items: center; gap: 0.5rem; }
.publish-panel-file {
  flex: 1; min-width: 0; color: var(--text-dim); font-size: var(--font-micro);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* UIX.9 — tabul LLM: lista de fisiere (inbox + biblioteca) si raspunsul modelului. */
.llm-files {
  max-height: 22rem; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  margin: 0.5rem 0;
}
.llm-file {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--border); cursor: pointer;
}
.llm-file:last-child { border-bottom: none; }
.llm-file:hover { background: var(--bg-hover); }
.llm-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.llm-detail { white-space: nowrap; font-size: var(--font-small); }
.llm-origin {
  font-size: var(--font-micro); padding: 0.05rem 0.45rem; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-muted); white-space: nowrap;
}
.llm-origin-library { color: var(--accent); border-color: var(--accent); }
/* UIX.74: OLD / NEW pe cele 2 fișiere bifate (ordinea folosită la comparații). */
.llm-ord:empty { display: none; }
.llm-ord {
  font-size: var(--font-micro); font-weight: 700; padding: 0.05rem 0.45rem;
  border-radius: 999px; border: 1px solid currentColor; white-space: nowrap;
}
.llm-ord-old { color: var(--text-muted); }
.llm-ord-new { color: var(--status-ok); }
.llm-step { margin-top: 1rem; }
.llm-edit-prompts { float: right; font-size: var(--font-small); }
.llm-empty { padding: 1rem; text-align: center; }
.llm-modes { gap: 1.25rem; flex-wrap: wrap; }
.llm-actions { flex-wrap: wrap; }
#llmFilesCard.drop-target { outline: 2px dashed var(--accent); outline-offset: 2px; }
.llm-result {
  white-space: pre-wrap; font-family: inherit; margin: 0 0 0.5rem;
  max-height: 32rem; overflow-y: auto; user-select: text;
}

/* EMA.2 — tabul EMA (js/ema.js) */
#emaRows { max-height: 65vh; }
.ema-table td { vertical-align: top; }
.ema-table .ema-date { white-space: nowrap; }
.ema-table .ema-cnas { font-size: 0.85em; margin-top: 0.15rem; }
.ema-table .ema-ind { max-width: 30rem; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.ema-kind { font-weight: 600; white-space: nowrap; }
.ema-kind.ema-ok { color: var(--status-ok); }
.ema-kind.ema-wait { color: var(--accent); }
.ema-kind.ema-neg { color: var(--status-error); }
.ema-kind.ema-end { color: var(--text-muted); }
/* EMA.4: panoul — trei coloane, una sub alta pe ecran îngust */
.ema-detail-open { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; }
.ema-detail-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: 1rem; max-height: 64vh; overflow: auto; }
.ema-detail-cols h4 { margin: 0 0 0.5rem; }
.ema-detail-cols p { margin: 0 0 0.5rem; line-height: 1.45; }
.ema-detail-cols ol { margin: 0; padding-left: 1.25rem; }
.ema-detail-cols li { margin-bottom: 0.5rem; line-height: 1.45; }
