:root{
  --bg:#0E0D0C;        /* surround — deepest warm black */
  --stage:#161514;     /* the stage */
  --panel:#171513;     /* surfaces */
  --card:#1C1A18;      /* raised surfaces */
  --border:#2A2826;    /* hairlines */
  --text:#EDEAE5;      /* paper — available */
  --muted:#8F8A84;     /* resting text */
  --rest:#5A5751;      /* resting glyphs */
  --red:#C03A2B;       /* Kandinsky red — now / selected / active only */
  --red-dim:#8E2A20;
}
*{box-sizing:border-box}
html,body{height:100%;margin:0;overscroll-behavior:none}
body{
  background:var(--bg);color:var(--text);
  font:14px/1.45 system-ui,-apple-system,'Segoe UI',sans-serif;font-weight:400;
  overflow:hidden;
  -webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;
}
#app{display:flex;flex-direction:column;height:100vh;height:100dvh}
#stage,#waveform,#waveOverview{-webkit-touch-callout:none}

.ic{width:18px;height:18px;display:block}

.brand{font-weight:500;letter-spacing:.01em;font-size:13px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Fixed app header: app title (left) + global Open/Save (right). The only fixed
   block besides the quick strip; everything else scrolls in #panel. */
#appHeader{display:flex;align-items:center;gap:8px;flex:0 0 auto}
/* Installed iPad web app: #rightCol hugs the screen's right edge, so this header
   (Open/Save) sits under the top-right status indicators. Add the top/right
   safe-area insets so it clears them. env() is 0 on desktop and the header is
   JS-relocated out of #rightCol on phone, so this affects the iPad layout only. */
#rightCol>#appHeader{padding:calc(14px + env(safe-area-inset-top,0px)) calc(14px + env(safe-area-inset-right,0px)) 14px 14px;border-bottom:1px solid var(--border)}
body.phone #appHeader{padding:0 0 12px;border-bottom:1px solid var(--border)}
/* 0.6.1: Open/Save are labeled and wrap onto their own full-width header row —
   beside the brand they would truncate the version tag in the 236px column. */
#appHeader{flex-wrap:wrap}
.projGlobal{display:flex;gap:6px;flex:1 0 100%}
#projectSetup .projGlobal{margin:0 0 8px}   /* 0.6.3: Open / Save live in Project */
.projGlobal button{flex:1;height:32px;padding:0;display:flex;align-items:center;justify-content:center;gap:7px}
.projGlobal .ic{width:17px;height:17px}
.projGlobal .btnTxt{font-size:12px}
.tag{font-size:10px;color:var(--muted);font-weight:400;border:1px solid var(--border);border-radius:10px;padding:1px 6px;margin-left:5px}
#projectName{width:100%;background:var(--card);border:1px solid var(--border);border-radius:6px;color:var(--text);font:inherit;font-size:13px;padding:6px 8px;margin-bottom:8px}
#projectName::placeholder{color:var(--rest)}
#projectName:focus{border-color:var(--red);outline:none}

/* phone-only controls — hidden on desktop / iPad */
#btnTools,#btnImmersive,#scrim,#barReveal,#rotateHint{display:none}

button{background:transparent;color:var(--muted);border:1px solid var(--border);border-radius:8px;padding:6px 12px;cursor:pointer;font:inherit;font-weight:400}
button:hover:not(:disabled){color:var(--text);border-color:#3A3733}
button:disabled{opacity:.35;cursor:default}
button.primary{background:var(--text);color:#141312;border-color:transparent;font-weight:500}
button.primary:hover:not(:disabled){background:#fff;color:#141312}
.iconBtn{width:36px;height:32px;padding:0;display:flex;align-items:center;justify-content:center}
.ghost{background:transparent}
.danger{color:var(--red)}
.wide{width:100%;margin-top:8px}
/* New Project — a deliberate document action: brighter text than the muted tool
   buttons + extra separation so it never reads as a lightweight link/transport
   control. Kept off Kandinsky red (reserved for active state); the confirm is
   the safety guard, not the colour. */
#btnNewProject{color:var(--text);margin-top:12px}
#btnNewProject:hover:not(:disabled){border-color:var(--text)}

#centerRow{flex:1;display:flex;min-height:0}
#canvasWrap{flex:1;position:relative;min-width:0;background:var(--bg)}
#stage{position:absolute;inset:0;display:block}
#hint{position:absolute;left:12px;bottom:8px;color:rgba(237,234,229,.22);font-size:11px;pointer-events:none;z-index:2}

#emptyState{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:rgba(14,13,12,.85);z-index:5;text-align:center;padding:20px}
#emptyState.hidden{display:none}
.hidden{display:none}
#emptyState h2{margin:0;font-weight:500;letter-spacing:.02em}
#emptyState p{color:var(--muted);max-width:440px;margin:0 0 6px}
#emptyState .alphaNote{font-size:12px;color:var(--rest);letter-spacing:.02em;margin:0 0 12px}
/* Start-screen creative choices */
.startChoices{display:flex;flex-wrap:wrap;gap:10px;justify-content:center}
.startChoices button{min-width:150px}
.startSecondary{display:flex;flex-wrap:wrap;gap:14px;justify-content:center;margin-top:10px}
.linklike{background:none;border:none;color:var(--muted);text-decoration:underline;text-underline-offset:3px;padding:6px 4px}
.linklike:hover:not(:disabled){color:var(--text)}
button.soon{position:relative;opacity:.6}
.soonTag{display:block;font-size:9px;letter-spacing:.06em;text-transform:uppercase;color:var(--rest);margin-top:2px}
.startSecondary .soon .soonTag{display:inline;margin-left:6px;text-decoration:none}
.clkPresets{flex-wrap:wrap;gap:6px;margin-bottom:6px}
.clkPresets button{flex:0 0 auto;padding:5px 10px;font-size:12px}
#clkDuration{width:100%;background:var(--card);border:1px solid var(--border);border-radius:6px;color:var(--text);font:inherit;font-size:15px;padding:8px 10px;margin-top:4px}
#clkDuration:focus{border-color:var(--red);outline:none}
#clickModal .modalBox{max-width:320px}
/* About / intro modal: a touch wider for comfortable reading; the emphasised
   line uses paper (--text) to lift out of the muted body copy. */
/* Capped height so the longer document never runs off a short screen (iPad in
   landscape, phone). Content scrolls; the Got it row stays pinned and reachable,
   which keeps the first-run presentation unchanged. */
.aboutBox{max-width:440px;max-height:80vh;display:flex;flex-direction:column}
.aboutScroll{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.aboutBox>.row{flex:0 0 auto;margin-top:14px}
.aboutBox strong{color:var(--text);font-weight:500}
/* Quiet section label — same treatment as the side-panel section headings. */
.aboutBox h4{margin:20px 0 10px;font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:var(--rest);font-weight:500}
.aboutList{list-style:none;margin:0;padding:0}
.aboutList li{color:var(--muted);font-size:13px;line-height:1.45;margin:0 0 12px}
/* Feedback. `body` sets user-select:none, so selection is re-enabled here: the
   address doubles as the copy fallback wherever mailto: does nothing (an iPad
   with no Mail account). Selectors carry a class extra so they beat `.modalBox p`. */
.aboutBox p.feedbackAddress{
  margin:0 0 10px;font-size:14px;overflow-wrap:anywhere;
  -webkit-user-select:text;user-select:text;-webkit-touch-callout:default;
}
.aboutBox p.feedbackAddress a{color:var(--text);text-decoration:underline;text-underline-offset:3px}
.aboutBox p.feedbackNote{margin:0 0 4px;font-size:12px;line-height:1.45;color:var(--rest)}
/* Technical-information disclosure. Reads as output, not a form. */
.techDetails{margin:14px 0 4px}
.techDetails summary{font-size:12px;color:var(--muted);cursor:pointer;padding:4px 0;user-select:none;-webkit-user-select:none}
.techDetails summary:hover{color:var(--text)}
.techCaption{margin:8px 0 6px;font-size:11px;color:var(--rest)}
/* Optional note — editable (card bg), distinct from the read-only preview. */
.techNoteLabel{display:block;margin:8px 0 4px;font-size:11px;color:var(--rest)}
.techNote{
  width:100%;box-sizing:border-box;resize:vertical;min-height:42px;
  border:1px solid var(--border);border-radius:6px;background:var(--card);color:var(--text);
  font:inherit;font-size:13px;padding:6px 8px;
  -webkit-user-select:text;user-select:text;
}
.techActions{display:flex;align-items:center;gap:12px;margin-top:10px}
.techStatus{font-size:11px;color:var(--rest)}
/* Read-only preview. Monospace + inset so it reads as output; selectable because
   body sets user-select:none, and manual selection is the copy fallback on http. */
.techReport{
  width:100%;box-sizing:border-box;resize:none;border:1px solid var(--border);border-radius:6px;
  background:var(--bg);color:var(--muted);
  font:11px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  padding:8px 10px;white-space:pre;overflow:auto;
  -webkit-user-select:text;user-select:text;
}
/* "This build" — deliberately quiet; informational, not a headline. Scoped with
   an extra class so it beats `.modalBox p` (0,1,1), which would otherwise
   override the font-size and margins. */
.aboutBox p.buildLine{font-size:11px;color:var(--muted);opacity:.7;margin:18px 0 4px}
#clickModal label{display:block;margin:10px 0 0;color:var(--muted);font-size:12px}
#clickModal select,#clickModal input[type=range]{width:100%;margin-top:4px;display:block}

#rightCol{width:236px;background:var(--panel);border-left:1px solid var(--border);display:flex;flex-direction:column;flex:0 0 auto;min-height:0}
/* Project as a direct column child under the app header (desktop/iPad, §15.8):
   panel-section visual grammar, but it lives in the column flow above the
   quick strip. On phone it moves into #panel and inherits #panel styling. */
#rightCol>#projectSection{padding:12px 14px;border-bottom:1px solid var(--border);flex:0 0 auto}
/* 0.6.3: the project name sits inside Project, under a quiet caption. */
.projNameLbl{margin:2px 0 4px;font-size:11px;color:var(--muted)}
/* Clear canvas: last in the sidebar, reachable with one swipe to the bottom. */
#panel #clearSection{border-bottom:none;padding-top:4px}
#quickStrip{padding:14px;border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:12px;flex:0 0 auto}
#quickScroll{display:flex;flex-direction:column;gap:12px}
#quickStrip #historyRow,#quickStrip #durRow{width:100%}
/* 0.6.2: Duration lane — full-height vertical slider at the canvas/panel seam
   (desktop + iPad; phone keeps it in the quick strip). The whole 44px lane
   width is the touch target; value on top, quiet rotated label at the foot.
   max is at the TOP (direction:rtl), matching the phone slider. */
#durLane{display:none}
body:not(.phone) #durLane{display:flex;flex:0 0 44px;width:44px;min-height:0;background:var(--panel);border-left:1px solid var(--border)}
body:not(.phone) #durLane #durRow{flex:1;display:flex;flex-direction:column;align-items:center;width:100%;min-height:0;margin:0;padding:10px 0 12px;gap:8px}
#durLane #durRow .val{order:0;float:none;font-size:11px}
#durLane #durSlider{
  order:1;-webkit-appearance:slider-vertical;appearance:slider-vertical;
  writing-mode:vertical-lr;direction:rtl;
  width:44px;height:auto;flex:1 1 auto;min-height:0;margin:0;padding:0;
}
#durLane #durRow .durLbl{order:2;writing-mode:vertical-rl;transform:rotate(180deg);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--rest)}
/* 0.6.1: Undo | Redo share one row 50/50 under the swatches. */
#historyRow{display:flex;gap:6px}
#toolSection #historyRow{margin-top:8px}   /* 0.6.3: Undo | Redo under Draw / Select */
/* Desktop/iPad: the top strip is empty now (swatches → Colour, Undo|Redo → Tool,
   Duration → its lane); on phone it is still the strip beside the canvas. */
body:not(.phone) #quickStrip{display:none}
/* Phone: Draw / Select and Undo | Redo both live in the strip, so the drawer's
   Tool section would be an empty heading. */
body.phone #toolSection{display:none}
/* 0.6.3: labelled like Open/Save (icon before label), 50/50, same height. */
#historyRow .histBtn{flex:1 1 0;min-width:0;height:32px;padding:0 6px;display:flex;align-items:center;justify-content:center;gap:6px}
.histBtn .ic{width:17px;height:17px}
.histBtn .btnTxt{font-size:12px}
#panel{flex:1;min-height:0;padding:14px;overflow-y:auto;display:flex;flex-direction:column;gap:16px}
#panel section{border-bottom:1px solid var(--border);padding-bottom:14px}
#panel section:last-child{border-bottom:none}
#panel h3{margin:0 0 8px;font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:var(--rest);font-weight:500}
#panel label{display:block;margin:8px 0 0;color:var(--muted);font-size:12px}
#panel select,#panel input[type=range]{width:100%;margin-top:4px;display:block}
.val{color:var(--text);float:right;font-variant-numeric:tabular-nums}
select{background:var(--card);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:4px;font:inherit;font-size:12px}
input[type=range]{accent-color:#6B6660}
input[type=checkbox]{accent-color:var(--red)}

.row{display:flex;gap:8px}
.row.hidden{display:none}   /* .hidden is declared earlier; a later display rule would win */
.row>button{flex:1}
/* Project action buttons: two stacked rows on desktop/phone (Import/Demo text +
   Open/Save icons). iPad collapses them to one icon row — see pointer:coarse. */
#projActions{display:flex;flex-direction:column}
#btnImport .ic,#btnDemo .ic{display:none}

.seg3{display:flex;gap:6px}
.seg3 button{flex:1;height:46px;padding:4px 0 3px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px}
.seg3 .ic{width:22px;height:22px}
.segLbl{font-size:10px;letter-spacing:.04em}
.seg3 button.active{color:var(--red);border-color:var(--red)}
.seg3.inert{opacity:.4}

#layerList{display:flex;flex-direction:column;gap:6px;margin-bottom:8px}
.layerRow{display:flex;align-items:center;gap:8px;border:1px solid transparent;border-radius:6px;padding:2px;cursor:pointer}
.layerRow.active{background:rgba(192,58,43,0.08);border-color:var(--red-dim)}
.layerVis{width:34px;height:34px;padding:0;flex:0 0 auto;display:flex;align-items:center;justify-content:center;font-size:15px;border-radius:6px}
.layerRow.hiddenLayer .layerVis{color:var(--rest)}
.layerName{flex:1;min-width:0;color:var(--text);font-size:12px;padding:5px 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.layerRow.hiddenLayer .layerName{color:var(--muted)}
.layerEdit{flex:0 0 auto;width:30px;height:30px;padding:0;display:flex;align-items:center;justify-content:center;color:var(--muted)}
.layerEdit:hover{color:var(--text)}
#renameInput,#labelInput{width:100%;background:var(--card);border:1px solid var(--border);border-radius:6px;color:var(--text);font:inherit;font-size:15px;padding:10px;margin-bottom:14px}
#renameInput:focus,#labelInput:focus{border-color:var(--red);outline:none}

/* Draggable new-label composer pill (floats over the stage). */
#labelComposer{position:fixed;transform:translate(-50%,-50%);z-index:90;display:flex;align-items:center;gap:6px;padding:6px;background:var(--card);border:1px solid var(--border);border-radius:12px;box-shadow:0 8px 28px rgba(0,0,0,.55)}
#labelComposer.hidden{display:none}
#lcGrip{flex:0 0 auto;width:34px;height:34px;display:flex;align-items:center;justify-content:center;font-size:16px;line-height:1;color:var(--muted);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}
#lcGrip:active{cursor:grabbing;color:var(--text)}
#lcInput{width:180px;background:var(--panel);border:1px solid var(--border);border-radius:6px;color:var(--text);font:inherit;font-size:15px;padding:8px 10px}
#lcInput:focus{border-color:var(--red);outline:none}
#labelComposer .lcBtn{flex:0 0 auto;width:34px;height:34px;padding:0;display:flex;align-items:center;justify-content:center;font-size:15px}
#labelComposer .lcConfirm{color:var(--red);border-color:var(--red)}
/* Stem + crosshair hang below the pill; the crosshair centre is the exact anchor. */
#labelComposer .lcStem{position:absolute;left:50%;top:100%;transform:translateX(-50%);width:2px;height:24px;background:var(--red);pointer-events:none}
#lcCross{position:absolute;left:50%;top:100%;transform:translate(-50%,24px);box-sizing:border-box;width:18px;height:18px;border:2px solid var(--red);border-radius:50%;background:rgba(192,58,43,0.15);pointer-events:none}
#lcCross::after{content:'';position:absolute;left:50%;top:50%;width:4px;height:4px;background:var(--red);border-radius:50%;transform:translate(-50%,-50%)}
@media (pointer:coarse){
  .layerVis{width:44px;height:42px;font-size:18px}
  .layerName{font-size:13px;padding:9px 6px}
  .layerEdit{width:42px;height:42px}
}

/* Click-track visual pulse: a full-stage edge glow, readable from across a
   room. The accented downbeat is markedly stronger than other beats. */
#beatFlash{position:absolute;inset:0;pointer-events:none;z-index:6;opacity:0;box-shadow:inset 0 0 70px 10px rgba(192,58,43,0.34)}
#beatFlash.accent{box-shadow:inset 0 0 140px 26px rgba(192,58,43,0.62)}
#beatFlash.pulse{animation:beatFlashAnim .22s ease-out}
#beatFlash.accent.pulse{animation-duration:.4s}
@keyframes beatFlashAnim{from{opacity:1}to{opacity:0}}
/* Experimental Sound Drawing block */
.expHead{margin:12px 0 4px;font-size:11px;color:var(--muted);font-weight:500}
.expTag{font-size:9px;letter-spacing:.06em;text-transform:uppercase;color:var(--red);border:1px solid var(--red-dim);border-radius:8px;padding:0 5px;margin-left:4px}
/* Music & Time (0.6.3 · B): two stacked status blocks (Music, Musical Grid),
   each a small caption, the state on its own line (wraps, never widens the
   column — §15.8), and one full-width button below. */
.mtBlock{margin-top:10px}
.mtBlock:first-of-type{margin-top:6px}
.mtHead{margin:0;font-size:11px;color:var(--muted)}
.mtValue{margin:2px 0 8px;font-size:13px;color:var(--text);line-height:1.35;overflow-wrap:anywhere}
#clickToggles{margin-top:2px}
#gridTapUI{margin-top:8px}
/* Alignment points (0.6.3 · C): one row per point — where it sits musically on
   the left, its time on the right; the selected row is outlined in paper. */
.gridPointList{display:flex;flex-direction:column;gap:4px;margin-bottom:6px}
.gridPoint{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;height:34px;padding:0 10px;font-size:12px}
.gridPoint.active{border-color:var(--text);color:var(--text)}
.gridPointTime{font-variant-numeric:tabular-nums;color:var(--muted)}
.gridPoint.active .gridPointTime{color:var(--text)}
#gridPointActions{margin:2px 0 4px}
/* Align a bar start: the target is the headline — unmistakable before Apply. */
.alignHead{margin:12px 0 8px;font-size:15px;font-weight:500;color:var(--text);font-variant-numeric:tabular-nums}
#gridBarStep button{white-space:nowrap}
#gridPointActions button{height:36px;padding:0 6px;font-size:12px;white-space:nowrap}
/* Grid overview (0.6.3 · B): the grid's actions; Remove is quiet and last. */
#gridOverviewUI .gridRemoveLink{display:block;margin-top:14px;color:var(--red)}
#gridOverviewUI .gridRemoveLink.hidden{display:none}   /* its own display rule would beat .hidden */
/* Layers: the label action sits under a quiet sub-caption. */
.subHead{margin:14px 0 6px;font-size:11px;color:var(--muted)}
/* 0.6.2 Tap Grid meter / tap-unit selectors — same active grammar as .seg3. */
.gridSegLbl{margin:0 0 4px;font-size:11px;color:var(--muted)}
.gridSeg{display:flex;gap:6px;margin-bottom:10px}
.gridSeg button{flex:1 1 0;min-width:0;height:36px;padding:0 4px;font-size:12px;white-space:nowrap}
.gridSeg button.active{color:var(--red);border-color:var(--red)}
.gridSeg.meterGrid{display:grid;grid-template-columns:repeat(3,1fr);margin-bottom:6px}   /* 6 meters, 3 × 2 */
#gridPane .gridHint{margin-top:0;margin-bottom:8px}

/* 0.6.2 Musical Grid context. body[data-sidebar="grid"] is set ONLY while the
   grid is being edited (derived from tapGrid: open || refineOpen). The sidebar
   then shows only #gridPane: structural "everything except" rules — nothing is
   hidden control-by-control, nothing is destroyed, no width changes. */
body:not([data-sidebar="grid"]) #gridPane{display:none}
body[data-sidebar="grid"] #appHeader,
body[data-sidebar="grid"] #projectSection,
body[data-sidebar="grid"] #quickScroll,
body[data-sidebar="grid"] #panel>:not(#gridPane){display:none}
/* desktop/iPad: Duration lives in its lane, so the strip would be an empty band */
body[data-sidebar="grid"]:not(.phone) #quickStrip{display:none}
/* the choreography canvas takes no input while the grid is edited */
body[data-sidebar="grid"] #stage{pointer-events:none}
/* phone: the strip's own later "body.phone #quickScroll{display:flex}" has equal
   specificity — restate for phone so only Duration stays in the strip. */
body.phone[data-sidebar="grid"] #quickScroll{display:none}
/* phone: drawer + scrim stop above the timeline so scrub / Set bar 1 / Align work */
body.phone[data-sidebar="grid"] #panel,
body.phone[data-sidebar="grid"] #scrim{bottom:calc(var(--phoneBar) + var(--phoneBarPad))}
#panel #gridPane{border-bottom:none}
.gridPaneHead{display:flex;align-items:center;gap:8px;margin-bottom:12px}
.gridPaneId{flex:1;min-width:0}
.gridPaneTitle{margin:0;font-size:15px;font-weight:500;letter-spacing:.01em;color:var(--text)}
.gridPanePhase{margin:2px 0 0;font-size:11px;letter-spacing:.04em;color:var(--muted)}
.gridPaneHead button{flex:0 0 auto}
/* touch-action:none — overlapping alternating-finger taps must not start a
   browser pinch/pan gesture on the button (0.6.2). */
.gridTapBtn{width:100%;height:52px;font-size:15px;font-weight:500;letter-spacing:.02em;color:var(--text);border-color:var(--border);touch-action:none}
.gridTapBtn:active{background:var(--red);border-color:transparent;color:#141312}
.gridReadout{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin:8px 0}
#gridTapCount{font-size:12px;color:var(--muted)}
#gridTapBpm{font-size:13px;color:var(--text);font-variant-numeric:tabular-nums}
#gridSetBar1{margin-top:10px}
#gridAnchorState{font-size:12px;color:var(--muted)}
#gridAnchorState.isSet{color:var(--text)}
.gridTapActions{margin-top:8px}
#gridRefineUI{margin-top:8px}
#gridRefineReadout{font-size:12px;color:var(--text);line-height:1.35}
/* Four recent colours in ONE row (0.6.3) — no horizontal scrolling. */
.swatches{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin:2px 0 8px}
.swatch{height:28px;border-radius:6px;border:2px solid transparent;cursor:pointer}
.swatch.active{border-color:var(--red)}
input[type=color]{width:100%;height:28px;border:1px solid var(--border);border-radius:6px;background:none;padding:2px;cursor:pointer}
/* Colour picker row (0.6.3): a colour WELL (ringed with a hue wheel so it reads
   as "any colour"; opens the system picker) + the exact HEX / rgb() field. */
.colorPick{display:flex;align-items:center;gap:8px}
.colorWell{flex:0 0 44px;height:32px;padding:3px;border-radius:8px;display:flex;cursor:pointer;
  background:conic-gradient(#f44,#fd4,#4f6,#4df,#46f,#e4f,#f44)}
.colorWell input[type=color]{width:100%;height:100%;border:none;border-radius:5px;padding:0;background:var(--panel)}
.colorWell input[type=color]::-webkit-color-swatch-wrapper{padding:0}
.colorWell input[type=color]::-webkit-color-swatch{border:none;border-radius:5px}
.colorText{flex:1 1 auto;min-width:0;height:32px;box-sizing:border-box;background:var(--card);border:1px solid var(--border);border-radius:6px;
  color:var(--text);font:inherit;font-size:13px;padding:0 8px;font-variant-numeric:tabular-nums;-webkit-user-select:text;user-select:text}
.colorText:focus{border-color:var(--muted);outline:none}
.colorText.invalid{border-color:var(--red)}
/* The Colour row shows the current colour even when collapsed. */
.colorChip{flex:0 0 auto;width:12px;height:12px;border-radius:3px;border:1px solid rgba(237,234,229,.25)}

#panel label.check{display:flex;align-items:center;gap:8px;margin-top:10px;cursor:pointer}
#panel label.check input{margin:0}
/* ONE disclosure convention (0.6.3 · B; from the §25 Project setup row) for
   every collapsible sidebar block — Project setup, Layers, Music & Time,
   Advanced, nested Voice A tuning. A row, not a static heading: label in the
   interactive grey, a line chevron at the right (› collapsed, ⌄ expanded), the
   whole row is the target, subtle hover/press feedback. The negative side margin
   lets feedback span the row without moving content. #rightCol scope: the one
   ancestor all of these share on every layout (phone included). */
#rightCol details.disclosure>summary{
  cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;
  font-size:10px;text-transform:uppercase;letter-spacing:.12em;font-weight:500;color:var(--muted);
  margin:0 -8px;padding:6px 8px;border-radius:6px;transition:background .12s,color .12s;
  -webkit-user-select:none;user-select:none;
}
#rightCol details.disclosure>summary::-webkit-details-marker{display:none}
#rightCol details.disclosure>summary::after{
  content:'';flex:0 0 auto;width:6px;height:6px;margin:0 4px 0 auto;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(-45deg);transition:transform .15s;
}
#rightCol details.disclosure[open]>summary{margin-bottom:4px}
#rightCol details.disclosure[open]>summary::after{transform:rotate(45deg)}
#rightCol details.disclosure>summary:hover{color:var(--text)}
#rightCol details.disclosure>summary:active{background:rgba(237,234,229,.06);color:var(--text)}
#rightCol details.disclosure>summary:focus-visible{outline:1px solid var(--muted);outline-offset:1px}
/* A disclosure that opens a panel section sits where the section's h3 used to:
   its touch row reaches into the EMPTY space around it (the gap above, and the
   section's bottom padding when collapsed) instead of pushing layout down — a
   full-size target with no material size increase. */
#panel>section>details.disclosure:first-child>summary{margin-top:-6px}
#panel>section>details.disclosure:first-child:not([open])>summary{margin-bottom:-4px}
/* Nested disclosure (Voice A tuning inside Advanced): same grammar, some air. */
#rightCol details.disclosure details.disclosure{margin-top:12px}
#panel .note{color:rgba(237,234,229,.28);font-size:11px;margin:8px 0 0;line-height:1.35}

#debugHud{
  position:absolute;top:12px;left:12px;z-index:3;pointer-events:none;
  background:rgba(14,13,12,.85);border:1px solid var(--border);border-radius:10px;
  padding:10px 12px;width:230px;
  font:11px/1.5 ui-monospace,Consolas,monospace;color:var(--muted);
}
#debugHud.hidden{display:none}
#debugHud.idle .dbgRow b{opacity:.45}
.dbgTitle{text-transform:uppercase;letter-spacing:.08em;font-size:10px;color:var(--rest);margin-bottom:6px;display:flex;justify-content:space-between;gap:8px}
#dbgMode{color:var(--red)}
#dbgMode.composition{color:var(--text)}
#dbgMode.idle{color:var(--rest)}
.dbgRow{display:flex;justify-content:space-between;gap:10px}
.dbgRow b{color:var(--text);font-weight:500;font-variant-numeric:tabular-nums}
.dbgBar{position:relative;height:8px;margin-top:8px;border-radius:4px;background:var(--card);border:1px solid var(--border);overflow:hidden}
.dbgBarFill{position:absolute;left:0;top:0;bottom:0;width:0;background:#6B6660;border-radius:4px}
.dbgBarMark{position:absolute;top:-1px;bottom:-1px;width:2px;left:0;background:var(--red)}
.dbgLegend{display:flex;justify-content:space-between;font-size:9px;color:var(--rest);margin-top:3px}

#timelineArea{height:calc(160px + env(safe-area-inset-bottom,0px));padding-bottom:env(safe-area-inset-bottom,0px);background:var(--panel);border-top:1px solid var(--border);display:flex;flex:0 0 auto}
#transportDock{width:118px;border-right:1px solid var(--border);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:8px;flex:0 0 auto}
#transportRow{display:flex;align-items:center;gap:6px}
#btnBack{width:34px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;padding:0}
#btnBack .ic{width:18px;height:18px}
#btnPlay{width:54px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;padding:0}
#btnPlay .ic{width:22px;height:22px}
#btnPlay .icPause{display:none}
#btnPlay.playing .icPlay{display:none}
#btnPlay.playing .icPause{display:block;color:var(--red)}
#btnPlay.playing{border-color:var(--red-dim)}
#timeDisplay{text-align:center;font-variant-numeric:tabular-nums;line-height:1.3}
#timeNow{font-size:16px;color:var(--text);display:block;font-weight:500}
#timeTotal{font-size:11px;color:var(--muted);display:block}
/* 0.6.3: musical position between time and total — secondary, but brighter than
   the total because it changes with the music. */
#timePos{font-size:12px;color:var(--text);opacity:.8;display:block;white-space:nowrap}
#timePos.hidden{display:none}

#waveWrap{flex:1;min-width:0;display:flex;flex-direction:column;position:relative}
/* Selection (§15.1 C2): armed Select + range readout chip — selection blue,
   never the red (loop/playhead own red). */
/* Draw | Select tool (§15.4): a two-state posture switch — BOTH states show an
   active treatment. Draw active = paper (normal making); Select active = the
   selection blue. Overrides the generic red .seg3 active. */
#toolSeg button.active{color:var(--text);border-color:var(--text)}
#toolSeg #toolSelect.active{color:#78BEFF;border-color:#78BEFF}
/* Phone: #toolSeg lives in the quick strip (relocated by applyPhone) —
   icon-only, stacked full-width in the 44px column. */
body.phone #quickScroll #toolSeg{display:flex;flex-direction:row;gap:4px;flex:0 0 auto}
body.phone #quickScroll #toolSeg button{flex:1 1 0;width:auto;min-width:0;height:34px;padding:0;flex-direction:row}
body.phone #quickScroll #toolSeg .segLbl{display:none}
body.phone #quickScroll #toolSeg .ic{width:20px;height:20px}
/* Contextual Selection section (§15.6) — panel-native, no floating chip. */
#selSection .selNote{margin:0 0 6px}
#selRangeInfo{color:rgba(185,220,255,.5)}
/* Responsive action grid: grows as future actions (Duplicate/Move/Rotate) join. */
.selActions{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:8px;margin-top:4px}
.selActions.hidden{display:none}
.selActions button{height:44px;display:flex;align-items:center;justify-content:center;gap:7px}
.selActions .ic{width:18px;height:18px}
#selDelete{border-color:var(--red-dim)}
#selDelete:hover{border-color:var(--red)}
#selDone{color:#B9DCFF;border-color:rgba(120,190,255,.45)}
#selDone:hover{color:var(--text);border-color:#78BEFF}
/* Repeat panel (§15.7): stepper form, no keyboard. */
#repeatPanel{margin-top:6px}
#repeatPanel.hidden{display:none}
.repRow{display:flex;align-items:center;gap:6px;margin:8px 0}
.repRow.hidden{display:none}
/* #repRowBars is a plain block group (Every + stacked Bars/Beats rows) — the
   global .hidden rule governs its visibility (no display rule here). */
.repEvery{margin:8px 0 0;font-size:11px;color:var(--muted)}
.repLbl{font-size:11px;color:var(--muted);width:42px;flex:0 0 auto}
.repStep{width:40px;height:40px;padding:0;font-size:17px;flex:0 0 auto}
.repVal{min-width:28px;text-align:center;font-variant-numeric:tabular-nums;color:var(--text)}
.repUnit{font-size:11px;color:var(--muted);margin-right:2px}
#repWarn{color:var(--red)}
#repeatPanel .row{margin-top:10px}
/* Phone: #selActions relocates into the quick strip (below the tool) —
   icon-only, stacked, only while selecting with members. */
/* Delete | Done on top, Repeat full-width below (three 27px buttons in one row
   were too narrow). While they show, the swatches step aside — colour does not
   apply in Select — so the strip still fits on the shortest phones. */
body.phone #quickScroll #selActions{display:grid;grid-template-columns:1fr 1fr;grid-template-areas:"del done" "rep rep";gap:4px;flex:0 0 auto;margin:0}
body.phone #quickScroll #selActions.hidden{display:none}
body.phone #quickScroll #selActions button{width:auto;min-width:0;height:40px;padding:0}
body.phone #quickScroll #selDelete{grid-area:del}
body.phone #quickScroll #selDone{grid-area:done}
body.phone #quickScroll #selRepeat{grid-area:rep}
body.phone #quickScroll #selActions:not(.hidden) ~ #swatches{display:none}
body.phone #quickScroll #selActions .selLbl{display:none}
body.phone #quickScroll #selActions .ic{width:18px;height:18px}
#waveform{flex:1;min-height:0;width:100%;display:block;cursor:crosshair}
#waveOverview{height:30px;width:100%;display:block;border-top:1px solid var(--border);cursor:grab}
#tlControls{display:flex;flex-direction:column;gap:6px;padding:8px;border-left:1px solid var(--border)}
#tlControls button{width:44px;padding:4px 0}
#btnLoop.active{color:var(--red);border-color:var(--red)}

/* Comfortable touch targets on coarse pointers (iPad) */
@media (pointer:coarse){
  button{padding:9px 14px}
  .iconBtn{width:46px;height:42px}
  .projGlobal button{height:42px;padding:0}
  .gridSeg button{height:44px;padding:0 4px}
  .gridPoint{height:42px}
  #gridPointActions button{height:44px}
  .ic{width:20px;height:20px}
  /* 0.6.2: 284 → 240 — the right column pays for the 44px Duration lane, so the
     drawing canvas keeps exactly its previous width on iPad. */
  #rightCol{width:240px}
  #panel{gap:18px}
  #panel label{font-size:13px}
  .swatch{height:40px}
  input[type=color]{height:36px}
  .colorWell{height:40px}
  .colorText{height:40px}
  #historyRow .histBtn{height:42px}
  .seg3 button{height:56px}
  .seg3 .ic{width:24px;height:24px}
  .segLbl{font-size:11px}
  #btnPlay{width:66px;height:54px}
  #btnPlay .ic{width:26px;height:26px}
  #btnBack{width:44px;height:54px}
  #btnBack .ic{width:22px;height:22px}
  #transportDock{width:144px}
  #timeNow{font-size:18px}
  /* §15.8: ~25% shorter timeline on iPad — the recovered height flows to the
     canvas automatically (#centerRow is flex:1). Overview keeps its 36px touch
     target; the waveform strip (~106px after ruler+lane) still clears the
     event-lane text gate (cssH ≥ 34) and bar-number labels comfortably. */
  #timelineArea{height:calc(148px + env(safe-area-inset-bottom,0px))}
  #waveOverview{height:36px}
  /* §15.9: the Project-setup summary is a primary touch disclosure — give it a
     comfortable target on touch devices. */
  #rightCol details.disclosure>summary{padding:12px 8px}
  #panel>section>details.disclosure:first-child>summary{margin-top:-12px}
  #panel>section>details.disclosure:first-child:not([open])>summary{margin-bottom:-8px}
  #tlControls button{width:54px;padding:9px 0;font-size:16px}
  input[type=range]{height:30px}
  #hint{display:none}
}

/* iPad-only compactness (coarse pointer, not phone). (0.6.3: the scrolling
   8-swatch row and the hidden picker are gone — the Colour section holds four
   recent swatches in one row plus the picker, on every layout.) */
@media (pointer:coarse){
  /* Project: collapse the two button rows into one icon row (Import · Demo ·
     Open · Save). Icons replace the Import/Demo text labels on iPad only. */
  body:not(.phone) #projActions{flex-direction:row;gap:8px}
  body:not(.phone) #projActions .row{display:contents}
  body:not(.phone) #projActions button{flex:1 1 0;min-width:0;height:42px;padding:0;display:flex;align-items:center;justify-content:center}
  body:not(.phone) #btnImport .ic,body:not(.phone) #btnDemo .ic{display:block}
  body:not(.phone) #btnImport .btnTxt,body:not(.phone) #btnDemo .btnTxt{display:none}
}

.modal{position:fixed;inset:0;background:rgba(8,7,6,.6);display:flex;align-items:center;justify-content:center;z-index:100}
.modal.hidden{display:none}
.modalBox{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:20px;max-width:380px}
.modalBox h3{margin:0 0 8px;font-weight:500}
.modalBox p{color:var(--muted);font-size:13px;margin:0 0 14px}

/* ===================== PHONE MODE ===================== */
/* Canvas is king: brand bar hidden, panel becomes a right drawer, the
   timeline collapses to a slim bottom bar, immersive hides it entirely.
   Same DOM, restyled — no second interface. */
body.phone #hint{display:none}
body.phone #debugHud{display:none}

/* rightCol dissolves: quickStrip becomes a thin working strip in the canvas's
   side letterbox (free space — the 16:9 canvas is height-limited), and the
   panel becomes the Tools drawer. */
body.phone #rightCol{display:contents}
/* Widened by the right safe-area inset so the Dynamic Island (when the phone is
   rotated island-right) never covers the swatches. iOS reports landscape insets
   SYMMETRICALLY (both edges, either rotation), so JS adds body.safe-right when
   the island is detectably on the LEFT — dropping the reservation and giving the
   width back (fail-safe: no detection → keep the padding). */
/* 0.6.3 phone touch pass: 84 → 136px, two ~46px columns. Free — the canvas is
   HEIGHT-limited on a landscape phone, so the stage keeps a side letterbox and
   the canvas itself does not shrink for this. */
body.phone #quickStrip{
  width:calc(136px + env(safe-area-inset-right,0px));flex:0 0 auto;
  background:var(--panel);border-left:1px solid var(--border);
  padding:6px calc(6px + env(safe-area-inset-right,0px)) 6px 6px;gap:6px;overflow:hidden;
  display:flex;flex-direction:row;align-items:stretch;
}
body.phone.safe-right #quickStrip{width:136px;padding:6px}
/* duration: vertical, full-height, fixed narrow column on the LEFT. The
   #quickStrip prefix is REQUIRED so this beats the desktop "#quickStrip
   #durRow{width:100%}" rule (which otherwise crushes the swatches to 0px). */
body.phone #quickStrip #durRow{
  order:-1;flex:0 0 28px;width:28px;height:100%;margin:0;
  display:flex;flex-direction:column;align-items:center;gap:4px;
}
body.phone #quickStrip #durRow .durLbl{display:none}
body.phone #quickStrip #durRow .val{float:none;font-size:9px;color:var(--text)}
body.phone #quickStrip #durSlider{
  -webkit-appearance:slider-vertical;appearance:slider-vertical;
  writing-mode:vertical-lr;direction:rtl;
  width:28px;flex:1 1 auto;min-height:0;margin:0;
}
/* right side, two columns: Open|Save · Draw|Select · Undo|Redo · (Delete|Done)
   · swatches 2×2 — always visible, no scroll. */
body.phone #quickScroll{order:0;flex:1 1 auto;min-width:0;overflow:visible;display:flex;flex-direction:column;gap:6px;align-items:stretch}
body.phone #quickScroll .swatches{display:grid;grid-template-columns:1fr 1fr;gap:4px;margin:0}
body.phone .swatch{width:auto;height:28px;border-width:2px}
/* Undo | Redo side by side, 44px tall — frequent, must not need aiming. */
body.phone #quickScroll #historyRow{flex-direction:row;gap:4px;flex:0 0 auto}
body.phone #quickScroll #historyRow .histBtn{flex:1 1 0;min-width:0;height:44px;padding:0;flex-direction:column;gap:2px}
body.phone #quickScroll #historyRow .histBtn .ic{width:18px;height:18px}
body.phone #quickScroll #historyRow .histBtn .btnTxt{font-size:10px}
/* Quick Open/Save at the top of the strip — phone only, side by side. */
#stripIO{display:none}
body.phone #stripIO{display:flex;flex-direction:row;gap:4px;flex:0 0 auto}
body.phone #stripIO button{flex:1 1 0;width:auto;min-width:0;height:34px}

body.phone #panel{
  position:fixed;top:0;right:0;bottom:0;width:min(340px,88vw);
  transform:translateX(102%);transition:transform .22s ease;
  z-index:60;box-shadow:-14px 0 36px rgba(0,0,0,.55);
  padding-top:max(14px,env(safe-area-inset-top,0px));
  /* Solid background: on phone #rightCol is display:contents, so the drawer
     doesn't inherit the column bg — without this it floats transparent over
     the canvas, which hurt readability. */
  background:var(--panel);
  /* keep drawer content clear of the Dynamic Island when it's on the right */
  padding-right:calc(14px + env(safe-area-inset-right,0px));
}
body.phone.safe-right #panel{padding-right:14px}
body.phone.tools-open #panel{transform:translateX(0)}
/* While the label composer is open on phone, hide the bar and strip so the
   stage keeps room above the keyboard (temporary, restored on close). */
body.phone.composing #timelineArea{display:none}
body.phone.composing #quickStrip{display:none}
body.phone #scrim{position:fixed;inset:0;background:rgba(8,7,6,.5);z-index:55}
body.phone.tools-open #scrim{display:block}

/* Bottom area (0.6.3 phone touch pass; was a 48px bar with a 12px overview at
   the very bottom — inside the iOS home-indicator swipe zone). Now:
     overview / visible-range strip — full width, TOP of the area, inset from
       the screen edges (edge-swipe gestures) → drags happen far from the bottom
     [ transport · readout | waveform (scrub / playhead / grid) | Loop · Tools · Hide ]
   The bottom row holds only TAP controls beside the home indicator; a minimum
   8px bottom pad keeps the waveform off the edge on home-button phones too
   (Control Center swipe). --phoneBar = padding 4 + overview 30 + gap 4 + row 46. */
body.phone{--phoneBar:84px;--phoneBarPad:max(8px,env(safe-area-inset-bottom,0px))}
body.phone #timelineArea{
  height:calc(var(--phoneBar) + var(--phoneBarPad));padding:4px 0 var(--phoneBarPad);
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-rows:30px 46px;row-gap:4px;
  grid-template-areas:"ov ov ov" "dock wave ctl";
}
body.phone #waveWrap{display:contents}
body.phone #waveOverview{
  /* no border: the canvas is sized from its box, a border would skew x by 1px */
  grid-area:ov;height:30px;border:none;border-radius:6px;
  margin:0 max(20px,env(safe-area-inset-right,0px)) 0 max(20px,env(safe-area-inset-left,0px));
  width:calc(100% - max(20px,env(safe-area-inset-left,0px)) - max(20px,env(safe-area-inset-right,0px)));
  /* read by WaveformView: roomier inset + grab zones on phone */
  --ov-pad:30;--ov-tol:30;--ov-handle:9;--ov-pan:28;
}
body.phone #waveform{grid-area:wave;height:100%}
body.phone #transportDock{grid-area:dock;width:auto;flex-direction:row;align-items:center;gap:6px;padding:0 8px}
body.phone #transportRow{gap:4px}
body.phone #btnPlay{width:48px;height:44px}
body.phone #btnBack{width:40px;height:44px}
body.phone #timeDisplay{min-width:58px}
body.phone #timeNow{font-size:14px}
body.phone #timeTotal{display:none}
body.phone #timePos{font-size:11px}
body.phone #tlControls{grid-area:ctl;flex-direction:row;align-items:center;gap:4px;padding:0 8px}
body.phone #tlFit{display:none}
/* The #tlControls prefix is REQUIRED: the generic "#tlControls button" width
   rules otherwise win and crushed Tools / Hide to 22px wide (iPhone finding). */
body.phone #tlControls #btnTools,body.phone #tlControls #btnImmersive{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;flex:0 0 auto}
/* Tools = the phone's primary navigation into the full menu: wider, brighter. */
body.phone #tlControls #btnTools{width:52px;color:var(--text);border-color:var(--text)}
body.phone #tlControls #btnTools .ic{width:24px;height:24px}
body.phone #tlControls #btnLoop{width:auto;height:44px;padding:0 12px}

/* Very short phones (≤ 340px tall, e.g. iPhone SE 1st gen landscape): the strip
   must still fit Delete|Done while selecting — trim gaps, Open/Save and swatch
   height; Undo|Redo keep their 44px. */
@media (max-height:340px){
  body.phone #quickScroll{gap:4px}
  body.phone #stripIO button{height:30px}
  body.phone .swatch{height:22px}
}
/* Dialogs on phone: never taller than the screen (the Click Track dialog is
   ~390px — its title and Duration were cut off above a 320–375px landscape
   viewport); scroll inside instead. Duration preset chips were 29px tall. */
body.phone .modalBox{max-height:calc(100% - 16px);overflow-y:auto;-webkit-overflow-scrolling:touch}
body.phone .clkPresets button{min-height:38px}
/* Drawer / dialogs on phone: a checkbox row is tappable across its whole label
   (was 19px tall with a 13px box); selects and the name field reach 40px. */
body.phone label.check{min-height:40px;display:flex;align-items:center;gap:10px}
body.phone label.check input[type=checkbox]{width:20px;height:20px;margin:0;flex:0 0 auto}
body.phone select,body.phone #projectName{min-height:40px}

/* immersive: drop the bar AND the side strip for a clean full-canvas pass */
body.phone.immersive #timelineArea{display:none}
body.phone.immersive #quickStrip{display:none}
body.phone.immersive #barReveal{
  display:flex;align-items:center;justify-content:center;
  position:fixed;left:0;right:0;bottom:0;
  /* 0.6.3 touch pass: 18 → 30px tap strip (a TAP target by the home indicator;
     taps never trigger the system swipe). */
  height:calc(30px + env(safe-area-inset-bottom,0px));
  padding-bottom:env(safe-area-inset-bottom,0px);
  background:rgba(28,26,24,.72);color:var(--muted);z-index:50;cursor:pointer;
}
body.phone.immersive #barReveal .ic{width:18px;height:12px}

/* portrait is not a real working mode: a full overlay prompts rotation
   (dismissible so portrait stays technically accessible). Installed PWA is
   landscape-locked via the manifest, so this only appears in a browser tab. */
body.phone #rotateHint{
  position:fixed;inset:0;z-index:90;background:rgba(14,13,12,.96);
  display:none;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;text-align:center;padding:24px;
}
body.phone #rotateHint .rotateMsg{font-size:20px;font-weight:500;color:var(--text)}
body.phone #rotateHint .rotateSub{font-size:13px;color:var(--muted);max-width:360px;line-height:1.4}
body.phone #rotateHint #rotateDismiss{margin-top:10px}
@media (orientation:portrait){body.phone:not(.portrait-ok) #rotateHint{display:flex}}
@media (orientation:landscape){body.phone #rotateHint{display:none}}
