/* Page basics. The theme is auto (the system's) unless theme.js sets data-theme; light-dark() picks
   each color. Dark is for a dark stage: black, so an OLED screen lights nothing around the chart,
   and no white, so nothing glares. Chords are brightest; lyrics, cues and margins are dimmer. The
   page, and every control on it, is --page, and the shelf over it --raised. The shelf's rules are
   --line, its quiet words --quiet, and what's picked on it --picked. The editor marks the cursor's
   phrase in --here, and Convert what converting did in --mark. --tap is a control's height, and a
   round button's width, in the em of where it's used, and --pad its padding at each side. --ring is
   the focus ring's width, and how far out from its control it sits. --shelf is the shelf's width
   where it stands beside the song or a PDF. --column is a page's widest, centered on a wide screen. */
:root { --column: 70rem; color-scheme: light dark; --page: light-dark(#fff, #000); --error: light-dark(#c62828, #ef5350); --warning: light-dark(#e09d00, #f0b429); --ink: light-dark(#000, #c8c8c8); --chord: light-dark(#000, #e8e8e8); --soft: light-dark(#000, #a0a0a0); --line: light-dark(#ccc, #555); --mono: ui-monospace, monospace; --small: 0.8125em; --quiet: light-dark(#5c5c5c, #a0a0a0); --picked: light-dark(#000, #3a3a3a); --on-picked: light-dark(#fff, #f0f0f0); --raised: light-dark(#fff, #111); --here: light-dark(#fff3c4, #3a3000); --mark: light-dark(#a34e00, #ffb347); --tap: 2.75em; --pad: 0.85em; --ring: 2px; --shelf: 19em; }
/* A double tap never zooms, so a quick second tap on a stepper steps it. Pinching still zooms, and so
   does iOS's Zoom, so the viewport never stops it (WCAG 1.4.4). */
:root { touch-action: manipulation; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
/* The app's own fonts, so a chart looks the same on every device and on paper: Inter for text,
   Source Serif 4 Bold for time signatures (scripts/fonts.sh). Text waits for its font
   (block) rather than showing in a fallback first: the song page deals its screenfuls and printed
   pages by measuring the text, and a font arriving later would change every line. The layout
   preloads Inter, and it's cached after the first visit, so the wait is short. A font that takes
   longer than the browser's block period, about 3 s, shows in a fallback until it arrives. */
@font-face { font-family: Inter; src: url("/static/fonts/InterVariable-7ec15766.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: block; }
@font-face { font-family: Inter; src: url("/static/fonts/InterVariable-Italic-c437f0de.woff2") format("woff2"); font-weight: 100 900; font-style: italic; font-display: block; }
@font-face { font-family: "Source Serif 4"; src: url("/static/fonts/SourceSerif4-Bold-9259f78f.woff2") format("woff2"); font-weight: 700; font-display: block; }
body { font-family: Inter, system-ui, sans-serif; max-width: var(--column); margin-inline: auto; padding: 1rem; background: var(--page); color: var(--ink); }
main { display: grid; gap: 1rem; }
label { display: block; }
/* Whatever's hidden takes no room, however it's laid out. */
[hidden] { display: none !important; }
/* Every page's base. Controls take the page's font and color, links its ink, and focus has one
   ring. A page's parts are 1.5rem apart, and a heading or paragraph has no margin of its own. A
   heading hyphenates a word too long for its line. A page's heading shrinks toward 1.25em, at most
   an eighth of the screen's width, so on a narrow screen at a big text size a word Chromium won't
   hyphenate, like a capitalized one, still fits its line. Only a string with no word break in it,
   like a file's name, breaks anywhere, so the page never scrolls sideways. The chart's own page keeps its 1rem, and its
   chart its title's size. A select stops at its space. A textarea is monospace, a little smaller
   than the text around it, so it follows the text size. A fieldset groups
   its fields, drawn as no box of its own. */
:is(button, input, select) { font: inherit; color: inherit; }
a { color: inherit; }
/* A stepper, and a choice drawn as a pill, ring the pill around their input. */
:focus-visible, .stepper:has(input:focus-visible), :is(.seg, .toggles) label:has(:focus-visible) { outline: var(--ring) solid var(--ink); outline-offset: var(--ring); }
main:not(:has(> nns-chart)) { gap: 1.5rem; }
:where(h1, h2) { margin: 0; hyphens: auto; overflow-wrap: anywhere; }
:where(h1) { font-size: clamp(1.25em, 13vw, 2em); }
:where(main:not(:has(> nns-chart)) > p) { margin: 0; }
:where(main h2:not(nns-chart h2)) { font-size: 1.1em; }
select { max-width: 100%; padding: 0 0.5em; }
textarea { width: 100%; }
/* So does the copy behind Convert's lyric chart, so their words line up, and code among a page's
   words, like Convert's example. */
:is(textarea, .sheet > .copy) { padding: 0.5em 0.75em; font: 0.875em/1.45 var(--mono); }
code { font-size: 0.875em; font-family: var(--mono); }
fieldset { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
/* The header: the app's name, then its pages, quiet. Where you are, here and on the shelf's trail,
   is bold ink (aria-current). Each wraps as it needs. */
body > header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5em 1.5em; margin-bottom: 1.5rem; }
.app { font-size: 1.125em; font-weight: 700; }
body > header ul { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25em 1.25em; margin: 0; padding: 0; list-style: none; }
body > header li a { color: var(--quiet); }
:is(body > header, .crumbs) [aria-current] { color: var(--ink); font-weight: 600; }
/* An import counts from la or do only in a minor key. */
#convert:not(:has(option[data-minor]:checked)) .field:has(> #minor) { display: none; }
/* A log: a line per change, newest first, with its action at the end of its line, like the
   History's Restore. Its words wrap to leave the action room, and the action drops under them only
   when their longest word leaves it none. */
.log { display: grid; margin: 0; padding: 0; list-style: none; }
.log > li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5em 1rem; padding-block: 0.75em; border-top: 1px solid var(--line); }
.log p { flex: 1 1 0; margin: 0; }

/* The chart is laid out like the paper. Each section is its own grid: equal columns at the content
   width keep bar N under bar N across sections. Before each bar (and after the last) are two tracks
   for its bar line (below). --bars is set inline on nns-chart and inherited; a longer phrase wraps
   onto more rows (html.rs). A bar is a bar: every bar's column is --bar-track, and a section whose
   extra bars run past the grid has --extras more of them, so a lyric wraps before it widens its bar
   and a row without extras ends early. --rem is the chart's rem: structure (labels, chords, marks)
   scales from it; lyrics take --lyric. No gutter: the label sits on the band, and with the bar line
   before bar 1, 1rem of padding sets bar 1 in from it. The song page's reading.js sets --rem
   inline: the chord size, or on a wide screen the size that shows the song whole. */
/* Geometry that changes together: chords are --chord-rems rems tall (reading.js sizes the rem
   from them), with their foot and side spacing, which barlines and bullets share, and columns
   --column-gap apart. */
nns-chart { --rem: 15px; --chord-rems: 1.25; --chord-size: calc(var(--chord-rems) * var(--rem)); --chord-foot: calc(0.1 * var(--rem) + 1px); --chord-side: calc(0.3 * var(--rem) + 1px); --column-gap: calc(3 * var(--rem)); --lyric: calc(2 * var(--rem) / 3); --gap: calc(0.5 * var(--rem)); display: block; font-size: var(--rem); }
nns-chart header { display: flex; align-items: baseline; gap: var(--rem); margin-bottom: var(--rem); }
nns-time { justify-items: center; font-family: "Source Serif 4", ui-serif, serif; line-height: 1.05; }
nns-chart header nns-time { display: inline-grid; font-weight: bold; font-size: 0.8em; }
/* The tempo's quarter note is a shape the renderer draws in inline SVG. It stands on the baseline,
   as tall as the figures beside it. */
nns-tempo > svg { height: 1cap; fill: currentColor; }
nns-pickup, nns-lyric, nns-margin, nns-foot, nns-jump { font-size: var(--lyric); }
nns-pickup, nns-lyric, nns-margin, nns-cue, nns-foot, nns-jump { color: var(--soft); }
:is(nns-foot, nns-jump, nns-cue, nns-pickup, nns-lyric) { font-style: italic; padding: calc(0.1 * var(--rem)) calc(0.3 * var(--rem)); line-height: 1.3; }
nns-chords { color: var(--chord); }
/* Chords stand out from the lyrics, bold unless the URL turns them off (?bold=off, reading.js), and
   in a preview, as the song page draws them by default: the whole chord, its number or letter, suffix
   and bass, and one that didn't read. Its marks' strokes
   scale by --stroke, as Inter's stems do from 400 to 700, so a bold 4 doesn't sit in a thin diamond.
   A flat or sharp is a filled shape whose outline adds to its stems, so its outline scales by
   --sign, which thickens them as much. The header's key stays as it is. */
nns-chart { --chord-weight: 400; --stroke: 1; --sign: 1; }
:is(nns-chart[bold], #preview nns-chart) :is(nns-phrase, nns-riff) { --chord-weight: 700; --stroke: 1.7; --sign: 3; }

nns-section { --bar-track: minmax(min-content, 1fr); --tracks: repeat(var(--bars), max-content max-content [bar] var(--bar-track)) var(--extra-tracks,) max-content; display: grid; grid-template-columns: var(--tracks); row-gap: calc(0.35 * var(--rem)); margin-top: calc(0.75 * var(--rem)); padding-left: calc(var(--rem) - var(--gap)); break-inside: avoid; }
nns-section[extras] { --extra-tracks: repeat(var(--extras), max-content max-content [bar] var(--bar-track)); }
nns-heading, nns-phrase, nns-foot { grid-column: 1 / -1; }
/* The part of a section that runs on into the next column ends with its label and "continues →" at
   the right (reading.js). Like the cue, it never widens the grid. */
nns-foot, nns-jump { text-align: end; }
nns-foot { contain: inline-size; }

/* Heading row: label then cue on one baseline, a light grey band across the section (in dark, a rule
   under it: a filled band is the brightest thing on a dark screen). The cue never wraps and never
   widens the grid; wider than the band, it is clipped with an ellipsis. */
nns-heading { display: flex; contain: inline-size; align-items: baseline; gap: calc(0.75 * var(--rem)); padding: calc(0.2 * var(--rem)) calc(0.5 * var(--rem)) calc(0.1 * var(--rem)); margin-inline: calc(var(--gap) - var(--rem)) 0; background: light-dark(#e8e8e8, transparent); box-shadow: inset 0 -1px light-dark(transparent, var(--line)); }
nns-label { font-size: var(--chord-size); line-height: 1.2; font-weight: bold; }
nns-cue { white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
nns-margin { white-space: nowrap; font-style: italic; }
nns-heading > nns-margin { margin-left: auto; }

/* A riff (#302) sits under its section's label, across the section, and never widens the grid. Its
   notes are the chart's rem, in the chords' ink and bold with them. Its bars wrap whole, at bar
   lines: a bar line ends each bar, and the first bar starts with one, as a chord row does. A pickup
   comes before that first bar line. */
nns-riff { grid-column: 1 / -1; contain: inline-size; display: flex; flex-wrap: wrap; align-items: end; row-gap: calc(0.45 * var(--rem)); margin: calc(0.3 * var(--rem)) 0 calc(0.1 * var(--rem)) var(--gap); font-size: var(--rem); line-height: 1; color: var(--chord); font-weight: var(--chord-weight); --rule: max(1px, 0.06em); --beam: max(1px, calc(0.06em * var(--stroke))); }
nns-riff > nns-measure { position: relative; display: flex; flex-wrap: wrap; align-items: start; gap: 0.32em; padding-inline: 0.4em; border-inline-end: var(--rule) solid; }
nns-riff > nns-measure:first-child:not([pickup], :has(> nns-barline[open])) { border-inline-start: var(--rule) solid; }
nns-riff > nns-measure[pickup] { padding-inline-start: 0; }
/* A repeat's sign is its bar line, as tall, and how many times it plays follows its :|. A time
   change starts its bar, its numbers stacked level with the bar's. */
nns-riff > nns-measure:has(> nns-barline[open]) { padding-inline-start: 0; }
nns-riff > nns-measure:has(+ nns-measure > nns-barline[open]) { border-inline-end: 0; }
nns-riff > nns-measure:has(> nns-barline[close]) { border-inline-end: 0; padding-inline-end: 0; }
nns-riff nns-barline { padding: 0; font-size: inherit; }
nns-riff nns-barline > svg { display: block; height: calc(0.42em + 1em + 0.62em); width: auto; }
nns-riff nns-times { font-size: 0.6em; }
nns-riff nns-measure > nns-time { display: grid; padding-top: calc(0.42 * var(--rem)); font-size: 0.5em; line-height: 1; font-weight: bold; }
/* Numbers as jianpu writes them, each step as typed. A number alone is a count, whatever the time,
   and a line under it halves the count. A beat's quick notes touch, so their lines join. A tie is
   the note again with an arc back to the one before, from its center to near the other's: a cell
   is at least 0.7em wide, and a beat's first note is 0.32em past the one before, a bar's 0.8em and
   a bar line. Each end sits in 0.05em, so ties side by side don't touch. A rest is its sign, a number's height. ^ and v
   are arrows before the number, a number's height, two-headed for ^^ and vv. */
nns-riff nns-beat { display: flex; position: relative; }
nns-riff :is(nns-note, nns-rest) { position: relative; min-width: 0.7em; height: 1em; padding: 0.42em 0.1em 0.62em; text-align: center; background-repeat: no-repeat; background-size: 100% var(--beam); }
nns-riff [lines="1"] { background-image: linear-gradient(currentColor 0 0); background-position: 0 1.34em; }
nns-riff [lines="2"] { background-image: linear-gradient(currentColor 0 0), linear-gradient(currentColor 0 0); background-position: 0 1.34em, 0 1.5em; }
nns-riff nns-note[tied]::before { content: ""; position: absolute; left: -0.3em; right: calc(50% + 0.05em); bottom: calc(100% - var(--base) + var(--at)); height: 0.3em; box-sizing: border-box; border: var(--beam) solid; border-bottom: 0; border-radius: 50% 50% 0 0 / 100% 100% 0 0; }
nns-riff nns-beat > nns-note[tied]:first-child::before { left: -0.62em; }
nns-riff nns-measure > nns-beat:first-child > nns-note[tied]:first-child::before { left: calc(-1.1em - var(--rule)); }
nns-riff nns-rest > svg { display: block; height: 1.05em; width: auto; margin-inline: auto; fill: currentColor; }
nns-riff nns-dir > svg { display: inline-block; height: 0.72em; width: auto; vertical-align: 0; margin-inline-end: 0.04em; overflow: visible; fill: none; stroke: currentColor; stroke-width: calc(0.07em * var(--stroke)); stroke-linecap: round; stroke-linejoin: round; }
/* Over the numbers, each mark sits just over what's under it at its own spot: its note's stop, its
   marks, and the arcs over it. The renderer works out how high, in hundredths of a rem over the
   numbers' line, as --up, and the room each bar needs over that line, as --room. A wrapped row is as
   tall as its own bars' marks, and its bars' numbers line up, each bar as tall as the next. The
   marks start 0.08rem over the numbers' line, which is a cell's 0.42em padding under its top, so
   0.34rem under it. */
nns-riff { --lift: calc(0.08 * var(--rem)); --base: calc(0.34 * var(--rem)); }
nns-riff > nns-measure { margin-top: max(0px, calc(var(--room, 0) * var(--rem) / 100 - var(--base))); }
nns-riff :is(nns-note[tied], nns-beat[tuplet], nns-fermata, nns-slur, nns-join, nns-swing) { --at: calc(var(--up, 0) * var(--rem) / 100); }
/* An ending: a line over its bars, hooked down at its first, its number under the hook, just over
   what's under all its bars and clear of their bar lines' tops. Its line goes on over a bar line to
   its next bar, and the next ending's hook starts in a little, so the two don't touch. */
nns-riff > nns-measure[ending] { --at: calc(var(--up, 0) * var(--rem) / 100); }
nns-riff > nns-measure[ending]::before { content: ""; position: absolute; left: 0; right: calc(-1 * var(--rule)); top: calc(var(--base) - var(--at) - 0.74 * var(--rem)); height: calc(0.74 * var(--rem)); box-sizing: border-box; border-top: var(--rule) solid; }
nns-riff > nns-measure[ending-start]::before { left: calc(0.2 * var(--rem)); border-left: var(--rule) solid; }
nns-riff > nns-measure[ending-start]::after { content: attr(ending); position: absolute; left: calc(0.35 * var(--rem)); top: calc(var(--base) - var(--at) - 0.64 * var(--rem)); font-size: 0.6em; font-weight: 400; line-height: 1; }
/* Swing is said in the chart's header, or over a riff's first notes, at its first bar line. Its
   8ths stay written straight. */
nns-swing { font-style: italic; }
nns-riff nns-swing { position: absolute; left: 0; top: calc(var(--base) - var(--at)); translate: 0 -100%; font-size: 0.6em; font-weight: 400; line-height: 1.25; white-space: nowrap; }
/* A note's grace notes are small and high, before it, under its lines. Its marks center over its
   number, an accent over its staccato. A rest's fermata goes over its sign. */
nns-riff nns-graces { display: inline-flex; vertical-align: top; gap: 0.15em; margin-inline-end: 0.15em; font-size: 0.55em; }
nns-riff nns-tone { display: inline-block; position: relative; }
nns-riff :is(nns-staccato, nns-accent) { position: absolute; left: 50%; translate: -50%; }
nns-riff nns-tone > nns-staccato { bottom: calc(100% + var(--lift)); }
nns-riff nns-tone > nns-accent { bottom: calc(100% + var(--lift)); }
nns-riff nns-tone:has(> nns-staccato) > nns-accent { bottom: calc(100% + var(--lift) + 0.26 * var(--rem)); }
nns-riff nns-tone > nns-fermata { bottom: calc(100% + var(--lift) + var(--at)); }
nns-riff nns-rest > nns-fermata { bottom: calc(100% - var(--base) + var(--at)); }
nns-riff :is(nns-staccato, nns-accent) > svg { display: block; overflow: visible; }
nns-riff nns-staccato > svg { width: 0.16em; height: 0.16em; fill: currentColor; }
nns-riff nns-accent > svg { width: 0.6em; height: 0.38em; fill: none; stroke: currentColor; stroke-width: calc(0.07em * var(--stroke)); stroke-linecap: round; stroke-linejoin: round; }
/* A stop's notes stack over its last, which is on the line, a number's height each, and its
   staccato and accent go over its first. */
nns-riff nns-over { position: absolute; bottom: 100%; left: 50%; translate: -50%; width: max-content; display: flex; flex-direction: column; align-items: center; }
/* A tuplet: its number over it, and its counts where typed, 3:2. A join's letter looks the same. */
nns-riff :is(nns-beat[tuplet], nns-join)::before { position: absolute; inset-inline: 0; font-size: 0.6em; line-height: 1; text-align: center; }
nns-riff nns-beat[tuplet]::before { content: attr(tuplet); bottom: calc(100% - var(--base) + var(--at)); }
nns-riff nns-beat[tuplet] > :not([lines]) { padding-inline: 0.22em; }
/* A slur arches over its notes, from the first one's number to the last one's: the chart's tie arc,
   turned over. A hammer-on, pull-off, slide, bend or release arches the same way from the note
   before to its own, with its letter 0.05rem over its line, and its ends in a little so the next
   one's arc doesn't touch it. The renderer names the numbers as anchors, as it does a tie's chords. Without anchor
   positioning, neither draws. */
:is(nns-slur, nns-join) { display: none; }
@supports (anchor-name: --a) {
  nns-riff:has(> :is(nns-slur, nns-join)) { position: relative; }
  :is(nns-slur, nns-join) { display: block; position: absolute; left: anchor(var(--from) center); right: anchor(var(--to) center); top: calc(min(anchor(var(--from) top), anchor(var(--to) top)) - var(--lift) - var(--at) - 0.3em); height: 0.3em; }
  nns-join { left: calc(anchor(var(--from) center) + 0.1em); right: calc(anchor(var(--to) center) + 0.1em); }
  nns-join::before { content: attr(how); bottom: calc(100% + 0.03 * var(--rem) * var(--stroke) + 0.05 * var(--rem)); }
  :is(nns-slur, nns-join) > svg { display: block; width: 100%; height: 100%; overflow: visible; fill: none; stroke: currentColor; stroke-width: calc(0.06em * var(--stroke)); stroke-linecap: round; scale: 1 -1; }
}

/* A phrase is a four-row subgrid: the pickup on row 1, the margin on row 2, chords on row 3, words
   on row 4. The pickup gets the whole row, so it stays on one line and the bars keep the whole width.
   It hangs left of bar 1, in line with the section label. The margin sits over the row's chords, its
   right edge at the row's last bar line, and wraps there. html.rs counts that line from the grid's
   end, so paper's gutter doesn't move it. It never sizes a track, so it never widens a bar or lands on
   a barline, and a pickup keeps its own line. A lyric on one line runs under the bars from bar 1, in
   line with its chords, and the bars take only the chord row. */
nns-phrase { display: grid; grid-template-columns: subgrid; grid-template-rows: auto auto auto auto; }
nns-bar { display: grid; grid-row: 3 / 5; grid-template-rows: subgrid; }
nns-phrase > nns-margin { grid-row: 2; grid-column: 1 / var(--end); text-align: end; white-space: normal; text-wrap: balance; contain: inline-size; }
nns-phrase > nns-lyric { grid-row: 4; grid-column: 3 / -1; margin-left: var(--gap); }
nns-phrase:has(> nns-lyric) > nns-bar { grid-row: 3; }
nns-pickup, nns-lyric { text-wrap: balance; }
nns-pickup { grid-row: 1; grid-column: 1 / -1; justify-self: start; padding-inline: 0; }
nns-pickup::after { content: " \2192"; }
nns-phrase:not(:has(nns-lyric)) nns-bar { min-width: calc(3.5 * var(--rem)); }

/* A fold: each pass's words are a row of their own, in pass order, as in a hymnal. Each bar spans
   them, its words for each pass a row of its subgrid, blank where the pass sings none, so a pass's
   line stays level across the bars when another's wraps. A loose pass runs across its own row from
   bar 1. The bars hold their columns by line, each after its [bar], so a loose line on its row never
   pushes a bar aside. A pass's number leads its line as typed: upright, bold, and as wide for every
   pass. Its pickup follows, its arrow kept on its line. */
nns-phrase[passes] { grid-template-rows: auto auto auto repeat(var(--passes), [pass] auto); }
nns-phrase[passes] > nns-bar { grid-row: 3 / -1; grid-column: bar var(--bar); }
nns-phrase[passes] > nns-bar > nns-lyric { grid-row: auto; }
nns-phrase[passes] > nns-lyric { grid-row: pass var(--pass); }
nns-pass { font-style: normal; font-weight: bold; font-variant-numeric: tabular-nums; }
nns-lyric > nns-pickup::after { content: "\a0\2192"; }

/* Lyrics by pairs or phrase (#156): strict words run across their bars, a pair's from its first bar
   that sings to its end, a phrase's to the section's edge, like a loose lyric. Each bar holds its
   column by line, as in a fold, so the words never push one aside. The words read as plain text,
   since the chords above show where each bar starts. */
nns-phrase[across] > nns-bar { grid-row: 3 / 5; grid-column: bar var(--bar); }
nns-phrase > nns-lyric[pair] { grid-column: bar var(--bar) / span var(--span); }
nns-phrase > nns-lyric[phrase] { grid-column: bar var(--bar) / -1; }
/* Words that wrap hang 1.5em in, like a hymnal's turnover line, on tight lines, and each verse after
   the first sits a gap below the one before, so a turnover never reads as the next verse (#166). A
   verse's words in a bar of their own, like an ending's by pairs, sit level with its runs. */
nns-phrase > nns-lyric:is([pair], [phrase]) { padding-left: calc(0.3 * var(--rem) + 1.5em); text-indent: -1.5em; }
nns-phrase > nns-lyric:is([pair], [phrase]), nns-phrase > nns-lyric:is([pair], [phrase]) > nns-pickup { line-height: 1.1; }
nns-phrase[passes] > nns-lyric[pass]:is([pair], [phrase]):not([pass="1"]),
nns-phrase[passes]:has(> nns-lyric:is([pair], [phrase])) > nns-bar > nns-lyric:not([pass="1"], :empty) { margin-top: calc(0.5 * var(--rem)); }

/* A bar is a two-column grid on the phrase's chord and words rows: the chords sit in column 1 of the
   chord row, the extra-bar bullet centers in column 2, the lyric spans both columns of the words row.
   Column 1 is as wide as the chords and column 2 takes the rest, so the lyric's longest word widens
   the bar and words never spill into the next bar. No fr: Firefox ignores an item that spans an fr
   track when it sizes the tracks (bug 1530097), and the lyric spilled. The gap between bars is each
   bar's left padding, so a bar line with no marks takes no room and a short phrase's missing bars
   keep their share of the width. */
nns-bar { position: relative; grid-template-columns: min-content auto; padding-left: var(--gap); }
/* The chord slot holds a bare chord or a split bar's chords, which share a line under them. Both keep
   the same margin, so the first chord starts at the same x, and the line takes the room a bare chord
   keeps under its baseline. The chords stand on one baseline, so a diamond's name lines up with the
   chord beside it and its point stays above the line. The line is as heavy as a diamond's outline. */
nns-chords { grid-row: 1; grid-column: 1; align-self: end; font-size: var(--chord-size); font-weight: var(--chord-weight); white-space: nowrap; margin: calc(0.2 * var(--rem) + 1px) var(--chord-side) var(--chord-foot); }
nns-chords[split] { --line: max(1px, 0.06em * var(--stroke)); display: flex; align-items: last baseline; gap: calc(0.4 * var(--rem)); margin-bottom: 0; padding-bottom: calc(var(--chord-foot) - var(--line)); border-bottom: var(--line) solid currentColor; }
nns-chords[simile] { font-weight: bold; }
nns-chord { display: inline-block; }
nns-chord[nc] { font-size: 0.8em; }
/* A chord's marks are shapes the renderer draws in inline SVG, sized in em and rem and placed from the
   chord itself, so they hold at any size, on any font, and print as they show. A push is a chevron
   before the chord, two for a sixteenth, centered on the caps. The rest of the chord is a stack: its
   name, and over it, from the name up, its ticks (a slanted stroke per beat), marcato (a caret) and
   fermata, then an ending's line. Each mark centers on the whole name, number, suffix and bass. A
   phrase keeps a row for each kind of mark any of its chords has, so each kind lines up across the
   phrase and the numbers stay level. The stack is trimmed to the caps, so the rows stand on the cap
   line on any font: the first 0.3em over it, clear of a raised suffix or a slash chord's numerator.
   Each row is its mark's height and a 0.2rem gap. A chord is at least as wide as its ticks, so six
   beats in 12/8 don't reach the next chord's. */
:is(nns-push, nns-beats, nns-marcato, nns-fermata, nns-diamond, nns-tie) > svg { overflow: visible; fill: none; stroke: currentColor; }
:is(nns-push, nns-beats, nns-marcato) > svg { stroke-linecap: round; stroke-linejoin: round; }
nns-push > svg { height: 0.6em; vertical-align: calc(0.5cap - 0.3em); margin-right: 0.1em; stroke-width: calc(0.075em * var(--stroke)); }
/* A sixteenth's second chevron overlaps the first, as far along as keeps the gap between their arms
   at any stroke: the gap and the stroke over the sine of the arms' slant (1.47 is 1 / sin 42.9°).
   A chevron is 0.375em wide. */
nns-push > svg:not(:last-child) { margin-right: calc((0.0526em + 0.075em * var(--stroke)) * 1.47 - 0.375em); }
nns-phrase { --name-gap: 0px; --ticks-row: 0px; --marcato-row: 0px; --fermata-row: 0px; --ending-row: 0px; }
nns-phrase:has(nns-beats, nns-marcato, nns-fermata, nns-bar[ending]) { --name-gap: 0.3em; }
nns-phrase:has(nns-beats) { --ticks-row: calc(0.62 * var(--rem)); }
nns-phrase:has(nns-marcato) { --marcato-row: calc(0.59 * var(--rem)); }
nns-phrase:has(nns-fermata) { --fermata-row: calc(0.825 * var(--rem)); }
nns-phrase:has(nns-bar[ending]) { --ending-row: calc(0.6 * var(--rem) + 1px); }
nns-stack { display: inline-block; position: relative; text-box: trim-both cap alphabetic; padding-top: calc(var(--name-gap) + var(--ticks-row) + var(--marcato-row) + var(--fermata-row) + var(--ending-row)); }
nns-stack:has(> nns-beats) { min-width: calc(var(--beats) * 0.315 * var(--rem)); text-align: center; }
nns-stack:has(> nns-diamond) { text-box: normal; }
:is(nns-beats, nns-marcato, nns-fermata) { position: absolute; left: 50%; translate: -50%; }
nns-beats { bottom: calc(1cap + var(--name-gap)); display: flex; gap: calc(0.14 * var(--rem)); }
nns-beats > svg { display: block; height: calc(0.42 * var(--rem)); stroke-width: calc(0.065 * var(--rem) * var(--stroke)); }
nns-marcato { bottom: calc(1cap + var(--name-gap) + var(--ticks-row)); line-height: 0; }
nns-marcato > svg { display: block; width: 0.5em; height: 0.3125em; stroke-width: calc(0.075em * var(--stroke)); }
nns-stack > nns-fermata { bottom: calc(1cap + var(--name-gap) + var(--ticks-row) + var(--marcato-row)); }
/* The suffix is a superscript: it rises over the number but never grows the chord's line box. */
nns-suffix { vertical-align: super; font-size: 0.65em; line-height: 0; }
/* Slash chord: a typeset fraction, the font's numerator and denominator figures around its fraction
   slash. `sups` lifts SF Pro's numerators a little and leaves Inter's alone. A fifth bigger than the
   chord so the figures read from a stand; line-height 0 keeps the chord's line box. The suffix
   stands on the numerator's baseline, which Inter puts a third of the figures' em up. */
nns-chord:has(nns-bass) nns-degree, nns-bass { font-size: 1.2em; line-height: 0; }
nns-chord:has(nns-bass) nns-degree { font-feature-settings: "numr", "sups"; }
nns-chord:has(nns-bass) nns-suffix { font-size: 0.5em; vertical-align: 0.8em; }
nns-bass { font-feature-settings: "dnom"; }
nns-bass::before { content: "\2044"; }
/* Accidentals: flats and sharps are signs the renderer draws in inline SVG, sized in cap, so they
   don't depend on the font's glyphs or features. A sign stands on its figure's baseline at its cap
   height: the number's, the key letter's, the suffix's figures. In a slash chord it's the size of
   the figure beside it, hung from the cap line over the slash and standing on the baseline under it.
   An outline gives the signs' thin strokes the weight of the text beside them, a little heavier when
   small, as the font's small figures are. */
:is(nns-degree, nns-bass, nns-suffix, nns-key, nns-tone) > svg { height: 1cap; fill: currentColor; overflow: visible; stroke: currentColor; stroke-width: calc(0.06 * var(--sign)); stroke-linejoin: round; }
:is(nns-degree, nns-tone) > svg { margin-right: 0.06em; }
nns-suffix > svg { margin-inline: 0.04em; }
nns-key { white-space: nowrap; }
nns-key > svg { margin-inline: 0.08em 0.06em; }
nns-chord:has(nns-bass) nns-degree > svg { height: 0.5cap; vertical-align: 0.5cap; margin-right: 0.04em; }
nns-bass > svg { height: 0.5cap; margin-inline: 0.04em; }
nns-chord:has(nns-bass) :is(nns-degree, nns-bass) > svg { stroke-width: calc(0.1 * var(--sign)); }
/* Letters: a sign follows its letter, as B♭, and a slash chord is written on one line, as B/F♯, its
   bass a little smaller. */
nns-chart[letters] :is(nns-degree, nns-bass, nns-tone) > svg { margin-inline: 0.06em 0.04em; }
nns-chart[letters] nns-chord:has(nns-bass) nns-degree { font-size: 1em; font-feature-settings: normal; }
nns-chart[letters] nns-chord:has(nns-bass) nns-suffix { font-size: 0.65em; vertical-align: super; }
nns-chart[letters] nns-bass { font-size: 0.85em; font-feature-settings: normal; }
nns-chart[letters] nns-bass::before { content: "/"; }
nns-chart[letters] nns-chord:has(nns-bass) :is(nns-degree, nns-bass) > svg { height: 1cap; vertical-align: baseline; stroke-width: calc(0.06 * var(--sign)); }

/* A bar line sits on the chord row in two tracks: the bar before's closing barline, then the next
   bar's |: and time change, which reach into the gap to sit 0.25rem from its first chord. Each track
   is as wide as the section's widest marks there, so marks never land on each other or on chords,
   and each bar's chords still start at the same x down the section. Barlines are engraved symbols
   the renderer draws in inline SVG. A barline takes the chords' font size and bottom spacing, so its
   baseline is theirs on any font, and spans their cap height and a little more each way. Time
   signatures are a bold serif, like engraved music. A time change stands on the chords' baseline:
   Source Serif's tight lines put the baseline 0.13rem lower in its box than Inter's lines put the
   chords', so it sits that much higher. */
:is(nns-close, nns-open) { grid-row: 3; display: flex; align-items: end; gap: calc(0.25 * var(--rem)); position: relative; white-space: nowrap; font-weight: bold; }
nns-close:not(:empty):has(+ nns-open:not(:empty)) { padding-right: calc(0.25 * var(--rem)); }
nns-open:not(:empty) { margin-right: calc(0.25 * var(--rem) - var(--gap)); }
/* A bar line's marks keep as much room before them as after: 0.25rem, plus the chords' margin. */
:is(nns-close:not(:empty), nns-close:empty + nns-open:not(:empty)) { padding-left: calc(0.25 * var(--rem)); }
/* Past two passes without endings, how many times a repeat plays follows its :|, at the bar line's
   top. */
nns-times { align-self: start; font-size: calc(0.8 * var(--rem)); line-height: 1; }
nns-barline { font-size: var(--chord-size); padding-bottom: var(--chord-foot); }
nns-barline > svg { height: calc(1cap + 0.3em); vertical-align: -0.15em; fill: currentColor; overflow: visible; }
nns-open > nns-time { display: grid; font-size: var(--rem); padding-bottom: calc(0.23 * var(--rem) + 1px); }
/* Extra-bar bullet: centered between the chords and the next column's first chord. The bar stretches
   over the next bar's gap and into its chords' margin; the lyric and the ending line give that
   stretch back. The bullet's right margin gives back the part inside the next bar, plus the 0.25rem
   it keeps from its own chords, so with no room to spare it still clears the next chords. */
nns-bar[stretch] { --stretch: calc(var(--gap) + var(--chord-side)); margin-right: calc(-1 * var(--stretch)); }
nns-bullet { grid-row: 1; grid-column: 2; justify-self: center; align-self: end; margin-inline: calc(0.25 * var(--rem)) calc(0.55 * var(--rem) + 1px); padding-bottom: var(--chord-foot); font-size: var(--chord-size); font-weight: bold; }
nns-bar > nns-lyric { grid-row: 2; grid-column: 1 / -1; margin-right: var(--stretch, 0px); }

/* Ending: every bar it covers has [ending]; the first also has [ending-start]. Each bar draws its
   piece of the line in its row over the chords' marks, and so does each bar line between them and the
   closing barline after the last; the first bar starts at the first chord's left edge instead, with
   the hook and number. Each piece reaches 1px back over the one before it, so they join without a
   seam, and ends at its own right edge, so a row's last stays in its section. */
nns-bar[ending]::after, :is(nns-close:has(+ nns-open + nns-bar[ending]:not([ending-start])), nns-open:has(+ nns-bar[ending]:not([ending-start])), nns-bar[ending] + nns-close:not(:empty))::after, nns-open[ending]:not(:empty)::after { content: ""; position: absolute; top: 0; left: -1px; right: var(--stretch, 0px); height: 0.7em; border-top: 1.5px solid; }
nns-bar[ending-start]::after { left: calc(var(--gap) + 1px - 0.3 * var(--rem)); border-left: 1.5px solid; }
nns-bar[ending-start]::before, nns-open[ending]:not(:empty)::before { content: attr(ending); position: absolute; top: 2px; left: calc(var(--gap) + var(--chord-side)); font-size: calc(0.75 * var(--rem)); line-height: 1; }
/* An ending that starts with a time change starts its bracket at the bar line instead, number and
   all, so the time change sits under it, and the row grows for the number to clear the time change.
   The ending before stops its line at its closing barline, short of the new hook. */
nns-close + nns-open[ending]:not(:empty) { padding-left: calc(0.3 * var(--rem)); padding-top: calc(0.75 * var(--rem) + 2px); }
nns-open[ending]:not(:empty)::after { left: 0; right: 0; border-left: 1.5px solid; }
nns-open[ending]:not(:empty)::before { left: var(--chord-side); font-weight: normal; }
nns-open[ending]:not(:empty) + nns-bar[ending-start]::after { left: -1px; border-left: 0; }
nns-open[ending]:not(:empty) + nns-bar[ending-start]::before { content: none; }
nns-bar[ending] + nns-close:has(+ nns-open[ending]:not(:empty))::after { right: calc(0.25 * var(--rem)); }

nns-fermata { width: 0.85em; height: 0.5em; }
:is(nns-fermata, nns-diamond, nns-tie) > svg { width: 100%; height: 100%; }
nns-fermata > svg { display: block; stroke-width: calc(2.2 * var(--stroke)); }
nns-fermata circle { fill: currentColor; stroke: none; }
/* A diamond surrounds the whole chord, number, suffix and bass. A diamond only clears a box's corners
   at twice its width, so two hidden copies in a four-column grid double the width with the name
   centered. Its height is about the chord's own: a box 1.75em tall centered on the number's cap, and
   a suffix or slash raises its top 0.25em. The box holds that height in the layout, so a phrase with
   a diamond is a little taller, and the outline fills it with an even line. Its fermata stands on
   its point. */
nns-diamond { --raise: 0em; display: inline-grid; grid-template-columns: repeat(4, auto); position: relative; padding: calc((1.75em - 1cap) / 2) 0.45em; }
nns-diamond:has(nns-suffix, nns-bass) { --raise: 0.25em; }
nns-name { grid-row: 1; display: inline-block; white-space: nowrap; text-box: trim-both cap alphabetic; padding-top: var(--raise); }
nns-name:nth-child(1) { grid-column: 1 / 3; visibility: hidden; }
nns-name:nth-child(2) { grid-column: 2 / 4; }
nns-name:nth-child(3) { grid-column: 3 / 5; visibility: hidden; }
nns-diamond > svg { position: absolute; inset: 0; stroke-width: calc(0.06em * var(--stroke)); }
nns-diamond > nns-fermata { bottom: calc(100% + 0.2em); }
/* A tie is an arc under the chords, from the one before to the tied chord, center to center and
   across any bar line. A tie on a line's first chord ties to the line above, so like engraving
   across a system break it's the arc's second half, from the line's first bar line. The renderer
   names the two chords as anchors and hangs the arc on the phrase, so it's placed from where they
   landed, at any size, on any font. Under the chords there's no room for it, so a phrase with a tie
   makes a row for it, 0.15rem clear of the split's line (and its room under a bare chord) and the
   arc's 0.4rem. Each end is 0.15em in from its chord's center, clear of a diamond's point. Without
   anchor positioning, a tie is a _ before the number. */
nns-tie { display: none; }
@supports not (anchor-name: --a) { nns-chord[tie] nns-degree::before { content: "_"; } }
@supports (anchor-name: --a) {
  nns-phrase:has(> nns-tie) { --tie: calc(0.55 * var(--rem)); position: relative; }
  nns-phrase:has(> nns-tie) nns-chords { margin-bottom: calc(var(--chord-foot) + var(--tie)); }
  nns-phrase:has(> nns-tie) nns-chords[split] { margin-bottom: var(--tie); }
  nns-phrase:has(> nns-tie[start]) > nns-close:first-of-type { anchor-name: --line; }
  nns-tie { display: block; position: absolute; left: calc(anchor(var(--from) center) + 0.15em); right: calc(anchor(var(--to) center) + 0.15em); top: calc(max(anchor(var(--from) bottom), anchor(var(--to) bottom)) + 0.25 * var(--rem) + 1px); height: calc(0.4 * var(--rem)); font-size: var(--chord-size); color: var(--chord); }
  nns-tie[start] { left: anchor(--line left); top: calc(anchor(var(--to) bottom) + 0.25 * var(--rem) + 1px); }
  nns-tie > svg { display: block; stroke-width: calc(0.06em * var(--stroke)); stroke-linecap: round; }
}

/* Song page: reading.js lays the chart out in columns, and the song gets the screen's whole width.
   One column in one long scroll runs down the page, and scrolling settles with a section (or the
   title, or the size warning above it) at the top. Screenfuls are read down each column in turn. A screenful is as tall as the screen with Safari's toolbars showing (svh), and scrolling
   settles on each one in turn, but two columns in one long scroll settle nowhere. With the toolbars
   hidden, the next one peeks in below, and the chart's bottom padding lets the last one still reach
   the top. */
:root:has(nns-chart:not([paper])[columns]) { scroll-snap-type: y mandatory; }
:root:has(nns-chart:not([paper])[columns="1"][paging="scroll"]) { scroll-padding-top: calc(8px + 1rem); }
body:has(nns-chart[columns]) { max-width: none; margin-bottom: 0; padding-bottom: 0; }
body:has(nns-screenful) { margin-top: 0; padding-top: 0; }
/* As a grid item, the chart would grow to its widest section instead of letting it overflow. So
   would the editor's and Convert's preview. */
:is(nns-chart:not([paper])[columns], #preview nns-chart) { min-width: 0; }
/* A size you picked draws at that size, so a section with a bar too wide for the screen scrolls
   sideways on its own, and the page doesn't (reading.js). */
:is(nns-chart:not([paper])[columns], #preview nns-chart) nns-section { overflow-x: auto; }
nns-chart:not([paper])[columns="1"] > * { scroll-snap-align: start; }
nns-chart:has(> nns-screenful) { padding-bottom: calc(100lvh - 100svh); }
/* The screen's height with the toolbars showing, resolved to px, so reading.js can tell a rotation
   from the toolbars hiding. */
@property --screen { syntax: "<length>"; inherits: false; initial-value: 0px; }
nns-chart { --screen: 100svh; }
nns-screenful { display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); column-gap: var(--column-gap); height: 100svh; box-sizing: border-box; padding-block: calc(8px + 1rem); scroll-snap-align: start; scroll-snap-stop: always; }
nns-chart[columns="2"] > nns-screenful { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* PDF columns, the screen's own pick when it's two of them wide: --columns of them, sharing the
   screen's width, but none wider than a PDF page at the chart's size (paper, below). */
nns-chart[fitted] > nns-screenful { grid-template-columns: repeat(var(--columns), minmax(0, var(--page-width))); justify-content: center; }
nns-chart[paging="scroll"] > nns-screenful { scroll-snap-align: none; }
nns-column > :first-child { margin-top: 0; }
/* Guides, each on unless the URL turns it off (?rules=off&jumps=off, reading.js). Rules split a
   screenful's columns down the middle of their gutter. Jumps end each column but the last by naming
   the section the next one starts with, like "Ch1 ↗", and Next ends the last by naming the next
   screenful's, like "Next: Ch1 →", where you turn. Both take a line kept for them under every
   column, so dealing leaves room for them. */
nns-screenful { --jump: calc(1.3 * var(--lyric) + 0.55 * var(--rem)); }
nns-screenful > nns-column { margin-bottom: var(--jump, 0px); }
nns-jump { display: block; margin-top: calc(0.35 * var(--rem)); font-weight: 600; white-space: nowrap; }
nns-chart[rules] > nns-screenful > nns-column { position: relative; }
nns-chart[rules] > nns-screenful > nns-column + nns-column::before { content: ""; position: absolute; inset-block: 0 calc(-1 * var(--jump, 0px)); left: calc(-1.5 * var(--rem)); border-left: 1px solid var(--line); }
/* The shelf button floats in the bottom right corner, over the song, when it shows. Only it covers
   it, and every column keeps the screen's whole height. The bottom padding is the screenful's. */
main > footer { position: fixed; right: calc(8px + 1rem); bottom: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; padding-bottom: calc(8px + 1rem); line-height: 1.5; color: var(--soft); pointer-events: none; }
main > footer > * { pointer-events: auto; }
/* Hidden, as the page opens (shelf.js), the shelf button covers nothing and takes no taps. Tabbing to
   it shows it. */
#shelf-button { transition: opacity 0.2s; }
main > footer[faded] > #shelf-button:not(:focus) { opacity: 0; pointer-events: none; }
/* A chip: a few words on the page's color, at least a tap tall, over the chart: the hint, Chart
   updated, and a link that no longer works. Words that wrap set their lines as tight as text, so
   they cover as little of the chart as they can. */
.chip { display: grid; align-content: center; box-sizing: border-box; min-height: var(--tap); margin: 0; padding: 0.25em 0.6rem; border-radius: 1rem; line-height: 1.35; background: var(--page); }
/* A save from another device says so, then fades (live.js). */
main > footer > div { display: flex; gap: 0.5rem; }
main > footer #updated { transition: opacity 0.6s, display 0.6s allow-discrete; }
#updated[hidden] { opacity: 0; }
@media (prefers-reduced-motion: reduce) { :is(#shelf-button, main > footer #updated) { transition: none; } }
/* The shelf, the same on the song page and a PDF's page: two lines across the bottom, where you are
   and then what you set. Every size is in em, so it holds at any text size. It takes at most half
   the screen, and scrolls past that, so the song or the PDF keeps the rest. The song page's waits
   behind the shelf button and opens over the song's foot, or beside it on a wide screen (below), with
   its own close button; a PDF's is always open. */
.round { width: var(--tap); height: var(--tap); padding: 0; display: grid; place-items: center; border-radius: 50%; border: 1px solid var(--line); background: var(--page); color: var(--ink); font-size: 1.15em; line-height: 1; cursor: pointer; }
main > footer > .round { box-shadow: 0 2px 8px rgb(0 0 0 / 0.2); }
#shelf { display: flex; flex-wrap: wrap; align-items: end; gap: 0.75em 1.25em; box-sizing: border-box; max-height: 50svh; overflow-y: auto; margin: 0; padding: 0.75em 1em; border: 0; border-top: 1px solid var(--line); background: var(--raised); color: var(--ink); line-height: 1.35; }
#shelf[popover] { inset: auto 0 0; width: auto; box-shadow: 0 -4px 16px rgb(0 0 0 / 0.2); }
#shelf[popover]:not(:popover-open) { display: none; }
/* A line: the first is the trail and Theme, beside the song page's close button. Each wraps as it
   needs. A PDF's page says why a save failed above them, pinned at the shelf's top as the shelf
   scrolls, so moving on from a refused field never hides why. */
.line { flex-basis: 100%; min-width: 0; display: flex; align-items: center; gap: 0.75em 1.25em; }
.scroll { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 0.75em 1.25em; }
.cells { align-items: end; }
.end { display: flex; align-items: center; gap: 0.75em 1em; margin-left: auto; }
.pinned { flex-basis: 100%; margin: 0; position: sticky; top: 0; z-index: 1; background: inherit; }
/* A status, a field's output and the title's say nothing while they have nothing to say. Only the
   shelf's is pinned: the song page's note over its title scrolls away with the song. */
:is(.status, .field > output, .title output):empty { display: none; }
/* The trail: where you are, the current page marked, as the header marks it. */
.trail { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25em 0.75em; min-height: var(--tap); }
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25em 0.45em; }
.crumbs > [aria-hidden] { color: var(--quiet); }
/* The header's links, the trail's, a card's and a foot's underline only under the pointer. */
:is(body > header, .trail, .card, .foot) a { text-decoration: none; }
:is(body > header, .trail, .card, .foot) a:hover { text-decoration: underline; }
/* An action and what it says: a button and its status, Delete, the notice and its Undo, Save and
   why a save failed. Beside it when it fits, under it when it doesn't. A card's Delete says it on a
   line under its links. */
.action { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0.5em 0.75em; min-width: 0; margin: 0; }
/* A setting: a small label over its control. It shrinks to the space it has, its label's words
   wrapping and its select stopping at its edge, so a form fits a phone at any text size. Lyrics and
   Holes are toggles in place of a label, and off, each dims its stepper, whose − and + are off too
   (stepper.js), and Lyrics dims Lyrics by. Lyrics by sits beside the lyric size, and the rest of
   Lyrics spans both. Its label and error keep clear of its control's focus ring. */
/* A field of parts, like the Header, shows while any part does. */
.field:has(label[hidden]):not(:has(label:not([hidden]))) { display: none; }
.field { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start; gap: calc(0.3em + 2 * var(--ring)); min-width: 0; }
/* A long field, a whole text like the editor's and Convert's, keeps a paragraph's space around
   it, below any of its layout's own margins. Controls side by side, like a size beside its key,
   share their field's rows, and the rest of the field spans them. */
.long { margin-block: 1em; }
.controls { grid-template-columns: auto auto; column-gap: 0.5em; }
.controls > :not(select, .stepper, .seg) { grid-column: 1 / -1; }
legend.label { float: left; padding: 0; }
.field > [id$="-error"] { font-size: var(--small); color: var(--error); }
.label { display: flex; align-items: center; gap: 0.35em; font-size: var(--small); font-weight: 500; color: var(--quiet); }
/* A toggled field, a size behind its checkbox like Lyrics or Holes, dims while it's off, and stays
   put, so ticking it moves nothing. */
.toggled:has(> .toggles input:not(:checked)) :is(.stepper, .seg, .rows) { opacity: 0.4; }
/* A control's box: a line around it, filled like the page. A control is a tap tall, and a pill is
   round at its ends. A field, a select and a text box are rounded less. A stepper is a pill: −, its
   number and unit, +. */
:is(.stepper, .seg, .toggles label, .pill, .text, select, textarea) { box-sizing: border-box; border: 1px solid var(--line); background: var(--page); }
:is(.stepper, .seg, .toggles label, .pill, .text, select) { min-height: var(--tap); }
:is(.stepper, .seg, .seg :is(label, a), .toggles label, .pill) { border-radius: calc(var(--tap) / 2); }
:is(.text, select, textarea, .sheet > .copy) { border-radius: 0.6em; }
/* A field that failed is outlined red, beside its words, over its box's line. The box's :is() is as
   heavy as its heaviest part, .toggles label, so this is as heavy, and comes after it. */
:is(input, select, textarea)[aria-invalid="true"] { border-color: var(--error); }
.stepper { display: inline-flex; align-items: center; transition: opacity 0.15s; }
.stepper button { width: calc(var(--tap) - 2px); height: 100%; padding: 0; border: 0; border-radius: 50%; background: none; font-size: 1.2em; line-height: 1; cursor: pointer; }
.stepper button:disabled { opacity: 0.3; cursor: default; }
.stepper input { width: calc(2ch + 0.25em); padding: 0; border: 0; background: none; text-align: right; font-variant-numeric: tabular-nums; appearance: textfield; }
.stepper input::-webkit-inner-spin-button, .stepper input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.stepper input:focus-visible { outline: none; }
.stepper input[inputmode=decimal] { width: calc(4ch + 0.25em); }
.unit { padding-left: 0.25em; color: var(--quiet); }
/* Columns are one pill of radios, the picked one filled. When they don't fit, they wrap onto more
   lines inside it, each line's options stretched evenly to fill it. Each toggle, like Bold, Lyrics
   or a header part, is a pill of its own, filled with a ✓ when it's on, so it shows by shape as
   well as fill. A screen reader reads its name alone, and says it's on as a checkbox does. */
.seg { display: inline-flex; flex-wrap: wrap; padding: 0.2em; gap: 0.15em; }
.seg > :is(label, a) { flex-grow: 1; justify-content: center; }
.seg :is(label, a) { min-height: calc(var(--tap) - 0.4em - 2px); }
.seg :is(label, a), .toggles label { position: relative; display: flex; align-items: center; padding: 0 var(--pad); cursor: pointer; white-space: nowrap; }
.seg a { color: inherit; text-decoration: none; }
.seg input, .toggles input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
/* What's picked is filled: a choice, the open layout, an open fold, and the column Convert's Show
   shows (its #fragment, or the lyric chart without one). */
:is(.seg, .toggles) label:has(:checked), .pill[aria-current], [open] > summary.pill,
#convert:not(:has(:is(#chart-text, #preview, #preview nns-section):target)) [href="#lyric-chart"],
#convert:has(#chart-text:target) [href="#chart-text"],
#convert:has(:is(#preview, #preview nns-section):target) [href="#preview"] { background: var(--picked); color: var(--on-picked); border-color: var(--picked); }
.toggles { display: flex; gap: 0.35em; }
.toggles label:has(:checked)::before, [open] > summary.pill::before { content: "\2713" / ""; margin-right: 0.35em; }
/* A fold's summary drawn as a toggle, like the editor's Lyric chart and Convert's Chords, is as wide
   as its words, with no marker of the browser's. A note in it, like Chords', runs on with its words,
   wrapping with them, and is quiet while it's closed. */
summary.pill { width: fit-content; }
:not([open]) > summary.pill > span { color: var(--quiet); }
summary.pill::-webkit-details-marker { display: none; }
/* A field's text is as wide as an email, or the space it has. */
.text { width: min(100%, 20em); padding: 0 var(--pad); }
.pills { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35em 0.5em; }
/* A pill: a button, or a link that does what one does, like a layout. Its words are ink wherever it
   sits, like in a quiet status. One line of them is centered in a tap's height. When it's alone on
   its line and still too wide, they wrap inside it as one run, a ✓ on their first line, in
   balanced lines as tight as text. */
.pill { display: inline-block; padding: calc((var(--tap) - 1lh) / 2 - 1px) var(--pad); line-height: 1.25; text-align: center; text-wrap: balance; color: var(--ink); text-decoration: none; cursor: pointer; }
/* Save layout's Name and button sit on the shelf like a PDF's Name and Save PDF. */
#save-layout { display: contents; }
.quiet { color: var(--quiet); }
.theme { display: flex; align-items: center; gap: 0.4em; white-space: nowrap; }
/* A key on its way waits beside a spinner, and one that couldn't come says why (reading.js). */
.field > output { font-size: var(--small); }
/* Chords: one label over their key and size, side by side, and under them what a key or size says. */
#chords > :is(select, .stepper) { grid-row: 2; }
/* What the sizes say keeps its line when it says nothing, so it comes and goes without moving a
   setting under a tap. */
#fitted { display: block; min-height: 1lh; }
/* Breaks, and Lyrics by's labels, and Convert chart's rules' labels: a row per break or label, in the
   chart's order, its section beside where it starts or its own pick and its ×, then Add, quiet until
   it's picked. A row too wide for its line wraps, its pick leaving its × room beside it. */
.rows { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em 1em; }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; white-space: nowrap; }
.row .section { font-weight: 600; }
.row select { max-width: calc(100% - var(--tap) - 0.5em); }
.row .round { flex: none; }
.rows > select:has(option[value=""]:checked) { color: var(--quiet); }
/* A button drawn as words, with no padding, underlined under the pointer: Delete and Sign out, so
   Delete chart and Delete song share a row beside the wide shelf's close button, and a flag's line
   in the editor. A danger is red, a tap tall. */
.bare { padding: 0; border: 0; background: none; text-align: start; cursor: pointer; }
.bare:hover { text-decoration: underline; }
.danger { min-height: var(--tap); color: var(--error); white-space: nowrap; }
/* An address, like a share's link or an email, is one long word, so it breaks anywhere to fit. */
.address { overflow-wrap: anywhere; }
#shrunk { margin: 0 0 1rem; font-size: 1rem; color: var(--warning); }
/* What a change did, with its Undo, or why it wasn't made. The song page has it over the title, as
   #shrunk. */
#notice { font-size: 1rem; }
nns-chart #notice { margin-bottom: 1rem; }
/* A status leads with what failed, like "Not saved.", in red. An output is a status too. A pill in
   one, like Convert's Write it again, keeps the page's text size, so it's a tap tall where the
   status is small. What it offers to do, like Keep mine and Use newer, wraps beside its words as
   one group, never one pill alone. */
:is(output, [role="status"]) strong { color: var(--error); }
:is(output, [role="status"]) .pill { font-size: 1rem; }
:is(output, [role="status"]) > .pills { display: inline-flex; vertical-align: middle; }
nns-chart[lyrics="off"] :is(nns-lyric, nns-pickup) { display: none; }

/* The song's page (#153): its title, then a card per chart, with its name to read it, Edit, its
   History and Delete, then its layouts, PDFs and shares as the shelf lists them, so the two read as
   one app. Cards sit side by side where they fit. Add a chart and Convert chart sit under them, and
   the song's History and Delete song at the foot. Settings reads the same, a session a card, and
   so do Shares and a chart's new share, whose form is a row of fields like Add a chart's. */
/* The title is a field like the app's others, labeled Title, with the song's name big in it, clear of
   its focus ring. It wraps, as tall as its lines, so it shows the whole name, as typed. */
.title { display: grid; gap: calc(0.4em + 2 * var(--ring)); margin: 0; }
.title .text { width: 100%; min-height: 0; padding: 0.1em 0.3em; border-radius: 0.3em; font: inherit; font-weight: bold; field-sizing: content; resize: none; hyphens: manual; }
.group { display: grid; gap: 0.75em; }
/* Cards: a card per thing, side by side where they fit: charts, sessions. Its name has a line of
   its own, its links and Delete the next, and what Delete says goes under them. A card that's only
   its name is all link: 0.8em of its 1.25em is the card's 1em. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 21em), 1fr)); gap: 1rem; margin: 0; padding: 0; list-style: none; }
.card { display: grid; align-content: start; gap: 1em; padding: 1em; border: 1px solid var(--line); border-radius: 0.9em; }
.card > .head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25em 1em; }
.card .name { flex-basis: 100%; font-size: 1.25em; font-weight: 600; }
.card > .name:only-child { margin: -0.8em; padding: 0.8em; }
.card .head form { display: contents; }
.card .head output { flex-basis: 100%; }
/* A stack: fields one over another, like Sign in */
.stack { display: grid; gap: 1em; justify-items: start; margin: 0; }
/* Across: things side by side, wrapping, lined up at their feet, like fields and their button, Add
   a chart and Convert chart, Undo and Redo. A plain link among them, or among a card's actions,
   like Edit beside Delete, is a tap tall, its words centered on the pills' line, and its lines as
   tight as text when it wraps. The foot: actions under a line, like a song's History and Delete
   song. */
.across { display: flex; flex-wrap: wrap; align-items: end; gap: 0.75em 1rem; min-inline-size: 0; }
:is(.across, .card > .head) > a:not(.pill, .name) { padding-block: calc((var(--tap) - 1lh) / 2); line-height: 1.25; }
.foot { padding-top: 1rem; border-top: 1px solid var(--line); }
/* What a thing is, a small label over each part: a device asking, a share */
.facts { display: grid; gap: 1em; margin: 0; }
.facts dd { margin: 0; }

/* Flags (editor): the element a problem sits on is outlined; the list below names them by line. */
:is(nns-section, nns-phrase, nns-chord)[error], nns-bar[error] > nns-chords { outline: 2px solid var(--error); outline-offset: 2px; }
:is(nns-section, nns-phrase, nns-chord)[warning], nns-bar[warning] > nns-chords { outline: 2px solid var(--warning); outline-offset: 2px; }
nns-diagnostics { display: block; margin-top: calc(1.5 * var(--rem)); font-size: 0.9rem; }
nns-diagnostic { display: block; margin-block: 0.25rem; }
nns-diagnostic::before { content: "Line " attr(line) ": "; font-variant-numeric: tabular-nums; font-weight: 600; }
nns-diagnostic[bar]::before { content: "Line " attr(line) ", bar " attr(bar) ": "; }
nns-diagnostic[error]::before { color: var(--error); }
nns-diagnostic[warning]::before { color: var(--warning); }

/* Preview (editor and import): dimmed while it's out of date, under a note that says why. A preview slower than
   0.5 s gets a spinner at its top right. */
/* A newer save sits beside yours when there's room for both. */
#versions:has(> #newer:not([hidden])) { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 30ch), 1fr)); column-gap: 1rem; }
#preview { position: relative; min-width: 0; }
[stale] > :is(nns-chart, object) { opacity: 0.35; }
#previewing { position: absolute; top: 0; right: 0; }
/* A warning has a line down its side: a stale preview, an unprinted PDF. */
.warning { margin: 0; padding-left: 0.5rem; border-left: 3px solid var(--warning); }
.spinner { display: inline-block; width: 1em; height: 1em; box-sizing: border-box; border: 2px solid var(--line); border-top-color: var(--ink); border-radius: 50%; vertical-align: -0.15em; animation: spin 0.8s linear infinite; }
@keyframes spin { to { rotate: 1turn; } }
/* Save (editor): one save at a time, so Save is disabled while one runs. aria-disabled keeps focus on it. */
button[aria-disabled="true"] { opacity: 0.55; cursor: progress; }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 2.4s; } }

/* A page that fills the screen, its parts each scrolling on their own: a PDF's page always, edge to
   edge, and the editor and Convert once they split, on a landscape screen at least 64em wide, each
   half at least 32em, in the column every page has, its padding inside its height, so the header
   stays put. Narrower, the editor and Convert scroll as one page, like any other. Bigger text makes
   the screen fewer em wide, so they stack again. */
body:is(.fill, .split) { display: flex; flex-direction: column; height: 100svh; margin-block: 0; box-sizing: border-box; }
body.fill { max-width: none; margin-inline: 0; }
body.split { max-width: calc(var(--column) + 2rem); }
body:is(.fill, .split) > main { flex: 1; min-height: 0; }

/* The editor's halves: the editor, and its preview, Convert's too. On a narrow screen they're no
   boxes of their own, so the preview stacks under Save. Split, the editor fills the left half and
   the preview the right, as tall as the screen under the nav. The chart's name is over it, and Save
   and why a save failed under it. */
#edit, #side { display: contents; }
/* A converted chart's lyric chart, folded over its chart text, closed, to read, as far under the
   name as the chart text is under it. Open, it's laid out as on Convert chart: over the chart text,
   beside the preview, and from 80em a column of its own, each filling its share of the screen. It
   doesn't wrap, so its chords stay over their words. */
details#lyric-chart { margin-top: 1em; }
#lyric-chart textarea { white-space: pre; }
#lyric-chart p { margin-bottom: 0; }

/* Convert chart: its lyric chart, the chart text that writes, and the preview of that. Its fields
   are a group. Neither text wraps, so a lyric chart's chords stay over their words, and long lines
   scroll sideways. On a narrow screen, Show's links pick the one you see, as the URL's #fragment
   names it, the lyric chart without one, and the page scrolls. Split, the lyric chart sits over the
   chart text, beside the preview, and from 80em they're three columns. Both fill the screen under
   the header, under the fields and Convert chart. */
#convert textarea { white-space: pre; }
/* Each rule: its name, the whole chart's pick, and its labels' rows, wrapping as they need. */
#rules { display: grid; gap: 0.5em; }
.rule { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em 0.75em; }
/* The Chords list, folded: each chord as written beside what it writes, as many to a row as fit.
   Its fold's words wrap when it's wider than the screen, and so does a chord's box. */
#chords-list > p { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 11em), 1fr)); gap: 0.3em 1em; margin: 0.5em 0 0; }
#chords-list label { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; }
#chords-list label > span { min-width: 5em; font-family: var(--mono); }
#chords-list input { width: 6em; font-family: var(--mono); }
/* The Reuses: a row for each section played again, its tick beside its words, the how-close of them
   quiet. */
#reuses > p { display: grid; gap: 0.35em; flex-basis: 100%; margin: 0; }
#reuses label { display: flex; align-items: baseline; gap: 0.5em; }
#reuses small { font-size: inherit; color: var(--quiet); }
#show { margin-block: 1em 0; }
/* The chart text: what wrote it beside its label when it fits, under it when it doesn't, like an
   action and its status, so Write it again has the line's width. Split, it's a grid (below). */
#chart-text { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.75em; }
#written { flex: 1 1 15em; }
#chart-text > textarea { flex-basis: 100%; grid-column: 1 / -1; align-self: stretch; }
/* What wrote the chart text says so quietly. A failed write's words are an error's, and a changed
   lyric chart or rule's are the text's own. */
#written { color: var(--quiet); }
#written [data-state="changed"] strong { color: var(--ink); }
/* What converting did, marked on its preview for the writer to check, in --mark. A section played
   again says under its heading how it differs from the time before. Its bars whose chords differ
   are dashed, and its phrases past the time before's are tinted. What the rules did: a pair's
   underline is doubled, and a joined line's first bar gets a bar line. */
nns-again { grid-column: 1 / -1; font-size: calc(0.8 * var(--rem)); font-weight: 600; color: var(--mark); }
nns-bar[differs] { outline: 2px dashed var(--mark); outline-offset: 1px; border-radius: 2px; }
nns-bar[past] { background: color-mix(in srgb, var(--mark) 10%, transparent); }
nns-bar[paired] > nns-chords { border-bottom-color: var(--mark); box-shadow: 0 max(1px, 0.06em) var(--mark); }
nns-bar[joined] { box-shadow: inset calc(0.2 * var(--rem)) 0 var(--mark); }
/* A bar pointed at marks its chords and words in a copy behind the lyric chart (convert.js). Both sit
   in one cell, drawn alike, the lyric chart clear over the copy and the copy's text clear. The copy
   pads out past its ends, so it scrolls as far as the lyric chart. */
#preview nns-bar[pointed] { background: color-mix(in srgb, var(--mark) 24%, transparent); }
#lyric-chart > .sheet { justify-self: stretch; display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); }
#lyric-chart > .sheet > * { grid-area: 1 / 1; position: relative; margin: 0; border-width: 1px; border-style: solid; white-space: pre; }
#lyric-chart > .sheet > .copy { overflow: hidden; padding-right: 3em; padding-bottom: 3em; border-color: transparent; color: transparent; background: var(--page); }
#lyric-chart > .sheet > textarea { background: transparent; }
#lyric-chart mark { color: transparent; background: color-mix(in srgb, var(--mark) 32%, transparent); border-radius: 2px; }
/* Marks, over the preview, off hides them all. It shows only when the preview has some. */
#side:not(:has(:is(nns-again, nns-bar[from], nns-bar[paired], nns-bar[joined]))) > #marks { display: none; }
#marks { margin: 0; }
#convert:has(#marks input:not(:checked)) nns-again { display: none; }
#convert:has(#marks input:not(:checked)) nns-bar { outline: none; background: none; box-shadow: none; }
#convert:has(#marks input:not(:checked)) nns-bar[paired] > nns-chords { border-bottom-color: currentColor; box-shadow: none; }
#convert:has(#marks input:not(:checked)) #lyric-chart mark { background: none; }
/* The editor's and Convert's layouts by screen, each condition's rules in one block, since CSS
   can't name a media query: stacked on a portrait screen or under 64em, split from 64em, and from
   80em, a column of its own for a lyric chart. */
@media (orientation: portrait), (width < 64em) {
  body.split { height: auto; margin-block: revert; }
  /* A section in the preview, as a reuse's Show names it, picks the preview. */
  #convert:not(:has(:is(#chart-text, #preview, #preview nns-section):target)) > :is(#rules, #chart-text, #side),
  #convert:has(#chart-text:target) > :is(#lyric-chart, #side),
  #convert:has(:is(#preview, #preview nns-section):target) > :is(#lyric-chart, #rules, #chart-text) { display: none; }
  /* Show stays in sight over the page as it scrolls, so a picked column, or a section of the
     preview, scrolls to the top under it. It keeps to one line, a tap tall, and scrolls sideways
     when it doesn't fit, like the shelf's lines on a phone (below), so it never covers more of the
     page. A preview's section too wide for the screen scrolls sideways on its own (above), so the
     page never does. */
  #show { position: sticky; top: 0; z-index: 1; flex-wrap: nowrap; max-width: 100%; }
  #lyric-chart, #chart-text, #preview, #preview nns-section { scroll-margin-top: calc(var(--tap) + 1.5em); }
  #convert { min-width: 0; }
}
@media (orientation: landscape) and (width >= 64em) {
  /* Split, the preview is beside the text, under a line down its side. The phrase the cursor is on
     is marked, in --here, and a bar taps to put the cursor at its chords (preview.js). */
  #side { display: grid; align-content: start; gap: 1rem; min-height: 0; overflow-y: auto; padding-left: 1rem; border-left: 1px solid var(--line); }
  #side nns-phrase[here] { background: var(--here); box-shadow: 0 0 0 calc(0.25 * var(--rem)) var(--here); scroll-margin-block: calc(0.25 * var(--rem)); }
  #side nns-bar[at] { cursor: pointer; }
  body.editor > main { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #edit { display: flex; flex-direction: column; gap: inherit; min-height: 0; }
  #edit > form { flex: 1; min-height: 0; display: grid; grid-template: auto minmax(0, 1fr) auto / minmax(0, 1fr); align-items: center; column-gap: 1rem; }
  #edit > form:has(> #lyric-chart) { grid-template-rows: auto auto minmax(0, 1fr) auto; }
  #edit > form:has(> #lyric-chart[open]) { grid-template-rows: auto minmax(0, 2fr) minmax(0, 3fr) auto; }
  /* A details's content is a box of its own, so it's a grid too, for the lyric chart to fill. */
  #lyric-chart[open] { align-self: stretch; display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; }
  #lyric-chart[open]::details-content { display: grid; grid-template-rows: minmax(0, 1fr) auto; min-height: 0; }
  #lyric-chart textarea { min-height: 0; resize: none; }
  #versions { align-self: stretch; min-height: 0; display: grid; grid-auto-rows: minmax(0, 1fr); }
  #versions > .field:not([hidden]) { align-self: stretch; display: flex; flex-direction: column; min-height: 0; }
  #versions textarea { flex: 1; min-height: 0; resize: none; }
  body.convert > main { grid-template-rows: auto auto minmax(0, 1fr); }
  body.convert > main:has(> #notice) { grid-template-rows: auto auto auto minmax(0, 1fr); }
  body.convert > main > p { margin-block: 0; }
  #convert { min-height: 0; display: grid; gap: 0.5rem 1rem; grid-template: "fields fields" auto "lyric preview" minmax(0, 2fr) "rules preview" auto "text preview" minmax(0, 3fr) / minmax(0, 1fr) minmax(0, 1fr); }
  #rules { grid-area: rules; }
  #convert > fieldset:first-child { grid-area: fields; }
  #show { display: none; }
  #convert > #lyric-chart { grid-area: lyric; display: flex; flex-direction: column; min-height: 0; margin: 0; }
  #lyric-chart > .sheet { flex: 1; min-height: 0; }
  #chart-text { grid-area: text; display: grid; grid-template: auto minmax(0, 1fr) / auto minmax(0, 1fr); min-height: 0; margin: 0; }
  #convert textarea { flex: 1; min-height: 0; resize: none; }
  #convert > #side { grid-area: preview; }
}
@media (orientation: landscape) and (width >= 80em) {
  body.editor > main:has(#lyric-chart[open]) { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  #edit > form:has(> #lyric-chart[open]) { grid-template: auto minmax(0, 1fr) auto / repeat(2, minmax(0, 1fr)); }
  #edit > form:has(> #lyric-chart[open]) > :is(p, div) { grid-column: 2; }
  #lyric-chart[open] { grid-area: 1 / 1 / -1; }
  #convert { grid-template: "fields fields fields" auto "lyric rules preview" auto "lyric text preview" minmax(0, 1fr) / minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); }
}

/* New PDF lays out its chart's song page here, out of sight, to see whether two columns fit (pdfs.js). */
iframe.measure { position: fixed; inset: 0; width: 100%; height: 100%; border: 0; visibility: hidden; }

/* A PDF's page: its file fills the screen in the browser's own viewer, above its shelf, which is
   always open. The page is a class on body, not a :has() on it:
   that re-styles the page on each change under it, and the song page's layout makes thousands, about
   5x slower. */
body.pdf { padding: 0; }
body.pdf > main { order: -1; display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem 1rem 0; }
/* While the file is behind its shelf, it's dimmed under a spinner (pdf.js). */
#viewer { position: relative; flex: 1; min-height: 0; }
#viewer > object { display: block; width: 100%; height: 100%; }
#printing { position: absolute; top: 50%; left: 50%; translate: -50% -50%; font-size: 2rem; }

/* A phone: each line of the shelf scrolls sideways instead of wrapping, which took nearly half the
   screen, and so does Convert's Show. Each fades out at its right edge over a thin scrollbar, so
   you can see there's more. The close button stays put. The padding keeps focus rings inside the
   scroll. */
@media (width < 40em) {
  .scroll, #show { overflow-x: auto; scrollbar-width: thin; padding-right: 2em; mask-image: linear-gradient(to left, transparent, #000 2em); }
  .scroll { flex-wrap: nowrap; padding-block: 0.25em; padding-left: 0.25em; margin: -0.25em 0 -0.25em -0.25em; }
  .scroll > *, .trail > * { flex: none; }
  .scroll .end { margin-left: 0; }
  .trail, .crumbs { flex-wrap: nowrap; }
}

/* Wide: on a landscape screen at least 48em wide, the shelf stands up at the right, as tall as the
   screen, beside a PDF or the song, which each get the full height. The song moves over for it, and
   reading.js lays it out again in the room left. The trail is on top, then the
   settings, each as wide as the shelf, and Theme and the page's end at its foot, where the shelf
   button was. The settings scroll between them, so the foot and the close button stay on screen
   however short the screen or long the settings, and their padding keeps focus rings inside the
   scroll. They end at a line over the foot, like a page's foot, so a setting cut at its edge shows
   it goes on. A PDF's page that says why a save failed says it over the foot, past the settings, so it
   moves none of them. A PDF's name gets a line of its own in the trail, cut short when it's long,
   so a new name never moves the settings under a tap. Bigger text makes the screen fewer em wide,
   so it gets two lines again. */
@media (orientation: landscape) and (width >= 48em) {
  body.pdf { display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr) auto; }
  body.pdf > main { grid-area: 1 / 1; padding-bottom: 1rem; }
  body.pdf > #shelf { grid-area: 1 / 2; }
  #shelf { width: var(--shelf); max-height: none; display: grid; grid-template: auto minmax(0, 1fr) auto / minmax(0, 1fr) auto; gap: 1.25em 0.75em; padding: 1em; border-top: 0; border-left: 1px solid var(--line); overflow-y: auto; }
  #shelf[popover] { inset: 0 0 0 auto; width: var(--shelf); height: auto; box-shadow: none; }
  #shelf:popover-open ~ main { margin-right: var(--shelf); }
  #shelf :is(.line, .scroll) { display: contents; }
  #shelf:has(> .status:not(:empty)) { grid-template-rows: auto minmax(0, 1fr) auto auto; }
  #shelf .status { grid-area: -3 / 1 / -2 / -1; }
  .trail { grid-column: 1 / -1; flex-direction: column; align-items: flex-start; min-height: auto; gap: 0.6em; }
  .crumbs { max-width: 100%; }
  #file { flex-basis: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #shelf .cells { grid-area: 2 / 1 / 3 / -1; align-self: stretch; display: grid; align-content: start; gap: 1em; min-height: 0; overflow-y: auto; padding: 0.25em; margin: -0.25em; border-bottom: 1px solid var(--line); }
  .end { grid-area: -2 / 1; align-self: end; margin-left: 0; justify-content: space-between; flex-wrap: wrap; }
  #shelf .round { grid-area: -2 / 2; align-self: end; }
  #shelf .field { justify-items: stretch; }
  #lyric-size { grid-template-columns: minmax(0, 1fr); }
  /* Chords' key and size share a line while they fit, or the size goes under the key, like a capo's
     shapes, or bigger text. Either way they fill the shelf, and what they say stays under both. */
  #chords { display: flex; flex-wrap: wrap; }
  #chords > :not(select, .stepper) { flex-basis: 100%; order: 1; }
  #chords > .label { order: 0; }
  #chords > :is(select, .stepper) { flex-grow: 1; }
  #shelf .stepper { display: flex; }
  #shelf :is(.stepper input, .unit) { flex: 1; }
  #shelf .seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; }
  #shelf .toggles { display: grid; grid-template-columns: repeat(3, 1fr); }
  #shelf :is(.seg, .toggles) label { justify-content: center; padding: 0 0.5em; }
  #shelf .text { width: 100%; }
  /* A long section name wraps, so its select shows its widest kind, like New screenful, whole. */
  #shelf .rows { display: grid; grid-template-columns: auto minmax(max-content, 1fr) auto; gap: 0.5em; }
  #shelf .row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; }
  #shelf .section { white-space: normal; overflow-wrap: anywhere; }
  #shelf .rows > select { grid-column: 1 / -1; }
  /* A row's × stays on its row, not at the shelf's foot with the song page's close button. */
  #shelf .row .round { grid-area: auto; align-self: center; }
}

/* Paper: reading.js lays out its own copy of the chart in printed pages of one column or two, each
   starting with the title. A page fits Letter and A4 inside its margin, half an inch, as wide as A4
   and as tall as Letter. The URL's margin, hole margin and paper set --margin, --hole, the paper
   attribute and the @page rules (reading.js), and on Letter or A4 a page fills that sheet inside its
   margin, and its hole margin on the side its holes go. Without holes, that side keeps the margin.
   On screen the
   copy waits out of sight past the left edge, laid out but never shown. --page-width is a page's
   width, and the song page's PDF columns (above) scale it by --scale, their chords over a PDF's.
   It's resolved to px, so reading.js can count the columns that fit. */
@page { margin: 0.5in; }
@property --page-width { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --column-gap { syntax: "<length>"; inherits: true; initial-value: 0px; }
nns-chart { --margin: 0.5in; --hole: var(--margin); --sheet-width: 210mm; --page-width: calc((var(--sheet-width) - var(--margin) - var(--hole)) * var(--scale, 1)); }
nns-chart[paper] { --sheet-height: 11in; position: fixed; top: 0; right: 100%; width: var(--page-width); visibility: hidden; }
nns-chart[paper="letter"] { --sheet-width: 8.5in; }
nns-chart[paper="a4"] { --sheet-height: 297mm; }
nns-page { display: grid; grid-template: auto minmax(0, 1fr) / minmax(0, 1fr); column-gap: var(--column-gap); height: calc(var(--sheet-height) - 2 * var(--margin)); }
nns-chart[columns="2"] > nns-page { grid-template-columns: repeat(2, minmax(0, 1fr)); }
nns-page > header { grid-column: 1 / -1; }
/* One-column paper keeps the margin, so a pickup costs no height: it sits right-aligned left of bar 1
   on the words row. --gutter is the longest pickup in the chart's ch, and the pickup is lyric size:
   --lyric-scale of that (reading.js). The same width in every section
   keeps bar 1 at the same x. Half a page has no room for it, so two columns put pickups above bar 1,
   like the screen. Without lyrics there are no pickups, and no margin. */
nns-chart[paper][columns="1"][gutter]:not([lyrics="off"]) nns-section { grid-template-columns: calc(var(--gutter) * var(--lyric-scale)) var(--tracks); padding-left: 0; }
nns-chart[paper][columns="1"][gutter]:not([lyrics="off"]) nns-heading { margin-inline: 0; }
/* An empty item holds the gutter so a phrase without a pickup still starts its bars in column 2. */
nns-chart[paper][columns="1"][gutter]:not([lyrics="off"]) nns-phrase::before { content: ""; grid-column: 1; grid-row: 3 / 5; }
nns-chart[paper][columns="1"][gutter]:not([lyrics="off"]) nns-phrase > nns-lyric[loose] { grid-column: 4 / -1; }
nns-chart[paper][columns="1"] nns-phrase > nns-pickup { grid-row: 4; grid-column: 1; justify-self: end; margin-left: 0; text-align: end; white-space: nowrap; }
nns-chart[paper][columns="1"] nns-phrase > nns-pickup::after { content: none; }

/* With PDFs on, the browser prints one line pointing to the chart's PDF instead (reading.js). */
#print-pdf { display: none; }

@media print {
  :root, :root[data-theme] { color-scheme: light; }
  #print-pdf { display: block; }
  main:has(> #print-pdf) > :not(#print-pdf) { display: none; }
  body:has(nns-chart[paper]) { margin: 0; padding: 0; }
  nav, body > header, form, #notice, main > footer, nns-chart:not([paper])[columns] { display: none; }
  nns-chart[paper] { position: static; visibility: visible; }
  /* Each page is already short enough. Left to its own height, one a little taller than the paper
     allows runs onto another sheet instead of being cut off. */
  nns-page { height: auto; }
  nns-page + nns-page { break-before: page; }
  :is(nns-heading, nns-riff) { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}
