/* Chord Atlas 9.5.1 — Container Layout
   Layout primitives are additive: existing IDs and JS contracts remain intact. */
:root{
  --ca-space-1:.25rem;--ca-space-2:.5rem;--ca-space-3:.75rem;--ca-space-4:1rem;--ca-space-5:1.5rem;--ca-space-6:2rem;
  --ca-container-gap:clamp(.65rem,1.25cqi,1rem);--ca-touch-target:44px;
  --neck-column-width:440px;
  /* Chord Atlas is a light workspace canvas; a pane is a composition
     placed on it, not a container obligated to fill the viewport. This
     caps how wide any single pane's row is allowed to get, so extra
     space on very wide displays stays visible as canvas instead of
     stretching cards. See "CHORD ATLAS LAYOUT SYSTEM" below. */
  --ca-pane-max-width:1700px;
}
.ca-container{container-type:inline-size;min-width:0;min-height:0;box-sizing:border-box}
.ca-controls{container-name:controls}.ca-parameters{container-name:parameters}.ca-scale-controls{container-name:scale-controls}
.ca-circle{container-name:circle}.ca-scale-choice{container-name:scale-choice}.ca-neck{container-name:neck}.ca-chord-area{container-name:chords}
.ca-map-visual{container-name:harmonic-map}.ca-tuner{container-name:tuner}.ca-tuner-card{container-name:tuner-card}
.ca-visual-viewport{min-width:0;max-width:100%;overflow:auto;overscroll-behavior:contain}

/* Pre-existing gap: this rule declared grid-template-columns/@container
   grid overrides below but never set display:grid, so the two panels
   (Circle of Fifths + scale info) always stacked as block children no
   matter how wide their container was. That's exactly the "normal
   desktop: compact multi-column arrangement" case this layout pass is
   about, so fixing it here rather than leaving it as dead CSS. */
.scale-selector-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(270px,100%),1fr));gap:var(--ca-container-gap)}
/* Circle of Fifths: a deterministic box derived from its own container
   width, not from whatever space happens to be left over by siblings.
   aspect-ratio guarantees a valid height the instant width is known,
   instead of waiting on SVG intrinsic-size quirks. */
#circleOfFifths{inline-size:min(100%,330px);block-size:auto;aspect-ratio:1/1}
.chord-grid{grid-template-columns:repeat(auto-fit,minmax(min(205px,100%),1fr))}

@container scale-controls (width < 600px){.scale-selector-grid{grid-template-columns:1fr}}
@container circle (width < 300px){.fifths-panel .panel-title-row>span{display:none}#circleOfFifths{inline-size:100%}}
@container scale-choice (width < 360px){.scale-quick-choices{gap:5px}.scale-choice-panel .hint{font-size:11px}}
@container chords (width < 480px){.chord-grid{grid-template-columns:1fr}}

/* Parameters and tool controls reflow intrinsically. */
.ca-parameters .control-strip,.ca-parameters .parameter-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(135px,100%),1fr));gap:var(--ca-space-2)
}
.ca-parameters select,.ca-parameters input[type="number"]{max-width:100%;min-width:0}
@container parameters (width < 250px){
  .ca-parameters .control-strip,.ca-parameters .parameter-grid{grid-template-columns:1fr}
  .ca-parameters .visualization-actions{align-items:stretch}
}

/* Tuner: medium is a real layout, not a shrunken large layout. */
.tuner-module{container-type:inline-size}
.tuner-module-card{min-width:0}
.tuner-module-controls{grid-template-columns:repeat(auto-fit,minmax(min(112px,100%),1fr))!important;align-items:end}
.tuner-size-group{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));min-width:0}
.tuner-size-button{min-width:0!important;white-space:nowrap}
.tuner-module-controls label{min-width:0}.tuner-module-controls select{width:100%;min-width:0!important}
.tuner-instrument-tuning{min-width:0;overflow:hidden}
.tuner-nut{min-width:0}.tuner-string{min-width:0}.tuner-string-target{min-width:0!important;width:100%;overflow:visible}
.tuner-string-note{white-space:nowrap;font-size:clamp(8px,3.2cqi,11px)}
.tuner-tuning-head{flex-wrap:wrap}

@container tuner (width < 520px){
  .tuner-module-controls{grid-template-columns:repeat(2,minmax(0,1fr))!important}
  .tuner-size-group{grid-column:1/-1}
  .tuner-tuning-hint{display:none}
  .tuner-instrument-tuning{padding-inline:7px}
  .tuner-string-note{padding-inline:2px}
}
@container tuner (width < 360px){
  .tuner-module-controls{grid-template-columns:1fr!important}
  .tuner-size-group{grid-column:auto}
  .tuner-instrument-tuning{display:none}
}
@container tuner (width >= 360px) and (width < 540px){
  .tuner-readout{gap:10px}.tuner-note{font-size:clamp(42px,16cqi,60px)}
}
@container tuner (width >= 540px){
  .tuner-module-controls{grid-template-columns:minmax(210px,1.5fr) repeat(4,minmax(105px,1fr))!important}
}

/* Keep overlays inside the visual field at awkward intermediate widths. */
@media (min-width:761px){
  .tuner-size-medium{width:clamp(440px,52vw,620px)}
  .tuner-size-large{width:min(760px,72vw)}
}
@media (max-width:760px){
  .tuner-size-medium{width:100vw;max-width:100vw}
}

/* Guardrails: no child may force a responsive region wider than its container. */
.ca-container img,.ca-container svg,.ca-container canvas{max-width:100%}
.ca-container>*{min-width:0}


/* ============================================================
   CHORD ATLAS CONTAINER LAYOUT — 9.5.1

   Product principle: Chord Atlas is a collection of musical content
   containers, not an administrative dashboard. Controls, the Circle
   of Fifths, scale information, the fretboard, progression results
   and the harmonic map are ordinary containers with a sensible
   intrinsic minimum width. The page places them; it does not wrap
   them in a permanent/collapsible sidebar, squeeze them into 48px
   strips, or hide them because the viewport is narrow.

   Mechanism: each pane is a single flex-wrap row. Wide enough -> its
   containers sit side by side, each at a comfortable width, without
   stretching to fill unused space. Not wide enough -> flex-wrap
   stacks them, each approximately full width, in ordinary document
   flow. That one mechanism (flex-wrap + a per-container min-width)
   is the only responsive transition most panes need — no rail, no
   collapse-to-icon state, no separate tablet/phone breakpoints.
   ============================================================ */

.progression-workspace,
.harmonic-map-layout.stage8,
.scale-workspace{
  display:flex;
  flex-wrap:wrap;
  align-items:flex-start;
  gap:clamp(16px,2vw,28px);
  max-width:var(--ca-pane-max-width);
  margin-inline:auto;
}

/* Controls: readable width, never a squeezed sidebar, never the
   whole row on a wide screen. */
#progressionControlRail,
#mapControlRail,
.scale-control-rail{
  flex:1 1 300px;
  min-width:min(260px,100%);
  max-width:360px;
}

.progression-stage{
  flex:3 1 560px;
  min-width:min(320px,100%);
}

/* The harmonic map visualization has a natural size (the SVG itself
   is already capped at max-height:760px) — more viewport width should
   not inflate the card around it. flex-grow:0 + max-width stop the
   growth; whatever room that frees up either stays visible as canvas
   or (>=900px, see the grid rules further down) goes to the Play
   Strip / journey controls instead. */
.harmonic-stage-stack{
  flex:0 1 800px;
  min-width:min(320px,100%);
  max-width:820px;
}

/* Scale Practice: Circle of Fifths + scale info sit beside the
   control panel; the fretboard is the wide item. Like the harmonic
   map above, this column's content (a small circle, a text panel)
   has a natural size, so it does not grow just because the row has
   room — flex-grow:0 here is what lets .neck-column (which SHOULD
   grow; horizontal fretboards benefit from real width) claim any
   freed space instead. */
.scale-controls-column{
  flex:0 1 720px;
  min-width:min(300px,100%);
  max-width:760px;
}

/* The two panels inside that column each get their own cap too, so
   that even when the column collapses to a single stacked panel on
   a mid-width container, neither one stretches into a full-width
   white rectangle around a much smaller graphic/text block. */
.scale-key-panel{
  max-width:390px;
}
.scale-choice-panel{
  max-width:520px;
}

/* The fretboard: orientation is a property of THIS container alone.
   Vertical uses the neck-width slider (--neck-column-width, kept in
   sync by syncScaleLayoutWidth()); horizontal forces a full-width
   row of its own via flex-basis:100%, which flex-wrap cannot place
   next to any preceding sibling — a plain CSS row-break, not a
   media query, and not a change to any other container's geometry. */
.neck-column{
  flex:2 1 var(--neck-column-width);
  min-width:min(320px,100%);
  max-width:100%;
}
.scale-workspace.neck-horizontal .neck-column{
  flex-basis:100%;
}


/* ============================================================
   HARMONIC MAP — Play Strip promoted, composition changes by width

   Play Strip (#mapJourneyPanel) is a primary player interaction, not
   an appendage stacked below the visualization; the journey/
   generation controls in #mapControlRail are secondary. Markup order
   stays controls -> map -> play strip -> stats (so source order and
   screen-reader flow don't change); visual order/placement is set
   here per breakpoint with `order` (flex) and `grid-area` (grid),
   never by moving elements around in the template.
   ============================================================ */

/* Phone/narrow (<900px): the unconditional flex-wrap row above
   already stacks anything that doesn't fit; this just guarantees
   Play Strip and the stats row each get their own full-width line,
   and reorders the stack so the thing a player actually taps while
   holding an instrument comes before the (secondary/advanced)
   controls that generated the journey. */
#mapJourneyPanel,
.harmonic-lower-grid{
  flex-basis:100%;
}
#mapJourneyPanel{ order:1; grid-area:play; }
.harmonic-stage-stack{ order:2; grid-area:map; }
#mapControlRail{ order:3; grid-area:journey; }
.harmonic-lower-grid{ order:4; grid-area:lower; }

/* Normal desktop / tablet: a compact multi-column arrangement.
   Controls stay left of the visualization (as before); Play Strip
   gets its own full-width, prominent row underneath instead of
   trailing the map as an appendage. */
@media(min-width:900px){
  .harmonic-map-layout.stage8{
    display:grid;
    grid-template-columns:minmax(280px,360px) minmax(0,1fr);
    grid-template-areas:
      "journey map"
      "play    play"
      "lower   lower";
    align-items:start;
  }
  /* .harmonic-lower-grid's own pre-existing margin:0 auto (for centering
     it as an ordinary block when its max-width happened to bind) means
     "auto" inline margins, which override grid's default stretch and
     shrink the item to fit-content instead of spanning the full "lower"
     area. Neutralize just the inline margins so it stretches like any
     other full-width grid row again; the top/bottom margin is unchanged. */
  .harmonic-lower-grid{
    margin-left:0;
    margin-right:0;
  }
}

/* Very wide desktop: take advantage of the room by repositioning,
   not stretching. Play Strip is promoted to a prominent top row;
   the map keeps its natural/max size (.harmonic-stage-stack's own
   max-width, set above) instead of ballooning into the freed space,
   and journey controls become a compact card beside it. */
@media(min-width:1600px){
  .harmonic-map-layout.stage8{
    grid-template-columns:minmax(0,1fr) minmax(280px,360px);
    grid-template-areas:
      "play    play"
      "map     journey"
      "lower   lower";
  }
}


/* ============================================================
   PARAMETERS / TRANSPORT — reusable vocabulary

   PARAMETERS answers "what am I exploring / how is it displayed?"
   and is always one card with two subsections:
     - Visuals: display-oriented (pattern/window, colors, labels,
       orientation, sizing) -- does not change the musical material.
     - Musical Parameters: changes the musical material itself.
   Both subsections start expanded -- important controls are not
   hidden behind a closed accordion on first load.

   TRANSPORT answers "play / stop / tempo" and is deliberately NOT
   part of Parameters: its own always-visible card (never a closed
   <details>, since hiding Play behind an accordion defeats the
   point), with its primary Play control(s) using the theme's accent
   color so "where do I press to hear this" is unambiguous. Stop and
   other secondary transport actions stay visually quiet.

   This section only reshapes Scale Practice's markup for now (see
   the process notes for this pass). Progressions and the Harmonic
   Map keep their existing sidebars; they only pick up the shared
   .transport-play button treatment below, applied directly to their
   existing Play buttons with no structural change.
   ============================================================ */

.parameters-card{
  padding:0;
  overflow:hidden;
}
.parameters-card-head{
  padding:14px 14px 10px;
}
.parameters-card-head h2{
  margin:2px 0 0;
  font-size:18px;
}
.parameters-section{
  border-top:1px solid var(--line);
}
.parameters-section:first-of-type{
  border-top:0;
}
.parameters-section summary{
  cursor:pointer;
  list-style:none;
  padding:12px 14px;
  display:flex;
  align-items:center;
  gap:10px;
}
.parameters-section summary::-webkit-details-marker{
  display:none;
}
.parameters-section summary:after{
  content:"+";
  font-size:18px;
  color:var(--brand);
  margin-left:auto;
}
.parameters-section[open] summary:after{
  content:"\2212";
}
.parameters-section-label{
  font-weight:950;
  font-size:14px;
  text-transform:uppercase;
  letter-spacing:.04em;
  color:var(--brand);
}
.parameters-section-body{
  padding:2px 14px 14px;
  display:flex;
  flex-direction:column;
  gap:12px;
}
.parameters-section-note{
  margin:0;
}
/* Legend, nested inside Visuals rather than its own floating card. */
.parameters-section-body .legend-panel{
  font-size:12px;
  line-height:1.8;
  padding-top:10px;
  border-top:1px solid var(--line);
}

/* Transport is a compact control object, not a workspace-filling one:
   on desktop it wraps its useful content instead of stretching to
   fill whatever grid track or flex row it happens to be placed in
   (the same rule that governs the Circle of Fifths / vertical-neck
   cards) -- Scale Practice additionally happens to place it inside
   the Parameters rail, which is what gives it the "aligned with the
   rail" width in practice, not a Scale-Practice-specific override.
   On narrow/mobile, where everything is a single stacked column
   anyway, full width of that column *is* the useful width, so it
   matches its stacked neighbors instead of looking arbitrarily
   narrower than them. This mobile/desktop split is the reusable
   default for any screen that adopts Transport. */
.transport-card{
  width:100%;
  max-width:100%;
  margin-bottom:var(--ca-space-4, 1rem);
}
@media(min-width:900px){
  .transport-card{
    width:fit-content;
  }
}
.transport-card-head{
  display:flex;
  align-items:baseline;
  gap:10px;
}
.transport-card-head h2{
  margin:2px 0 0;
  font-size:18px;
}
/* Controls stack as a coherent group -- a button row, then tempo
   underneath -- rather than space-between spreading BPM to a far
   edge that only exists because the card used to be much wider. */
.transport-body{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:10px;
  margin-top:8px;
}
.transport-controls{
  display:flex;
  gap:8px;
  flex-wrap:wrap;
}
.transport-tempo{
  display:flex;
  align-items:center;
  gap:8px;
}

/* The primary Play control: its own semantic color (--transport-play,
   see style.css :root), not --accent (Support/CTA) and not --brand
   (primary generate/navigate actions) -- Play is visually prominent
   without being mistaken for either of those other two categories. */
.transport-play{
  background:var(--transport-play);
  border-color:color-mix(in srgb,var(--transport-play) 75%,#000);
  color:#fff;
  font-weight:900;
}
.transport-play:hover{
  filter:brightness(1.05);
}
.transport-play:disabled{
  opacity:.55;
  cursor:not-allowed;
}
:root[data-theme="midnight"] .transport-play{
  color:#08131b;
}

/* ============================================================
   SCALE PRACTICE — orientation changes the desktop composition

   The left rail is one column holding two stacked, independently-
   sized cards -- Transport (compact) above Parameters (can be tall)
   -- in normal document flow, so their combined height never has to
   line up against the content column's row heights (a shared grid
   row would force whichever side is shorter to sit inside a
   too-tall row with dead space below it). The rail as a whole is
   still a single grid item beside the content column.

   Vertical (unconditional/base -- see the fretboard-orientation
   tests, which require vertical to stay the base state rather than
   a parallel .neck-vertical selector): normal desktop is the rail
   beside a single content column (Key+Scale, stacked, above the
   vertical neck); very wide desktop splits that content column so
   Key+Scale and the neck sit side by side.

   Horizontal (.scale-workspace.neck-horizontal override, higher
   specificity so it wins over the width tiers below): rail | Key+Scale
   (side by side), with the horizontal fretboard directly beneath
   that row instead of far down the page -- unconditionally, at every
   desktop width, since a horizontal fretboard always wants its own
   full-width row.

   The neck's column/track is sized from --neck-column-width (the
   same variable the flex fallback and syncScaleLayoutWidth() already
   keep in sync with the neck-width slider), not an arbitrary
   fraction -- a fixed 0-minimum fr track would let the grid squeeze
   the column narrower than the actual fretboard content and clip it
   (this page has overflow-x:hidden), regardless of viewport width.
   ============================================================ */

@media(min-width:900px){
  .scale-workspace{
    display:grid;
    grid-template-columns:minmax(280px,360px) minmax(var(--neck-column-width),1fr);
    grid-template-areas:
      "params key"
      "params neck";
    align-items:start;
  }
  .scale-control-rail{ grid-area:params; }
  .scale-controls-column{ grid-area:key; }
  .neck-column{ grid-area:neck; }

  /* Neck Width means physical neck THICKNESS in either orientation: in
     vertical it drives the horizontal dimension (--neck-column-width,
     above), in horizontal it drives the fretboard's VERTICAL dimension
     (see drawHorizontalFretboard() in app.js). A horizontal fretboard's
     LENGTH is governed by its visible fret span and the workspace it's
     given -- not by that slider -- so its column must not inherit a
     minimum derived from --neck-column-width (which is slider-driven). */
  .scale-workspace.neck-horizontal{
    grid-template-columns:minmax(280px,360px) minmax(480px,1fr);
    grid-template-areas:
      "params key"
      "params fret";
  }
  .scale-workspace.neck-horizontal .neck-column{ grid-area:fret; }
}

/* Very wide desktop: enough room to split the content column instead
   of stacking within it. Scoped to :not(.neck-horizontal) -- otherwise
   this 3-column definition would leak into horizontal mode too (same
   property, and an unqualified .scale-workspace selector still wins
   when neck-horizontal's own rule above never redeclares
   grid-template-columns), leaving column 3 an unused, unnamed track
   and capping the horizontal fretboard's row at column 2's width
   instead of the full remaining space. */
@media(min-width:1300px){
  .scale-workspace:not(.neck-horizontal){
    grid-template-columns:minmax(280px,360px) minmax(280px,420px) minmax(var(--neck-column-width),1fr);
    grid-template-areas:
      "params key neck";
  }
}

/* Vertical neck: the SVG already gets an explicit pixel width from
   the neck-width slider (see setupFretboardSvg() / drawVerticalFretboard()
   in app.js) -- the card wrapping it should follow that width instead
   of stretching to its grid track just because the track is wider. */
.neck-shell{
  width:max-content;
  max-width:100%;
}
.scale-workspace.neck-horizontal .neck-shell{
  width:100%;
}


/* ============================================================
   TUNER — same card/canvas language, no Transport (it listens,
   it doesn't play back). Parameters reuses the exact same
   .parameters-card/.parameters-section markup and styling as Scale
   Practice; only the tuner-specific bits (spacing inside the floating
   module, the holding-state dim, and the debug grid) are added here.
   ============================================================ */

.tuner-parameters-card{
  margin-top:14px;
}

/* HOLDING: the engine is showing the last reliable reading rather than
   a fresh one (see tuner-engine.js). Dim rather than blank the display,
   so a decaying note fades out gracefully instead of flashing an alarm. */
#tunerDisplay.tuner-holding{
  opacity:.6;
  transition:opacity .25s ease;
}
#tunerDisplay{
  transition:opacity .25s ease;
}

.tuner-debug-panel{
  margin-top:14px;
  background:color-mix(in srgb, var(--card) 92%, #000);
}
.tuner-debug-grid{
  margin:10px 0 0;
  display:grid;
  grid-template-columns:auto 1fr;
  gap:4px 10px;
  font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
.tuner-debug-grid dt{
  color:var(--muted);
  font-weight:700;
}
.tuner-debug-grid dd{
  margin:0;
  color:var(--ink);
  text-align:right;
}
