Files
Vincent 6b7c09bacd Reorderable columns, a loaded first file, and a spectrogram worth keeping
Drag a heading and the column moves, with a copy of it following the pointer
and the column it came from stepping back. One array of keys — every column,
shown or hidden — backs the table, the Settings list and what is saved, so a
hidden column keeps its neighbour and returns where it was rather than at the
end. A drag ends in a click, and the click is what sorting listens for, so
that click is swallowed.

Opening a folder loads its first file: the read, the peaks, the channel chips
and the waveform, then paused at the start rather than playing. playRow gained
a paused mode instead of a second loader that could drift from it. It cannot
stop a folder opening, and a file that will not decode no longer writes a
playback error over the line saying the folder opened — nobody asked it to
play. The badge follows the transport now, so a paused file stops claiming to
be playing.

A bulk run re-reads every file it touches, but nothing told the transport to
look again: rename the boom across a card and the mixer went on showing the
old name for the very file it had just rewritten.

Settings loses its Done button and the mixer its Close — both apply as you
touch them, and the window's own close is enough. Save Image moves onto the
file name's line; the rule meant to do that had been dead for some time,
overwritten by the shared modal header. The exported spectrogram carries the
folder, the file and the frequency axis, drawn in, because a PNG read
somewhere else has none of that. The viewer is unchanged.

Mixer track names wear the player's pill, the waveform thumbnails give their
grey panel back to the row, and every button is the transport's size.

Build output that had been committed by accident is untracked, and .gitignore
grows the entries for it.

459 checks.
2026-09-04 00:28:31 +02:00

863 lines
26 KiB
CSS

/* ---------------------------------------------------------------
Native app shell.
In a window of its own there's no page to sit on, so the card
chrome, the outer margin and the grey backdrop all go: the app is
the window. The read-only entry points go too — this build opens
folders read-write and nothing else.
--------------------------------------------------------------- */
html {
-webkit-text-size-adjust: 100%;
height: 100%;
}
body {
margin: 0;
padding: 0;
height: 100%;
background: var(--color-bg);
color: var(--color-text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 15px;
line-height: 1.5;
/* The window itself is the scroll container; nothing here should
ever produce a horizontal one. */
overflow-x: hidden;
}
.page {
max-width: none;
margin: 0;
padding: 0;
min-height: 100%;
}
.bwfa-scope.bwfa-app {
background: var(--color-bg);
border: 0;
border-radius: 0;
box-shadow: none;
/* The plugin caps itself at --container-lg (960px) and centres inside
that, which is right for a page in a theme and wrong for a window:
widen the window past 960 and the extra space just sat there. In an
app the window IS the container, so the cap goes and the padding
below becomes the only gutter. */
max-width: none;
width: 100%;
margin-inline: 0;
padding: 18px 20px 28px;
min-height: 100%;
box-sizing: border-box;
}
/* Read-only selection is gone, and so is the in-app title: the window
already says what this is, and the privacy note was written for a
web page. The markup stays put — the analyser wires listeners to
these nodes at startup and the bridge still hands files back through
the inputs inside them — it just isn't shown. */
.bwfa-scope .bwfa-header,
.bwfa-scope .bwfa-dropzone,
.bwfa-scope .bwfa-edit-divider {
display: none !important;
}
/* Which promotes the editor to the main event. */
.bwfa-scope .bwfa-edit-entry {
margin: 0 0 18px;
padding: 18px 20px;
border: 1px dashed var(--color-border);
border-radius: 10px;
background: var(--color-surface);
text-align: center;
transition: border-color .12s ease, background-color .12s ease;
}
.bwfa-scope .bwfa-edit-entry.is-dragover {
border-color: var(--color-info);
border-style: solid;
background: var(--color-info-bg);
}
/* Open Folder used to be sized up here, and the one on the launch screen
sized up again. Both are gone: a button is a button, and the transport's
size is the size. */
.bwfa-scope .bwfa-edit-entry .bwfa-dropzone-subnote {
max-width: 62ch;
margin: 12px auto 0;
font-size: 12.5px;
color: var(--color-text-muted);
}
/* Header sits tighter now that it's a title bar rather than a page
heading. */
.bwfa-scope .bwfa-header {
margin-bottom: 14px;
}
.bwfa-scope .bwfa-title {
font-size: 19px;
margin: 0 0 4px;
}
/* Let the table use the full width of the window. */
.bwfa-scope .table-responsive {
width: 100%;
overflow-x: auto;
}
.bwfa-scope .bwfa-table {
width: 100%;
}
/* Keep both action columns tight; the rest of the width belongs to
the metadata. */
.bwfa-scope .bwfa-table thead th:nth-child(1),
.bwfa-scope .bwfa-table thead th:nth-child(2) {
width: 1%;
white-space: nowrap;
}
/* ---- Sticky table header ------------------------------------------
Two things in the framework break `position: sticky` on a table
header in WebKit specifically, and both were in play:
- `border-collapse: collapse`. Collapsed borders belong to the
table grid rather than to the cells, and Safari has never
painted a sticky header correctly through one — rows bleed over
the header and its underline detaches. `separate` with zero
spacing looks identical and behaves.
- `-webkit-overflow-scrolling: touch` on the scroll container.
It hands scrolling to a separate compositing layer, which is a
long-standing way to get stale pixels and sticky elements that
scroll away. Momentum scrolling is the platform's job on macOS
anyway.
------------------------------------------------------------------ */
.bwfa-scope .table-responsive {
-webkit-overflow-scrolling: auto;
}
.bwfa-scope .bwfa-table {
border-collapse: separate;
border-spacing: 0;
}
/* Collapse was what drew the row lines; with separate borders each cell
draws its own, which comes to the same thing visually. */
.bwfa-scope .bwfa-table th,
.bwfa-scope .bwfa-table td {
border-bottom: 1px solid var(--color-border);
}
/*
* Both selectors, deliberately. The plugin gives every *sortable* header
* `position: relative` (for the sort arrow), and
* `.bwfa-table th[data-bwfa-sort]` outranks `.bwfa-table thead th` — so
* naming only the second left fourteen of seventeen headers relative
* rather than sticky. The three that held were the ones that aren't
* sortable: the two action columns, Description and Note. Hence a header
* that was half stuck and half scrolling, with rows painting through the
* gap.
*
* Sticky is itself a positioned value, so the absolutely-positioned sort
* arrow still anchors to its own cell.
*/
.bwfa-scope .bwfa-table thead th,
.bwfa-scope .bwfa-table thead th[data-bwfa-sort] {
position: sticky;
top: 0;
/* Above the rows, which are unpositioned, and above the row
backgrounds that were painting over it. */
z-index: 3;
background: var(--color-bg);
background-clip: padding-box;
}
/* Nothing in the body may promote itself above the header. */
.bwfa-scope .bwfa-table tbody td {
position: static;
z-index: auto;
}
@media (max-width: 700px) {
.bwfa-scope.bwfa-app {
padding: 12px 12px 20px;
}
}
/* ---- Toolbar ------------------------------------------------------
The window's minWidth is set so this row always fits; nowrap makes
that a hard guarantee rather than a hope, and keeps the search field
as the only thing that gives.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-toolbar {
flex-wrap: nowrap;
align-items: center;
gap: 12px;
}
.bwfa-scope .bwfa-search-group {
flex: 1 1 auto;
min-width: 180px;
margin-bottom: 0;
}
.bwfa-scope .bwfa-export-actions {
flex: none;
flex-wrap: nowrap;
}
.bwfa-scope .bwfa-export-actions .btn,
.bwfa-scope .bwfa-toolbar .btn {
white-space: nowrap;
}
/* ---- Selection ----------------------------------------------------
This is an app, not a document: dragging a selection across a table
of takes only ever looks like a mistake. Fields you type into keep
selection, since editing without it is miserable.
------------------------------------------------------------------ */
.bwfa-scope,
body {
-webkit-user-select: none;
user-select: none;
}
.bwfa-scope input,
.bwfa-scope textarea,
.bwfa-scope select,
.bwfa-scope [contenteditable="true"] {
-webkit-user-select: text;
user-select: text;
}
/* ---- The folder bar, once a folder is open -------------------------
Before: a dashed panel inviting you to open something. After: one
line saying which folder you're in, with the button to change it.
The invitation has served its purpose and the table needs the room.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-edit-entry.is-folder-open {
display: flex;
align-items: center;
gap: 12px;
margin: 0 0 14px;
padding: 0;
border: 0;
background: none;
text-align: left;
}
.bwfa-scope .bwfa-edit-entry.is-folder-open .bwfa-dropzone-subnote {
display: none;
}
.bwfa-scope .bwfa-current-folder {
font-size: 15px;
font-weight: var(--fw-medium);
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bwfa-scope .bwfa-current-folder::before {
content: "";
display: inline-block;
width: 13px;
height: 11px;
margin-right: 8px;
vertical-align: -1px;
background-color: var(--color-text-muted);
-webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 12'%3E%3Cpath d='M1 2.5A1.5 1.5 0 0 1 2.5 1h2.2c.4 0 .8.2 1 .5l.7.9h5.1A1.5 1.5 0 0 1 13 3.9v5.6A1.5 1.5 0 0 1 11.5 11h-9A1.5 1.5 0 0 1 1 9.5v-7Z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 12'%3E%3Cpath d='M1 2.5A1.5 1.5 0 0 1 2.5 1h2.2c.4 0 .8.2 1 .5l.7.9h5.1A1.5 1.5 0 0 1 13 3.9v5.6A1.5 1.5 0 0 1 11.5 11h-9A1.5 1.5 0 0 1 1 9.5v-7Z'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
/* ---- Window layout: the table is the only thing that scrolls -------
The player has to stay put while a long day scrolls past it. Pinning
it with position:fixed and reserving page padding didn't hold up —
the plugin sets .table-responsive to overflow-y:hidden, so the table
never scrolls itself and the window does, which puts the last rows
under a fixed footer no matter how much padding is reserved.
So the layout is explicit instead: the app is a column exactly as
tall as the window, the table region is the one scrolling box, and
the player is an ordinary block ordered after it. There is no
clearance to get wrong, because the scrolling box ends where the
player begins. The sticky table header now sticks to the top of that
box, which is also what you want.
------------------------------------------------------------------ */
html,
body {
height: 100%;
overflow: hidden;
}
.page {
height: 100%;
min-height: 0;
}
.bwfa-scope.bwfa-app {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
padding-bottom: 14px;
}
.bwfa-scope .bwfa-results {
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-height: 0;
margin-top: 0;
}
.bwfa-scope .bwfa-results > .table-responsive {
flex: 1 1 auto;
min-height: 0;
overflow-x: auto;
overflow-y: auto;
}
/* Ordered last regardless of where it sits in the markup. */
.bwfa-scope .bwfa-player {
order: 99;
flex: none;
margin: 12px 0 0;
padding: 10px 14px 12px;
gap: 8px;
}
.bwfa-scope .bwfa-player-waveform {
height: 34px;
}
/* The plugin spaced the status line by giving the results panel a top
margin; making that panel a flex child meant zeroing it, which left
"Done — 35 files analysed" sitting on top of the search field. The
status carries its own spacing now, and keeps its min-height so the
layout doesn't jump when the line appears. */
.bwfa-scope .bwfa-status {
margin: 6px 0 14px;
}
/* ---- Launch state --------------------------------------------------
With nothing open there's nothing to report, so the status line and
the "No files analysed yet" placeholder are noise. What's left is one
panel, centred, which is the only thing there is to do.
------------------------------------------------------------------ */
.bwfa-scope.bwfa-app:not(.has-folder) {
justify-content: center;
}
.bwfa-scope.bwfa-app:not(.has-folder) .bwfa-status,
.bwfa-scope.bwfa-app:not(.has-folder) .bwfa-empty {
display: none;
}
.bwfa-scope.bwfa-app:not(.has-folder) .bwfa-edit-entry {
max-width: 560px;
margin: 0 auto;
padding: 32px 28px;
}
/* The app's own icon, inlined at build time from the .icns source set so
the frontend stays a single self-contained file. Launch screen only —
once you're working, the window's title bar and Dock icon are enough. */
.bwfa-scope .bwfa-launch-logo {
display: none;
}
.bwfa-scope.bwfa-app:not(.has-folder) .bwfa-launch-logo {
display: block;
width: 88px;
height: 88px;
margin: 0 auto 22px;
background-image: url("@@LAUNCH_LOGO@@");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
/* Every folder this build opens is opened read-write, so a banner saying
so on every screen is telling you something you can't change and
already know. The warning that matters is on the launch panel, where
you choose the folder in the first place. */
.bwfa-scope .bwfa-editing-note {
display: none !important;
}
/* ---- Bulk edit and export live in modals ---------------------------
Both panels used to open as siblings of the table inside a column
exactly as tall as the window. The table region is the flexible one
(`min-height: 0`, so it may shrink to nothing), so a panel at its
natural height squeezed the table out of existence — and since the
window itself doesn't scroll, that left nothing scrollable anywhere.
Capping the panel and flooring the table held, but only by dividing a
space neither of them wanted to share.
As modals they're out of that fight: the dialog is positioned against
the viewport and scrolls itself, and the table keeps the whole column.
The panel inside gives up its own card — the dialog is the card now.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-sheet-dialog {
position: relative;
/* Width and height come from --modal-width with every other modal's.
Setting them here is how the sheets ended up a different size from
the rest, twice. */
}
.bwfa-scope .bwfa-sheet-wide {
max-width: 1120px;
}
/* Padding comes from --modal-pad with every other modal's. This file is
loaded after overrides.css, so anything set here silently beats the
shared rules — which is how Bulk Edit ended up with this panel's 24px
on top of the shared header's 32px while Sound Report had only the 32.
Three rounds of "why is that one different" traced back to here. */
/* The close button is a traffic light now, styled once for every modal in
overrides.css. This rule used to pin it top right with padding of its
own, which quietly made the sheets' button a different size and place
from everything else's — it loaded after the shared rule and won. */
.bwfa-scope .bwfa-sheet-close {
z-index: 2;
}
/* Room for the close button, so a long heading can't run under it. */
/* Header padding comes from --modal-pad with every other modal's. */
.bwfa-scope .bwfa-results > .table-responsive {
min-height: 20vh;
}
/* ---- Reset ---------------------------------------------------------
Sits left of the folder button and undoes the session: closes the
folder, empties the table, forgets what to reopen. Only meaningful
once something is open, so that's the only time it's there.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-reset {
display: none;
}
.bwfa-scope .bwfa-edit-entry.is-folder-open .bwfa-reset {
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
width: 30px;
height: 30px;
padding: 0;
font-size: 0;
border-radius: 50%;
}
.bwfa-scope .bwfa-reset::before {
content: "";
display: block;
width: 13px;
height: 13px;
background-color: currentColor;
-webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2.5 14.2 10.2H1.8z' fill='black'/%3E%3Crect x='1.8' y='11.9' width='12.4' height='2.1' rx='.7' fill='black'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2.5 14.2 10.2H1.8z' fill='black'/%3E%3Crect x='1.8' y='11.9' width='12.4' height='2.1' rx='.7' fill='black'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
}
/* ---- Export panel --------------------------------------------------
Wears the bulk-edit panel's classes, so the card, the 38px control
height, the label treatment and the 40vh cap all come for free. Only
the parts it doesn't share are here: the destination row, which is a
field with a button welded to its end, and the report.
------------------------------------------------------------------ */
/* Its own row class rather than the bulk-edit one: the app enumerates
.bwfa-bulk-edit-row to work out which fields to write, so sharing the
name would hand it five controls that have nothing to do with editing.
The look is shared here instead, which is the part worth sharing. */
.bwfa-scope .bwfa-export-fields {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 16px 20px;
margin-bottom: var(--space-4);
max-width: 1080px;
align-items: start;
}
.bwfa-scope .bwfa-export-row {
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.bwfa-scope .bwfa-export-row > .form-label {
min-width: 0;
margin: 0;
color: var(--color-text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.bwfa-scope .bwfa-export-row > .form-control,
.bwfa-scope .bwfa-export-row > .form-select {
width: 100%;
height: 38px;
min-height: 38px;
padding: 0 10px;
line-height: 1.2;
box-sizing: border-box;
font-size: var(--fs-sm);
}
.bwfa-scope .bwfa-export-row > .form-select {
-webkit-appearance: none;
appearance: none;
padding-right: 30px;
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%2371717a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 11px center;
background-size: 11px;
}
.bwfa-scope .bwfa-export-row input[type="number"] {
-moz-appearance: textfield;
}
.bwfa-scope .bwfa-export-row input[type="number"]::-webkit-outer-spin-button,
.bwfa-scope .bwfa-export-row input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Nothing to type into means nothing to look at: a disabled target reads
as inactive rather than as a field you're failing to fill in. */
.bwfa-scope .bwfa-export-row > .form-control:disabled {
background-color: var(--color-surface-alt, #f4f4f5);
color: var(--color-text-muted);
}
/* The path is the long one, so it gets the width when there is any. */
.bwfa-scope .bwfa-export-dest {
grid-column: span 2;
min-width: 0;
}
.bwfa-scope .bwfa-export-dest-row {
display: flex;
gap: 8px;
align-items: stretch;
min-width: 0;
}
.bwfa-scope .bwfa-export-dest-row > .form-control {
flex: 1 1 auto;
min-width: 0;
height: 38px;
padding: 0 10px;
font-size: var(--fs-sm);
box-sizing: border-box;
direction: ltr;
/* A long path should show its end — the folder — not its beginning. */
text-overflow: ellipsis;
}
/* The one button in the app that isn't the standard height, because it is
not standing among buttons: it is paired with the path field beside it and
takes that field's 38px, so the two read as one control. The row stretches
its items, so this height only spells out what the field would impose
anyway. Side padding matches every other button; the vertical padding has
to be 0 for a fixed height to mean anything. */
.bwfa-scope .bwfa-export-dest-row > .btn {
flex: none;
height: 38px;
padding: 0 0.75rem;
white-space: nowrap;
}
/* ---- The report modal ----------------------------------------------
A finished export is not a form, so it stops looking like one. The
dialog is the only one that doesn't scroll as a whole: the heading,
the counts and the buttons stay put and the list moves under them,
which is the difference between reading a hundred rows and hunting
for the button that dismisses them.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-sheet-report {
display: flex;
flex-direction: column;
overflow: hidden;
/* Width comes from --modal-width with every other modal's. This used
to set its own, which is exactly how six dialogs ended up six
different sizes. */
}
.bwfa-scope .bwfa-sheet-report .bwfa-result-panel {
display: flex;
flex-direction: column;
min-height: 0;
flex: 1 1 auto;
}
.bwfa-scope .bwfa-result-panel .bwfa-bulk-edit-header {
margin-bottom: var(--space-4);
}
.bwfa-scope .bwfa-result-panel .bwfa-bulk-edit-header p {
margin: 4px 0 0;
font-size: var(--fs-sm);
color: var(--color-text-muted);
word-break: break-all;
}
.bwfa-scope .bwfa-result-tally {
display: flex;
gap: var(--space-5);
flex: none;
padding-bottom: var(--space-4);
border-bottom: 1px solid var(--color-border);
}
.bwfa-scope .bwfa-result-stat {
display: flex;
flex-direction: column;
gap: 1px;
line-height: 1.15;
}
.bwfa-scope .bwfa-result-stat strong {
font-size: 22px;
font-weight: var(--fw-semibold);
font-variant-numeric: tabular-nums;
color: var(--color-text);
}
.bwfa-scope .bwfa-result-stat span {
font-size: var(--fs-xs, 12px);
color: var(--color-text-muted);
}
/* A count of nothing still belongs on screen — "0 failed" is the whole
reassurance — but it shouldn't compete with the counts that matter. */
.bwfa-scope .bwfa-result-stat.is-zero strong,
.bwfa-scope .bwfa-result-stat.is-zero span {
color: var(--gray-400, #b0b0b8);
}
.bwfa-scope .bwfa-result-stat.is-bad strong {
color: var(--color-danger, #b42318);
}
.bwfa-scope .bwfa-result-note {
flex: none;
margin: var(--space-3) 0 0;
font-size: var(--fs-sm);
color: var(--color-text-muted);
}
.bwfa-scope .bwfa-result-panel .bwfa-bulk-edit-actions {
flex: none;
margin-top: var(--space-4);
padding-top: var(--space-4);
border-top: 1px solid var(--color-border);
}
.bwfa-scope .bwfa-export-report {
margin-top: var(--space-3);
font-size: var(--fs-sm);
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
/* Room for the scrollbar so the last column doesn't sit under it. */
padding-right: 4px;
}
.bwfa-scope .bwfa-export-report ul {
margin: 0;
padding: 0;
list-style: none;
}
.bwfa-scope .bwfa-export-report li {
display: flex;
gap: 16px;
padding: 7px 2px;
color: var(--color-text-muted);
border-bottom: 1px solid var(--color-border-subtle, var(--gray-100, #f1f1f4));
}
.bwfa-scope .bwfa-export-report li:last-child {
border-bottom: 0;
}
.bwfa-scope .bwfa-export-report li.is-problem {
color: var(--color-danger, #b42318);
}
.bwfa-scope .bwfa-export-report-name {
flex: none;
width: 38%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--color-text);
font-variant-numeric: tabular-nums;
}
.bwfa-scope .bwfa-export-report-detail {
flex: 1 1 auto;
min-width: 0;
}
/* ---- Track picker in the export panel ------------------------------
The same chips as the player's channel strip, because they answer
the same question about the same file — there they mute, here they
choose what gets written. Only offered for a single file: across a
folder of takes, "track 3" isn't the same thing twice.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-export-tracks {
grid-column: 1 / -1;
}
.bwfa-scope .bwfa-export-tracks .bwfa-channel-chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 4px 0;
}
.bwfa-scope .bwfa-export-tracks .chip {
cursor: pointer;
user-select: none;
}
/* Off reads as off: struck through and faded, the way a muted channel
already reads in the player. */
.bwfa-scope .bwfa-export-tracks .chip.is-off {
opacity: 0.45;
text-decoration: line-through;
}
/* ---- The audio escape hatch ----------------------------------------
Only in the app, where reloading the window costs a folder re-scan
and nothing else: the last folder reopens by itself.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-settings-action {
display: block;
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid var(--color-border);
}
/* ---- What a combine would make ------------------------------------
Shown before anything is written, because the answer to "can this be
done" is already in the metadata: rates, timecodes, lengths. A
problem here disables Export rather than interrupting with a dialog.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-export-summary-line {
margin: 4px 0 14px;
padding: 10px 12px;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm, 6px);
background-color: var(--color-surface);
font-size: var(--fs-sm);
color: var(--color-text);
}
.bwfa-scope .bwfa-export-summary-line.is-blocked {
border-color: var(--color-danger);
background-color: var(--color-danger-bg);
color: var(--color-danger);
}
.bwfa-scope .bwfa-export-summary-line small {
display: block;
margin-top: 4px;
color: var(--color-text-muted);
}
.bwfa-scope .bwfa-export-summary-line.is-blocked small {
color: inherit;
}
/* ---- Naming the copies ---------------------------------------------
The pattern row and the preview both span, because a filename is a
long thing and reading old against new is the entire point of
showing it at all.
------------------------------------------------------------------ */
.bwfa-scope .bwfa-export-pattern {
grid-column: 1 / -1;
min-width: 0;
}
.bwfa-scope .bwfa-export-tokens {
margin: 6px 0 0;
font-size: var(--fs-xs, 12px);
color: var(--color-text-muted);
font-variant-numeric: tabular-nums;
word-spacing: 4px;
}
.bwfa-scope .bwfa-export-names {
margin: 4px 0 12px;
padding: 10px 12px;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm, 6px);
background-color: var(--color-surface);
font-size: var(--fs-sm);
color: var(--color-text-muted);
}
.bwfa-scope .bwfa-export-names.is-blocked {
border-color: var(--color-danger);
background-color: var(--color-danger-bg);
color: var(--color-danger);
}
.bwfa-scope .bwfa-export-name-row {
display: flex;
align-items: baseline;
gap: 10px;
padding: 2px 0;
min-width: 0;
}
/* The arrow is drawn rather than typed, so a name containing one can't
be mistaken for the thing pointing at it. */
.bwfa-scope .bwfa-export-name-row > span::after {
content: "\2192";
margin-left: 10px;
color: var(--color-text-muted);
}
.bwfa-scope .bwfa-export-name-row > span {
flex: none;
max-width: 46%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bwfa-scope .bwfa-export-name-row > strong {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: var(--fw-medium, 500);
color: var(--color-text);
}
.bwfa-scope .bwfa-export-names small {
display: block;
margin-top: 4px;
}