:root {
  --bg: #f5f6f8;
  --panel: #ffffff;
  --border: #dde1e6;
  --text: #1c2128;
  --text-dim: #5b6570;
  --accent: #2563eb;
  --accent-dim: #dbe7fd;
  --sidebar-bg: #14213d;
  --sidebar-text: #cbd5e1;
  --sidebar-text-dim: #8a97ac;
  --sidebar-active: #1f2f57;
  --danger: #b3261e;
  /* Export is the only action sharing a toolbar with four settings controls,
     and the accent cannot carry it: the active subtable chip, the selected
     menu item and every link are already accent blue, so an accent button
     joins the pattern instead of breaking it. Green is unused elsewhere in
     this UI and is what a spreadsheet download is expected to look like. */
  --export: #15803d;
  --export-text: #ffffff;
  --mono: "Cascadia Code", "Consolas", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f1115;
    --panel: #1a1d24;
    --border: #2a2e37;
    --text: #e6e8eb;
    --text-dim: #9aa3af;
    --accent: #5b8def;
    --accent-dim: #1c2a45;
    --sidebar-bg: #0b0e14;
    --sidebar-text: #cbd5e1;
    --sidebar-text-dim: #8a97ac;
    --sidebar-active: #1c2333;
    --danger: #ff6b6b;
    /* Light green on dark text: on a dark page a deep green reads as muddy
       rather than as a button, and this keeps the contrast well past AA. */
    --export: #34d399;
    --export-text: #06281a;
  }
}

* { box-sizing: border-box; }
body { margin: 0; font-family: -apple-system, Segoe UI, Roboto, Arial, sans-serif; background: var(--bg); color: var(--text); }

#app { display: flex; min-height: 100vh; }

#sidebar {
  width: 300px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  display: flex;
  flex-direction: column;
  padding: 16px 14px;
  gap: 14px;
  overflow-y: auto;
}

.brand { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 16px; color: #fff; padding: 4px 4px 8px; border-bottom: 1px solid #ffffff22; }
.brand-icon { font-size: 18px; }

#loader-box { display: flex; flex-direction: column; gap: 6px; }
#loader-box label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--sidebar-text-dim); }
#path-input {
  background: #ffffff10; border: 1px solid #ffffff26; color: #fff; border-radius: 6px;
  padding: 8px 10px; font-size: 13px; font-family: var(--mono);
}
#path-input::placeholder { color: #8a97ac; }
#load-btn, #browse-btn, #fs-browse-btn, #open-folder-btn {
  background: var(--accent); color: #fff; border: none; border-radius: 6px;
  padding: 9px 10px; font-size: 13px; font-weight: 600; cursor: pointer;
}
#load-btn:hover, #browse-btn:hover, #fs-browse-btn:hover { filter: brightness(1.1); }
#load-btn:disabled, #browse-btn:disabled, #fs-browse-btn:disabled { opacity: .6; cursor: default; }
#load-btn.secondary, #browse-btn { background: #ffffff14; }
#load-btn.secondary:hover, #browse-btn:hover { background: #ffffff22; filter: none; }
.browse-label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--sidebar-text-dim); }
.browse-hint { font-size: 11.5px; color: var(--sidebar-text-dim); line-height: 1.4; }
.browse-hint code { background: #ffffff14; color: var(--sidebar-text); padding: 1px 4px; border-radius: 4px; font-size: 11px; }

.or-divider {
  display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--sidebar-text-dim);
  text-transform: uppercase; letter-spacing: .04em; margin-top: 4px;
}
.or-divider::before, .or-divider::after { content: ""; flex: 1; height: 1px; background: #ffffff1f; }
#load-status { font-size: 12px; color: var(--sidebar-text-dim); min-height: 16px; }
#load-status.error { color: #ff8a8a; }
#load-status.ok { color: #7ee0a5; }

.candidate-box { display: flex; flex-direction: column; gap: 4px; }
.candidate-box .candidates-label { font-size: 11px; color: var(--sidebar-text-dim); margin-top: 2px; }
.candidate-box .candidate-item {
  display: flex; justify-content: space-between; align-items: baseline; gap: 8px; background: #ffffff10;
  border: 1px solid #ffffff26; border-radius: 6px; padding: 7px 10px; font-size: 12.5px; cursor: pointer;
}
.candidate-box .candidate-item:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.candidate-box .candidate-item .cand-type {
  font-size: 10.5px; color: var(--sidebar-text-dim); margin-left: 6px;
}
.candidate-box .candidate-item:hover .cand-type { color: #ffffffcc; }
.candidate-box .candidate-item .sz { color: var(--sidebar-text-dim); white-space: nowrap; }
.candidate-box .candidate-item:hover .sz { color: #ffffffcc; }
.candidate-box .browse-error {
  font-size: 12px; color: #ff8a8a; background: #ff8a8a18; border: 1px solid #ff8a8a44;
  border-radius: 6px; padding: 8px 10px; line-height: 1.4;
}

#recent-projects { display: flex; flex-direction: column; gap: 4px; max-height: 30vh; overflow-y: auto; }
.recent-item-row {
  display: flex; align-items: center; gap: 4px;
}
.recent-item-row .recent-item {
  flex: 1; min-width: 0;
}
.recent-remove {
  flex-shrink: 0; width: 22px; height: 22px; border-radius: 6px; border: none; background: transparent;
  color: var(--sidebar-text-dim); font-size: 15px; line-height: 1; cursor: pointer;
}
.recent-remove:hover { background: #ff8a8a26; color: #ff8a8a; }
#clear-all-btn {
  align-self: flex-start; background: transparent; border: none; color: var(--sidebar-text-dim);
  font-size: 11.5px; cursor: pointer; padding: 2px 2px; text-decoration: underline;
}
#clear-all-btn:hover { color: #ff8a8a; }

.recent-item {
  font-size: 12px; color: var(--sidebar-text-dim); background: #ffffff08; border-radius: 6px;
  padding: 6px 8px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.recent-item:hover { background: #ffffff14; color: #fff; }

nav#menu { display: flex; flex-direction: column; gap: 2px; }
.menu-section-title { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--sidebar-text-dim); margin: 10px 4px 2px; }
.menu-item {
  text-align: left; background: transparent; border: none; color: var(--sidebar-text);
  padding: 8px 10px; border-radius: 6px; font-size: 13.5px; cursor: pointer; display: flex; justify-content: space-between;
}
.menu-item:hover { background: #ffffff10; color: #fff; }
.menu-item.active { background: var(--sidebar-active); color: #fff; font-weight: 600; }
.menu-item .count { color: var(--sidebar-text-dim); font-weight: 400; font-size: 12px; }
.hidden { display: none !important; }

#content { flex: 1; padding: 28px 34px; overflow-x: hidden; overflow-y: auto; max-height: 100vh; }

/* ---------- Breadcrumb ----------
   The site is three levels deep - board, study, view - and every page below
   the board shows the whole path with each step above it clickable. */
#crumbs {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-bottom: 14px; font-size: 12.5px;
}
.crumb {
  background: none; border: none; padding: 2px 0; font-family: inherit; font-size: 12.5px;
  color: var(--accent); cursor: pointer; border-radius: 4px;
}
.crumb:hover { text-decoration: underline; }
.crumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.crumb-here { color: var(--text-dim); cursor: default; }
.crumb-here:hover { text-decoration: none; }
.crumb-sep { color: var(--text-dim); }

/* The sidebar's own way back, for when the breadcrumb has scrolled away. */
.menu-item.back-item { color: var(--sidebar-text-dim); margin-bottom: 4px; }
.menu-item.back-item:hover { color: #fff; }

#welcome { max-width: 640px; margin-top: 40px; }
#welcome h1 { font-size: 24px; }
#welcome p { color: var(--text-dim); line-height: 1.5; }
#welcome .hint { font-size: 13px; }
code { background: var(--accent-dim); padding: 1px 5px; border-radius: 4px; font-family: var(--mono); }

.page-title { font-size: 20px; font-weight: 700; margin-bottom: 2px; }
.page-desc { color: var(--text-dim); font-size: 13.5px; margin-bottom: 18px; }
.page-title-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }
.violations-report-box { text-align: right; flex-shrink: 0; }
.violations-report-btn {
  padding: 9px 16px; border-radius: 8px; border: none; background: var(--danger); color: #fff;
  font-size: 12.5px; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.violations-report-btn:hover { filter: brightness(1.1); }
.violations-report-btn:disabled { opacity: .6; cursor: default; }
/* "Checked, and clean" - a statement, not an action. Deliberately not the
   danger colour: red here reads as "violations found" at a glance, which is
   the opposite of what it says. */
.violations-clean { font-size: 12.5px; color: var(--text-dim); white-space: nowrap; }

.card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 16px 18px; margin-bottom: 18px;
}
.card h3 { margin: 0 0 10px; font-size: 14px; text-transform: uppercase; letter-spacing: .03em; color: var(--text-dim); }

.kv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px 20px; }
/* min-width lets a cell shrink below its content, and the wrap breaks strings
   with nowhere natural to break - a file path, a Windows share. Without both,
   a long value runs straight out of its cell and over its neighbours. */
.kv-grid .kv { font-size: 13px; min-width: 0; }
.kv-grid .k { color: var(--text-dim); }
.kv-grid .v { font-weight: 600; overflow-wrap: anywhere; }

/* ---------- Overview info cards ----------
   Three shapes, because an info table is three different things: a single
   record (key/value), a Metric/Unit/Value report (a labelled list), or an
   ordinary multi-row table. */

.card h3 .detail-count {
  float: right; font-weight: 400; text-transform: none; letter-spacing: 0;
  font-size: 12px; color: var(--text-dim);
}

.metric-list { display: flex; flex-direction: column; }
.metric-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 5px 0; border-bottom: 1px solid var(--border); font-size: 13px;
}
.metric-row:last-child { border-bottom: none; }
.metric-name { color: var(--text-dim); }
.metric-val { font-weight: 600; white-space: nowrap; text-align: right; }
.metric-unit { font-weight: 400; color: var(--text-dim); font-size: 12px; }
/* ETAP writes blank rows as report spacers and "-- ... --" as section heads. */
.metric-gap { height: 10px; }
.metric-section {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
  color: var(--text-dim); padding: 10px 0 4px; border-bottom: 1px solid var(--border);
}

.mini-scroll { overflow-x: auto; }
table.mini-table { border-collapse: collapse; width: 100%; font-size: 12.5px; }
table.mini-table th, table.mini-table td {
  padding: 5px 12px 5px 0; border-bottom: 1px solid var(--border);
  text-align: left; white-space: nowrap;
}
table.mini-table th {
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-dim); font-weight: 600;
}
table.mini-table tbody tr:last-child td { border-bottom: none; }
table.mini-table tbody tr:hover { background: var(--accent-dim); }

.info-details > summary {
  cursor: pointer; list-style: none; display: block;
}
.info-details > summary::-webkit-details-marker { display: none; }
.info-details > summary h3 { display: inline; }
.info-details > summary h3::before { content: "\25B8\00a0"; color: var(--text-dim); }
.info-details[open] > summary h3::before { content: "\25BE\00a0"; }
.info-details > summary:hover h3 { color: var(--accent); }
.info-details > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.info-details[open] > summary { margin-bottom: 10px; }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 12px; }
.stat-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px;
  cursor: pointer; transition: border-color .15s;
}
.stat-card:hover { border-color: var(--accent); }
.stat-card .num { font-size: 26px; font-weight: 700; color: var(--accent); }
.stat-card .lbl { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }

/* Wrapping is not cosmetic here. The toolbar needs ~860px and #content hides
   horizontal overflow, so below about 1100px the last controls - Export and
   the row count - sat outside the viewport with no way to scroll to them.
   They were not hard to find; they were unreachable. */
.table-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; }
.table-toolbar input[type=search] {
  flex: 1; max-width: 320px; padding: 7px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 13px;
}
.table-toolbar .row-count { font-size: 12.5px; color: var(--text-dim); margin-left: auto; }
.table-toolbar select {
  padding: 7px 8px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 12.5px;
}
.search-col-select { max-width: 160px; }
.col-toggle-btn {
  padding: 7px 12px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 12.5px; cursor: pointer; white-space: nowrap;
}
.col-toggle-btn:hover { border-color: var(--accent); color: var(--accent); }

.col-panel {
  border: 1px solid var(--border); border-radius: 10px; background: var(--panel);
  padding: 12px 14px; margin-bottom: 10px;
}
.col-panel-actions { display: flex; gap: 8px; margin-bottom: 10px; }
.col-panel-actions button {
  padding: 5px 10px; border-radius: 6px; border: 1px solid var(--border); background: transparent;
  color: var(--text-dim); font-size: 12px; cursor: pointer;
}
.col-panel-actions button:hover { border-color: var(--accent); color: var(--accent); }
.col-panel-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 4px 12px;
  max-height: 220px; overflow-y: auto;
}
.col-panel-list label { font-size: 12.5px; display: flex; align-items: center; gap: 6px; cursor: pointer; }

/* The one action among the toolbar's settings, and it used to carry exactly
   the same styling as the Columns toggle beside it - so it read as a fourth
   dropdown and went unfound. Filled accent is what this app uses everywhere
   else for "this does something": Load, Select This Folder, Violations
   Report. */
.export-toggle-btn {
  padding: 8px 16px; border-radius: 6px; border: none;
  background: var(--export); color: var(--export-text);
  font-size: 13px; font-weight: 700; cursor: pointer; white-space: nowrap;
}
.export-toggle-btn:hover { filter: brightness(1.08); }
.export-toggle-btn:focus-visible { outline: 2px solid var(--export); outline-offset: 2px; }
.export-panel {
  border: 1px solid var(--border); border-radius: 10px; background: var(--panel);
  padding: 12px 14px; margin-bottom: 10px;
}
.export-note { font-size: 12px; color: var(--text-dim); margin-bottom: 10px; }
.export-panel-actions { display: flex; gap: 8px; }
.export-panel-actions button {
  padding: 7px 14px; border-radius: 6px; border: 1px solid var(--accent); background: var(--accent-dim);
  color: var(--accent); font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.export-panel-actions button:hover { background: var(--accent); color: #fff; }
.export-status { font-size: 12px; color: var(--text-dim); margin-top: 8px; }

/* Filesystem-backed controls. Hidden while the deploy mode is still unknown,
   and permanently on a hosted instance where the API refuses those endpoints.
   Hiding by default is the point: the alternative - showing them and removing
   them once /api/config answers - leaves them clickable for however long that
   request takes, which on a cold start is seconds. */
body.config-pending .local-only,
body.hosted .local-only { display: none !important; }

.truncation-note {
  font-size: 12.5px; color: var(--warn, #d08b28); margin-bottom: 10px;
  padding: 9px 12px; border-radius: 8px;
  border: 1px solid var(--warn, #d08b28); background: rgba(208, 139, 40, 0.09);
}

.table-scroll { overflow: auto; border: 1px solid var(--border); border-radius: 10px; max-height: 60vh; background: var(--panel); }
table.data-table { border-collapse: collapse; width: max-content; min-width: 100%; font-size: 12.5px; }
table.data-table th, table.data-table td {
  padding: 6px 10px; border-bottom: 1px solid var(--border); white-space: nowrap; text-align: left;
}
table.data-table thead th {
  position: sticky; top: 0; background: var(--panel); cursor: pointer; user-select: none;
  border-bottom: 2px solid var(--border); z-index: 1;
}
table.data-table thead th:hover { color: var(--accent); }
table.data-table tbody tr:hover { background: var(--accent-dim); }
.null-cell { color: var(--text-dim); font-style: italic; }

table.data-table tfoot {
  position: sticky; bottom: 0;
}
table.data-table tfoot td {
  background: var(--accent-dim); border-top: 2px solid var(--accent); border-bottom: none;
  font-weight: 700; color: var(--accent);
}
table.data-table tfoot td.stat-label {
  text-transform: uppercase; font-size: 11px; letter-spacing: .03em;
}

.pager { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 10px; }
.pager-btn {
  padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--panel);
  color: var(--text); font-size: 12.5px; cursor: pointer;
}
.pager-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.pager-btn:disabled { opacity: .4; cursor: default; }
.pager-info { font-size: 12.5px; color: var(--text-dim); }

.subtable-tabs { display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap; }
.subtable-tab {
  padding: 6px 12px; border-radius: 20px; border: 1px solid var(--border); background: var(--panel);
  color: var(--text-dim); font-size: 12.5px; cursor: pointer;
}
.subtable-tab.active { background: var(--accent); border-color: var(--accent); color: #fff; }

.bus-picker { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; }
.bus-picker select {
  flex: 1; max-width: 420px; padding: 8px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 13px;
}
.conn-group { margin-bottom: 14px; }
.conn-group h4 { margin: 0 0 6px; font-size: 13px; color: var(--text-dim); }
.conn-list { display: flex; flex-direction: column; gap: 6px; }
.conn-row {
  display: flex; justify-content: space-between; gap: 12px; background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; font-size: 13px;
}
.conn-row .id { font-weight: 600; }
.conn-row .other { color: var(--text-dim); }
.badge { font-size: 11px; padding: 2px 7px; border-radius: 10px; background: var(--accent-dim); color: var(--accent); font-weight: 600; }

.error-box { color: var(--danger); background: #b3261e18; border: 1px solid #b3261e44; padding: 10px 14px; border-radius: 8px; font-size: 13px; }
.loading { color: var(--text-dim); font-size: 13px; padding: 20px 0; }

.tables-list { display: flex; flex-direction: column; gap: 2px; max-height: 70vh; overflow: auto; border: 1px solid var(--border); border-radius: 10px; background: var(--panel); }
.tables-list .t-row { display: flex; justify-content: space-between; padding: 7px 12px; font-size: 12.5px; cursor: pointer; border-bottom: 1px solid var(--border); }
.tables-list .t-row:hover { background: var(--accent-dim); }
.tables-list .t-row .cat-tag { font-size: 10.5px; color: var(--accent); }

/* ---------- Module board ----------
   One tile per ETAP module, always in the same position. Modules we cannot
   read keep their tile (dimmed) on purpose: "this project has no harmonics
   study" and "this tool doesn't read harmonics" are different answers, and
   hiding the second one makes them look identical. */

.board-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
}
.board-change {
  flex-shrink: 0; padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: 12.5px; cursor: pointer; white-space: nowrap;
}
.board-change:hover { border-color: var(--accent); color: var(--accent); }

.board {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 12px;
  /* Grid stretches every tile in a row to match the tallest one. A module
     holding fifteen studies would then leave ~300px of empty box inside the
     module holding none, which reads as broken rather than empty. Let each
     tile take its own height; min-height keeps the sparse ones uniform. */
  align-items: start;
}

.tile {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 14px 16px 12px; display: flex; flex-direction: column; min-height: 152px;
}
.tile-mod {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); font-weight: 600; margin-bottom: 10px;
}
.tile-big { font-size: 15px; font-weight: 600; line-height: 1.3; }
.tile-sub { font-size: 12px; color: var(--text-dim); margin-top: 3px; line-height: 1.4; }
.tile-foot {
  margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 11px; color: var(--text-dim);
}

.tile.dim { background: transparent; border-style: dashed; }
.tile.dim .tile-big { color: var(--text-dim); font-weight: 500; font-size: 13.5px; }

/* A project folder can hold a dozen runs of one study. Cap the list so one
   busy module cannot stretch the whole row of tiles past a screen. */
.tile-files { display: flex; flex-direction: column; gap: 6px; max-height: 330px; overflow-y: auto; }
.tile-file {
  display: flex; flex-direction: column; gap: 2px;
  text-align: left; font-family: inherit; font-size: 13px; color: var(--text);
  background: var(--accent-dim); border: 1px solid transparent; border-radius: 6px;
  padding: 7px 10px; cursor: pointer;
}
.tile-file .tf-line { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.tile-file .tf-sub { font-size: 11px; color: var(--text-dim); line-height: 1.3; }
.tile-file:hover:not(:disabled) { border-color: var(--accent); }
.tile-file:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tile-file:disabled { opacity: .55; cursor: default; }
.tile-file.is-working { opacity: .7; cursor: progress; }
.tile-file .tf-name {
  font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tile-file .tf-meta { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; }
.tile-file.is-analyzed .tf-meta { color: var(--accent); font-weight: 600; }

.board-note { margin-top: 18px; font-size: 12.5px; color: var(--text-dim); }

/* In-app folder browser modal */
.fs-modal {
  position: fixed; inset: 0; background: #00000066; display: flex; align-items: center;
  justify-content: center; z-index: 100;
}
.fs-modal-box {
  width: min(680px, 92vw); max-height: 80vh; background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 20px 60px #00000044;
}
.fs-modal-header {
  display: flex; justify-content: space-between; align-items: center; padding: 14px 18px;
  border-bottom: 1px solid var(--border); font-weight: 700; font-size: 14px;
}
.fs-modal-close {
  background: transparent; border: none; font-size: 20px; line-height: 1; color: var(--text-dim); cursor: pointer;
  width: 28px; height: 28px; border-radius: 6px;
}
.fs-modal-close:hover { background: var(--accent-dim); color: var(--accent); }
.fs-quick {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 18px 0;
}
.fs-quick-btn {
  padding: 5px 12px; border-radius: 16px; border: 1px solid var(--border); background: var(--panel);
  color: var(--text-dim); font-size: 12px; cursor: pointer;
}
.fs-quick-btn:hover { border-color: var(--accent); color: var(--accent); }
.fs-quick-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.fs-breadcrumb-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 18px;
  border-bottom: 1px solid var(--border);
}
.fs-breadcrumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px; font-size: 12.5px; min-width: 0;
}
.fs-select-btn {
  flex-shrink: 0; padding: 6px 12px; border-radius: 6px; border: none; background: var(--accent);
  color: #fff; font-size: 12px; font-weight: 600; cursor: pointer;
}
.fs-select-btn:hover { filter: brightness(1.1); }
.fs-select-btn:disabled { opacity: .4; cursor: default; }
.fs-crumb { cursor: pointer; color: var(--accent); white-space: nowrap; }
.fs-crumb:hover { text-decoration: underline; }
.fs-crumb.active { color: var(--text); font-weight: 600; cursor: default; }
.fs-crumb.active:hover { text-decoration: none; }
.fs-crumb-sep { color: var(--text-dim); }
.fs-list { overflow-y: auto; padding: 8px; }
.fs-row {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 8px;
  cursor: pointer; font-size: 13px;
}
.fs-row:hover { background: var(--accent-dim); }
.fs-row .cand-type { font-size: 10.5px; color: var(--text-dim); margin-left: 4px; }
.fs-row:hover .cand-type { color: var(--accent); }
.fs-row .sz { margin-left: auto; font-size: 11.5px; color: var(--text-dim); white-space: nowrap; }
.fs-row.fs-file { font-weight: 600; }
.fs-row.fs-up { color: var(--text-dim); }
.fs-empty { padding: 20px; text-align: center; color: var(--text-dim); font-size: 13px; }
