/* ─────────────────────────────────────────────────────────────
   MapFactory components. Requires mf-tokens.css + mf-base.css.
   New code: use the .btn / .input / .panel / .label classes.
   Legacy class names are listed in each selector so existing
   markup picks up the system with no HTML changes. Delete them
   from the lists once the pages are migrated.
   ───────────────────────────────────────────────────────────── */

/* ── Buttons ─────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1h);
  height: var(--control-h); padding: 0 var(--sp-3);
  background: var(--bg-surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  line-height: 1; white-space: nowrap; cursor: pointer;
  transition: border-color var(--dur), background var(--dur), color var(--dur);
}
/* Hover is neutral, like a table selection (--sel-bg): red on this site means
   the main action or something wrong, never "the pointer is here". */
.btn:hover {
  border-color: var(--border-strong); background: var(--sel-bg);
}

/* Buttons are neutral throughout: red here means something is wrong (a danger
   button, a refused value), never "press me". */
/* Primary = the obvious next step: a firmer border and bold text */
.btn--primary {
  border-color: var(--border-strong); font-weight: var(--fw-semibold);
}

/* Solid = the one strongest action on a page: filled in the text colour */
.btn--solid {
  background: var(--sel-edge); border-color: var(--sel-edge); color: var(--bg-panel);
  font-weight: var(--fw-semibold);
}
/* .btn:hover would otherwise win on specificity and tint the fill away */
.btn--solid:hover { background: var(--sel-edge); border-color: var(--sel-edge); filter: brightness(0.88); }

.btn--ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
.btn--ghost:hover { color: var(--text); background: var(--bg-surface); border-color: transparent; }

.btn--danger, .btn--danger:hover { color: var(--danger-text); border-color: var(--danger); background: var(--danger-bg); }

/* Sizes */
.btn--sm {
  height: var(--control-h-sm); padding: 0 var(--sp-2);
  font-size: var(--fs-xs); border-radius: var(--r-sm);
}
.btn--lg { height: var(--control-h-lg); padding: 0 var(--sp-5); font-size: var(--fs-md); }
.btn--block { display: flex; width: 100%; }

.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: default; pointer-events: none; }

/* Segmented toggle (x-axis Time/Distance etc.) */
.segmented {
  display: inline-flex; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden;
}
.segmented > button {
  height: calc(var(--control-h) - 2px); padding: 0 var(--sp-3);
  background: transparent; border: 0; color: var(--text-dim);
  font-size: var(--fs-sm); transition: background var(--dur), color var(--dur);
}
.segmented > button + button { border-left: 1px solid var(--border); }
.segmented > button[hidden] + button { border-left: 0; }   /* a hidden first button leaves no line */
.segmented > button:hover { color: var(--text); background: var(--bg-surface); }
.segmented > button.is-active { background: var(--bg-surface); color: var(--accent-text); }
/* A choice that must show at a glance (Map A / Map B): the chosen one filled solid. */
.segmented--strong > button.is-active,
.segmented--strong > button.is-active:hover { background: var(--text); color: var(--bg); font-weight: var(--fw-semibold); }

/* ── Tabs ─────────────────────────────────────────────────
   A page's own sections, as folder tabs on a line: the open one is joined to
   the page below it, with an accent edge on top; the others sit back, filled.
   <div class="tabs" role="tablist"><button class="tab is-active" role="tab">…</button>…</div>
   (A choice inside a panel is a .segmented, not this.) */
.tabs {
  display: flex; flex-wrap: wrap; gap: var(--sp-1); align-items: flex-end;
  max-width: var(--mft-max); border-bottom: 1px solid var(--border-strong);
}
.tabs > .tab {
  margin-bottom: -1px; padding: var(--sp-2) var(--sp-4);
  background: var(--bg-surface); color: var(--text-dim);
  border: 1px solid var(--border); border-bottom-color: var(--border-strong);
  border-radius: var(--r-md) var(--r-md) 0 0;
  font-size: var(--fs-md); font-weight: var(--fw-medium);
  transition: background var(--dur), color var(--dur);
}
.tabs > .tab:hover { color: var(--text); background: var(--bg-raised); }
.tabs > .tab.is-active {
  background: var(--bg); color: var(--text);
  border-color: var(--border-strong); border-bottom-color: var(--bg);
  box-shadow: inset 0 2px 0 var(--accent);
  font-weight: var(--fw-semibold);
}

/* ── Form controls ───────────────────────────────────────── */
.input, .select, .textarea {
  height: var(--control-h); padding: 0 var(--sp-2);
  background: var(--bg-deep); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-size: var(--fs-sm); outline: none;
  transition: border-color var(--dur);
}
.textarea {
  height: auto; min-height: 100px; padding: var(--sp-2) var(--sp-3);
  font-family: var(--font-mono); font-size: var(--fs-sm); resize: vertical;
}
.input--sm { height: var(--control-h-sm); font-size: var(--fs-xs); border-radius: var(--r-sm); }
.input--num { font-family: var(--font-mono); text-align: right; }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--accent);
}
select option { background: var(--bg-surface); color: var(--text); }

.field { display: flex; flex-direction: column; gap: var(--sp-1); }
.field-row { display: flex; align-items: center; gap: var(--sp-2); }

/* ── Labels & headings ───────────────────────────────────── */
.label {
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-label);
  color: var(--text-dim);
}
.section-label {
  padding-bottom: var(--sp-1); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-2);
}

.page-heading {
  font-size: var(--fs-2xl); font-weight: var(--fw-semibold);
  letter-spacing: 0.01em; margin-bottom: var(--sp-5);
}
.page-heading span, .header-accent { color: var(--accent-text); }

/* Intro paragraph under a page heading */
.page-intro { color: var(--text-dim); margin: 0 0 var(--sp-5); max-width: 820px; }

/* Breadcrumb trail: <div class="crumbs"><a>…</a><span class="sep">›</span><span>…</span></div> */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1h);
  margin: 0 0 var(--sp-4); font-size: var(--fs-sm); color: var(--text-dim);
}
.crumbs a { color: var(--accent-text); }
.crumbs .sep { opacity: .5; }

.panel-title, .header-title { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
.text-dim { color: var(--text-dim); }
.num, .meta-value.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ── Surfaces ────────────────────────────────────────────── */
/* Modal dialog. The page shows/hides the backdrop (display: flex / none).
   <div class="modal-backdrop"><div class="modal">
     <div class="modal-head"><span class="modal-title">…</span><button class="modal-close">&#x2715;</button></div>
     <div class="modal-body">…</div>
   </div></div> */
.modal-backdrop {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  align-items: center; justify-content: center; padding: var(--sp-4);
  background: var(--overlay-bg);
}
.modal {
  width: min(560px, 96vw); max-height: 90vh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-modal);
}
.modal-head {
  display: flex; align-items: center; flex-shrink: 0;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border);
}
.modal-title { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
.modal-close {
  margin-left: auto; padding: var(--sp-half) var(--sp-2);
  background: none; border: none; border-radius: var(--r-sm);
  color: var(--text-dim); font-size: var(--fs-xl);
  transition: color var(--dur), background var(--dur);
}
.modal-close:hover { color: var(--text); background: var(--bg-surface); }
.modal-body { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4); overflow-y: auto; }
.modal-body .textarea { min-height: 140px; }

/* Collapsible panel: <details class="disclosure"><summary>Title</summary>
   <div class="disclosure-body">…</div></details> */
.disclosure { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-md); }
.disclosure > summary { cursor: pointer; padding: var(--sp-3); font-weight: var(--fw-semibold); user-select: none; }
.disclosure-body { padding: 0 var(--sp-3) var(--sp-3); }

.panel {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.card {
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-4);
}
.card--raised { background: var(--bg-raised); border-color: var(--border-strong); }

/* The TSL pages' panel shading on another page: put .tsl-shade on its
   .page-content (and its modals). Cards and folds take the blue-grey panel,
   fields inside them a shade deeper, borders the TSL blue-grey. */
.tsl-shade {
  --bg-surface: var(--tsl-panel);
  --bg-panel: var(--tsl-field);
  --bg-raised: var(--tsl-panel-2);
  --border: var(--tsl-border);
  --border-strong: var(--tsl-border-strong);
}

/* ── Tool pages ── */
/* A section heading with an accent bar on the left (e.g. "Bank A") */
.accent-heading {
  padding-left: var(--sp-3); border-left: 3px solid var(--accent);
  font-size: var(--fs-lg); font-weight: var(--fw-semibold); letter-spacing: var(--tracking-wide);
}
/* Loaded files: <div class="file-list"><div class="file-row">name · meta · buttons</div></div> */
.file-list { display: flex; flex-direction: column; gap: var(--sp-1); }
.file-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-1h) var(--sp-3); font-size: var(--fs-sm);
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-sm);
}

/* Named library bar (js/named-library.js): pick, New, Save, Save As, Rename,
   Delete and a status line; and the notes that go with each item. Picker and
   notes on the panel colour (white in light mode). */
.named-lib { margin-bottom: var(--sp-4); }
.named-lib-pick { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-dim); }
.named-lib-pick .select { min-width: 260px; background: var(--bg-panel); }
.named-lib-status { color: var(--text-dim); font-size: var(--fs-sm); }
.named-lib-status[data-kind="error"] { color: var(--danger-text); }
.named-lib-notes { max-width: var(--mft-max); margin-bottom: var(--sp-4); }
.named-lib-notes .textarea { width: 100%; min-height: 72px; font-family: var(--font-sans); background: var(--bg-panel); }

/* ── File picker (js/file-picker.js) ─────────────────────── */
/* Folders down the left, the chosen folder's files with their details on the
   right, laid out as MoTeC i2's Open Log File(s) window is:
     <div class="modal-backdrop fpick"><div class="modal modal--wide">
       .modal-head
       .fpick-bar    Choose folder… · .crumbs.fpick-crumbs · .fpick-search
       .fpick-main   .fpick-tree (ul > li > .fpick-node > .fpick-twist + .fpick-name)
                     .fpick-list (table.table.fpick-table, or p.fpick-empty)
       .fpick-tray   the files chosen so far (when several may be chosen)
       .fpick-foot   .fpick-status · the buttons
   The chosen row and folder are shaded like any selection (--sel-bg,
   --sel-edge): red on this site means something is wrong. */
.modal--wide { width: min(1240px, 96vw); height: min(780px, 100%); max-height: 100%; }   /* a window with a list in it */
.fpick:not([hidden]) { display: flex; }
.fpick { padding-top: calc(var(--nav-height) + var(--sp-4)); }   /* clear of the site's header, which sits over a backdrop */
.fpick-bar {
  display: flex; align-items: center; gap: var(--sp-3); flex-shrink: 0;
  padding: var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--border);
}
.fpick-crumbs { flex: 1; min-width: 0; margin: 0; flex-wrap: nowrap; overflow: hidden; white-space: nowrap; }
.fpick-search { width: var(--sidebar-width); flex-shrink: 0; }
.fpick-main { display: flex; flex: 1; min-height: 0; }
.fpick-tree {
  width: var(--sidebar-width); flex-shrink: 0; overflow: auto; padding: var(--sp-2);
  border-right: 1px solid var(--border); background: var(--bg-surface); font-size: var(--fs-sm);
}
.fpick-tree ul { list-style: none; margin: 0; padding: 0; }
.fpick-tree ul ul { padding-left: var(--sp-3); }
.fpick-node { display: flex; align-items: center; border-radius: var(--r-sm); }
.fpick-node:hover { background: var(--sel-bg); }
.fpick-node.is-at { background: var(--sel-bg); box-shadow: inset 2px 0 0 var(--sel-edge); }
.fpick-twist, .fpick-name { background: none; border: none; color: inherit; font: inherit; cursor: pointer; }
.fpick-twist { width: var(--sp-4); flex-shrink: 0; padding: 0; color: var(--text-dim); }
.fpick-twist:disabled { cursor: default; }
.fpick-name {
  flex: 1; min-width: 0; padding: var(--sp-half) var(--sp-1); text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fpick-list { flex: 1; min-width: 0; overflow: auto; outline: none; }
/* (.table's own rules come later in this file: these say .table as well, to win) */
.table.fpick-table { width: 100%; border-collapse: collapse; }
.table.fpick-table thead th { position: sticky; top: 0; z-index: 1; text-align: left; cursor: pointer; user-select: none; }
.table.fpick-table thead th.num { text-align: right; }
.table.fpick-table td { max-width: 30ch; overflow: hidden; text-overflow: ellipsis; cursor: default; }
.table.fpick-table td.num { font-family: var(--font-figures); }
.table.fpick-table tbody tr:hover td { background: var(--sel-bg); }   /* (not .table's red tint: the pointer being here is not news) */
.table.fpick-table tbody tr[aria-selected="true"] td {
  background: var(--sel-bg); box-shadow: inset 0 1px 0 var(--sel-edge), inset 0 -1px 0 var(--sel-edge);
}
.table.fpick-table tr.is-bad td { color: var(--text-faint); }
.fpick-empty {
  margin: 0; padding: var(--sp-6) var(--sp-4); text-align: center;
  color: var(--text-dim); font-size: var(--fs-md); line-height: var(--lh-normal);
}
.fpick-empty .btn { margin-top: var(--sp-3); }
.fpick-tray { flex-shrink: 0; max-height: 28%; overflow: auto; padding: var(--sp-2) var(--sp-4); border-top: 1px solid var(--border); }
.fpick-tray[hidden] { display: none; }
.fpick-tray-head {
  margin-bottom: var(--sp-1); color: var(--text-dim); font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-label);
}
.fpick-tray .fpick-empty { padding: var(--sp-1) 0; text-align: left; font-size: var(--fs-sm); }
.fpick-tray-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fpick-tray-file { color: var(--text-dim); font-family: var(--font-mono); font-size: var(--fs-xs); white-space: nowrap; }
.fpick-foot {
  display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0;
  padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border);
}
.fpick-status {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--text-dim); font-family: var(--font-mono); font-size: var(--fs-sm);
}
.fpick-status[data-kind="error"] { color: var(--danger-text); }

/* ── Chips / tags ────────────────────────────────────────── */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-half) var(--sp-3); border-radius: var(--r-pill);
  background: var(--bg-deep); border: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--text);
}
.tag {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-half) var(--sp-2); border-radius: var(--r-sm);
  background: var(--accent-dim); font-size: var(--fs-sm);
}

/* ── Data table ──────────────────────────────────────────── */
.table { font-size: var(--fs-sm); color: var(--text); }
.table th, .table td { padding: var(--sp-1h) var(--sp-3); border-bottom: 1px solid var(--border); white-space: nowrap; }
.table thead th {
  background: var(--bg-surface); color: var(--text-dim);
  font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-label); text-align: right;
}
.table td.num, .table .num { text-align: right; }
.table tbody tr:hover td { background: var(--accent-dim); }

/* ── MFTable (js/mf-table.js) ────────────────────────────── */
/* The editable map grid. Every part has its own class, all prefixed mft- so
   nothing clashes with the vendor DataTables (dt-) on the admin pages. The
   whole set is styled here, including parts no page builds yet, so content can
   be added later without design work:

   <div class="card mft [mft--dense] [mft--full]">   a panel (script adds card mft); it never
                                                     folds: a page wanting a fold wraps it in
                                                     <details class="disclosure"> and titles that
     <div class="mft-header">Title                   optional
       <div class="mft-tools"><button class="btn btn--sm">View as graph</button></div>   addTool()
     </div>
     <div class="mft-wrap">                            scrolls sideways
       <div class="mft-frame">                         only when there are axis titles
         <div class="mft-frame-top">                 the row above the grid
           <div class="mft-col-title mft-col-title--top">RPM</div>   (tools here only with no title line)
         </div>
         <div class="mft-row-title mft-row-title--left">Gear</div>
         <table class="mft-table">
           <caption class="mft-value-title">Torque (Nm)</caption>
           <thead><tr>
             <th class="mft-corner mft-corner--top-left"><span class="mft-corner-title">Gear \ RPM</span></th>
             <th class="mft-col-head mft-col-head--top">5000</th> …
             <th class="mft-corner mft-corner--top-right"></th>
           </tr></thead>
           <tbody><tr>
             <th class="mft-row-head mft-row-head--left">1</th>
             <td class="mft-value" data-v="-12.5432">-12.54</td> …   whole number in data-v, shown rounded
             <th class="mft-row-head mft-row-head--right">1</th>
           </tr></tbody>
           <tfoot><tr>
             <th class="mft-corner mft-corner--bottom-left"></th>
             <th class="mft-col-head mft-col-head--bottom">5000</th> …
             <th class="mft-corner mft-corner--bottom-right"></th>
           </tr></tfoot>
         </table>
         <div class="mft-row-title mft-row-title--right">Gear</div>
         <div class="mft-col-title mft-col-title--bottom">RPM</div>
       </div>
     </div>
     <div class="mft-toolbar">buttons…
       <div class="mft-dp">                            decimal places, one more / one fewer
         <button class="btn mft-dp-more"><span class="mft-dp-ico"><span><i>←</i>.0</span><span>.00</span></span></button>
         <button class="btn mft-dp-less"><span class="mft-dp-ico"><span>.00</span><span><i>→</i>.0</span></span></button>
       </div>
     </div>
   </div>

   States the script sets: mft-selected, mft-picked, mft-editing, mft-refused on
   cells; mft-col-head--in-sel / mft-row-head--in-sel on the headers of the
   selected columns and rows. Today the script builds the top and left
   headers, the top-left corner, and any titles a page gives it
   (new MFTable(id, { titles: { top, bottom, left, right, corner, value } })). */

.mft { margin-bottom: var(--sp-4); max-width: var(--mft-max); }

/* Tables side by side when there is room: wrap neighbouring tables in
   <div class="mft-group">. Each starts at its own natural width and shares
   what is left of the row (up to --mft-max); too narrow for two, they stack. */
.mft-group { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.mft-group > .mft { flex: 1 1 max-content; min-width: 0; margin-bottom: 0; }
.mft-group:has(> .mft--dense) { gap: var(--sp-3); margin-bottom: var(--sp-3); }

.mft-header {
  position: relative;                              /* centred; anything a page adds to the line sits at the right */
  display: flex; justify-content: center; align-items: center; text-align: center;
  padding: var(--sp-1h) 0; margin-bottom: var(--sp-2);
  font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); letter-spacing: 0.03em;
}

.mft-wrap { overflow-x: auto; margin-bottom: var(--sp-3); }
.mft-empty { padding: var(--sp-6) 0; font-size: var(--fs-md); color: var(--text-dim); }

/* The grid */
.mft-table {
  border-collapse: collapse; min-width: max-content;
  font-size: var(--fs-xs); color: var(--text);
}
.mft-table th,
.mft-table td {
  padding: var(--sp-1h) var(--sp-3);
  border: 1px solid var(--border);
  white-space: nowrap;
}
/* Headers and corners: the same face and size as the values (--font-figures),
   semibold and dim on the surface colour. (Capitals spaced out at 10px were
   what rendered soft on Windows; the weight is fine.) A rule for
   mft-col-head covers both the top and the bottom row; --top/--bottom (and
   --left/--right for rows) are for styling one side only. */
.mft-table .mft-col-head,
.mft-table .mft-row-head,
.mft-table .mft-corner {
  background: var(--bg-surface); color: var(--text-dim);
  font-family: var(--font-figures); font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.mft-table .mft-col-head,
.mft-table .mft-corner { text-align: center; }
.mft-table .mft-row-head--left { text-align: right; }    /* against the values */
.mft-table .mft-row-head--right { text-align: left; }
.mft-table .mft-value {
  background: var(--bg-panel); text-align: right;
  font-family: var(--font-figures); font-size: var(--fs-xs); font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  cursor: cell;
}

/* Lined up on the decimal point (the script sets these; see _alignNumbers):
   each number is given the characters it lacks either side of its point,
   drawn in no colour, so they take exactly their own width and never show
   or copy. */
.mft-table [data-lead]::before { content: attr(data-lead); color: transparent; }
.mft-table [data-trail]::after { content: attr(data-trail); color: transparent; }
.mft-table .mft-editing::before, .mft-table .mft-editing::after { content: none; }

/* Colour scale (the hill button, MFTable.setHeat): each value over its blend of
   --heat-low/-mid/-high. A page's own cell shading (an id rule, or inline)
   and the selection still show over it. */
.mft--heat .mft-table .mft-value[style*="--mft-heat"] {
  background: color-mix(in oklab, var(--mft-heat) var(--heat-strength), var(--bg-panel));
}
.mft-heat-btn { padding: 0 var(--sp-1h); }
.mft-heat-btn svg { width: var(--sp-5); height: var(--sp-4); display: block; }
.mft-heat-ico-low { fill: var(--heat-low); }
.mft-heat-ico-mid { fill: var(--heat-mid); }
.mft-heat-ico-high { fill: var(--heat-high); }
.mft-heat-btn[aria-pressed="true"] { background: var(--sel-bg); border-color: var(--sel-edge); }
.mft--graph .mft-heat-btn { display: none; }   /* nothing to colour in graph view */

/* The headers of the selection: brighter, tinted, with an edge on the
   side that faces the values — the way a spreadsheet shows where you are. */
.mft-table .mft-col-head--in-sel,
.mft-table .mft-row-head--in-sel { background: var(--sel-bg); color: var(--text); }
.mft-table .mft-col-head--top.mft-col-head--in-sel { box-shadow: inset 0 -2px 0 var(--sel-edge); }
.mft-table .mft-col-head--bottom.mft-col-head--in-sel { box-shadow: inset 0 2px 0 var(--sel-edge); }
.mft-table .mft-row-head--left.mft-row-head--in-sel { box-shadow: inset -2px 0 0 var(--sel-edge); }
.mft-table .mft-row-head--right.mft-row-head--in-sel { box-shadow: inset 2px 0 0 var(--sel-edge); }

/* Cell states. A selection is shaded, with one border round the outside of
   the block, as Excel draws it, in neutral colours (--sel-bg, --sel-edge) — red on this site
   means something is wrong: the script marks each edge cell's outer sides
   (mft-sel-top/-bottom/-left/-right) and the border is drawn inside them.
   (The [class*="--in-sel"] line lets it win on a selected header too.) */
.mft-table .mft-selected,
.mft-table .mft-selected[class*="--in-sel"] {
  --mft-st: 0px; --mft-sb: 0px; --mft-sl: 0px; --mft-sr: 0px;
  background: var(--sel-bg) !important;
  box-shadow: inset 0 var(--mft-st) 0 var(--sel-edge), inset 0 calc(-1 * var(--mft-sb)) 0 var(--sel-edge),
              inset var(--mft-sl) 0 0 var(--sel-edge), inset calc(-1 * var(--mft-sr)) 0 0 var(--sel-edge);
}
.mft-table .mft-selected.mft-sel-top { --mft-st: 2px; }
.mft-table .mft-selected.mft-sel-bottom { --mft-sb: 2px; }
.mft-table .mft-selected.mft-sel-left { --mft-sl: 2px; }
.mft-table .mft-selected.mft-sel-right { --mft-sr: 2px; }
/* A picked cell (Ctrl+click) has the selection's shade and a border of its
   own, so picked cells still show inside a selected block. */
.mft-table .mft-value.mft-picked {
  background: var(--sel-bg) !important;
  outline: 2px solid var(--sel-edge); outline-offset: -2px;
}
/* a typed value refused for being outside the cell's limits (flashes briefly) */
.mft-table .mft-value.mft-refused { outline: 2px solid var(--danger); outline-offset: -2px; }
/* An open cell: a caret, a normal text selection, and an outline that says so.
   The grid blocks selection while dragging a range, so it is handed back here. */
.mft-table .mft-value.mft-editing {
  background: var(--bg-panel) !important;
  outline: 2px solid var(--sel-edge); outline-offset: -2px;
  cursor: text; -webkit-user-select: text; user-select: text;
}

/* Axis titles: the same small capitals as the headers, but in the text colour
   and heavier, so a title reads as the name of the headers beside it. Column
   and row titles sit outside the table in .mft-frame, so the grid's own rows
   and columns stay as they are; a corner title sits in a corner cell, and the
   value title is the table's caption. */
.mft-frame {
  display: inline-grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "top top top" "left table right" "bottom bottom bottom";
}
.mft-frame > .mft-table { grid-area: table; }
.mft-col-title,
.mft-row-title,
.mft-corner-title,
.mft-value-title {
  color: var(--text); font-size: var(--fs-2xs); font-weight: var(--fw-semibold);
  text-transform: uppercase; letter-spacing: var(--tracking-label);
}
.mft-col-title { text-align: center; }
/* The row above the grid: the column title centred, any tools (MFTable.addTool
   — a graph's "View as graph", say) at its right. */
.mft-frame-top {
  grid-area: top; position: relative;
  display: flex; justify-content: center; align-items: center;
}
.mft-frame-top:has(.mft-tools) { min-height: calc(var(--control-h-sm) + 2 * var(--sp-half)); }
.mft-tools {
  position: absolute; right: var(--sp-half); top: 0; bottom: 0;
  display: flex; align-items: center; gap: var(--sp-1);
}
.mft-tools--left { right: auto; left: var(--sp-half); }   /* a Copy button, opposite the graph's */
/* a Copy button that has just copied: a green glow, text unchanged */
.mft-copy.is-copied { border-color: var(--success); background: var(--success-bg); color: var(--success); }
.mft-tools:empty { display: none; }
/* worked out by the page (readOnly): only the decimal places in its toolbar */
.mft--readonly .mft-toolbar > :not(.mft-dp) { display: none; }
.mft-frame > .mft-col-title--top { grid-area: top; }   /* placed in the frame itself, as the specimen does */
.mft-col-title--bottom { grid-area: bottom; }
.mft-row-title { writing-mode: sideways-lr; text-align: center; }   /* reads upwards */
.mft-row-title--left { grid-area: left; }
.mft-row-title--right { grid-area: right; }
/* Each title is a cell joined onto the grid, as if merged across it: the top
   and bottom ones span the whole width, the side ones the grid's height, in
   the headers' border and background (their own lettering kept). They sit
   outside the table, so the grid's rows and columns are untouched. Each
   leaves off the side it shares with the grid (or with another title), whose
   own border draws that line: overlapping two borders only lines up when the
   grid starts on a whole pixel, and shows as a double line when it doesn't. */
.mft-frame-top:has(.mft-col-title),
.mft-frame > .mft-col-title--top,
.mft-col-title--bottom,
.mft-row-title {
  background: var(--bg-surface); border: 1px solid var(--border);
}
.mft-col-title--top { padding: var(--sp-1h) var(--sp-2); }
.mft-frame-top:has(.mft-col-title),
.mft-frame > .mft-col-title--top { border-bottom: 0; }
.mft-col-title--bottom { border-top: 0; padding: var(--sp-1h) var(--sp-2); }
.mft-row-title { padding: var(--sp-2) var(--sp-1h); }
.mft-row-title--left { border-right: 0; }
.mft-row-title--right { border-left: 0; }
/* the value title: a joined cell along the top of the grid, left-aligned */
.mft-value-title {
  caption-side: top; text-align: start; padding: var(--sp-1h) var(--sp-2);
  background: var(--bg-surface); border: 1px solid var(--border); border-bottom: 0;
}

/* Toolbar */
.mft-toolbar { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.mft-toolbar .btn { height: var(--control-h-lg); }
/* Decimal places: Excel's pair of buttons, at the right-hand end. Each icon is
   two lines of figures, right-aligned so the noughts line up, with the arrow
   in the accent colour. */
.mft-dp { display: flex; gap: var(--sp-1); margin-left: auto; }
.mft-toolbar .mft-dp .btn { padding: 0 var(--sp-2); }
.mft-dp-ico {
  display: flex; flex-direction: column; align-items: flex-end;
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.05;
}
.mft-dp-ico i { font-style: normal; color: var(--accent-text); }

/* Dense: tighter cells, small toolbar buttons, less padding (the figures are
   the same size as ever). Full: the grid fills the card's width. */
.mft.mft--dense { padding: var(--sp-3); margin-bottom: var(--sp-3); }
.mft--dense .mft-header { margin-bottom: var(--sp-1); }
.mft--dense .mft-wrap { margin-bottom: var(--sp-2); }
.mft.mft--dense .mft-table th,
.mft.mft--dense .mft-table td { padding: var(--sp-half) var(--sp-1h); }   /* beats a page add-on's own padding */
.mft--dense .mft-toolbar { margin-bottom: 0; }
.mft--dense .mft-toolbar .btn { height: var(--control-h-sm); padding: 0 var(--sp-2); font-size: var(--fs-xs); }
.mft--dense .mft-dp-ico { font-size: var(--fs-3xs); line-height: 1; }
.mft--full .mft-table { width: 100%; }
.mft--full .mft-frame { display: grid; }

/* Graph view (js/mf-table-graph.js) */
/* In place of the table: the same thin border and value-cell background, at
   the height the table had (the script sets it as it swaps them). */
.mft-graph { margin-bottom: var(--sp-3); border: 1px solid var(--border); background: var(--bg-panel); }
.mft--dense .mft-graph { margin-bottom: var(--sp-2); }
/* graph view: the grid and its side titles go; the top row stays, for its tools */
.mft--graph .mft-frame > :not(.mft-frame-top) { display: none; }
.mft--graph .mft-col-title--top { visibility: hidden; }
.mft--graph .mft-frame-top { background: none; border-color: transparent; }
.mft--graph .mft-wrap:not(:has(.mft-tools)) { display: none; }   /* tools on the title line: the lot goes */
.mft-graph[hidden] { display: none; }
.mft-graph svg { display: block; width: 100%; height: 360px; -webkit-user-select: none; user-select: none; }
.mft-graph .grid { stroke: var(--border); stroke-width: 1; opacity: .28; }
.mft-graph .ax { stroke: var(--border); stroke-width: 1; }
.mft-graph .ax.zero { opacity: .8; stroke-dasharray: 4 3; }
.mft-graph .tick { fill: var(--text-dim); font-size: var(--fs-sm); font-family: var(--font-mono); }
.mft-graph .axlabel { fill: var(--text-dim); font-size: var(--fs-md); }
.mft-graph .legend-title { fill: var(--text-dim); font-size: var(--fs-xs); }
.mft-graph .legend-text { fill: var(--text); font-size: var(--fs-xs); font-family: var(--font-mono); }
.mft-graph .empty { fill: var(--text-dim); font-size: var(--fs-lg); }
.mft-graph .curve { fill: none; stroke-width: 1.6; stroke-linejoin: round; }
.mft-graph .is-hot .curve { stroke-width: 3; }
.mft-graph .cursor { stroke: var(--text); stroke-width: 1; opacity: .5; }
.mft-graph .dot.is-hot { stroke: var(--text); stroke-width: 1.5; }
.mft-graph .readout { fill: var(--text); font-size: var(--fs-sm); font-family: var(--font-mono); }

/* Paste box: with breakpoints, or values only */
.mft-paste-mode { gap: var(--sp-1); font-size: var(--fs-sm); }
.mft-paste-mode label { display: flex; gap: var(--sp-2); align-items: baseline; }
.mft-paste-mode label:has(input:disabled) { color: var(--text-dim); }
.mft-paste-msg { color: var(--danger-text); font-size: var(--fs-sm); }
.mft-paste-msg:empty { display: none; }

/* Breakpoint box */
.mft-bp-current { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-1); }
.mft-bp-current-label { flex: 1; font-size: var(--fs-sm); color: var(--text-dim); }
.mft-bp-copy { flex-shrink: 0; }
.mft-bp-tags {
  display: flex; flex-wrap: wrap; gap: var(--sp-1h);
  min-height: 32px; padding: var(--sp-1h);
  background: var(--bg-deep); border: 1px solid var(--border); border-radius: var(--r-sm);
}
.mft-bp-tag { color: var(--text); }
.mft-bp-tag button {
  padding: 0; background: none; border: none; cursor: pointer;
  color: var(--text-dim); font-size: var(--fs-md); line-height: 1;
}
.mft-bp-tag button:hover { color: var(--accent-text); }
.mft-bp-section { margin-top: var(--sp-2); font-size: var(--fs-xs); letter-spacing: 0.05em; }
.mft-bp-manual { display: flex; gap: var(--sp-2); }
.mft-bp-manual input { flex: 1; }
.mft-bp-paste { display: flex; gap: var(--sp-2); align-items: center; }
.mft-bp-paste input[type="text"] { flex: 1; min-width: 0; }
.mft-bp-grid { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.mft-bp-grid input[type="number"] { width: 80px; }
.mft-bp-replace {
  display: flex; align-items: center; gap: var(--sp-1h);
  font-size: var(--fs-sm); color: var(--text-dim); cursor: pointer;
}

/* Right-click menu (on the body, so the grid's scroll box can't clip it) */
.mft-menu {
  position: fixed; z-index: 300; min-width: 210px; padding: var(--sp-1);
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-pop); font-size: var(--fs-md);
}
.mft-menu button {
  display: block; width: 100%; padding: var(--sp-1h) var(--sp-3);
  border: none; border-radius: var(--r-sm); background: none;
  color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.mft-menu button:hover:not(:disabled) { background: var(--sel-bg); }
.mft-menu button:disabled { color: var(--text-dim); opacity: 0.5; cursor: default; }
.mft-menu hr { height: 0; margin: var(--sp-1) var(--sp-1h); border: none; border-top: 1px solid var(--border); }

/* ── Status banners ──────────────────────────────────────── */
.banner-error, .alert--danger { background: var(--danger-bg); border-color: var(--danger); color: var(--danger-text); }
.banner-warning, .alert--warning { background: var(--warning-bg); border-color: var(--warning); color: var(--warning); }
.alert--success { background: var(--success-bg); border-color: var(--success); color: var(--success); }

/* ── Navigation (condensed cut for density) ──────────────── */
.nav-brand { font-family: var(--font-condensed); font-size: var(--fs-xl); letter-spacing: 0.06em; }
.nav-link { font-family: var(--font-condensed); font-size: var(--fs-lg); font-weight: var(--fw-medium); }
.nav-item:hover > .nav-link { background: var(--nav-hover); }
.nav-dropdown { box-shadow: var(--shadow-pop); border-radius: 0 0 var(--r-md) var(--r-md); }
.nav-dropdown li a { font-size: var(--fs-md); }

/* ── Mono identifiers (channel names, IDs, file names) ───── */
.channel-name, .analysis-file-name, .cmp-param-path {
  font-family: var(--font-mono); font-size: var(--fs-sm);
}

/* ── Channel groups window (js/channel-groups.js, MFChannelGroups) ──
   As MoTeC i2's Time/Distance Graph Properties: a table of groups (bold rows: scale mode, min,
   max, size) and their channels (shown, colour, name), the buttons under it, OK / Cancel. */
.modal-backdrop.cg { z-index: var(--z-popover); }   /* (over the nav bars: under them, its head was hidden at 100%) */
.cg-win { width: min(760px, 96vw); height: min(720px, 92vh); max-height: 92vh; }
.cg-body { flex: 1 1 auto; min-height: 0; gap: var(--sp-2); }
.cg-heading { margin: 0; }
.cg-list { flex: 1 1 auto; min-height: 0; overflow: auto; border: 1px solid var(--border-strong); background: var(--bg-deep); outline: none; }
.cg-list:focus-visible { border-color: var(--sel-edge); }
.cg-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.cg-table th { position: sticky; top: 0; z-index: 1; padding: var(--sp-1) var(--sp-2); text-align: right; font-weight: var(--fw-medium);
               color: var(--text-dim); background: var(--bg-surface); border-bottom: 1px solid var(--border-strong); }
.cg-table th:first-child { text-align: left; }
.cg-table th:nth-child(2) { text-align: center; }
.cg-table td { padding: var(--sp-half) var(--sp-2); text-align: right; white-space: nowrap; }
.cg-table tbody tr { cursor: default; }
.cg-table tbody tr.is-sel td { background: var(--sel-bg); }
.cg-group td { border-top: 1px solid var(--border); }
.cg-group .cg-name { font-weight: var(--fw-semibold); }
.cg-table .cg-name { text-align: left; width: 100%; }
.cg-table .cg-ch .cg-name { display: flex; align-items: center; gap: var(--sp-2); padding-left: var(--sp-4); }
.cg-ch .cg-name small { color: var(--text-dim); }
.cg-ch.is-off .cg-name span { color: var(--text-dim); }
.cg-colour { width: var(--sp-4); height: var(--sp-4); padding: 0; border: 1px solid var(--border-strong); border-radius: var(--r-sm); background: var(--c); cursor: pointer; }
.cg-in { height: auto; padding: 0 var(--sp-1); font-size: var(--fs-sm); }
.cg-fig { width: 9ch; text-align: right; font-family: var(--font-figures); }
.cg-rename { width: 24ch; }
.cg-range { font-family: var(--font-figures); color: var(--text-dim); }
.cg-table .cg-none, .cg-add-list .cg-none { text-align: left; color: var(--text-dim); padding: var(--sp-3); margin: 0; }
.cg-tools { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }
.cg-tools[hidden], .cg-add[hidden], .cg-msg[hidden] { display: none; }
.cg-add { display: flex; flex-direction: column; gap: var(--sp-2); }
.cg-add-head { display: flex; align-items: center; gap: var(--sp-2); }
.cg-add-title { font-weight: var(--fw-semibold); margin-right: auto; }
.cg-add-find { width: 28ch; }
.cg-add-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--sp-half) var(--sp-3);
               max-height: 12em; overflow-y: auto; font-size: var(--fs-sm); }
.cg-add-ch { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.cg-add-ch span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cg-add-ch small { color: var(--text-dim); }
.cg-msg { margin: 0; color: var(--danger-text); font-size: var(--fs-sm); }
.cg-foot { display: flex; justify-content: flex-end; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); flex-shrink: 0; }
.cg-foot .btn { min-width: 8ch; }

/* ── Colour grid (js/colour-grid.js, MFColourGrid) ──
   Windows' and i2's colour box: 8 × 6 basic colours under the square it is for, Default / Other…
   below. Over everything, the channel groups window included. */
.cgrid { position: fixed; z-index: calc(var(--z-popover) + 1); padding: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-2);
         background: var(--bg-panel); border: 1px solid var(--border-strong); border-radius: var(--r-md); box-shadow: var(--shadow-pop); }
.cgrid-cells { display: grid; grid-template-columns: repeat(8, var(--sp-5)); gap: var(--sp-1); }
.cgrid-cell { width: var(--sp-5); height: var(--sp-5); padding: 0; background: var(--c); border: 1px solid var(--border-strong); border-radius: var(--r-sm); cursor: pointer; }
.cgrid-cell:hover, .cgrid-cell:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.cgrid-cell.is-on { outline: 2px solid var(--sel-edge); outline-offset: 1px; }
.cgrid-foot { display: flex; justify-content: space-between; gap: var(--sp-2); }
