/* ===========================================================================
   PHYTHAGRAM — core styling.
   ---------------------------------------------------------------------------
   A cypher terminal. Near-black ground, neutral light text, and terminal green
   used only where it means something: the active workspace, the selected
   cipher, Patricia values, playback state. Most of the screen is not green —
   an interface glowing uniformly is a costume, not a tool.

   Two typefaces:
     IBM Plex Mono  every musical value, every piece of metadata, most controls
     IBM Plex Sans  headings, prose, navigation

   Green is never the only signal. Every state it marks also changes a caret,
   a rule, a weight or a glyph, so the interface survives greyscale.
   =========================================================================== */

:root {
  /* ground */
  --bg:        #0a0c0b;
  --bg-1:      #101413;
  --bg-2:      #161b19;
  --bg-3:      #1e2422;

  /* text */
  --fg:        #d8dedb;
  --fg-2:      #a3aca8;
  --fg-3:      #7c8582;

  /* the one accent */
  --green:     #56d98a;
  --green-2:   #3fa869;
  --green-dim: #2c6b46;

  --amber:     #c8a24a;
  --red:       #d9584f;

  --accent:     var(--green);
  --accent-hot: #7ae2a0;
  --flat:       #6fb8d8;
  --sharp:      var(--green);
  --alert:      var(--red);
  --good:       var(--green);

  --line:      rgba(216, 222, 219, .26);
  --line-soft: rgba(216, 222, 219, .13);
  --line-hair: rgba(216, 222, 219, .07);
  --line-hot:  var(--green-2);

  /* Categories are keyed in muted tones; the library is an index, not a
     spectrum. Green stays reserved for state. */
  --cat-chromatic:       var(--green);
  --cat-classic:         #6fb8d8;
  --cat-modal:           #8fbf7a;
  --cat-barry-harris:    var(--amber);
  --cat-melodic-minor:   #7aa6c8;
  --cat-harmonic-minor:  #9b8fc4;
  --cat-harmonic-major:  #b088bd;
  --cat-bebop:           #c2a05e;
  --cat-pentatonic:      #6dbfae;
  --cat-blues:           #6a97c9;
  --cat-symmetric:       #c48598;
  --cat-messiaen:        #bd7f95;
  --cat-double-harmonic: #c58f6a;
  --cat-neapolitan:      #93bb7d;
  --cat-hungarian:       #bfa269;
  --cat-spanish:         #cc8a68;
  --cat-synthetic:       #78a8c4;
  --cat-world:           #c0a86b;
  --cat-custom:          #9aa39f;

  --f-mono: "IBM Plex Mono", "SF Mono", ui-monospace, monospace;
  --f-sans: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;

  --ease: cubic-bezier(.22, .61, .36, 1);
  --gutter: clamp(14px, 3vw, 34px);
  --measure: 1240px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--f-mono);
  font-size: 13.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  font-variant-ligatures: none;
}

/* The ambient layer sits behind everything and touches nothing. */
#ambient-canvas {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.bar, .statusbar, main { position: relative; z-index: 1; }

/* ----------------------------------------------------------------- a11y */

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

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--green); color: var(--bg);
  padding: 10px 18px; z-index: 60;
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
}
.skip:focus { left: 0; }

:focus-visible { outline: 1px solid var(--green); outline-offset: 2px; }

/* --------------------------------------------------------------- header */

.bar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg);
  border-bottom: 1px solid var(--line-soft);
}

.bar-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  align-items: stretch;
  gap: 0 clamp(14px, 3vw, 40px);
  min-height: 40px;
}

/* One word, one colour. The wordmark is split into per-letter cells by
   wordmark.js so it can show the classic reduction cipher on hover; the cells
   sit side by side with no gap, so it still reads as a single word. */
.brand {
  display: flex;
  align-items: center;
  gap: 0;
  font-family: var(--f-sans);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg);
  white-space: nowrap;
  cursor: default;
}

/* Each cell is sized by its letter, and the digit is laid over the top of it.
   That is what lets the word turn into numbers without a single character
   moving — the alternative, swapping text content, reflows the whole header. */
.brand-ch {
  position: relative;
  display: inline-block;
}
.brand-letter,
.brand-digit { transition: opacity .16s var(--ease); }

.brand-digit {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  /* The value is the one thing on the wordmark that is not the name, so it
     takes the colour the system reserves for cipher values everywhere else. */
  color: var(--green);
  /* Digits are narrower than the capitals they replace, so they are centred
     in the space the letter left behind. */
  letter-spacing: 0;
}

/* Per letter, not per word: each character answers for itself, so running
   along the wordmark decodes it one letter at a time. */
.brand-ch:hover .brand-letter { opacity: 0; }
.brand-ch:hover .brand-digit  { opacity: 1; }

/* ---------------------------------------------------------------- tabs */

.nav {
  display: flex;
  gap: 0 clamp(10px, 2vw, 24px);
  overflow-x: auto;
  scrollbar-width: none;
  flex: 1;
}
.nav::-webkit-scrollbar { display: none; }

.navtab {
  position: relative;
  background: none;
  border: 0;
  padding: 0 2px;
  color: var(--fg-3);
  font-family: var(--f-sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  transition: color .14s var(--ease);
}
.navtab:hover { color: var(--fg); }
.navtab[aria-selected="true"] { color: var(--green); }
/* A rule under the active tab, so state is not colour alone. */
.navtab[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--green);
}

.bar-right {
  display: flex;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
}
.ambient-ctl select {
  border: 0;
  background: none;
  color: var(--fg-3);
  font-size: 10.5px;
  letter-spacing: .1em;
  padding: 0;
  width: auto;
  min-width: 0;
  cursor: pointer;
}
.ambient-ctl select:hover { color: var(--fg); }

.sys {
  font-size: 10.5px;
  letter-spacing: .12em;
  color: var(--green-2);
}
.sys::before { content: "● "; color: var(--green); font-size: 8px; vertical-align: 2px; }

/* ------------------------------------------------------------ statusbar */

.statusbar { border-bottom: 1px solid var(--line-hair); background: var(--bg-1); }
.statusbar-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 5px var(--gutter) 6px;
  display: flex;
  flex-wrap: wrap;
  gap: 0 10px;
  font-size: 10.5px;
  letter-spacing: .08em;
  color: var(--fg-3);
  overflow-x: auto;
  scrollbar-width: none;
}
.statusbar-inner::-webkit-scrollbar { display: none; }
.st-item { white-space: nowrap; }
.st-key { color: var(--fg-3); }
.st-slash { color: var(--line); margin: 0 4px; }
.st-val { color: var(--green); }
.st-sep { color: var(--line); }

/* ------------------------------------------------------------ workspace */

main { max-width: var(--measure); margin: 0 auto; padding: 0 var(--gutter) 60px; }

.wsp { padding: 18px 0 0; }
.wsp[hidden] { display: none; }
.wsp:focus { outline: none; }

.block { padding: 0 0 18px; }

.lbl {
  margin: 0 0 10px;
  font-family: var(--f-sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--fg-3);
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.lbl-meta {
  font-family: var(--f-mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--fg-3);
}

.sub {
  margin: 22px 0 8px;
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.note { margin: 0 0 10px; font-size: 12px; color: var(--fg-2); max-width: 74ch; }

/* Shortcut legend. Quiet by default — it is a reminder, not a control — and it
   wraps rather than scrolling, because a hint that needs scrolling is not one. */
.keys {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  margin: 0 0 14px;
  font-family: var(--f-mono);
  font-size: 11px;
  color: var(--fg-3);
}
.keys kbd {
  font-family: inherit;
  font-size: 10px;
  padding: 1px 5px;
  border: 1px solid var(--rule, #2a312f);
  color: var(--fg-2);
}
.lede {
  margin: 0 0 14px;
  font-family: var(--f-sans);
  font-size: 14px;
  line-height: 1.6;
  color: var(--fg-2);
  max-width: 70ch;
}
.colophon { margin-top: 30px; padding-top: 14px; border-top: 1px solid var(--line-hair); color: var(--fg-3); }

/* ---------------------------------------------------------------- input */

#input {
  width: 100%;
  background: var(--bg-1);
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--green);
  color: var(--fg);
  font-family: var(--f-mono);
  font-size: clamp(18px, 2.6vw, 26px);
  letter-spacing: .04em;
  line-height: 1.3;
  padding: 12px 14px;
  resize: none;
  overflow: hidden;
}
#input::placeholder { color: var(--fg-3); }
#input:focus { outline: none; border-color: var(--line); border-left-color: var(--accent-hot); }

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

.ctl-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0 clamp(12px, 2vw, 24px);
}
.ctl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(122px, 1fr));
  gap: 0 clamp(12px, 2vw, 22px);
}

.field { display: block; margin-bottom: 12px; }
.field-wide { flex: 1 1 220px; }

.field-label {
  display: block;
  font-family: var(--f-sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: 4px;
}

select, input[type="number"], input[type="search"], input[type="text"], textarea {
  width: 100%;
  background: var(--bg-1);
  border: 1px solid var(--line-soft);
  border-radius: 0;
  color: var(--fg);
  font-family: var(--f-mono);
  font-size: 12.5px;
  padding: 6px 8px;
  transition: border-color .14s var(--ease);
}
select:hover, input:hover, textarea:hover { border-color: var(--line); }
select:focus, input:focus, textarea:focus { border-color: var(--green-2); }
select { cursor: pointer; min-width: 9ch; }
input[type="number"] { max-width: 9ch; }
textarea { resize: vertical; line-height: 1.5; }

.switches { display: flex; flex-wrap: wrap; gap: 0 clamp(14px, 2.4vw, 30px); padding: 4px 0 6px; }

.check {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 10px;
  font-family: var(--f-sans);
  font-size: 12px;
  color: var(--fg-2);
  cursor: pointer;
}
.check input {
  appearance: none;
  width: 12px; height: 12px;
  border: 1px solid var(--line);
  background: var(--bg-1);
  cursor: pointer;
  flex: none;
  display: grid;
  place-content: center;
}
.check input:checked { border-color: var(--green-2); }
.check input:checked::after { content: ""; width: 6px; height: 6px; background: var(--green); }
.check:hover { color: var(--fg); }

/* --------------------------------------------------------------- buttons */

.act {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--fg-2);
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 7px 14px;
  cursor: pointer;
  transition: color .14s var(--ease), border-color .14s var(--ease), background .14s var(--ease);
}
.act:hover { color: var(--green); border-color: var(--green-2); background: rgba(86, 217, 138, .07); }
.act:disabled { color: var(--fg-3); border-color: var(--line-hair); cursor: default; }
.act:disabled:hover { background: transparent; color: var(--fg-3); }

.act-go { color: var(--green); border-color: var(--green-2); margin-bottom: 12px; }
.act-go:hover { background: var(--green); color: var(--bg); border-color: var(--green); }

.act-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

.transport { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.transport .act { margin-bottom: 0; }

/* ------------------------------------------------------------ disclosure */

.fold { border-top: 1px solid var(--line-hair); }
.fold > summary {
  list-style: none;
  cursor: pointer;
  padding: 9px 0;
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fg-3);
  display: flex;
  align-items: baseline;
  gap: 10px;
  transition: color .14s var(--ease);
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before {
  content: "▸";
  color: var(--green-2);
  font-size: 9px;
  width: 1ch;
}
.fold[open] > summary::before { content: "▾"; }
.fold > summary:hover { color: var(--fg); }
.fold-body { padding: 2px 0 20px; }

/* --------------------------------------------------------- the word strip */

.wstrip {
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(18px, 3vw, 44px);
  border-top: 1px solid var(--line-hair);
  padding-top: 12px;
}

.wsp-word {
  background: none;
  border: 0;
  padding: 4px 0 10px;
  text-align: left;
  cursor: pointer;
  color: var(--fg-2);
  transition: color .14s var(--ease);
}
.wsp-word:hover { color: var(--fg); }
.wsp-word.is-active { color: var(--green); }

.wsp-name {
  display: block;
  font-family: var(--f-sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .1em;
}
.wsp-caret { color: var(--green); display: inline-block; width: 1ch; }
.wsp-values { display: block; margin-top: 4px; font-size: 15px; color: var(--fg); }
.wsp-word.is-active .wsp-values { color: var(--green); }
.wsp-value .acc-flat { color: var(--flat); }
.wsp-value .acc-sharp { color: var(--sharp); }
.wsp-dot { color: var(--fg-3); margin: 0 5px; }
.wsp-chord { display: block; margin-top: 3px; font-size: 10.5px; color: var(--fg-3); }

/* ------------------------------------------------------- letter mapping */

.lettermap {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0 clamp(14px, 2.4vw, 30px);
}
.lm-group { border-top: 1px solid var(--line-hair); padding: 8px 0 14px; }
.lm-word {
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--green-2);
  margin-bottom: 6px;
}
.lm-row { display: flex; align-items: baseline; gap: 7px; font-size: 13px; line-height: 1.7; }
.lm-letter { color: var(--fg-3); width: 1.4ch; }
.lm-arrow { color: var(--line); font-size: 10px; }
.lm-value { color: var(--green); min-width: 3.6ch; }
.lm-value .acc-flat { color: var(--flat); }
.lm-note { color: var(--fg); }

/* ----------------------------------------------------------------- tabs */

.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0 18px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line-hair);
}
.tab {
  position: relative;
  background: none;
  border: 0;
  padding: 2px 0;
  color: var(--fg-3);
  font-family: var(--f-sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  cursor: pointer;
}
.tab:hover { color: var(--fg); }
.tab[aria-pressed="true"] { color: var(--green); }
.tab[aria-pressed="true"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -7px;
  height: 1px;
  background: var(--green);
}

.view { padding-top: 16px; min-height: 48px; }

/* ------------------------------------------------------------ the cells */

.stream { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px 0; }
.cell {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 0 12px 0 0;
  min-width: 34px;
}
.cell-letter { font-size: 9.5px; letter-spacing: .12em; color: var(--fg-3); }
.cell-value { font-size: 19px; color: var(--fg); white-space: nowrap; line-height: 1.2; }
.cell-value .acc-flat { color: var(--flat); }
.cell-value .acc-sharp { color: var(--sharp); }
.cell-sub { font-size: 9.5px; color: var(--fg-3); }
.cell-sep { align-self: center; color: var(--fg-3); font-size: 12px; }
.cell-other .cell-value { color: var(--fg-3); }
.cell-space { width: 16px; }

.empty { color: var(--fg-3); font-size: 12px; letter-spacing: .1em; }

.plainline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line-hair);
}
.plain { flex: 1 1 240px; font-size: 12px; color: var(--fg-2); word-break: break-word; user-select: all; }

/* --------------------------------------------- the cipher as a document */

.sequence {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  border-top: 1px solid var(--line-hair);
}
.seq-row {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 5px 4px 5px 0;
  border-bottom: 1px solid var(--line-hair);
}
.seq-index { font-size: 10px; color: var(--fg-3); min-width: 2.2ch; }
.seq-value { font-size: 15px; color: var(--green); }
.seq-value .acc-flat { color: var(--flat); }
.seq-value .acc-sharp { color: var(--accent-hot); }
.seq-repeat {
  grid-column: 1 / -1;
  padding: 10px 0 0;
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--green-2);
}

/* --------------------------------------------------------------- alphabet */

.alphabet {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
  border-top: 1px solid var(--line-hair);
  border-left: 1px solid var(--line-hair);
}
.letter {
  border-right: 1px solid var(--line-hair);
  border-bottom: 1px solid var(--line-hair);
  padding: 6px 7px 7px;
}
.letter.cycle-2 { background: rgba(216, 222, 219, .03); }
.letter.cycle-3 { background: rgba(216, 222, 219, .06); }
.letter.cycle-4 { background: rgba(216, 222, 219, .09); }
.letter-char { display: block; font-size: 9.5px; color: var(--fg-3); letter-spacing: .12em; }
.letter-value { display: block; font-size: 15px; color: var(--green); margin-top: 1px; }
.letter-value .acc-flat { color: var(--flat); }
.letter-note { display: block; font-size: 9.5px; color: var(--fg-3); margin-top: 2px; }

/* ------------------------------------------------- the compact strip ----

   The same mapping under the Compose dropdown, where it is a reference and
   not the subject. One line of `A=1  B=♭2  …` that wraps rather than shrinks:
   type small enough to fit any alphabet on one line would be type too small
   to read, and the whole point is that you can read it without opening
   anything.
   ------------------------------------------------------------------------ */

.alphabet-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(10px, 1.6vw, 18px);
  border: 0;
  padding: 2px 0 0;
  /* Its own line-height, so a wrapped strip stays readable rather than
     becoming a solid block of characters. */
  line-height: 1.9;
}
.alphabet-inline .letter {
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
  border: 0;
  padding: 0;
  background: none;
}
.alphabet-inline .letter-char {
  display: inline;
  font-family: var(--f-mono);
  font-size: 11.5px;
  color: var(--fg-2);
  letter-spacing: .04em;
}
.alphabet-inline .letter-eq { color: var(--fg-3); font-size: 11px; }
.alphabet-inline .letter-value {
  display: inline;
  font-family: var(--f-mono);
  font-size: 12.5px;
  margin: 0;
}
/* Cycle shading is a grid device; in a strip it would read as highlighting. */
.alphabet-inline .letter.cycle-2,
.alphabet-inline .letter.cycle-3,
.alphabet-inline .letter.cycle-4 { background: none; }
.alphabet-inline .letter.cycle-2 .letter-char,
.alphabet-inline .letter.cycle-3 .letter-char,
.alphabet-inline .letter.cycle-4 .letter-char { color: var(--fg-3); }

/* ------------------------------------------------------------------ chords */

.chords { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); border-top: 1px solid var(--line-hair); }
.chord { padding: 12px 16px 14px 0; border-bottom: 1px solid var(--line-hair); }
.chord-word { font-size: 10px; letter-spacing: .2em; color: var(--fg-3); margin-bottom: 9px; }
.chord-stack { display: flex; flex-direction: column-reverse; gap: 2px; margin-bottom: 10px; }
.chord-tone { display: flex; align-items: baseline; gap: 10px; font-size: 13px; }
.chord-tone .t-letter { color: var(--fg-3); font-size: 9.5px; width: 1.6em; }
.chord-tone .t-value { color: var(--green); min-width: 4ch; }
.chord-tone .t-note { color: var(--fg); }
.chord-tone .acc-flat { color: var(--flat); }
.chord-id { border-top: 1px solid var(--line-hair); padding-top: 8px; font-size: 11.5px; color: var(--fg-3); }
.chord-id b { display: block; font-family: var(--f-sans); font-size: 17px; font-weight: 600; color: var(--fg); }
.chord-id .unnamed { color: var(--fg-3); font-style: italic; }

/* ----------------------------------------------------------------- decoder */

.decode-row {
  display: flex; align-items: baseline; gap: 14px;
  padding: 8px 0; border-bottom: 1px solid var(--line-hair); flex-wrap: wrap;
}
.decode-value { font-size: 16px; min-width: 5ch; color: var(--green); }
.decode-value .acc-flat { color: var(--flat); }
.decode-letters { font-size: 14px; letter-spacing: .18em; color: var(--fg); }
.decode-tag {
  font-family: var(--f-sans); font-size: 9.5px; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--fg-3); border: 1px solid var(--line-soft); padding: 1px 8px;
}
.decode-tag.ambiguous { color: var(--amber); border-color: var(--amber); }
.decode-tag.ambiguous::before { content: "※ "; }
.decode-error { color: var(--red); font-size: 12px; }
.decode-summary {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line-hair);
  font-size: 12.5px; color: var(--fg-2); max-width: 74ch;
}
.decode-summary b { color: var(--green); font-weight: 500; }

/* ------------------------------------------------------------- raw data */

.raw {
  margin: 0;
  padding: 12px 14px;
  background: var(--bg-1);
  border: 1px solid var(--line-hair);
  border-left: 2px solid var(--green-dim);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--fg-2);
  max-height: 420px;
  overflow: auto;
  white-space: pre;
}

/* --------------------------------------------------------------- exports */

.exports { border-top: 1px solid var(--line-hair); }
.exrow {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 16px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line-hair);
}
.exname { font-family: var(--f-sans); font-size: 12px; font-weight: 600; letter-spacing: .1em; color: var(--fg); }
.exdesc { font-size: 11.5px; color: var(--fg-3); }

/* ---------------------------------------------------------- two columns */

.two-col {
  display: grid;
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: 0 clamp(18px, 3vw, 40px);
  align-items: start;
}
.col-detail { border-left: 1px solid var(--line-hair); padding-left: clamp(16px, 2.4vw, 32px); }

/* =========================================================== simplification

   Hierarchy through type and space rather than through more boxes. Four
   levels, and only two of them are ever loud:

     PRIMARY    the musical result — the largest thing on the screen
     SECONDARY  controls for the task in hand
     ADVANCED   configuration, behind a disclosure
     TECHNICAL  Patricia values, quiet by default

   =========================================================================== */

/* A workspace gets room between its parts. Crowding was the complaint, and
   space is the cheapest fix that removes nothing. */
.wsp > .block { padding-bottom: 26px; }
.wsp > .fold + .fold { margin-top: 0; }

/* Section headings step back so they do not compete with the result they are
   labelling. They are signposts, not content. */
.lbl {
  font-size: 9.5px;
  letter-spacing: .22em;
  color: var(--fg-3);
  font-weight: 500;
}

/* One primary action per screen. The accent is reserved for it; everything
   else is an outline. */
.act-go {
  color: var(--green);
  border-color: var(--green-dim);
}
.act-go:hover:not(:disabled) {
  color: var(--accent-hot);
  border-color: var(--green-2);
  background: rgba(86, 217, 138, .07);
}

/* A row of controls that reads as one line rather than a grid of boxes. */
.ctl-row {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: 0 clamp(14px, 2.4vw, 28px);
}
.ctl-row .act { margin-bottom: 14px; }
.field-narrow { max-width: 7rem; }

/* Closed disclosures sit closer together, so a stack of them reads as a
   contents list rather than as five empty sections. */
.fold > summary { padding: 8px 0; }
.fold[open] > summary { color: var(--fg-2); }
.fold[open] > .fold-body { padding-bottom: 18px; }

/* A disclosure that is actively changing what you see says so, in the one
   colour the system reserves for state. */
.fold.is-active > summary { color: var(--green); }

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

@media (max-width: 900px) {
  /* Every control in every workspace clears the 44px touch target. One rule
     for the whole application rather than a copy of it per panel: the panels
     were drifting apart, and three of them had never been given it at all. */
  .wsp select,
  .wsp textarea,
  .wsp input[type="text"],
  .wsp input[type="number"],
  .wsp input[type="search"] { min-height: 44px; }

  .wsp .act,
  .wsp .tab { min-height: 44px; padding-top: 0; padding-bottom: 0; }

  .wsp .check { min-height: 44px; display: inline-flex; align-items: center; }

  /* Tappable content, not form controls: word chips, the related-cipher
     links, the card heading that selects a word. Same target, same reason.

     The heading only gets the height — it already lays itself out as a
     full-width column, and forcing inline-flex on it collapsed the card. */
  .wsp .wordcard-head { min-height: 44px; justify-content: center; }

  .wsp .wordchip,
  .wsp .related-btn,
  .wsp .ghost { min-height: 44px; display: inline-flex; align-items: center; }
  .wsp input[type="checkbox"] { width: 20px; height: 20px; }
  .wsp input[type="range"] { height: 44px; }

  .bar-inner { flex-wrap: wrap; padding-top: 6px; padding-bottom: 4px; min-height: 0; }
  .brand { flex: 1 1 auto; }
  .bar-right { order: 2; }
  .nav {
    order: 3;
    flex: 1 0 100%;
    padding: 6px 0 5px;
    border-top: 1px solid var(--line-hair);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }
  .two-col { grid-template-columns: 1fr; }
  .col-detail { border-left: 0; padding-left: 0; border-top: 1px solid var(--line-hair); padding-top: 16px; margin-top: 16px; }
  .exrow { grid-template-columns: 1fr auto; }
  .exdesc { grid-column: 1 / -1; grid-row: 2; }
}

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

@media (prefers-reduced-motion: reduce) {
  .brand-letter, .brand-digit { transition: none; }
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ================================================= result actions + why ===

   The actions that carry a result forward, and the explanation that is only
   ever there because someone asked for it.
   =========================================================================== */

.result-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line-hair);
}

/* A button that offers rather than urges. Used for "Why?", which should be
   findable without ever competing with the thing it explains. */
.act-quiet {
  border-color: transparent;
  color: var(--fg-3);
  padding-left: 4px;
  padding-right: 4px;
  letter-spacing: .12em;
}
.act-quiet:hover:not(:disabled) { color: var(--fg); background: none; }
.act-quiet[aria-expanded="true"] { color: var(--green); }

.why {
  margin-top: 14px;
  padding: 14px 0 4px 14px;
  border-left: 2px solid var(--green-dim);
  max-width: 60ch;
}
.why[hidden] { display: none; }

.why-line {
  margin: 0 0 9px;
  font-family: var(--f-sans);
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--fg-2);
}
.why-row {
  margin: 0 0 5px;
  font-family: var(--f-sans);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--fg-2);
}
.why-chain { margin: 0 0 10px; font-family: var(--f-mono); font-size: 13px; }
.why-letter { color: var(--fg); font-family: var(--f-mono); }
.why-value  { color: var(--green); font-family: var(--f-mono); }
.why-arrow  { color: var(--fg-3); }

/* What Practice is currently for, when something sent you there. */
.practising {
  margin: 0 0 4px;
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--green-2);
}
.practising[hidden] { display: none; }

/* ================================================= encode transport ======

   Generation and playback are one workflow, so the transport sits with the
   result rather than on a page of its own.
   =========================================================================== */

.transport {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px clamp(10px, 2vw, 18px);
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line-hair);
}
.transport .field { margin: 0; }
.transport-loop { margin: 0; }
.playback-status { margin-left: auto; color: var(--green-2); }

/* Where the playhead is. Updated once per word, never on a timer. */
.progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 10px;
}
.progress[hidden] { display: none; }
.progress-bar {
  flex: 1;
  height: 2px;
  background: var(--line-hair);
  overflow: hidden;
}
.progress-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--green-2);
  transition: width .18s var(--ease);
}
.progress-count {
  font-family: var(--f-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  color: var(--fg-3);
  min-width: 6ch;
  text-align: right;
}

/* The detail heading and its instrument switcher share a line. */
.lbl-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.lbl-row .lbl { margin-bottom: 0; }

@media (prefers-reduced-motion: reduce) {
  .progress-fill { transition: none; }
}

/* ===========================================================================
   THE INPUT — where you start.
   ---------------------------------------------------------------------------
   Everything else on the page is a control acting on something that already
   exists. This is the one field that makes something exist, and until you have
   typed in it the application has nothing to show you — so it is the one
   control allowed to be brighter than the rest.

   The treatment is a rule, not a box: a green underline that thickens and
   lights on focus, plus a faint inner wash. Terminal green is used everywhere
   in this interface to mean "this is live", and this is the most live thing on
   the screen. No pulsing, no border chase, nothing moving while you read.
   =========================================================================== */

#input {
  background: linear-gradient(var(--bg-1), var(--bg-1)) padding-box,
              linear-gradient(180deg, rgba(86, 217, 138, .10), rgba(86, 217, 138, .02)) padding-box;
  border: 1px solid var(--line-soft);
  border-bottom: 2px solid var(--green-dim);
  font-size: clamp(15px, 2.2vw, 18px);
  letter-spacing: .06em;
  padding: 11px 12px;
  caret-color: var(--green);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease),
              background-color .16s var(--ease);
}

#input::placeholder {
  color: var(--fg-3);
  letter-spacing: .04em;
  text-transform: none;
}

#input:hover {
  border-color: var(--line);
  border-bottom-color: var(--green-2);
}

/* Focus is unmistakable without being loud: the rule becomes the accent and a
   soft glow lifts the field off the ground. `:focus-visible` is not used here
   — this field is meant to be clicked, and a mouse click should light it. */
#input:focus {
  outline: none;
  border-color: var(--green-2);
  border-bottom-color: var(--green);
  box-shadow: 0 0 0 1px rgba(86, 217, 138, .28),
              0 0 18px -6px rgba(86, 217, 138, .55);
}

/* The label above it carries the same accent, so the pair reads as one thing
   rather than as a heading that happens to sit above a box. */
#encode .block:first-of-type .lbl { color: var(--green-2); }

@media (max-width: 560px) {
  #input { font-size: 16px; }   /* 16px stops iOS zooming the page on focus */
}

@media (prefers-reduced-motion: reduce) {
  #input { transition: none; }
}
