/* The chart itself. This stylesheet is shared by the on-screen view and the
   printed page, so what you proof is what comes out of the PDF. */

/* The page the chart is composed onto. In Build this is a plain wrapper at
   the chart's old page width; in Layout and Read it is given the frame's
   exact pixel size by js/reading.js and scaled to the window.

   It is also the chart's query container, which is the point: the reflow
   rules further down have to answer to the *page's* width, not the browser
   window's. Keyed to the window, composing in a narrow window would quietly
   lay the chart out differently from the iPad that reads it — which is the
   one thing a fixed page is supposed to make impossible. */
.chart-frame {
  container-type: inline-size;
  container-name: chart;
  max-width: 860px;
  margin: 0 auto;
}

/* The dials the Layout panel turns. All neutral at 1, all written straight
   onto this element as inline custom properties by paintLayout in
   js/reading.js — which is what lets a slider move without re-rendering the
   chart, and a re-render means VexFlow redrawing every stave on the page.

   Defaults are declared here rather than only in the JS so a chart still
   looks right in any context that never runs paintLayout: the print path,
   the test harness, a chart rendered into the groove bench. */
.chart {
  --chart-notation: 1;
  --chart-text: 1;
  --chart-pad: 1;
  --chart-space: 1;
  --chart-label-w: 92px;

  --chart-ink: #000;
  --chart-line: #b9bec7;
  --chart-faint: #7b818c;
  --chart-warn: #a15c00;
  background: #fff;
  color: var(--chart-ink);
  width: 100%;
  padding: calc(22px * var(--chart-pad)) calc(26px * var(--chart-pad)) calc(30px * var(--chart-pad));
  border-radius: 3px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14), 0 8px 24px rgba(0, 0, 0, 0.06);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* --- heading -------------------------------------------------------- */

.chart-head {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 4px 12px;
  border-bottom: 2px solid var(--chart-ink);
  padding-bottom: 6px;
  margin-bottom: 12px;
}
.chart-title { font-size: calc(24px * var(--chart-text)); margin: 0; font-weight: 700; letter-spacing: -0.015em; }
.chart-meta { grid-column: 1; font-size: calc(13px * var(--chart-text)); color: var(--chart-faint); }

/* The notehead in a tempo marking, set in the music font rather than in
   whatever the system has — see TEMPO_NOTE_VALUES in js/model.js for why
   Unicode's own characters will not do. Bravura is already loaded (VexFlow
   engraves the staves with it) and is embedded in an exported page, so this
   comes out right in a PDF too. It sits a little low and runs a little large
   at its natural size, which is what the nudge and the size are for. */
.tempo-note {
  font-family: Bravura, serif;
  font-size: 1.45em;
  line-height: 0;
  vertical-align: -0.06em;
  margin-right: 0.12em;
}
/* The notehead picker: a visible glyph with an invisible native select over
   it. See noteValuePicker in js/chart.js — macOS draws a select's option list
   itself, in the system font, so a music glyph in an <option> is a box. */
.note-pick {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  min-width: 1.4em;
}
/* The face carries .tempo-note when it is a notehead, and that class is
   tuned for sitting inline in a line of text — zero line-height so it does
   not open up the row it is in. Standing on its own in a control it needs
   its height back, or it collapses to nothing and the glyph hangs outside
   its own box. */
.note-pick-face {
  pointer-events: none;
  white-space: nowrap;
  line-height: 1.1;
  display: inline-block;
  min-width: 0.75em;
  text-align: center;
}
.note-pick .tempo-note { line-height: 1.1; vertical-align: baseline; }
.note-pick-select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
  font: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.note-pick.disabled { opacity: 0.75; }
.note-pick.disabled .note-pick-select { cursor: default; }
.chart-total { grid-column: 2; grid-row: 1 / span 2; font-size: calc(12px * var(--chart-text)); color: var(--chart-faint); align-self: center; }

/* Build only: the title and meta line are the same text, just editable in
   place — no border or background until you actually reach for one, so an
   idle chart still reads exactly like the printed one. */
input.chart-title, .cm-field {
  border: none; background: none; padding: 1px 3px; margin: -1px -3px;
  font: inherit; color: inherit; letter-spacing: inherit; border-radius: 3px;
}
input.chart-title { width: 100%; }
input.chart-title:hover, .cm-field:hover,
input.chart-title:focus, .cm-field:focus { outline: none; background: rgba(31, 95, 208, 0.08); }
.chart-meta-edit { grid-column: 1; display: flex; flex-wrap: wrap; gap: 2px 4px; font-size: 13px; color: var(--chart-faint); }
.cm-field { font-size: 13px; color: var(--chart-faint); }
.cm-field.cm-artist, .cm-field.cm-genre { width: 9em; }
.cm-field.cm-timesig, .cm-field.cm-key { width: 3.5em; }
.cm-tempo-group { display: inline-flex; align-items: center; gap: 1px; }
.cm-field.cm-tempo-unit { width: auto; padding-right: 0; cursor: pointer; }
.cm-tempo-detect { font-size: 11px; padding: 1px 6px; }
.cm-tempo-eq { margin: 0 2px 0 1px; }
.cm-field.cm-tempo { width: 3em; text-align: center; }
.cm-field.cm-tempo.empty { width: 4.2em; margin: 0 2px; box-shadow: inset 0 0 0 1px rgba(31, 95, 208, 0.45); background: #fff; }
.cm-field.cm-tempo::placeholder { color: rgba(31, 95, 208, 0.7); }

.chart-notes { margin-bottom: 10px; }
.chart-head-wrap { position: relative; }

/* --- sections ------------------------------------------------------- */

.chart-body {
  display: flex;
  flex-direction: column;
  /* Reading mode may flow the sections into columns: a chart that is tall and
     narrow wastes a landscape screen, and two columns halve its height. */
  column-count: var(--chart-columns, 1);
  column-gap: calc(24px * var(--chart-space));
  column-fill: balance;
}
.chart-body[style*="--chart-columns"] { display: block; }
.chart-body > * { break-inside: avoid; }

.chart-section {
  display: grid;
  grid-template-columns: var(--chart-label-w) minmax(0, 1fr);
  gap: calc(3px * var(--chart-space)) 10px;
  padding: calc(6px * var(--chart-space)) 0;
  border-top: 1px solid var(--chart-line);
  break-inside: avoid;
  transition: transform .12s ease;
}
.chart-section:first-child { border-top: 0; padding-top: 2px; }
.chart-section.selected { background: #f2f7ff; box-shadow: inset 3px 0 0 #1f5fd0; }
.chart-section.dragging, .phrase.dragging {
  position: relative;
  z-index: 5;
  transition: none;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
  cursor: grabbing;
}

/* Selecting a phrase or section is what reveals its drag handle — nothing
   else in the chart carries one, so a chart that fits a screen unselected
   still fits it once something is picked. */
.chart-drag {
  border: 0;
  background: none;
  padding: 0 2px;
  margin-left: 4px;
  font-size: 12px;
  line-height: 1;
  color: var(--chart-faint);
  cursor: grab;
  touch-action: none;
}
.chart-drag:active { cursor: grabbing; }

/* Copy/duplicate/delete, wherever they show up in the chart, are the same
   scale as the drag handle next to them — a normal-sized icon button would
   blow out a strip that is 13px tall the rest of the time. */
.ph-side .icon-btn, .sec-tools .icon-btn {
  border: 0; background: none; padding: 0 2px; min-width: auto; min-height: auto;
  font-size: 12px; line-height: 1; color: var(--chart-faint);
}
.ph-side .icon-btn:hover, .sec-tools .icon-btn:hover { color: var(--chart-ink); background: none; }
.ph-side .icon-btn.danger, .sec-tools .icon-btn.danger { color: #b3261e; }
.sec-tools .chart-drag { color: var(--chart-faint); }

/* Where a dragged phrase would land: a bar on the side of whichever phrase it
   is closest to, or a dashed outline around an empty section's phrase area
   when there is nothing there to be closest to. */
.phrase.drop-before { box-shadow: inset 3px 0 0 #1f5fd0; }
.phrase.drop-after { box-shadow: inset -3px 0 0 #1f5fd0; }
.chart-section.drop-into-empty .phrases { outline: 2px dashed #1f5fd0; outline-offset: 2px; border-radius: 3px; }

.sec-head { grid-column: 1; }
.sec-name {
  font-size: calc(15px * var(--chart-text));
  font-weight: 700;
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.2;
}
input.sec-name {
  border: none; background: none; padding: 1px 2px; margin: -1px -2px -1px -4px;
  width: 100%; color: inherit; border-radius: 3px;
}
input.sec-name:hover, input.sec-name:focus { outline: none; background: rgba(31, 95, 208, 0.1); }
/* The ▾ beside a name you can edit (sectionlabel.js). Quiet until the name is
   pointed at, but never hidden outright — an iPad has no hover to find it with. */
.sec-head .name-field { display: flex; align-items: center; min-width: 0; }
.sec-head .name-field input.sec-name { flex: 1 1 auto; min-width: 0; }
.sec-bars {
  font-size: calc(12px * var(--chart-text));
  color: var(--chart-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.sec-bars-mismatch { color: var(--chart-warn); }
/* Build: the count is a field, but reads as the label until it is reached for. */
.sec-bars-edit { white-space: nowrap; }
.sec-bars-input {
  width: 2.6em; border: none; background: none; padding: 1px 2px; margin: -1px 0 -1px -2px;
  font: inherit; color: inherit; text-align: right; border-radius: 3px;
}
.sec-bars-input:hover, .sec-bars-input:focus { outline: none; background: rgba(31, 95, 208, 0.1); }
.sec-bars-input::placeholder { color: var(--chart-faint); }
.sec-notes { grid-column: 2; }

/* Section-level tools, shown only once the section is selected. Floated over
   the top-right corner rather than given a row of their own, so selecting a
   section never changes its height — nothing below it moves. */
.sec-tools {
  position: absolute;
  top: 3px;
  right: 4px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 3px;
  background: rgba(242, 247, 255, 0.9);
  border-radius: 3px;
  padding: 1px 2px;
}

.rg-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  background: var(--accent-soft, #eaf1fd);
  border-radius: 5px;
  padding: 5px 8px;
  margin-bottom: 6px;
  font-size: 12px;
  grid-column: 1 / -1;
}
.rg-label { font-weight: 600; }
.rg-times-input { width: 44px; }

.phrases { grid-column: 2; display: flex; flex-direction: column; gap: calc(5px * var(--chart-space)); min-width: 0; }
/* Stretching every box in a row to match the tallest one meant a single note
   or lyric on one phrase pushed blank space into every other box beside it,
   several times over in a busy row — exactly what made a note feel like it
   cost far more room than one line of text should. Staves still line up
   across the row regardless (see alignChartStaves in chart.js, which aligns
   them directly rather than relying on the boxes around them being equal
   height) — only the boxes' own bottom edges, where a note sits, now differ
   when only one of them actually has one. */
.phrase-run { display: flex; flex-wrap: wrap; gap: calc(5px * var(--chart-space)); align-items: flex-start; }

/* alternate endings */
.phrase-run.ending { display: block; position: relative; padding-left: 8px; width: max-content; max-width: 100%; align-self: flex-start; }
.phrase-run.ending .phrase-run-inner { display: flex; flex-wrap: wrap; gap: 6px; padding-top: 12px; }
.ending-bracket {
  position: absolute;
  inset: 0 0 auto 0;
  border-top: 1.5px solid var(--chart-ink);
  border-left: 1.5px solid var(--chart-ink);
  height: 11px;
}
.ending-bracket span {
  position: absolute;
  top: 1px;
  left: 4px;
  font-size: 10px;
  font-weight: 700;
  background: #fff;
  padding: 0 3px;
  line-height: 1;
}

/* --- phrase cells --------------------------------------------------- */

.phrase {
  position: relative;
  border: 1px solid var(--chart-line);
  border-radius: 3px;
  padding: 2px 5px 3px;
  min-width: 48px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: #fff;
  break-inside: avoid;
  transition: transform .12s ease;
}
.phrase.selected { outline: 2px solid #1f5fd0; outline-offset: 1px; }

/* How far through this pass of a multi-bar or repeated phrase playback has
   got — only drawn when there is more than one bar to get through, so a
   phrase that is only ever one bar stays exactly as plain as it always was. */
.phrase.sounding-progress::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  border-radius: 0 0 2px 2px;
  background: #1f5fd0;
  width: calc(var(--play-progress, 0) * 100%);
  transition: width 0.15s linear;
}

.ph-top {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  gap: 4px;
  font-size: calc(10px * var(--chart-text));
  color: var(--chart-faint);
  line-height: 1;
  min-height: 13px;
}
.ph-side { display: flex; align-items: baseline; gap: 4px; }
.ph-side.right { justify-content: flex-end; }
/* The bar count is the number you scan for, so it sits centred and bold over
   the bar it counts. */
.ph-bars {
  font-weight: 800;
  color: var(--chart-ink);
  font-variant-numeric: tabular-nums;
  font-size: calc(14px * var(--chart-text));
  text-align: center;
}
.ph-sig { font-weight: 700; color: var(--chart-ink); border: 1px solid var(--chart-ink); border-radius: 2px; padding: 0 3px; }
.ph-times { font-weight: 700; color: var(--chart-ink); }

.ph-text-line, .ph-rest, .ph-ref, .ph-repeat {
  font-size: calc(14px * var(--chart-text));
  line-height: 1.25;
}
.ph-text-line.style-instruction { font-weight: 600; }
.ph-text-line.style-arrangement { font-style: italic; color: #3a3f48; }
.ph-text-line.style-texture { font-style: italic; }
.ph-text-line.style-fill {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: calc(13px * var(--chart-text));
}
.ph-text-line.style-uncertain { font-weight: 700; }
.ph-rest {
  font-weight: 600;
  letter-spacing: 0.08em;
  color: #5c626d;
  text-transform: uppercase;
  font-size: calc(12px * var(--chart-text));
}
.ph-repeat { font-size: calc(22px * var(--chart-text)); font-weight: 600; text-align: center; line-height: 1; padding: 2px 8px; }
.ph-ref { display: flex; align-items: center; gap: 5px; font-weight: 600; }
.ph-ref-arrow { font-size: 15px; }
.ph-groove-label { font-size: calc(11px * var(--chart-text)); color: var(--chart-faint); margin-bottom: 1px; display: flex; gap: 5px; align-items: baseline; }
/* Swing is a performance direction, so it is set like one: italic, in the
   chart's ink rather than the label's grey, and hard to miss. */
.ph-swing {
  font-style: italic;
  font-weight: 600;
  color: var(--chart-ink);
  letter-spacing: 0.01em;
}

.phrase.type-text:has(.style-fill) { border-style: dashed; }
.phrase.type-text:has(.style-uncertain) { border-color: #b3261e; }
.phrase.type-rest { border-style: dotted; }
.phrase.type-repeat { justify-content: center; }

/* notes pinned to a phrase or section */
.note {
  font-size: calc(12.5px * var(--chart-text));
  font-style: italic;
  color: #2b4a86;
  line-height: 1.25;
}
.note::before { content: "✎ "; font-style: normal; }

/* A lyric is a landmark rather than an instruction: the words, set as words,
   in their own colour so the eye finds them without reading them. */
.note.style-lyric {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-size: calc(13px * var(--chart-text));
  font-style: italic;
  color: #7a3d8f;
}
.note.style-lyric::before { content: "\201c"; font-style: normal; margin-right: 1px; }
.note.style-lyric::after { content: "\201d"; font-style: normal; margin-left: 1px; }
.ph-notes { border-top: 1px dotted var(--chart-line); padding-top: 2px; margin-top: 1px; }

/* While a chart is being written, a note or lyric keeps to the width its box
   already has instead of stretching the box — and every box in the row —
   out to fit the words: a long lyric made a one-bar box several bars wide.
   It is cut short with an ellipsis, and reads in full while you type in it
   or hover it. Layout and Read are the finished page and set it out in full. */
body:not(.layout-view):not(.reading) .phrase .ph-notes { width: 0; min-width: 100%; }
body:not(.layout-view):not(.reading) .phrase .ph-notes .note,
body:not(.layout-view):not(.reading) .phrase .ph-notes .note-input {
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
body:not(.layout-view):not(.reading) .phrase .ph-notes .note-input:focus { text-overflow: clip; }

/* --- section-group repeats ------------------------------------------ */

/* ×N sits against the bracket, on the left, rather than out at the far
   right edge where it was read as belonging to the last line. */
.repeat-group {
  display: grid;
  grid-template-columns: auto 12px minmax(0, 1fr);
  align-items: stretch;
  gap: 0 6px;
  break-inside: avoid;
}
.rg-bracket {
  border: 2px solid var(--chart-ink);
  border-right: 0;
  border-radius: 3px 0 0 3px;
  margin: 6px 0;
}
.rg-body { min-width: 0; }
.rg-times {
  align-self: center;
  font-size: 13px;
  font-weight: 700;
  padding-right: 1px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.rg-times small { font-weight: 400; font-size: 10px; color: var(--chart-faint); }
/* A collapsed "by name" block that is not the same every time round. */
.phrase.varies { position: relative; }
.phrase.varies::after {
  content: "\2260"; position: absolute; top: 1px; right: 3px;
  font-size: 11px; font-weight: 700; color: var(--chart-warn);
}
.sec-varies { display: block; font-size: 10px; font-weight: 600; color: var(--chart-warn); }

/* --- groove grids --------------------------------------------------- */

.grid-view { display: flex; flex-direction: column; gap: 1px; }
.grow { display: flex; align-items: center; gap: 4px; }

.glabel {
  flex: 0 0 15px;
  width: 15px;
  font-size: 8px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--chart-faint, #7b818c);
  text-align: right;
  line-height: 1;
}

.gcells {
  display: grid;
  flex: 1 1 auto;
  border-left: 1.5px solid var(--chart-ink, #000);
  border-right: 1.5px solid var(--chart-ink, #000);
}

.gcell {
  position: relative;
  min-width: 14px;
  height: 19px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid #f0f1f4;
  font-size: 11px;
  line-height: 1;
  color: #000;
  /* room above the note for the accent mark */
  padding-top: 6px;
}
.gcell:last-child { border-right: 0; }
.gcell.beat { border-left: 1px solid #c3c7cf; }
.gcell.barline { border-left: 1.5px solid #000; }

/* ghost notes in brackets, accents under a caret — the way you would write them */
.gcell.w-ghost .glyph { font-size: 8px; color: #5c626d; }
.gcell.w-ghost .glyph::before { content: "("; }
.gcell.w-ghost .glyph::after { content: ")"; }
.gcell.w-accent .glyph { font-weight: 800; }
.gcell.w-accent::after {
  content: ">";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
}

.grid-view.compact .gcell { height: 18px; min-width: 13px; }
.grid-view.editable .gcell { height: 28px; min-width: 20px; font-size: 13px; padding-top: 7px; }
.grid-view.editable .glabel { text-align: left; }
.grid-view.editable .gcells { border-color: #b9bec7; }
.grid-view.editable .gcell.w-accent::after { top: 2px; }

.grid-view.triplet .gcell.beat { border-left-color: #8d939c; }

/* --- narrow screens --------------------------------------------------- */
/* A phone gets a reflow, not a shrink: the section name moves above its
   phrases instead of sitting in a column that would eat a third of the width. */

@container chart (max-width: 620px) {
  .chart { padding: 14px 12px 20px; }
  .chart-title { font-size: 21px; }

  .chart-section {
    grid-template-columns: minmax(0, 1fr);
    gap: 3px;
    padding: 7px 0;
  }
  .sec-head {
    grid-column: 1;
    display: flex;
    align-items: baseline;
    gap: 8px;
  }
  .sec-name { font-size: 14px; }
  .phrases, .sec-notes { grid-column: 1; }

  .repeat-group { grid-template-columns: auto 8px minmax(0, 1fr); gap: 0 4px; }

  .phrase { min-width: 48px; }
}

/* Score no longer picks a width of its own: the frame is the width, set in
   device pixels by js/reading.js, and the chart simply fills it. What used
   to be a search across a dozen candidate widths is now a property of the
   page you chose to compose onto. */

/* --- what is on the page at all --------------------------------------- */
/* A lyric cue is priceless on one chart and clutter on the next, and the
   same goes for the artist line and the bar totals. Hiding rather than not
   rendering, so the switch costs a class change and never a re-render. */

.chart.hide-meta .chart-meta { display: none; }
.chart.hide-bar-total .chart-total,
.chart.hide-bar-total .sec-bars { display: none; }
.chart.hide-notes .note,
.chart.hide-notes .ph-notes,
.chart.hide-notes .sec-notes,
.chart.hide-notes .chart-notes { display: none; }

/* Without their boxes the phrases read as a run of music across the line
   rather than a row of cards. Some charts want the cards; some want the
   music to breathe. The bar count stays either way — it is the number the
   eye scans for. */
.chart.hide-boxes .phrase {
  border-color: transparent;
  background: none;
  padding-left: 0;
  padding-right: 0;
}
.chart.hide-boxes .phrase-run { gap: calc(14px * var(--chart-space)); }

/* --- staff notation --------------------------------------------------- */

.notation { line-height: 0; }
.notation svg { display: block; max-width: 100%; height: auto; }
/* VexFlow paints in absolute black; keep it that way in print. */
.notation svg path, .notation svg rect { fill: currentColor; }
.notation svg text { fill: currentColor; }

.phrase.sounding-bar { outline: 2px solid #1f5fd0; outline-offset: 1px; }

/* The note being struck, inside the phrase that is sounding. VexFlow paints
   noteheads, stems and flags as fills and strokes on a group, so colouring the
   group means setting both — a stem is a stroked path, a notehead a filled one.
   A drum notehead is often a thin glyph (an X for a hi-hat), so colour alone
   reads as barely more than a hairline; a glow behind it is what actually
   catches the eye at a glance, the way the eye is meant to use this. */
.sounding-note,
.sounding-note path,
.sounding-note rect,
.sounding-note text { fill: #1f5fd0; stroke: #1f5fd0; stroke-width: 1.6px; }
.sounding-note {
  filter: drop-shadow(0 0 1.5px #1f5fd0) drop-shadow(0 0 4px #1f5fd0);
}

/* The same note, when the groove is drawn as the compact grid instead of
   notation — a plain span, not an SVG group, so it takes the highlight as a
   background rather than a fill. */
.gcell.sounding-note { background: #1f5fd0; color: #fff; }
.gcell.sounding-note .glyph { color: #fff; }

/* --- writing straight into the chart --------------------------------- */

/* The inline "+". Idle it takes no width at all: a chart has to fit one
   screen, and a row of waiting boxes is what stops it fitting. It opens up
   when the section is under the pointer, and stays open in a section with
   nothing in it yet, where it is the only thing to aim at. */
.phrase-add {
  position: relative;
  flex: 0 0 auto;
  width: 0;
  overflow: visible;
  display: flex;
  align-items: stretch;
  opacity: 0;
  transition: width 90ms ease, opacity 90ms ease;
}
.chart-section:hover .phrase-add,
.phrase-add.always,
.phrase-add.open { width: 44px; opacity: 1; }

.phrase-add-box {
  width: 44px;
  min-height: 100%;
  border: 1.5px dashed var(--chart-line);
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  color: var(--chart-line);
  cursor: pointer;
  user-select: none;
}
.phrase-add:hover .phrase-add-box,
.phrase-add.open .phrase-add-box { border-color: #1f5fd0; color: #1f5fd0; }

.phrase-add-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 5px;
  background: #fff;
  border: 1px solid var(--chart-line);
  border-radius: 4px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);
}
.phrase-add-menu .btn { white-space: nowrap; text-align: left; }

/* Nothing to add while reading, and nothing to print. */
body.reading .phrase-add { display: none; }
@media print { .phrase-add { display: none; } }

/* A note being written reads exactly as a note already written: the box is the
   text, with no field around it. */
.note-input {
  width: 100%;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  outline: 0;
}
.note-input::placeholder { color: currentColor; opacity: 0.4; }
.note-input:focus { box-shadow: 0 0 0 1px rgba(31, 95, 208, 0.4); border-radius: 2px; }

/* The bar count, editable on the selected box. Same size and position as the
   number it replaces, so nothing moves when a box is selected. */
.ph-bars-input {
  width: 3.8ch;
  border: 0;
  padding: 3px 0;
  margin: -3px 0;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: inherit;
  text-align: center;
  outline: 0;
  -moz-appearance: textfield;
}
.ph-bars-input::-webkit-outer-spin-button,
.ph-bars-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ph-bars-input:focus { box-shadow: 0 0 0 1px rgba(31, 95, 208, 0.4); border-radius: 2px; }

.chart-section, .phrase { position: relative; }
.note-menu { top: 2px; left: 2px; }
