ZDDC/classifier/css/layout.css
ZDDC d4d48cad4a feat(classifier): MDL becomes a read-only catalog (MDL ∪ archive) overlay
Reframes the By-MDL tab as a "⊞ Catalog" button that opens an overlay over the
target pane (the left filetree stays the drag source). The catalog is the
de-duplicated union of everything the project knows about a tracking number:
its MDL deliverables AND its archive files, merged by tracking number, with an
informational "Archive revs" column (which revisions already exist) and an "MDL"
flag. Nothing is written or altered — the Revision column is classifier-local
and starts blank (never pre-filled from an old archive rev).

- Drag a source file onto a row → assigns the tracking number only (the mdl
  axis); set the revision in the bulk-editable Revision column (ctrl-shift
  select rows + ctrl-Enter). Per-file Title: MDL/file toggle + ✕ remove kept.
- Columns split the tracking number into the configured pattern fields, each with
  its own autofilter (per-column, via the shared seltable). Default pattern is
  now the 8-field ORIG-PHASE-PROJECT-AREA-DISC-TYPE-SEQ-SUFFIX.
- Server load merges every party's archive/<party>/mdl/*.yaml with a recursive
  walk of the archive documents; local load reads a folder of deliverable yamls.

Test: catalog shows merged archive revisions; drop names a file (tracking only);
bulk revision feeds the derived name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 14:58:31 -05:00

704 lines
26 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Classifier layout — tokens from shared/base.css */
/* .empty-state / .empty-state__inner / .welcome-list live in
shared/base.css. Classifier keeps the .drag-over modifier locally
because it's the only tool whose empty state is a drop target. */
.empty-state.drag-over {
background: var(--primary-light);
outline: 2px dashed var(--primary);
outline-offset: -4px;
}
/* Browser Warning */
.browser-warning {
background-color: rgba(217, 119, 6, 0.08);
border: 2px solid var(--warning);
border-radius: var(--radius);
padding: 1.5rem;
margin: 1.5rem 0;
text-align: left;
}
.browser-warning h3 {
color: var(--warning);
margin-top: 0;
}
.browser-warning ul {
margin: 0.5rem 0;
padding-left: 1.5rem;
}
/* Main App */
.main-app {
display: flex;
flex-direction: column;
height: 100vh;
background-color: var(--bg);
position: relative;
}
/* Header — shared/base.css provides .app-header base */
.app-header {
padding: 0.5rem 1rem;
}
.header-divider {
color: var(--border);
margin: 0 0.25rem;
}
/* Main Content */
.main-content {
display: flex;
flex: 1;
overflow: hidden;
}
/* Folder Tree Pane */
.folder-tree-pane {
width: 300px;
min-width: 150px;
display: flex;
flex-direction: column;
background-color: var(--bg-secondary);
border-right: 1px solid var(--border);
flex-shrink: 0;
position: relative;
transition: width 0.2s ease, min-width 0.2s ease;
}
.folder-tree-pane.collapsed {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
overflow: hidden;
}
.folder-tree-pane.collapsed .pane-header-controls,
.folder-tree-pane.collapsed .classify-filters,
.folder-tree-pane.collapsed .tree-filter,
.folder-tree-pane.collapsed .folder-tree,
.folder-tree-pane.collapsed .pane-header h3 {
display: none;
}
.folder-tree-pane.collapsed .pane-header {
padding: 0.5rem;
justify-content: center;
}
.folder-tree-pane.collapsed .pane-header-title {
flex-direction: column;
}
.pane-header-title {
display: flex;
align-items: center;
gap: 0.5rem;
}
.collapse-tree-btn {
padding: 0.25rem 0.5rem;
font-size: 0.8rem;
}
/* Resize Handle */
.resize-handle {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 5px;
cursor: col-resize;
background-color: transparent;
z-index: 10;
}
.resize-handle:hover {
background-color: var(--primary);
}
.pane-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background-color: var(--bg);
border-bottom: 1px solid var(--border);
}
.pane-header-left,
.pane-header-right {
display: flex;
align-items: center;
gap: 0.75rem;
}
.pane-header h3 {
font-size: 1rem;
font-weight: 600;
margin: 0;
}
.pane-header-controls {
display: flex;
flex-wrap: wrap;
gap: 0.3rem 0.75rem;
align-items: center;
justify-content: flex-end;
}
/* Classify-mode filter row, laid out as a toolbar under the pane header. */
.tree-toolbar {
display: flex; flex-wrap: wrap; align-items: center;
gap: 0.2rem 0.7rem; padding: 0.3rem 1rem;
border-bottom: 1px solid var(--border);
}
.tree-toolbar__label { color: var(--text-muted); font-size: 0.8rem; font-weight: 600; }
.classify-filters .filter-count { color: var(--text-muted); font-size: 0.85em; }
/* Live filter box above a file tree. */
.tree-filter {
width: 100%; box-sizing: border-box; margin: 0.25rem 0;
padding: 0.25rem 0.5rem; font: inherit; font-size: 0.85rem;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg); color: var(--text);
}
.tree-filter:focus { outline: none; border-color: var(--primary); }
.folder-stats,
.file-stats {
display: flex;
gap: 1rem;
font-size: 12px;
color: var(--text-muted);
}
.folder-tree {
flex: 1;
overflow-y: auto;
padding: 0.5rem;
}
/* Folder Item */
.folder-item {
display: flex;
align-items: center;
padding: 0.5rem;
cursor: pointer;
border-radius: var(--radius);
user-select: none;
transition: background-color 0.15s;
}
.folder-item:hover {
background-color: var(--bg-hover);
}
/* Counts read "direct+total". Completed numbers are blue — var(--primary),
which is theme-aware (medium blue in light, lighter blue in dark). The
direct number is always completed (known the moment the folder is read).
The "+total" subtree count stays muted grey + pulses while still scanning,
then turns blue once final. Once the row is fully scanned (both numbers
blue) the folders/files labels turn blue too (.folder-count.done). */
.folder-count .ct-direct,
.folder-count .ct-total {
color: var(--primary);
}
.folder-count .ct-total.pending {
color: var(--text-muted, #9aa0a6);
font-style: italic;
animation: scan-pulse 1.2s ease-in-out infinite;
}
.folder-count.done .ct-label {
color: var(--primary);
}
@keyframes scan-pulse {
0%, 100% { opacity: 0.55; }
50% { opacity: 1; }
}
/* Page footer — hosts the live scan status. */
.app-footer {
flex-shrink: 0;
display: flex;
align-items: center;
padding: 0.2rem 0.75rem;
border-top: 1px solid var(--border, #e2e2e2);
background: var(--bg-secondary, #f5f5f5);
font-size: 0.75rem;
color: var(--text-muted, #8a8a8a);
min-height: 1.4em;
}
.scan-status {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scan-status.scanning { color: var(--primary, #2868c8); }
.folder-item.selected {
background-color: var(--bg-selected);
font-weight: 500;
}
.folder-item.folder-hover-highlight {
background-color: rgba(217, 119, 6, 0.12);
border-left: 3px solid var(--warning);
transition: background-color 0.2s, border-left 0.2s;
}
.folder-item.has-unsaved {
border-left: 3px solid var(--warning);
}
.folder-toggle {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 12px;
color: var(--text-muted);
}
.folder-icon {
margin-right: 0.5rem;
color: var(--text-muted);
}
.folder-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.folder-count {
font-size: 11px;
color: var(--text-muted);
margin-left: 0.5rem;
}
.folder-children {
margin-left: 1.5rem;
}
/* ── Welcome screen (intro + tutorial) ─────────────────────────────────── */
/* Scroll when the viewport is short. The inner card uses auto margins instead
of the base .empty-state's align-items:center so it centers when it fits but
collapses to the top when taller than the viewport — otherwise centering
clips the top of the card and it can't be scrolled into view. */
.empty-state--overlay { overflow-y: auto; }
.empty-state--overlay > .empty-state__inner { margin: auto; }
.welcome { max-width: 900px; padding: 1.5rem 0.5rem 2.5rem; }
.welcome__title { font-size: 2.6rem; line-height: 1.1; margin: 0 0 0.6rem; }
.welcome__lede {
font-size: 1.2rem; line-height: 1.55; color: var(--text);
margin: 0 auto 2rem; max-width: 62ch;
}
.welcome__methods {
display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
margin: 1.75rem 0 0; text-align: left;
}
@media (max-width: 780px) { .welcome__methods { grid-template-columns: 1fr; } }
.method {
border: 1px solid var(--border); border-radius: var(--radius);
padding: 1rem 1.15rem; background: var(--bg);
}
.method--primary { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.method__title { font-size: 1.1rem; margin: 0 0 0.5rem; }
.method__tag {
display: inline-block; font-size: 0.68rem; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.04em; color: var(--primary);
margin-left: 0.4rem; vertical-align: middle;
}
.method__tag--warn { color: var(--warning); }
.method__what { font-size: 0.95rem; color: var(--text-muted); margin: 0 0 0.7rem; }
.method__steps { margin: 0; padding-left: 1.25rem; font-size: 0.95rem; line-height: 1.6; }
.method__steps li { margin: 0.35rem 0; }
.method__steps code {
background: var(--bg-secondary); padding: 0.05rem 0.35rem;
border-radius: 4px; font-size: 0.85em;
}
.welcome__note { font-size: 0.9rem; color: var(--text-muted); margin-top: 1.5rem; }
/* ── Workspaces (welcome manager) ──────────────────────────────────────── */
.workspaces { text-align: left; margin: 1.5rem 0 0.5rem; }
.ws-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.ws-head__actions { display: flex; gap: 0.5rem; }
.ws-head h2 { margin: 0; font-size: 1.4rem; }
.ws-list { display: flex; flex-direction: column; gap: 0.4rem; }
.ws-empty { color: var(--text-muted); font-size: 0.85rem; padding: 0.75rem; border: 1px dashed var(--border); border-radius: var(--radius); }
.ws-row {
display: flex; align-items: center; gap: 0.75rem;
padding: 0.6rem 0.75rem; border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg);
}
.ws-row__main { flex: 1; min-width: 0; }
.ws-row__name { font-weight: 600; }
.ws-row__meta { font-size: 0.78rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-row__actions { display: flex; gap: 0.3rem; flex-shrink: 0; }
.ws-or { font-size: 0.82rem; color: var(--text-muted); margin: 1rem 0 0.5rem; }
/* ── Workflow mode switch (header) ─────────────────────────────────────── */
.mode-switch {
display: inline-flex;
margin-left: 0.5rem;
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.mode-btn {
border: none;
background: var(--bg);
color: var(--text-muted);
padding: 0.3rem 0.7rem;
font-size: 0.8rem;
cursor: pointer;
}
.mode-btn + .mode-btn { border-left: 1px solid var(--border); }
.mode-btn.active {
background: var(--primary);
color: var(--bg);
font-weight: 600;
}
/* ── Target pane (Classify & Copy) ─────────────────────────────────────── */
.target-pane {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.target-pane[hidden], .spreadsheet-pane[hidden] { display: none; }
.target-tabs { display: flex; gap: 0.25rem; }
.target-tab {
border: 1px solid var(--border);
border-bottom: none;
background: var(--bg-secondary);
color: var(--text-muted);
padding: 0.3rem 0.8rem;
font-size: 0.85rem;
border-radius: var(--radius) var(--radius) 0 0;
cursor: pointer;
}
.target-tab.active {
background: var(--bg);
color: var(--primary);
font-weight: 600;
}
.target-body { flex: 1; overflow: hidden; }
.target-panel { height: 100%; display: flex; flex-direction: column; }
.target-panel[hidden] { display: none; }
.target-panel__toolbar {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--border);
flex-wrap: wrap;
}
.target-hint { font-size: 0.75rem; color: var(--text-muted); }
.target-tree { flex: 1; overflow: auto; padding: 0.5rem 0.75rem; }
.target-empty { color: var(--text-muted); font-size: 0.85rem; padding: 1rem 0.25rem; }
/* tree nodes */
.tnode { margin: 0.1rem 0; }
.tnode__children { margin-left: 1.25rem; border-left: 1px dashed var(--border); padding-left: 0.5rem; }
.tnode__row {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.2rem 0.3rem;
border-radius: var(--radius);
}
.tnode__row:hover { background: var(--bg-hover); }
.tnode__toggle {
border: none; background: none; cursor: pointer;
color: var(--text-muted); width: 1.1em; font-size: 0.8rem; padding: 0;
}
.tnode__icon { font-size: 0.85rem; }
.tnode__name { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tnode--leaf > .tnode__row > .tnode__name { color: var(--primary); font-weight: 600; }
.tnode--party > .tnode__row > .tnode__name { font-weight: 700; }
.tnode--bin > .tnode__row > .tnode__name { color: var(--primary); }
.tnode__badge {
background: var(--primary); color: var(--bg);
border-radius: 999px; padding: 0 0.4rem; font-size: 0.7rem; font-weight: 600;
}
/* Node CRUD controls sit to the right of the level name, revealed on hover. */
.tnode__actions { display: inline-flex; gap: 0.1rem; margin-left: 0.3rem; flex: 0 0 auto; opacity: 0; transition: opacity 0.12s; }
.tnode__row:hover .tnode__actions, .tslot__row:hover .tnode__actions { opacity: 1; }
.tnode__act {
border: 1px solid var(--border); background: var(--bg);
border-radius: var(--radius); cursor: pointer;
font-size: 0.72rem; padding: 0.05rem 0.35rem; color: var(--text);
}
.tnode__act:hover { background: var(--bg-hover); }
/* placed files under a node */
.tnode__files { margin: 0.1rem 0 0.2rem 1.6rem; }
.tfile { display: flex; align-items: baseline; gap: 0.4rem; font-size: 0.75rem; padding: 0.05rem 0; cursor: grab; }
.tfile[draggable="true"]:active { cursor: grabbing; }
.tfile__remove { opacity: 0; flex: 0 0 auto; align-self: center; line-height: 1; }
.tfile:hover .tfile__remove { opacity: 1; }
.tfile__remove:hover { color: var(--danger); border-color: var(--danger); }
.tfile__orig { color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 14rem; }
.tfile__arrow { color: var(--text-muted); }
.tfile__name { color: var(--text); }
.tfile--err .tfile__name { color: var(--danger); }
.tfile--err::before { content: "⚠"; color: var(--danger); }
/* transmittal slots + bin form */
.tslot { margin: 0.15rem 0 0.15rem 1.1rem; }
.tslot__row { display: flex; align-items: center; gap: 0.5rem; padding: 0.15rem 0.3rem; }
.tslot__name { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.tnode--bin { margin-left: 1.1rem; }
.binform {
display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center;
margin: 0.2rem 0 0.3rem 1.1rem; padding: 0.4rem; background: var(--bg-secondary);
border: 1px solid var(--border); border-radius: var(--radius);
}
.binform input, .binform select {
font-size: 0.78rem; padding: 0.2rem 0.3rem;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg); color: var(--text);
}
.binform__seq { width: 7rem; }
.binform__title { width: 11rem; }
/* drop-target affordance */
.tnode__row.drop-hover, .tslot.drop-hover { outline: 2px dashed var(--primary); outline-offset: -2px; background: var(--primary-light); }
/* ── Source-tree file rows (classify mode) ─────────────────────────────── */
.file-item {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.15rem 0.5rem;
cursor: grab;
border-radius: var(--radius);
font-size: 0.85rem;
user-select: none;
}
.file-item:hover { background: var(--bg-hover); }
.file-item:active { cursor: grabbing; }
.file-item.match-highlight { background: var(--primary-light); outline: 1px solid var(--primary); }
.folder-item[draggable="true"] { cursor: grab; }
.file-icon { color: var(--text-muted); }
.file-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* classification state dot */
.cl-dot {
width: 0.55rem; height: 0.55rem; border-radius: 999px; flex-shrink: 0;
border: 1px solid var(--border); background: transparent;
}
.cl-dot--none { background: transparent; }
.cl-dot--tracking,
.cl-dot--transmittal { background: var(--warning); border-color: var(--warning); }
.cl-dot--partial { background: var(--warning); border-color: var(--warning); }
.cl-dot--done { background: var(--success); border-color: var(--success); }
.cl-dot--excluded { background: var(--text-muted); border-color: var(--text-muted); opacity: 0.6; }
.file-item.excluded .file-name { text-decoration: line-through; color: var(--text-muted); }
.folder-item.excluded .folder-name { text-decoration: line-through; color: var(--text-muted); }
/* placed-file row in the target pane is clickable (reveal in source) */
.tfile { cursor: pointer; }
.tfile:hover .tfile__orig { text-decoration: underline; } /* click row (not the name input) → preview */
input.tfile__name {
flex: 1 1 auto; min-width: 10rem; font: inherit; color: var(--text);
border: 1px solid transparent; background: transparent; border-radius: 3px; padding: 0 0.2rem;
}
input.tfile__name:hover { border-color: var(--border); }
input.tfile__name:focus { border-color: var(--primary); background: var(--bg); outline: none; }
/* cross-tree reveal flash */
.reveal-flash, .match-highlight { animation: cl-flash 1.5s ease-out; }
@keyframes cl-flash {
0%, 40% { background: var(--primary-light); outline: 2px solid var(--primary); outline-offset: -2px; }
100% { background: transparent; outline-color: transparent; }
}
/* exclude/include context menu */
.cl-menu {
position: fixed; z-index: 9500;
background: var(--bg); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: 0 6px 18px rgba(0,0,0,0.18);
padding: 0.25rem; min-width: 11rem;
}
.cl-menu__item {
display: block; width: 100%; text-align: left;
border: none; background: none; color: var(--text);
padding: 0.4rem 0.6rem; font-size: 0.83rem; cursor: pointer; border-radius: var(--radius);
}
.cl-menu__item:hover { background: var(--bg-hover); }
/* Spreadsheet Pane */
.spreadsheet-pane {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.spreadsheet-container {
flex: 1;
overflow: auto;
background-color: var(--bg);
}
/* ZIP Extract Button in Tree */
.zip-extract-btn {
margin-left: auto;
padding: 0.15rem 0.4rem;
font-size: 0.7rem;
opacity: 0;
transition: opacity 0.15s;
}
.folder-item:hover .zip-extract-btn {
opacity: 1;
}
.zip-extract-btn:disabled {
opacity: 0.5;
cursor: wait;
}
/* ── Catalog overlay (MDL archive; seltable rows = drop targets) ───────── */
.target-pane { position: relative; }
.target-tabs__catalog { margin-left: 0.75rem; }
.catalog-overlay {
position: absolute; inset: 0; z-index: 20;
display: flex; flex-direction: column; min-height: 0;
background: var(--bg); border-left: 2px solid var(--primary);
}
.catalog-overlay[hidden] { display: none; }
.catalog-overlay__head {
display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
padding: 0.45rem 0.75rem; border-bottom: 1px solid var(--border); background: var(--bg-secondary, var(--bg));
}
.catalog-overlay__title { font-weight: 700; font-size: 0.9rem; }
.catalog-overlay__close { margin-left: auto; background: none; border: none; font-size: 1.5rem; line-height: 1; color: var(--text-muted); cursor: pointer; padding: 0 0.4rem; }
.catalog-overlay__close:hover { color: var(--text); }
.catalog-overlay__table { flex: 1; min-height: 0; }
.catalog-overlay__table .seltable { height: 100%; }
.mdl-rev__input {
width: 8rem; padding: 0.15rem 0.35rem; border: 1px solid var(--border);
border-radius: var(--radius); background: var(--bg); color: var(--text); font-size: 0.8rem;
}
.seltable__extra { white-space: normal; }
.mdlfile__name { font-size: 0.78rem; }
#mdlPanel .tfile { gap: 0.3rem; align-items: center; padding: 0.05rem 0; cursor: grab; }
#mdlPanel .tfile--err .mdlfile__name { color: var(--danger); }
#mdlPanel .tfile__remove { opacity: 0.6; }
#mdlPanel .tfile:hover .tfile__remove { opacity: 1; }
/* ── MDL-from-archive overlay ───────────────────────────────────────────── */
.mdl-overlay { position: fixed; inset: 0; z-index: 1100; background: rgba(0,0,0,0.45); display: flex; align-items: center; justify-content: center; padding: 2rem 1rem; }
.mdl-overlay__box { background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 10px 40px rgba(0,0,0,0.3); width: 100%; max-width: 1000px; height: 80vh; display: flex; flex-direction: column; }
.mdl-overlay__head { display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); }
.mdl-overlay__head h2 { margin: 0; font-size: 1.1rem; }
.mdl-overlay__close { background: none; border: none; font-size: 1.6rem; line-height: 1; color: var(--text-muted); cursor: pointer; padding: 0 0.4rem; }
.mdl-overlay__close:hover { color: var(--text); }
.mdl-overlay__status { padding: 0.4rem 1rem; color: var(--text-muted); font-size: 0.82rem; border-bottom: 1px solid var(--border); }
.mdl-overlay__table { flex: 1; min-height: 0; }
.mdl-overlay__foot { display: flex; justify-content: flex-end; gap: 0.5rem; padding: 0.75rem 1rem; border-top: 1px solid var(--border); }
/* ── Shared selectable + autofilter table (seltable) ────────────────────── */
.seltable { display: flex; flex-direction: column; min-height: 0; height: 100%; }
.seltable__bar { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.5rem; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.seltable__filter {
flex: 1; min-width: 8rem; padding: 0.3rem 0.5rem;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg-secondary, var(--bg)); color: var(--text); font-size: 0.85rem;
}
.seltable__count { color: var(--text-muted); font-size: 0.78rem; white-space: nowrap; }
.seltable__scroll { flex: 1; min-height: 0; overflow: auto; }
.seltable__table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 0.82rem; }
.seltable__table th, .seltable__table td { border-bottom: 1px solid var(--border); padding: 0.25rem 0.5rem; text-align: left; white-space: nowrap; }
.seltable__table thead th {
position: sticky; top: 0; z-index: 2; background: var(--bg-secondary, var(--bg));
color: var(--text-muted); font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
}
.seltable__row { cursor: pointer; user-select: none; }
.seltable__row:hover { background: var(--bg-hover); }
.seltable__row.is-selected { background: var(--primary-light, rgba(37,99,235,0.12)); }
.seltable__row.is-selected:hover { background: var(--primary-light, rgba(37,99,235,0.18)); }
.seltable__row.drop-hover { outline: 2px solid var(--primary); outline-offset: -2px; }
/* ── Copy destination dialog ────────────────────────────────────────────── */
.copy-choice__backdrop {
position: fixed; inset: 0; z-index: 1000;
background: rgba(0, 0, 0, 0.45);
display: flex; align-items: center; justify-content: center; padding: 1rem;
}
.copy-choice {
background: var(--bg); color: var(--text);
border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
max-width: 460px; width: 100%; padding: 1.25rem 1.5rem;
}
.copy-choice h3 { margin: 0 0 0.5rem; font-size: 1.15rem; }
.copy-choice p { margin: 0 0 1.1rem; color: var(--text-muted); font-size: 0.85rem; line-height: 1.5; }
.copy-choice code { font-size: 0.82em; }
.copy-choice__select {
width: 100%; margin: 0 0 1rem; padding: 0.45rem 0.55rem;
border: 1px solid var(--border); border-radius: var(--radius);
background: var(--bg-secondary, var(--bg)); color: var(--text); font-size: 0.9rem;
}
.copy-choice__btns { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.5rem; }
/* ── By-tracking merged-cell table ──────────────────────────────────────── */
#trackingTree { padding: 0; } /* table reaches the edges; cells carry padding */
.ttable { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 0.82rem; }
.ttable th, .ttable td {
border-right: 1px solid var(--border);
border-bottom: 1px solid var(--border);
vertical-align: top;
padding: 0;
}
.ttable thead th {
position: sticky; top: 0; z-index: 3;
background: var(--bg-secondary, var(--bg));
color: var(--text-muted);
font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
text-align: left; padding: 0.3rem 0.5rem; white-space: nowrap;
border-top: 1px solid var(--border);
}
.ttable__rh { color: var(--primary); }
.ttable__fileh { width: 99%; } /* the files column soaks up remaining width */
.ttable__cell--empty { background: var(--bg-secondary, var(--bg)); }
/* The merged-cell value stays pinned just under the header while you scroll the
group, so a tall rowspan never reads as a blank column. */
.tcell__inner {
position: sticky; top: 1.6rem;
display: flex; align-items: center; gap: 0.3rem;
padding: 0.25rem 0.5rem; white-space: nowrap;
}
.tcell__name { font-weight: 600; }
.trev__inner .tcell__name { color: var(--primary); }
.tcell__preview { text-decoration: none; cursor: pointer; }
.tcell__preview:hover { text-decoration: underline; }
.ttable__cell:hover .tnode__actions, .ttable__rev:hover .tnode__actions { opacity: 1; }
.ttable .drop-hover { outline: 2px solid var(--primary); outline-offset: -2px; }
.ttable__file { padding: 0.1rem 0.4rem; }
.ttable__drop { color: var(--text-muted); font-style: italic; font-size: 0.75rem; }
.ttable .tfile { gap: 0.3rem; align-items: center; }
.ttable .tfile__name {
flex: 1; min-width: 8rem; max-width: 24rem;
padding: 0.15rem 0.35rem; border: 1px solid transparent; border-radius: var(--radius);
background: transparent; color: var(--text); font-size: 0.8rem;
}
.ttable .tfile__name:hover, .ttable .tfile__name:focus { border-color: var(--border); background: var(--bg); }
.ttable .tfile__name--err { color: var(--danger); }
.ttable .tfile--err::before { content: none; } /* we render our own badge instead */
.tfile__badge { font-size: 0.78rem; flex: 0 0 auto; }
.tfile__badge--ok { color: var(--success, #16a34a); }
.tfile__badge--err { color: var(--danger); }