/* ==========================================================================
   NokoNoko.ru — машина песен.  Machine panel, dark only.

   Every colour, type role, radius, spacing step and rule below comes from
   DESIGN.md. There is no step row and no grid of lightable cells in this file.
   ========================================================================== */

:root {
    color-scheme: dark;

    /* --- hardware (DESIGN.md) ---------------------------------------------- */
    --ground: #0e0e0e;
    --panel: #1a1a1a;
    --panel-raised: #202020;
    --well: #121212;
    --hairline: #2e2e2e;
    --key-off: #242424;
    --key-off-edge: #303030;
    --key-ink: #141414;
    /* Ember, not pink-red: failure is the one warm colour on the panel that is
     neither a lamp nor a level — it sits between the step orange and the
     charcoal instead of fighting the candy set. */
    --danger-ink: #ff7a45;
    --well-edge: #000;
    --inset-shade: rgba(0, 0, 0, .9);

    /* --- candy values: keys, lamps and section swatches -------------------- */
    --step-red: #ff3b30;
    --step-orange: #ff9a00;
    --step-yellow: #ffe100;
    --step-green: #34c759;
    --step-white: #f2f2f2;
    --s0-mid: #aaaaaa;
    /* the four section swatches, one fixed level each */
    --s1-mid: #b2700d;
    --s2-mid: #b2332c;
    --s3-mid: #b29f0d;

    /* --- silkscreen and prose ---------------------------------------------- */
    --silkscreen: #bdbdbd;
    --silkscreen-dim: #6e6e6e;
    --letter: #e6e6e6;

    /* --- typography (DESIGN.md) -------------------------------------------- */
    --font-plate: "Roboto Condensed", "Arial Narrow", "Liberation Sans Narrow", "DejaVu Sans Condensed", "Nimbus Sans Narrow", sans-serif;
    --font-readout: "DejaVu Sans Mono", "Liberation Mono", Consolas, Menlo, monospace;
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif;
    --fs-hero: clamp(2.1rem, 6.4vw, 4.25rem);
    --fs-lead: clamp(1rem, 1.5vw, 1.1875rem);
    --fs-heading: 0.8125rem;
    --fs-display: clamp(1.4rem, 2.6vw, 2.125rem);
    --fs-key: 0.8125rem;
    --fs-label: 0.6875rem;
    --fs-readout: 0.9375rem;
    --fs-body: 0.9375rem;
    --ls-label: 0.18em;

    /* --- radii -------------------------------------------------------------- */
    --r-key: 3px;
    --r-panel: 4px;
    --r-well: 3px;

    /* --- spacing ------------------------------------------------------------ */
    --hair: 4px;
    --xs: 8px;
    --sm: 12px;
    --md: 16px;
    --lg: 24px;
    --xl: 32px;

    /* --- machine frame ------------------------------------------------------ */
    --topbar-h: 60px;
    --transport-h: 96px;
    /* measured from the real transport on load and resize */
    --console-w: 300px;
    --detail-w: 344px;
    --seg-t: clamp(1.8px, 0.45vw, 3px);
    /* segment thickness: the whole readout derives from it */
}

/* ==========================================================================
   Base
   ========================================================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
}

[hidden] {
    display: none !important;
}

html,
body {
    height: 100%;
}

body {
    margin: 0;
    background: var(--ground);
    color: var(--letter);
    font-family: var(--font-body);
    font-size: var(--fs-body);
    line-height: 1.62;
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
}

.sprite {
    position: absolute;
}

h1,
h2,
h3,
h4,
p,
dl,
dd,
dt,
ol,
ul,
li,
figure {
    margin: 0;
    padding: 0;
}

ul,
ol {
    list-style: none;
}

button,
input,
textarea,
summary {
    font: inherit;
    color: inherit;
}

a {
    color: inherit;
    text-decoration: none;
}

:focus-visible {
    outline: 2px solid var(--step-red);
    outline-offset: 2px;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.icon {
    width: 20px;
    height: 20px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.icon--play,
.icon--pause {
    fill: currentColor;
    stroke-width: 1.5;
}

/* ==========================================================================
   Type roles
   ========================================================================== */

.legend {
    font-family: var(--font-plate);
    font-size: var(--fs-label);
    font-weight: 700;
    line-height: 1;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--silkscreen);
}

.legend--dim {
    color: var(--silkscreen-dim);
}

.legend--right {
    text-align: right;
}

.legend--section {
    margin-bottom: var(--xs);
    color: var(--silkscreen-dim);
}

.readout {
    font-family: var(--font-readout);
    font-size: var(--fs-readout);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.06em;
    font-variant-numeric: tabular-nums;
    color: var(--letter);
}

.readout--dim {
    color: var(--silkscreen-dim);
    font-size: 0.8125rem;
}

.note {
    font-size: 0.8125rem;
    line-height: 1.55;
    color: var(--silkscreen);
}

.note--dim {
    color: var(--silkscreen-dim);
}

.note--danger {
    color: var(--danger-ink);
}

.legend-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sm);
    margin-bottom: var(--xs);
}

/* ==========================================================================
   Shell
   ========================================================================== */

.app {
    display: grid;
    grid-template-rows: var(--topbar-h) minmax(0, 1fr) auto;
    height: 100dvh;
}

/* Grid items default to min-content: without this a nowrap readout anywhere in
   a band props the whole page open. */
.app>* {
    min-width: 0;
}

/* --- top bar ------------------------------------------------------------- */

.topbar {
    display: flex;
    align-items: center;
    gap: var(--md);
    padding: 0 var(--md);
    background: var(--panel);
    border-bottom: 1px solid var(--hairline);
}

.plate {
    display: flex;
    align-items: baseline;
    gap: var(--xs);
}

.plate__name {
    font-family: var(--font-plate);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--letter);
}

.plate__sub {
    color: var(--silkscreen-dim);
}

.banks {
    display: flex;
    align-items: stretch;
    gap: var(--hair);
    margin-left: var(--xs);
}

.bank {
    position: relative;
    /* The tab text stands on the bottom edge, where the active bank's underline is.
     The line box is squared to the type size first: the count beside the label is
     also a readout with its own line-height, and bottom alignment would otherwise
     leave the two on different baselines instead of one. The narrow layout
     overrides this (see the 620px block). */
    display: flex;
    align-items: flex-end;
    gap: var(--xs);
    line-height: 1;
    padding: var(--md) var(--sm) 0;
    height: var(--topbar-h);
    background: none;
    border: 0;
    cursor: pointer;
    font-family: var(--font-plate);
    font-size: var(--fs-key);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--silkscreen-dim);
    transition: color 100ms linear;
}

.bank:hover {
    color: var(--silkscreen);
}

.bank[aria-current="true"] {
    color: var(--letter);
}

.bank[aria-current="true"]::after {
    content: "";
    position: absolute;
    left: var(--sm);
    right: var(--sm);
    bottom: 0;
    height: 2px;
    background: var(--step-red);
    box-shadow: 0 0 8px rgba(255, 59, 48, 0.55);
}

/* The label and its count move together: the row is bottom-aligned, so padding
   under one alone would break the single baseline the two share (measured at 0px
   before this). Both carry the same inset — the tab text stands that far above
   the active tab's underline. */
.bank__label,
.bank__count {
    padding-bottom: var(--xs);
}

.bank__count {
    font-size: 0.8125rem;
    color: var(--silkscreen-dim);
}

/* The count is set in the readout face and the label in the plate face, and the
   two put the same 13px caps on baselines two pixels apart. The line box here is
   one em plus four pixels — half of that extra height lifts the readout onto the
   label's baseline, measured against the live page. */
.bank__count {
    line-height: calc(1em + 4px);
}

.bank[aria-current="true"] .bank__count {
    color: var(--silkscreen);
}

.status {
    display: flex;
    /* The lamp is 8px, the same height as the label's capitals, so putting its
     bottom edge on the label's baseline centres it on the capitals themselves.
     Centring on the line box instead sits it 1px low: at 11px the box is 8px
     ascent + 2px descent, and the capitals only occupy the ascent. */
    align-items: baseline;
    gap: var(--xs);
    margin-left: auto;
    padding-left: var(--md);
    border-left: 1px solid var(--hairline);
}

.status__text {
    color: var(--silkscreen);
}

.lamp {
    width: 8px;
    height: 8px;
    flex: none;
    border-radius: 50%;
    background: #262626;
    border: 1px solid #1b1b1b;
}

.lamp--on {
    background: var(--step-red);
    border-color: #7a1a14;
    box-shadow: 0 0 8px rgba(255, 59, 48, 0.6);
}

/* Failure lights ember, not the live red: the rim is danger-ink darkened the same
   way #7a1a14 darkens step-red. */
.lamp--fail {
    background: var(--danger-ink);
    border-color: #7a3a20;
    box-shadow: 0 0 8px rgba(255, 122, 69, 0.6);
}

.lamp--ready {
    background: var(--step-green);
    border-color: #1f8a3b;
    box-shadow: 0 0 8px rgba(52, 199, 89, 0.6);
}

.lamp--orange.is-lit {
    background: var(--step-orange);
    box-shadow: 0 0 6px rgba(255, 154, 0, 0.5);
}

.lamp--yellow.is-lit {
    background: var(--step-yellow);
    box-shadow: 0 0 6px rgba(255, 225, 0, 0.45);
}

.lamp--red.is-lit {
    background: var(--step-red);
    box-shadow: 0 0 6px rgba(255, 59, 48, 0.5);
}

/* --- body band ----------------------------------------------------------- */

.body {
    display: grid;
    grid-template-columns: var(--console-w) minmax(0, 1fr);
    min-height: 0;
}

.body>* {
    min-width: 0;
}

.body.is-detail {
    grid-template-columns: var(--console-w) minmax(0, 1fr) var(--detail-w);
}

/* --- keys ---------------------------------------------------------------- */

.key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--xs);
    min-height: 36px;
    padding: 0 var(--md);
    background: var(--key-off);
    border: 1px solid var(--key-off-edge);
    border-bottom-color: #151515;
    border-radius: var(--r-key);
    cursor: pointer;
    font-family: var(--font-plate);
    font-size: var(--fs-key);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--silkscreen);
    transition: background-color 100ms linear, color 100ms linear;
}

.key:hover {
    background: #2b2b2b;
    color: var(--letter);
}

.key:active {
    transform: translateY(1px);
    border-color: #141414;
    border-bottom-color: var(--key-off-edge);
}

.key--primary {
    min-height: 40px;
    padding: 0 var(--lg);
    background: var(--step-red);
    border-color: #ff5e54;
    border-bottom-color: #b3251f;
    color: var(--key-ink);
}

.key--primary:hover {
    background: #ff5147;
    color: var(--key-ink);
}

.key--quiet {
    color: var(--silkscreen);
}

.key--danger {
    color: var(--danger-ink);
}

.key:disabled {
    cursor: not-allowed;
    color: var(--silkscreen-dim);
}

.key--primary:disabled,
.key--play:disabled {
    background: var(--key-off);
    border-color: var(--key-off-edge);
    border-bottom-color: #151515;
    color: var(--silkscreen-dim);
}

/* Готовое лицо — у клавиши, которую можно нажать. Селектор с id: лицо клавиши
   создания должно побеждать всё, что говорит о ней же, — иначе его перебивает
   случайное правило с тем же весом (проверено: с классовым селектором зелёный
   проигрывал серому .key). Одна форма на две клавиши: входная клавиша лендинга
   носит то же лицо, потому что это то же состояние — машина готова. */
#btn-create.key--ready,
.key--hero {
    background: var(--step-green);
    border-color: #5fd97a;
    border-bottom-color: #1f8a3b;
    color: var(--key-ink);
}

/* Готовая клавиша подаётся под курсором своим зелёным, а не красным hover’ом
   выше: он остался от красного лица и до этой клавиши уже не доходит. Нажатие
   снимает только 1px вниз: тёмная обводка .key:active — грань серой клавиши. */
#btn-create.key--ready:hover,
.key--hero:hover {
    background: #45d56a;
    color: var(--key-ink);
}

#btn-create.key--ready:active,
.key--hero:active {
    border-color: #5fd97a;
    border-bottom-color: #1f8a3b;
}

.key--primary.key--outline-danger {
    background: transparent;
    border-color: var(--danger-ink);
    border-bottom-color: var(--danger-ink);
    color: var(--danger-ink);
}

/* Пока идёт запись, клавиша выключена и носит серое лицо, а не зелёное: зелёный
   обещал бы нажатие, которого не будет. Обводка «сервер не отвечает» остаётся —
   это состояние машины, а не приглашение. */
#btn-create.key--ready:disabled {
    background: var(--key-off);
    border-color: var(--key-off-edge);
    border-bottom-color: #151515;
    color: var(--silkscreen-dim);
}

/* Лицо клавиши создания выше остальных клавиш панели, а нижняя грань затенена
   скосом: подпись держим ровно по середине бокса и без строчного интервала,
   иначе буквы читаются выше центра. */
#btn-create {
    align-items: center;
    justify-content: center;
    line-height: 1;
}

.key--play:disabled .key__word {
    color: var(--silkscreen-dim);
}

.key--icon {
    min-height: 30px;
    padding: 0 var(--xs);
}

.key--small {
    min-height: 30px;
    padding: 0 10px;
    font-size: 0.75rem;
}

/* Одна поправка на все клавиши с подписью — и обязательно после их правил
   выше: строчное выравнивание ставит по центру строку, а не сами буквы, и
   прописные без выносных (а подписи здесь все такие) читаются на два пикселя
   выше середины лица. Зазор равен 0.4em, потому что при центрировании он
   сдвигает содержимое только на половину. Клавиши транспорта исключены: у них
   своя композиция из значка и слова. */
.key--small,
.key--quiet,
#btn-create {
    padding-top: 0.4em;
}

.key--icon .icon {
    width: 16px;
    height: 16px;
}

.key--burger {
    display: none;
}

.key__badge {
    min-width: 20px;
    padding: 2px 4px;
    border-radius: 2px;
    background: var(--step-red);
    color: var(--key-ink);
    font-size: 0.75rem;
    text-align: center;
}

/* ==========================================================================
   Scrubber, structure, job progress

   A take's arrangement is reported as words with their section colours, and the
transport's position as one recessed trough under a fader-style handle. There is
tno grid of lightable cells anywhere in this interface.
   ========================================================================== */

.scrub {
    flex: 3 1 0;
    min-width: 0;
}

.trough {
    position: relative;
    display: flex;
    align-items: center;
    height: 22px;
    padding: 0 5px;
    background: var(--well);
    border: 1px solid var(--well-edge);
    border-radius: var(--r-well);
    box-shadow: inset 0 1px 0 var(--inset-shade);
}

.trough__fill {
    position: absolute;
    left: 5px;
    right: 5px;
    top: 50%;
    height: 6px;
    margin-top: -3px;
    background: var(--step-red);
    opacity: 0.5;
    border-radius: 2px;
    transform: scaleX(var(--p, 0));
    transform-origin: left center;
    pointer-events: none;
}

.fader.fader--scrub {
    position: relative;
    z-index: 1;
    width: 100%;
    height: 22px;
}

.fader.fader--scrub::-webkit-slider-runnable-track {
    height: 6px;
    background: none;
    box-shadow: none;
}

.fader.fader--scrub::-moz-range-track {
    height: 6px;
    background: none;
}

.fader.fader--scrub::-webkit-slider-thumb {
    margin-top: -6px;
}

.structure {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--hair) var(--xs);
    margin-bottom: var(--lg);
    max-width: 62ch;
    font-family: var(--font-plate);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--silkscreen);
}

.structure__part {
    display: flex;
    align-items: center;
    gap: 5px;
}

.structure__sep {
    color: var(--silkscreen-dim);
}

.structure__version {
    margin-right: var(--hair);
}

.structure__empty {
    color: var(--silkscreen-dim);
}

/* The job's own hairline: full row width for as long as the job runs — a live
   marker, not a progress fraction (G2). It is not there once the take is done. */
.take__progress {
    position: absolute;
    left: 0;
    bottom: -1px;
    height: 1px;
    width: 0;
    background: var(--step-red);
}

.take--queued .take__progress,
.take--processing .take__progress {
    width: 100%;
}

.take__hit {
    position: relative;
}

/* ==========================================================================
   Console — the drawn registration console
   ========================================================================== */

.console {
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto;
    min-height: 0;
    background: var(--panel);
    border-right: 1px solid var(--hairline);
}

.console__scroll {
    overflow-y: auto;
    padding: var(--md);
}

.group {
    margin-bottom: var(--lg);
}

/* Two keys on one line: the composer's own file pair stands side by side. */
.key-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
}

.well {
    background: var(--well);
    border: 1px solid var(--well-edge);
    border-top-color: var(--well-edge);
    border-radius: var(--r-well);
    box-shadow: inset 0 1px 0 var(--inset-shade);
}

.input {
    display: block;
    width: 100%;
    padding: 10px var(--sm);
    background: none;
    border: 0;
    outline: none;
    font-family: var(--font-body);
    font-size: var(--fs-body);
    line-height: 1.5;
    color: var(--letter);
}

.input::placeholder {
    color: #565656;
}

.input--area {
    resize: none;
    overflow: hidden;
    min-height: 132px;
}

.input--area-sm {
    min-height: 72px;
}

.input:focus-visible {
    outline: 2px solid var(--step-red);
    outline-offset: -2px;
}

.style-bank {
    display: block;
}

.style-controls {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    margin-top: var(--hair);
}

/* The brief takes a full row of its own: the action keys stay together below it. */
.style-controls .well {
    flex: 1 1 100%;
}

/* The lyric keys sit under the text, mirroring the style row's rhythm. */
.lyric-controls {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    margin-top: var(--hair);
}

/* The palette: one ruled strip per axis, the silkscreen word on its summary. */
.palette {
    border-top: 1px solid var(--hairline);
}

.palette__head {
    display: flex;
    align-items: center;
    gap: var(--xs);
    padding: var(--xs) 0;
    cursor: pointer;
    list-style: none;
}

.palette__head::-webkit-details-marker {
    display: none;
}

.palette__head .readout {
    margin-left: auto;
}

.palette__chevron {
    width: 8px;
    height: 8px;
    border-right: 1.5px solid var(--silkscreen-dim);
    border-bottom: 1.5px solid var(--silkscreen-dim);
    transform: rotate(45deg) translate(-2px, -2px);
}

.palette[open] .palette__chevron {
    transform: rotate(-135deg) translate(-2px, -2px);
}

.palette__keys {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    padding-bottom: var(--hair);
}

.stylekey {
    /* Ключ палитры — элемент flex-строки: ряд вытягивает его по самой высокой
     клавише, и без собственного выравнивания подпись осталась бы у верхней
     кромки вытянутого бокса. Коробка строки сжата до кегля, а сверху добавлен
     зазор: строчное выравнивание ставит по центру строку, а не сами буквы, и
     без него прописные без выносных читаются на два пикселя выше середины. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    min-height: 30px;
    padding: 0.4em 10px 0;
    background: var(--key-off);
    border: 1px solid var(--key-off-edge);
    border-bottom-color: #151515;
    border-radius: var(--r-key);
    cursor: pointer;
    font-family: var(--font-plate);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--silkscreen);
    transition: background-color 90ms linear, color 90ms linear;
}

.stylekey:hover {
    background: #2b2b2b;
    color: var(--letter);
}

.stylekey[aria-pressed="true"] {
    background: var(--step-white);
    border-color: #ffffff;
    border-bottom-color: #b9b9b9;
    color: var(--key-ink);
}

/* The library: ruled rows, the listener's own always in sight, the built-in
   catalogue under a fold of its own — the palette's head, the palette's
   chevron, so a fold looks like a fold on this panel.
   An apply row is the hit area; the rename/delete keys are the sprite's, like
   every other icon key on the panel. */
.presets {
    margin-top: var(--xs);
    border-top: 1px solid var(--hairline);
    padding-top: var(--xs);
}

.presets__list {
    margin-top: var(--hair);
}

.presets__fold {
    border-top: 1px solid var(--hairline);
}

.presets__fold .presets__list {
    margin-top: 0;
}

.preset {
    display: flex;
    align-items: center;
    gap: var(--hair);
    border-bottom: 1px solid var(--hairline);
}

.preset__apply {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: var(--xs);
    min-height: 34px;
    padding: 6px var(--sm) 6px var(--xs);
    background: var(--panel-raised);
    border: 0;
    border-left: 2px solid transparent;
    cursor: pointer;
    text-align: left;
    transition: background-color 90ms linear;
}

.preset__apply:hover {
    background: #262626;
}

.preset__name {
    min-width: 0;
    font-family: var(--font-plate);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--silkscreen);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.preset__apply:hover .preset__name {
    color: var(--letter);
}

.preset__origin {
    flex: none;
    margin-left: auto;
}

.preset__key {
    min-height: 28px;
}

.preset__key.is-armed {
    color: var(--danger-ink);
}

.preset__well {
    flex: 1 1 auto;
}

.preset__input {
    min-height: 32px;
    padding: 5px var(--xs);
    font-size: 0.8125rem;
}

.console__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    padding: var(--sm) var(--md);
    background: var(--panel);
    border-top: 1px solid var(--hairline);
}

.console__actions .note {
    flex: 1 1 100%;
}

.console__actions .key--primary {
    flex: 1 1 auto;
}

/* ==========================================================================
   Board — the bank of takes
   ========================================================================== */

.board {
    /* The row grid's columns live here, on the board: the header labels and the
     take rows are siblings, and both must read the same variables. */
    --take-num: 36px;
    --take-play: 32px;
    --take-len: 56px;
    --take-status: 92px;
    --take-edge: 56px;
    --take-gap: var(--md);
    min-height: 0;
    overflow-y: auto;
    padding: var(--md) var(--lg) var(--lg);
    background: var(--ground);
}

.board__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--md);
    padding-bottom: var(--xs);
    border-bottom: 1px solid var(--hairline);
}

.board__head .legend {
    font-size: 0.8125rem;
    color: var(--letter);
}

.swatch {
    width: 10px;
    height: 10px;
    border-radius: 2px;
    background: var(--c);
    border: 1px solid #141414;
}

.swatch--s0 {
    --c: var(--s0-mid);
}

.swatch--s1 {
    --c: var(--s1-mid);
}

.swatch--s2 {
    --c: var(--s2-mid);
}

.swatch--s3 {
    --c: var(--s3-mid);
}

/* One row of the bank is a grid that the row and its header labels share. Every
   column is a variable (see .board) because the row's own keys are absolutely
   placed and must sit on those same lines: number, name, the play key's cell,
   length, status, and the strip at the right edge that holds the save key.
   Cells are placed explicitly, so a hidden column — the length on a narrow
   screen — cannot shift the ones after it. */
.take {
    position: relative;
    border-bottom: 1px solid var(--hairline);
}

.board__labels,
.take__hit {
    display: grid;
    grid-template-columns: var(--take-num) minmax(0, 1fr) var(--take-play) var(--take-len) var(--take-status);
    align-items: center;
    gap: var(--take-gap);
}

/* 56px on the right = 12px edge + the 32px save key + a 12px gap to the status
   column, so the key never sits on top of the status word. */
.board__labels {
    padding: var(--xs) var(--take-edge) var(--xs) var(--sm);
}

.board__labels .legend:nth-child(4),
.board__labels .legend:nth-child(5) {
    text-align: right;
}

.take__num {
    grid-column: 1;
}

.take__name {
    grid-column: 2;
}

.take__play-slot {
    grid-column: 3;
}

.take__len {
    grid-column: 4;
}

.take__status {
    grid-column: 5;
}

.take__hit {
    width: 100%;
    padding: var(--sm) var(--take-edge) var(--sm) var(--sm);
    background: var(--panel-raised);
    border: 0;
    border-left: 2px solid transparent;
    cursor: pointer;
    text-align: left;
    transition: background-color 90ms linear;
}

.take__hit:hover {
    background: #262626;
}

.take.is-open .take__hit {
    border-left-color: var(--silkscreen-dim);
    background: #262626;
}

.take.is-playing .take__hit {
    border-left-color: var(--step-red);
}

/* Пока идёт запись, состояние говорит со своей строки: не в одну линию с
   клавишей, а над ней — та же доля ширины, что у поля заявки в палитре. */
.console__actions #create-busy {
    flex: 1 1 100%;
}

/* A field the request is carrying stops taking edits: it cannot change what has
   already been sent, so the caret turns into a plain pointer instead of promising
   an edit that will not count. */
.input[readonly] {
    cursor: default;
}

/* A well waiting on the model: the content fades and the well lights the same 1px
   line a running take carries along its bottom edge. Nothing spins and nothing
   blinks —
   see DESIGN.md — the lit line and the word beside the pressed key say «working»
   in the panel's own vocabulary, and prefers-reduced-motion needs no special case. */
.well.is-busy {
    position: relative;
}

.well.is-busy .input {
    opacity: 0.4;
}

.well.is-busy::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: var(--step-red);
    box-shadow: 0 0 8px rgba(255, 59, 48, 0.55);
}

.legend.legend--busy {
    color: var(--step-red);
}

/* Ключи палитры и наборы — тоже клавиши композитора: пока идёт запись, они
   выключены и видно, что выключены (у .key это делает :disabled). */
.stylekey:disabled,
.preset__apply:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Пока идёт запись, ключи палитры и наборы не пишут в поля: гасим их классом на
   консоли, а не поштучно — они перерисовываются заново и родились бы включёнными
   (занятость проверяет и сам обработчик, см. creating() в app.js). */
.console.is-writing .stylekey,
.console.is-writing .preset__apply {
    opacity: 0.4;
    pointer-events: none;
    cursor: not-allowed;
}

/* The row's play key and the save key are both siblings of the hit — a button inside
   a button is not a button — and both are placed on the grid above: the play key
   covers its own cell between the name and the length, the save key the strip at
   the right edge. */
.take__play {
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    right: calc(var(--take-edge) + var(--take-status) + var(--take-len) + var(--take-gap) * 2);
    width: var(--take-play);
    height: 30px;
}

.take__key {
    position: absolute;
    top: 0;
    bottom: 0;
    right: var(--sm);
    width: 32px;
    height: 30px;
    margin: auto;
}

.take__num {
    display: flex;
    align-items: center;
    gap: var(--xs);
    color: var(--silkscreen-dim);
}

.take.is-playing .take__num {
    color: var(--step-red);
}

.take__lamp {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #2c2c2c;
}

.take.is-playing .take__lamp {
    background: var(--step-red);
    box-shadow: 0 0 7px rgba(255, 59, 48, 0.6);
}

.take__name {
    min-width: 0;
}

.take__title {
    display: block;
    font-family: var(--font-plate);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--letter);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The version and the styles share the row's second line: the version keeps its
   width, the styles take what is left and truncate. */
.take__meta {
    display: flex;
    align-items: baseline;
    min-width: 0;
    margin-top: 3px;
}

.take__version {
    flex: none;
    margin-right: var(--xs);
}

.take__styles {
    flex: 0 1 auto;
    min-width: 0;
    font-family: var(--font-plate);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--silkscreen-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.take__len {
    text-align: right;
    color: var(--silkscreen);
}

.take__status {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
}

.take__status .legend {
    color: var(--silkscreen);
}

.take--queued .take__status .legend,
.take--processing .take__status .legend {
    color: var(--step-red);
}

.take--error .take__status .legend {
    color: var(--danger-ink);
}

.take--canceled .take__status .legend,
.take--expired .take__status .legend {
    color: var(--silkscreen-dim);
}

.board__note {
    margin-top: var(--md);
    max-width: 62ch;
}

.empty {
    padding: var(--xl) 0;
    max-width: 44ch;
}

.empty__line {
    font-family: var(--font-plate);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--silkscreen);
}

.group__hint {
    margin-top: var(--hair);
    font-size: 0.75rem;
}

/* ==========================================================================
   Detail — the take's proof
   ========================================================================== */

.detail {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    min-height: 0;
    background: var(--panel);
    border-left: 1px solid var(--hairline);
}

.detail__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sm);
    padding: var(--sm) var(--md);
    border-bottom: 1px solid var(--hairline);
}

.detail__scroll {
    overflow-y: auto;
    padding: var(--md);
}

.detail__title {
    font-family: var(--font-plate);
    font-size: var(--fs-display);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.01em;
    text-transform: uppercase;
    color: var(--letter);
    margin-bottom: var(--sm);
    overflow-wrap: anywhere;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    margin-bottom: var(--lg);
}

.chip {
    /* A chip is a sticker, so its label sits on the optical middle of the sticker:
     flex centring puts the line box in the middle (a stretched or taller chip
     would otherwise leave its word at the top edge), and the extra top inset,
     halved by that centring, lands the capitals themselves on the middle. */
    display: inline-flex;
    align-items: center;
    padding: 4px 8px;
    padding-top: calc(4px + 0.4em);
    background: var(--key-off);
    border: 1px solid var(--key-off-edge);
    border-radius: var(--r-key);
    font-family: var(--font-plate);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--silkscreen);
}

/* The label is its own box so a long style can still wrap inside the chip. */
.chip__text {
    min-width: 0;
}

.lyric {
    margin-bottom: var(--lg);
    max-width: 62ch;
}

.lyric__line {
    color: var(--silkscreen);
}

.lyric__line+.lyric__line {
    margin-top: 2px;
}

.lyric__line.is-tag {
    margin-top: var(--sm);
    font-family: var(--font-plate);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--silkscreen-dim);
}

#detail-structure {
    margin-bottom: var(--lg);
}

.detail__error {
    margin-top: var(--md);
    max-width: 62ch;
}

.data {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--xs) var(--md);
}

.data dt {
    align-self: center;
}

.data dd {
    text-align: right;
}

/* Nothing in this panel may push the scroll area sideways: a 19-digit seed or one
   unbroken word in the lyric would otherwise run past the edge and leave a
   horizontal scrollbar over content that is not there. Values break anywhere
   instead, exactly as the take's title already does. */
.data dd,
.lyric__line {
    overflow-wrap: anywhere;
}

/* The seed is the longest value the panel ever shows — nineteen digits in a row,
   and upstream draws it from randbelow(2**63) — so it is set a step smaller,
   with the readout tracking pulled in, to stand in its column on one line. */
.data__seed {
    font-size: 0.8125rem;
    letter-spacing: 0.03em;
}

.detail__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--hair);
    padding: var(--sm) var(--md);
    border-top: 1px solid var(--hairline);
}

/* ==========================================================================
   Transport
   ========================================================================== */

.transport {
    position: relative;
    z-index: 25;
    /* the player outranks the scrim: it is never
                                           dimmed, and never more than a glance away */
    background: var(--panel);
    border-top: 1px solid var(--hairline);
}

.transport__line {
    display: flex;
    align-items: center;
    gap: var(--md);
    padding: var(--xs) var(--md);
}

.transport__line--row {
    border-bottom: 1px solid var(--hairline);
}

/* The three slots share the line equally, so the row and the key trio sit dead
   centre at every width. A slot that is not needed keeps its share and only
   hides its contents — the machine loses a readout, never its symmetry. */
.transport__now,
.transport__styles,
.transport__time,
.transport__vol {
    flex: 1 1 0;
    min-width: 0;
}

.transport__now {
    display: flex;
    align-items: baseline;
    gap: var(--xs);
}

.transport__name {
    font-family: var(--font-plate);
    font-size: var(--fs-key);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--letter);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.transport__time {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--xs);
    overflow: hidden;
}

/* --- segmented readout --------------------------------------------------
   Four LED digit slots and a colon, drawn from seven bars each. An unlit bar
   stays a dark red ghost behind the smoked window, exactly like the display it
   copies; the accessible value is carried as text beside it. */
.seg-display {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    /* One thickness drives the whole digit: the row and column templates below are
     multiples of it, so a digit keeps its proportions at any size. */
    --seg-h: calc(var(--seg-t) * 9 + 4px);
    padding: 3px 5px;
    background: var(--well);
    border-radius: var(--r-well);
    box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.9);
}

.seg-digit {
    display: grid;
    width: calc(var(--seg-t) * 6 + 2px);
    height: var(--seg-h);
    grid-template-columns: var(--seg-t) calc(var(--seg-t) * 4) var(--seg-t);
    grid-template-rows: var(--seg-t) calc(var(--seg-t) * 3) var(--seg-t) calc(var(--seg-t) * 3) var(--seg-t);
    gap: 1px;
}

.seg {
    background: #2c1614;
    border-radius: 1px;
}

/* The horizontals take the full width; each vertical fills its own zone, which is
   why a 1 reads as one tall bar over another and not as two specks. */
.seg--a {
    grid-area: 1 / 1 / 2 / 4;
}

.seg--f {
    grid-area: 2 / 1 / 3 / 2;
}

.seg--b {
    grid-area: 2 / 3 / 3 / 4;
}

.seg--g {
    grid-area: 3 / 1 / 4 / 4;
}

.seg--e {
    grid-area: 4 / 1 / 5 / 2;
}

.seg--c {
    grid-area: 4 / 3 / 5 / 4;
}

.seg--d {
    grid-area: 5 / 1 / 6 / 4;
}

.seg.is-on {
    background: var(--step-red);
    box-shadow: 0 0 5px rgba(255, 59, 48, 0.55);
}

.seg-colon {
    display: grid;
    height: var(--seg-h);
    grid-template-rows: var(--seg-t) calc(var(--seg-t) * 3) var(--seg-t) calc(var(--seg-t) * 3) var(--seg-t);
    gap: 1px;
}

.seg-colon span {
    width: var(--seg-t);
    align-self: center;
    height: var(--seg-t);
    background: #2c1614;
    border-radius: 1px;
}

.seg-colon span:first-child {
    grid-row: 2;
}

.seg-colon span:last-child {
    grid-row: 4;
}

.seg-colon span.is-on {
    background: var(--step-red);
    box-shadow: 0 0 5px rgba(255, 59, 48, 0.55);
}

.transport__styles {
    display: flex;
    gap: var(--hair);
    overflow: hidden;
}

.key-trio {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--hair);
}

.key--transport {
    flex-direction: column;
    gap: 2px;
    min-width: 62px;
    min-height: 44px;
    padding: 4px var(--sm);
}

.key--transport .icon {
    width: 16px;
    height: 16px;
}

.key__word {
    font-size: 0.625rem;
    letter-spacing: 0.14em;
    color: var(--silkscreen-dim);
}

.key--play {
    color: var(--step-red);
}

.key--play .icon {
    color: var(--step-red);
}

.key--play:hover {
    background: #2b2b2b;
}

.key--play .key__word {
    color: var(--silkscreen-dim);
}

.key--play.is-on .key__word {
    color: var(--silkscreen);
}

.transport__vol {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sm);
}

.icon--vol {
    width: 16px;
    height: 16px;
    color: var(--silkscreen-dim);
}

.fader {
    -webkit-appearance: none;
    appearance: none;
    width: 96px;
    height: 16px;
    background: none;
    cursor: pointer;
}

.fader::-webkit-slider-runnable-track {
    height: 6px;
    border-radius: 2px;
    background: var(--well);
    box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.9);
}

.fader::-moz-range-track {
    height: 6px;
    border-radius: 2px;
    background: var(--well);
}

.fader::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 10px;
    height: 18px;
    margin-top: -6px;
    background: var(--silkscreen);
    border: 1px solid #6b6b6b;
    border-radius: 2px;
}

.fader::-moz-range-thumb {
    width: 10px;
    height: 18px;
    background: var(--silkscreen);
    border: 1px solid #6b6b6b;
    border-radius: 2px;
}

.ladder {
    display: flex;
    align-items: flex-end;
    gap: 2px;
}

.ladder .lamp {
    width: 5px;
    height: 16px;
    border-radius: 1px;
}

/* ==========================================================================
   Scrim (off-canvas console, overlay detail)
   ========================================================================== */

.scrim {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: rgba(8, 8, 8, 0.72);
}

/* ==========================================================================
   Landing — the machine's front door
   ========================================================================== */

/* The panel locks the viewport for the studio; the landing is a document and
   scrolls like one. Its face is one centred column; the nameplate's text aligns
   to that column's edge, while its bar and hairline stay full-bleed. */
body.landing {
    --page-w: 1024px;
    height: auto;
    min-height: 100%;
    overflow: visible;
}

.landing__page {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

.landing__main {
    flex: 1 1 auto;
}

/* The nameplate stays at hand while the page scrolls. It is not a second serve
   of the hero key: the landing keeps one action, and it lives in the hero. */
.landing .topbar {
    position: sticky;
    top: 0;
    z-index: 10;
    min-height: var(--topbar-h);
    padding-inline: max(var(--lg), calc((100% - var(--page-w)) / 2 + var(--lg)));
}

/* Hero, steps and clip share the one column, so their rules and gutters line up
   down the page. Each keeps `width: 100%`: as flex items, auto margins would
   otherwise shrink them to their content. */
.hero,
.steps,
.clip {
    width: 100%;
    max-width: var(--page-w);
    margin-inline: auto;
}

.hero {
    padding: clamp(48px, 10vh, 112px) var(--lg) clamp(40px, 8vh, 88px);
}

.hero__title {
    max-width: 24ch;
    font-family: var(--font-plate);
    font-size: var(--fs-hero);
    font-weight: 700;
    line-height: 0.98;
    letter-spacing: 0.01em;
    text-transform: uppercase;
    text-wrap: balance;
    color: var(--letter);
}

.hero__lead {
    margin-top: var(--md);
    max-width: 56ch;
    font-size: var(--fs-lead);
    line-height: 1.5;
    color: var(--silkscreen);
}

.hero__act {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--md);
    margin-top: var(--lg);
}

/* The one key of the page, and the only thing on it that acts. It wears the
   ready face of the studio's create key (see above), because that is what it
   is: the machine's power light, not a running channel. It keeps the key
   label's size; the cap is what grows. */
.key--hero {
    min-height: 48px;
    padding: 0 var(--xl);
}

/* Steps: the studio's ruled bank of takes read as a procedure — three rows that
   never change, no cards. */
.steps {
    padding: 0 var(--lg) clamp(40px, 8vh, 88px);
}

.steps__title,
.clip__title {
    padding-bottom: var(--md);
    border-bottom: 1px solid var(--hairline);
    font-size: var(--fs-heading);
}

.step {
    display: grid;
    grid-template-columns: 44px minmax(130px, 200px) minmax(0, 1fr);
    align-items: baseline;
    gap: var(--md);
    padding: var(--lg) 0;
    border-bottom: 1px solid var(--hairline);
}

.step__name {
    color: var(--letter);
}

.step__text {
    max-width: 62ch;
}

/* The screen sits in the column, dark until the key is pressed: the machine
   speaks only when asked. */
.clip {
    padding: 0 var(--lg) clamp(40px, 8vh, 88px);
}

.clip__video {
    display: block;
    width: 100%;
    margin-top: var(--lg);
    aspect-ratio: 16 / 9;
    background: var(--well);
    border: 1px solid var(--hairline);
    border-radius: var(--r-well);
}

/* The closing rule spans the column, as the nameplate's rule spans the page. */
.landing__foot {
    width: 100%;
    max-width: var(--page-w);
    margin-inline: auto;
    padding: var(--lg);
    border-top: 1px solid var(--hairline);
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1180px) {
    .body.is-detail {
        grid-template-columns: var(--console-w) minmax(0, 1fr);
    }

    .detail {
        position: fixed;
        z-index: 30;
        top: var(--topbar-h);
        right: 0;
        /* The panel stops where the transport begins: the player is the one thing an
       overlay never covers. */
        bottom: var(--transport-h);
        width: min(var(--detail-w), 94vw);
        border-left: 1px solid var(--hairline);
    }

    .plate__sub,
    .board__labels {
        display: none;
    }
}

@media (max-width: 900px) {
    .key--burger {
        display: inline-flex;
    }

    .body {
        grid-template-columns: minmax(0, 1fr);
    }

    .console {
        position: fixed;
        z-index: 30;
        top: var(--topbar-h);
        bottom: var(--transport-h);
        left: 0;
        width: min(var(--console-w), 92vw);
        transform: translateX(-100%);
        border-right: 1px solid var(--hairline);
    }

    .console.is-open {
        transform: none;
    }

    .detail {
        z-index: 31;
    }

    /* The drawer and the panel are fixed here and stop where the transport begins,
     so the board owns the whole row — including when the detail panel is open. */
    .body.is-detail {
        grid-template-columns: minmax(0, 1fr);
    }

    .board {
        padding: var(--md) var(--md) var(--lg);
    }

    .bank {
        padding: var(--md) var(--xs) 0;
    }

    .bank[aria-current="true"]::after {
        left: var(--xs);
        right: var(--xs);
    }

    .board {
        --take-num: 32px;
        --take-len: 52px;
        --take-status: 84px;
    }

    /* The procedure reads down the page: the number and the name hold one line,
     the explanation takes the next. */
    .step {
        grid-template-columns: 36px minmax(0, 1fr);
        row-gap: var(--xs);
    }

    .step__text {
        grid-column: 2;
    }
}

@media (max-width: 900px) {

    /* PRODUCT.md: the player sheds the volume slider and the ladder at ~900px.
     The slots keep their share so the key trio stays centred. */
    .transport__vol,
    .transport__styles {
        visibility: hidden;
    }
}

@media (max-width: 620px) {

    /* Line one has nothing to centre — the keys on line two do, and they keep their
     invisible side slots. So the take's name leaves the flow entirely here
     instead of holding a share the readout needs. */
    .transport__now {
        display: none;
    }

    :root {
        --topbar-h: 94px;
        --fs-readout: 0.8125rem;
    }

    .transport__total {
        visibility: hidden;
    }

    .topbar {
        flex-wrap: wrap;
        align-content: center;
        padding: var(--xs) var(--sm) 0;
        gap: var(--xs);
    }

    .plate__name {
        font-size: 1.0625rem;
        letter-spacing: 0.06em;
    }

    .banks {
        order: 2;
        width: 100%;
        margin-left: 0;
        justify-content: space-between;
    }

    .bank {
        height: 34px;
        padding: 0;
        align-items: flex-start;
    }

    .bank[aria-current="true"]::after {
        left: 0;
        right: 0;
        bottom: 4px;
    }

    .bank__count {
        display: none;
    }

    .status {
        border-left: 0;
        padding-left: 0;
        align-items: center;
    }

    .status__text {
        display: none;
    }

    .board {
        --take-num: 28px;
        --take-len: 0px;
        --take-status: 78px;
    }

    .take__len,
    .board__labels .legend:nth-child(4) {
        display: none;
    }

    .board__labels {
        display: none;
    }

    .board {
        padding: var(--sm);
    }

    .transport__line {
        gap: var(--sm);
        padding: var(--xs) var(--sm);
    }

    /* No bank row fills the bar here, so it tightens to the nameplate alone;
     the entry key takes the width a thumb expects. */
    .landing .topbar {
        min-height: 0;
        padding: var(--sm);
    }

    .hero {
        padding: clamp(40px, 9vh, 72px) var(--sm) var(--xl);
    }

    .steps {
        padding: 0 var(--sm) var(--xl);
    }

    .clip {
        padding: 0 var(--sm) var(--xl);
    }

    .key--hero {
        width: 100%;
    }

    .landing__foot {
        padding: var(--md) var(--sm);
    }
}

@media (prefers-reduced-motion: reduce) {

    .key,
    .stylekey,
    .take__hit,
    .preset__apply {
        transition: none;
    }

    .key:active {
        transform: none;
    }
}