/* ==========================================================================
   Chords.

   The whole look lives here. Nothing is shared with the FLOA design system on
   purpose: this is an application, not a page, and it wants its own rules.

   The one thing worth reading before changing anything is the .ln block near
   the bottom. A chord is positioned in pixels, but those pixels are measured
   from a character index at runtime (see layoutLine in app.js), which is what
   keeps a chord over the same syllable in Hebrew and in English alike.
   ========================================================================== */

:root {
  --ink: #17202a;
  --ink-soft: #5b6b78;
  --line: #e2e8ec;
  --bg: #f7f9fa;
  --card: #ffffff;
  --accent: #0e8c7e;
  --accent-ink: #0a6c61;
  /* the green laid down flat, for the few marks that are the app's own green
     said quietly rather than pressed: a reading that went right, a string in
     tune, the recordings on a card */
  --accent-soft: #dcf1e9;
  --chord: #e11d63;
  /* the red pressed down, for the same job --accent-ink does for the green:
     a red fill that has to darken under the hand and stay red doing it */
  --chord-ink: #b3164d;
  --chord-soft: #fde7ef;

  /* THE PAGE TALKING ABOUT WHAT IS UNDER IT rather than being it: what a
     reading could not finish, and the band over a version that is not the
     song. One warm colour for all of them, wherever they stand. */
  --note: #fdf6ec;
  --note-line: #f0dfc4;

  /* --- WHAT STATE A SONG IS IN, AND IT IS ONE COLOUR -----------------------
     There were five: blue while the machine still had it, amber while it asked
     to be checked, brown while somebody was working on it, violet while
     somebody was waiting on somebody, green once it was out in the world. Five
     colours is a key, and a key has to be learned before the page can be read:
     the wall of the library came out as a colour chart of a code nobody was
     given, and the one thing every label actually says, in a word, in Hebrew,
     was the thing the colour was competing with.

     So the colour stops carrying the meaning and goes back to carrying the
     kind: this is a state, states look like this, and WHICH state it is, is
     written on it.

     AND THE COLOUR IS YELLOW, BECAUSE IT IS NOBODY ELSE'S. It was the app's
     own green, the one on the button that adds a song and on the row that
     publishes one, so the few cards carrying a state wore the colour of "press
     this" on a wall where they were the one thing not being pressed. Yellow is
     the one colour here that belongs to no control: not the green of a button,
     not the red of a chord. It marks a card instead of inviting a press, and
     it is soft because a label is read beside a name and not instead of it.

     Named per state still, because these are five different facts and a page
     that wanted to tell two of them apart should not have to invent a colour
     to do it. */
  --state-ink: #8a6100;     --state-soft: #fbf0cc;
  --imported-ink: var(--state-ink);  --imported-soft: var(--state-soft);
  --review-ink: var(--state-ink);    --review-soft: var(--state-soft);
  --draft-ink: var(--state-ink);     --draft-soft: var(--state-soft);
  --published-ink: var(--state-ink); --published-soft: var(--state-soft);
  --offer-ink: var(--state-ink);     --offer-soft: var(--state-soft);

  /* THE SAME FACT AS A MARK RATHER THAN AS A WORD: the dot on the button that
     hides the row about it, where there is no room for the word (see
     .more-news). Full rather than soft, because nine pixels of a pale colour on
     a white bar is nothing at all. */
  --state-mark: #e0a010;

  /* AND WHAT A THING IS, WHICH IS NOT A STATE. These label a recording and how
     a song was read, not where a song is in its life, and they keep colours of
     their own so that a wall of yellow states is not also a wall of yellow
     everything else (see .tag-measured, .tag-model, .tag-half, .tag-words). */
  --told-ink: #2f5d8a;      --told-soft: #dde9f4;
  --part-ink: #8a5a12;      --part-soft: #f6e6ca;

  --danger: #c0392b;
  --radius: 14px;

  /* ONE CORNER FOR EVERYTHING SMALL, AND IT IS NOT A CIRCLE. The app was drawn
     in two shapes at once: pills for anything wearing a word (.btn, the search
     boxes, the state chips) and eight pixel corners for anything wearing a
     picture (.icon-btn, the steppers). Both are on screen together in the bar
     over every page, and the pair read as two toolkits rather than as one, so
     the bar had to be given a third shape of its own to hide the seam.

     There is no seam now. A button, a field, a chip and a strip of them all
     take this corner, and the shape stops carrying meaning it never had: what
     tells a button from a chip is the ink and the hand, not the roundness.
     Only the card keeps its own larger corner (see --radius), because a sheet
     of paper is a different kind of thing from a control on it. */
  --corner: 8px;
  --shadow: 0 1px 2px rgba(23, 32, 42, .05), 0 8px 24px rgba(23, 32, 42, .06);

  /* --- PLAY, STOP AND PAUSE ARE ONE SIZE WHEREVER THEY ARE -----------------
     Three shapes and one meaning: this sound starts, this sound ends, this
     sound waits. They are drawn on a pill on a song card, on the round red
     one that records, and on the round one beside a recording, and each of
     those had picked its own number: eleven on the card, fourteen on the two
     round ones. The buttons around them are different sizes and should be,
     because a card is not a strip; the SHAPE inside them is the same shape
     saying the same thing, and a triangle that is one size here and another
     there reads as two different controls.

     Bigger than any of them was, too, and by a good deal. These are the shapes
     pressed with a guitar in the way, and eleven pixels of triangle is a mark
     rather than a button: it went to sixteen first, which is the size of an
     ordinary icon in this app, and an ordinary icon is exactly what this is
     not. What is being drawn is the one shape on the screen that makes a
     sound. */
  --transport: 20px;

  --song-size: 18px;

  /* The song is set in the face a printed chord sheet is set in, not in the
     app's own. That is David: the Hebrew text face songbooks have been set in
     for decades, with the stroke weight that varies across a letter and the
     narrow proportions that a sans has neither of.

     The list after it is not decoration, it is the same face under the names
     different systems file it under, and then the nearest thing where it is
     absent. No web font is fetched: these are already on the machine, which is
     why the fallbacks matter. */
  --song-font: David, "David Libre", "Frank Ruehl CLM", FrankRuehl, "Times New Roman", "Noto Serif Hebrew", serif;

  /* The chords are NOT in the song's face, and that is on purpose. They are
     Latin letters sitting over Hebrew ones, and a sans keeps them reading as
     symbols rather than as words: the eye should find the chord row without
     looking for it. */
  --chord-font: "Arial Hebrew", Arial, "Helvetica Neue", Helvetica, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

/* A phone paints a grey-blue wash over anything it thinks is a link the moment
   a finger lands on it, and it paints the whole of it: a card, a row, a bar.
   Every press here already has a look of its own, so the wash only arrives late
   and over the wrong shape. It is off for the whole app, and inherits. */
html { -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.6 "Assistant", "Rubik", "Segoe UI", system-ui, -apple-system, sans-serif;
  min-height: 100vh;
}

/* THE WHOLE WINDOW, ON EVERY PAGE. It used to be a column of about eighty
   characters, with the library alone allowed out of it, and that rule came
   from a page of prose. Nothing here is prose: the library is a wall of
   cards, a playlist is a wall of cards, and a song is a sheet that answers a
   wide screen by standing in two or three columns rather than by running down
   the middle of it. So the gutter is the only thing left of it. */
.wrap { width: calc(100% - 32px); margin-inline: auto; }

/* AIR UNDER THE BAR, ON EVERY PAGE. It used to be the first thing on each
   page that carried its own top margin, which meant every new page was a page
   that had to remember to, and the ones that begin with a wall of cards did
   not: a card resting against the bottom edge of a sticky bar reads as part of
   it. One rule here, and nothing below has a top margin of its own.

   IT IS A NUMBER WITH A NAME because one thing on the library gives it back:
   the picture at the head of the page is meant to touch the bar (see .strip),
   and it can only take back exactly what was added here. Two places holding
   one number is how they come to disagree. */
:root { --bar-air: 22px; --top-h: 61px; }
#app { padding-top: var(--bar-air); }

/* --- ONE SHEET PER PAGE ---------------------------------------------------
   #app is not the page any more, it is what the page is laid on. Every page
   that opens gets a sheet of its own, and the page it covered is kept aside
   whole, out of the document, so that going back is a sheet being put back
   rather than a page being built for the second time (see the stack in
   app.js). Only one is ever in here, so it needs no rules of its own: it is
   the block #app used to be. */

/* --- A SONG IS THE PAGE ---------------------------------------------------
   Everything else here is something ON a page: a wall of cards, a form, a
   list. A song is the page. So on a song there is nothing between the header
   and the words: no gutters, no air over them, and no card around them.

   The card was worth having when the sheet was a column of about eighty
   characters standing in the middle of a screen, where it said where the song
   began and ended. It is the whole width now, so what it draws is a box round
   the edge of the window: a border a thousand pixels from anything it could be
   distinguishing. The phone lost it for the same reason years ago (see the
   narrow rules below), and this is the desk catching up. */
body.on-song #app { padding-top: 0; width: 100%; }
/* THE MARGIN BELONGS TO THE PAPER NOW. Every segment keeps half a gutter
   inside itself, which is what holds the words off its edges and what leaves
   room for a chord hanging past the end of a line; the sheet keeping its own
   as well would be the same margin twice, and on a phone that is a third of
   the glass spent on nothing. */
body.on-song .sheet { padding-inline: 0; }
/* THE PAPER IS THE WHOLE WINDOW. It was the segments alone, each a white card
   on a grey desk, because the segments were a fixed width and the room left
   over at the two ends was not part of the song: white, it read as page with
   nothing written on it, and grey it read as the desk the cards lay on.

   The segments divide the whole of the room now (see planColumns), so there is
   no desk left to show, and what said where one ended is a hairline between
   them rather than the shape of a card. What is left over is a margin, which
   is what a margin looks like on paper: paper. */
body.on-song { background: var(--card); }

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

.top {
  position: sticky; top: 0; z-index: 20;
  background: rgba(247, 249, 250, .92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  /* The visibility carries no delay HERE, so that coming back is immediate:
     the bar is on the screen from the first frame of the slide down (see
     body.on-air, where the same property waits for the slide up to finish). */
  transition: transform .28s ease, margin-block-end .28s ease, visibility 0s,
              background-color .2s ease, border-color .2s ease;
}
.top-in { display: flex; align-items: center; gap: 16px; min-height: 60px; }

/* --- AND AT THE TOP OF THE LIBRARY THE BAR IS ONLY WHAT IS IN IT ------------
   The picture runs up behind it to the very top of the screen (see .strip,
   which takes back the height of this bar as well as the air under it), so
   while nothing has been scrolled the bar has no paper of its own: the mark,
   the box and the buttons stand on the drawing.

   IT COMES BACK ON THE FIRST PIXEL OF SCROLL. What is behind the bar a moment
   later is songs, and a row of cards sliding under a mark with nothing between
   them is unreadable in the way a glass bar exists to prevent. The class is on
   the body rather than here because the page decides it, and it is only ever
   put there by the library (see hero in app.js).

   The border goes with the background, in one move: a hairline hanging over a
   drawing with no bar attached to it is a line drawn across the picture. */
body.bar-clear .top {
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: transparent;
}

/* --- AND WHILE A TAKE IS RUNNING THERE IS NO HEADER ------------------------
   Somebody recording is playing the song, and the only thing on the screen
   they are using is the song. A name, a search box and a row of doors are not
   pressed with a guitar in both hands, and on a phone they are a tenth of the
   glass: the header goes up and off the way it came, and the page comes up
   with it, which is a line or two more of the song for nothing.

   TWO MOVES AND NOT ONE. The lift takes the header off the screen and the
   negative margin takes its height out of the flow, so what rises is not the
   bar alone but the whole page under it. Both are measured in JavaScript
   while it is still standing, because how far the page comes up is exactly
   how tall the thing leaving is (see airRoom).

   The button that stops the recording steps out of here before this runs, and
   stays. Everything else goes.

   AND ONCE IT HAS GONE IT IS NOT DRAWN AT ALL, which is the third move and the
   one that makes the promise true. A bar lifted out of sight by a transform is
   still a bar the browser is placing, and the placing is exactly the thing
   nobody controls: this one is stuck to the top of the window, and a window
   that is scrolled hard at its ends, or that is growing and shrinking because
   an address bar is sliding in and out of it, moves the things stuck to it.
   Which is how a header that had gone came back, mid take, for somebody who
   did nothing but scroll the song.

   So it is taken out of the drawing once it has left, and nothing a browser
   does with a sticky box can put a hidden one on the screen. Its box stays
   where it was, holding the space the negative margin above cancels, and only
   the paint stops. The wait is the length of the slide: hidden any earlier and
   the header would vanish instead of leaving. */
body.on-air .top {
  transform: translateY(-100%);
  margin-block-end: calc(0px - var(--top-away, 60px));
  pointer-events: none;
  visibility: hidden;
  transition: transform .28s ease, margin-block-end .28s ease, visibility 0s linear .28s;
}
.brand {
  display: inline-flex; align-items: center; flex: none;
  color: var(--ink); text-decoration: none;
}
.brand svg { width: 24px; height: 24px; color: var(--accent); }
/* THE MARK AND THE NAME BESIDE IT ARE ONE THING. The row's gap is what stands
   between one control and the next, and these two are not two controls: the
   picture and the word say the same thing, and sixteen pixels of bar between
   them read as a space with something taken out of it, next to the eight the
   buttons at the other end of the same bar stand at. Half of it is given back,
   the way .top-facts takes its own back below, and the two close into one
   mark with its name against it.
   A phone holds the whole row at eight already, so there is nothing to take
   there and the rule is undone in the narrow block. */
.brand { margin-inline-end: -8px; }
/* AND ON THE LIBRARY IT IS NOT IN THE ROW. Everywhere else the corner holds the
   way back, which is the most useful thing in the bar; at home it held a link
   to the page it was standing on. The row there is the search box and the fork,
   and the box starts at the edge (see paintBrand). */
body.at-home .brand { display: none; }
/* THERE WAS A .top-pick HERE, a slot between the mark and the name holding a
   tick that took every song on the page, and a .picking beside it holding what
   could then be done to them. Both are gone with the ticking itself: see the
   note over .list. */
.top-actions { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; }
/* AND WITH NOTHING IN IT, IT IS NOT THERE AT ALL. A page whose corner holds
   nothing (the bill, the people, a playlist with nothing to do to it) still
   spent the row's gap on this box, and worse than the gap: the auto margin
   above is what holds a corner, and TWO of them in one row split the space
   between them rather than one of them taking it. Which is what stood between
   the total on the bill and the end of the bar. Empty, it takes nothing and
   holds nothing, exactly as .top-facts and the box beside it already do. */
.top-actions:empty { display: none; }

/* THE BAR'S BUTTONS ARE DARKER, AND THAT IS ALL THEY ARE. There used to be a
   shape here too: a picture on its own was made a circle in this one bar,
   because the library's row was pills and a song's row was corners and the
   glass between them clashed with whichever one it was not. Every control in
   the app takes the same corner now (see --corner), so the bar has nothing
   left to reconcile and the circle is gone with the reason for it.

   The ink stays. Elsewhere .icon-btn is drawn soft because it sits beside the
   thing it acts on and should not compete with it, and up here it is the thing
   itself.

   Written above the quiet ones further down the file, which have to stay the
   later rule so that they still turn red under the hand. */
.top-actions > .icon-btn { color: var(--ink); }
/* AND THEY ARE ALL THE SAME WHITE. The bar is not white, it is the page's own
   grey with the page moving under it, and a button drawn on it in transparent
   is not a button standing on the bar: it is a hole in the bar with a line
   round it. Which is what a ghost is EVERYWHERE ELSE, and rightly, because
   elsewhere it stands on white and the transparency is what keeps it quiet.

   Up here the row is read as a row: the dots beside the glass beside the fork.
   One of them white and one of them grey is one control saying it is a
   different kind of thing from the one next to it, and it is not. */
.top-actions .btn.ghost { background: var(--card); }

/* EXCEPT THE FORK, WHICH IS FILLED. It is a picture and no word now (see tuner
   in app.js), and a fork is a shape most people have never pressed: white among
   white it was the one button on the bar nobody could name without pressing it.
   The fill is what the word used to do, in no width at all.

   AND THE FILL IS RED. Behind this button is a microphone that listens, which
   is the one thing in the app that is not the app doing something for you but
   the app taking something in, and red is the colour that already says so
   everywhere else: the record button, the door to the microphone under a song
   (see .ear-door.is-on). It was green, which is the colour of a thing that
   acts, and it also put a second filled green on the page beside the button
   that adds a song. Now the one green thing adds and the one red thing
   listens.

   Pressed and while it is listening it darkens and stays red, the way the
   green did: the state is a shade of the same fact, not another colour. The
   .is-on here outranks the softer one written further down the file, which is
   for the door that stands beside the words rather than in the bar. */
.top-actions > .icon-btn.tuner {
  color: #fff; background: var(--chord); border-color: var(--chord);
}
.top-actions > .icon-btn.tuner:hover,
.top-actions > .icon-btn.tuner.is-on,
.top-actions > .icon-btn.tuner.is-on:hover {
  color: #fff; background: var(--chord-ink); border-color: var(--chord-ink);
}

/* --- WHAT PAGE THIS IS ----------------------------------------------------
   The app's name used to stand here beside its own mark, which is one word
   saying what the mark already said and the only word on the bar nobody is
   looking for. In its place goes the name of the page you are on: the song,
   the playlist, the person, the shelf.

   And on the three pages where that name is a THING rather than a label, it
   is the field itself. A song's name, a playlist's name and a person's name
   are typed here and nowhere else. The page carried a second copy as a
   heading, and two editable copies of one name are two places for it to be
   wrong. On paper the heading comes back (see .on-paper), because paper has
   no bar.

   As much of it as the bar allows and no more: a name that would push the
   search box off the end is cut with an ellipsis.

   The column holds the name and the small line under it, and it is the column
   that gives way when the bar runs out of room: two things that shrink on
   their own shrink at two different moments. */
.top-name {
  flex: 0 1 auto; min-width: 0;
  display: flex; flex-direction: column; justify-content: center;
}
.top-where {
  max-width: 100%;
  font-weight: 700; font-size: 17px; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  outline: none;
}
.top-where:empty { display: none; }
/* AND WHERE THERE IS NO NAME, THE COLUMN IS NOT THERE AT ALL. Both lines in it
   go on their own when they are empty, but the column that holds them still
   spends the row's gap, and the room in this row belongs to the search box (see
   .top-find). The library is the page this is about: it stopped naming itself
   up here, and what it gave up is the box's now. */
body.unnamed .top-name { display: none; }

/* --- AND WHO MADE IT WAS UNDER ITS NAME, AND IS NOT ANY MORE ----------------
   There was a .top-sub here, a second line under the title holding the credits
   at twelve pixels, with a little pen and a little note standing in for the
   words "מילים" and "לחן" because at that size the words were two thirds of
   the line. It was already a compromise, and it got worse as the credits got
   truer: the words of a song are three people's as often as one, and three
   names each carrying a picture that has to be hovered to be read is a line
   nobody takes in at a glance.

   It is one press away instead, in the panel behind the info button, where
   there is room for the word and for everybody it belongs to, and every name
   in it is a chip with that person's page behind it. */
/* Typed into rather than read. It takes a line under the pointer, because a
   name in a bar reads as a label until something says otherwise, and it says
   what it wants while it is empty. */
.top-where[contenteditable] { cursor: text; border-bottom: 1px solid transparent; }
.top-where[contenteditable]:hover { border-bottom-color: var(--line); }
.top-where[contenteditable]:focus { border-bottom-color: var(--accent); }
.top-where[contenteditable]:empty { display: block; min-width: 8ch; }
.top-where[contenteditable]:empty::before {
  content: attr(data-empty);
  color: var(--ink-soft); font-weight: 400;
}

/* --- ONE SEARCH BOX, AND IT IS IN THE BAR ---------------------------------
   It used to be on the library's own page, which is the one page where a
   search box is worth least: the songs are already on the screen. Where it is
   actually wanted is everywhere else. You are inside a song and you want the
   next one. You are planning a playlist and you want to remember what you
   played in March. You have a name in your head and you want everything that
   person wrote.

   None of those is a filter on the page you are on. They are all the way OFF
   it, which is navigation, and navigation belongs in the bar.

   A FIELD AND A GLASS AND NOTHING ELSE. It grew a cross of its own at one
   end, and the plain form styling further down this file drew a second
   rounded white box around the field inside the rounded white box around all
   of it. What that looked like was two boxes and a button. A search box is
   the plainest control there is: somewhere to type, and a picture saying what
   typing there does.

   AND IT TAKES WHATEVER THE BAR HAS LEFT. It was capped at 420px, which on a
   wide screen left a stretch of empty bar between the name of the page and the
   row of buttons: room nothing was using, next to the one control that could
   use it. A song's name is long, a playlist's is longer, and what you type
   here is one of them. Everything else on the bar is either fixed or asks for
   only as much as its own words need, so the space that is left over is the
   search box's by default. */
.top-find { position: relative; flex: 1 1 200px; min-width: 0; }
.top-find .find {
  display: flex; align-items: center; gap: 9px;
  padding: 0 14px; height: 38px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--corner);
  transition: border-color .12s;
}
.top-find .find:hover { border-color: #cdd8de; }
.top-find .find:focus-within { border-color: var(--accent); }
.top-find .find > svg { flex: none; width: 17px; height: 17px; color: var(--ink-soft); }
/* --- WHAT THE PAGE IS HELD DOWN TO, IN FRONT OF THE FIELD -------------------
   A style is a sieve over the library rather than a page of its own (see
   pickKind in app.js), and this is where it says so: a chip in the front of the
   box, and the typing carries on after it. One control, read as one sentence,
   this kind of song and these letters in it.

   It never wraps and never gives way: the field beside it is what has the room
   to lose. Empty it is not there at all, so on every page that is holding
   nothing down the box is a box (see .find-kind:empty). */
.find-kind { flex: none; display: flex; align-items: center; margin-inline-start: -3px; }
.find-kind:empty { display: none; }
/* Inside the box it is not a card on a page: the box is the white, so the chip
   is the soft green the app says "this is what is narrowing things" in, rather
   than the outlined grey it wears on a song, where it is a fact about the song
   and not a thing being done (see .tag-style). */
.find-kind .tag-style {
  color: var(--accent-ink); background: var(--accent-soft); box-shadow: none;
  max-width: 40vw; overflow: hidden;
}
.find-kind .tag-style > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.find-kind .tag-x { color: var(--accent-ink); }
/* The type is written into the selector because the bare `input` rules below
   are as specific as a class and come after these: without it the field wears
   the form styling, and a white rounded box inside a white rounded box is
   what this looked like. */
.top-find input[type="search"] {
  flex: 1 1 auto; min-width: 0; width: auto;
  font: inherit; font-size: 15px; color: inherit;
  background: none; border: 0; border-radius: 0; padding: 0; height: auto;
  appearance: none;
}
.top-find input[type="search"]:focus-visible { outline: none; }
/* WHAT THE OPEN PAGE HAS TO SAY, AT THE FAR END OF THE BOX. The library puts
   its three state counts here; every other page leaves it empty, and an empty
   box still spends the row's gap, so it goes when it is empty.

   Never wrapped and never stretched: it is a passenger in a control that
   belongs to the field, and the field is what gives way to it. */
/* AND AS CLOSE TO THE END OF THE BOX AS IT IS TO THE TOP OF IT. The box carries
   fourteen pixels of padding, which is what a field's first letter wants and is
   twice the seven left over above and below a chip this tall: the counts stood
   further from the end of the box than from its edges, which reads as a group
   that has not quite arrived. Half the padding is given back, and the air round
   them is the same air on all four sides. */
.find-extra {
  flex: none; display: flex; align-items: center; gap: 8px;
  margin-inline-end: -7px;
}
.find-extra:empty { display: none; }
.find-extra .tallies { flex: none; flex-wrap: nowrap; }
/* Inside the box they are not cards on a page: the box is the white, and a
   second white box on it is a box in a box.

   AND THEY ARE THE SAME LABEL THAT IS ON THE CARDS. What they count is the word
   standing in the corner of every row down the wall, so up here they are that
   word in that type: the same twelve pixels, the same weight, the same corner
   (see .tag). They were a size of their own, larger than the thing they were
   counting and standing in the narrowest row on the page. */
.find-extra .tally {
  background: none; padding: 1px 10px; gap: 5px;
  font-size: 12px; font-weight: 700; line-height: 1.6;
}
.find-extra .tally-n { font-size: 12px; }
/* Two crosses in one box is one too many: Escape empties it, and so does
   going anywhere. */
.top-find input[type="search"]::-webkit-search-cancel-button { display: none; }
/* Not the browser's cross, which empties the field and leaves you inside the
   search. This one ends the search: it empties the box AND hands the whole
   library back under the wall it was narrowed to. */
.top-find .find-x {
  display: none;
  flex: none; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin-inline-end: -3px;
  appearance: none; background: none; border: 0; padding: 0;
  color: var(--ink-soft); cursor: pointer;
}
/* AND IT IS THERE FROM THE FIRST LETTER, AT EVERY WIDTH. It used to appear only
   where the box had taken the whole bar, which is a phone, so on a desk the one
   way out of a search was to select the letters and delete them, or to know
   about Escape. The way back is worth a picture the moment there is something
   to come back from, and not before: an empty box is not a search anybody is
   inside of.
   Asked of the placeholder rather than of a class, because the placeholder is
   shown exactly while the field is empty, whoever emptied it and however. */
.top-find .find:has(input[type="search"]:not(:placeholder-shown)) .find-x {
  display: flex;
}
.top-find .find-x > svg { width: 16px; height: 16px; }

/* WHAT THE BOX FOUND, HANGING UNDER IT. Not a page: a search that took over
   the screen would lose the song you were reading in order to tell you about
   another one, and half the time what the box is for is a glance.

   As wide as the box, whatever the box came out to be. It carried a width of
   its own, and two edges that nearly line up read as a mistake rather than as
   two things. */
.find-out {
  position: absolute; z-index: 30; top: calc(100% + 8px);
  inset-inline-start: 0; width: 100%;
  max-height: min(70vh, 560px); overflow-y: auto;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 10px 34px rgba(23, 32, 42, .16);
  padding: 6px;
}
.find-out[hidden] { display: none; }
.find-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%; text-align: start; cursor: pointer;
  appearance: none; font: inherit; color: inherit;
  background: none; border: 0; border-radius: var(--corner); padding: 8px 10px;
}
.find-row:hover, .find-row.is-on { background: var(--bg); }
.find-main { flex: 1 1 auto; min-width: 0; }
.find-t { font-weight: 700; font-size: 15px; }
/* One line each. A result is a way to a page, not the page. */
.find-said {
  color: var(--ink-soft); font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.find-tags { flex: none; display: flex; gap: 4px; }
/* THERE WAS A .find-mark HERE, on the rows a playlist answered with: "הוספה"
   or "בפלייליסט" at the end of a line of names in the drop. A playlist sieves
   its own wall now, into cards, and the word is in the corner of the card (see
   .set-row.is-pick). */
.find-none { padding: 14px 12px; color: var(--ink-soft); font-size: 14px; }
.find-more { padding: 8px 12px 6px; color: var(--ink-soft); font-size: 12px; }

/* THERE WAS A .who HERE, the button in the bar carrying whoever is signed in.
   The account is a chip over the wall now, with the other doors (see
   .tally-door), and it is that chip either way round: a name signed in, and
   the word התחברות over Google's mark signed out. The bar on the library
   holds none of it. The playlists and the people still carry the way in
   themselves, having no such row (see session in app.js). */

/* On a phone the bar holds four things and the screen holds about two of
   them. What goes is the WORD on any button that has a picture, because a
   picture is the part that survives being small; the buttons that are only a
   word keep it, since there is nothing else left of them.

   Not a second row: the bar is sticky, and a sticky header that grew a row
   would take that row off the top of every song for good.

   And a label goes OVER its field rather than beside it. A word and a field
   side by side on a screen this narrow leave the field a few characters wide,
   and the date is the worst of them: it is the one field that sizes itself, so
   it sat up on the label's own line and squeezed it. */
@media (max-width: 620px) {
  .top-actions .btn svg + .lb { display: none; }
  /* The fork used to be the exception here, keeping its word on a phone
     because a tuning fork is a shape most people have never pressed. It has no
     word at any width now, on the bar or off it, and says what it is by being
     the one thing up here filled at all, and filled in the microphone's red
     (see .icon-btn.tuner). */
  /* AND THE WAY IN KEEPS ITS WORD. Google's mark is known everywhere, and
     it still says only "Google", never what pressing it here is for. It is
     left in the bar on the two pages that have no row of doors to hold it
     (see session in app.js), and on those it stands there alone, so the room
     is not the question. */
  .top-actions .btn.google svg + .lb { display: inline; }
  .top-actions .btn.small { padding: 8px; }
  .top-actions .btn svg { width: 18px; height: 18px; }
  /* A button that has lost its word is thirty-six across with an eighteen
     pixel picture in it, so the ones that never had a word are that too. */
  .top-actions > .icon-btn { width: 36px; height: 36px; }
  .top-actions > .icon-btn > svg { width: 18px; height: 18px; }
  /* And the capo with them. It stands in this row too (see placeControls), it
     is pressed by the same thumb, and a box six pixels shorter than the two
     beside it is the one thing in the bar that does not sit on the line the
     others do. Its picture and its number stay the size they are: the number
     is read, not aimed at, and it is already the largest thing in the box.

     Named through the bar, and not as .tools .dial-btn: the height it is
     overriding is written further down the file, and a rule inside a media
     query is still just a rule. What wins here is the third class. */
  .top-actions .tools .dial-btn { height: 36px; }

  /* The app's name goes and its mark stays. The bar has to hold the search
     box, and a word that says which app you are in is the one thing on it
     that nobody is looking for: the mark says the same and costs a quarter of
     the room. */
  .top-in { gap: 8px; }
  /* which is already what the mark and the name were pulled to on a desk */
  .brand { margin-inline-end: 0; }

  /* A GLASS UNTIL IT IS PRESSED, AND THEN THE WHOLE BAR. The bar of a phone
     holds a mark, the name of the page and four pictures, and what is left
     over for a search box is about ninety pixels: a box you cannot read your
     own typing in.

     A second row was the other answer and it is the wrong one. The bar is
     sticky, so a row grown here is a row taken off the top of every song for
     good, to hold a box that is empty almost all of the time.

     So it takes the room from everything else, and only while it is being
     used. A press anywhere off it gives the bar back.

     AND WHILE IT IS CLOSED IT IS ONE OF THE PICTURES, so it is exactly the
     size and the shape of one: a thirty-six pixel square with an eighteen
     pixel glass in it, on the corner every control in the app takes (see
     --corner). Closed, it is not a search box.
     It is the button that opens one, and it stands in a row of buttons.

     The gap that separated them was the actions pushing themselves to the far
     end. The two of them are one row again and the space in front of them is
     what gives way.

     ALL OF WHICH IS ABOUT A BAR THAT STILL CARRIES A NAME. Where it does not,
     the box is a box here too, and the block further down is that.

     AND IN THE OTHER ORDER FROM THE ONE THEY STAND IN ON A DESK. There the
     box is a box, and it lies between the name of the page and the buttons
     because that stretch of bar is the only room nobody else wants. Here it
     is not a box, it is one more picture in a row of pictures, and a row of
     pictures is read from the corner in: the glass takes the corner, and the
     fork stands in front of it.

     Which hands the auto margin back to the actions, where it was before the
     box came to sit at the end of the row. It holds everything after it at
     the far end, and the glass, riding along behind it on `order`, comes with
     it. That is also the whole of what a rule about a hidden glass used to
     do here: the corner belongs to the actions either way now, so a page that
     has no glass (see paintHeader) needs nothing said about it.

     AND IT IS THE WHITE THE OTHERS ARE. It was drawn transparent here, which
     on a bar that is not white is a hole with a line round it standing beside
     two solid buttons (see .top-actions .btn.ghost, which had the same
     trouble). A row of pictures is one row or it is not. */
  .top-find { flex: none; width: 36px; order: 1; }
  .top-find .find {
    height: 36px; padding: 0; gap: 0; cursor: pointer; justify-content: center;
    color: var(--ink);
  }
  .top-find .find > svg { width: 18px; height: 18px; color: inherit; }
  .top-find input[type="search"] { width: 0; flex: 0 0 0; }

  /* Open, it is a field again: the room and the space around what is in it
     come back. The white is not mentioned here any more, because it never
     went: closed it is a button and a button on this bar is white.

     AND IT IS OPEN FROM THE START ON A BAR WITH NO NAME ON IT. The whole of the
     glass above is an answer to a row that is full: a mark, the name of the
     page and four pictures, with ninety pixels left over. The library carries
     no name any more (see where in app.js), so the row is the mark, the box and
     the fork, and there is room for the box to BE a box. Which is also the only
     way anybody meets it: a glass that has to be pressed before it says what it
     is for is a search nobody looks for.
     It goes back to the order it stands in on a desk, so the fork keeps the
     corner and the box runs from the mark up to it.

     AND THE WALL OF PLAYLISTS AND THE WALL OF PEOPLE ARE THE SAME BAR. Neither
     names itself any more either (see viewPlaylists and viewCreators in
     app.js), for the reason the library does not, and so the same one rule
     answers all three: a bar with no name on it has the room, and the box
     takes it. */
  body.finding .top-find,
  body.unnamed .top-find { flex: 1 1 auto; width: auto; order: 0; }
  body.finding .top-find .find,
  body.unnamed .top-find .find {
    padding: 0 12px; gap: 9px; justify-content: flex-start;
  }
  body.finding .top-find input[type="search"],
  body.unnamed .top-find input[type="search"] { width: auto; flex: 1 1 auto; }
  /* The facts go with the name, because they are the name's second half: what
     the song says about itself has nothing to do with the question being typed
     into the box, and one more picture standing there is one more bite out of
     the ninety pixels the box was already short of.

     Not on the bare bar, where nothing is in the way: the box already runs the
     width of the row, and there is no room to be had by taking the mark and the
     fork off the screen. All that would be left is the flinch of a bar
     rearranging itself under the thumb that touched it. */
  body.finding:not(.unnamed) .brand, body.finding:not(.unnamed) .top-actions,
  body.finding:not(.unnamed) .top-name, body.finding:not(.unnamed) .top-facts,
  body.finding:not(.unnamed) .top-in > .tools { display: none; }
  /* On a full bar, everything that could have given the bar back is hidden, so
     the box has to carry its own way out. On the bare one it is the way out of
     the SEARCH rather than out of the bar: a press empties the box and hands
     the whole wall back, which is otherwise a field to be cleared by hand. */
  body.finding .top-find .find-x { display: flex; }

  /* the total beside the name comes down with the name: they are one line,
     and one of them a pixel bigger than the other is what breaks that */
  .top-where, .top-bill { font-size: 16px; }
  .find-out { inset-inline-start: auto; inset-inline-end: 0; }

  /* THE DATE WAS PUT ON A LINE OF ITS OWN HERE, when a date field was as wide
     as the browser felt like making it. It is the width of its own text now
     and it stands beside its word like everything else on the row. */
  .kinds-label { flex: 1 1 100%; }
}

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

.btn {
  appearance: none; border: 1px solid transparent; cursor: pointer;
  background: var(--accent); color: #fff;
  padding: 9px 16px; border-radius: var(--corner);
  font: inherit; font-weight: 600; font-size: 15px; line-height: 1.2;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background .15s, color .15s, border-color .15s;
}
.btn:hover { background: var(--accent-ink); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn.ghost:hover { background: #fff; border-color: #cdd8de; }
.btn.danger { background: transparent; color: var(--danger); border-color: #f0d3cf; }
.btn.danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn.small { padding: 6px 12px; font-size: 14px; }
.btn:disabled { opacity: .5; cursor: default; }
.btn svg { width: 17px; height: 17px; }

.icon-btn {
  appearance: none; border: 1px solid var(--line); background: #fff; cursor: pointer;
  width: 30px; height: 30px; border-radius: var(--corner); padding: 0;
  display: inline-grid; place-items: center; color: var(--ink-soft);
}
.icon-btn:hover { color: var(--ink); border-color: #cdd8de; }
.icon-btn svg { width: 15px; height: 15px; }

/* For the one you almost never mean and can never take back. No border and no
   colour until you are actually on it, so it is reachable without being
   offered. */
/* the one that is IN a state rather than doing a thing: pressed, it is the
   editor being open */
.icon-btn.is-on { color: #fff; background: var(--accent); border-color: var(--accent); }
.icon-btn.is-on:hover { color: #fff; background: var(--accent-ink); border-color: var(--accent-ink); }

.icon-btn.quiet { border-color: transparent; background: none; }
.icon-btn.quiet:hover { color: var(--danger); border-color: #f0d3cf; background: #fff; }

/* --- shared bits -------------------------------------------------------- */

.muted { color: var(--ink-soft); }
.err { color: var(--danger); font-size: 14px; margin: 4px 0 0; }
/* The raw string a machine handed us: an English message, a code, a path. It
   is set in monospace and left to right because that is what it is, and it is
   never a sentence anybody wrote. */
/* IN THE COLOUR THE CHORDS ARE, which is the app's other colour and the one it
   already uses for the thing that went wrong: it was a brown on a pink of its
   own, a third colour on a page that has two, and what it said in that brown
   was that a reading had failed. */
.detail {
  margin-top: 6px; padding: 7px 10px; border-radius: var(--corner);
  background: var(--chord-soft); color: var(--chord);
  font: 12px/1.5 ui-monospace, Menlo, Consolas, monospace;
  direction: ltr; text-align: left; word-break: break-word;
}
/* The same box for a sentence WE wrote, which is Hebrew and reads right to
   left in the page's own type. In .detail it came out backwards: the full stop
   landed on the wrong end and the words sat in a monospace grid they were
   never written for.

   AND IN THE WARM COLOUR, not the pink. Pink is the chords: it is on every
   chip over every line and on the letters in the corner of every card, so a
   pink box on a card read as chords at a glance, and what it says is that
   there are none. The same sentence stands on the song page in .song-note,
   and it is the same sentence, so it is the same colour. */
.note {
  margin-top: 6px; padding: 7px 10px; border-radius: var(--corner);
  background: var(--note); border: 1px solid var(--note-line);
  color: var(--ink-soft);
  font-size: 13px; line-height: 1.5; text-align: right;
}
.center { text-align: center; padding: 56px 0; color: var(--ink-soft); }
.center p { margin: 0 0 18px; }

/* .btn sets display, which beats the user agent's rule for [hidden] */
[hidden] { display: none !important; }

.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}

input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="date"], textarea, select {
  font: inherit; color: var(--ink);
  background: #fff; border: 1px solid var(--line); border-radius: var(--corner);
  padding: 9px 12px; width: 100%;
}
input:focus-visible, textarea:focus-visible, select:focus-visible, .btn:focus-visible, .icon-btn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
label { display: block; font-size: 14px; font-weight: 600; color: var(--ink-soft); }
label input, label textarea, label select { margin-top: 5px; font-weight: 400; color: var(--ink); }

/* --- index -------------------------------------------------------------- */

/* No heading over the list. The page is the list, it says so in the top bar,
   and a title that repeats that only pushed the songs down the screen. */
/* AND THERE WAS A .search HERE, and now there is no box on a page at all. It
   was the library's own, with the state chips riding inside it; searching
   moved into the bar, where it reaches the people and the playlists as well and
   stands on every page rather than on one, and the chips moved down onto the
   row over the wall, where they are filtering and nothing else.

   The shape outlived it by one box, the shelf at the foot of a playlist, and
   that box is the bar's now too (see state.pick). Which is the whole point of
   there being one: a person types the name of a song into the same field
   wherever in this app they happen to be standing. */

/* How much of the library is waiting for something, in four numbers. Quiet and
   small: they are the state of the shelf, not the shelf. Pressable, because a
   number worth showing is a number somebody wants the list of.

   AT THE FAR END, over the column of labels they are counting. A number and
   the rows it counts want to be in the same place, or the eye has to travel
   the width of the page to connect them. */
/* In the row over the wall they take the width, and in the search box they
   take what they need (see .find-extra). */
.tallies {
  display: flex; flex-wrap: wrap; gap: 8px;
  flex: 1 1 auto;
}
.tally {
  display: inline-flex; align-items: baseline; gap: 6px;
  appearance: none; cursor: pointer; font: inherit; font-size: 13px;
  background: var(--card);
  border: 1px solid var(--line); border-radius: var(--corner); padding: 4px 12px;
}
.tally-n { font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; }
/* Each in its own state's colour, always, and not only when it is the one
   being looked at: it is the same colour that state wears on every row below
   and on the button inside the song. Pressed, it fills with it. */
/* THE ROW OVER THE WALL, AND ONLY ON A PHONE: the states, and nothing else
   any more. On a desk they are at the end of the search box and this row is
   not drawn at all: see rehome in the script. */
.kinds-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 0 0 16px;
}
/* AND THEY SIT IN THE MIDDLE OF IT. They were against the start edge because
   a tick stood in front of them holding them there; on their own they were a
   short huddle of chips in one corner of a page whose every other band, the
   shelves and the wall, is laid out across the whole of it. Centred, they are
   a band of their own. */
.kinds-row .tallies { justify-content: center; }

/* --- AND WHILE THE BOX IS HOLDING THE PAGE DOWN, THE WALL CAN REACH THE BAR --
   The library opens with the doors, the drawing, the band of shelves and the
   row of counts, and then the songs. Every one of those is about the whole
   library. Somebody who has typed three letters is not asking about the whole
   library, and what they asked for was starting a screen and a half below the
   answer they were reading.
   All of that used to come off the page while the box was in use. Now it stays
   and the page scrolls past it instead (see siftRoom in the script), so the
   reader can bring it back with a thumb rather than by emptying the box.
   What is left here is the floor that scroll lands on: a wall narrowed to four
   songs is shorter than the head standing above it, and a document that ends
   before the scroll does hands the scroll straight back, head and all. A
   screen's worth under the top of the wall is enough for the head to clear the
   glass at any height it comes to.
   The band of shelves is not given one: it is above the wall, so it is part of
   what the scroll is getting out of the way. */
/* And the same floor under a playlist's wall, which the same box sieves into
   the same library (see state.sift in renderPlaylist). */
body.sifting .list:not(.band), body.sifting .set { min-height: calc(100dvh - var(--top-h)); }

/* All five in the one colour a state wears, and the word on each is which of
   them it is (see the states at the top of this file). They were five
   different colours, which made this row a key to a code, and the code said
   nothing the words did not. */
.tally-offer, .tally-imported, .tally-review, .tally-draft, .tally-published {
  color: var(--state-ink);
}
.tally:hover { border-color: currentColor; }
.tally.is-on { border-color: currentColor; }
.tally-offer.is-on, .tally-imported.is-on, .tally-review.is-on,
.tally-draft.is-on, .tally-published.is-on { background: var(--state-soft); }

/* AND THE ONE CHIP IN THE ROW THAT MAKES SOMETHING. The others narrow the wall
   underneath, so they are quiet and take their colour from the state they
   count; this one adds a song, and it wears the colour every button in the app
   that does something wears. Same size and same corner as its neighbours,
   because it stands in their row, and filled, because it is not one of them.
   It is only ever drawn on a phone, where it came down out of the bar. */
.tally-add {
  align-items: center;
  background: var(--accent); color: #fff; border-color: transparent;
  font-weight: 600;
}
.tally-add:hover { background: var(--accent-ink); border-color: transparent; }
.tally-add svg { width: 16px; height: 16px; }

/* --- AND ABOVE THAT ROW, THE DOORS TO THE REST OF THE APP -------------------
   The playlists, the people, and whoever is signed in. They were three rows
   behind three dots in the corner of the bar, and a picture of three dots
   says "there is more" and nothing else: half the app sat behind a press
   that had to be spent before it could be read. They are chips over the wall
   now (see paintDoors in the script), in a band of their own above the row
   that adds and counts, read at a glance.

   Quiet, in the same grey the app's second lines are written in: the row
   under them carries a number each and the one filled chip that makes
   something, and a door is neither. Same size and same corner, so the two
   rows read as one band with a hairline of air between them. */
.doors-row { margin-bottom: 8px; }
.tally-door { align-items: center; color: var(--ink-soft); }
.tally-door svg { flex: none; width: 16px; height: 16px; }
/* A name is as long as somebody's name is, and one long one should not push
   the other doors out of the row. Cut with an ellipsis: the whole of it is in
   the panel that chip opens. */
.tally-door .tally-l {
  display: inline-block; max-width: 14ch;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* --- AND UNDER THE BAR, ONE PICTURE ----------------------------------------
   The library opens on a wall of names, and it is the only page here that is
   about the thing all of them are: songs somebody plays and sings. So the head
   of it carries a drawing (public/assets/strip.webp), and it is the one thing
   on the page that is neither a row nor something to press.

   FULL BLEED, AND UP BEHIND THE BAR TO THE TOP OF THE SCREEN. #app keeps a
   gutter of sixteen pixels either side and a band of air on top (see .wrap and
   --bar-air), and above that the bar itself stands in the flow; everything
   else on the page stands under all of it. A picture that stopped short of any
   of them would read as a card with a drawing in it rather than as the head of
   the page, so it hands back the gutter, the air AND the height of the bar,
   and the bar, which is sticky and painted over what follows it, floats on the
   drawing (see body.bar-clear up in the header rules).

   THE BAR'S OWN HEIGHT IS MEASURED AND NOT WRITTEN DOWN. It is a row of
   controls whose height is whatever they come to at this width, in this font,
   on this phone; a number typed here would be right on one screen and leave a
   seam or a jump on the next. It arrives as --top-h (see barHeight in app.js)
   and the fallback below is only for the frame before the first measurement.

   IT IS A BAND AND NOT A PICTURE OF A BAND. It was a landscape frame on a
   phone, three fifths as tall as it was wide, and the first thing under it was
   below the fold on a small screen: the library opened on a drawing instead of
   on songs. Two fifths, and the songs are back where the thumb is.

   WHAT THE SHORTER FRAME DOES IS SHOW MORE OF THE DRAWING, not less of it: the
   art is about three to one and every frame here is narrower than that, so it
   is filled and cut rather than reshaped (see cover below). A shorter band is a
   wider window onto the same drawing, which is why the two of them stand with
   room either side of them and the notes are strewn well past it.

   THE SHAPE IS WHAT CHANGES WITH THE WIDTH, and not the drawing. A desk gets a
   thinner band still: the same height held across two thousand pixels is a
   screenful spent before the first song, and past about 1650 the ceiling stops
   it growing at all. */
.strip {
  margin: calc((var(--bar-air) + var(--top-h)) * -1) -16px 18px;
  /* Two fifths of the glass for the drawing, and the bar's height on top of
     that, so that what is left under the bar is the same band it would have
     been if the bar had been standing on it. */
  height: calc(40vw + var(--top-h));
  /* --- AND THE BAR STANDS ON PAPER AND NOT ON THE PICTURE --------------------
     The room the bar takes is given back to the drawing above, and then handed
     straight to this padding: what is behind the mark and the search box is a
     band of the drawing's own colour, and the drawing itself begins under
     them. Nothing of it is covered, which is the whole difference between a
     picture that runs behind a bar and a picture with a bar sitting on its
     people.

     The colour is the top edge of the drawing, exactly, so the two meet with no
     seam. The drawing was prepared to make that possible: its white borders
     were cut off and the band of its own colour was carried on upwards, so its
     whole top edge is this one flat value (see scripts/strip.py).

     AND IT IS ONLY BEHIND THE BAR. It was the whole box once, which was fine
     while the drawing was opaque to its last row; it fades out to nothing now,
     and a colour laid under the whole box is exactly what a fade to nothing
     must not find waiting for it. Painted to the height of the padding and no
     further, so what the fade ends in is the page. */
  padding-top: var(--top-h);
  background: linear-gradient(#f3f7f6, #f3f7f6) top / 100% var(--top-h) no-repeat;
  overflow: hidden;
}
.strip img {
  display: block; width: 100%; height: 100%;
  /* FILLED, NEVER STRETCHED. Every frame here is narrower than the drawing, so
     what a frame has no room for is cut off its sides or its ends, and the
     middle of it, where the two of them are standing, is in every one of
     them. */
  object-fit: cover;
  /* AND WHAT IS CUT OFF A SHORT BAND IS THE FEET. On a wide screen the band is
     a slice of a drawing that is nearly as tall as its people, and a slice
     taken from the middle takes the same off the top as off the bottom: their
     heads. Held up here, the wider the screen gets the more of the legs it
     loses and never the heads, which is how a photographer would have framed it
     anyway. A tenth and not a quarter: the drawing carries a strip of its own
     colour above the heads for exactly this, so the window can sit high without
     standing on anybody's hair. */
  object-position: 50% 10%;
}
/* A HEIGHT, AND NOT A RATIO WITH A CEILING ON IT. aspect-ratio and max-height
   together do not do what they look like they do: the ratio is kept, so a box
   whose height is cut to the ceiling gives up the width to match, and a band
   that is meant to run to both edges of the glass comes back off them. The
   height is asked for outright instead, a sixth of the window between a floor
   and a ceiling, and the width is left alone at the whole of it. The floor is
   there because a sixth of a narrow desk window is a letterbox with two heads
   in it; the ceiling, because past about 1650 pixels the band would go on
   growing into the screenful it was cut down from. */
@media (min-width: 621px) {
  .strip { height: calc(clamp(150px, 17vw, 280px) + var(--top-h)); }
}
/* A drawing is not a fact about a song, and paper gets the facts. */
@media print { .strip { display: none !important; } }

/* --- AND AIR ABOVE THE SHELVES ---------------------------------------------
   The band of styles is the first thing on the page that is the LIBRARY
   rather than something to press, and it was sitting a hair under the row of
   chips: two bands of rounded boxes with nothing between them read as one
   confused band. The room says which is which.

   It is a margin on the shelves and not under the chips, so it is the same
   gap at both widths: on a phone there is a row of counts between the two and
   on a desk there is not, and adjacent margins collapse to the larger of them
   either way. Nothing when there are no shelves at all. */
.shelves:not(:empty) { margin-top: 26px; }

/* --- THE LIBRARY IS A WALL OF CARDS ---------------------------------------
   It was a column of full-width rows, which is what a list of one line each
   wants; these are not one line each. A row carried a name, who wrote it, what
   kind of song it is, the chords it uses, what state it is in and when it
   changed, and it spread all of that across the whole screen with a hand's
   width of nothing in the middle of every one.

   So each song is a card as wide as what is inside it, and they wrap. A short
   song takes a little room and a long one takes more, which is a shelf: you
   see the shape of the library rather than reading down a ledger. */
.list {
  list-style: none; margin: 0 0 64px; padding: 0;
  /* COLUMNS, NOT A GRID, and the difference is what a card is allowed to be.
     A grid puts its rows in step: every card in a row is the height of the
     tallest one in it, so either the short ones are stretched or the space
     under them is a hole, and there is no third answer.

     Columns have no rows. Each card is exactly as tall as what is written on
     it, the next one starts where the last one ended, and the only space
     anywhere is the twelve pixels between them. As many columns as the window
     holds, all one width, and in Hebrew the first is the right hand one, where
     the page already starts. */
  columns: auto 340px;
  column-gap: 12px;
}

/* AND A WALL THAT DOES NOT FILL THE WINDOW STANDS IN THE MIDDLE OF IT.
   Columns are laid from the edge the page begins at, so a wall that does not
   fill its columns leaves the empty ones at the far end and stands against one
   side of the screen with a hand's width of nothing beside it.

   The auto margins are here and the width they middle is written on by the
   script, which is the only one of the two that can know it: how many columns a
   wall of unequal cards balances into is the browser's own answer, and it is
   measured off the cards after they are laid (see middleWall in app.js). This
   was four :has() rules counting up to four cards, which is the one case the
   count and the answer agree on. The band of shelves and the bill middle
   themselves, further down. */
.list:not(.band):not(.ledger):not(.sets) { margin-inline: auto; }
/* A card is never split down the middle of itself by a column ending, and it
   carries its own space underneath: in a column layout there is no gap
   property to do it. */
.list li {
  display: flex; min-width: 0; position: relative;
  break-inside: avoid; margin-bottom: 12px;
}
.list li > a, .list li > .row, .list li > .shelf { flex: 1 1 auto; min-width: 0; }
/* THERE WAS A CHECKBOX OVER THE CORNER OF EVERY CARD, and a gutter left in the
   card for it. A whole second way of using the library hung off it: tick a few
   songs and a row of buttons appeared to do something to all of them at once.
   It is gone. A card is a song and a press on it opens that song, and what
   happens to a song happens on the song's own page, where the thing being
   changed is on the screen while it changes. */

/* Everything starts at the top of the card. The cards in a row are all the
   height of the tallest of them, so a song with a short name and no chords
   centred what little it has in the middle of a card sized for something else,
   and the wall stopped having a line to read along. */
.list a, .list .shelf {
  display: flex; align-items: flex-start; gap: 14px; text-decoration: none; color: inherit;
  /* ONE CARD IS ONE CARD, WHEREVER IT IS. A song in the library and a song in
     a playlist are the same sheet of paper on the same desk, and they carry
     the same three things: the white, the hairline round it and the shadow
     under it (see .card). Half of them had no shadow, which on the same grey
     read as a box drawn on the desk beside a card rather than as another card.
     A segment of a song is not one of these any more: a song is the page
     itself, not a wall of cards on one (see .col). */
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 18px; transition: border-color .15s, transform .15s;
}
/* --- LIT ONLY WHERE THERE IS SOMETHING TO LIGHT IT WITH ---------------------
   A card lifts and takes a green edge under a pointer, which is the right thing
   to say to a mouse and the wrong thing to say to a finger: a touch screen has
   no hover, so it fakes one on the last thing tapped and leaves it there. What
   that looked like was a card that stayed selected after its play button was
   pressed, on a press that was never about the card at all. */
@media (hover: hover) {
  .list a:hover, .list .shelf:hover { border-color: var(--accent); transform: translateY(-1px); }
  /* AND NOT WHILE THE POINTER IS ON THE BUTTON STANDING ON IT. Playing a
     recording is not a way of opening the song, so the card should not be
     offering to open while it is being done. */
  .list a:hover:has(.has-takes:hover) { border-color: var(--line); transform: none; }
}
/* The label inside the button is words in the middle of a link, so a press
   that lands a hair off centre selects them and paints them instead. */
.when.has-takes { user-select: none; -webkit-user-select: none; }
.list .t { font-weight: 700; font-size: 17px; }
.list .a { color: var(--ink-soft); font-size: 14px; }
/* What is in the playlist, by name. Two lines at most: a line in an index is a
   taste of the list, not the list, and a playlist of thirty songs would push
   the next playlist off the screen. */
.list .names {
  margin-top: 2px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden;
}
/* --- WHAT IS IN AN EVENING, AS CHIPS --------------------------------------
   They were a sentence of names with dots between them, which reads as one
   thing said about the playlist. They are a list of songs, and what somebody
   looking at one on this card almost always wants is to open it, so each is a
   chip and a press on it goes to the song rather than to the playlist around
   it (see playlistRow).

   No clamp on it. Two lines of a sentence was a taste of a list; chips wrap
   into a block that is plainly a list, and a playlist with twenty songs in it
   is a playlist with twenty songs in it. */
.pl-songs { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* A button drawn as the chip it is standing among: the reset first, then the
   two things .tag would have given it, because `font` is a shorthand and this
   rule comes after it. */
.pl-song {
  appearance: none; cursor: pointer; border: 0;
  font: inherit; font-size: 12px; font-weight: 600; line-height: 1.6;
}
.pl-song:hover { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* --- AND WHOSE IT IS, ON THE ONES THAT ARE NOT YOURS ----------------------
   Almost every card on this wall is the reader's own and says nothing here at
   all, so this line is not part of how a playlist's card is read: it is a mark
   on the few that came from somebody else. Quiet, and above the description,
   because it belongs to the name rather than to what the list says about
   itself (see playlistRow). */
.pl-from { margin-top: 2px; font-weight: 600; }

/* --- AND A PLAYLIST'S CARD IS AS WIDE AS THE PAGE --------------------------
   The songs stand in columns of 340 because a song card is a name, a line of
   credit and three chords: narrow things, many of them, read by scanning down
   a shelf. A playlist card is a name with a LIST inside it, and the list is
   the whole of what somebody came to look at. Poured into one 340 column it
   broke a set of fifteen songs into fifteen lines of one chip each, a tall
   thin ribbon of names beside an empty half of a screen.

   So this wall is one card wide. Full width, one under the next, and the
   chips wrap across the room they need. The script leaves it alone: middling
   a wall is for a wall that has columns to count (see middleWalls). */
.list.sets { columns: auto; }

/* The name, and what the reading of it cost, which is the only thing that
   shares its line. */
.list .t-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
/* AND WHO WROTE IT ON THE LINE UNDER IT, the way the song's own page says it
   under the name in the bar. Beside the name it was a second thing of the same
   size fighting it for the width of a card. */
.list .by { color: var(--ink-soft); font-size: 14px; }
/* Only the one standing under the row, and not the count of songs that still
   sits inside it on a person's card. The same two pixels under a name that has
   no row around it, which is a playlist's card: what the list says about
   itself sits against the name it is about. */
.list .t-row + .by, .list .t + .by { margin-top: 2px; }
/* Which of the songs by this name. Only appears where a name repeats, so an
   index of songs that are each the only one of themselves never grows a column
   of ones. Quiet, and clearly not part of the name. */
.list .dupe {
  display: inline-block; margin-inline-start: 8px; vertical-align: 1px;
  font-size: 12px; font-weight: 700; line-height: 1.5;
  color: var(--ink-soft); background: var(--line);
  border-radius: var(--corner); padding: 0 8px;
}
/* The song's own chords, under its name, in the order it reaches them and in
   the page's own direction: the first one the song plays is the first one you
   read.

   The same three on a row of a playlist, which is the list somebody is
   actually holding a guitar over. Two places, one look, one rule. */
.list .keys, .set-main .keys {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px; margin-top: 6px;
}
.list .k, .set-main .k {
  font-size: 13px; font-weight: 700;
  color: var(--chord); background: var(--chord-soft); border-radius: var(--corner); padding: 2px 9px;
  direction: ltr; white-space: nowrap;
}

/* The far end of a card: the state at the top of it and the date at the
   bottom. With the tick and the name at the other end, that gives the card its
   four corners, one fact in each: where you choose, where you read, where you
   sort, where you last left off. Nothing floats in the middle of the card
   except what the card is actually about. */
.list .side {
  margin-inline-start: auto; align-self: stretch;
  display: flex; flex-direction: column; align-items: flex-end;
  justify-content: space-between; gap: 8px;
}
.list .side-tags { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }
.list .when { white-space: nowrap; color: var(--ink-soft); font-size: 13px; }
/* --- HOW MANY RECORDINGS OF IT ARE OUT --------------------------------------
   Where the clock used to be, and it is a different kind of thing so it is
   drawn as one: a mark and a number rather than a line of text.

   AND IT IS THE GREEN, NOT THE PINK. The pink is the chords', and the argument
   for it here was that a recording is somebody playing this song. True, and it
   is not what the button is counting: it counts the takes that are OUT, the
   ones anybody may hear, and it is not there at all until one of them is (see
   db.outTakes). Out in the world is the one thing this app says in green, on
   the chip that says a song is published and on the row that publishes it, and
   a number of public recordings is the same fact about a different thing. */
/* AND IT IS A BUTTON. A wall of songs is a wall of things to pick up, and the
   shortest way to decide whether to pick this one up is to hear somebody play
   it, so the mark that says there are recordings is the thing that plays one.
   The count stays inside it: what is being pressed is "the recordings of this
   song", and how many there are is part of what that means. */
/* AND IT IS NOT THE WALL'S. The button is part of a song card, and a song
   card is drawn on the library, on a person's page and on a playlist's list,
   so what it looks like cannot hang off the list it happened to be born in.
   Everything it needs it carries itself: the width it wants, and a refusal to
   be squeezed by whatever it is standing beside. */
.when.has-takes {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
  flex: none; white-space: nowrap;
  padding: 3px 9px 3px 7px; border-radius: 999px;
  border: 1px solid var(--accent-soft); background: var(--accent-soft);
  color: var(--accent-ink); font: inherit; font-size: 12px;
  font-variant-numeric: tabular-nums; font-weight: 700;
}
.when.has-takes:hover { border-color: var(--accent); }
.when.has-takes svg { width: var(--transport); height: var(--transport); }
.when.has-takes.is-playing {
  color: #fff; background: var(--accent); border-color: var(--accent);
}
.when.has-takes[disabled] { opacity: .5; cursor: default; }
/* THE DATE STAYS AT THE BOTTOM WITH NOTHING OVER IT. A published song carries
   no chip any more (see songRow), so its column holds one thing, and
   space-between with one thing in it puts that thing at the top: the date
   would sit level with the name on most cards of the library and level with
   the chords on the rest. Pushed down by hand, the corner is the corner. */
.list .side > .when:only-child { margin-block-start: auto; }

/* a song that is not openable yet: being read, or failed. Same box as a link,
   without the link, so the list keeps its rhythm while one row is busy. */
.list .row {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  /* the same card as the link beside it, because that is the whole point of it */
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 18px;
}
.list .row.is-reading { border-style: dashed; }
.list .row.is-queued { border-style: dashed; opacity: .72; }
.list .row.is-failed { border-color: #f0d3cf; background: #fffaf9; }
/* THE PRICE OF A READING WAS HERE, beside the name of every song, for the one
   account that pays for them. It is a page of its own now (see .ledger below):
   money is read in totals and in comparisons, and a number in the corner of a
   card is neither. */
.list .row .a { color: var(--ink-soft); font-size: 14px; }
.list .row .detail, .list .row .note { flex-basis: 100%; }

.row-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-inline-start: auto; }

/* --- THE BAND OVER THE WALL: THE STYLES ------------------------------------
   The same card as a song, and not the same shape of list. The songs are a
   wall: many, unequal, read by scrolling, and columns are what lets each one
   be exactly as tall as it is. A band is a handful of short cards read across
   in one look, and columns would pour eight of them down the right hand edge
   and leave the rest of the line empty.

   So a band is a row that wraps, MIDDLED: five cards sit in the middle of the
   page rather than trailing off from one edge, and the last line of a long
   band is centred under the ones above it instead of ending halfway. */
.list.band {
  columns: auto;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 12px; margin-bottom: 36px;
}
/* The card carries its own space in a column layout; in a row it is the gap's
   job, and two of them together is a double line between the bands. */
.list.band li { margin-bottom: 0; max-width: 340px; }
/* AND EACH CARD IS READ ACROSS ITS OWN MIDDLE. A song card starts everything
   at the top because it has four corners with a different fact in each; these
   have a name at one end and a word about it at the other, on one line, and
   anything else lines up with that line. */
.list.band a, .list.band .shelf { align-items: center; }
.list.band .side { align-self: auto; justify-content: center; }
/* --- AND A SHELF IS A BUTTON, BECAUSE PRESSING ONE DOES NOT LEAVE THE PAGE ---
   It was a link to a page of its own. It holds the library down to one kind of
   song now and the page stays where it is (see pickKind in app.js), so the card
   is a button wearing exactly the card the songs under it wear: everything a
   browser puts on a button of its own is taken back off, and what is left is
   the white, the hairline and the shadow that .list a above already said. */
.list .shelf {
  appearance: none; font: inherit; text-align: start; cursor: pointer;
  width: 100%;
}
/* AND THE ONE THAT IS ON SAYS SO, in the same soft green everything in this app
   that is currently narrowing something says it in (see .tally.is-on). It is
   the one card in the band that is not a way to somewhere: pressing it again is
   the way back to all of them, which is what the cross on the chip in the
   search box also does. */
.list .shelf.is-on {
  border-color: var(--accent); background: var(--accent-soft); color: var(--accent-ink);
}
.list .shelf.is-on .tag-count { color: var(--accent-ink); background: #fff; }
/* AND THE NAME ON ONE OF THESE IS SMALLER THAN THE NAME ON A SONG. A band
   stands ABOVE the wall the page is for, and it was set in the same seventeen
   pixels: two or three shelves in the type of the thing they are shelves of,
   which made the first screen of the library read as two walls of equal
   weight. It is a way in, not the thing. */
.list.band .t { font-size: 15px; }

/* Which shelf this is. Quiet and centred: it is a label on a shelf, not a
   heading somebody is meant to read before the shelf.

   CENTRED OVER THE WALL OF SONGS, which is the one that fills from the edge of
   the page rather than from the middle. It used to start where its cards
   start, for that reason, and centred it sits over the band of shelves above
   it instead of off to one side of the page. */
.band-h {
  margin: 0 0 12px;
  font-size: 14px; font-weight: 700; color: var(--ink-soft);
  text-align: center;
}

/* the way to what was deleted, and the way back from it: under the list, where
   somebody who has finished reading it is looking */
/* One row under the wall, holding whatever doors this account has: the bill
   and the bin. A gap, because there can be two of them and the second arrives
   a moment after the page does. */
.after-list { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin: -40px 0 64px; }
/* a song that is not in the library any more, and is still every word of what
   it was */
.list .row.is-gone { opacity: .8; }

/* --- THE BILL: EVERY READING AND WHAT IT COST -----------------------------
   /chords/reads, and it is the one list in this app that is NOT a wall. The
   library is a wall because a song is a thing of its own size and the shape of
   the shelf is worth seeing; a bill is read DOWN, one line per reading, with
   the money in the same place on every line so the eye can run the column.
   Hence one narrow column and not the card layout above.
   ------------------------------------------------------------------------ */
.list.ledger {
  columns: auto; max-width: 680px; margin-inline: auto; margin-bottom: 28px;
}
.list.ledger li { margin-bottom: 8px; }
/* ONE READING IS ONE CARD, and the card is the link where the song can be
   opened. `.read` catches both, because a card that cannot be opened is drawn
   by `.list .row` as the same sheet of paper without the link. */
.list .read { align-items: center; gap: 10px; padding: 12px 16px; }
.list .read .what { flex: 1 1 auto; min-width: 0; }
.list .read .t { font-size: 16px; }
.list .read .side { flex: none; align-self: center; }

/* THE MONEY, ALWAYS AT THE END OF THE ROW AND ALWAYS THE SAME WIDTH. Tabular
   figures and one direction: a column of prices that shifts by a digit is a
   column nobody can compare down. */
.read-paid-one, .read-total {
  font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate;
  white-space: nowrap; font-weight: 700;
}
.read-paid-one { font-size: 16px; }

/* THE WHOLE OF IT, ON THE BAR, AT THE HEAD OF ITS OWN COLUMN. It stood over
   the page as a line of its own, at twenty-two pixels, and left the screen
   with the first scroll; up here it stays while the list runs (see viewReads).

   AND IT STANDS WHERE THE OTHER PRICES STAND. Every reading below puts its
   money at the end of its row, in one column the eye runs down, and the total
   is the top of that column: beside the name of the page it was a second thing
   to find, a hand's width from the numbers it is the sum of. Which is the
   whole reason the money on this page is a column at all.

   NOT A CHIP AND NOT A BOX. Nothing in that bar is a fact with a border round
   it: a box up there is a thing to press, and this is a number to read. So it
   is the number, in the weight and the size of the name at the other end of
   the bar.

   HOW IT FINDS THE COLUMN. The bill is 680 wide and middled in the page (see
   .list.ledger), so the column's end is half of whatever is left over, and
   then the card's own 16 of padding and the hairline round it. The bar is the
   same .wrap, so the same sum lands the total on the same pixel at every
   width: hard against the edge on a phone, and out over the column on a desk.
   The auto margin in front of it does the rest of the row. */
.top-bill {
  font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate;
  white-space: nowrap; font-weight: 700; font-size: 17px;
}
.top-facts:has(.top-bill) {
  margin-inline-start: auto;
  margin-inline-end: calc(max(0px, 100% - 680px) / 2 + 17px);
}
.read-n { color: var(--ink-soft); font-size: 14px; }

/* --- ONE ACCOUNT IS A DRAWER ----------------------------------------------
   The heading holds the whole answer, a name, a sum and how many readings it
   is made of, and the readings are behind it. It is a `summary`, so the mark
   the browser draws by itself is taken off and one of ours is drawn instead:
   the same chevron at the same size in every browser, turned over when the
   drawer is open. */
.read-band { max-width: 680px; margin: 0 auto 10px; }
.read-h {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  cursor: pointer; list-style: none;
  padding: 10px 4px; border-bottom: 1px solid var(--line);
}
.read-h::-webkit-details-marker { display: none; }
.read-h:hover { border-bottom-color: var(--accent); }
.read-h:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--corner); }
.read-turn {
  flex: none; width: 16px; height: 16px; color: var(--ink-soft);
  transition: transform .15s ease;
}
.read-band[open] > .read-h > .read-turn { transform: rotate(180deg); }
/* the cards inside sit off the heading rather than against it */
.read-band[open] > .list.ledger { margin-top: 10px; }
.read-who { font-weight: 700; font-size: 17px; flex: 1 1 auto; min-width: 0; }
.read-paid { display: flex; align-items: baseline; gap: 8px; flex: none; }
.read-paid .read-total { font-size: 16px; }
@media (prefers-reduced-motion: reduce) {
  .read-turn { transition: none; }
}

/* HOW THE READING WENT, in the same chips the states of a song wear, and in
   colours that mean the same things they mean there: green for the one that
   went right and cost least, blue while it was the machine's work, amber for
   the half that has been left to a person, red for the one that came back with
   nothing. */
.tag-measured { color: var(--accent-ink); background: var(--accent-soft); }
.tag-model { color: var(--told-ink); background: var(--told-soft); }
.tag-half { color: var(--part-ink); background: var(--part-soft); }
.tag-failed { color: var(--danger); background: #f9e6e3; }

/* The chip that gathers the rows by account rather than ordering them. Pressed
   it is the accent, because it is the one control here that changes the shape
   of the page and not the order of it. */
.tally-group.is-on { color: var(--accent); background: var(--accent-soft); }

/* What stands in the sheet while the machine is still reading the song into
   it. In the sheet and not over the page, because it is standing exactly where
   the words will be. */
.coming { text-align: center; padding: 30px 0 34px; }
.coming p { margin: 12px 0 0; font-size: 14px; }

/* --- a playlist ----------------------------------------------------------
   A name, a line saying what the list is, and the songs in the order they will
   be sung. The head and the tools are the song page's own, because it is the
   same shape of page: one thing, open, with its controls above it. What is new
   starts at .set.
   ------------------------------------------------------------------------ */

/* A name that has not been typed yet still has to be somewhere to click. An
   empty contenteditable is zero pixels wide, so it says what it is instead.
   Both names on this app work that way, a song's and a playlist's. */
/* The headings a song, a playlist and a person carry are for PAPER now: the
   name itself is typed in the bar, and a page that showed it twice would have
   two places for it to be wrong. Paper has no bar. */
.song-head h1.on-paper, .pl-title.on-paper { margin: 0 0 6px; }

/* WHAT THE LIST IS, IN ONE FIELD UNDER THE NAME. It was two, a date and a
   room, laid out as a little grid of labels and answers: a form, on a page
   whose whole point is that there is nothing to fill in. What is here now is
   a line of writing, so it is drawn the way the name above it is drawn, as
   words on the page rather than as a box to complete.

   AND THE AIR IS UNDER IT, NOT OVER IT. It had none of its own over it and
   four pixels under it, which put it in the middle of the band the bar leaves
   over every page (see #app) and then dropped the first song of the list
   straight onto it. It is the second line of a name that is in the bar: it
   belongs up against what it is about, and the songs below are a different
   thing and want saying so. So ten of the band is taken back and spent on the
   other side of the line. */
.pl-meta { margin: -10px 0 16px; max-width: 640px; }
.pl-said:empty { display: none; }
/* what the field above holds, as plain words, kept back for the printer. The
   lines it was typed on are lines it keeps: a description of three things on
   three lines prints as three lines. */
.on-paper { display: none; }
.pl-said { white-space: pre-line; }

/* What the save button on the song page says by appearing and disappearing.
   There is no button here (every change writes itself), so the word carries
   it alone. */
/* Where the writing got to. In the top bar on a song, beside the ways back,
   because it is about the page rather than about the song; on a playlist it is
   all that a toolbar left behind, so it stands on its own line there. */
.save-state { font-size: 13px; font-weight: 600; color: var(--ink-soft); white-space: nowrap; }
/* on the playlist it is the whole of what a toolbar left behind, so it stands
   on its own line rather than at the end of a row of controls */
.pl-state { display: block; margin: 6px 0 18px; }
/* And it is empty unless a write failed, which is the only thing it has left
   to say (see note): an empty line still spends its margins, so it goes. */
.pl-state:empty { display: none; }
.save-state.is-bad { color: var(--danger); }

/* --- THE SONGS, AND THEY ARE THE WALL THE LIBRARY IS ------------------------
   This was a column of ribbons: one row per song, each the full width of the
   window, each holding a name and two short lines at one end and a hand's
   width of nothing across the middle. A song in a list looked nothing like the
   same song on the shelf it came from, and the two halves of the app read as
   two apps.

   So it is the same wall, in the same columns, at the same width (see .list).
   The card is the same card: white, a hairline round it, the shadow under it,
   the name over the people over the shapes. What it carries that the library's
   does not is the number it stands at and the two tools that move it and take
   it out.

   COLUMNS AND NOT A GRID, for the reason the library gives at length: a grid
   puts its rows in step, so every card in a row is the height of the tallest
   in it, and a song with no chords is either stretched or followed by a hole.
   Columns have no rows.

   An ol either way, so the numbers are the browser's own counter: a drag moves
   one card and never redraws the list, and a number written by hand would have
   to be rewritten by hand too. */
.set {
  list-style: none; counter-reset: song; margin: 0 0 18px; padding: 0;
  columns: auto 340px; column-gap: 12px;
}
/* A card is never split down the middle of itself by a column ending, and it
   carries its own space underneath: in a column layout there is no gap
   property to do it (see .list li). */
.set-row {
  counter-increment: song;
  break-inside: avoid; margin-bottom: 12px;
  display: flex; align-items: flex-start; gap: 12px;
  /* a song in a playlist is a card like a song in the library (see .list a) */
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 18px; transition: border-color .15s, transform .15s;
  /* THE WHOLE CARD IS THE HANDLE (see the move in renderPlaylist), and a card
     being dragged with a mouse would otherwise take the words on it with it:
     a press that travels across text is the browser selecting the text, and
     the move would come with half a song title painted blue behind it. And on
     a phone the same press held over the name is the browser offering to open
     the link somewhere else, which is a panel arriving in the middle of a
     move. */
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
/* AND IT LIFTS UNDER A POINTER, the way the library's card does, because it is
   the same card and a press on it goes to the same place. Lit off the part of
   it that is the way in and not off the whole: the corner holds a wastebasket
   and a play button, and a card that offers to open while the hand is on the
   wastebasket is a card saying the wrong thing.

   Only where there is a pointer to say it with. A touch screen fakes a hover
   on the last thing tapped and leaves it there, which reads as a card that
   stayed selected after a press that was never about the card (see .list a). */
@media (hover: hover) {
  .set-row:has(.set-main.is-way:hover) {
    border-color: var(--accent); transform: translateY(-1px);
  }
}
/* The number is the card's, not the row's: it stands at the top beside the
   name rather than in the middle of a card whose height it knows nothing
   about.

   And it is the SIZE of the name, which it was not on the ribbon this used to
   be: two pieces of text on one line, at two sizes and two line heights, do
   not sit on the same line, they sit a pixel and a half apart, and on a wall
   of cards that is a column of numbers that all look mispositioned. Same size,
   same line box, and what keeps it quiet is the grey. */
.set-row::before {
  content: counter(song) ".";
  flex: none; min-width: 2ch;
  font-weight: 700; font-size: 17px; color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
/* A CARD BEING CARRIED, AND IT HAS TO SAY SO PLAINLY. On a phone the move
   begins with a third of a second of holding still, and a card that looks
   exactly as it did afterwards is a gesture that gave no answer: the hand does
   not know whether to move yet. So it lifts off the wall and pales, and the
   wall under the hand says the same thing with the cursor. */
.set-row.is-moving {
  opacity: .55; border-color: var(--accent); transform: translateY(-2px) scale(1.01);
}
.set.is-moving { cursor: grabbing; }
/* the song was deleted from the library after it was put in the playlist */
.set-row.is-gone { border-style: dashed; color: var(--ink-soft); }

/* --- AND THE SAME WALL, WHILE THE BOX IS BEING TYPED IN ---------------------
   Words in the box turn this wall into the library narrowed to them (see
   state.sift in renderPlaylist), so every card here is a song that MIGHT go in
   the list rather than one that is in it. Same card, same width, same column:
   what changes is what the corner offers and what the number means.

   The counter goes, because it counts cards on this wall and the number a card
   wants to show is its place in the PLAYLIST. That one is written in (see
   .set-n), and the cards that are not in the list show none. */
.set-row.is-pick::before { content: none; }
.set-n {
  flex: none; min-width: 2ch;
  font-weight: 700; font-size: 17px; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* The whole card is the press, so the whole card says so: the hand over any
   part of it and the same lift the cards below give a pointer. The name is not
   lit, because it is not a way to the song here. */
.set-row.is-pick { cursor: pointer; }
@media (hover: hover) {
  .set-row.is-pick:hover { border-color: var(--accent); transform: translateY(-1px); }
}
/* ALREADY IN THE LIST, AND IT HAS TO BE READABLE AT A GLANCE: a shelf where
   the songs already chosen look like the ones that are not is a shelf somebody
   picks the same song off twice. A tint, its number in accent ink, and the
   word in the corner, which is what the eye lands on last and confirms with. */
.set-row.is-pick.is-in { background: #eef5f4; border-color: #cfe1de; }

/* --- THE ROW THAT ASKS WHAT ELSE BELONGS ON THE LIST ----------------------
   A press, not a panel standing open: suggestions under every playlist would
   be a second wall of songs under the one wall somebody came here to read (see
   the row in renderPlaylist). So it is one quiet button at the foot of the
   list, and the chevron on it turns over when the wall behind it is open,
   which is how every drawer in this app says which way it is (see .read-turn).

   Aligned with the start of the cards above it rather than centred, because it
   is a thing to do to the list and not a full stop under it. */
.pl-more { margin: 0 0 14px; }
.pl-more[hidden] { display: none; }
.pl-turn { transition: transform .15s ease; }
.pl-more.is-on .pl-turn { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .pl-turn { transition: none; }
}
/* THE SAME WALL, ONE STEP BACK. It is the same cards at the same width in the
   same columns, because a song is a song wherever it is offered; what says
   these are not the list is that they stand under the button that asked for
   them, each carrying the line that says why it is here. */
.pl-suggest { margin-top: 2px; }
.pl-suggest[hidden] { display: none; }
/* WHY THIS CARD IS ON THE WALL. In the app's own colour rather than in the
   grey the credits are in: the credits are a fact about the song and this is
   the page speaking, and a reader has to be able to tell the two apart at a
   glance. A suggestion that cannot say where it came from is an opinion with
   nothing behind it (see suggestFor). */
.pl-why {
  margin-top: 4px; font-size: 13px; font-weight: 600; color: var(--accent-ink);
}

/* --- THE FAR CORNER OF THE CARD, which is where the library's keeps its own
   (see .list .side). The tools first, because they are what this page is for
   doing, and whatever there is to hear under them. */
.set-side {
  flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
}
.set-tools { display: flex; align-items: center; }

.set-main { flex: 1 1 auto; min-width: 0; }
.set-main .t-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
/* Who wrote it, on the line under the name, in the same ink and at the same
   two pixels the wall's cards hold it at (see .list .by). One song is one card
   wherever it is shown, and a playlist is the list of the same songs. */
.set-main .by { color: var(--ink-soft); font-size: 14px; }
.set-main .t-row + .by { margin-top: 2px; }
/* --- WHO IS SINGING THIS ONE ----------------------------------------------
   On a shared playlist only, under whoever wrote the song, because a card is
   read down: what it is, who made it, who is doing it tonight, then the shapes
   (see whoSings in app.js).

   Its own line and not beside the credits. The two are different kinds of
   fact, one about the song and one about this evening, and side by side at the
   same size they read as one list of people. */
.pl-by { margin-top: 6px; }
/* The same outlined chip a style is, because it is the same kind of small
   quiet word standing among the facts of a card (see .tag-style). What it has
   that a style has not is a press, so the reset comes first: `font` is a
   shorthand and this rule stands after .tag. */
.pl-who {
  display: inline-flex; align-items: center; gap: 5px;
  appearance: none; cursor: pointer; border: 0;
  font: inherit; font-size: 12px; font-weight: 600; line-height: 1.6;
  color: var(--ink-soft); background: none;
  box-shadow: inset 0 0 0 1px var(--line);
  border-radius: var(--corner); padding: 2px 10px;
}
.pl-who > svg { width: 13px; height: 13px; flex: none; }
.pl-who:hover { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
/* SOMEBODY IS SINGING IT, WHICH IS NOT THE SAME AS THE QUESTION BEING ASKED.
   Unnamed, the chip is an empty box inviting a press; named, it is a fact
   about the evening, and a list read at a glance has to say which of its songs
   are already handed out. Same shape, filled in. */
.pl-who.is-on {
  color: var(--state-ink); background: var(--state-soft); box-shadow: none;
}
.pl-who.is-on:hover { color: var(--state-ink); box-shadow: inset 0 0 0 1px var(--state-ink); }

.set-t { font-weight: 700; font-size: 17px; color: inherit; text-decoration: none; }
a.set-t:hover { color: var(--accent); text-decoration: underline; }
/* The whole card opens the song, not the name on it (see setRow), so the whole
   card says so: the hand over any part of it, and the name lighting up as if
   the pointer were on it, because that is where the press is going. */
.set-main.is-way { cursor: pointer; }
.set-main.is-way:hover .set-t { color: var(--accent); }

/* THERE WAS A .set-grip HERE, two short lines in the corner of every card and
   the only place a card could be dragged from. The card is the handle now, all
   of it, so there is nothing left to draw: the picture of the gesture stood
   next to the gesture and took a thumb's width out of every row to do it. What
   is left of it is a class on the card while it is travelling, two rules up. */

/* THERE WAS A .pool HERE: the library, as a panel nailed to the foot of every
   playlist. A heading, a sentence explaining itself, a second search field and
   the whole shelf under it, open on a page of three songs whether or not
   anybody was adding one, and the playlist above it pushed up the screen by it.

   It is the box in the bar now, which is the field this app already searches
   songs in and which costs the page nothing while it is shut (see state.pick).
   What is left of the panel is two lines further up this file: a mark on the
   end of a result saying whether that song is already in the playlist. */

/* --- song page ---------------------------------------------------------- */

/* Nothing in here is on the screen any more: the name is in the bar and the
   facts are on the strip, and what is left is the heading paper needs. */
.song-head { margin: 0; }
/* The name, and at the far end of its own line whatever the song says about
   itself. Under the title those two words cost a line of the page, and on a
   phone the page is the song. Baseline-aligned, so the label sits on the name
   rather than in the air over it. */
.head-top { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.head-top h1 { flex: 1 1 auto; min-width: 0; }
.song-head h1 { margin: 0; font-size: 30px; letter-spacing: -.02em; outline: none; }
.song-head .by { color: var(--ink-soft); margin-top: 2px; }
/* What the reading could not finish. On the song and not instead of it, so it
   reads as a note about the page rather than as the page's subject. */
.song-note {
  margin: 0 0 14px; padding: 9px 14px; border-radius: var(--radius);
  background: var(--note); border: 1px solid var(--note-line);
  color: var(--ink-soft); font-size: 14px;
}

/* A VERSION OF THE SONG RATHER THAN THE SONG. Everything under this band looks
   exactly like the song and is not it, so the band says so and the two things
   worth doing about it sit inside the sentence that explains them: the answer
   to a label belongs next to the label.

   The same warm colour as the note above, because both are the page talking
   about what is under it rather than being it.

   These rules were a band saying "a machine read this and nobody has checked
   it", which the status chip says now, in one word, in the top bar. */
.past-band {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 14px; padding: 8px 10px 8px 14px; border-radius: var(--radius);
  background: var(--note); border: 1px solid var(--note-line);
  font-size: 14px;
}
.past-said { color: var(--ink-soft); flex: 1 1 240px; }
/* ONE SHAPE AND ONE COLOUR, AND THE WORD SAYS WHICH STATE IT IS. The same pale
   green on the tag, on the tally counting them and on the row inside the song
   that sets them, which is why the pair is named once at the top of this file:
   what the colour says is "this is where the song is in its life", and what it
   is, is written on it in a word. */
.tag, .review-tag {
  font-size: 12px; font-weight: 700; line-height: 1.6;
  border-radius: var(--corner); padding: 1px 10px; white-space: nowrap;
}
.review-tag, .tag-imported, .tag-offer, .tag-review, .tag-draft, .tag-published {
  color: var(--state-ink); background: var(--state-soft);
}
/* The number a shelf or a person holds, and nothing but the number: what it
   counts is the songs, which is what every card in the app is made of, so the
   word for it was the same word on every card in the band (see countTag).

   AND IT IS GREY, WHICH IS THE ONE THING IT IS NOT. The green on the chips
   above says "this is where a song is in its life", and it is worth its ink
   because it marks the few cards that are not like the rest. A count is on
   EVERY card in the band, it is news about none of them, and in that green it
   was a row of labels shouting the ordinary. Grey is the same shape saying the
   same number quietly, and it is the ink the app already writes a number in
   beside a name (see .dupe).

   Centred in its own line rather than sitting on the baseline of the name,
   because a chip has a box around it and a box lined up by the letters inside
   it reads as having slipped. */
.tag-count {
  color: var(--ink-soft); background: var(--line);
  align-self: center; font-variant-numeric: tabular-nums;
}

/* --- WHAT KIND OF THING THIS IS -------------------------------------------
   The four above say what state a song is in. These say what a thing IS: a
   song, a person who wrote one, a playlist it was sung at. One box searches
   all of them now, so a row of results is a row of three different kinds of
   thing, and without a word on each the list is a list of names with no way
   to tell which page a press would open.

   Deliberately quieter than the states. A state is news about a song and a
   kind is not: it is what the row already looks like, said in a word for the
   one glance where the look is not enough. */
.tag-kind { color: var(--ink-soft); background: var(--bg); box-shadow: inset 0 0 0 1px var(--line); }
/* Who wrote the words is a state of a kind: it is what this person is to the
   songs under their name, so it wears the one colour the app says that in. The
   tune is the chords' own red, because that is what a tune is here. */
.tag-words { color: var(--state-ink); background: var(--state-soft); }
.tag-tune { color: var(--chord); background: var(--chord-soft); }

/* WHAT KIND OF SONG IT IS, which is not one of the four states and does not
   wear one of their colours. It is a fact about the music, so it is quiet and
   outlined: on a row it sits beside who wrote the song, where the other facts
   about the song are, and the far column stays the column of states. */
.tag-style {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--ink-soft); background: none;
  box-shadow: inset 0 0 0 1px var(--line); font-weight: 600;
}
.tag-x {
  appearance: none; cursor: pointer; border: 0; background: none; padding: 0 0 0 1px;
  font: inherit; font-size: 14px; line-height: 1; color: var(--ink-soft);
}
.tag-x:hover { color: var(--danger); }

/* One list of a song's, being written. The word, what it already says, and one
   more chip that adds to it.

   THE WHOLE FORM IS THREE OF THESE. It was the styles alone, standing under two
   text fields that asked who wrote the words and who wrote the tune, and all
   three are lists: the words of a song are three people's as easily as one, and
   a field made them one person with commas in their name. So the row is the
   shape of every fact about a song that there can be several of. */
.kinds-field {
  display: flex; align-items: baseline; gap: 8px;
  min-width: 0;
}
/* WHAT IS ON THE ROW WRAPS, THE WORD IN FRONT OF IT DOES NOT. The row used to
   be one flex line of all three, so the second style a song was given pushed
   "סגנון" onto a line of its own and the row stopped matching the two above
   it. The styles and the field that adds one wrap between themselves instead,
   inside the room the word leaves them. */
.kinds-body {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px;
}
.kinds-list { display: flex; flex-wrap: wrap; gap: 6px; }
/* A width in ems and not `auto`. A field is `width: 100%` everywhere in this
   app, and a flex item asked for an automatic basis takes its width property
   as that basis: eight ems of room asked for the whole row and went to a line
   of its own the moment the song had one style on it. */
.song-meta .kinds-field input[type="text"] {
  flex: 1 1 8em; min-width: 0;
  margin-top: 0; padding: 4px 2px; border-radius: 0;
  background: none; border: 0; border-bottom: 1px solid var(--accent);
}
/* ONE MORE OF THESE, DRAWN AS ONE OF THESE. The way to add a style is the same
   chip its result will be, with a plus where the name goes: what a press makes
   is one more of the things standing beside it. It was a field standing open
   with grey words in it, which is a second shape on a row of chips and a line
   under empty space on a song that may already have every style it needs.

   The field is what the press opens, in its place, so the row never holds both
   and nothing on it moves but the one thing that changed.

   It IS a .tag-style, so the ring, the corner and the quiet are already its. What
   is left here is the difference between a word and a button: it is pressable,
   it is one character wide, and it answers the pointer. */
.tag-add {
  appearance: none; cursor: pointer; border: 0; font: inherit;
  font-size: 13px; font-weight: 700; line-height: 1.5;
  padding-inline: 9px;
}
.tag-add:hover { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
/* A chip is displayed inline-flex, which is a display of its own and therefore
   beats the browser's own rule for a hidden element. Said here, or the plus
   stands beside the field it was replaced by. */
.tag-add[hidden] { display: none; }

/* Who wrote it and what kind of song it is, on the song itself: there is no
   other page to keep them on any more. Three fields, and all three of them are
   filled in once and read at a glance for the rest of the song's life.

   IT IS NOT ON THE PAGE AT ALL. A form is what you want for the ten seconds
   you are typing into it and never again, so it lives in a panel over the
   page (see the song's own dialog) and the page under it does not move while
   it is open. What stands in its place is .song-info, one button in the bar
   that opens it and says what is inside it when it is hovered.

   ONE FIELD UNDER THE NEXT, because the panel is the width of a form and not
   the width of a screen: three fields in a row across a desk put "מילים" and
   the line it belongs to half a metre apart.

   AND ALL THREE ARE THE SAME ROW NOW. Two of them were a label and a text
   field, which is a form saying a song has one writer, and the third was
   chips. They are three .kinds-field rows: a word, what has been said already
   standing as chips, and a plus that adds one more. */
.song-meta { display: grid; gap: 18px; }

/* ONE COLUMN FOR THE THREE WORDS, so the three fields start where each other
   starts. They were each as wide as their own word, which put "מילים" and
   "לחן" a syllable apart and the two names that follow them a syllable apart
   as well: a form of three lines with three different left edges reads as
   three unrelated things.

   THE WORD ALONE. Each of them carried the little picture that stands in for
   it where there is no room for the word: a pen, a note, a tag. Where the word
   itself is written out, the picture beside it is a picture of the word, and
   three of them down the side of a panel of three fields is a column of
   decoration in the one place there was never a shortage of room. */
.meta-word {
  flex: none; width: 4.8em; white-space: nowrap;
  font-size: 13px; font-weight: 600; color: var(--ink-soft);
}
/* THE NAME IS BIGGER THAN THE WORD IN FRONT OF IT. Both were thirteen pixels,
   the size a label wants, which made what somebody typed as quiet as the
   heading over it. What is typed is the content of the form and the word is
   the question, so the answer is the one set at reading size. */
.song-meta input[type="text"] { font-size: 15px; }
/* The browser's own arrow, which appears at the far end of a field that has a
   datalist behind it: a solid black triangle, floating half a panel away from
   the word it belongs to, in a form that has nothing else sharp in it. The
   suggestions are not lost with it. They still drop as soon as a letter is
   typed, which is when anybody wants them.
   Two names for the same button, because Chrome has called it both. */
.song-meta input::-webkit-calendar-picker-indicator,
.song-meta input::-webkit-list-button {
  display: none !important; opacity: 0; width: 0;
}

/* The head of a song and the head of a playlist are written, not filled in.
   The title above them is a bare line of text with no box around it, and a
   boxed field under it would say that the two are different kinds of thing when
   they are the same kind of thing. So the box goes and a rule stays: a line
   under the words is the whole of the invitation to type on them, which is what
   a line on paper has always been.

   Two selectors deep on purpose. The shared field rule is an attribute
   selector, so it outranks a single class and would put the border, the white
   fill and the padding straight back. */
/* And so is the line that says what the list is. Same page, same hand, and
   the field is a line to READ on a list that has been made: the writing was
   the ten seconds it took. So at rest it is words, and the rule arrives under
   the pointer and stays while the field is being typed in, which is exactly
   when there is a field.

   No label over it. A word saying "תיאור" over the one box on the page would
   be a form growing back a row at a time; what the box is for is said by the
   words already in it, or by the placeholder while there are none. */
.song-meta input[type="text"],
.pl-meta textarea {
  margin-top: 0; padding: 4px 2px; border-radius: 0;
  background: none; border: 0;
  border-bottom: 1px solid transparent;
}
/* It wraps rather than scrolling, and it grows a line at a time to whatever
   was typed into it (see fitSaid): a description is as long as somebody felt
   like making it, and a field that hides its own second line is a field you
   cannot read back. */
.pl-meta textarea {
  display: block; width: 100%;
  resize: none; overflow: hidden; line-height: 1.5;
  font-size: 15px; color: var(--ink-soft);
  white-space: pre-wrap; overflow-wrap: break-word;
}
.pl-meta textarea:hover { border-bottom-color: var(--line); }
/* The focus ring would be a box again, which is the one shape this field is
   trying not to be. The line answers instead, in the accent and a pixel
   heavier, and the weight is a shadow rather than a border so that nothing on
   the row moves when it arrives. */
.pl-meta textarea:focus-visible {
  outline: none;
  border-bottom-color: var(--accent); box-shadow: 0 1px 0 var(--accent);
}
/* The line is what a field in this app answers a focus with; the ring the
   browser would draw is the box these fields are trying not to be. */
.song-meta input:focus-visible { outline: none; }

/* THERE WAS A .status-chip HERE, the one word saying what state the song is
   in, standing in the bar beside its name. The bar is the narrowest thing on
   the page and that was the one word in it nobody pressed. The word is on the
   row that opens the editor now, in the panel behind the three dots, and what
   is left up here is nothing at all: a song that is not published is open for
   writing, and the same row in the same panel publishes it (see songRows). */

/* Where the writing got to, in place of the button that used to ask for it.
   Quiet: it is the answer to a question nobody has asked out loud, and it is
   read at a glance or not at all. */
/* "Not finished", in the author's own words. One word about the whole song,
   and it is either on or it is not: pressed, it looks like the label it puts
   on the row in the library.

   There was a direction button beside it, shaped the same way. The direction
   belongs to a line now, and it is chosen down in the sheet on the lines it is
   about. */
.draft-btn {
  flex: none; appearance: none; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 700;
  color: var(--ink-soft); background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--corner);
  padding: 4px 13px;
}
.draft-btn:hover { color: var(--ink); border-color: var(--ink-soft); }
.draft-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Pressed, each looks like the label it puts on the row: the button, the tag
   and the tally are three drawings of one fact. */
.draft-btn.is-on { color: var(--draft-ink); background: var(--draft-soft); border-color: currentColor; }
.pub-btn.is-on { color: var(--published-ink); background: var(--published-soft); border-color: currentColor; }

/* Two gaps, and the difference between them is what says where one control ends
   and the next begins: the parts of a control sit close enough to read as one
   thing, and the room is spent between the controls instead. */
/* --- THERE IS NO STRIP OVER THE SONG --------------------------------------
   There were three rows here: who wrote it, what kind of song it is, and the
   three dials. They became one, and then that one emptied out too. The dials
   went up beside the name and the credits became the second line of it (see
   placeControls); the wastebasket, the versions, the way to publish and the
   ways back are rows in the panel behind the three dots (see songRows), which
   is one corner on every width rather than a band across the top of every
   song. Nothing is left to draw, on a phone or anywhere else, so the song
   begins directly under the bar and the bar keeps its own bottom line. */

/* --- AND WHO WROTE IT, BESIDE THE NAME ------------------------------------
   Its own place in the bar, between the name of the song and the search. It
   was at the far end with the dials, where it was the one line of text in a
   row of controls and half a bar away from the name it is about.

   ONE LINE, AND WHOLE NAMES ON IT. It is not given a width to fit inside and
   it does not shrink: a name cut to "ת…" is a name nobody can read, and two of
   them are two things nobody can read taking the room they were cut to save.
   What gives way instead is the search box beside it, which is a field and
   loses nothing by being narrower. Empty on every page but a song, and an
   empty box still spends the row's gap, so it goes when it is empty. */
/* Nothing of the SONG'S stands here any more: who wrote it is the line under
   its name (see .top-under) and what state it is in is a dot on the three dots
   (see .more-news). What the slot holds now is what a page has to say about
   itself in a word or a number, which so far is one page and one number: what
   the readings cost (see .top-bill). Empty, it takes nothing. */
.top-facts {
  flex: none; display: flex; align-items: center; gap: 8px;
  margin-inline-start: -10px;
}
.top-facts:empty { display: none; }

/* --- THE SECOND LINE OF THE TITLE ------------------------------------------
   Who wrote the song, under its name and smaller than it, which is exactly
   what a card in the library says and where anybody looks for it. It was a
   line like this once, with a little pen and a little note standing in for the
   words the room would not fit; the pictures are what made it unreadable, and
   what is here now is the people, in their own names.

   It shrinks with the name above it rather than pushing anything: a bar that
   grew a second line of its own would take that line off the top of every
   song. Empty on all but two pages, and empty is nothing: the other is the
   bill, where what stands here is what the total up beside the name is made
   of (see viewReads). */
.top-under {
  max-width: 100%;
  font-size: 12px; line-height: 1.25; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.top-under:empty { display: none; }

/* --- AND THE DOT ON THE ROW IT IS ABOUT ------------------------------------
   A song that is not published looks exactly like one that is. It is the same
   page, the same words, the same green everywhere: nothing on the screen says
   that nobody else can see this, and the one row that would say so is behind a
   button nobody has a reason to press.

   So the button says there is something in it (see .more-news), and the same
   dot stands again on the row it is about, so that pressing the button leads
   the eye straight to the thing the dot was for. What it MEANS takes a word,
   and the bar has nowhere to put one; the word is on the row, which is where
   the dot goes.

   AT THE END OF THE LINE, because a row in the panel is a line of text across
   the whole width and its top corner is half a panel away from the word it
   would be marking. Where reading it leaves you, and with no ring around it:
   there is nothing underneath here for it to be lifted off. */
.has-news { position: relative; }
.has-news::after {
  content: ""; position: absolute;
  top: 50%; inset-inline-end: 12px; margin-top: -3px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--state-mark);
}
/* and on the row under the pointer, which fills with the app's green, the dot
   goes white: a yellow mark on a green fill is the one thing on the row that
   would have to be looked for */
.print-menu .btn.has-news.is-on::after { background: #fff; }

/* --- ONE SLOT BESIDE THE DOTS, FOR WHATEVER THE BUTTON HAS TO SAY ----------
   What is behind these dots is a panel, and a shut panel says nothing: a song
   of yours that nobody else can see yet, details somebody has offered, or
   simply recordings, all of them found only by opening it and looking. So the
   button says which, in one place, beside the dots (see songMore, which puts
   exactly one mark in here at a time).

   INSIDE THE BUTTON AND NOT ON ITS CORNER, for either of them. They were both
   drawn on the corner for a while, in the language of the badge the record
   button wears (see .tape-new): a small thing hung half off the edge, because
   this app already had one way of saying "there is something in here". That
   language is a notification's, a thing that has just happened and is waiting
   on you, and it hangs off the corner because it belongs to no part of the
   button in particular. What is behind this one is not news. It is what is in
   here, which is what a picture on a button is for, so the mark steps inside
   and stands beside the dots as the second half of the label.

   And it costs nothing to read: a mark half off a corner has to be told apart
   from the edge it overlaps, and there is nothing here to tell it apart from.

   THE BUTTON GROWS TO HOLD IT, sideways only. It is a square while it holds
   one thing and a short row while it holds two, and the height never moves,
   because the row it stands in is a line of controls whose tops and bottoms
   are the thing holding the row together. */
.icon-btn.has-mark {
  width: auto; padding: 0 7px;
  display: inline-flex; align-items: center; gap: 5px;
}
/* Neither of them takes a press of its own, so a fingertip landing on one
   opens the panel like anywhere else on the button. */
.more-takes, .more-news, .more-yet { display: inline-flex; pointer-events: none; }

/* THE RECORDINGS, IN THE GREEN THEY ARE COUNTED IN ON A CARD (see
   .when.has-takes), which is the same fact about the same thing.

   THE SIZE OF THE PICTURE BESIDE IT, and it is not written here at all: it is
   an icon inside an icon button and takes the size every icon in one takes
   (see .icon-btn svg). It was drawn smaller for a while, on the thought that
   the dots are what the button does and this is only what it happens to hold,
   and a shape that small beside a full-sized one reads as a leftover of the
   badge it used to be rather than as the other half of the label. Two pictures
   on one button are two pictures. */
.more-takes { color: var(--accent); }

/* AND THE STATE, WHICH IS A DOT AND NOT A PICTURE. It is the one mark here
   that is about the song rather than about what is inside the panel, and it
   has no picture to be: "not published" is a state, and a state is a colour in
   this app (see the states at the top of this file). The same yellow the
   library writes it in on the card, and the same dot again on the row that
   publishes (see .has-news), so the two are one sentence read in two presses.

   Smaller than the picture beside it, because it is not one: a nine pixel
   circle standing as tall as the dots would be a third dot in a column of
   three. It keeps the height of the row it is in without claiming to be
   drawn. */
.more-news {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--state-mark);
}

/* AND THE ONE THAT IS BOTH: a recording of this song that is on the device and
   has not been published (see draftRow). The play shape, because what is
   behind the dots is a recording; the yellow of the state, because what is
   true of it is that nobody else can hear it yet. Read together it is one
   sentence, and it is the mark that wins wherever it is there (see songMore),
   since it is the only one of the three that is waiting on a decision nobody
   has made yet. */
.more-yet { color: var(--state-mark); }

/* THREE CONTROLS, AND NOTHING DRAWN ROUND THEM. Each of them is already a box
   with a line round it, and a fourth line round all three is a box inside a box
   on a row that is itself inside a bordered strip. What holds them together is
   that they stand together, which they do without being fenced in.

   The element itself stays: it is what placeControls hands to the bar in one
   line. It is a group now and not a surface.

   It used to pull itself to the far end of whatever row it was on, from when
   that row was the strip and it was alone there. It stands in the bar now, on
   every width, at the end nearest the name of the song it is about, and there
   is nothing left for it to be at the end of. */
/* AND IT DOES NOT WRAP. It could, on the strip: a row of its own with nothing
   else on it had room to become two. In the bar the row is shared, and a group
   that folds in half there does not take a second line of its own, it makes
   the whole bar taller and leaves the capo standing above the microphone. What
   gives way instead is the name of the song, which is built to be cut (see
   .top-where). */
.tools {
  display: flex; align-items: center; gap: 4px 8px; flex: none;
}
.tools .ctl { display: flex; align-items: center; gap: 5px; }
/* The picture and the number side by side, read in that order: what it is,
   and what it is at. */
.tools .dial { display: flex; align-items: center; gap: 4px; line-height: 1; }
/* --- A CONTROL THAT IS ITS OWN BUTTON --------------------------------------
   Both dials fold: the picture and the value are what you press, and what it
   could be comes out under them. So the pair has to LOOK pressable, which the
   two loose spans it used to be did not, and it is drawn as one box with a
   line round it. Open, it is lit like everything else in this app that has a
   panel hanging off it.

   AND IT IS THE HEIGHT OF THE BUTTONS BESIDE IT. It was twenty two, from when
   it stood on a strip of its own among other dials and the row was sized to
   it. It stands in the bar now, between the glass and the three dots (see
   placeControls), and a box two thirds the height of its neighbours reads as
   something that came from somewhere else. */
.tools .dial-btn {
  appearance: none; font: inherit; color: inherit; cursor: pointer;
  padding: 2px 6px; height: 30px; background: #fff;
  border: 1px solid var(--line); border-radius: var(--corner);
}
.tools .dial-btn:hover { background: var(--bg); }
.tools .dial-btn[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.tools .dial-btn[aria-expanded="true"] .lbl { color: inherit; }

/* --- AND WHAT COMES OUT OF IT ----------------------------------------------
   Under the dial, over everything, with the shadow that says it is standing
   off the page, the same as the offer under a word (see .gap-offer).

   NOT UNDER .tools. The panel is on the body while it is open, so a rule that
   only worked inside the strip would leave it there unstyled. */
.dial-pop {
  position: fixed; z-index: 50; padding: 4px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--corner);
  box-shadow: 0 2px 8px rgba(23, 32, 42, .12);
  /* A column of eight on a phone held sideways is taller than the glass, and a
     panel that runs off the bottom is a choice nobody can reach. */
  max-height: calc(100vh - 56px); overflow-y: auto;
}

/* --- TWO COLUMNS, SIDE BY SIDE ---------------------------------------------
   The frets and the keys are one panel now, because they were always one
   question (see fillPlay). Beside each other and not one under the other: the
   neck is eight rows tall and the keys are five, and stacked they are a
   column of thirteen that a phone has to be scrolled through. Side by side
   the panel is as tall as the taller of the two and both are on the screen at
   once, which is what lets the reader see that choosing a key moves the fret.

   The key is the first column, which right to left is the right hand one: it
   is the question the panel is opened with, and the fret beside it is the
   answer the app works out while the reader chooses. */
.play-pop { display: flex; align-items: flex-start; gap: 4px; }
.pop-part + .pop-part { border-inline-start: 1px solid var(--line); padding-inline-start: 4px; }
/* WHAT THE COLUMN IS, OVER IT, and the whole reason there is a head at all: a
   column of numbers beside a column of chords does not say by itself which of
   them is the capo.

   A PICTURE AND NOT A WORD. Each column is one short thing wide, four
   characters at the most, and a word over it is wider than everything it
   names: two labels were setting the width of the panel and the choices under
   them were sitting in the air they left. The pictures are the ones on the
   dial and in the app's own vocabulary, at the size of what they stand over.
   Quiet, because a head is a label and not a choice: what is pressed is
   underneath it. */
.pop-head {
  display: flex; justify-content: center; padding: 5px 0 7px; color: var(--ink-soft);
}
.pop-head svg { width: 15px; height: 15px; }

/* --- THE KEYS ON OFFER -----------------------------------------------------
   A few keys the song can be played in. As wide as the widest chord and no
   wider: each row used to carry the fret that key wanted at its other end,
   which is the column standing right beside this one, and the width that
   sentence needed stayed behind after it went (see keyRow).

   SO IT IS THE FRETS' COLUMN, in every measure that shows: same width, same
   height, same middle. Two columns of one short thing, read together, are one
   panel; two columns drawn to different rules are two panels that happen to
   touch.

   A row is a line of a menu and not a button on a toolbar, so it is drawn as
   one: no border and it lights under a finger. */
.play-pop .keys { display: flex; flex-direction: column; }
.key-opt {
  appearance: none; display: flex; align-items: center; justify-content: center;
  min-width: 52px; height: 32px; padding: 0 6px;
  font: inherit; white-space: nowrap;
  color: inherit; background: none; border: 0; border-radius: 6px; cursor: pointer;
}
.key-opt:hover { background: var(--bg); }
/* The chord in the ink chords are written in everywhere else in the app, so
   the list reads as a row of chords and not as a row of words. */
.key-opt .key-name {
  font-size: 15px; font-weight: 700; direction: ltr; color: var(--chord);
}
/* Where you already are. Painted rather than ticked: a mark in a column of its
   own is a column, and this list is two things wide already. */
.key-opt.is-on { background: var(--chord-soft); }

/* --- AND THE EIGHT FRETS ---------------------------------------------------
   ONE COLUMN, TOP TO BOTTOM, and not the four by two pad this was first drawn
   as. A pad is a keypad, and a keypad is for a number you already know: it is
   read by hunting for the one you came for. This is a neck. Eight frets in a
   row down the panel are the neck itself, in the order the neck is in, and the
   eye runs down them instead of across and back.

   Which is also the shape of the keys beside them, so the two panels are one
   thing learned once: a column of choices, the one you are at painted in. */
.frets { display: flex; flex-direction: column; }
.fret-opt {
  appearance: none; min-width: 52px; height: 32px; padding: 0;
  font: inherit; font-size: 15px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: inherit; background: none; border: 0; border-radius: 6px; cursor: pointer;
}
.fret-opt:hover { background: var(--bg); }
.fret-opt.is-on { color: #fff; background: var(--accent); }

/* A PICTURE NEEDS A SIZE. An svg with none is not small, it is whatever the
   box around it happens to allow, which in a flex row is nothing at all: the
   three pictures were in the page and none of them was on the screen. */
.tools .lbl { display: flex; color: var(--ink-soft); }
.tools .lbl svg { width: 15px; height: 15px; }
/* The capo's fret, and the only number left in the bar. It was given the width
   of two and a half digits, from when it stood on a strip with room to spare
   and a hole under a number that moved would have shown. There is no second
   digit: the neck stops at the seventh fret (see MAX_CAPO), so every value it
   can ever hold is one character wide, and the rest of that width was the box
   pushing the name of the song off the end of the bar. */
.tools .val {
  font-size: 14px; font-weight: 700; min-width: 1ch;
  text-align: center; direction: ltr; font-variant-numeric: tabular-nums;
}
/* A line never wraps by itself (white-space: pre on .ln-t), so a long line
   overflows and the whole sheet scrolls sideways. That is deliberate: the
   chord row and the word row have to move together, or a chord stops being
   over its syllable, and no wrapping the browser knows how to do would move
   them together.

   On a wide screen that is the end of it, and the scroll is never needed. On a
   phone the browser is not asked to wrap, but the song IS poured to the width
   of the screen, by flowSheet in app.js, which cuts each line and its chords
   together into rows that fit, fills a leftover row with the line after it,
   and marks both (see .ln.is-cont and .sp below).

   The generous side padding is not decoration. A chord is centred on its
   character, so one over the FIRST character sticks out half a label past the
   start of the line, and the alternative to room for it is nudging it inward,
   which would mean the sheet no longer shows what the song says. Wide enough
   for half of a long name like G#m7b5. */
.sheet {
  background: none;
  border: 0; border-radius: 0; box-shadow: none;
  padding: 22px 34px 30px; margin-bottom: 0;
  /* As wide as its columns need, in the middle of what is left. The width
     itself is written on the element by fitColumns, because it is a fact
     about this song at this size on this screen. */
  margin-inline: auto;
  /* --- THE SHEET IS THE WHOLE OF WHAT IS UNDER THE BAR ----------------------
     Even where the song stops halfway down it, and this is not about how it
     looks: the paper is white on white and nothing shows either way. It is
     about what the fingers land on.

     TWO FINGERS BELOW THE LAST LINE ARE TWO FINGERS ON THE SONG. The pinch
     that sets the reading size is taken by this element (see the touch
     handlers in app.js) and so is the promise not to let the browser zoom the
     page instead (see touch-action below). Where the sheet stopped with the
     words, everything under them was the body: a pinch there did nothing at
     all, or worse, did the browser's own zoom, which makes the words bigger
     and the screen no wider. On a phone, where most of a short song's screen
     is under the last line, that is most of the page.

     IN dvh AND NOT vh. A phone's vh is the tall viewport, the one with the
     address bar hidden, so vh minus the bar is taller than what is actually on
     the glass and the page scrolls by the height of the address bar with
     nothing in that strip. dvh is what is showing now. */
  min-height: calc(100dvh - 60px);
  overflow-x: auto;
  font-family: var(--song-font);
  /* The chord lane's height, said once: it is also where the words start,
     which is where a repeat bar starts (see .is-rep), and two rules holding
     the same number is how they come to disagree. Declared HERE and not on the
     root because this is the element --song-size is written on, and a var()
     resolved above it would be resolved against the default size and stay
     there whatever the reader picks. */
  --lane-h: calc(var(--song-size) * .61);
  --rep-gutter: calc(var(--song-size) * 1.15);
  /* TWO FINGERS ON THE SONG SET THE SONG'S SIZE, not the page's zoom (see the
     wheel and touch handlers in app.js). Panning is left alone, so the sheet
     still scrolls both ways; it is the pinch that is taken, and taken because
     the browser's answer to it is the wrong one here: zooming the page makes
     the words bigger and the screen no wider, and a chord sheet's lines never
     wrap. */
  touch-action: pan-x pan-y;
}

/* --- A SONG IN SCREENFULS -------------------------------------------------
   A page is the window under the header, and the columns stand on it. The
   next set of columns begins under that, the same height again, and is
   reached by scrolling: which is what a book does, and what somebody playing
   from a stand is doing when they scroll, taking the next page rather than
   the next inch.

   The lines are dealt out by hand (see pageUp in app.js) rather than left to
   the browser's own columns, and the reason is that a multicol BALANCES: it
   shares the whole song out between the columns it is given, so each one is
   as tall as a third of the song, and reading to the bottom of the first
   means scrolling through a third of it before starting again at the top.
   There is no way to ask a multicol for a row of columns that ends and
   another that begins.

   The segments divide the whole of the room between them (see planColumns), so
   what is left over at the two ends is width no line of this song would have
   used, and the page stands in the middle of it. */
.page {
  display: flex; align-items: flex-start;
  margin-inline: auto;
  /* Air at the two ends of the row of segments. The height below is the whole
     page INCLUDING this, and what is dealt into it is measured against what is
     left. PAGE_AIR in app.js is the same number, and it is spent once now:
     there was a card here that kept its own air inside its edges as well. */
  --page-air: 16px;
  padding: var(--page-air);
}

/* --- WHERE ONE SCREENFUL ENDS AND THE NEXT BEGINS -------------------------
   A hairline across the top of every page but the first. The air alone said
   it while each screenful was a row of cards on a desk, because a gap between
   two rows of cards is a gap between two rows of cards; with the cards gone it
   was two verses with a slightly wider space between them, at the one place in
   the song where the words do not run on.

   PAINTED AND NOT A BORDER. A border is a pixel of the box, and this box has
   its height written onto it in app.js to the fraction of a pixel: a border
   would take that pixel off the inside of every page and every screenful would
   sit a little higher than the one above it. */
.page + .page {
  background: linear-gradient(var(--line), var(--line)) top center / 100% 1px no-repeat;
}

/* --- A SEGMENT IS NOT A CARD ------------------------------------------------
   It was: white paper with a radius, a hairline round it and a shadow under
   it, lying on a grey desk. What that shape was for was saying where one
   segment ended and the next began, and it said it by making every segment a
   small object in the middle of a large screen. A song is not a wall of small
   objects, it is one page with the words laid out on it, and the reader is
   holding a guitar rather than browsing.

   So the paper is the whole page now (see body.on-song), and what says where a
   segment ends is a single hairline standing between them (see .rule). What is
   left here is the two things a segment does rather than looks like: it does
   not shrink below the width it was given, and it cuts off anything that hangs
   out past its edge. */
.col {
  min-width: 0; position: relative;
  /* A LINE WIDER THAN THE SEGMENT IS CUT OFF AT ITS EDGE. It happens while a
     line is being typed into and has not been broken again yet, and wherever a
     chord stands out past the end of the words. Over the desk it would be ink
     lying in the space that says a segment ended; over the next segment it
     would be one line of the song written inside another. */
  overflow: hidden;
}

/* --- AND THE DESK BETWEEN TWO OF THEM, WITH THE RULE DOWN ITS MIDDLE --------
   There were hairlines here once, one down each edge of every segment, and
   they went because a rule down the middle of an empty space is a rule drawn
   where the space is not saying anything on its own: they were half a wide
   gutter away from the words on either side, and the eye could not tell one
   from the space after a verse. Both of those are answered here. There is ONE
   rule between two segments rather than two, the desk it stands in is narrow
   (see CARD_GAP), and it runs the full height of the screenful rather than the
   height of whichever column happened to have the most in it.

   IT IS AN ELEMENT AND NOT A MARGIN, which is the whole trick: it stands in
   the row beside the segments, so stretching it is stretching a thing that is
   there, and the rule reaches the bottom of the page whether the words did or
   not. A line drawn from inside a segment would stop where that segment's
   words stopped, and a page ruled to a different height in every column has a
   ragged edge down it. */
.rule {
  flex: none; align-self: stretch;
  background: linear-gradient(var(--line), var(--line)) center / 1px 100% no-repeat;
}
/* The desk beside a slot a short last page never reached: it holds the width
   open so the pages above keep their shape, and it draws nothing, because a
   rule between nothing and nothing is a line down a blank half of a page. */
.rule.is-empty { background: none; }

/* --- a narrow screen -----------------------------------------------------
   620px is also where editing stops (see NARROW in app.js). Keep the two in
   step: below this width the song is read, not written.

   What a phone is short of is width, and every one of these gives some back.
   A song of short lines can still stand in two segments here, because how many
   there are is asked of the song rather than of the screen (see planColumns);
   what this says is only that the words run to both edges of the glass. */
@media (max-width: 620px) {
  /* At arm's length those twenty pixels are a word and a half of every line.
     The height stays as it is: the sheet is the whole of what is under the bar
     on every screen, and on this one most of all, because a pinch has to land
     on the song wherever the fingers go down (see .sheet). */
  .sheet { padding: 16px 22px 24px; }

  /* THE SEGMENT HERE IS THE GLASS. Air at the two ends of a page is worth
     nothing on something held at arm's length, and the words run from one edge
     of the screen to the other.

     AND NOTHING IS CUT OFF. Elsewhere what is beyond a segment is another
     segment, so a row that has outgrown its own is clipped at the edge; here
     what is beyond it is the edge of the screen, and a line too wide for it is
     meant to hang out and take the sheet's own sideways scroll with it (see
     .sheet). Clipped, those words are simply gone. */
  .page { padding-inline: 0; }
  .col { overflow: visible; }

  /* The strip used to be given the card's corner down here, because a pill
     stretched across the whole width of a phone reads as a lozenge rather than
     as a row of controls. It is the same corner as everything else now, at
     every width, so there is nothing left to correct. */
}

/* Where the capo goes, inside the sheet so it prints with the song: the shapes
   below it are useless to anyone who does not know. */
.capo-line {
  display: inline-block; margin-bottom: 14px;
  font-size: 14px; font-weight: 700; color: var(--chord);
  background: var(--chord-soft); border-radius: var(--corner); padding: 3px 12px;
}

/* --- a line, and the chords above it ------------------------------------
   .ln is the positioning context. .ln-t renders one span per character so a
   character index can be turned into a pixel offset; .ln-c is the same width
   and holds the chords, each one absolutely placed at the offset of the
   character it belongs to.

   Two details make right-to-left work:
     the inset is logical (inset-inline-start), so under dir="rtl" it is
     measured from the right edge, exactly where an RTL line starts;
     a chord carries dir="ltr" and its own bidi isolation, so "Am" and "G/B"
     never flip or reorder inside a Hebrew line. That flip is the thing that
     makes chord sheets in Word and Google Docs come out wrong.
   ------------------------------------------------------------------------ */

/* The chord row sits as close to the words as the glyphs allow: a chord that
   floats is a chord you have to look twice to attach to a syllable.

   The lane is deliberately shorter than the chord in it. A chord is absolutely
   positioned at the lane's top, so the difference hangs down into the space the
   text's own line height leaves empty above its letters, which costs nothing
   and closes the gap. */
/* The pair, chords and the words under them, is one thing on the page. So the
   air goes BETWEEN the pairs and not inside them: tight above the words, open
   below the line. */
/* --- WHAT COMES OUT WHEN A SONG IS COPIED --------------------------------
   The words, and only the words.

   Somebody dragging across a song and pressing copy wants the lyrics: to send
   them to whoever is singing, to search for the next verse, to paste them
   somewhere that has no idea what a chord is. What they were getting was every
   chord label interleaved with the syllables it sits over, because the labels
   are text in the same page and a selection takes everything in its path.

   So the chord lane cannot be selected at all, and neither can the gaps inside
   words: a gap is room on the screen, not a character of the song, and a word
   spelled out with them in it is not that word.

   Only where the song is being READ. In the editor a gap has to be reachable
   by the caret to be deleted, and it is the words themselves being worked on
   there rather than copied out. */
.chord, .ln-c { user-select: none; -webkit-user-select: none; }
.sheet:not(.ed) 
.ln-t .gap { user-select: none; -webkit-user-select: none; }

/* THE AIR BETWEEN ONE LINE AND THE NEXT, and it is the only air in a row: what
   is above the words is the chords' and belongs to them. It was .45 of an em,
   then .3, and it is a seventh of a song size now: about five pixels off every
   line of the song since this started, which is two lines more on a screenful
   and a good deal more than that on a phone. A song is not prose and is not
   read a paragraph at a time. It is read a line ahead, by somebody who wants
   as much of the next verse in front of them as will go.

   IN SONG SIZES AND NOT IN EM, which is the same correction .ln-c already
   carries below. An em here is the APP's sixteen pixels, because a row
   inherits the page's font and only .ln-t is set in the song's: as a fixed
   number of pixels this was the right gap at one size and at no other, wide
   enough to read as a blank line at the small end and gone altogether at the
   large. The space between two lines is a fact about the words, so it is
   measured in them. */
.ln { position: relative; margin-bottom: calc(var(--song-size) * .14); }
/* IN SONG SIZES, NOT IN EM. An em here is the APP's sixteen pixels, because
   the lane inherits the page's font and only .ln-t is set in the song's, so
   this was a fixed fifteen pixels at every size the song was ever read at.
   The chord in it scales (see .chord below), so the two only agreed at the
   one size the number was picked at: smaller, the lane stood taller than the
   chord and the chords floated away from the words; bigger, the chord grew
   out of the lane and came down on top of them.

   Kept SHORTER than the chord is tall, deliberately, and by a good deal: the
   difference hangs down into the space the text's own line height leaves
   empty above its letters. That space costs nothing, because it is there
   whether a chord uses it or not, and every bit of it the chord takes is a
   bit less air between the chord and the syllable it names. A chord that
   floats is a chord you have to look twice at to attach to a word.

   THE FLOOR ON IT IS THE LETTERS THEMSELVES, and this is near it. Measured
   rather than guessed: at .61 there is about six hundredths of a size between
   a chord's foot and the top of the letters' own ascent box, which at .58 was
   three, and three is a pixel at a reading size and nothing at all at a small
   one. The margin is not spare room, it is what a word carrying vowel points
   needs: a holam sits above the letter, and above that box. */
.ln-c { position: relative; height: var(--lane-h); }

/* --- AND ON A PHONE IT IS ALSO SOMETHING TO PRESS -------------------------
   The height above is the height a chord needs and not a pixel more, which is
   right everywhere the song is being read and wrong in the one place a lane is
   pressed. Eleven pixels is not a small target, it is not a target: measured
   with a real browser and a real finger, a tap on the strip lands in the words
   underneath, and so does a tap aimed to the pixel, because a phone snaps a
   tap to whatever near it is worth tapping and a line you can type into is
   worth more than a strip. Swept, the answer is fourteen: at twelve the middle
   of the lane starts winning the tap, and fourteen is that with something to
   spare.

   THE REACH GOES ABOVE THE CHORD AND NOT AROUND IT. The label is pushed down
   by exactly what the lane grew by, so it stands where it always stood, as
   close to the syllable as the glyphs allow. What grew is the empty air over
   it, which was the previous line's business and is now the way in to putting
   a chord down.

   The last three pixels, the ones against the letters, still go to the words,
   and they should: that close to a line, a tap is somebody reaching for the
   text.

   A TAIL ROW GETS ONE TOO. A piece of a long line carrying no chords has no
   lane at all while it is being read, which saves the space it would waste. On
   a phone nearly every line is poured into a head and a tail, so a tail with
   no lane is half the song with nowhere to put a chord. It costs the space
   here and it is worth it, in the editor and only there.
   ------------------------------------------------------------------------ */
@media (max-width: 620px) {
  .ed .ln-c,
  .ed .ln.is-cont.is-tight .ln-c { height: calc(var(--song-size) * .61 + 14px); }
  .ed .chord { top: 14px; }
}
.ln-t {
  white-space: pre;
  font-size: var(--song-size);
  /* Bold, because the words are what is being read from across a room with a
     guitar in your hands. */
  font-weight: 700;
  /* --- THE LEADING, AND IT IS WHERE THE AIR ACTUALLY WAS --------------------
     A row was measured at 39.4 pixels at a reading size, and only 2.5 of that
     was the space between rows. The rest of the air was in here: 1.55 of a
     size against letters about 16 pixels tall left six pixels of half leading
     ABOVE them and six more BELOW, on every line of every song, and shaving
     the margin between rows was cutting at the small half of the problem.

     The six above is not spare, and this is why the number moved rather than
     went: the chord hangs down out of its lane into exactly that space (see
     .ln-c), which is what keeps a chord attached to the syllable it names. So
     the leading came down and the two pixels the words used to be pulled up by
     went with it, and the chord's foot still stands where it stood, about a
     pixel into the letters' own box.

     WHAT IS GAINED IS THE HALF UNDER THE LETTERS, which is air nothing is
     using: it and the gap between rows (see .ln) are the same gap twice, and a
     song is read a line ahead by somebody who wants the next verse in front of
     them. A song comes out about a tenth shorter for it.

     THE FLOOR IS THE LETTERS THEMSELVES, and vowel points sit above them: a
     holam is drawn above the letter and above that box. This is measured, not
     guessed, and it is near that floor. */
  line-height: 1.3;
  min-height: 1.3em;
}

/* left / right are written by layoutLine, never here, and never as a logical
   inset: this element is dir="ltr" so a logical inset would resolve against
   ITS direction, not the line's. It also carries no horizontal padding or
   margin, so the box it occupies is exactly the glyphs and the measured
   distance needs no compensation. */
.chord {
  position: absolute; top: 0;
  direction: ltr; unicode-bidi: isolate;
  font-family: var(--chord-font);
  color: var(--chord); font-weight: 700;
  font-size: calc(var(--song-size) * .82);
  line-height: 1;
  white-space: pre;
}

/* The tick under a chord, the way a printed sheet marks one, and it points at
   the chord's ANCHOR: the exact character it names, which on a right to left
   line is the label's right edge and on a left to right one its left.

   Not decoration. It is the one place on the page where the thing this whole
   app is about, which letter a chord falls on, is drawn rather than implied,
   and the label alone cannot say it: "Am" is wider than two Hebrew letters, so
   without the tick you cannot tell which of them it means. A chord over a
   space has its tick over that space, and that is how you can see that it is.

   A pseudo element, so it adds nothing to the chord's box and nothing to the
   measuring. */
.chord::after {
  content: "";
  /* Under the MIDDLE of the label, because the label is placed with its middle
     on the character it names (see layoutLine). So the tick and the chord mark
     the same point, and the eye lines the whole label up with the letter.

     Pulled up into the label's own descender space so it touches the letters,
     and short, so what is left over is the gap down to the words. */
  position: absolute; top: calc(100% - 4px); left: 50%;
  width: 1.5px; height: .3em;
  background: currentColor; border-radius: 1px;
  transform: translateX(-50%) rotate(16deg); transform-origin: top center;
}

.ln.is-section { margin: 22px 0 4px; }
.ln.is-section:first-child { margin-top: 0; }
.ln-section {
  font-weight: 800; font-size: calc(var(--song-size) * .82);
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-soft);
}
/* --- what did not fit on the screen --------------------------------------
   .is-cont is a row that BEGINS with the leftover of the line above it (see
   flowSheet in app.js, which is where the width is decided).

   IT IS NOT INDENTED, AND THE SPACE MOVED TO THE OTHER END. An indent said
   "this is the end of the line above" by starting the words somewhere else,
   and it cost the words that came down the one thing they wanted, which is to
   begin where every other line begins: a word pushed in from the margin is a
   word the eye has to go and find. So the rows all start together, and what
   says where one line of the song ended is a gap under the last of its rows,
   twice the air between two rows of the same line.

   Which is the same fact told the other way about, and told where it is
   cheaper: a reader going down the page needs to know where the NEXT line
   starts, not where the last one is still going. */
.ln.has-cont { margin-bottom: 0; }
.ln.is-cont.is-tight .ln-c { height: 0; }
/* The last row of a broken line, with the next line of the song under it. */
.ln.is-cont.is-last { margin-bottom: 1.35em; }

/* --- TWO LINES OF THE SONG ON ONE LINE OF THE PAGE -------------------------
   The last row of a broken line is usually one word on an otherwise empty
   row, so the next line of the song starts on that row rather than under it
   (see flowSheet). What stands between them is .ln-sep: the artificial spaces
   the format already has, carrying the mark that says a new line begins here.

   TWO ROWS AND NOT ONE ROW HOLDING TWO. A single row would be two lines of the
   song at once: one caret for both, one lane of chords over both, and a copy
   that ran them together. Side by side, each row is one line of the song, with
   its own chords over its own characters and its own place in the song.

   ON THE BASELINE, because that is the line the two of them actually share.
   Aligning their tops would hang one line's words lower than the other's
   wherever the two rows have different lanes over them, a row with chords
   beside a row without.

   The air under the shared line is on the pair and not on either row: what it
   says is where the LAST line on it ended, which is what the row underneath
   follows on from. */
.ln-row { display: flex; align-items: baseline; margin-bottom: .45em; }
.ln-row > .ln { margin-bottom: 0; }
/* AND THE ROW THAT ENDED A LINE KEEPS NO AIR EITHER, which the rule above
   says and was not winning. The air under the last row of a broken line
   (see .ln.is-cont.is-last) is written with one class more than that rule has,
   so inside a pair it stood: and inside a pair it is not air under anything.
   The items here are aligned on the baseline, so a margin under one of them is
   not a gap after the line, it is depth added to the flex line itself, and the
   pair came out twenty pixels taller than the words in it. A blank strip
   under two lines that had already ended, and a wider one than the space
   between two verses.

   The pair is what says where the shared line ends (the two rules under this
   one), and it was saying it as well: the same air, once inside the box and
   once after it. */
.ln-row > .ln.is-cont.is-last { margin-bottom: 0; }
.ln-row.has-cont { margin-bottom: 0; }
.ln-row.is-last { margin-bottom: 1.35em; }
/* Neither of them gives way: what fits on this line was worked out in pixels
   before the rows were built, and a row squeezed narrower than its words is a
   row whose last word is drawn over the segment beside it. */
.ln-row > .ln, .ln-row > .ln-sep { flex: none; }
/* It is not part of either line, so it is not part of anything taken off the
   page: a drag across the two rows selects the words of both and not the room
   between them. */
.ln-sep { user-select: none; -webkit-user-select: none; cursor: default; }

/* Room between two letters of a word that must not be broken. The character is
   there, it is one of the line's own and a chord can sit on it; what it is not
   is ink. A space's worth of width, given here rather than left to the font,
   because the codepoint is a private-use one and what a font draws for one of
   those is a box, if it draws anything. */
/* The character itself has no size at all, which is what puts out the box a
   font draws for a codepoint it has never heard of. The WIDTH is the span's,
   given in the song's own size rather than in em: an em of a font-size of zero
   is zero. */

.ln-t .gap {
  display: inline-block; vertical-align: baseline; position: relative;
  /* named, because the arc below has to reach across a whole run of these and
     an arc that measures a gap differently than the gap measures itself would
     stop short of the last one or hang past it */
  --gap-w: calc(var(--song-size) * .34);
  width: var(--gap-w);
  /* WIDTH AND NOTHING ELSE. No size to the character means no height either,
     so the box sits on the baseline taking up no part of the line: a gap must
     cost the line the room between two letters and not one pixel of its
     height. */
  height: 0;
  font-size: 0;
  /* AND WHAT IS DRAWN ON IT IS NOT CLIPPED BY IT. The box is a nothing tall,
     so anything hung off it, the break mark above all, lies entirely outside
     it: a gap that clipped to its own bounds would draw none of it. Said out
     loud rather than left to the default, because the default is the one
     thing here nobody would think to check. */
  overflow: visible;
}

/* A gap in the editor draws an ARC UNDER THE ROOM IT MADE, the way a tie is
   drawn under two notes held together: the two letters are still one word, and
   what is between them is room and not a break. A straight rule said the same
   thing but said it like a hyphen, which is the one thing a gap is not.

   The arc is concave, dipping at the middle and rising to nothing at both
   ends, so it reads as belonging to the letters on either side of it rather
   than as a mark of its own.

   ONE ARC PER RUN, drawn by the first gap of the run across all of them (see
   `--run`, counted when the spans are built). Five gaps pressed in a row are
   one piece of room, and five little arcs would read as five of something.

   IN THE CHORDS' OWN COLOUR, because the gap belongs to them. It was a grey,
   which is what a page uses for a thing it is not saying much about, and this
   is not that: nobody opens a gap for the sake of the word, they open it
   because a chord had nowhere to stand. Red says whose it is, and the eye
   finds it without being sent looking. Faded well down from the labels
   themselves, so a line of gaps is never mistaken for a line of chords. The
   reader's page and the printed one have nothing at all. The model has a gap
   there, not a hyphen. */
/* --- WHAT AN ARTIFICIAL SPACE IS MARKED WITH ------------------------------
   A diagonal, drawn on the run rather than written into it. It was a curve
   for a while and the shape is the only thing that changed: everything about
   how it is drawn is what the curve did, because that is the version that
   worked.

   ON THE RUN, WHICH NEEDS NO CLASS OF ITS OWN. fillSpans already marks the
   first gap of every run and tells it how many there are, so the stylesheet
   has everything it needs. Three attempts at this put a class on some other
   gap from the pour, and a class that has to be added is a class that can
   fail to arrive, which is exactly what kept happening.

   OUT OF THE FLOW, so the mark cannot make the line taller or push it up. A
   span with a background needs a height to paint it in, and that height would
   be a line's worth of room under every word that had a gap in it.

   Placed a little above the baseline, where the middle of a letter is, so it
   reads as being on the line rather than under it. And drawn rather than
   written, because a solidus in the text is one more character in a row of
   characters, and the one thing this must not look like is a word: the rest
   of the row is the song, and this is a fact about the screen. */
.ln-sep .gap-run::after {
  content: "";
  position: absolute;
  /* centred in the run, however many spaces it holds */
  inset-inline-start: calc(var(--gap-w) * (var(--run, 1) - 1) / 2);
  width: var(--gap-w);
  bottom: calc(var(--song-size) * .08);
  height: calc(var(--song-size) * .56);
  /* thick enough to be a stroke rather than a hairline the antialiasing eats */
  border-inline-start: 2px solid var(--chord);
  transform: rotate(20deg);
  transform-origin: bottom;
}
/* it leans the way the line runs, or it leans back into the words it holds
   apart and reads as the wrong kind of mark */
.ln-sep[dir="ltr"] .gap-run::after { transform: rotate(-20deg); }

/* --- AND A SPACE SOMEBODY OPENED KEEPS ITS ARC ----------------------------
   Two marks for two different things. The diagonal says "these two lines were
   not written on one line", which is a fact about the screen; the arc says
   "this is room between two letters", which is a fact about the song. They
   must not be the same mark.

   TOLD APART BY WHICH ROW THEY ARE IN, and by nothing else. The separator is
   a row of its own, `.ln-sep`, built by the pour out of nothing but gaps and
   standing between two lines; every other run of gaps is inside the words of
   a line. So the diagonal is drawn only in there, and the arc only outside
   it, and no press of the gap button can produce either the wrong one.

   IT WAS TOLD APART BY COUNTING, and counting was wrong. The separator lays
   down four gaps, so the two marks swapped at four: press the gap button four
   times to hold a long word open and the page said «a new line begins here»,
   about a place where nobody had pressed anything of the sort. A count is a
   guess at what somebody meant, and the row already knows.

   THE ROW IS THE ONE CLASS THAT ARRIVES. Earlier attempts marked some gap
   from the pour and the class kept failing to reach the span; this one is on
   the container buildSep creates, which is the same class fillSpans already
   reads to decide that a run standing alone still carries a mark. One fact,
   read in two places, and neither can be handed a row without it. */
.ln-t:not(.ln-sep) .gap-run::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  width: calc(var(--gap-w) * var(--run, 1));
  bottom: calc(var(--song-size) * .12);
  /* the height IS the depth of the dip: the vertical radius is the whole of
     it, so the curve uses every pixel given here and no more */
  /* AND IT DEEPENS WITH THE RUN. A tie is shallow, and a shallow curve held
     across a hand's width of room is a straight line with two bent ends: the
     one thing it must not read as. So the dip grows a little with every gap
     under it and stops at a third of the size, which is as deep as a mark
     under the words can go before it is a mark of its own. */
  height: calc(var(--song-size) * min(.33, .15 + .035 * (var(--run, 1) - 1)));
  /* THICK ENOUGH TO BE A STROKE. A hairline curve loses to the antialiasing
     along its shallow middle, which is exactly the part that says «arc»: it
     comes out as a smudge with two crisp ends. */
  border-bottom: 2px solid var(--chord);
  border-radius: 0 0 50% 50% / 0 0 100% 100%;
  opacity: .55;
}


/* The button that opens one. Under the letters, in the air between two lines,
   because it is the answer to a click and not a thing the page has: out of the
   way of the words and of the chords over them, and gone the moment anything
   is typed. Small, for the same reason.

   THE BOX AROUND IT CARRIES THE POSITION, not the button: one thing to place
   under the letter, one thing to ask whether a press landed inside. */
.gap-offer { position: fixed; z-index: 50; }
.gap-btn {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 22px; padding: 0;
  appearance: none; cursor: pointer;
  background: #fff;
  border: 1px solid var(--line); border-radius: var(--corner);
  box-shadow: 0 2px 8px rgba(23, 32, 42, .12);
}
.gap-btn svg { width: 15px; height: 15px; }

/* THE BUTTON IS DRAWN IN THE COLOUR OF WHAT IT LEAVES BEHIND. The arc it puts
   under the letters is the page's one red, so the arc on the button is that
   same red: press it, and the thing that appears is the thing that was on the
   button. */
.gap-do { color: var(--chord); }
.gap-do:hover { border-color: var(--chord); }

/* ON A PHONE IT STANDS OVER the letters and not under them: the caret there
   comes with a handle hanging under it, and that drop lands on whatever the
   offer put there (see offerGap). Above the letters the room is the chord
   lane, one line's worth, and one button is one button tall and covers the
   lane it is standing in and nothing else.

   Bigger, too. Twenty six pixels is a size for a pointer, and what is aiming
   at it is a thumb. */
@media (max-width: 620px) {
  .gap-btn { width: 38px; height: 34px; }
  .gap-btn svg { width: 19px; height: 19px; }
}

/* --- the chords of a copy, offered over the next marking -------------------
   It stands off the page the same way the offer under a letter does, and it is
   the same red, because what it puts down is chords and the chords on this page
   are red. It carries its words as well as its picture: two notes over a line
   is a clear enough drawing once you know what it does, and nobody arrives
   knowing, so the button says it.

   Small, though. It is standing over words somebody has just marked and is
   still reading, and a marking is not a request for a toolbar. */
/* A ROW, because there is more than one thing to offer over a marking now: the
   chords of the last copy, and a repeat around the lines. They are two answers
   to one gesture and they stand side by side. */
.chord-offer { position: fixed; z-index: 50; display: flex; gap: 6px; }
/* The panel behind the count, which is the same floating thing with smaller
   buttons in it: fewer, wider, and the number between them is not a button. */
.rep-pop .chord-btn { padding: 0 7px; }
.rep-pop .rep-count {
  display: flex; align-items: center; padding: 0 2px;
  font-size: 12px; line-height: 1; color: var(--ink);
  min-width: 14px; justify-content: center;
}
.chord-btn {
  display: flex; align-items: center; gap: 5px;
  height: 25px; padding: 0 8px;
  appearance: none; cursor: pointer;
  font: inherit; font-size: 12px; line-height: 1; white-space: nowrap;
  color: var(--chord); background: #fff;
  border: 1px solid var(--line); border-radius: var(--corner);
  box-shadow: 0 2px 8px rgba(23, 32, 42, .12);
}
.chord-btn:hover { border-color: var(--chord); }
.chord-btn svg { width: 14px; height: 14px; }

/* A blank line is the gap between two stanzas, and a gap does not need a full
   line of words plus an empty chord lane above it to say so: about half that
   reads as a break without reading as a missing verse. The lane goes entirely,
   since a line with no characters has nothing for a chord to sit over. */
.ln.is-blank { margin-bottom: .22em; }
.ln.is-blank .ln-c { height: 0; }
.ln.is-blank .ln-t { min-height: 1em; }

/* ==========================================================================
   A REPEAT: A BAR DOWN THE MARGIN AND A NUMBER BESIDE IT.

   The mark every musician already reads, and the reason the song stores it as
   `|:` and `:|3` rather than as a word: the word "repeat" appears nowhere on
   the page, so it has no business being one in the file either.

   A LINE AND NOT A BRACKET. A bracket with hooks on its ends is more ink than
   this needs, and the ink on a chord sheet is already spoken for: the chords
   are the coloured thing and the eye goes to them. A rule down the side reads
   as structure at a glance and competes with nothing.

   AND IT IS DRAWN BY THE ROWS THEMSELVES, one piece each, joined through the
   gap underneath. Nothing measures it and nothing positions it, so it follows
   its rows wherever the pouring puts them: broken lines, two lines sharing a
   line of the page, a column that ends halfway down a verse. Which rows are
   the ends of a block is decided in markRepeats, in the order the rows came
   out in, because that is the only place the answer exists.

   THE ROOM IT STANDS IN IS REAL ROOM. The margin is on every row of a song
   that has a repeat anywhere in it, not only on the rows inside one: a gutter
   that opened and closed down the page would move the words sideways at every
   block, and the words are the thing that must not move. A song with no
   repeat keeps every pixel it had. */
/* --- AND THE THING THAT DRAWS IS THE LINE OF THE PAGE ---------------------
   A row of the song usually is one, and where two of them share a line of the
   page they stand in a pair (see buildRow) and the PAIR is one. This matters
   for one reason and it is not tidiness: the second line in a pair begins in
   the middle of the page, so a bar drawn against its own start edge is a
   stroke through the words. Reported exactly that way, on a verse whose lines
   had been broken. Which element draws is decided in markRepeats; what is
   here is that both kinds have the same margin, so their bars stand against
   the same edge and the pieces make one rule. */
.sheet.has-rep .ln,
.sheet.has-rep .ln-row { margin-inline-start: var(--rep-gutter); }
.sheet.has-rep .ln-row > .ln { margin-inline-start: 0; }
/* and the pair has to be a box a bar can be placed against */
.ln-row { position: relative; }

.sheet .is-rep::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(var(--rep-gutter) * -1);
  width: calc(var(--rep-gutter) * .58);
  /* The bar is the edge of this box nearest the words, and the number sits in
     the box on the far side of it. One pseudo-element for both, because the
     other one is the follower's band and a row can be lit and repeated at the
     same time. */
  border-inline-end: 2px solid var(--ink-soft);
  pointer-events: none;
}
/* --- AND EACH PIECE REACHES ONLY AS FAR AS IT HAS A NEIGHBOUR -------------
   Through the gap above it or below it, so two pieces meet and read as one
   line, and no further: where the run ends, at the foot of the block or at the
   foot of a column, the bar ends with its row. Half a size covers every gap
   between two rows here, and the overlap it makes in the middle of a run is
   under the piece that is already there. */
.sheet .is-rep-up::after { inset-block-start: calc(var(--song-size) * -.5); }
.sheet .is-rep-dn::after { inset-block-end: calc(var(--song-size) * -.5); }
/* --- AND WHERE IT STARTS IS WHERE THE WORDS DO ----------------------------
   Not at the top of the row, which is the top of the chord lane. What is being
   repeated is the words; the chords are a label standing over them, and a bar
   that starts above them reads as beginning half a line early. */
.sheet .is-rep-a::after { inset-block-start: var(--lane-h); }
/* Except where there is no lane: a blank line, a leftover row that carries no
   chords, and a sheet of words alone. */
.sheet .is-rep-a.is-blank::after,
.sheet .is-rep-a.is-cont.is-tight::after,
.paper.words .is-rep-a::after { inset-block-start: 0; }

/* --- AND THE COUNT IS A REAL THING, NOT DRAWN TEXT ------------------------
   It was `content: attr(data-times)` on the bar itself, which is one element
   fewer and cannot be pressed: a pseudo-element takes no listener, and the
   count is the control. Pressing it is how a repeat is changed to three or
   taken away, and there is nowhere else that gesture could live without
   putting a second thing on the page that means the same thing.

   Placed against the row and not the block, like the foot of the bar it
   stands at: the block's height is not a number any row knows. */
.sheet .is-rep-z > .rep-n {
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(var(--rep-gutter) * -1);
  width: calc(var(--rep-gutter) * .48);
  display: flex; align-items: center; justify-content: center;
  font-size: calc(var(--song-size) * .6);
  line-height: 1;
  color: var(--ink-soft);
  background: none; border: 0; padding: 0; margin: 0;
  font-family: inherit;
  user-select: none; -webkit-user-select: none;
  cursor: default;
}
/* Pressed only where it can be answered. On a page being read it is the number
   and nothing else; a reader who presses it has not asked for anything. */
.sheet.ed .is-rep-z > .rep-n { cursor: pointer; }
.sheet:not(.ed) .is-rep-z > .rep-n { pointer-events: none; }

/* --- editor ------------------------------------------------------------- */

/* The one bar left, and it sits under the sheet: ways to add a line at the end
   of the song, at the end of the song. It was sticky when it was a toolbar at
   the top; a footer that follows you up the page is just something moving. */
.ed-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 10px 12px;
  background: rgba(247, 249, 250, .94);
  border: 1px solid var(--line); border-radius: var(--corner);
}
.ed-bar .grow { margin-inline-start: auto; }

/* In the editor a line keeps its own box and the row's buttons sit beside it,
   never inside it: padding on .ln would shift every measurement the chord
   positions are taken from.

   Nothing here changes the SHAPE of the words. No box, no border, no growing
   field: the text on screen is the text being edited, so clicking into a line
   moves a caret and moves nothing else.

   The two lanes were tinted for a while so you could see which strip took a
   chord and which took words. They are not any more: on a page that is always
   editable, that colour is on the screen all the time and the song stops
   looking like a song. The pointer says the same thing and costs no ink. */
.ed .ln-t { cursor: text; outline: none; }
.ed .ln-section { cursor: text; outline: none; }
.ed .ln-c { cursor: copy; }

/* THERE WAS A LOOK FOR A SELECTED LINE HERE, a wash of colour over the whole
   row and a bar in the margin beside it, because a drag across the words took
   whole lines rather than words. It takes what it crosses now, so what a
   selection looks like is what a selection looks like: the browser's own. */

/* A chord in the editor is the same chord the reader sees, and it stays that
   way. No border, no box, no highlight, nothing that appears or grows. The
   only thing the editor adds is the pointer's shape, which costs no pixels:
   grab over a chord, text while typing into one, copy over the empty lane
   where a new one can be put down.

   min-width on a chord being typed is the single exception, and it is not
   decoration: an empty chord has no glyphs, so without it there is nowhere for
   the caret to blink. */
.ed .chord { cursor: grab; touch-action: none; user-select: none; }
.ed .chord.is-dragging { cursor: grabbing; }
.ed .chord:empty { min-width: 2ch; display: inline-block; }

/* The one thing in the editor that appears on screen, because it is the answer
   to a click rather than a change to the song. One low row of names, and it is
   meant to be forgettable: no chips, no panel, no colour it did not already
   have. It should read as a list, not as a dialog. */
.picker {
  position: fixed; z-index: 50;
  display: flex; align-items: flex-start; flex-wrap: nowrap; gap: 1px;
  max-width: min(300px, calc(100vw - 12px));
  padding: 3px; border-radius: var(--corner);
  background: #fff; border: 1px solid var(--line); box-shadow: 0 4px 14px rgba(23, 32, 42, .12);
}
.picker button {
  appearance: none; cursor: pointer; border: none; background: transparent;
  font: inherit; font-size: 13px; line-height: 1.4; direction: ltr;
  padding: 3px 7px; border-radius: 5px;
}
.picker-chip { color: var(--chord); font-weight: 700; }
.picker-chip:hover, .picker-x:hover { background: var(--chord-soft); }
.picker-chip.is-on { background: var(--chord-soft); }
.picker-x { flex: none; color: var(--ink-soft); font-size: 15px; }
.picker-x:hover { color: var(--danger); background: #fdf1ef; }
/* Two class names deep on purpose. The shared input[type="text"] rule is an
   attribute selector, so it outranks a single class and would put its own
   width, padding and radius back on this field. */
.picker .picker-field {
  flex: none; width: 5ch; margin-inline-end: 3px;
  padding: 3px 5px; border-radius: 5px;
  border: 1px solid var(--chord-soft);
  direction: ltr; text-align: left;
  font-size: 13px; line-height: 1.4; font-weight: 700; color: var(--chord);
}
.picker .picker-field:focus-visible { outline: none; border-color: var(--chord); }
.picker .picker-field.is-bad { border-color: var(--danger); color: var(--danger); }

/* The names on offer, beside the field and wrapping under themselves rather
   than under it, so the field stays where it was put however many chords the
   letters so far could still become. */
.picker-found { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
/* One row of names, wrapping under itself rather than under the field, so the
   field stays where it was put however many chords the letters so far could
   still become. Two of these: the song's own on top, the rest underneath, with
   a line between them so they read as two answers and not one long list. */
.picker-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1px; }
.picker-row:empty { display: none; }
.picker-more { border-top: 1px solid var(--line); padding-top: 2px; }
/* a song with no chords in it yet has an empty row on top, and a line under
   nothing is a line over the only row there is */
.picker-row:empty + .picker-more { border-top: none; padding-top: 0; }

.hint {
  font-size: 13px; color: var(--ink-soft);
  background: #eef5f4; border: 1px solid #d7e7e4; border-radius: var(--corner);
  padding: 9px 13px; margin: 0 0 14px;
}

/* --- upload / import ---------------------------------------------------- */

.drop {
  border: 2px dashed #cfdbe1; border-radius: var(--radius); background: var(--card);
  padding: 28px 20px; text-align: center; margin-bottom: 16px;
  transition: border-color .15s, background .15s;
}
.drop.is-over { border-color: var(--accent); background: #eef5f4; }
.drop h3 { margin: 0 0 4px; font-size: 17px; }
.drop p { margin: 0 0 14px; color: var(--ink-soft); font-size: 14px; }

.busy { display: inline-flex; align-items: center; gap: 9px; color: var(--ink-soft); font-size: 15px; }
.spin {
  width: 17px; height: 17px; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 2s; } }

/* --- ONE SHEET, AND EVERYTHING OVER THE PAGE IS IT -------------------------
   The tuner, the handful of rows behind a button in the bar, the panel of the
   song's facts, and every dialog about a song. One shape, arriving from one
   edge, with one bar across the top of it, so that a panel is read once and
   recognised after that (see openSheet in app.js). The account is the one
   exception, and it is at the end of this section.

   AT THE FOOT OF THE SCREEN AND NOT IN THE MIDDLE OF IT. A panel in the middle
   is a thing the page was interrupted by; a panel at the bottom is a thing
   that was reached for, it comes up under the hand that asked for it, and it
   goes back down the way it came. On a wide screen it is the same sheet,
   centred, because a shape that changes with the window is two shapes.

   The width is the one measure everything here shares. --------------------- */
:root { --sheet: 520px; }

/* THE BAR ACROSS THE TOP. Not decoration and not a control with a name: it is
   the one mark that says this came up from below and can be pushed back down,
   and a gesture nothing on screen hints at is a gesture nobody makes.

   It takes the whole width, so the finger that reaches for it does not have to
   find it, and the touch never goes to the page under it while a sheet is
   being dragged. */
.grip {
  flex: none; display: flex; align-items: center; justify-content: center;
  height: 24px; cursor: grab; touch-action: none; user-select: none;
}
.grip::before {
  content: ""; width: 40px; height: 4px; border-radius: 2px;
  background: var(--line);
}
.is-held .grip { cursor: grabbing; }
/* WHILE A HAND IS ON IT, IT IS WHERE THE HAND PUT IT. Nothing eases towards
   anywhere: a sheet that lags a finger by a fifth of a second is a sheet that
   feels like it is being pulled through water. */
.is-held { transition: none !important; }

/* AND IT COMES UP FROM THE EDGE IT LIVES ON. A dialog says this with a
   transition, because it has a start and an end the browser knows about; a
   panel that is simply put on the page says it with this. */
@keyframes pop-up { from { transform: translateY(100%); } }

/* --- dialog, toast ------------------------------------------------------ */

.dlg {
  border: none;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -1px 3px rgba(23, 32, 42, .1), 0 -18px 60px rgba(23, 32, 42, .22);
  /* the foot of the window, in the middle of it */
  margin: auto auto 0; max-width: var(--sheet); width: 100%;
  /* and never taller than the window, whatever is in it */
  max-height: calc(100dvh - 40px);
  /* AND NO PADDING OF ITS OWN, not a pixel. A press that lands on the dialog
     element and not on anything inside it is how the dark behind it is read
     (see openSheet), and a strip of padding along the foot of the panel would
     be a strip inside the panel that closed it. */
  padding: 0;
}
/* THE COLUMN IS ON THE OPEN ONE AND NOT ON THE CLASS. An author's `display`
   beats the browser's own `dialog:not([open]) { display: none }` whatever the
   specificity says, because author rules beat user agent rules, so a display
   written here without [open] on it puts every shut dialog on the page. */
.dlg[open] { display: flex; flex-direction: column; }
.dlg::backdrop { background: rgba(23, 32, 42, .35); }
/* WHAT SCROLLS IS THE PANEL AND NOT THE PAGE. A long panel keeps its own
   scroll, and the pull at the end of it stops there rather than dragging the
   page along behind the sheet. */
.dlg-in {
  padding: 4px 24px calc(24px + env(safe-area-inset-bottom));
  display: grid; gap: 12px;
  min-height: 0; overflow-y: auto; overscroll-behavior: contain;
}
.dlg-in h2 { margin: 0; font-size: 20px; line-height: 1.3; letter-spacing: -.01em; }
/* A panel opens onto its heading rather than onto the first thing in it that
   can take the focus, which is a field, and on a phone a field is a keyboard.
   The heading is a place to start and not a control, so no ring is drawn
   around it. */
.dlg-in h2:focus { outline: none; }

/* IT ARRIVES, RATHER THAN BEING THERE, and it arrives from the edge it lives
   on. A panel that appears between two frames is read as the page having been
   redrawn, and the eye then has to find what changed; a fifth of a second of
   rising from the bottom says where it came from, that the page under it is
   still the page, and which way to push it to be rid of it.

   Three things have to be allowed to animate for the way out to work as well
   as the way in: the two properties, and the discrete jumps of `display` and
   of the top layer, which are what actually end a dialog. The plain transition
   stands on its own, and browsers that know how to interpolate those jumps
   take the second one, so an older one loses the closing frames and nothing
   else. */
.dlg, .dlg::backdrop { transition: opacity .2s ease, transform .22s ease; }
@supports (transition-behavior: allow-discrete) {
  .dlg, .dlg::backdrop {
    transition: opacity .2s ease, transform .22s ease,
                overlay .22s allow-discrete, display .22s allow-discrete;
  }
}
.dlg, .dlg::backdrop { opacity: 0; }
.dlg { transform: translateY(100%); }
.dlg[open] { opacity: 1; transform: none; }
.dlg[open]::backdrop { opacity: 1; }
@starting-style {
  .dlg[open] { opacity: 0; transform: translateY(100%); }
  .dlg[open]::backdrop { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .dlg, .dlg::backdrop { transition: none; }
  .dlg { transform: none; }
}
/* --- AND ONE PANEL IS NOT A SHEET ----------------------------------------
   The account. Everything else that comes up over the page is about the song
   under it: the facts, the tuner, the recording, and a sheet rising over the
   thing it belongs to is the right shape for that, because the page stays the
   page and the panel is a thing reached for.

   The account is not about the song, and it is not about the page either. It
   is the one panel that interrupts, and a panel that interrupts belongs in the
   middle of the screen: it opens where the eye already is, it wears the same
   corner on all four sides because no edge of it is anchored to anything, and
   there is nothing to push down because it did not come up from anywhere.

   So no grip either (see openPop in app.js), and the two ways out of it are
   the two ways out of everything: a press on the dark behind it, or back. */
.dlg.pop {
  /* the middle of the window, in both directions */
  margin: auto;
  border-radius: var(--radius);
  box-shadow: 0 1px 3px rgba(23, 32, 42, .1), 0 18px 60px rgba(23, 32, 42, .22);
  /* and off the edges of a narrow screen, which the sheet never had to be */
  width: calc(100% - 32px);
}
/* THE ROOM AT THE TOP IS THE PANEL'S OWN NOW. On a sheet the bar across the
   top is what holds the heading off the edge, so the column under it starts
   almost flush; with no bar there is nothing there, and the heading would sit
   on the corner. */
.pop .dlg-in { padding: 24px; }

/* AND A BAR IT WAS GIVEN BEFORE IS NOT SHOWN. The account never has one, but
   the creators and the style are a sheet on a phone and a pop on a wide screen
   (see openByWindow in app.js), and the panel is built once: one opened at the
   foot of a narrow window keeps the bar it was given there. A handle offering a
   gesture that has nowhere to go is worse than no handle, so it comes off with
   the shape, and the push comes off with it (see gripUp). */
.pop .grip { display: none; }

/* IT COMES UP OUT OF ITSELF, rather than up from an edge. A shape that grows
   the last few percent into place says the same thing the rise from the foot
   of the screen says, that this arrived and the page under it is still the
   page, without claiming it came from a direction it did not come from. */
.dlg.pop { transform: scale(.96); }
.dlg.pop[open] { transform: none; }
@starting-style {
  .dlg.pop[open] { transform: scale(.96); }
}

/* A panel that explains a mark shows the mark, at the size of the words next
   to it rather than of an illustration: it is a heading with a symbol in it,
   not a picture with a caption. */
.dlg-head { display: flex; align-items: center; gap: 10px; }
.dlg-head svg { flex: none; width: 26px; height: 26px; color: var(--chord); }
.dlg-in p { margin: 0; font-size: 14px; }
.dlg-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
/* The one button in a row that is not the answer to the question the panel is
   asking. Pushed to the other end so it is not pressed on the way to one that
   is. */
.dlg-actions .far { margin-inline-end: auto; }

/* --- AND THE ANSWER THAT LOSES SOMETHING ----------------------------------
   A light red, and light is the whole of it. It is not the dangerous button in
   the row, which is drawn in the full colour and asked twice about; it is an
   ordinary answer that happens to leave a recording behind, and the colour is
   there to be noticed on the way past rather than to stop anybody. */
.btn.toss {
  background: #fdeceb; color: #b3261e; border-color: #f3c9c5;
}
.btn.toss:hover { background: #fbdcd9; color: #8f1d18; border-color: #e8ada7; }

/* --- AND THE ANSWER THAT LOSES IT AND STOPS -------------------------------
   A bin and no word. It stands in a row with two answers written as sentences,
   and a third sentence there would read as a third equal side to the question,
   which it is not: the two are what to do with the recording, and this is the
   way out for somebody who has finished playing (see askTake).

   It is a .btn and not an .icon-btn, because it stands in a line of buttons
   and the thing holding that line together is that their tops and bottoms
   agree; an icon button here is thirty pixels beside thirty-eight. Its word is
   hidden rather than never written, so the button still says what it is to a
   screen reader and to a pointer resting on it, exactly as the bar's buttons
   do on a narrow screen (see .top-actions .btn svg + .lb).

   Quiet until the hand is on it, and then red: the colour belongs to what the
   press does, not to a button sitting in a row.

   Called .bin and not .drop, which is taken: .drop is the dashed box a file is
   dragged into, and it is written as a bare class, so it would have reached
   this button and made it one too. */
.btn.bin { padding-inline: 11px; color: var(--ink-soft); }
.btn.bin .lb { display: none; }
.btn.bin svg { width: 18px; height: 18px; }
.btn.bin:hover { background: #fdeceb; color: #b3261e; border-color: #f3c9c5; }

/* --- AND THE ANSWER THAT KEEPS IT, IN THE SAME COLOUR AT FULL WEIGHT --------
   The pair in this row is one question with two answers, and it was drawn as a
   green button beside a pale red one: two colours is two unrelated things to
   press, and the green is the app's own «this is the way on» wearing it on a
   panel where both of them are. So they share a colour and differ in weight,
   which is the thing actually being said: one of these is the ordinary answer
   and the other is not.

   The fill is the ink the light one is written in, and the hover is the ink it
   goes to under a pointer, so there is one colour here and not three. */
.btn.keep {
  background: #b3261e; color: #fff; border-color: #b3261e;
}
.btn.keep:hover { background: #8f1d18; border-color: #8f1d18; }

/* --- THE PANEL THE SONG'S FACTS ARE WRITTEN IN ----------------------------
   A form and not a question, so it is spaced like one: a heading, and air
   under it before the first field. The heading used to have a line of its own
   held close beneath it saying the typing keeps itself, and the tighter gap
   that held it there went when it did.

   There is no row of buttons at the foot. There was one, running the width of
   the panel and doing nothing but shutting it, which is a button standing
   where the one that saves would stand on a panel that saves as it is typed.
   Escape and the dark behind the panel do the same thing and neither of them
   has to be read first, so the panel ends where its fields end. */
.dlg-meta .song-meta { margin-top: 16px; }

/* --- WHAT WRITING HERE MEANS, WHERE IT DOES NOT MEAN THE OBVIOUS THING ----
   One sentence between the heading and the first field, and only for somebody
   changing a song that is not theirs: what they type is kept beside the song
   and not in it. The song's own account is told nothing, because there is
   nothing to tell.

   It is quiet and it is not a warning. Nothing here can go wrong, and a line
   in red over a form that saves itself would say that something can. */
.meta-said {
  margin: 10px 0 0; font-size: 13px; line-height: 1.6; color: var(--ink-soft);
}
/* The form follows it at the gap it would have had from the heading, so a
   panel with the sentence and one without are the same panel. */
.meta-said + .song-meta { margin-top: 14px; }

/* --- AND WHAT SOMEBODY ELSE WOULD HAVE THEM SAY --------------------------
   Under the form, under a line, because it is not a fourth field: the fields
   are what this account says and this is what another one is proposing. The
   line is the same one the credit at the foot of the panel stands under, and
   for the same reason: what is above it is the answer, and what is below it is
   about the answer.

   Boxed and inset, so that a panel holding two answers cannot be misread as a
   panel holding one. */
.meta-offers {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  display: grid; gap: 14px;
}
.meta-offers[hidden] { display: none; }
.meta-offer {
  display: grid; gap: 10px;
  padding: 12px; border-radius: 10px; background: var(--bg);
}
.meta-offer-said { font-size: 13px; font-weight: 600; color: var(--ink-soft); }
/* The answers in it are chips and not links, so they carry the chip's own ring
   and nothing else: this is a thing to read and answer, not a way out. */
.meta-offer .told-row { align-items: baseline; }
.meta-none { font-size: 13px; color: var(--ink-soft); }
/* The two buttons sit where they are read last, at the end of the block rather
   than centred in it: the block is a sentence and they are what to do about
   it. */
.meta-offer .row-actions { justify-content: flex-start; margin-inline-start: 0; }

/* --- AND THE SAME PANEL, READ RATHER THAN FILLED IN -----------------------
   What somebody who cannot change the song sees when they press the same
   button: the same three lines in the same order, with the answers standing
   where the fields were. So the word in front keeps the width the form gives
   it and the answer keeps the size the form set for what was typed, and the
   two panels are one panel that has been answered, down to the air under the
   heading. */
.dlg-told .song-told { margin-top: 16px; }
.song-told { display: grid; gap: 14px; }
.told-row { display: flex; align-items: baseline; gap: 8px; min-width: 0; }

/* A NAME IS A PAGE AND A STYLE IS A SHELF, so both are links, and both are the
   same chip they are everywhere else in the app. The name was a line of text
   with an underline arriving under it, which reads well for the one song in ten
   that one person wrote and not at all for the nine where the words are three
   people's: a row of names has to say where each of them ends, and three chips
   say it without a comma being asked to do the work of a border.

   The ring the chip already has is what lights up. A chip that gained an
   underline on the way in would be a chip with a line through the bottom of its
   own border. */
.told-tags { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.told-tags .tag-style { text-decoration: none; }
.told-tags .tag-style:hover { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

/* --- AND WHO PUT IT IN THE LIBRARY ---------------------------------------
   Under a line, in the panel's quiet ink, and as a sentence rather than as a
   third row of the list above it. Who wrote a song is true wherever it is
   sung; who typed it in is true only here, about this row, and a fact of that
   kind read as one more answer in the column would be read as one more thing
   about the song.

   It also arrives a moment after the panel does, and a line that has to
   appear is a line that should not be able to move the answers above it: at
   the foot of the panel, nothing is under it to be pushed. */
.told-who {
  margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--ink-soft);
}
/* Hidden until there is a name to say. Said here rather than left to the
   browser, so that giving this line a display of its own later cannot quietly
   bring it back on every song. */
.told-who[hidden] { display: none; }

/* --- signing in --------------------------------------------------------- */

/* THE ONLY WAY IN, so it is one button and it looks like itself everywhere:
   white with a border and the mark in its own four colours, which is what
   Google asks of a button that carries it, and which is right anyway. The door
   belongs to somebody else, so it should not be painted in this site's green
   like the buttons that do its own work. */
.btn.google { background: #fff; color: #3c4043; border-color: #dadce0; font-weight: 600; }
.btn.google:hover { background: #f7f8f8; border-color: #c9ced3; }
.btn.google svg { width: 18px; height: 18px; }

.toast {
  position: fixed; inset-inline: 0; bottom: 22px; margin-inline: auto;
  width: max-content; max-width: calc(100% - 32px);
  background: var(--ink); color: #fff; padding: 11px 20px; border-radius: var(--corner);
  font-size: 15px; box-shadow: var(--shadow);
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity .2s, transform .2s; z-index: 60;
}
.toast.is-on { opacity: 1; transform: none; }
.toast.is-bad { background: var(--danger); }

/* --- print -------------------------------------------------------------- */

/* Which of the two pieces of paper. Under the print button, and small: it is
   two words and a choice, not a dialog.

   AND NOT THE SHEET, which everything else standing over the page here is (see
   .dlg, and openSheet in app.js). This hangs off the button that opened it and
   is read in the corner the hand is already in; a choice between two words
   does not want the width of the window and does not want to stand at the
   other end of the screen from the question that raised it. */
.print-menu {
  position: fixed; z-index: 60;
  display: flex; flex-direction: column; align-items: stretch; gap: 2px;
  padding: 6px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--corner);
  box-shadow: 0 6px 20px rgba(23, 32, 42, .16);
  /* Every panel in here used to be three rows written by hand. One of them is
     a list of whatever somebody has made (see askPlaylists), so it can be
     twenty, and twenty rows hanging off a button in the corner is a panel
     whose foot is below the screen and cannot be reached. */
  max-height: 70vh; overflow-y: auto;
}
/* A LIST OF NAMES SOMEBODY ELSE WROTE, so the panel cannot be sized by what is
   in it: one playlist called "שירים" and one called a sentence would give the
   panel the width of the sentence. It stops at a readable line and the rest is
   said by the end of it. */
.print-menu .btn.pl-row > .lb {
  max-width: 26ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* What a panel says when it is not a list of things to press: it is loading,
   or there is nothing there yet. Not a row, because there is nothing to press,
   and the rows around it are all presses. */
.under-note {
  padding: 9px 14px; font-size: 14px; color: var(--ink-soft);
}
/* A ROW IS A LINE OF A MENU, NOT A BUTTON IN A BOX. The panel already has a
   border and a shadow around it, and drawing a second border around every row
   inside it says four times over what the panel said once: four boxes in a
   box. What separates one line from the next is the space it stands in, so the
   rows lose their outline and take an ordinary button's height instead, and
   the fill arrives only under the pointer, on the row being chosen. */
/* TWO COLUMNS AND NOT A ROW OF THINGS PUSHED TOGETHER: the pictures under
   each other, the words under each other. A button lays itself out by putting
   its picture next to its word, which is right for a button standing alone and
   wrong for a list: a row with no picture starts its word where the pictures
   are, and one word in the column is half a letter out of line with the rest.
   So the picture has a column of its own that is there whether or not the row
   has one to put in it, and the word always begins in the second. */
.print-menu .btn {
  display: grid; grid-template-columns: 17px 1fr; gap: 7px;
  align-items: center; justify-items: start; text-align: start;
  padding: 9px 14px;
  border-color: transparent; background: none;
}
.print-menu .btn > svg { grid-column: 1; }
.print-menu .btn > .lb { grid-column: 2; }
.print-menu .btn:hover { background: var(--bg); border-color: transparent; }
/* A row that is a door to something already open says so, the same way the
   picture of it did when it stood in the bar (see .icon-btn.is-on). */
.print-menu .btn.is-on,
.print-menu .btn.is-on:hover { color: #fff; background: var(--accent); border-color: var(--accent); }
/* Except the one with a microphone behind it, which is red wherever it stands:
   the picture of it in the bar says the same thing in the same colour (see
   .ear-door.is-on). */
.print-menu .btn.ear-row.is-on,
.print-menu .btn.ear-row.is-on:hover { background: var(--chord); border-color: var(--chord); }
/* AND NO NAME IN HERE ANY MORE. The panel used to hold the doors to the rest
   of the app, one of them carrying whoever was signed in; those went to the
   row of chips over the wall (see .tally-door). What is left in these rows is
   what is done TO the page they were opened over. */

/* --- THE PEOPLE ON A PLAYLIST, INSIDE THE PANEL THAT SHARES IT ------------
   Two shapes for one list, because two different things can be done to a name
   in it. A person the reader may take off the playlist is a row like every
   other row in here, with a wastebasket in the picture column. A person they
   may not, which is the account that made the list and, for everybody but that
   account, everybody else, is a line and not a press.

   The line is written where the rows are written, in the same column, so a
   roster of four does not come out as two lists at two indents: .under-note
   already has the panel's own padding, and this is the one place it stands
   among rows rather than instead of them (see askShare). */
.print-menu .crew-one {
  padding-inline-start: 38px; font-weight: 600; color: var(--ink);
}
/* AND TAKING SOMEBODY OFF IS NOT A RED BUTTON. It is one of the ordinary rows
   of the panel, and it says what it does by the picture beside the name; the
   colour arrives under the pointer, at the moment somebody is about to press
   it, which is the moment it is worth saying. */
.print-menu .btn.crew-out:hover { color: var(--danger); }

/* THERE WAS A .styler HERE, the same small panel holding every style the
   library already uses, for naming a handful of ticked songs at once. It went
   with the ticking. A song is given its style on the song's own page. */

/* ==========================================================================
   THE SONG ON PAPER.

   A second copy of the song, laid out by the same code that lays out the page
   on the screen and for the same reasons, except that the room it is given is
   a sheet of A4 upright instead of a window (see toPaper in app.js). It stands
   off the screen from the moment a printer asks for it and it is what the
   printer is given; the page the reader is looking at is not printed at all.

   WHY A COPY AND NOT THE PAGE. The columns are real elements with the song
   dealt out into them, so laying the page out for paper means taking the
   reader's page apart under them and putting it back when the printing is
   over, and when that is cannot be known: several browsers fire afterprint the
   moment window.print returns, before anything has been laid out for paper.

   WHY NOT A STYLESHEET, which is what this used to be. How many segments a
   song stands in and where each page of it ends are worked out by measuring
   the song, in the reader's own font at the reader's own size, and CSS cannot
   measure. Taking the columns apart for paper printed a page nobody had laid
   out; leaving them alone printed a page built for a window, which the printer
   then squeezed to half its size to make it fit.

   So everything below is what this copy IS, on screen and off it, because it
   has to be measurable while it is being laid out. What belongs to the printer
   alone is down in @media print: which of the two copies is shown.
   ========================================================================== */
/* OUT OF THE WINDOW RATHER THAN HIDDEN, and the difference is the whole thing:
   every line of this copy is measured while it stands here, and what a hidden
   box hands back when it is asked how wide a letter is depends on the browser.
   Standing somewhere nobody is looking is not a special state, it is an
   ordinary box at an address off the side of the glass.

   FIXED, because a fixed box is outside the flow and outside what a window can
   be scrolled to: an absolute one at a negative offset is scrollable overflow
   in a page that runs right to left, which is a bar along the bottom of the
   song and a screen that can be dragged sideways onto nothing. */
.paper {
  position: fixed; top: 0; left: -20000px; z-index: -1;
  pointer-events: none;
}
/* The air a page keeps at its two ends is the space between one screenful and
   the next, and paper has no next screenful: it has a margin of its own (see
   @page) and a fresh sheet after every page. PAGE_AIR in app.js gives the same
   nothing to the arithmetic, and neither may be changed alone. */
.paper .page { --page-air: 0px; }
/* and the hairline that says a screenful ended: on paper the sheet says it */
.paper .page + .page { background: none; }
/* A SEGMENT ON PAPER CUTS NOTHING OFF. On screen it does, because a line being
   typed into has not been broken to the column yet and would be written across
   the one beside it. Nothing is typed into this copy: every line in it was
   poured to the width it is standing in, and the only thing that reaches past
   that is a chord hanging past the end of its line, which is what the margin
   inside every segment is for. */
.paper .col { overflow: visible; }
/* THE RULE BETWEEN TWO SEGMENTS IS DRAWN AND NOT WRITTEN, which on paper is
   the difference between printing and not: it is a background (see .rule), and
   a print dialog leaves backgrounds off unless it is asked. Nobody printing a
   song is going to go and tick that, and without the rule the two segments of
   a sheet are two columns of words with a space down the middle, which is the
   one thing the rule was put there to stop. */
.paper .rule { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
/* the sheet is paper here, not something lying on a screen */
.paper .sheet {
  min-height: 0; padding: 0; border: none; box-shadow: none; overflow: visible;
}
.paper .song-head { margin: 0 0 12px; }
.paper .on-paper { display: block; }
/* and one of them is left out when there is nothing to say (see sayWho) */
.paper .on-paper[hidden] { display: none; }
.paper .song-meta, .paper .past-band, .paper .save-state { display: none; }

/* --- THE LYRICS SHEET ------------------------------------------------------
   The same page with the chords taken off it and the gaps closed up, which is
   the whole reason a gap is a character of its own and not a run of spaces:
   the words come back together into words.

   For the people singing, who do not read chords and to whom a pink symbol
   over every line is a page that is harder to follow.

   AND IT IS TAKEN OFF BEFORE THE PAGE IS LAID OUT, which is why none of this
   is in the print stylesheet any more. How many segments the words stand in
   and where each sheet of them ends are worked out by measuring lines, and a
   line with a row of chords over it is half as tall again as the same line
   without one: measured with the chords and printed without them, every sheet
   came out with a hand's width of nothing at the foot of it. */
.paper.words .ln-c { display: none; }
.paper.words .ln-t .gap { width: 0; }
/* where a capo goes is one more thing that is not about singing */
.paper.words .capo-line { display: none; }

/* TIGHTER, AND FURTHER FROM THE NAME. The spacing of a chord sheet is built
   around the row of symbols over every line: take that row away and the same
   spacing is a page of words with a chord's worth of air between them, which
   reads as a list rather than as a song. So the lines close up to something a
   verse can be seen whole in, the blank line between two verses keeps enough
   to still be a break, and the title gets the room the chords used to take: a
   heading resting on the first line reads as part of it. */
/* AND THE WORDS MAY WRAP HERE. Every line was poured to the width of the
   segment it stands in and fits it, so this changes nothing on an ordinary
   sheet; what it does is make the one line that measured a hair wide break
   like a paragraph instead of being cut off at the edge of its column. A chord
   sheet cannot have that, because a chord has to stay over its syllable. */
.paper.words .ln-t { white-space: pre-wrap; line-height: 1.35; min-height: 0; }
.paper.words .song-head { margin-bottom: 30px; }
.paper.words .ln { margin-bottom: 0; }
.paper.words .ln.is-blank .ln-t { min-height: .9em; }
.paper.words .ln.is-section { margin: 16px 0 3px; }

@media print {
  /* --- WHAT IS BEING PRINTED ON ---------------------------------------------
     A4 upright, which is the sheet that is already in the tray of whatever
     printer this is being sent to. The margin is the printer's, and it is the
     only margin on the page, so the name of the song, whoever wrote it and the
     first letter of every line all begin at the same place.

     HOW MANY SEGMENTS STAND ON IT IS NOT SET HERE and is not a fact about the
     paper. It is asked of the song, at the size paper is set in, exactly as it
     is asked of a window (see planColumns in app.js): a song of short lines
     stands in two on this sheet and a song of long ones stands in one, and
     neither is a case anybody has to write down.

     PAPER in app.js holds the same sheet less the same margin, in the
     millimetres the columns are worked out from, and two places holding one
     number is how they come to disagree: neither may be changed alone. */
  @page { size: A4; margin: 10mm; }

  .top, .tools, .ed-bar, .song-meta, .toast, .print-menu { display: none !important; }
  /* A microphone is about the room, and paper is not in it. The mark it leaves
     on the chords goes with it: what is being played at this second is the
     shortest lived fact in the app, and printing one is printing a moment. */
  .ear, .takes { display: none !important; }
  /* and the glass the tuner puts the page behind is a grey page on paper */
  body.on-ear::before { display: none !important; }
  /* and the band under the line goes with them: paper has no follower on it */
  .ln.is-here::before { display: none !important; }
  .chord.is-heard {
    color: inherit !important; background: none !important; box-shadow: none !important;
    /* and it comes back down: the lift is room for a halo, and there is no
       halo on paper */
    transform: none !important;
  }

  /* --- AND WHICH OF THE TWO COPIES ------------------------------------------
     The song laid out for paper is shown and the page on the screen is not
     (see toPaper). The screen's page says so on itself rather than through the
     body, because a browser that never raised beforeprint built no copy at
     all, and a page with both halves hidden is a blank sheet: with no copy
     there is no class either, and what comes out is what always came out. */
  .off-paper { display: none !important; }
  .paper {
    position: static; left: auto; top: auto;
    width: auto !important; z-index: auto;
  }
  /* EVERY SCREENFUL IS A SHEET, which is what the whole layout already means:
     a page here is exactly as much of the song as the room holds, and the room
     it was dealt into was a sheet of A4. */
  .paper .page { break-inside: avoid; }
  .paper .page + .page { break-before: page; }
  /* EXCEPT WHERE THERE IS ONE SEGMENT AND THEREFORE ONE PAGE, which is a song
     whose lines are too long to stand two of them side by side on this sheet.
     There is nothing to deal out then and the song simply runs down the paper
     (see pageUp), so where each sheet ends is the printer's business, and the
     only thing to say about it is that it may not end inside a line: a chord
     and the syllable under it are one thing, and half of each is neither. */
  .paper .ln, .paper .ln-row { break-inside: avoid; }

  /* --- AND WHERE NO COPY WAS BUILT AT ALL -----------------------------------
     Which is a browser that raises no beforeprint and a print nobody pressed
     the button for: the page on the screen is what goes to the printer, and
     these three lines are the least it owes whoever asked for the words. The
     class is put on the body by the press (see printNow) and means nothing
     anywhere but here.

     It says the same thing .paper.words says, and both are true at once on
     every print that did build a copy, which is why they may not disagree:
     they are set by the same press, from the same answer. */
  body.print-words .ln-c { display: none !important; }
  body.print-words .ln-t .gap { width: 0 !important; }
  body.print-words .capo-line { display: none !important; }

  .song-head { margin: 0 0 12px; }
  /* Which version this is, and what to do about it, are about the page rather
     than about the song. On paper it is the song. */
  .past-band { display: none !important; }
  /* what is offered on a screen is not a fact about the song on paper */
  .gap-offer, .dial-pop, .chord-offer { display: none !important; }
  /* what a version changed is about two versions, and paper holds one */
  .ln.is-add::before, .ln.is-gone::before { display: none; }
  .ln.is-gone { display: none; }
  body { background: #fff; }

  /* A playlist on paper is the name, the line under it and the songs in order.
     The buttons that emptied it and played it are tools, and a tool on a
     printed page is ink spent on something nobody can press. The library it was
     built from is not here to be hidden any more: it is the box in the bar, and
     the bar does not print (see state.pick). */
  /* And the row that asks what else belongs on the list, with the wall behind
     it: a page being handed to somebody to sing from is finished, and a
     question about what to add to it is a thing for the screen. */
  .pl-meta, .hint, .set-row button, .pl-more, .pl-suggest { display: none !important; }
  .on-paper { display: block; }
  /* and one of them is left out when there is nothing to say (see sayWho): the
     class turns these on for the printer, so it has to be told when not to */
  .on-paper[hidden] { display: none; }
  .set-row { border: none; padding: 4px 0; break-inside: avoid; margin: 0; box-shadow: none; }
  /* AND ONE COLUMN ON PAPER, whatever the screen was doing. The wall is
     columns as wide as the room allows, and a sheet of A4 has room for two:
     a list somebody is going to sing from, in two columns, is a list read in
     the wrong order by whoever is holding it. */
  .set { columns: 1; }
  /* --- ONE MARGIN, AND EVERYTHING ON THE PAGE STANDS ON IT ------------------
     The margin used to belong to the sheet, then to #app: a little room at the
     start of the line, because the first chord of a line is centred on its
     first character and half of it hangs past the start. It is the paper's now
     (see @page above), which is the one place that can hold it: the columns
     are dealt out to the width of what is left, so a margin anywhere inside
     the page would be room the song was promised and then not given.

     What is left here is everything on the page giving up a margin of its own,
     so that the title, whoever wrote the song and the first letter of every
     line all begin at the same place, and the chord that hangs past it hangs
     into the paper's margin, which is what it is for. */
  #app { padding-inline: 0; }
  .wrap { width: 100%; }
  /* The edges of a sheet are what says where the song is on a screen. On paper
     the paper says it. The copy laid out for the printer has given these up
     already (see .paper); this is for the sheet on the page itself, which is
     printed only where no copy was ever built. */
  .sheet { border: none; box-shadow: none; padding: 0 !important; overflow: visible; }
  .sheet { min-height: 0 !important; }
}


/* ==========================================================================
   THE SEED, which most people will never see.

   Every address here is written to disk with the song already in it (see
   pages/render.js), so that a crawler, and anybody whose script has not
   arrived yet, is given the words rather than an empty box. app.js takes it
   out the moment it starts and draws the real page over it.

   So this is styled for the half second it is up and for the reader who has
   no script at all: plain, readable, and out of the way. The sheet is set in
   a monospace face because a chord in it is placed by COUNTING CHARACTERS,
   which is the one thing that can be done without measuring anything: the
   real sheet next door measures every letter and is right at any size.

   AND IT HOLDS STILL BEFORE IT SHOWS ITSELF. On a load that went well the
   script is here within a few hundred milliseconds, and all the seed does
   there is put a page of plain markup on the screen and have it replaced by
   the real one, which reads as a fault and not as a fallback. So it waits out
   the length of a load that went well. Past that the script is late, somebody
   is looking at a page with nothing on it, and the words are better than
   nothing.

   Whoever this is actually for is unaffected: a reader that does not run
   scripts does not animate a stylesheet either and takes the markup as
   written, and one that does run scripts is given the real page, which is
   what app.js draws over this.
   ========================================================================== */
#seed { animation: seed-wait 0s linear 600ms both; }
@keyframes seed-wait { from { visibility: hidden; } to { visibility: visible; } }

.seed { max-width: 720px; margin-inline: auto; padding: 20px 0 64px; }
.seed h1 { font-size: 26px; margin: 0 0 6px; }
.seed h2 { font-size: 17px; margin: 26px 0 8px; }
.seed p { margin: 0 0 12px; color: var(--ink-soft); }
.seed a { color: var(--accent-ink); }
.seed-by { font-size: 14px; }
.seed-kinds a { margin-inline-end: 10px; }

.seed-sheet {
  margin: 10px 0 20px; padding: 16px; overflow-x: auto;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px; line-height: 1.85; color: var(--ink);
}

.seed-list { list-style: none; margin: 0; padding: 0; }
.seed-list li { padding: 8px 0; border-bottom: 1px solid var(--line); }
.seed-note { color: var(--ink-soft); font-size: 13px; }

/* ==========================================================================
   THE MICROPHONE, along the foot of the screen.

   A band and not a dialog, and that is the whole design: everything in here is
   read WHILE PLAYING, with both hands on a guitar and the song still on the
   page above it. A modal would cover the one thing it is about. So it stands
   at the bottom, the page is given room under itself to make up for it, and
   nothing here ever takes the focus.

   Fixed rather than sticky, because a person playing scrolls the song and does
   not want the needle scrolling away with it.
   ========================================================================== */
.ear {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 60;
  margin-inline: auto; max-width: var(--sheet);
  background: var(--card);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 -1px 3px rgba(23, 32, 42, .1), 0 -18px 60px rgba(23, 32, 42, .18);
  padding: 0 14px calc(10px + env(safe-area-inset-bottom));
  animation: pop-up .22s ease;
  transition: transform .22s ease;
}
/* AND THE DARK BEHIND IT BELONGS TO ONE OF THE TWO SIDES AND NOT TO THE OTHER.
   The measurement is read WHILE the song under it is being played from, and a
   page behind glass is a page nobody can follow, so nothing is darkened for
   it. THE TUNER IS THE OTHER THING ENTIRELY: a string is turned with the eyes
   on the needle, the page behind it is not being read at all, and a panel that
   asks to be looked at while the page stays lit is a panel that has to be
   found. So it stands like every other panel in this app, over a page put
   behind glass, and the dark is also what it is closed by: a press on it is a
   press outside the band, which is the gesture that puts it away already (see
   earOutside in app.js).

   THE PAGE DRAWS IT AND NOT THE BAND, because a shape inside the band could
   never cover the band's own edges. It exists for as long as the band does and
   only turns dark for the tuner, so the fifth of a second of the sheet leaving
   is not a fifth of a second of the page flashing back to white behind it (see
   earRoom, and shutEar which takes the dark off as the sheet starts down).

   Nothing under it is pressable while it is dark, which is what the glass
   means, and while it is clear it must not eat a single press. */
body.on-ear::before {
  content: ""; position: fixed; inset: 0; z-index: 59;
  background: rgba(23, 32, 42, .35);
  opacity: 0; pointer-events: none;
  transition: opacity .22s ease;
}
body.ear-dark::before { opacity: 1; pointer-events: auto; }
/* THE GLASS COMES ON RATHER THAN BEING ON. The page is given it in the same
   breath as the band is built, so the first style it is ever drawn with is the
   dark one, and a transition from a style nothing was ever drawn with does not
   run: the page would snap dark under a sheet still sliding up. This is where
   it is told what it came from. A browser that does not know the rule loses
   the fade and nothing else. */
@starting-style {
  body.ear-dark::before { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ear { animation: none; transition: none; }
  body.on-ear::before { transition: none; }
}
/* Room under the song for the band standing over it, so the last line of a
   song is a line you can read rather than one behind the glass. */
body.on-ear { padding-bottom: 196px; }

/* THERE WAS A LID HERE: two tabs, a loudness bar and a cross, thirty pixels of
   row standing over the song for as long as the microphone was open. All of it
   is gone (see buildEar in app.js).

   THE TABS, because there are two doors now and each opens its own side: the
   fork in the bar asks about one string, the red button on the song asks about
   the chords. THE BAR, because "is the microphone reaching the page" is
   answered better by the panel under it: a note that moves IS the microphone
   working. THE CROSS, because a panel over the page is closed by pressing the
   page, which is what every other panel in this app does. */

.ear-body { padding-bottom: 6px; }

/* ==========================================================================
   THE TUNER.

   Left to right, always. Flat is on the left and sharp is on the right on
   every tuner that has ever been made, and a Hebrew page is not a reason to be
   the one that is the other way round: this is a picture of a needle, not a
   sentence.
   ========================================================================== */
.tune { max-width: 420px; margin-inline: auto; text-align: center; }

/* THE ROW THE NOTE GOES IN, AND IT IS NOT THERE UNTIL THERE IS ONE. Its height
   is the height of a forty pixel letter, and with nothing plucked yet it is a
   band of empty white over the dial. It is made when the first note lands and
   kept from then on (see paintTune), so the panel opens with the standard gap
   its own padding gives it and does not breathe between one pluck and the
   next. */
.tune-read {
  display: flex; align-items: baseline; justify-content: center; gap: 4px;
  height: 0; overflow: hidden;
}
.tune.has-read .tune-read { height: 46px; }
/* The note, in the size the whole panel exists to show. A tuner is read from
   across a room, at a glance, by somebody whose hands are busy. */
.tune-name { font-family: var(--chord-font); font-size: 40px; font-weight: 700; line-height: 1; }
.tune-oct { font-size: 15px; color: var(--ink-soft); }
/* How far off, in cents, off to one side. It is the number that says what to
   do next, and it is smaller than the note because the note is what you are
   looking for and this is only how the search is going. */
.tune-cents {
  margin-inline-start: 10px; min-width: 40px; text-align: start;
  font-size: 17px; font-variant-numeric: tabular-nums; color: var(--ink-soft);
}
.tune.is-true .tune-name, .tune.is-true .tune-cents { color: var(--accent); }
.tune.is-quiet .tune-name { color: var(--line); }

/* --- THE DIAL --------------------------------------------------------------
   A line with a mark in the middle, and the needle on it. Not a rotating
   pointer: what is being shown is one number between minus fifty and plus
   fifty, a straight line is what that number is, and a round dial face would
   be a drawing of an instrument rather than a reading. */
.tune-dial {
  position: relative; height: 26px; margin: 2px 0 10px;
  border-radius: 13px; background: var(--bg); border: 1px solid var(--line);
}
/* In tune is a BAND and not a point, and the band is drawn: five cents either
   way is under what an ear hears on a strummed chord, so a needle anywhere in
   it is a string that is done. Without it the target is a hairline and nobody
   is ever finished. */
/* THE BAND AND THE NEEDLE SAY THE SAME THING IN TWO SIZES, and they say it in
   the two colours this app already has: green once the string is there, red
   while it is not. The band is the pale one of the pair and the needle is the
   full one, so the answer is readable across a room and exact up close.

   And grey while nothing is being heard. Red is what "not yet" looks like, and
   a panel that opens red is telling somebody a string is wrong before they have
   played one. */
.tune-dial::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 45%; width: 10%;
  background: var(--chord-soft); border-radius: 4px;
}
.tune.is-true .tune-dial::before { background: var(--accent-soft); }
.tune.is-quiet .tune-dial::before { background: var(--line); }
/* There is no mark down the middle. The band IS the mark, and a second one
   inside it was a target nobody can hit standing in front of the target
   everybody can (see buildTune). */
.tune-pin {
  position: absolute; top: -3px; bottom: -3px; left: 50%; width: 3px; margin-left: -1.5px;
  border-radius: 2px; background: var(--chord); transition: left .06s linear;
}
.tune.is-true .tune-pin { background: var(--accent); }
.tune.is-quiet .tune-pin { background: var(--line); }

/* The six open strings. Not a thing to press: a bottom E tuned all the way up
   to F is perfectly in tune and completely wrong, and the only thing on this
   panel that says so is which of these lit up. */
.tune-strings { display: flex; justify-content: center; gap: 6px; }
.peg {
  width: 30px; height: 26px; display: grid; place-items: center;
  font-family: var(--chord-font); font-size: 13px; font-weight: 700;
  color: var(--ink-soft); background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--corner);
}
.peg.is-on { color: #fff; background: var(--accent); border-color: var(--accent); }

/* ==========================================================================
   WHAT IT HEARS.

   Four things, in the order they are worth reading: the answer, what it nearly
   answered, the twelve numbers the answer is made of, and how those numbers
   score against the chords this song is actually written in.

   THE THIRD OF THOSE IS NOT DECORATION. A wrong answer over sensible bars and
   a wrong answer over mush are different faults with different fixes, and
   without the bars there is nothing to tell them apart by.
   ========================================================================== */
.ear-chord { max-width: 620px; margin-inline: auto; }

.heard { display: flex; align-items: baseline; gap: 10px; }
.heard-now {
  font-family: var(--chord-font); font-size: 30px; font-weight: 700;
  line-height: 1.1; color: var(--chord); min-width: 2ch;
}
.ear-chord.is-quiet .heard-now { color: var(--line); }
.heard-sure { font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
/* The runners up. A wrong answer with the right one a point behind it is a
   different report from a wrong answer that was never close, and the distance
   between those two is most of whether following a song can be made to work. */
.heard-also {
  font-family: var(--chord-font); font-size: 12px; color: var(--ink-soft);
  height: 16px; white-space: nowrap; overflow: hidden;
}

.chroma { display: flex; align-items: flex-end; gap: 3px; height: 54px; margin: 8px 0 4px; }
.cx { position: relative; flex: 1; height: 100%; display: flex; align-items: flex-end; }
.cx-fill { width: 100%; height: 0; background: var(--chord-soft); border-radius: 2px 2px 0 0; }
.cx-tag {
  position: absolute; inset-inline: 0; bottom: 0; text-align: center;
  font-family: var(--chord-font); font-size: 9px; color: var(--ink-soft);
}

/* --- THE SWITCH, AND WHAT IS BEHIND IT -------------------------------------
   The one thing on this tab that is not a measurement. Everything else says
   what the room sounds like; this says where in the song we are, and it is
   what the measurement was for. */
.ear-lead { display: flex; align-items: center; gap: 10px; padding-bottom: 4px; }
.ear-go {
  appearance: none; cursor: pointer; font: inherit; font-size: 13px;
  padding: 5px 12px; border-radius: var(--corner);
  color: var(--ink); background: #fff; border: 1px solid var(--line);
}
.ear-go:hover { border-color: var(--accent); }
.ear-go.is-on { color: #fff; background: var(--accent); border-color: var(--accent); }
.ear-at { flex: 1; font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
/* The way back to the measurement, and only while the measurement is put away:
   when the whole of it is on screen there is nothing to ask for. */
.ear-peek {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px;
  border: 0; background: none; color: var(--ink-soft); padding: 4px 6px;
  border-radius: var(--corner); display: none;
}
.ear-peek:hover { background: var(--bg); color: var(--ink); }
.ear-chord.is-following .ear-peek { display: block; }
.ear-chord.is-shown .ear-peek { color: var(--ink); }
/* WHILE IT IS FOLLOWING THE BAND IS ONE ROW, because what is being looked at
   is the song. The measurement is a press away for whoever wants to see why it
   did what it did, and it is in nobody's way until then. */
body.ear-small .ear-work { display: none; }
body.on-ear.ear-small { padding-bottom: 78px; }

/* --- AND THE SONG'S OWN CHORDS ---------------------------------------------
   The only part of this panel that is about the song rather than about the
   room, and the one that answers the real question. Naming a chord out of all
   of them is a hard problem; choosing between the eight a song is written in
   is a much easier one, and this is where you can see how much easier.

   IN THE SONG'S ORDER AND NEVER SORTED BY SCORE. A list that rearranges itself
   twenty times a second cannot be read at all, and what is being asked of it
   is not which is winning, which is written at the top in letters twice this
   size, but how far apart they are. */
.ear-mine { margin: 6px 0 4px; }
.mine-row { display: flex; align-items: center; gap: 8px; height: 18px; }
.mine-name {
  width: 52px; flex: none; text-align: end;
  font-family: var(--chord-font); font-size: 12px; font-weight: 700; color: var(--chord);
}
.mine-bar { flex: 1; height: 6px; border-radius: 3px; background: var(--bg); overflow: hidden; }
.mine-fill { display: block; height: 100%; width: 0; background: var(--line); transition: width .08s linear; }
.mine-row.is-top .mine-fill { background: var(--accent); }
.mine-num {
  width: 24px; flex: none; text-align: start;
  font-size: 11px; color: var(--ink-soft); font-variant-numeric: tabular-nums;
}

/* What it heard, in the order it heard it. The measurement no single frame can
   show: a page that follows the playing is a page that gets this sequence
   right, and reading it back against the song is how you find out whether it
   would have. */
.ear-tape {
  font-family: var(--chord-font); font-size: 12px; color: var(--ink-soft);
  height: 17px; white-space: nowrap; overflow: hidden; direction: ltr;
  border-top: 1px solid var(--line); padding-top: 4px; margin-top: 4px;
}

/* --- AND ON THE SONG ITSELF ------------------------------------------------
   Every place in the song written with the chord being heard, lit at once.
   Which is NOT following the song and does not pretend to be: what it shows is
   how many places the sound is consistent with, and that count IS the
   difficulty of the following. Four chords repeated four times lights sixteen
   marks, and nothing in the sound will ever choose between them.

   A shadow and a background, and no padding, because a chord label carries
   none: its box is exactly its glyphs and the placing measures that box (see
   .chord). A pixel of padding would move every chord on the line.

   --- AND THE MARK RISES BY EXACTLY WHAT IT GREW BY ---------------------------
   The lane is deliberately short, so a chord's foot stands about a pixel into
   the top of the letters' own box: that is what keeps a chord attached to the
   syllable it names (see .ln-c). Which leaves nothing underneath for a halo to
   grow into, and three pixels of it came down on the words.
   So the mark is lifted by its own spread. The floor of the pill lands where
   the floor of the bare glyphs was, the whole of it grows UPWARD into the air
   the previous line was leaving empty anyway, and the chord goes on naming the
   letter it was naming. Lifted and not padded: padding is in the box and the
   placing measures the box, so a padded chord would move sideways too. */
/* The lift belongs to the mark that is drawn, and `is-at` is not drawn any
   more (see below): lifting a chord that looks exactly like every other chord
   is a letter that moves for no reason anybody can see. */
.chord.is-heard { transform: translateY(-3px); }
.chord.is-heard {
  background: var(--chord-soft);
  box-shadow: 0 0 0 3px var(--chord-soft);
  border-radius: 3px;
}
/* --- AND WHILE A TAKE IS RUNNING, ONE CHORD CARRIES A RING -----------------
   The arithmetic's own answer, on the one chord it is about (see markSounding
   in app.js), standing beside the band that says where the MARK is. The two
   are allowed to disagree and the disagreement is the whole reason to draw
   both: a ring ahead of the band is the page catching up with the playing, and
   a ring the band never reaches is the failure that used to be invisible.

   THE CHORD ITSELF AND NOT A BOX ROUND IT. A box was the first drawing and it
   was wrong twice: it lands inside the band, which is the one place it has to
   be readable, and a rectangle round two letters at a reading size is mostly
   rectangle. What is being pointed at is a chord, so the picture is the chord.

   BIGGER AND DARKER, AND NOT BOLDER, because a chord is already at 700 and
   most of what --chord-font resolves to on a phone has nothing above it: a
   weight that is not there is a mark that does not appear, and this is the one
   mark that must never fail to. A tenth more size and the deeper of the two
   inks the chords are written in are both there in any font.

   AND IT IS A TRANSFORM AND NOT A FONT SIZE, which is what keeps it over its
   own syllable. A chord is CENTRED on the character it names (see planLine in
   app.js) and its place on the line was measured and written at the size it
   was: growing the type would widen the box from a left edge that is already
   fixed, and the label would slide off its letter by half of what it gained. A
   scale grows it about its own middle, which is the anchor, so it stays where
   it was pointing and the tick under it grows with it.

   UPWARDS, because the room above a chord is room the line's own leading
   leaves empty anyway, and the room below it is the words. */
.chord.is-sounding {
  color: var(--chord-ink);
  transform: scale(1.14);
  transform-origin: 50% 100%;
}

/* --- AND WHERE WE ARE, WHICH IS DRAWN ON THE LINE AND NOT ON THE CHORD -----
   `.chord.is-at` HAS NO PICTURE, on purpose. It was a filled chord, in the ink
   the chords are already in, and it was the thing being looked for: a mark on
   one chord is exact and it is a few millimetres across, on a page held at
   arm's length by somebody whose hands are on a guitar. Two marks a bar, each
   of which has to be FOUND, is the work the following was supposed to save.

   So the answer stays on the chord in the page, because that is where the
   follower's answer belongs and everything downstream reads it there, and what
   is DRAWN is the band across its line below. One answer, one picture, and the
   picture is the size of the thing being read. */
/* It moves several times a bar, so it arrives rather than appears: a mark that
   blinks from place to place at that rate reads as flicker, and the eye finds
   a thing that faded in where a thing that snapped in has to be searched for. */
@media (prefers-reduced-motion: no-preference) {
  .chord { transition: background-color .12s linear, color .12s linear, box-shadow .12s linear, transform .12s linear; }
}

/* --- AND THE LINE THE MARK IS ON ------------------------------------------
   A mark on one chord is precise and it is small, and small is the wrong thing
   to be on a page held at arm's length by somebody whose hands are on a
   guitar: finding it means looking for it. A whole line lit is caught without
   hunting, and catching it is already knowing which words are being sung. The
   chord inside it stays, because the line cannot say which beat of itself we
   are on.

   BEHIND THE ROW AND NOT ON THE WORDS. A band drawn behind the pair, chords
   and words together, is what makes it read as one line of a song; colouring
   the letters instead would be a second kind of ink on a page that already
   uses ink to mean chord. It bleeds a little past the words on both sides so
   that it is a band and not a box drawn tight around a sentence.

   AND THE SAME AIR ABOVE THE CHORDS AS BELOW THE WORDS. A pixel either side of
   the row is a pixel either side of the BOX, and the box is not the ink: the
   words carry their own half leading and a descender's worth of room under
   them, and the chord is set at line-height 1 and starts almost at the top
   edge. So the same number top and bottom drew a band that sat on the chords
   and floated under the words, which reads as a band that has slipped.

   Measured, at a reading size and in the fonts this page actually uses: about
   two and a half pixels of air over the chord against about seven under the
   letters, at eighteen. The difference is a third of a size, and it is spent
   here, upwards, into room the line above was not using. */
.ln.is-here::before {
  content: "";
  position: absolute;
  inset: calc(var(--song-size) * -.32) -10px -1px;
  background: var(--chord-soft);
  border-radius: 9px;
  pointer-events: none;
}
/* --- AND IT IS THE WIDTH OF THE LINE, NOT THE WIDTH OF THE PAGE -----------
   A row is a block, so its box runs to the far edge of the segment however
   few words are written on it, and a band drawn on that box is a stripe
   across the page with a line of a song at one end of it. What is being
   pointed at is the line, so the picture is the shape of the line: the words,
   the chords over them, and a little air past both ends.

   The row being lit shrinks to what is written on it, and nothing moves for
   it. The box keeps its start edge, which is the right one in a Hebrew song
   and the left one in a Latin one, and every chord is placed from that same
   edge (see metrics in app.js), so the only thing that changes is where the
   box ENDS.

   ONLY WHERE THE SONG IS BEING READ. In the editor the room past the end of a
   line is what a caret is put with and what a chord is pressed onto (see the
   lane's height on a phone), and a row that ends where its words do is a row
   with nothing to press after them. */
.sheet:not(.ed) .ln.is-here { width: fit-content; }
/* The room above is the chord lane's, and a page of words alone has no lane:
   the rows sit straight on top of each other there (see .paper.words), so the
   third of a size would be spent on the line before instead. What is left is
   the words' own leading, which is even at both ends to begin with. */
.paper.words .ln.is-here::before {
  inset: -1px -10px;
}
/* The row's own contents come back over it: the band is behind the line, and
   `.ln` is already a positioned box (see above) so this is the whole of it. */
.ln.is-here > * { position: relative; }

@media (prefers-reduced-motion: no-preference) {
  .ln::before { transition: opacity .16s linear; }
}

/* ==========================================================================
   RECORDING, and what says so.

   THE RED IS ON THE MICROPHONE. Somebody playing needs to know they are being
   recorded from the other side of a room, without reading anything, so the
   picture they pressed to start listening is the picture that says it is
   listening, and the same one goes red while it is being kept.

   The pulse is what makes it a state rather than a colour. A red dot that does
   not move reads as a decoration; one that breathes reads as live, and that is
   the whole difference between "there is a microphone here" and "it is on".
   ========================================================================== */
/* --- THE ONE BUTTON, AND THE THREE THINGS IT IS ----------------------------
   Not started, and it records. Running, and it holds. Held, and it carries on,
   with the one thing it cannot mean standing beside it.

   FILLED, ROUND, AND IN THE INK THE CHORDS ARE IN, in all three. It is the
   whole of the way in and the only thing in this strip that starts anything;
   everything else here is a setting, drawn quiet on purpose, because a setting
   is read far more often than it is pressed. And it is the size of the buttons
   in the bar above rather than of the dials beside it, so the two rows line up
   down the edge of the page. */
.tape-bar .icon-btn.is-rec {
  width: 34px; height: 34px; border-radius: 999px;
  color: #fff; background: var(--chord); border-color: var(--chord);
  box-shadow: 0 1px 4px rgba(225, 29, 99, .32);
}
.tape-bar .icon-btn.is-rec svg { width: var(--transport); height: var(--transport); }

/* --- THERE WAS A MICROPHONE ON THE CORNER OF THIS BUTTON -------------------
   A mark the size of a notification dot, meaning a take had been made, was on
   this device and nowhere else, and a press here would ask what to do with it.

   IT IS GONE, AND SO IS THE QUESTION BEHIND IT. A recording belongs with the
   recordings: it is a row on the sheet behind the three dots now (see
   .take.is-draft), and what says so from the bar is the mark beside those dots
   (see .more-yet). This button starts a recording and does nothing else, which
   is what a filled circle with a note in it should have meant all along. */
.tape-bar .icon-btn.is-rec:hover {
  color: #fff; background: #c2185b; border-color: #c2185b;
  box-shadow: 0 2px 7px rgba(225, 29, 99, .45);
}
/* And while it is running it breathes, which is the difference between "there
   is a recording here" and "it is going". Nothing else on the page has to say
   so, and nothing else does. */
.tape-bar .icon-btn.is-rec.is-taping { animation: on-air 1.6s ease-in-out infinite; }

/* --- AND WHERE IT STANDS ONCE THE HEADER HAS GONE --------------------------
   In exactly the place it was standing a moment earlier. The header slides up
   and off while a take is running (see body.on-air) and this is the one thing
   in it that is being used, because it is the way to stop: what happens is
   that everything around it leaves, not that it moves.

   Which is why the two numbers are read off the screen rather than written
   here. The top is where the button already was, and the side is the gutter
   the header keeps, so nothing shifts by a pixel at the moment the row it was
   standing in goes (see airRoom). */
.tape-bar.is-air {
  position: fixed; z-index: 30;
  top: var(--air-top, 13px);
  inset-inline-end: 16px;
}

/* ==========================================================================
   THE PLAYER AT THE FOOT OF THE SCREEN.

   A recording that plays with nothing on screen is a recording nobody can do
   anything with: no way to see how far in it is, no way to go back ten
   seconds, and no way to stop it except finding again the one row out of fifty
   whose button started it.

   AND IT IS A PANEL, WEARING WHAT EVERY PANEL HERE WEARS. It was a strip laid
   along the foot of the page: no bar across the top, nothing dark behind it,
   and the list still live underneath, so it read as part of the page rather
   than as something that had come up over it and could be sent back down. A
   thing that can be put away has to say so, and here that is said one way and
   one way only (see .dlg and .grip): the bar, the dark, and the three ways out.

   So the shape is not written here. It is a dialog like the rest, and what is
   left for this block is what is ON it: the name, the player and the way out.
   ========================================================================== */
.dock-in {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  /* the bar across the top is the room at the top now */
  padding-top: 0;
  /* AND A FINGER ON IT IS PUSHING IT, NEVER SCROLLING. There is nothing here to
     scroll, the panel is three things on one line, but a browser that has not
     been told so reads a downward drag as a scroll it might have to make and
     takes the touch back mid push (see gripUp). Said on the row and not on the
     panel, so the player keeps its own, which is a drag along a bar. */
  touch-action: none;
}
.dock-in .dock-play { touch-action: auto; }
/* The name of the song is the way to it: somebody listening to a recording is
   somebody halfway to wanting the song, and it is already written here on the
   one part of the screen that is not going anywhere. */
.dock-said {
  appearance: none; border: 0; background: none; cursor: pointer; font: inherit;
  flex: 1 1 160px; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  text-align: start; padding: 4px 6px; margin-inline-start: -6px;
  border-radius: var(--corner);
}
.dock-said:hover { background: var(--bg); }
.dock-name {
  font-weight: 700; font-size: 15px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dock-who {
  font-size: 12px; color: var(--ink-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* --- A PLAYER IS A LEFT TO RIGHT INSTRUMENT --------------------------------
   Play, then the time gone, then the bar, then the time left: that is the
   order on every machine that has ever played anything, and a page that runs
   the other way was flipping it. The controls are drawn by the browser out of
   parts this stylesheet cannot reach, so what a mirrored one actually did was
   fill the bar from the far end and slide its own pieces about as the elapsed
   time grew a digit.

   The same exception the chord labels live under (see .chord): Latin text and
   Latin machinery inside a Hebrew page carry their own direction, and it is
   said on them rather than left to be inherited. */
.dock .dock-play, .take-play { direction: ltr; }
.dock .dock-play { flex: 2 1 240px; height: 36px; min-width: 0; }
.dock-x { flex: none; }
/* NOTHING IS ASKED OF THE PAGE UNDERNEATH ANY MORE. A strip fixed over the
   foot of a list hides the last row of it, so the page used to be given the
   room back; a panel standing over the page with the dark behind it takes
   nothing from the page, and shifting the list under the dark would be a jump
   nobody asked for. */
/* On a phone the name and the player each want the width, so they take a line
   each rather than squeezing into one and giving neither enough. */
@media (max-width: 620px) {
  .dock-said { flex-basis: 100%; }
  .dock .dock-play { flex-basis: calc(100% - 46px); }
}

/* ==========================================================================
   THE TAKES OF A SONG.

   Under the words, where the words end. A take is not what somebody came to
   the page for, so it does not stand between them and the song; it is worth
   finding when they get to the bottom, so that is where it is.
   ========================================================================== */
/* IT COMES UP FROM THE BOTTOM, AND ONLY WHEN IT IS ASKED FOR. It stood under
   the words, at the end of the song, which is a fine place for something
   nobody came for and a bad place for something somebody wants: the way to a
   recording was to scroll the whole song past. And it was there on every song
   whether or not anybody was looking for it, taking the foot of the page.

   So it is a sheet that rises over the song from the edge it is nearest, the
   way a phone offers a handful of choices, and it is opened by name from the
   panel behind the three dots. It is closed the way every other panel here is:
   a press on the page, Escape, or a push downwards.

   Fixed to the bottom rather than to a scroll position: what is under it is
   the song, and the song is what somebody is reading while the recording
   plays. */
/* AND THE SONG IS GIVEN THE ROOM THE SHEET TOOK. Nothing is dark behind this
   one, so the page under it is still being read, and a sheet standing over the
   foot of it hides the last verse. The room is the height of the sheet, which
   is measured while it is open (see roomForTakes) because the sheet is one row
   while a recording plays and a list when it stops. The number here is only
   what stands where a browser cannot measure. */
body.on-takes { padding-bottom: var(--takes-room, 240px); }
.takes {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 62;
  max-height: min(70vh, 560px); overflow-y: auto;
  padding: 6px 16px calc(18px + env(safe-area-inset-bottom));
  background: var(--card); border-top: 1px solid var(--line);
  border-start-start-radius: 18px; border-start-end-radius: 18px;
  box-shadow: 0 -6px 26px rgba(23, 32, 42, .16);
  transform: translateY(100%); transition: transform .18s ease-out;
}
.takes.is-open { transform: none; }
.takes:empty, .takes[hidden] { display: none; }
/* NOTHING IN IT TO SCROLL, SO A FINGER ON IT IS PUSHING IT DOWN. Said only
   while that is true, which is decided by measurement (see roomForTakes): a
   sheet with more recordings than fit keeps the drag for its own scrolling,
   and is pushed down by the bar. */
.takes.is-still { touch-action: none; }
.takes.is-still .take-play { touch-action: auto; }
/* THE HANDLE IS THE ONE EVERY SHEET HERE HAS (see .grip). It used to be drawn
   here and nothing else: a bar that said the sheet could be pushed back down,
   over a sheet that could not be. */
.takes-head {
  font-size: 15px; color: var(--ink-soft); font-weight: 600;
  margin: 0 0 10px; padding-inline-start: 2px;
}
/* ONE OF THEM IS PLAYING, SO ONE OF THEM IS ON THE SHEET. A row of takes with
   a sound coming out of one is a list somebody has to read to find out which,
   and the answer is the only thing on it worth looking at while it plays. The
   rest are not removed, only put away: pausing brings them back. */
.takes-list.is-one .take { display: none; }
.takes-list.is-one .take.is-playing { display: flex; }
.takes-list { display: flex; flex-direction: column; gap: 8px; }

.take {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card);
}
.take-go { flex: none; width: 34px; height: 34px; border-radius: 999px; }
.take-go svg { width: var(--transport); height: var(--transport); }
/* --- AND THE WORDS ARE NEVER THE THING THAT GIVES WAY ----------------------
   This was `min-width: 0`, which is the usual thing to write beside `flex: 1`
   and was exactly wrong here. The row wraps, and a wrapping row only moves
   something down to the next line when what is on it cannot be made narrower;
   `min-width: 0` says the words CAN, so the browser took the whole row's
   shortfall out of them rather than wrapping anything. On a phone with a chip,
   a button and a bin on the same row that left about a centimetre for the
   name, and "הקלטה חדשה" came down the sheet one word per line.

   So the words are given a floor. Whatever does not fit beside them goes to
   the next line, which is what the wrap was for. */
.take-said { flex: 1; min-width: 9rem; display: flex; flex-direction: column; gap: 3px; }
/* The name and where the recording stands, side by side: one is who played it
   and the other is who can hear it, which is one sentence. */
.take-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.take-who { font-size: 14px; color: var(--ink); font-weight: 600; }
.take-when { font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
/* A take is a sound at a pitch and the page is a drawing that moves, so a
   reader who has taken the song down two is about to hear something that does
   not agree with the chords in front of them. Said, never prevented. */
.take-off {
  flex: none; font-size: 11px; color: var(--ink-soft);
  padding: 2px 8px; border-radius: 999px; background: var(--bg);
}
.take-pass { flex: none; }
.take-out.is-on { color: var(--accent); border-color: var(--accent); background: #eefaf7; }
.take-play { width: 100%; height: 34px; margin-top: 2px; }
.take.is-mine { border-color: var(--chord-soft); }

/* --- AND THE ONE THAT IS ONLY ON THIS DEVICE ------------------------------
   The recording that has been made and not kept (see draftRow in app.js). It
   stands at the top of the same list, in the same shape as the rest, and the
   one thing that separates it is the colour: the yellow this app writes "not
   published" in, on its edge and on the triangle that plays it, which is the
   same mark the dots above are wearing while it is there (see .more-yet).

   A LINE AND A TRIANGLE, AND NOT A FILL. A yellow card in a column of white
   ones reads as a warning, and there is nothing wrong here: a draft is the
   ordinary state of a take a minute after it was played, and it survives the
   tab, the reload and the closed phone. The edge says which row it is; it does
   not say anything has gone wrong. */
.take.is-draft { border-color: var(--state-mark); }
.take.is-draft .take-go { color: var(--state-mark); border-color: var(--state-mark); }
/* The word beside it, in the same small print "בסולם אחר" is in, because it is
   the same kind of thing: one line about this recording that is not the
   ordinary case. In the state's own ink, so the row says it twice in one
   colour rather than in two. */
/* --- WHERE A RECORDING OF YOURS STANDS, IN ONE WORD -------------------------
   Beside the name, inside the column of words, and never in the row itself:
   the row is a play button, a name, a date and up to three controls, and a
   chip among them is the thing that pushes a control down onto a second line
   (see .take-line).

   Smaller than the name it stands beside and not as small as the date under
   it: it is a fact about the recording rather than a heading, and it has to be
   readable at arm's length by somebody deciding whether to take it down. */
.take-mark {
  font-size: 11px; font-weight: 600; white-space: nowrap;
  padding: 2px 8px; border-radius: 999px;
  color: var(--ink-soft); background: var(--bg);
}
/* NOT PUBLISHED, in the yellow this app writes every "not out yet" in: the
   draft on the device, and a saved take nobody has offered. The middle case,
   a recording that is out on a song that is not, is yellow too, because from
   a listener's side it is the same fact: nobody can hear it. */
.take-yet { color: var(--state-ink); background: var(--state-soft); }
/* AND THE OTHER END OF THE SAME SENTENCE: a recording of yours that anybody
   with the link can hear. In the app's green, which is the colour of the ring
   round the button that put it there, so the word and the control that takes
   it back are read as one thing (see .take-out.is-on). */
.take-is-out { color: var(--accent); background: #eefaf7; }

/* AND A SENTENCE IS NOT A CHIP. Why the recording cannot be kept is a line of
   prose, and a line of prose squeezed in beside a play button, a chip and a
   bin is four things fighting over one row. It takes the whole width and
   therefore its own line, under the row it is about, which is where a note
   about something goes. */
.take-note {
  flex-basis: 100%; margin: 2px 0 0;
  font-size: 12px; color: var(--ink-soft);
}

/* In the panel that offers the take, where it is the one thing on the page and
   gets the whole width of it. */
.dlg-in .take-play { margin: 10px 0 4px; }

/* The one line above it. The panel is opened by a press on the mark over the
   song, which may be a day and a closed phone after the recording was made, so
   it says what the recording is and where it is before anything is asked about
   it. Quiet, because the take under it is the thing being looked at. */
.dlg-in .take-says { color: var(--ink-soft); line-height: 1.5; }

/* Both doors are toggles and both say so, in the two places they stand.

   IN THE RED, AND NOT IN THE APP'S GREEN. What is behind either of them is a
   microphone that is listening, which is the one thing in here that is not the
   app doing something for you but the app taking something in. Red is the
   colour that already means that: it is the chords' red and it is the colour
   of the button that records. Green here read as another thing switched on.

   This is the soft red, for a door standing among the words, where a filled
   box would be the loudest thing on the page. The fork in the bar is filled
   red whether it is listening or not, and darkens instead (see
   .icon-btn.tuner), which is written above and outranks this. */
.tools .ear-door.is-on, .top-actions .icon-btn.is-on {
  color: var(--chord); border-color: var(--chord); background: var(--chord-soft);
}

/* On a phone the band is most of the screen if it is allowed to be, so what
   goes is what is furthest from the point: the runners up are for somebody
   sitting down with this to find out whether it works, and that is not being
   done one handed on a bus. */
@media (max-width: 620px) {
  body.on-ear { padding-bottom: 200px; }
  .ear-chord .heard-also { display: none; }
  .chroma { height: 44px; }
}
