/* Tone Lab proposed components: forms, notices, the status line, dialogs, menus, tables and empty states. Light theme only.
   None of this is in design/guidelines.md yet, so each part is marked Proposed. They are drawn from the controls' parts: 32 px
   heights, 1 px --ctl-line borders, square corners and the 2 px ink focus outline from base.css.
   Colour means signal kind, so nothing here adds one: errors and emphasis use ink weight and rules, never red.
   Link after tokens.css, base.css and controls.css (and rack.css or site.css). */

/* Proposed: not in guidelines.md yet */
/* ---------- text inputs: text, email, password, search and number, and textarea ---------- */
.input {
  height: 32px;
  max-width: 100%;
  padding: 0 10px;
  border: 1px solid var(--ctl-line);
  border-radius: 0;
  background: var(--surface);
  color: var(--ink);
  font: 500 13px/1 var(--font-ui);
  appearance: none;
  -webkit-appearance: none;
}
.input:hover { border-color: var(--ink); }
.input::placeholder { color: var(--muted); opacity: 1; }
.input:disabled, .input:disabled:hover { border-color: var(--disabled-line); background: var(--surface); color: var(--disabled-text); }
.input[type="number"] { font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
.input[type="number"]::-webkit-outer-spin-button, .input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
textarea.input { height: auto; min-height: 80px; padding: 8px 10px; line-height: 1.4; resize: vertical; }

/* Proposed: not in guidelines.md yet */
/* ---------- forms: a stack of rows, each a label above its field, then a hint or an error ---------- */
.form { display: grid; gap: 16px; max-width: 400px; }
.form fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.form-row { display: grid; gap: 4px; justify-items: start; }
.form-row > :is(.input, .sel) { width: 100%; }
.form-row > label, .form legend { padding: 0; color: var(--ink); font: 500 12px/1.3 var(--font-ui); }
.form fieldset .form-row { margin-top: 4px; }
/* Not .hint: rack.css has that for the key help under the rack. */
.form-hint { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.4; }
/* Ink and a second pixel of border, not red. Set aria-invalid="true" on the field, or .error on its row. */
.error .input, .input[aria-invalid="true"] { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.err { margin: 0; color: var(--ink); font: 600 12px/1.4 var(--font-ui); }
/* A plain mark, so the message reads as an error without colour. Screen readers skip it: the words say what is wrong. */
.err::before { content: "!"; content: "!" / ""; margin-right: 6px; }
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* Proposed: not in guidelines.md yet */
/* ---------- checkboxes and radios: 14 px squares, as round means an output jack ---------- */
.check, .radio { display: inline-flex; align-items: center; gap: 8px; color: var(--text); font: 500 13px/1.3 var(--font-ui); cursor: pointer; }
:is(.check, .radio) input {
  flex: none;
  width: 14px;
  height: 14px;
  margin: 0;
  border: 1px solid var(--ctl-line);
  border-radius: 0;
  background: var(--surface);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}
:is(.check, .radio) input:hover { border-color: var(--ink); }
/* Checked fills --set: a value you chose. A radio keeps a white ring inside, so a group of them doesn't read as checkboxes. */
:is(.check, .radio) input:checked { border-color: var(--set); background: var(--set); }
.radio input:checked { box-shadow: inset 0 0 0 2px var(--surface); }
:is(.check, .radio):has(input:disabled) { color: var(--disabled-text); cursor: default; }
:is(.check, .radio) input:disabled { border-color: var(--disabled-line); background: var(--surface); box-shadow: none; cursor: default; }
/* No on/off switch: use a segmented switch (.seg in controls.css) with Off and On, which shows both states and the chosen one. */

/* Proposed: not in guidelines.md yet */
/* ---------- notices: an inline message in a ruled box with an ink bar. Say what kind it is in words ("Saved offline.", "Couldn't load.") ---------- */
.notice { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 8px 12px 8px 14px; background: var(--surface); box-shadow: inset 2px 0 0 var(--ink), inset 0 0 0 1px var(--line); color: var(--text); font-size: 13px; line-height: 1.4; }
.notice > p { flex: 1 1 240px; margin: 0; }
.notice b { color: var(--ink); font-weight: 600; }

/* Proposed: not in guidelines.md yet */
/* ---------- status line: autosave and the like, "Saved 14:02" or "Saving…" ---------- */
/* No --live square while saving. --live means sound is happening now (Play, the current step, the logo's beat), and autosave runs
   every few seconds while a patch plays, so a green square beside the transport would flicker on and off with nothing to hear.
   The words carry the state; a failed save goes ink and 600 weight like an error. */
.status { color: var(--muted); font: 500 12px/1.3 var(--font-ui); white-space: nowrap; font-variant-numeric: tabular-nums; }
.status.err { color: var(--ink); font-weight: 600; }
.status.err::before { margin-right: 4px; }

/* Proposed: not in guidelines.md yet */
/* ---------- dialogs, for <dialog>: square and ruled, no shadow. The page fades behind it ---------- */
.dialog { width: min(480px, calc(100vw - 32px)); max-height: calc(100vh - 32px); padding: 0; border: 1px solid var(--card-line); border-radius: 0; background: var(--surface); color: var(--text); }
.dialog::backdrop { background: color-mix(in srgb, var(--bg) 80%, transparent); }
.dialog-head { display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 8px 8px 8px 16px; border-bottom: 1px solid var(--line); }
.dialog-head h2 { flex: 1; color: var(--ink); font: 600 15px/1.3 var(--font-ui); }
.dialog-body { padding: 16px; line-height: 1.4; }
.dialog-body > * + * { margin-top: 8px; }
.dialog-body .form { max-width: none; }
.dialog .actions { justify-content: flex-end; padding: 12px 16px; border-top: 1px solid var(--line); }

/* Proposed: not in guidelines.md yet */
/* ---------- menus: a popover list of 28 px rows. Say a destructive item in words ("Delete card") and put it last, after a rule ---------- */
/* No display here: it would override the popover's own display: none and leave the menu open. */
.menu { width: max-content; min-width: 160px; margin: 0; padding: 4px 0; border: 1px solid var(--ctl-line); border-radius: 0; background: var(--surface); color: var(--ink); font: 500 13px/1 var(--font-ui); }
.menu > :is(button, a) {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 28px;
  padding: 0 12px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.menu > :is(button, a):hover { background: var(--well); }
.menu > :is(button, a):focus-visible { outline-offset: -2px; }
.menu > :is(:disabled, [aria-disabled="true"]), .menu > :is(:disabled, [aria-disabled="true"]):hover { background: none; color: var(--disabled-text); cursor: default; }
.menu kbd { margin-left: auto; }
.menu hr { height: 0; margin: 4px 0; border: 0; border-top: 1px solid var(--line); }

/* Proposed: not in guidelines.md yet */
/* ---------- tables: ruled data with tabular figures. Wrap in .table-scroll where it may be wider than the screen ---------- */
/* Positioned, so an absolute child such as a .sr-only header is clipped here rather than widening the page. */
.table-scroll { position: relative; max-width: 100%; overflow-x: auto; }
.table { width: 100%; border: 1px solid var(--line); border-collapse: collapse; background: var(--surface); color: var(--text); font: 13px/1.3 var(--font-ui); font-variant-numeric: tabular-nums; }
.table :is(th, td) { height: 32px; padding: 6px 12px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; }
.table thead th { color: var(--muted); font-weight: 500; white-space: nowrap; }
.table tbody th { color: var(--ink); font-weight: 600; }
.table tbody tr:hover { background: var(--well); }
.table .num { text-align: right; }
/* A row's own actions, such as its menu button, in the last cell. A 24 px button keeps the row 32 px high. */
.table .act { width: 1%; padding: 4px 8px; text-align: right; }
.table .act .btn.sq { width: 24px; height: 24px; }
/* In a scroller, rows keep to one line and the table scrolls, rather than squeezing a date onto four lines. */
.table-scroll .table :is(th, td) { white-space: nowrap; }
/* The row names stay put while the other columns scroll under them, so a row still says what it is on a phone. */
.table-scroll .table tr { background: var(--surface); }
.table-scroll .table :is(thead th:first-child, tbody th) { position: sticky; left: 0; z-index: 1; background: inherit; }

/* Proposed: not in guidelines.md yet */
/* ---------- empty state: a short heading, one muted line and one button ---------- */
.empty { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: 32px 24px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
/* h2 or h3, whichever the page's outline needs. */
.empty :is(h2, h3) { color: var(--ink); font: 600 15px/1.3 var(--font-ui); }
.empty p { margin: 0; color: var(--muted); }
.empty .btn { margin-top: 8px; }

/* Proposed: not in guidelines.md yet */
/* ---------- filter bar: a switch, a search field and a count, above the list they filter ---------- */
.filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-bottom: 16px; }
/* At the top bar's 32 px, beside the search field, rather than a card's 24. */
.filters .seg button { height: 32px; padding: 0 10px; font-size: 13px; }
.filters .input[type="search"] { flex: 0 1 240px; min-width: 0; }
.filters .status { margin-left: auto; }
/* So six choices still fit a phone. */
@media (max-width: 760px) { .filters .seg button { padding: 0 8px; font-size: 12px; } }
