/* ============================================================
   PSALM DRONE
   ------------------------------------------------------------
   One stylesheet. The palette is the Collect Workshop's, which is
   thecommonwild.org's -- cream stock, warm near-black, one earth
   accent -- taken over wholesale rather than approximated, so the
   three workshop tools are recognisably one set of hands.

   The proof-of-concept had its own rubric red for the sounding
   state. It was close enough to the site accent to be a near-miss
   rather than a decision, so it is gone; --accent does that work
   now and happens to be the right colour for it anyway, a rubric
   being red by definition.

   Light-first, like the Collect Workshop and unlike Kalendar. The
   bare :root block below is a fallback that in practice nobody
   sees: this tool needs JavaScript to make any sound at all, and
   src/theme.js always writes an explicit data-theme before paint.
   ============================================================ */

:root {
  --paper: #f5f1e8;
  --paper-2: #efeade;
  --paper-3: #e7e1d2;
  --ink: #211c17;
  --ink-muted: #6f665b;
  --ink-faint: #9a9084;
  --rule: #d8d1c1;
  --accent: #8a3b1e;
  --accent-deep: #6e2f17;

  --measure: 33rem;
  --gutter: clamp(1rem, 4vw, 2rem);
  --serif: ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino,
           "Book Antiqua", Charter, Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  color-scheme: light;
}

/* The same design lit from the other side. Only the neutrals move.
   Written as an attribute rather than a media query for the reason given
   above: theme.js resolves the system preference itself and always writes
   an explicit value, so the palette lives in one block instead of two that
   have to be kept identical. */
:root[data-theme="dark"] {
  --paper: #171512;
  --paper-2: #1e1b17;
  --paper-3: #26221d;
  --ink: #e8e2d6;
  --ink-muted: #a49a8c;
  --ink-faint: #756c60;
  --rule: #35302a;
  --accent: #d98a63;
  --accent-deep: #e8a884;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

main {
  max-width: var(--measure);
  margin: 0 auto;
  /* env() so the controls clear the home indicator when this is run
     full-screen from a phone's home screen, which is the intended way. */
  padding: 1.8rem var(--gutter) calc(3rem + env(safe-area-inset-bottom));
}

a { color: var(--accent); }
a:hover { color: var(--accent-deep); }

.titlerow { display: flex; align-items: center; gap: .75rem; }
h1 {
  font-size: 1.05rem; font-weight: 600; letter-spacing: .01em;
  margin: 0; flex: 1 1 auto;
}
.standfirst { margin: .15rem 0 2rem; color: var(--ink-muted); font-size: .95rem; }

/* The theme button. Not a control of the instrument, so it keeps to the
   corner and to the faint end of the palette until you point at it. Same
   pill as the Collect Workshop's, which is where readers of both will
   already have found it. */
.themebtn {
  font-family: var(--sans); font-size: .72rem; letter-spacing: .04em;
  border: 1px solid var(--rule); border-radius: 999px;
  padding: .15rem .6rem; background: none; color: var(--ink-faint);
  cursor: pointer; flex: 0 0 auto;
}
.themebtn:hover { color: var(--accent); border-color: var(--accent); }

/* --- the held tone ----------------------------------------------------- */
.tone { display: flex; align-items: baseline; gap: .9rem; margin-bottom: .4rem; }
.tone-name {
  font-size: clamp(4.2rem, 20vw, 6rem);
  line-height: .82; font-weight: 400;
  font-variant-numeric: lining-nums;
  letter-spacing: -.02em; white-space: nowrap;
}
.tone-name sub {
  font-size: .3em; color: var(--ink-faint);
  vertical-align: baseline; position: relative; top: -.15em; left: .06em;
}

/* The one moving thing on the page, and the only indication visible from
   across a room. Grey and still when silent, accent and breathing when
   sounding. The sound drifts without a period (see src/audio.js), so the
   stroke does too, near enough: its brightness and its thickness move on
   two cycles, 17 and 23 seconds, that only line up again every six and a
   half minutes. */
.stroke {
  flex: 1; height: 3px; background: var(--rule);
  position: relative; top: -.55rem;
  transition: background-color .9s ease;
}
/* will-change guarantees the compositor gives this its own layer, so the
   breath is a transform on an existing texture rather than a repaint of the
   strip every frame. Scoped to .sounding: a promoted layer costs memory, and
   there is no reason to hold one for a static grey rule. */
body.sounding .stroke {
  background: var(--accent);
  animation: glow 17s ease-in-out infinite, swell 23s ease-in-out infinite;
  will-change: transform, opacity;
}
@keyframes glow {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}
@keyframes swell {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(2); }
}
@media (prefers-reduced-motion: reduce) {
  body.sounding .stroke { animation: none; opacity: 1; }
}

.hz {
  color: var(--ink-muted); font-family: var(--sans); font-size: .82rem;
  margin: 0 0 .5rem;
}

/* --- the psalm tone ------------------------------------------------------
   One button a note, in order. These are an instrument, not a form: large,
   and painted in --accent only while a note is actually sounding, because
   that colour means "sounding" everywhere else in this app. The note being
   edited below is outlined, which is a different thing and looks like one. */
.strip {
  display: flex; flex-wrap: wrap; align-items: stretch; gap: .3rem;
  margin: .6rem 0 .35rem;
}
.pill {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 3.6rem; min-height: 3.6rem; padding: .35rem .55rem .3rem;
  flex: 0 1 auto;
  font: inherit; color: var(--ink); background: var(--paper-2);
  border: 1px solid var(--rule); border-radius: 3px; cursor: pointer;
  /* An instrument key: no scrolling from it, no double-tap zoom, no text
     selection or callout menu under a held finger. */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.pill:hover { border-color: var(--ink-muted); }
.pill.sel { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.pill.held { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.pill.held .pill-role, .pill.held .pill-note sub, .pill.held .pill-key { color: inherit; opacity: .8; }
.pill-note {
  font-size: 1.45rem; line-height: 1.05;
  font-variant-numeric: lining-nums;
}
.pill-note sub { font-size: .5em; color: var(--ink-faint); vertical-align: baseline; }
.flexpill { border-style: dashed; }
.pill-role {
  font-family: var(--sans); font-size: .64rem; letter-spacing: .04em;
  color: var(--ink-muted); margin-top: .1rem;
}
/* Two marks in the corners: the interval from the drone top right, where
   a superscript goes, and the keyboard digit top left, on a keyboard only. */
.pill-key {
  position: absolute; top: .15rem; left: .3rem;
  font-family: var(--sans); font-size: .58rem; color: var(--ink-faint);
}
.pill-int {
  position: absolute; top: .12rem; right: .28rem;
  font-family: var(--sans); font-size: .6rem; letter-spacing: .01em;
  color: var(--accent);
}
.pill.held .pill-int { color: inherit; opacity: .85; }
/* Room at the top for the two corner marks, so they sit above the note
   rather than beside it; narrow enough sideways that a tone with a flex --
   five buttons -- still fits one row on a phone. */
.pill { min-width: 3.3rem; padding: .8rem .4rem .3rem; }
.strip-break {
  align-self: center; padding: 0 .1rem;
  font-size: 1.4rem; color: var(--ink-faint);
}
.strip-hint { margin: 0 0 1.4rem; }
.strip-hint kbd {
  font-family: var(--sans); font-size: .95em;
  border: 1px solid var(--rule); border-radius: 3px; padding: 0 .3em;
}

/* Instructions for a keyboard are noise on a phone, and "tap" is wrong
   with a mouse. Whichever the device has a fine pointer that can hover is
   taken to have a keyboard too, which is right often enough. */
.for-keys { display: none; }
@media (hover: hover) and (pointer: fine) {
  .for-keys { display: revert; }
  .pill-key.for-keys { display: block; }
  .for-touch { display: none; }
}

/* --- primary action ---------------------------------------------------- */
.sound {
  display: block; width: 100%; padding: 1.05rem;
  font: inherit; font-size: 1.1rem;
  color: var(--paper); background: var(--ink);
  border: none; border-radius: 2px; cursor: pointer;
  margin: .6rem 0 2.4rem;
}
body.sounding .sound { background: var(--accent); color: #fff; }
:root[data-theme="dark"] body.sounding .sound { color: #201a14; }

/* --- the deck, folded ------------------------------------------------------
   With a psalm open, the drone, the tone and the Sound button become one bar
   that stays at the top while the psalm scrolls beneath it: the note, the
   tone's buttons at a smaller size, and "Sound" without "the tone". The
   stroke goes -- the Sound button turning accent says the same thing in
   less room. */
body.psalm-mode .deck {
  position: sticky; top: 0; z-index: 3;
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: .6rem;
  margin: 0 calc(-1 * var(--gutter)) 1.2rem;
  padding: .5rem var(--gutter) .55rem;
  padding-top: calc(.5rem + env(safe-area-inset-top));
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
body.psalm-mode .deck .tone { margin: 0; }
body.psalm-mode .deck .tone-name { font-size: 2.1rem; }
body.psalm-mode .deck .stroke,
body.psalm-mode .deck .hz,
body.psalm-mode .deck .strip-hint,
body.psalm-mode .deck .pill-role,
body.psalm-mode .deck .long { display: none; }
body.psalm-mode .deck .strip { margin: 0; gap: .2rem; }
body.psalm-mode .deck .pill { min-width: 2.5rem; min-height: 2.5rem; padding: .2rem .35rem; }
body.psalm-mode .deck .pill-note { font-size: 1.05rem; }
body.psalm-mode .deck .pill-key { top: .05rem; left: .15rem; }
body.psalm-mode .deck .pill-int { top: .02rem; right: .12rem; font-size: .52rem; }
body.psalm-mode .deck .pill { min-width: 2.35rem; padding: .5rem .2rem .2rem; }
body.psalm-mode .deck .strip-break { font-size: 1rem; }
body.psalm-mode .deck .sound {
  width: auto; margin: 0; padding: .6rem .8rem; font-size: .95rem;
}

/* --- the psalm ------------------------------------------------------------
   Set as a psalter sets it: verse number in the margin, the half-verses as
   separate lines, the asterisk kept. Each cadence is underlined with its
   note written above it in ruby, the way a pointed psalter puts a mark over
   the syllable. The step you are on is shaded; the verse you are in has a
   rule in the margin. */
.psalm { scroll-margin-top: 6rem; }
.psalm textarea {
  width: 100%; min-height: 14rem; resize: vertical;
  font: inherit; font-size: .95rem; line-height: 1.5;
  color: var(--ink); background: var(--paper-2);
  border: 1px solid var(--rule); border-radius: 2px; padding: .6rem .7rem;
}
.psalm textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.psalm .hint strong { color: var(--ink-muted); }
.psalm #psalmEdit .row { margin-top: .7rem; }

/* The psalm's heading row holds more than a readout -- Point, Edit, the
   copy button -- and the copy button is taller than a line of text. As a
   float it hung down into the first verse and narrowed it, so this row is
   laid out as a row instead. */
#psalmShow > .label {
  display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; flex-wrap: wrap;
}
#psalmShow > .label .readout { float: none; text-align: right; }

.iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: middle; margin-left: .45rem;
  width: 1.9rem; height: 1.9rem; padding: 0;
  color: var(--ink-muted); background: none;
  border: 1px solid var(--rule); border-radius: 3px; cursor: pointer;
}
.iconbtn:hover { color: var(--accent); border-color: var(--accent); }
.copyout { margin-left: .4rem; color: var(--accent); }
.copyout:empty { display: none; }

.linkish {
  font: inherit; font-size: inherit; color: var(--accent);
  background: none; border: none; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: .15em;
}
.psalm-title {
  white-space: pre-line; font-style: italic; color: var(--ink-muted);
  margin: 0 0 .8rem;
}

.verse {
  display: grid; grid-template-columns: 1.6rem 1fr; gap: .2rem;
  padding: .35rem 0 .35rem .1rem; margin-left: -.1rem;
  border-left: 2px solid transparent;
}
.verse.current { border-left-color: var(--accent); }
.verse-num {
  font-family: var(--sans); font-size: .72rem; color: var(--ink-faint);
  padding-top: .55rem; text-align: right; padding-right: .35rem;
}
.half {
  margin: 0; white-space: pre-line; line-height: 1.9;
}
.half + .half { padding-left: 1.2rem; }
.star { color: var(--ink-faint); }

.seg {
  border-radius: 2px; cursor: pointer;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
.seg.cad { text-decoration: underline; text-decoration-color: var(--ink-faint); text-underline-offset: .2em; }
.seg.here { background: var(--paper-3); }
/* The flex is a drop, not a cadence: dotted, where a cadence is solid. */
.seg.flex { text-decoration-style: dotted; }
.seg.held { background: var(--accent); color: var(--paper); }
.seg.held rt, .seg.held rt sub { color: inherit; }
/* Centred, not spread: by default a browser stretches ruby across the whole
   word, which pulls "F♯3" apart into three separate marks. */
.seg ruby { ruby-align: center; }
.seg rt {
  ruby-align: center;
  font-family: var(--sans); font-size: .62rem; color: var(--accent);
  text-decoration: none; letter-spacing: .02em;
}
.seg rt sub { font-size: .8em; vertical-align: baseline; color: var(--ink-faint); }

/* The step buttons stay within reach of a thumb while the psalm scrolls. */
.psalmnav {
  position: sticky; bottom: 0; z-index: 2;
  display: flex; gap: .5rem;
  margin: .8rem calc(-1 * var(--gutter)) 0;
  padding: .6rem var(--gutter) calc(.6rem + env(safe-area-inset-bottom));
  background: var(--paper); border-top: 1px solid var(--rule);
}
.psalmnav .navgroup { display: flex; gap: .5rem; flex: 1; }
.psalmnav .chip { padding: .7rem 1rem; }
.psalmnav .next { flex: 1; }

/* --- pointing ---------------------------------------------------------------
   The same text, taken apart into words to tap. The cadence is underlined
   as in the ordinary view, and the word it begins on is marked more
   strongly, since that is the thing being set. Every line end offers an
   asterisk; the one in use is solid, the rest are ghosts of it. Taps here
   are clicks, not presses: nothing sounds, and a scroll is never a tap. */
.pointing .w {
  cursor: pointer; border-radius: 2px;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.pointing .w:hover { background: var(--paper-3); }
.pointing .w.cad {
  text-decoration: underline; text-decoration-color: var(--accent);
  text-decoration-thickness: 2px; text-underline-offset: .22em;
}
.pointing .w.start { color: var(--accent); }
.pointing .w.flex { text-decoration-style: dotted; }
.pointing .w.gap { cursor: default; }
.pointing .w.gap:hover { background: none; }
.brk {
  font: inherit; line-height: 1; cursor: pointer;
  background: none; border: 1px dashed var(--rule); border-radius: 2px;
  color: var(--ink-faint); opacity: .55;
  padding: 0 .3rem; margin-left: .35rem;
}
.brk:hover { opacity: 1; }
.brk[aria-pressed="true"] {
  opacity: 1; border-style: solid; border-color: var(--ink-muted); color: var(--ink);
}

.psalm-only { display: none; }
body.psalm-mode .psalm-only { display: block; }
.setup-head {
  font-family: var(--sans); font-size: .72rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-faint);
  border-top: 1px solid var(--rule); padding-top: 1.2rem; margin: 2.2rem 0 1.4rem;
}

/* --- control groups ---------------------------------------------------- */
section { margin-bottom: 1.9rem; }
.label {
  font-family: var(--sans); font-size: .78rem; letter-spacing: .04em;
  color: var(--ink-muted); margin: 0 0 .5rem;
}
.readout { color: var(--ink-faint); float: right; font-weight: 400; }
.hint {
  font-family: var(--sans); font-size: .74rem; color: var(--ink-faint);
  margin: .45rem 0 0;
}

.row { display: flex; flex-wrap: wrap; gap: .3rem; }
.row + .row { margin-top: .35rem; }

.chip {
  font: inherit; font-size: .95rem;
  color: var(--ink); background: transparent;
  border: 1px solid var(--rule); border-radius: 2px;
  padding: .42rem .6rem; min-width: 2.6rem; cursor: pointer;
}
.chip:hover:not([disabled]) { border-color: var(--ink-muted); }
.chip[aria-pressed="true"], .chip[aria-checked="true"] {
  background: var(--ink); border-color: var(--ink); color: var(--paper);
}
.chip[disabled] { opacity: .4; cursor: not-allowed; }
.row.pitch .chip { flex: 1 1 3.2rem; }

/* The notes counted from the drone: the interval as the label, its letter
   small beneath, so the two ways of naming a note can be learnt side by
   side. */
.chip.step { display: flex; flex-direction: column; align-items: center; line-height: 1.15; padding: .35rem .3rem; }
.step-int { font-family: var(--sans); font-size: .8rem; }
.step-ltr { font-size: .78rem; color: var(--ink-faint); }
.chip[aria-pressed="true"] .step-ltr { color: inherit; opacity: .75; }
.row.view { margin-bottom: .45rem; }
.row.view .chip { font-family: var(--sans); font-size: .78rem; padding: .3rem .6rem; }
.row.view.names { margin: .8rem 0 0; align-items: center; }
.row.view.names .names-label { font-family: var(--sans); font-size: .74rem; color: var(--ink-faint); margin-right: .2rem; }
/* Solfège under the interval, or alone in its place. Set in italic, as
   sung syllables usually are, so it never reads as a word of the label. */
.int-sol { font-style: italic; }
.int-num + .int-sol { margin-left: .25em; }
/* Both at once would run into the keyboard digit on a wide interval
   (↓2nd teˌ), so in the strip they stack, and the pill makes room above
   the note for two lines. */
.strip.both .pill-int { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.15; }
.strip.both .int-num + .int-sol { margin-left: 0; }
.strip.both .pill { padding-top: 1.45rem; }
body.psalm-mode .deck .strip.both .pill { padding-top: 1.05rem; }
.step-sol { font-family: var(--sans); font-size: .74rem; font-style: italic; }
.step-int + .step-sol { color: var(--ink-muted); }
.chip[aria-pressed="true"] .step-sol { color: inherit; }

/* --- the mix --------------------------------------------------------------
   Label, fader, and a third column that only the reciting note uses, for its
   On/Off. The others' faders run on into it. */
.fader {
  display: grid; grid-template-columns: 6.6rem 1fr 3.2rem;
  align-items: center; gap: .6rem; margin-top: .45rem;
}
.fader label {
  font-family: var(--sans); font-size: .8rem; color: var(--ink-muted);
}
.fader input[type="range"] { margin: 0; }
.fader input[type="range"]:last-child { grid-column: 2 / 4; }
.fader.off input[type="range"] { opacity: .4; }
.fader-out { font-family: var(--sans); font-size: .74rem; color: var(--ink-faint); text-align: right; }
.chip.small { font-family: var(--sans); font-size: .74rem; padding: .3rem .4rem; min-width: 0; }
.mix .row { margin-bottom: .2rem; }

input[type="range"] { width: 100%; accent-color: var(--accent); margin: .5rem 0 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- the two note pickers ------------------------------------------------
   The drone note and the notes of the psalm tone are chosen the same way,
   with the same twelve chips in the same order, because they are the same
   kind of decision. The octave chips are labelled with the note they give. */
.row .chip[disabled] { opacity: .35; }
.chip sub { font-size: .7em; vertical-align: baseline; position: relative; top: .2em; }

footer {
  margin-top: 2.4rem; padding-top: 1rem; border-top: 1px solid var(--rule);
  color: var(--ink-faint); font-family: var(--sans); font-size: .78rem;
}
footer p { margin: 0 0 .7rem; }
footer kbd {
  font-family: var(--sans); font-size: .95em;
  border: 1px solid var(--rule); border-radius: 3px;
  padding: 0 .3em; color: var(--ink-muted);
}

/* Present for a screen reader, absent for everyone else. Used for the
   labels on the two sliders, which are legible from their headings on
   screen and would be nothing but a label with no name without this. */
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

[hidden] { display: none !important; }

/* Query-string examples in the footer. Monospace, but sized to sit in the
   sans-serif line around it rather than towering over it. */
footer code {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: .92em;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0 .25em;
  color: var(--ink-muted);
}
