/*
 * site/styles.css — the layout of the page and every component.
 *
 * What it is for
 *   One plain stylesheet, no framework, for where things go and how big
 *   they are. Every colour and font comes from the tokens in theme.css
 *   (loaded first), so no rule below names a colour directly; change the
 *   look there, the layout here.
 *
 * The look
 *   The builder is a sepia page laid on an ultramarine backdrop, between a
 *   header and a footer printed in gold on the blue (header.html and
 *   footer.html, filled in by app/platform/partials.js). The playlist is
 *   drawn as a chaplet: a thread runs down the left side and each item is a
 *   bead on it. The bead is also the drag handle and shows a block's repeat
 *   count (10 on a Hail Mary decade); a blank block is a hollow bead on a
 *   dashed stretch of thread. Each item's card is one line. Everything else
 *   stays quiet so the strand reads first. The whole page is set in a book
 *   serif already on the device, so nothing is downloaded.
 *
 *   Square corners, like a printed page: no rule here rounds a box, with
 *   two deliberate exceptions, the "AI voice" badge (a pill) and the beads
 *   (round, because they are the chaplet's beads, not boxes).
 *
 * Plan section
 *   "UI components (site/app/ui)", styling paragraph: "Styling is two
 *   stylesheets and no CSS framework. theme.css holds every colour and
 *   font token … styles.css lays out the components and names colours only
 *   through those tokens." And the ItemCard.js row: "Each item on one line".
 *
 * Do not break
 *   - One-handed phone use (the brief): every control is at least 44 × 44
 *     CSS pixels (Apple's and Google's minimum comfortable tap size), and
 *     nothing works only on hover.
 *   - No sideways scrolling: flexible boxes get min-width: 0 and long names
 *     wrap (overflow-wrap: anywhere) instead of pushing the page wider.
 *   - Form controls use font-size 1rem (17 px here). iOS Safari zooms the
 *     whole page when you tap a field whose text is smaller than 16 px, and
 *     doesn't zoom back. Keep every input, select and textarea at 16 px or
 *     more. (Still true in iOS 18; test by tapping a field on an iPhone.)
 *   - .item--drop-before/after draw the insertion line as an overlay so the
 *     cards never move during a drag (ui/drag.js measures them once).
 *   - Only .bead has touch-action: none, so the list still scrolls by
 *     finger everywhere else.
 *   - A ticked card is marked with a background tint and a box-shadow
 *     ring, never a thicker border: a border change would make the card
 *     taller or wider and shift every card below it.
 *   - Don't add border-radius to boxes (see "The look"). Form controls get
 *     border-radius: 0 explicitly in Base, because iOS Safari rounds text
 *     fields and dropdowns by default.
 */

/* ---------- Sizes ------------------------------------------------------- */
/* Colours and fonts are in theme.css; these are the layout's own numbers. */
:root {
  --tap: 44px; /* minimum tap target (see "Do not break") */
  --bead: 30px; /* visible bead diameter, inside its 44 px handle */
  --gutter: 12px; /* side margin inside the page on phones */
  --sheet-margin: 6px; /* the strip of blue each side of the page on phones */
}
@media (min-width: 900px) {
  :root {
    --sheet-margin: 24px; /* a wider frame of blue on big screens */
    --gutter: 16px; /* and a little more room inside the page */
  }
}

/* ---------- Base --------------------------------------------------------- */
/* 17 px body text with generous line height: easy to read at arm's length,
   including for older eyes. */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  font-size: 17px;
  -webkit-text-size-adjust: 100%; /* stop iOS enlarging text on rotate */
}
/* The backdrop itself (the blue and its gradient) is painted in theme.css.
   On phones the bottom padding keeps the end of the page (the footer, or
   the last card when there is no footer) clear of the fixed view switcher
   (56 px buttons + 1 px border, rounded up to 72 px for breathing room)
   and the iPhone's home bar (env(safe-area-inset-bottom)). Wide screens
   have no switcher (see "Page layout"). */
body {
  margin: 0;
  padding-bottom: calc(72px + env(safe-area-inset-bottom));
  color: var(--ink);
  font: 1rem/1.45 var(--serif);
}
@media (min-width: 900px) {
  body {
    padding-bottom: 0;
  }
}
h1,
h2,
h3,
p {
  margin: 0;
}
button,
input,
select,
textarea {
  font: inherit;
  font-size: 1rem; /* ≥ 16 px: no iOS zoom (see "Do not break") */
  color: inherit;
  max-width: 100%;
  /* Platform workaround (iOS Safari): text fields and dropdowns get
     rounded corners from the browser's own styles even with a border set.
     The page's boxes are square (see "The look"). To tell whether it's
     still needed: remove this line and look at a Pause box on an iPhone. */
  border-radius: 0;
}
/* A typed pause between the arrow steps (0.3 with 0.5 s arrows, see
   app/ui/inputSteps.js) is "off the grid" to the browser, and Firefox
   paints such a box with a red glow (a box-shadow) once it has been
   edited. Only the builder's own inline message judges a value
   (core/limits.js), so the glow is turned off. To tell whether it's still
   needed: delete this rule, type 0.3 in a Pause box in Firefox, and leave
   the box; if no red glow appears, it's gone. */
.setting__control:invalid {
  box-shadow: none;
}
/* The message shown before the app starts, or if the library fails. It
   sits straight on the blue (the page is drawn by the app), so it is gold
   like the header. */
.boot {
  padding: 32px var(--gutter);
  color: var(--gold);
  font-size: 1.25rem;
  text-align: center;
}

/* ---------- Site header and footer (header.html, footer.html) ------------ */
/* Gold on the ultramarine, centred, set like a book's title page. Both
   start out `hidden` in index.html and are shown by platform/partials.js
   only when their file has content, so an empty one takes no space. The
   classes named here are the ones header.html and footer.html suggest to
   whoever edits them. */
.site-header,
.site-footer {
  padding: 18px var(--gutter);
  color: var(--gold);
  text-align: center;
}
.site-header__title {
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: 0.04em; /* a touch of spacing, as on a title page */
}
.site-header__tagline {
  margin-top: 2px;
  font-style: italic;
}
.site-footer {
  padding-top: 20px;
  padding-bottom: 24px;
  font-size: 0.95rem;
}
.site-footer p + p {
  margin-top: 6px;
}
/* Links stay gold (the browser's default blue would vanish on the blue)
   and underlined, so they still look like links. */
.site-header a,
.site-footer a {
  color: inherit;
}
.site-header :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--gold);
}
@media (min-width: 900px) {
  .site-header {
    padding-top: 28px;
    padding-bottom: 24px;
  }
  .site-header__title {
    font-size: 2.1rem;
  }
}
/* Text for screen readers only, such as labels whose meaning is clear from
   the layout. The standard clip pattern keeps it readable by assistive tech. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
/* A clear focus ring for keyboard users; :focus-visible keeps it off for
   taps and clicks. */
:focus-visible {
  outline: 3px solid var(--marian);
  outline-offset: 2px;
}

/* ---------- Buttons ------------------------------------------------------ */
/* Three kinds: primary (filled blue: Download, Add), quiet (outlined: most
   actions), icon (square, for ▶ ↑ ↓ ×). All are at least 44 px tall. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 0 16px;
  border: 1px solid var(--line);
  background: transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.btn--primary {
  background: var(--marian);
  border-color: var(--marian);
  color: var(--on-marian);
  font-weight: 600;
}
.btn--icon {
  min-width: var(--tap);
  padding: 0;
  font-size: 1.1rem;
}
.btn--danger {
  color: var(--danger);
}
/* The button that confirms something drastic (Clear all's "Clear"):
   filled red, so it can't be mistaken for Cancel beside it. */
.btn--danger-solid {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--on-danger);
  font-weight: 600;
}
.btn:disabled {
  opacity: 0.45;
  cursor: default;
}
/* Line icons drawn as inline SVG (Undo, Redo): stroked in the text colour,
   so they follow the disabled fade. Round ends and joins match the beads. */
.icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Checkboxes (card selection, Select all): drawn by the browser, at 22 px
   so they are easy to see, in the action colour. The 44 px tap area comes
   from the <label> around each one, not from the box itself. */
.check {
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--marian);
  cursor: pointer;
}

/* ---------- Page layout -------------------------------------------------- */
/* Phone: one column, with the playlist, the prayer library and the
   templates as three views (the bar at the bottom switches; App sets
   data-view). Wide screen (900 px and up): the playlist on the left, and
   on the right the prayer library or the templates (the Prayers /
   Templates switch at its top; App sets data-side); the bottom bar is
   hidden. 900 px is roughly where two 400 px columns plus margins fit.
   The playlist gets the larger share (1.6 : 1) so a card's name and its
   settings fit on one line on a laptop screen. */
/* The page: a sepia sheet on the blue, at most 1120 px wide, with a strip
   of blue each side (--sheet-margin). Its edge and shadow lift it off the
   backdrop. The room the phone's view switcher needs below it is kept by
   body (see Base). */
.app {
  width: min(1120px, calc(100% - 2 * var(--sheet-margin)));
  margin: 0 auto;
  padding-bottom: 16px;
  border: 1px solid var(--page-edge);
  background: var(--page);
  box-shadow: 0 6px 30px var(--shadow);
}
.layout {
  display: grid;
  gap: 20px;
  padding: 12px var(--gutter) 24px;
}
.pane {
  min-width: 0; /* let the grid column shrink instead of overflowing */
}
@media (max-width: 899px) {
  .app[data-view="playlist"] .pane--side,
  .app:not([data-view="playlist"]) .pane--playlist {
    display: none;
  }
}
/* On every screen size, the right-hand pane shows one library at a time.
   On a phone data-side follows the bottom bar's choice (App.js). */
.app[data-side="library"] .side--templates,
.app[data-side="templates"] .side--library {
  display: none;
}
@media (min-width: 900px) {
  .app {
    padding-bottom: 32px;
  }
  .layout {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    align-items: start;
    gap: 32px;
  }
  /* The library stays in view while the playlist scrolls. */
  .pane--side {
    position: sticky;
    top: 150px;
    max-height: calc(100vh - 170px);
    overflow-y: auto;
  }
  /* The view switcher is hidden on wide screens in the "View switcher"
     section below: it has to come after .tabs's own display rule. */
}

/* ---------- Top bar ------------------------------------------------------ */
/* Sticks to the top while scrolling, so the total and Download are always
   one tap away. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: grid;
  gap: 8px;
  padding: 12px var(--gutter) 10px;
  background: var(--page);
  border-bottom: 1px solid var(--line);
}
/* The title box, then Undo and Redo at the end of the same row.
   min-width: 0 here and width: 0 on the title are both needed on a phone:
   a text box has a built-in width of about 20 characters (≈ 280 px at
   this font size), and without them that width, plus the two buttons,
   would stretch the top bar's grid column past the screen edge and push
   Redo and Download off it. With width 0, flex: 1 lets the title take
   exactly the room the buttons leave. */
.topbar__head {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.topbar__title {
  flex: 1;
  width: 0;
  min-width: 0;
  min-height: var(--tap);
  padding: 0;
  border: 0;
  border-bottom: 1px dashed transparent;
  background: transparent;
  font-size: 1.5rem;
}
.topbar__title:focus {
  border-bottom-color: var(--marian);
  outline: none;
}
.topbar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* The running total: big tabular numbers so they don't jiggle as they
   change, with the cap (or the amount to cut) in small type under them, so
   the total and both buttons fit on one row of a phone. */
.topbar__total {
  display: grid;
  margin-right: auto;
  line-height: 1.1;
}
.topbar__time {
  font-size: 1.6rem;
  font-weight: 600;
  font-variant-numeric: lining-nums tabular-nums; /* even-height digits that don't jiggle */
}
.topbar__cap {
  color: var(--muted);
  font-size: 0.85rem;
}
/* Spec: "the duration counter turns red with the amount to cut". */
.topbar__total--over .topbar__time,
.topbar__total--over .topbar__cap {
  color: var(--danger);
}
.topbar__messages {
  margin: 0;
  padding-left: 20px;
  color: var(--muted);
  font-size: 0.9rem;
}
.topbar__error {
  color: var(--danger);
}
.topbar__note {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* ---------- Progress bar -------------------------------------------------- */
/* Shown while clips download for a build; a first build on a slow
   connection is the only time it's on screen long. */
.progress {
  height: 6px;
  background: var(--line);
  overflow: hidden;
}
.progress__fill {
  height: 100%;
  background: var(--marian);
  transition: width 0.15s linear;
}

/* ---------- "Restored" notice --------------------------------------------- */
.notice {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin: 12px var(--gutter) 0;
  padding: 6px 6px 6px 14px;
  border-left: 4px solid var(--marian);
  background: var(--surface);
}
/* The message (and any notes under it) takes the free space, pushing the
   buttons to the right. */
.notice__text {
  display: grid;
  gap: 2px;
  margin-right: auto;
}
.notice__note {
  color: var(--muted);
  font-size: 0.95rem;
}

/* ---------- Defaults bar -------------------------------------------------- */
/* Narrator takes the full width on a phone (names can be long); speed and
   pause share the next row. */
.defaults {
  padding: 14px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.defaults__title {
  margin-bottom: 10px;
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 400;
}
.defaults__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
}
.defaults__grid > :first-child {
  grid-column: 1 / -1;
}

/* ---------- Setting fields ----------------------------------------------- */
/* Spec: inherited values gray with "default"; set values bold with Reset. */
.setting {
  display: grid;
  gap: 4px;
  min-width: 0;
}
.setting__label {
  display: flex;
  align-items: baseline;
  gap: 8px;
  color: var(--muted);
  font-size: 0.9rem;
}
.setting__default {
  font-style: italic;
}
.setting__row {
  display: flex;
  gap: 6px;
  min-width: 0;
}
.setting__number {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.setting__control {
  flex: 1;
  width: 100%;
  min-width: 0;
  min-height: var(--tap);
  padding: 0 10px;
  border: 1px solid var(--line);
  background: var(--surface);
}
/* "Mixed" (selection bar: the ticked blocks disagree) is gray like an
   inherited value: no single value is set. */
.setting--mixed .setting__control,
.setting--inherited .setting__control {
  color: var(--muted);
}
.setting--set .setting__control {
  font-weight: 700;
  border-color: var(--ink);
}
.setting__unit {
  color: var(--muted);
}
.setting__reset {
  min-height: var(--tap);
  padding: 0 12px;
  border: 0;
  background: var(--page);
  cursor: pointer;
}
.setting__message {
  color: var(--danger);
  font-size: 0.9rem;
}

/* ---------- The strand (playlist) ---------------------------------------- */
/* The thread is one vertical line behind the beads, centred in the 44 px
   bead column (22 px from the left edge). */
.playlist {
  margin-top: 20px;
}
.strand {
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
}
.strand:not(:empty)::before {
  content: "";
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: calc(var(--tap) / 2 - 1px);
  width: 2px;
  background: var(--thread);
}
.item {
  position: relative;
  display: grid;
  grid-template-columns: var(--tap) minmax(0, 1fr);
  gap: 10px;
  padding: 6px 0;
}
/* The bead: a 44 px handle (tap size) around a 30 px visible bead. It is
   the only place a drag can start, so it alone disables touch scrolling. */
.bead {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  margin-top: 4px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.bead span {
  display: grid;
  place-items: center;
  width: var(--bead);
  height: var(--bead);
  border-radius: 50%;
  background: var(--marian);
  color: var(--on-marian);
  font-size: 0.8rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.bead:active {
  cursor: grabbing;
}
/* Silence: a hollow bead, and the thread beside it dashed, like a gap in
   the chaplet. The dashed stripe is painted over the solid thread. */
.item--blank .bead span {
  background: var(--page);
  border: 2px dashed var(--thread);
}
.item--blank::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--tap) / 2 - 1px);
  width: 2px;
  background: repeating-linear-gradient(to bottom, var(--thread) 0 5px, var(--page) 5px 10px);
}
/* A block that can't play: its bead turns red. */
.item--problem .bead span {
  background: var(--danger);
}

/* ---------- Dragging ------------------------------------------------------ */
/* The dragged card fades; the insertion line is an overlay above (or below
   the last) card, so nothing shifts while the finger moves. */
.item--dragging .card {
  opacity: 0.45;
}
.item--drop-before::after,
.item--drop-after::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--marian);
}
.item--drop-before::after {
  top: -2px;
}
.item--drop-after::after {
  bottom: -2px;
}

/* ---------- Cards --------------------------------------------------------- */
/* Two columns: the 44 px checkbox cell, then the card's contents. The
   checkbox cell replaces the card's old 14 px left padding. */
.card {
  display: grid;
  grid-template-columns: var(--tap) minmax(0, 1fr);
  min-width: 0;
  padding: 6px 8px 6px 0;
  border: 1px solid var(--line);
  background: var(--surface);
}
/* The checkbox's tap area: a full 44 px square, lined up with the card's
   line (name, settings and play button). */
.card__select {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  cursor: pointer;
}
.card__body {
  min-width: 0;
}
/* A ticked card: tinted, with a 2 px ring (1 px border + 1 px shadow) in
   the action colour. See "Do not break" for why not a thicker border. */
.item--selected .card {
  border-color: var(--marian);
  background: var(--selected-bg);
  box-shadow: 0 0 0 1px var(--marian);
}
/* A card's one line (ui/ItemCard.js): the open/close button, which fills
   the line, and the play button at its right end. align-items: flex-start
   keeps ▶ beside the name's first line when the settings wrap under it. */
.card__line {
  display: flex;
  align-items: flex-start;
  gap: 4px;
}
/* The <h3> around the open/close button only gives the card a heading for
   screen readers; it adds no size or weight of its own. */
.card__heading {
  flex: 1;
  min-width: 0;
  font-size: 1rem;
  font-weight: 400;
}
/* The open/close button IS the line: the name, then the values with Edit
   at their end. It wraps as those two pieces. On a wide card they share
   one line; on a narrow phone the values drop under the name as a whole
   rather than squeezing it. The whole line is the tap target, so it's at
   least 44 px tall. */
.card__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 12px;
  width: 100%;
  min-height: var(--tap);
  padding: 7px 6px 7px 0; /* centres one text line in the 44 px line */
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}
.card__name {
  min-width: 0;
  font-size: 1.2rem;
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
/* Narrator (and its AI badge), speed, repeat, pause, then Edit. It stays
   beside the name when its whole content fits there (flex-basis auto =
   its natural width), otherwise it drops under the name and wraps within
   itself. It then grows to fill the rest of its line (flex-grow 1) so
   Edit, pushed right by margin-left: auto, sits at the line's end. */
.card__values {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 8px;
  min-width: 0;
}
.val--inherited {
  color: var(--muted);
}
.val--set {
  font-weight: 700;
}
/* Edit / Close, at the right end of the values (see .card__values). */
.card__more {
  margin-left: auto;
  color: var(--marian);
  font-weight: 600;
}
.card__problem {
  padding-bottom: 6px;
  color: var(--danger);
}
.card__panel {
  display: grid;
  gap: 14px;
  padding: 12px 0 8px;
  border-top: 1px solid var(--line);
}
/* Settings flow two or three to a row as space allows (160 px is the
   narrowest a box plus its Reset button stays usable), with the
   narrator on its own row because names can be long. */
.card__settings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
}
.card__settings > :first-child {
  grid-column: 1 / -1;
}
.card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ---------- Playlist toolbar (Select all, Clear all) ----------------------- */
/* Sits just above the strand. Select all's checkbox is indented 11 px,
   half of (44 px bead column − 22 px box), so it lines up over the beads. */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 16px;
}
.toolbar__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}
.toolbar__all {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap);
  padding-left: 11px;
  font-weight: 600;
  cursor: pointer;
}

/* ---------- Confirmation in place (ui/ConfirmButton.js) -------------------- */
/* The question and its two buttons wrap onto a second line on a narrow
   phone rather than squeezing. */
.confirm {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}
.confirm__question {
  font-weight: 600;
}

/* ---------- Selection bar (ui/SelectionBar.js) ----------------------------- */
/* Sticks to the bottom of the screen while the list scrolls, just above
   the phone's view switcher: 57 px is the switcher's 56 px buttons plus
   its 1 px top border, plus the iPhone home-bar inset. On wide screens
   (no switcher) it sits 12 px above the bottom edge. It is the last thing
   in the playlist pane, so once scrolled to the end it rests in its own
   place below "Add silence". */
.selbar {
  position: sticky;
  bottom: calc(57px + env(safe-area-inset-bottom));
  z-index: 9; /* above the cards, below the top bar and switcher (10) */
  display: grid;
  gap: 4px;
  margin-top: 12px;
  padding: 6px 10px;
  border: 1px solid var(--marian);
  background: var(--surface);
  box-shadow: 0 -4px 18px var(--shadow);
}
@media (min-width: 900px) {
  .selbar {
    bottom: 12px;
  }
}
.selbar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* Slimmer side padding than other buttons (12 px instead of 16 px) so the
   count, Duplicate and Delete fit one line on a 375 px phone (the common
   iPhone width). On narrower phones Delete wraps to a second line. */
.selbar__row .btn {
  padding: 0 12px;
}
/* "× 5 selected": the count is also the Clear selection button, so the
   row fits one line on a 320 px phone (count, Duplicate, Delete). */
.selbar__row .selbar__count {
  padding: 0 10px 0 8px;
}
.selbar__count {
  margin-right: auto; /* pushes Duplicate and Delete to the right */
  border-color: var(--marian);
  font-weight: 700;
}
.selbar__count > span:first-child {
  color: var(--muted);
  font-size: 1.15rem;
}
/* "Settings for all N prayers": a full-width text button, like a card's
   line. */
.selbar__toggle {
  min-height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  color: var(--marian);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
/* The four settings, laid out like a card's. Capped at 45% of the screen
   height and scrollable inside, so on a phone with the keyboard open the
   bar can't cover the whole list. */
.selbar__settings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  max-height: 45vh;
  overflow-y: auto;
  padding: 4px 0 8px;
}
.selbar__settings > :first-child {
  grid-column: 1 / -1; /* narrator on its own row, as on cards */
}

/* ---------- Badge ---------------------------------------------------------- */
/* Spec: an "AI voice" badge wherever an AI narrator appears. The one box
   on the page that keeps round ends (see "The look"), so it reads as a
   label, not part of the text. */
.badge {
  flex: none;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--badge-bg);
  color: var(--badge-ink);
  font-family: var(--sans);
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}

/* ---------- Empty playlist and Add silence -------------------------------- */
.empty {
  display: grid;
  gap: 6px;
  padding: 20px 4px 12px;
  color: var(--muted);
}
.empty__title {
  color: var(--ink);
  font-size: 1.25rem;
}
.add-silence {
  margin: 10px 0 0 calc(var(--tap) + 10px);
}

/* ---------- Library ------------------------------------------------------- */
.library__title {
  margin-bottom: 10px;
  font-size: 1.4rem;
  font-weight: 500;
}
.library__search {
  width: 100%;
  min-height: var(--tap);
  padding: 0 12px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.library__none {
  padding: 16px 0;
  color: var(--muted);
}
.tree {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Nested folders step in, with a light rule showing which folder they're in. */
.tree .tree {
  margin-left: 14px;
  padding-left: 10px;
  border-left: 1px solid var(--line);
}
.tree__toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: var(--tap);
  padding: 0 4px;
  border: 0;
  background: none;
  font-weight: 600;
  text-align: left;
  text-transform: capitalize; /* folder names are lowercase on disk */
  cursor: pointer;
}
.tree__chevron {
  width: 1em;
  color: var(--muted);
}
.prayer {
  display: grid;
  gap: 6px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.prayer__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.prayer__name {
  font-size: 1.15rem;
  overflow-wrap: anywhere;
}
.prayer__controls {
  display: flex;
  gap: 8px;
  min-width: 0;
}
.prayer__narrator {
  flex: 1;
  min-width: 0;
  min-height: var(--tap);
  padding: 0 10px;
  border: 1px solid var(--line);
  background: var(--surface);
}

/* ---------- Prayers / Templates switch (wide screens) ---------------------- */
/* Two joined buttons at the top of the right-hand pane; the pressed one is
   filled. Hidden on phones (see Page layout). */
.side-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-bottom: 14px;
  border: 1px solid var(--line);
  background: var(--surface);
}
.side-switch__btn {
  min-height: var(--tap);
  border: 0;
  background: none;
  font-weight: 600;
  cursor: pointer;
}
.side-switch__btn[aria-pressed="true"] {
  background: var(--marian);
  color: var(--on-marian);
}
/* The bottom bar already picks the library on a phone. This must stay
   AFTER the .side-switch rule above: both have the same specificity, so
   the later one wins (the same reason as the view switcher's rule). */
@media (max-width: 899px) {
  .side-switch {
    display: none;
  }
}

/* ---------- Templates (ui/Templates.js, ui/ImportPlaylist.js) ------------- */
/* Rows reuse the prayer library's .tree and .prayer styles; these add the
   "Your own playlist" box at the top (Open, Paste, and the Replace / Add
   question) and the template rows' extra lines. The box is dashed to set
   it apart from the templates below it, which are the site's own. */
.openfile {
  display: grid;
  gap: 8px;
  margin-bottom: 16px;
  padding: 12px;
  border: 1px dashed var(--thread);
}
.openfile__title {
  font-size: 1rem;
  font-weight: 700;
}
/* Open and Paste side by side, wrapping on a narrow phone. The paste box,
   once open, takes a whole row of its own (flex-basis 100%). */
.openfile__buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
}
.openfile__open {
  display: grid;
  gap: 6px;
}
.openfile__btn {
  justify-self: start;
}
.paste {
  display: grid;
  flex-basis: 100%;
  gap: 6px;
}
.paste__label {
  font-weight: 600;
}
/* A monospace font, because the pasted text is code-like JSON; 1rem keeps
   iOS from zooming the page when the box is tapped (see "Do not break"). */
.paste__text {
  width: 100%;
  min-height: 8rem;
  padding: 8px 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font: 1rem/1.4 ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
  resize: vertical;
}
.paste__buttons,
.loadchoice__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.paste__error {
  color: var(--danger);
}
.loadchoice {
  display: grid;
  gap: 8px;
}
.loadchoice__question {
  font-weight: 600;
}
.loadchoice__note {
  color: var(--muted);
  font-size: 0.9rem;
}
/* The real file input is visually hidden inside the label (OpenFile.js),
   so the label shows the keyboard focus ring for it. */
.openfile__btn:focus-within {
  outline: 3px solid var(--marian);
  outline-offset: 2px;
}
.openfile__hint {
  color: var(--muted);
  font-size: 0.9rem;
}
.openfile__error,
.template__info--error,
.template__warn {
  color: var(--danger);
}
.template__info {
  color: var(--muted);
  font-variant-numeric: tabular-nums; /* lengths line up row to row */
}
.template__warn {
  font-size: 0.9rem;
}
/* Use's question ("Replace your 16 items?") wraps under the buttons on a
   narrow phone instead of squeezing them. */
.template__controls {
  flex-wrap: wrap;
}
.templates__error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 12px 0;
}
.templates__problems {
  margin-top: 16px;
  color: var(--muted);
  font-size: 0.9rem;
}
.templates__problems ul {
  margin: 4px 0 0;
  padding-left: 20px;
}

/* ---------- View switcher (phones) ----------------------------------------- */
/* Fixed to the bottom of the screen, where a thumb rests; padded above the
   iPhone's home bar. */
.tabs {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* Playlist, Add prayers, Templates */
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.tabs__btn {
  min-height: 56px;
  border: 0;
  border-top: 3px solid transparent;
  background: none;
  font-weight: 600;
  cursor: pointer;
}
.tabs__btn[aria-pressed="true"] {
  border-top-color: var(--marian);
  color: var(--marian);
}
/* Wide screens show both views at once, so no switcher. This must stay
   AFTER the .tabs rule above: both have the same specificity, so the later
   one wins. */
@media (min-width: 900px) {
  .tabs {
    display: none;
  }
}
.tabs__count {
  display: inline-block;
  min-width: 1.6em;
  margin-left: 4px;
  padding: 0 6px;
  background: var(--page);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ---------- "Added …" confirmation ---------------------------------------- */
/* Floats above the switcher; can't be tapped, so it never blocks a button. */
.toast {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(68px + env(safe-area-inset-bottom));
  z-index: 11;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.toast__msg {
  max-width: calc(100% - 2 * var(--gutter));
  padding: 8px 16px;
  background: var(--ink);
  color: var(--surface);
}
@media (min-width: 900px) {
  .toast {
    bottom: 24px;
  }
}

/* ---------- Reduced motion ---------------------------------------------- */
/* People who ask their device for less motion get no animated progress. */
@media (prefers-reduced-motion: reduce) {
  .progress__fill {
    transition: none;
  }
}
