/* ===========================================================================
   COMPOSER — controls, voice-leading analysis, word events, instruments.
   Loaded after cipher.css and library.css.

   The voice-leading display is an analytical figure, not an effect: hairlines
   on paper, one per voice, drawn between the notes they connect. Words are
   typographic objects rather than cards — the word is the subject, the
   analysis is apparatus set beside it.
   =========================================================================== */

/* ---------------------------------------------------------------- controls */

.controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 0 clamp(16px, 2vw, 28px);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-hair);
}

.switches {
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(18px, 2.6vw, 36px);
  padding: 16px 0 4px;
}

.voice-ranges, .custom-weights {
  border-top: 1px solid var(--line-soft);
  padding: 16px 0 4px;
  margin: 8px 0 0;
}
.voice-ranges[hidden], .custom-weights[hidden] { display: none; }

.range-row { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.range-name {
  font-family: var(--f-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  width: 84px;
  flex: none;
}
.range-row select { width: auto; min-width: 84px; }
.range-to { color: var(--fg-3); font-size: 11px; font-family: var(--f-mono); }

.weight-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 0 clamp(16px, 2vw, 28px);
}

/* ------------------------------------------------- voice-leading figure */

/* The grid and its overlay share a positioning context so the measured
   coordinates line up. */
#voice-grid { position: relative; }

.vgrid {
  display: grid;
  grid-template-columns: 5.5rem repeat(var(--words), minmax(92px, 1fr));
  overflow-x: auto;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.vgrid > * { padding: 10px 12px 10px 0; }

.vgrid-corner, .vgrid-label {
  font-family: var(--f-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  display: flex;
  align-items: center;
}

.vgrid-word {
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--fg);
  display: block;
  border-bottom: 1px solid var(--line-soft);
  transition: color .16s var(--ease);
}
.vgrid-word b {
  display: block;
  font-family: var(--f-sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .1em;
}
.vgrid-word:hover { color: var(--green); }
.vgrid-word.is-active { color: var(--green); }
/* Marked with a rule as well as a hue. */
.vgrid-word.is-active { border-bottom: 2px solid var(--green); }

.vgrid-patricia {
  display: block;
  font-family: var(--f-mono);
  font-size: 10.5px;
  color: var(--fg-3);
  margin-top: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vgrid-cell {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-family: var(--f-mono);
  border-bottom: 1px solid var(--line-hair);
}
.vgrid-cell.is-active { background: rgba(86, 217, 138, .07); }

.vgrid-note { font-size: 16px; color: var(--fg); }
.vgrid-note sub { font-size: 9px; color: var(--fg-3); }
.vgrid-rest { color: var(--fg-3); }

/* Movement is stated in glyph + number; the hue only reinforces it. */
.vgrid-move { font-size: 10.5px; letter-spacing: .02em; color: var(--fg-3); }
.vgrid-move.is-hold { color: var(--green-2); }
.vgrid-move.is-up { color: var(--green); }
.vgrid-move.is-down { color: var(--flat); }

.vgrid-summary {
  display: grid;
  gap: 4px;
  margin-top: 16px;
  font-size: 13px;
  color: var(--fg-3);
}
.vgrid-step b {
  color: var(--fg-2);
  font-family: var(--f-mono);
  font-weight: 500;
  margin-right: 10px;
}
.vgrid-warn { color: var(--green); }

/* --------------------------------------------------------------- trails */

.vtrails { position: absolute; left: 0; top: 0; pointer-events: none; overflow: visible; }

.vtrail {
  fill: none;
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .5;
  /* Drawn in, once, then left alone. */
  stroke-dasharray: var(--len, 2000);
  stroke-dashoffset: var(--len, 2000);
  animation: trail-draw .9s var(--ease) forwards;
  animation-delay: var(--delay, 0s);
}
.vtrail-0 { stroke: var(--green); }
.vtrail-1 { stroke: var(--flat); }
.vtrail-2 { stroke: var(--green-2); }
.vtrail-3 { stroke: var(--fg-3); }
.vtrail-4 { stroke: #c48598; }
.vtrail-5 { stroke: #c2a05e; }

@keyframes trail-draw { to { stroke-dashoffset: 0; } }

/* ------------------------------------------------------------------ melody */

.melody { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0; }
.melody-arrow { align-self: center; color: var(--fg-3); font-size: 14px; padding: 0 16px; }

.melody-word {
  background: none;
  border: 0;
  border-left: 1px solid var(--line-soft);
  padding: 4px 20px 10px 16px;
  cursor: pointer;
  text-align: left;
  transition: border-color .16s var(--ease);
}
.melody-word:hover { border-left-color: var(--fg); }
.melody-word.is-active { border-left: 2px solid var(--green); }

.melody-label {
  display: block;
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 8px;
}
.melody-notes { display: flex; flex-wrap: wrap; }
.melody-shift {
  display: block;
  margin-top: 6px;
  font-family: var(--f-mono);
  font-size: 10px;
  color: var(--fg-3);
}

/* ---------------------------------------------------------------- word nav */

.word-nav {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-hair);
  margin-bottom: 16px;
}

.wordchips { display: flex; flex-wrap: wrap; gap: 0 22px; flex: 1; }

.wordchip {
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--fg-3);
  font-family: var(--f-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 4px 0;
  cursor: pointer;
  transition: color .16s var(--ease);
}
.wordchip:hover { color: var(--fg); }
.wordchip.is-active { color: var(--fg); border-bottom-color: var(--green); }

.word-context { margin-bottom: 26px; }

.motion {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 14px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line-hair);
  font-size: 13px;
  color: var(--fg-2);
}
.motion b {
  font-family: var(--f-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  min-width: 200px;
}
.motion-moves { display: flex; gap: 10px; }
.motion-chip { font-family: var(--f-mono); font-size: 12px; color: var(--fg-3); }
.motion-chip.is-hold { color: var(--green-2); }
.motion-chip.is-up { color: var(--green); }
.motion-chip.is-down { color: var(--flat); }
.motion-total { font-family: var(--f-mono); font-size: 11.5px; color: var(--fg-3); }

/* --------------------------------------------- words as typographic objects */

.word-panels { display: grid; gap: 0; }

.wordcard {
  padding: 18px 0;
  border-top: 1px solid var(--line-hair);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 8px clamp(24px, 4vw, 56px);
  align-items: start;
}
.wordcard:first-child { border-top: 0; }
/* The current event is marked by a rule in the margin, not a coloured card. */
.wordcard.is-active { box-shadow: inset 2px 0 0 var(--green); padding-left: 14px; }

.wordcard-head {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: left;
}
.wordcard-head b {
  font-family: var(--f-sans);
  font-size: clamp(19px, 2.4vw, 26px);
  font-weight: 600;
  letter-spacing: .09em;
  line-height: 1;
  color: var(--fg);
}
.wordcard.is-active .wordcard-head b { color: var(--green); }
.wordcard-chord {
  font-family: var(--f-mono);
  font-size: 14px;
  color: var(--fg-3);
}

.wordcard-patricia {
  grid-column: 1;
  display: flex;
  flex-wrap: wrap;
  margin-top: 14px;
}
.wordcard-patricia .cell-value { font-size: 20px; }

/* A fixed-width label with the values flowing beside it. Grid columns would
   drop each note into its own cell — these have to run as a line. */
.wordcard-meta, .wordcard-voicing {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 12px;
  margin: 0 0 8px;
  font-family: var(--f-mono);
  font-size: 12.5px;
  color: var(--fg-2);
  line-height: 1.7;
}
.wordcard-meta b, .wordcard-voicing b {
  flex: 0 0 8.5rem;
  font-family: var(--f-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
}
/* The runner-up chord names. Deliberately quieter than the recommendation
   above them — they are alternatives, not competing headlines. */
.wordcard-also { color: var(--fg-3); margin-top: -4px; }
.wordcard-inversion { color: var(--fg-3); }
.wordcard-note { color: var(--fg); }
.wordcard-note sub { font-size: 9px; color: var(--fg-3); }

.wordcard .instrument, .wordcard .guitar-wrap, .wordcard .guitar-meta {
  grid-column: 2;
}

/* ------------------------------------------------------- piano and staff */

.instrument { overflow-x: auto; padding: 6px 0 10px; }
.piano-svg { min-width: 340px; display: block; }
.staff-svg { min-width: 320px; display: block; }

/* A technical diagram: thin lines, no fills beyond the sounding keys. */
.key-white { fill: #cdd4d1; stroke: #0a0c0b; stroke-width: .8; }
.key-black { fill: #141917; stroke: #0a0c0b; stroke-width: .8; }
.key-white.is-on { fill: var(--green); }
.key-black.is-on { fill: var(--green-2); }
.key-label { font-family: var(--f-mono); font-size: 8.5px; fill: #0a0c0b; }
.key-octave { font-family: var(--f-mono); font-size: 8.5px; fill: var(--fg-3); }

.staff-line, .staff-ledger { stroke: var(--fg-2); stroke-width: .8; }
.staff-note { fill: var(--green); }
.staff-clef { font-size: 40px; fill: var(--fg-2); }
.staff-accidental { font-size: 15px; fill: var(--fg-2); }
.staff-caption { font-family: var(--f-mono); font-size: 9.5px; fill: var(--fg-3); }

/* --------------------------------------------------------- chord diagram */

.guitar-wrap { max-width: 180px; margin: 10px 0 4px; }

.chordbox { display: block; }
.cb-fret { stroke: var(--fg-3); stroke-width: .8; }
.cb-string { stroke: var(--fg-3); stroke-width: .8; }
.cb-nut { fill: var(--fg-2); }
.cb-dot { fill: var(--fg); }
.cb-root-dot { fill: var(--green); }
.cb-open { fill: none; stroke: var(--fg); stroke-width: 1.2; }
.cb-open.cb-root { stroke: var(--green); stroke-width: 1.8; }
.cb-barre { fill: var(--fg-2); opacity: .8; }
.cb-finger { font-family: var(--f-mono); font-size: 9px; fill: #0a0c0b; }
.cb-mark { font-family: var(--f-mono); font-size: 11px; fill: var(--fg-3); }
.cb-position { font-family: var(--f-mono); font-size: 9.5px; fill: var(--fg-3); }
.cb-stringname { font-family: var(--f-mono); font-size: 8.5px; fill: var(--fg-3); }
.cb-degree { font-family: var(--f-mono); font-size: 8.5px; fill: var(--green); }

.guitar-none, .guitar-missing { color: var(--green); font-size: 13px; font-style: italic; }
.guitar-meta {
  margin: 4px 0 0;
  font-family: var(--f-mono);
  font-size: 11.5px;
  color: var(--fg-3);
}
.guitar-barre { color: var(--fg-2); }

/* ------------------------------------------------------------- responsive */

@media (max-width: 900px) {
  .wordcard { grid-template-columns: 1fr; }
  .wordcard-meta, .wordcard-voicing,
  .wordcard .instrument, .wordcard .guitar-wrap, .wordcard .guitar-meta { grid-column: 1; }
  .motion b { min-width: 0; flex-basis: 100%; }
  .vgrid { grid-template-columns: 4.4rem repeat(var(--words), minmax(84px, 1fr)); }
  .melody-arrow { display: none; }
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  .vtrail { animation: none; stroke-dasharray: none; stroke-dashoffset: 0; }
  .cat-dot { transition: none; }
}

/* ===========================================================================
   PROGRESSIONS — the cipher chain.
   ---------------------------------------------------------------------------
   The chain is the workspace's argument in one shape: a letter is a value, a
   value is a degree, a degree is a chord. It reads down each column, so the
   whole derivation for one letter is a glance rather than a search across five
   panels.
   =========================================================================== */

.hp-modes { margin-bottom: 12px; }

.hp-input {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0 clamp(10px, 2vw, 20px);
}
.hp-input .field-wide { flex: 1 1 260px; }
.hp-input #hp-input {
  font-family: var(--f-mono);
  font-size: clamp(14px, 2.2vw, 17px);
  letter-spacing: .06em;
}
.hp-input .act { margin-bottom: 12px; }

/* How the field read what was typed. Said, not assumed silently — if the guess
   is wrong the user can see that it was a guess. */
.hp-kind {
  margin-bottom: 16px;
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.hp-chain-wrap { overflow-x: auto; margin: 4px 0 14px; }

.hp-chain { display: inline-grid; gap: 1px; min-width: 100%; }
.hp-chain[hidden] { display: none; }

.hp-chain-row {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--line-hair);
}
.hp-chain-label {
  flex: none;
  width: 7ch;
  /* Sticky, so the row still says what it is once the chain is scrolled
     sideways — which on a phone it always is. The background is what stops it
     being read through by the cells passing underneath. */
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--bg);
  border-right: 1px solid var(--line-soft);
  padding: 5px 8px 5px 0;
  font-family: var(--f-sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-3);
  align-self: center;
}

.hp-chain-cell {
  flex: 1 1 0;
  min-width: 5.5ch;
  padding: 5px 6px;
  background: none;
  border: 0;
  border-left: 1px solid var(--line-hair);
  font-family: var(--f-mono);
  font-size: 12.5px;
  color: var(--fg-2);
  text-align: center;
  cursor: pointer;
  transition: background .12s var(--ease), color .12s var(--ease);
}
.hp-chain-cell:hover { background: var(--bg-1); color: var(--fg); }
.hp-chain-cell:focus-visible { outline: 1px solid var(--green-2); outline-offset: -1px; }
.hp-chain-cell.is-on { background: rgba(86, 217, 138, .1); color: var(--fg); }
.hp-chain-cell.is-playing { background: rgba(122, 226, 160, .22); color: var(--fg); }

.hp-chain-letter { color: var(--fg); font-size: 14px; }
.hp-chain-value { color: var(--green-2); }
.hp-chain-degree { color: var(--green); }
.hp-chain-chord { color: var(--flat); }

/* A chord borrowed into the key rather than built by the scale. Dashed, not
   dimmed: it is a different claim, not a weaker one. */
.hp-chain-chord.is-borrowed {
  border-bottom: 1px dashed var(--amber);
  color: var(--amber);
}

.hp-chain-joins { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 8px 0 0 7ch; }
.hp-join { font-family: var(--f-mono); font-size: 11px; color: var(--fg-3); }

/* ------------------------------------------------------------- analysis */

.hp-fact { display: flex; flex-wrap: wrap; gap: 2px 14px; padding: 3px 0; }
.hp-fact-term {
  flex: none;
  width: 9ch;
  font-family: var(--f-sans);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-3);
}
.hp-fact-value { font-family: var(--f-mono); font-size: 12.5px; color: var(--fg-2); }

.hp-story {
  margin: 12px 0 0;
  padding-left: calc(9ch + 14px);
  font-family: var(--f-sans);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--fg-2);
}

/* -------------------------------------------------------------- explore */

.hp-reverse {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin: 10px 0;
}
.hp-reverse-step {
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  border-left: 1px solid var(--line-soft);
}
.hp-reverse-numeral { font-family: var(--f-mono); font-size: 11px; color: var(--green); }
.hp-reverse-symbol { font-family: var(--f-mono); font-size: 15px; color: var(--fg); }
.hp-reverse-value { font-family: var(--f-mono); font-size: 12px; color: var(--green-2); }
.hp-reverse-letters {
  font-family: var(--f-mono);
  font-size: 13px;
  letter-spacing: .18em;
  color: var(--fg-2);
}

/* The progression's roots, shown on the map. */
.circle-cell.in-progression .circle-face { stroke: var(--flat); stroke-width: 1.8; }

@media (max-width: 620px) {
  .hp-chain-label { width: 6.5ch; font-size: 8px; padding-right: 5px; }
  .hp-chain-cell { font-size: 11.5px; min-width: 4.5ch; padding: 5px 3px; }
  .hp-chain-joins { padding-left: 0; }
  .hp-story { padding-left: 0; }
  .hp-fact-term { width: 100%; }
}

/* A chord shown as its notes because the vocabulary has no name for it. */
.hp-cell-symbol.is-unnamed { font-size: 11.5px; color: var(--fg-2); border-bottom: 1px dashed var(--line); }
