The browser page is gone, with its shim, its shell CSS and its suite. build.py has no --tauri flag and one output: the app's page. The patch lists lose the SHARED_ prefix, which only ever meant "shared between the two builds", and test-pdf.js was quietly loading the browser page — it reads the app's now. Space plays and pauses, in the main window off the player at the bottom and in the mixer off the same transport. It is swallowed rather than passed on: that stops the window scrolling, and stops a focused button taking the same press as a second activation, which toggles twice and looks like a dead key. Typing, and any dialog other than the mixer, keep it. Deciding what is in front needs both markers — closing does not always remove .open, and .modal without it is display:none regardless of the hidden attribute. The mixer footer put the next file's name adrift in the middle of the row. The margin-left: auto meant to park it beside Close could do nothing, because the framework's flex: 1 1 auto had both nav groups growing to fill the row and left no free space to absorb. Pinned to flex: 0 0 auto. The file-detail modal shares the markup and follows. Bulk track rename wrote nothing, on every file, and had never worked. A rename is keyed on the name it replaces rather than a path, so the frame-rate pass threw reading edit.path off it — before any byte was written, so nothing was corrupted, only untouched. The failure handler discarded the reason and the run still ended on a tidy Done, which is why 0 saved read as progress; it now names the file and the cause in the log. 429 checks. The gap that hid the rename bug was end-to-end: the writer was unit tested and the panel rendered, and nothing drove one into the other.
1566 lines
48 KiB
CSS
1566 lines
48 KiB
CSS
/* ---------------------------------------------------------------
|
|
Fixes applied to both builds, kept separate from the plugin's own
|
|
stylesheet so that file stays byte-identical to the original.
|
|
--------------------------------------------------------------- */
|
|
|
|
/* The detail modal laid its metadata out with
|
|
`repeat(auto-fill, minmax(180px, 1fr))`, and dt/dd are separate grid
|
|
items flowing in sequence. Any odd column count therefore splits the
|
|
pairs: three columns give you label, value, label / value, label,
|
|
value, so every other row reads inside out. Pinning the layout to
|
|
exactly two label+value pairs per row makes that impossible. */
|
|
.bwfa-scope .bwfa-meta-grid {
|
|
grid-template-columns:
|
|
minmax(6.5rem, max-content) minmax(0, 1fr)
|
|
minmax(6.5rem, max-content) minmax(0, 1fr);
|
|
column-gap: var(--space-6, 32px);
|
|
row-gap: var(--space-3, 12px);
|
|
align-items: baseline;
|
|
}
|
|
|
|
/* Label and value now sit side by side rather than stacked. */
|
|
.bwfa-scope .bwfa-meta-grid dt {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* Narrow enough and two pairs stop fitting; drop to one, still paired. */
|
|
@media (max-width: 760px) {
|
|
.bwfa-scope .bwfa-meta-grid {
|
|
grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
|
|
}
|
|
}
|
|
|
|
/* Room for two columns of metadata without the modal feeling cramped. */
|
|
|
|
|
|
/* The edit form gets the same extra width, so give its fields a wider
|
|
minimum rather than letting them multiply into thin strips. */
|
|
.bwfa-scope .bwfa-edit-grid {
|
|
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
|
|
/* Was `end`, which bottom-aligns cells of differing heights and
|
|
leaves the labels scattered at whatever height their own text
|
|
happens to reach. Stretch instead, and let each field place its
|
|
own control. */
|
|
align-items: stretch;
|
|
}
|
|
|
|
/* Label on top, control pinned to the bottom of the cell — so every
|
|
control across a row shares one baseline no matter how tall the
|
|
labels above them are. */
|
|
.bwfa-scope .bwfa-edit-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-edit-field > .form-control,
|
|
.bwfa-scope .bwfa-edit-field > .form-select {
|
|
margin-top: auto;
|
|
}
|
|
|
|
/* One height for every control in the form. A native <select> sizes
|
|
itself from the platform's own metrics and ignores the padding that
|
|
makes an <input> 38px, so both get told explicitly. */
|
|
.bwfa-scope .bwfa-edit-grid .form-control,
|
|
.bwfa-scope .bwfa-edit-grid .form-select {
|
|
height: 38px;
|
|
min-height: 38px;
|
|
padding: 0 10px;
|
|
line-height: 1.2;
|
|
box-sizing: border-box;
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-edit-grid .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;
|
|
}
|
|
|
|
/* Steppers on an empty number field are just clutter; the value is
|
|
typed, never nudged. */
|
|
.bwfa-scope .bwfa-edit-grid input[type="number"] {
|
|
-moz-appearance: textfield;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-edit-grid input[type="number"]::-webkit-outer-spin-button,
|
|
.bwfa-scope .bwfa-edit-grid input[type="number"]::-webkit-inner-spin-button {
|
|
-webkit-appearance: none;
|
|
margin: 0;
|
|
}
|
|
|
|
/* The toggles keep the framework's inline label+switch pairing, but sit
|
|
on the same line as the controls beside them rather than floating in
|
|
the middle of a taller cell. */
|
|
.bwfa-scope .bwfa-edit-field.form-switch {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
gap: var(--space-2, 8px);
|
|
align-self: end;
|
|
min-height: 38px;
|
|
}
|
|
|
|
/* Note and Description are multi-line; they get the full row. */
|
|
.bwfa-scope .bwfa-edit-field:has(textarea) {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-edit-grid textarea.form-control {
|
|
height: auto;
|
|
min-height: 5rem;
|
|
padding: 8px 10px;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Bulk edit
|
|
|
|
No per-field checkboxes: a field you fill in gets written to every
|
|
file, a field left blank is left alone. So each cell is just a label
|
|
over a control, same shape as the per-file form, and the grid is
|
|
capped so a wide window doesn't spread thirteen fields across eight
|
|
columns.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-bulk-edit-fields {
|
|
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
gap: 16px 20px;
|
|
max-width: 1080px;
|
|
align-items: start;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-row {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-row > .form-label {
|
|
min-width: 0;
|
|
margin: 0;
|
|
color: var(--color-text-muted);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* A filled-in field is one that's about to be written, so it earns a
|
|
darker label than the ones being skipped. */
|
|
.bwfa-scope .bwfa-bulk-edit-row:has(.form-control:not(:placeholder-shown)) > .form-label,
|
|
.bwfa-scope .bwfa-bulk-edit-row:has(select.form-select option:not([value=""]):checked) > .form-label {
|
|
color: var(--color-text);
|
|
font-weight: var(--fw-semibold);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-row > .form-control,
|
|
.bwfa-scope .bwfa-bulk-edit-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-bulk-edit-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-bulk-edit-row > textarea.form-control {
|
|
height: auto;
|
|
min-height: 60px;
|
|
padding: 8px 10px;
|
|
line-height: 1.45;
|
|
resize: vertical;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-row input[type="number"] {
|
|
-moz-appearance: textfield;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-row input[type="number"]::-webkit-outer-spin-button,
|
|
.bwfa-scope .bwfa-bulk-edit-row input[type="number"]::-webkit-inner-spin-button {
|
|
-webkit-appearance: none;
|
|
margin: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-panel {
|
|
/* Padding comes from --modal-pad, in the unified block below. */
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-header p {
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-hint {
|
|
font-size: var(--fs-sm);
|
|
color: var(--color-text-muted);
|
|
margin: 0 0 var(--space-5);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-actions {
|
|
margin-top: var(--space-2);
|
|
padding-top: var(--space-4);
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Text selection
|
|
|
|
The framework selects text in near-black with white text, which
|
|
looks like a terminal rather than a Mac. This is macOS's own
|
|
selection blue, with the text colour left alone.
|
|
--------------------------------------------------------------- */
|
|
::selection {
|
|
background-color: #b4d5fe;
|
|
color: inherit;
|
|
}
|
|
|
|
.bwfa-scope ::selection {
|
|
background-color: #b4d5fe;
|
|
color: inherit;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Export field picker
|
|
--------------------------------------------------------------- */
|
|
|
|
|
|
.bwfa-scope .bwfa-export-actions-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
padding-bottom: 14px;
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-export-fields {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
gap: 4px 20px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-export-field {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 5px 6px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: var(--fs-sm);
|
|
min-width: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-export-field:hover {
|
|
background-color: var(--color-surface-alt, #f4f4f5);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-export-field input {
|
|
flex: none;
|
|
width: 15px;
|
|
height: 15px;
|
|
margin: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-export-field span {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Row and header accents
|
|
|
|
The plugin marks state with coloured slivers: a gold inset on the
|
|
first cell of a circled take, a blue one on the playing row, and a
|
|
blue rule under the table header. All three go. A playing row says
|
|
so by being green all the way across, which is legible at a glance
|
|
from across a room; circled takes are still reported by their own
|
|
column.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-table tbody tr.bwfa-row-circled td:first-child,
|
|
.bwfa-scope .bwfa-table tbody tr.bwfa-row-playing td:first-child,
|
|
.bwfa-scope .bwfa-table tbody tr.bwfa-row-playing.bwfa-row-circled td:first-child {
|
|
box-shadow: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-table thead th {
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-table.table-striped tbody tr.bwfa-row-playing td,
|
|
.bwfa-scope .bwfa-table.table-striped tbody tr.bwfa-row-playing:hover td,
|
|
.bwfa-scope .bwfa-table.table-hover tbody tr.bwfa-row-playing:hover td {
|
|
background-color: #dff5e4;
|
|
}
|
|
|
|
/* Play and Pause are different lengths, so the button used to resize
|
|
mid-playback and shove everything after it sideways. One width for
|
|
both states. */
|
|
.bwfa-scope .bwfa-table td [data-bwfa-play-btn],
|
|
.bwfa-scope .bwfa-player-playpause,
|
|
.bwfa-scope [data-bwfa-modal-play] {
|
|
min-width: 68px;
|
|
text-align: center;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
The hidden attribute has to win
|
|
|
|
`[hidden] { display: none }` comes from the UA stylesheet, so any
|
|
author rule that sets display beats it. The plugin sets
|
|
`display: flex` on the player, and the app shell does the same for
|
|
the results panel — so both stayed on screen with their hidden
|
|
attribute set, which is why the toolbar, an empty table and the
|
|
transport were all visible before a folder was ever opened.
|
|
|
|
One rule fixes every case, present and future: if the markup says
|
|
hidden, it's hidden.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope [hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Modal backdrop
|
|
|
|
A modal exists to say that the thing behind it isn't what you're
|
|
working on, and blur says that far better than a flat wash of
|
|
opacity does. Both builds, every modal.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .modal-backdrop {
|
|
background-color: rgba(24, 24, 27, 0.55);
|
|
-webkit-backdrop-filter: blur(10px) saturate(0.8);
|
|
backdrop-filter: blur(10px) saturate(0.8);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Sound report
|
|
|
|
Export Fields, Export CSV and Export PDF became one button and a
|
|
modal: the report's details, its format and its fields are one
|
|
decision, and three buttons in the toolbar made it three. The
|
|
originals stay in the DOM because the analyser wires its export
|
|
pipeline to them at startup and the modal drives them rather than
|
|
reimplementing any of it.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-legacy-export {
|
|
display: none !important;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-details {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
gap: 14px 18px;
|
|
margin-bottom: var(--space-5);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-row {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-row > .form-label {
|
|
margin: 0;
|
|
color: var(--color-text-muted);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-row > .form-control,
|
|
.bwfa-scope .bwfa-report-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-report-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;
|
|
}
|
|
|
|
/* The field list is the long half of the modal, so it gets a heading of
|
|
its own rather than starting where the details stop. */
|
|
.bwfa-scope .bwfa-report-fields-head {
|
|
display: flex;
|
|
align-items: baseline;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
padding-top: var(--space-4);
|
|
margin-bottom: var(--space-3);
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-fields-head h4 {
|
|
margin: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-count {
|
|
color: var(--color-text-muted);
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-report-fields-head .bwfa-export-actions-row {
|
|
margin: 0 0 0 auto;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
The columns cogwheel
|
|
|
|
The columns control used to be a dropdown in the toolbar, one
|
|
more button in a row of them, describing something that happens
|
|
in the table. It's now a cogwheel in the table's own first header
|
|
cell — the empty one above Play, which was doing nothing — and it
|
|
opens a modal listing every column.
|
|
--------------------------------------------------------------- */
|
|
/* Built to read as a smaller sibling of the eject button in the folder
|
|
bar: same circle, same hairline border, same muted glyph. Smaller
|
|
because a table header is not the place for a 30px control. */
|
|
.bwfa-scope .bwfa-columns-cog {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-sizing: border-box;
|
|
width: 22px;
|
|
height: 22px;
|
|
padding: 0;
|
|
/* Lighter than the framework's own border and text-muted: this is a
|
|
control you look for rather than one that asks to be noticed, so at
|
|
rest it's barely there and it comes forward under the pointer. */
|
|
border: 1px solid #eaeaee;
|
|
border-radius: 50%;
|
|
background-color: transparent;
|
|
color: #c6c6cc;
|
|
line-height: 0;
|
|
cursor: pointer;
|
|
transition: border-color var(--duration-fast, 120ms), color var(--duration-fast, 120ms);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-columns-cog:hover,
|
|
.bwfa-scope .bwfa-columns-cog:focus-visible {
|
|
border-color: #b4b4bb;
|
|
color: #6e6e77;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-columns-cog::before {
|
|
content: "";
|
|
display: block;
|
|
width: 12px;
|
|
height: 12px;
|
|
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 24 24'%3E%3Cpath d='M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6h.09A1.65 1.65 0 0 0 10 3.09V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9v.09a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z' fill='none' stroke='black' stroke-width='1.8'/%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 24 24'%3E%3Cpath d='M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6h.09A1.65 1.65 0 0 0 10 3.09V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9v.09a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z' fill='none' stroke='black' stroke-width='1.8'/%3E%3C/svg%3E");
|
|
-webkit-mask-repeat: no-repeat;
|
|
mask-repeat: no-repeat;
|
|
-webkit-mask-size: contain;
|
|
mask-size: contain;
|
|
}
|
|
|
|
/* Two columns of switches: 26 of them in one list is a scroll for no
|
|
reason, and the modal has the width for it. */
|
|
|
|
|
|
.bwfa-scope .bwfa-columns-dialog .bwfa-columns-menu {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
gap: 2px 20px;
|
|
max-height: none;
|
|
min-width: 0;
|
|
overflow: visible;
|
|
}
|
|
|
|
/* The header cell it lives in is otherwise empty, so it sets the column's
|
|
width — keep it to the button and align it left, with the Play buttons
|
|
under it rather than centred over them. */
|
|
.bwfa-scope .bwfa-table thead th:first-child {
|
|
text-align: left;
|
|
vertical-align: middle;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Settings modal
|
|
|
|
Three topics behind three accordions, all closed to start with:
|
|
the point of the cog is that you go looking for one thing, not
|
|
that you read a wall of options every time.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-settings-section {
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-section:first-child {
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-section > summary {
|
|
list-style: none;
|
|
cursor: pointer;
|
|
padding: 12px 4px 12px 22px;
|
|
position: relative;
|
|
font-weight: var(--fw-semibold);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-section > summary::-webkit-details-marker {
|
|
display: none;
|
|
}
|
|
|
|
/* A disclosure triangle of our own, so it points where we want it. */
|
|
.bwfa-scope .bwfa-settings-section > summary::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 4px;
|
|
top: 50%;
|
|
width: 0;
|
|
height: 0;
|
|
margin-top: -4px;
|
|
border-left: 5px solid var(--color-text-muted);
|
|
border-top: 4px solid transparent;
|
|
border-bottom: 4px solid transparent;
|
|
transition: transform var(--duration-fast, 120ms) ease;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-section[open] > summary::before {
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-body {
|
|
padding: 0 4px 16px 22px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice-list {
|
|
display: grid;
|
|
gap: 4px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
padding: 8px 10px;
|
|
border-radius: var(--radius-sm, 6px);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice:hover {
|
|
background-color: var(--color-surface-alt);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice input {
|
|
margin: 2px 0 0;
|
|
flex: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice span {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice small {
|
|
color: var(--color-text-muted);
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Dark mode
|
|
|
|
The framework maps every surface, border and text colour onto one
|
|
grayscale ramp, so the whole app turns over by redefining the ramp
|
|
— no per-component overrides, and anything added later comes along
|
|
for free. Anthracite rather than black: a true-black window in a
|
|
dark room is a light source with a hole in it, and the greys need
|
|
somewhere to sit below the page.
|
|
|
|
The ramp is not a straight inversion. Dark interfaces need less
|
|
contrast at the top end (white on near-black glares) and more
|
|
separation at the bottom, so the surfaces sit closer together and
|
|
the text stops short of white.
|
|
--------------------------------------------------------------- */
|
|
/* html and body are outside the scoped container but still paint the
|
|
window, so the ramp is mirrored onto the root. Only the handful of
|
|
values anything outside the app actually reads. */
|
|
:root {
|
|
--color-bg: #ffffff;
|
|
--color-text: #333333;
|
|
}
|
|
|
|
.bwfa-scope[data-bwfa-theme="dark"] {
|
|
--gray-0: #202225;
|
|
--gray-50: #25272b;
|
|
--gray-100: #2a2d31;
|
|
--gray-150: #313438;
|
|
--gray-200: #3b3e43;
|
|
--gray-300: #4c5057;
|
|
--gray-400: #6d727a;
|
|
--gray-500: #8a9098;
|
|
--gray-600: #a6abb3;
|
|
--gray-700: #c3c7cd;
|
|
--gray-800: #e3e5e8;
|
|
--gray-900: #f1f2f4;
|
|
--gray-1000: #ffffff;
|
|
|
|
--color-success: #6cc38d;
|
|
--color-success-bg: #1e3328;
|
|
--color-danger: #f08b84;
|
|
--color-danger-bg: #3a2422;
|
|
--color-warning: #ddb85a;
|
|
--color-warning-bg: #35301f;
|
|
--color-info: #8ab4e8;
|
|
--color-info-bg: #22303f;
|
|
}
|
|
|
|
/* Selection: the same idea as the light theme's macOS blue, at a
|
|
weight that works under light text. */
|
|
.bwfa-scope[data-bwfa-theme="dark"] ::selection {
|
|
background-color: #2f4f75;
|
|
color: #f1f2f4;
|
|
}
|
|
|
|
/* The playing row, and the Play button that has to stay legible on it. */
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-table.table-striped tbody tr.bwfa-row-playing td,
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-table.table-striped tbody tr.bwfa-row-playing:hover td,
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-table.table-hover tbody tr.bwfa-row-playing:hover td {
|
|
background-color: #22382c;
|
|
}
|
|
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-columns-cog {
|
|
border-color: #3b3e43;
|
|
color: #6d727a;
|
|
}
|
|
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-columns-cog:hover,
|
|
.bwfa-scope[data-bwfa-theme="dark"] .bwfa-columns-cog:focus-visible {
|
|
border-color: #6d727a;
|
|
color: #c3c7cd;
|
|
}
|
|
|
|
/* The backdrop is already a dark wash; on a dark page it needs to be
|
|
deeper to read as one at all. */
|
|
.bwfa-scope[data-bwfa-theme="dark"] .modal-backdrop {
|
|
background-color: rgba(8, 9, 10, 0.62);
|
|
}
|
|
|
|
/* The window itself, when the app is in dark mode. `:has()` is how a
|
|
scoped theme reaches its own page furniture; WebKit has had it since
|
|
Safari 15.4, and the fallback is simply the light window it is today. */
|
|
html:has(.bwfa-scope[data-bwfa-theme="dark"]) {
|
|
--color-bg: #202225;
|
|
--color-text: #e3e5e8;
|
|
background-color: #202225;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Settings, one size down
|
|
|
|
Nothing in the cog is prose — it's a list of switches and short
|
|
labels — and at body size it read as the loudest thing on screen
|
|
for the least important. Everything in the dialog steps down a
|
|
size together, controls included, so the proportions hold.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-columns-dialog {
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
/* The title size comes from the shared header rule, with every other
|
|
modal's. This set its own and made Settings the odd one out. */
|
|
|
|
.bwfa-scope .bwfa-settings-section > summary {
|
|
font-size: var(--fs-sm);
|
|
padding: 10px 4px 10px 20px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice {
|
|
padding: 6px 8px;
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-choice small,
|
|
.bwfa-scope .bwfa-columns-dialog .form-switch {
|
|
font-size: var(--fs-xs);
|
|
}
|
|
|
|
/* The radios come from the platform, so they're sized rather than
|
|
restyled — a scaled transform would blur them. */
|
|
.bwfa-scope .bwfa-choice input[type="radio"] {
|
|
width: 13px;
|
|
height: 13px;
|
|
margin-top: 1px;
|
|
}
|
|
|
|
/* The switch is drawn by the framework out of one input; both halves
|
|
of it have to come down together or the knob leaves the track. */
|
|
.bwfa-scope .bwfa-columns-dialog .form-switch input {
|
|
width: 2rem;
|
|
height: 1.1rem;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-columns-dialog .form-switch input::before {
|
|
width: calc(1.1rem - 4px);
|
|
height: calc(1.1rem - 4px);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-columns-dialog .form-switch input:checked::before {
|
|
transform: translateX(0.9rem);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-columns-dialog .bwfa-columns-menu .form-switch {
|
|
padding: 3px var(--space-2);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------
|
|
Note and Description, side by side
|
|
|
|
They're the only two free-text fields in either edit form, and
|
|
they were laid out as leftovers: Note ending up in whatever cell
|
|
was going spare and Description alone on a row of its own. As a
|
|
pair on their own row, at the same width and the same height,
|
|
the form has a bottom edge instead of a ragged tail.
|
|
--------------------------------------------------------------- */
|
|
.bwfa-scope .bwfa-edit-field:has(.bwfa-edit-textarea),
|
|
.bwfa-scope .bwfa-bulk-edit-row:has(textarea) {
|
|
grid-column: span 2;
|
|
}
|
|
|
|
/* The first of the pair starts a fresh row, so the second lands
|
|
beside it rather than wherever the flow left off. On a narrow
|
|
window the grid is two columns wide and they stack — still equal,
|
|
still full width. */
|
|
.bwfa-scope .bwfa-edit-field:has(.bwfa-edit-textarea):nth-last-child(2),
|
|
.bwfa-scope .bwfa-bulk-edit-row:has(textarea):nth-last-child(2) {
|
|
grid-column-start: 1;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-edit-grid textarea.form-control,
|
|
.bwfa-scope .bwfa-bulk-edit-row > textarea.form-control {
|
|
min-height: 76px;
|
|
height: 76px;
|
|
}
|
|
|
|
/* The audio reset is an app-only escape hatch: in a browser tab a reload
|
|
loses the folder along with the audio. */
|
|
.bwfa-scope .bwfa-settings-action {
|
|
display: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-settings-action small {
|
|
display: block;
|
|
margin-top: 6px;
|
|
color: var(--color-text-muted);
|
|
font-size: var(--fs-xs);
|
|
max-width: 46ch;
|
|
}
|
|
|
|
|
|
/* ---- What it's doing goes beside the buttons ------------------------
|
|
It used to be a line of its own below them, which only existed while
|
|
a job was running: the modal grew by a line the moment you pressed
|
|
the button and shrank again when it finished, under the cursor. On
|
|
the same row as the buttons it can't change the height at all, and a
|
|
long message is cut off before it reaches them rather than wrapping.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-bulk-edit-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-actions > .btn {
|
|
flex: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-edit-progress,
|
|
.bwfa-scope .bwfa-bulk-edit-progress[hidden] {
|
|
display: block;
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
margin: 0;
|
|
margin-right: auto;
|
|
text-align: left;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* The Apply button while it is waiting to be told twice. */
|
|
.bwfa-scope .bwfa-bulk-edit-actions .btn.is-confirming {
|
|
background-color: var(--color-danger, #b42318);
|
|
border-color: var(--color-danger, #b42318);
|
|
color: #fff;
|
|
}
|
|
|
|
/* The question, while it is being asked. */
|
|
.bwfa-scope .bwfa-bulk-edit-progress.is-asking {
|
|
color: var(--color-text);
|
|
font-weight: var(--fw-medium, 500);
|
|
}
|
|
|
|
/* ---- Track names, as fields rather than labels ----------------------
|
|
What a track is called changes on the day: a radio moves from one
|
|
actor to another between setups. It was a row of read-only badges,
|
|
which is the one piece of metadata you most want to correct.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-track-names {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
gap: 8px;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-track-name {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-track-name-index {
|
|
flex: none;
|
|
width: 1.5em;
|
|
text-align: right;
|
|
color: var(--color-text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-track-name > .form-control {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
height: 32px;
|
|
padding: 0 8px;
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
/* ---- Track names are chips, and the chip is the thing you click -----
|
|
The player already shows channels as chips, so the same names in the
|
|
edit and bulk panels read as the same objects. A row of permanent
|
|
input boxes turned a list of what is there into a form waiting to be
|
|
filled in; this stays a list until you click one.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-name-edit {
|
|
display: inline-flex;
|
|
min-width: 0;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-name-chip {
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
cursor: text;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-name-chip:hover {
|
|
border-color: var(--color-action, var(--color-text));
|
|
}
|
|
|
|
.bwfa-scope .bwfa-name-chip.is-empty {
|
|
color: var(--color-text-muted);
|
|
font-style: italic;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-name-edit-field {
|
|
height: 30px;
|
|
min-width: 8em;
|
|
max-width: 16em;
|
|
padding: 0 8px;
|
|
font-size: var(--fs-sm);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-track-names,
|
|
.bwfa-scope .bwfa-bulk-tracks-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-track-name,
|
|
.bwfa-scope .bwfa-bulk-track {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* How many takes carry this name, sitting with the chip rather than in a
|
|
column of its own: it is a note on the chip, not a field of data. */
|
|
.bwfa-scope .bwfa-bulk-track-count {
|
|
flex: none;
|
|
font-size: var(--fs-xs, 12px);
|
|
color: var(--color-text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
margin-right: var(--space-2);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-track.is-renamed .bwfa-bulk-track-count {
|
|
color: var(--color-info, #375a7f);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-track.is-unnamed {
|
|
opacity: 0.75;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-tracks {
|
|
margin-top: var(--space-4);
|
|
padding-top: var(--space-4);
|
|
border-top: 1px solid var(--color-border);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-bulk-tracks-title {
|
|
font-weight: var(--fw-semibold);
|
|
font-size: var(--fs-sm);
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
|
|
/* ---- Spectrogram ----------------------------------------------------
|
|
Time across, frequency up, brightness as level. Round like the eject
|
|
button, at the end of the player's header row, because it is about
|
|
the file that is loaded rather than about the table.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-spectro-open {
|
|
margin-left: auto;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-open {
|
|
margin-left: var(--space-1, 4px);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-round-btn {
|
|
/* flex: none belongs here, not on one button. Without it these shrink in
|
|
the player's flex row: the icon still paints (it overflows) so the
|
|
button looks perfectly normal, while its hit area has gone to nothing
|
|
and the click lands on the header behind it. A dead button that looks
|
|
alive, and no test with a layout engine behind it can see the
|
|
difference. */
|
|
flex: none;
|
|
width: 26px;
|
|
min-width: 26px;
|
|
height: 26px;
|
|
padding: 0;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 1px solid var(--gray-200, #eaeaee);
|
|
border-radius: 50%;
|
|
background: none;
|
|
color: var(--gray-500, #c6c6cc);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-round-btn:hover {
|
|
border-color: var(--gray-400, #b4b4bb);
|
|
color: var(--color-text, #6e6e77);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-round-btn svg {
|
|
fill: currentColor;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-dialog {
|
|
position: relative;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-head h4 {
|
|
margin: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-head p {
|
|
margin: 4px 0 var(--space-4);
|
|
font-size: var(--fs-sm);
|
|
color: var(--color-text-muted);
|
|
}
|
|
|
|
/* The picture is one pixel per column and per bin, stretched to fit:
|
|
smoothing it would invent detail that isn't in the file. */
|
|
.bwfa-scope .bwfa-spectro-canvas {
|
|
display: block;
|
|
width: 100%;
|
|
height: min(52vh, 460px);
|
|
background-color: #440154;
|
|
border-radius: var(--radius-sm, 6px);
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
/* The frequency axis, beside the picture rather than floating over it: a
|
|
flex row means the labels line up with the image at any height without
|
|
anything being positioned by hand. */
|
|
.bwfa-scope .bwfa-spectro-plot {
|
|
display: flex;
|
|
align-items: stretch;
|
|
min-height: 0;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-scale {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
flex: none;
|
|
width: 4.5em;
|
|
padding: 0 8px 0 0;
|
|
text-align: right;
|
|
font-size: 11px;
|
|
color: var(--color-text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* The top and bottom labels sit at the very edges of the image, so they
|
|
are nudged inward to stay level with the pixels they describe. */
|
|
.bwfa-scope .bwfa-spectro-scale span:first-child {
|
|
transform: translateY(-0.15em);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-scale span:last-child {
|
|
transform: translateY(0.15em);
|
|
}
|
|
|
|
/* Save Image sits with the title, on the right, where the modal's own
|
|
heading block already reserves the room. */
|
|
.bwfa-scope .bwfa-spectro-head {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
gap: var(--space-4);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-head h4,
|
|
.bwfa-scope .bwfa-spectro-head p {
|
|
flex: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-spectro-save {
|
|
margin-left: auto;
|
|
flex: none;
|
|
}
|
|
|
|
/* ---- Every modal closes the way a Mac window closes -----------------
|
|
One red button, top left, at the margins a real window uses. Every
|
|
dialog in the app carries the same .modal-close, so this is one rule
|
|
and there is nothing that can be missed: the detail view, bulk edit,
|
|
export, the export report, the sound report, the columns picker and
|
|
the spectrogram all get it from here.
|
|
|
|
The glyph is hidden until you point at it, which is what the system
|
|
does — the colour is the affordance, the cross is the confirmation.
|
|
------------------------------------------------------------------ */
|
|
/* The two numbers that decide whether it looks like a Mac window or like
|
|
a web page pretending to be one. Kept as variables because they are the
|
|
thing most likely to want a nudge, and nothing else should hardcode them.
|
|
|
|
Measured against a real title bar: the dot sits closer to the corner
|
|
than its own width, which is what makes it read as part of the frame
|
|
rather than as a control placed inside the content. */
|
|
.bwfa-scope {
|
|
--traffic-size: 14px;
|
|
--traffic-inset: 18px;
|
|
/* Clear air between the traffic light and the title. Roughly a
|
|
centimetre on a laptop screen, which is what it takes to stop the
|
|
heading reading as a label attached to the button. */
|
|
--traffic-gap: 40px;
|
|
}
|
|
|
|
.bwfa-scope .modal-close {
|
|
position: absolute;
|
|
top: var(--traffic-inset);
|
|
left: var(--traffic-inset);
|
|
right: auto;
|
|
width: var(--traffic-size);
|
|
height: var(--traffic-size);
|
|
min-width: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-sizing: border-box;
|
|
/* An inset shadow rather than a border, so the edge can't add to the
|
|
12px the system uses. */
|
|
border: 0;
|
|
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.16);
|
|
border-radius: 50%;
|
|
background-color: #ff5f57;
|
|
color: transparent;
|
|
font-size: 11px;
|
|
line-height: 1;
|
|
cursor: default;
|
|
opacity: 1;
|
|
flex: none;
|
|
z-index: 2;
|
|
}
|
|
|
|
.bwfa-scope .modal-close:hover {
|
|
background-color: #ff5f57;
|
|
color: rgba(0, 0, 0, 0.55);
|
|
}
|
|
|
|
.bwfa-scope .modal-close:active {
|
|
background-color: #bf4943;
|
|
}
|
|
|
|
/* Room for it, on the side it is now on. */
|
|
/* An earlier round's version of this rule. The unified header block below
|
|
owns the padding now; leaving this here set a second, smaller padding-top
|
|
on four of the six headers. */
|
|
|
|
/* The close button is positioned against its dialog, so every dialog has
|
|
to be something to position against. Without this it anchors to the
|
|
overlay instead and lands off the corner of the panel entirely, which
|
|
is why the Sound Report looked like it had no close button at all. */
|
|
.bwfa-scope .modal-dialog {
|
|
position: relative;
|
|
}
|
|
|
|
|
|
/* The Sound Report was the odd one out: 760px against the wide sheets'
|
|
1120px, so the same three columns of fields sat in a narrower box and
|
|
the whole modal read as a different piece of furniture. */
|
|
|
|
|
|
/* ====================================================================
|
|
One modal, six times over
|
|
--------------------------------------------------------------------
|
|
These grew one at a time and it showed: three had a rule under the
|
|
heading and three didn't, the titles came in three sizes, the widths
|
|
ran from 660 to 1120, and the traffic light sat anywhere from level
|
|
with the title to a centimetre above it. Nothing below is new design,
|
|
it is the same design applied to all of them.
|
|
|
|
The rules, and there are only four:
|
|
1. One width. Two values, and a modal picks one deliberately.
|
|
2. A header block: title, optional single line under it, always a
|
|
rule beneath, always the same room above for the traffic light.
|
|
3. A body with one padding.
|
|
4. A footer, when there are actions, always ruled and right-aligned.
|
|
==================================================================== */
|
|
.bwfa-scope {
|
|
--modal-width: 1120px;
|
|
/* Wide enough to clear the traffic light, so the title starts to the
|
|
right of it rather than against it — and because everything else in
|
|
the dialog uses the same gutter, the title, the fields and the
|
|
buttons all line up on one edge. */
|
|
--modal-pad: 42px;
|
|
}
|
|
|
|
/* Rule 5, which the export report already followed and the rest didn't:
|
|
the heading and the buttons stay put and the middle scrolls. A dialog
|
|
that scrolls as a whole makes you hunt for the button that dismisses
|
|
it, and one that doesn't scroll at all simply loses its bottom half —
|
|
which is what the Sound Report was doing with 26 fields in it. */
|
|
.bwfa-scope .modal-dialog {
|
|
width: min(var(--modal-width), 92vw);
|
|
max-width: min(var(--modal-width), 92vw);
|
|
max-height: 88vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.bwfa-scope .modal-header,
|
|
.bwfa-scope .bwfa-bulk-edit-header,
|
|
.bwfa-scope .bwfa-spectro-head,
|
|
.bwfa-scope .modal-footer,
|
|
.bwfa-scope .bwfa-bulk-edit-actions {
|
|
flex: none;
|
|
}
|
|
|
|
.bwfa-scope .modal-body,
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-export-fields,
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-bulk-edit-fields,
|
|
.bwfa-scope .bwfa-spectro-dialog .bwfa-spectro-canvas {
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* Inside a dialog, a panel gives up its own card: the dialog is the card.
|
|
Leaving it its background, border and rounded corners is what produced a
|
|
second box inside the first, visible as a stray strip below the footer.
|
|
The padding rule that used to carry this went when the padding did. */
|
|
.bwfa-scope .modal-dialog .bwfa-bulk-edit-panel,
|
|
.bwfa-scope .modal-dialog .bwfa-result-panel,
|
|
.bwfa-scope .modal-dialog .bwfa-export-panel {
|
|
background: none;
|
|
border: 0;
|
|
border-radius: 0;
|
|
box-shadow: none;
|
|
margin: 0;
|
|
}
|
|
|
|
/* The panels inside the sheets are the flex column, not the dialog. */
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-bulk-edit-panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 0;
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
/* One width, no exceptions. Export Files is a shorter form than the rest
|
|
and there was a case for narrowing it, but a set of dialogs that open at
|
|
the same size reads as one application and a set that doesn't reads as
|
|
several. The consistency is worth more than the tighter box. */
|
|
|
|
/* ---- 2. The header ---- */
|
|
.bwfa-scope .modal-header,
|
|
.bwfa-scope .bwfa-bulk-edit-header,
|
|
.bwfa-scope .bwfa-spectro-head {
|
|
display: block;
|
|
margin: 0;
|
|
padding: calc(var(--traffic-inset) + var(--traffic-size) + var(--traffic-gap))
|
|
var(--modal-pad) var(--space-4);
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
/* Descendants, not direct children. Sound Report and File metadata wrap
|
|
their title in a .bwfa-modal-title-group so it can sit beside the close
|
|
button; Bulk Edit and Export put the heading straight in the header. A
|
|
`>` matched the second pair and silently missed the first, which is the
|
|
whole reason Sound Report kept a different title size after every other
|
|
difference had been dealt with. */
|
|
.bwfa-scope .modal-header h3,
|
|
.bwfa-scope .modal-header h4,
|
|
.bwfa-scope .modal-header .modal-title,
|
|
.bwfa-scope .bwfa-columns-dialog .modal-title,
|
|
.bwfa-scope .bwfa-bulk-edit-header h4,
|
|
.bwfa-scope .bwfa-spectro-head h4 {
|
|
margin: 0;
|
|
font-size: var(--fs-xl, 20px);
|
|
font-weight: var(--fw-semibold);
|
|
line-height: 1.25;
|
|
}
|
|
|
|
/* One line under the title, and only one: everything else these panels
|
|
wanted to say has been folded into it or into a hint. */
|
|
.bwfa-scope .modal-header p,
|
|
.bwfa-scope .bwfa-bulk-edit-header p,
|
|
.bwfa-scope .bwfa-spectro-head p,
|
|
.bwfa-scope .modal-header .bwfa-modal-filename,
|
|
.bwfa-scope .bwfa-bulk-edit-header .bwfa-bulk-edit-hint {
|
|
display: block;
|
|
margin: 3px 0 0;
|
|
font-size: var(--fs-sm);
|
|
line-height: 1.45;
|
|
color: var(--color-text-muted);
|
|
}
|
|
|
|
/* ---- 3. The body ---- */
|
|
.bwfa-scope .modal-body,
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-export-fields,
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-bulk-edit-fields {
|
|
padding: var(--modal-pad);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-sheet-dialog .bwfa-bulk-edit-panel,
|
|
.bwfa-scope .bwfa-spectro-dialog {
|
|
padding: 0;
|
|
}
|
|
|
|
/* ---- 4. The footer ---- */
|
|
.bwfa-scope .modal-footer,
|
|
.bwfa-scope .bwfa-bulk-edit-actions {
|
|
margin: 0;
|
|
padding: var(--space-4) var(--modal-pad);
|
|
border-top: 1px solid var(--color-border);
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
/* Anything the panels put between the body and the footer sits in the
|
|
body's gutter, not against the edge of the dialog. */
|
|
/* Whatever a panel puts between the body and the footer sits in the body's
|
|
gutter, not against the edge of the dialog — and keeps its distance from
|
|
the footer's rule. Without the bottom margin the last block butts against
|
|
that line, which reads as two rules with the content trapped between. */
|
|
.bwfa-scope .bwfa-export-summary-line,
|
|
.bwfa-scope .bwfa-export-names,
|
|
.bwfa-scope .bwfa-bulk-tracks,
|
|
.bwfa-scope .bwfa-export-report {
|
|
margin-left: var(--modal-pad);
|
|
margin-right: var(--modal-pad);
|
|
margin-bottom: var(--space-5);
|
|
}
|
|
|
|
|
|
/* The wrapper that lets a title sit beside the close button carries no
|
|
spacing of its own: the header owns the padding, for all of them. */
|
|
.bwfa-scope .bwfa-modal-title-group {
|
|
margin: 0;
|
|
padding: 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* ---- Stepping through the card -------------------------------------
|
|
The arrows were in the header, which pushed the title right and made
|
|
this the one modal whose heading didn't start on the shared gutter.
|
|
In the footer they have the empty space to themselves, and each one
|
|
can say which file it leads to.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .modal-footer .bwfa-modal-nav {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
/* Each group is only as wide as what it holds. The framework gives
|
|
.bwfa-modal-nav flex: 1 1 auto for the header it was written for, and
|
|
in the footer that made both groups grow to fill the row: the forward
|
|
arrow ended up stranded in the middle of the footer with its name, a
|
|
long way from the buttons it belongs beside, and the margin-left: auto
|
|
below could do nothing about it because there was no free space left
|
|
for it to absorb. */
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
/* Back sits hard left; forward sits against the buttons it precedes, with
|
|
its filename on the inside so each name is beside the arrow that leads
|
|
to it and the two groups read outward from the middle. */
|
|
.bwfa-scope .modal-footer .bwfa-modal-nav-back {
|
|
margin-right: 0;
|
|
}
|
|
|
|
/* All the free space goes here, so the forward arrow and the name of the file
|
|
it leads to sit against the buttons rather than floating in the middle. */
|
|
.bwfa-scope .modal-footer .bwfa-modal-nav-on {
|
|
margin-left: auto;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-modal-nav-name {
|
|
font-size: var(--fs-sm);
|
|
color: var(--color-text-muted);
|
|
max-width: 14em;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* A name with no file to name takes no room. */
|
|
.bwfa-scope .bwfa-modal-nav-name:empty {
|
|
display: none;
|
|
}
|
|
|
|
|
|
/* Play becomes Pause, which is a wider word: without a floor the button
|
|
changes size the moment you press it and the row shuffles under the
|
|
cursor. Sized for the longer of the two. */
|
|
.bwfa-scope [data-bwfa-modal-play],
|
|
.bwfa-scope [data-bwfa-player-playpause] {
|
|
min-width: 5.5em;
|
|
}
|
|
|
|
/* The detail modal puts focus on its close button as it opens, which drew
|
|
the framework's black focus ring around the traffic light — on that one
|
|
modal only, since it's the only one that focuses anything. No ring on
|
|
focus. Keyboard users still get one, in the button's own red rather than
|
|
a black box, so it reads as part of the control instead of around it. */
|
|
.bwfa-scope .modal-close:focus {
|
|
outline: none;
|
|
box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.16);
|
|
}
|
|
|
|
.bwfa-scope .modal-close:focus-visible {
|
|
outline: 2px solid rgba(255, 95, 87, 0.55);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* ---- the mixer ---------------------------------------------------
|
|
One row per track: name, fader, level, mute, solo. Horizontal rather
|
|
than a wall of vertical faders, because track names here are words
|
|
like "Boom" and "Lav Sarah" and they need room to be read.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-mixer-strips {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
/* Room for the scale, which hangs above the first meter. */
|
|
padding-top: 1.1em;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-strip {
|
|
display: grid;
|
|
grid-template-columns: 9em minmax(0, 1.5fr) minmax(0, 1fr) 4.5em auto auto;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
/* The meter's cell. The scale goes inside it rather than in a row of its own:
|
|
a second grid, however carefully its columns are copied, resolves its fr
|
|
units from its own contents and lands the marks somewhere else entirely. */
|
|
.bwfa-scope .bwfa-mixer-meter-cell {
|
|
position: relative;
|
|
display: block;
|
|
min-width: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-fader {
|
|
width: 100%;
|
|
margin: 0;
|
|
accent-color: var(--color-action);
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-db {
|
|
font-variant-numeric: tabular-nums;
|
|
text-align: right;
|
|
color: var(--text-muted, #8a8a8e);
|
|
font-size: 0.86em;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-mute,
|
|
.bwfa-scope .bwfa-mixer-solo {
|
|
/* .chip's padding is 0.85rem on the left and 0.5rem on the right — fine
|
|
under a word, visibly lopsided under a single letter. Zero it and let
|
|
flex do the centring, with the line box collapsed so the glyph sits on
|
|
the middle rather than on its own baseline. */
|
|
flex: none;
|
|
width: 28px;
|
|
min-width: 28px;
|
|
height: 28px;
|
|
padding: 0;
|
|
gap: 0;
|
|
border-radius: 50%;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
line-height: 1;
|
|
font-variant-numeric: normal;
|
|
text-align: center;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-mute.is-muted,
|
|
.bwfa-scope .bwfa-mixer-solo.is-soloed {
|
|
background: var(--color-action);
|
|
border-color: var(--color-action);
|
|
color: #fff;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-transport {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
margin-top: var(--space-4);
|
|
padding-top: var(--space-4);
|
|
border-top: 1px solid var(--border, rgba(128, 128, 128, 0.25));
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-transport .btn,
|
|
.bwfa-scope .bwfa-player-playpause {
|
|
min-width: 6em;
|
|
}
|
|
|
|
/* The word inside the transport button is not a target. It is rewritten as
|
|
playback runs, and a node that changes under the pointer between mousedown
|
|
and mouseup takes the click with it. */
|
|
.bwfa-scope .bwfa-btn-label {
|
|
pointer-events: none;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-note,
|
|
.bwfa-scope .bwfa-mixer-empty {
|
|
margin: var(--space-3) 0 0;
|
|
font-size: 0.85em;
|
|
color: var(--text-muted, #8a8a8e);
|
|
}
|
|
|
|
/* ---- the meters --------------------------------------------------
|
|
Pre-fader peak, so the bar says what is on the track rather than what
|
|
you have done to it: mute a channel and it carries on reading.
|
|
------------------------------------------------------------------ */
|
|
.bwfa-scope .bwfa-mixer-meter {
|
|
position: relative;
|
|
display: block;
|
|
width: 100%;
|
|
height: 14px;
|
|
border-radius: 3px;
|
|
border: 1px solid var(--color-border);
|
|
overflow: hidden;
|
|
/* The scale's own colours, fixed to position: green until about -18, amber
|
|
through the last few dB, red at the top. Stops are placed where those
|
|
levels actually fall on a -60 to 0 scale, so the colour under the end of
|
|
the bar means the same thing every time. */
|
|
background: linear-gradient(
|
|
to right,
|
|
#1e7d3a 0%,
|
|
#3aa757 55%,
|
|
#7dbb3f 70%,
|
|
#e0b13c 85%,
|
|
#e07a2f 93%,
|
|
#c62828 100%
|
|
);
|
|
}
|
|
|
|
/* Covers the part of the scale that isn't lit. Moving this rather than
|
|
growing a coloured bar is what keeps each colour tied to its level. */
|
|
.bwfa-scope .bwfa-mixer-meter-mask {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
background: var(--color-surface-alt);
|
|
}
|
|
|
|
/* The highest peak of the last moment or so, left behind as a mark. This is
|
|
the part you actually read when something clipped a second ago. */
|
|
.bwfa-scope .bwfa-mixer-meter-hold {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 2px;
|
|
margin-left: -1px;
|
|
background: var(--color-text);
|
|
opacity: 0;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-meter.is-hot .bwfa-mixer-meter-hold {
|
|
background: #fff;
|
|
box-shadow: 0 0 0 1px #c62828;
|
|
}
|
|
|
|
/* The scale, on the strips' own grid so the marks sit over the meters. */
|
|
.bwfa-scope .bwfa-mixer-scale {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: calc(100% + 3px);
|
|
height: 1em;
|
|
display: block;
|
|
}
|
|
|
|
.bwfa-scope .bwfa-mixer-scale span {
|
|
position: absolute;
|
|
top: 0;
|
|
transform: translateX(-50%);
|
|
font-size: 9px;
|
|
line-height: 1;
|
|
color: var(--color-text-muted);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|