/* ——— Settings ———
   Preferences for how the site looks and sounds.

   Layout rule for the whole panel: a single column of full-width cards, one
   per subject. Settings fail when options are scattered across collapsible
   groups, because the person scanning it cannot tell how many preferences
   exist. Here every setting is visible without clicking anything, and each
   card names its subject in the heading.

   The panel is rendered in two hosts — the /settings page and the dialog that
   opens over any page — so everything below is written against the card and row
   classes only. The two hosts own their own chrome: the page has a hero, the
   dialog has a header and a backdrop.

   Reuses the shared .appearance-* swatch components from style_training.css so
   the board/pieces/arrows/highlights picker looks identical to the one inside
   the trainer. */

/* ——— Dialog ———
   A real <dialog>, so the top layer, the backdrop, the focus trap, and the
   Escape key are the browser's rather than something reimplemented. The rules
   here are only what it needs to look like this site. */

.settings-dialog {
  width: min(880px, calc(100vw - 32px));
  /* A definite height, not just a max-height. The panel scrolls, so the dialog
     must be no taller than the space it is given, and `min()` is what makes
     that "as tall as the viewport allows, but no more".

     The nested .settings-dialog-frame originally took `max-height: inherit`,
     which does not work: `inherit` copies the computed value of the PARENT's
     property, and the parent's max-height is a length only in the sense that it
     resolves to one — so the frame ends up with an auto-ish height and grows to
     fit all three cards. That put the last row about 1800px down, far outside
     the viewport, with the dialog's own overflow:hidden silently clipping it
     and no way to scroll to it. The clamp belongs on the dialog, and the frame
     is the flex container that distributes it. */
  height: min(88vh, 880px);
  max-height: min(88vh, 880px);
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 18px;
  background: transparent;
  color: var(--cream);
  font-family: var(--font);
  /* The panel scrolls, not the dialog box: scrolling the box would move the
     header out of reach, so it is a separate block above the scroller. */
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
    0 32px 90px rgba(0, 0, 0, 0.55);
}

/* The backdrop carries the dimming. Kept separate from the dialog's own
   background, which is transparent so the frame below can supply the gradient
   and the card edges can be rounded independently. */
.settings-dialog::backdrop {
  background: rgba(9, 9, 11, 0.62);
  /* Slow enough to read as the page receding, quick enough that a repeated
     open does not feel like waiting. */
  animation: settings-backdrop-in 0.18s ease-out;
}

html[data-theme="light"] .settings-dialog::backdrop {
  background: rgba(24, 24, 27, 0.4);
}

@keyframes settings-backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Opening animation. Kept to opacity and a small rise: a scale or a slide from
   the sidebar row would have to guess which row was pressed, and a long
   transition makes a dialog that is opened repeatedly feel sluggish. */
.settings-dialog[open] {
  animation: settings-dialog-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes settings-dialog-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.settings-dialog-frame {
  display: flex;
  flex-direction: column;
  /* Fills the dialog's clamped height exactly. `height: 100%` rather than
     `max-height: inherit`, which as noted above does not clamp — and without
     a real height here the body has nothing to shrink against, so it grows to
     its full content height and the panel stops scrolling. */
  height: 100%;
  min-height: 0;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 140px),
    color-mix(in srgb, var(--panel) 94%, var(--bg-2));
}

.settings-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex: 0 0 auto;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--line);
}

.settings-dialog-kicker {
  margin: 0 0 4px;
  color: var(--muted);
  font-size: 0.65rem;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.settings-dialog-title {
  margin: 0;
  font-family: var(--serif, Georgia, "Times New Roman", serif);
  font-size: 1.34rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--cream);
}

.settings-dialog-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  margin: -2px -4px 0 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--bg-3);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.18s ease,
    border-color 0.18s ease,
    background-color 0.18s ease;
}

.settings-dialog-close svg {
  width: 16px;
  height: 16px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
}

.settings-dialog-close:hover {
  color: var(--cream);
  border-color: var(--line-strong);
  background: var(--hover-fill);
}

.settings-dialog-close:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--gold) 70%, transparent);
  outline-offset: 2px;
}

/* The scroller. `overscroll-behavior` stops the scroll from chaining to the
   page behind once the panel hits its end, which would otherwise scroll the
   content the dialog is covering. */
.settings-dialog-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 16px 20px 20px;
}

.settings-view {
  max-width: 860px;
  margin: 0 auto;
  padding: 28px 0 56px;
}

.settings-hero {
  margin-bottom: 22px;
}

.settings-hero h1 {
  margin: 6px 0 8px;
  font-size: clamp(1.7rem, 3.4vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.12;
  color: var(--cream);
}

.settings-hero p {
  margin: 0;
  max-width: 62ch;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.6;
}

.settings-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ——— Live preview ———
   The Appearance card splits into a board and its controls. The board is the
   point: a 34px swatch cannot distinguish two board finishes, so the preview is
   where a choice actually gets confirmed. */

.settings-card--appearance {
  overflow: hidden;
}

.settings-look {
  display: grid;
  grid-template-columns: minmax(220px, 280px) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
}

.settings-look-controls {
  min-width: 0;
}

.settings-preview {
  position: sticky;
  top: 20px;
}

.settings-preview-frame {
  position: relative;
  /* Height comes from the board inside it, so this box must not be sized by
     its absolutely positioned caption. `relative` plus a padding is what keeps
     the board from spilling outside the frame. */
  padding: 12px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 5%, transparent), transparent 60%),
    color-mix(in srgb, var(--bg-2) 92%, var(--panel));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 6%, transparent),
    0 12px 30px -20px rgba(0, 0, 0, 0.8);
}

.settings-preview-caption {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 9px;
  color: var(--muted);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

/* A live status pip, so the board reads as rendering rather than sitting
   static next to the controls. */
.settings-preview-caption::after {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-left: 7px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow: 0 0 8px color-mix(in srgb, #22c55e 70%, transparent);
  animation: settings-pip 2.4s ease-in-out infinite;
}

@keyframes settings-pip {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* The board wrapper owns the square aspect ratio; the arrow lives in a sibling
   overlay so it is never a grid item. When it was a grid child it added
   implicit rows and the square rows came out at different heights, which read
   as a stretched, misshapen chessboard rather than a board. */
.settings-preview-layer {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 7px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.32);
}

.settings-preview-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  /* Both axes are explicit and equal, so all 64 squares are identical
     regardless of what else is in the layer. */
  grid-template-rows: repeat(8, 1fr);
  width: 100%;
  height: 100%;
}

.settings-preview-square {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
}

/* These read the same custom properties the trainer uses, so the preview
   cannot show a finish the board would not actually render. */
.settings-preview-square.is-light {
  background: var(--board-light);
}

.settings-preview-square.is-dark {
  background: var(--board-dark);
}

.settings-preview-square.is-move::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--hl-from, rgba(57, 255, 20, 0.48));
}

/* The origin ring sits above the piece. Without an explicit z-index it was
   painted underneath, so on any square holding a piece the ring was invisible
   and the selectable-origin styling could not be judged at all. */
.settings-preview-square.is-origin::before {
  content: "";
  position: absolute;
  inset: 6%;
  z-index: 4;
  border: 2px solid var(--hl-ring, #d6ffb8);
  border-radius: 4px;
  box-shadow: 0 0 0 1px var(--hl-ring-soft, rgba(214, 255, 184, 0.55));
  pointer-events: none;
}

/* Sized and fitted exactly as the trainer's own pieces (92% with
   object-fit: contain), so the preview shows the real proportions rather than
   a stretched approximation of them. */
.settings-preview-piece {
  position: relative;
  z-index: 2;
  display: flex;
  width: 92%;
  height: 92%;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
}

.settings-preview-piece img {
  width: 92%;
  height: 92%;
  object-fit: contain;
  display: block;
}

/* The arrow is an SVG polygon spanning the board, with the shaft and head
   merged into one tapered shape. Geometry lives in the module, in an 8x8
   viewBox, so it scales with the preview and stays in proportion.

   The earlier version drew the arrow with a rotated CSS box whose shaft was
   5.5% of the board height — against a square of 12.5% that is a very heavy
   bar, and it read as a blob. The SVG keeps the trainer's own proportions:
   a shaft 0.2 of a square wide. */
.settings-preview-arrow {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

/* ——— Cards ——— */

.settings-card {
  padding: 20px 22px;
  border: 1px solid var(--line-strong);
  border-radius: 16px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--cream) 4%, transparent), transparent 80px),
    color-mix(in srgb, var(--panel) 90%, var(--bg-2));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--cream) 5%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.22);
}

.settings-card-top {
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}

.settings-card-top h2 {
  margin: 0 0 5px;
  font-family: var(--serif, Georgia, "Times New Roman", serif);
  font-size: 1.16rem;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--cream);
}

.settings-card-top p {
  margin: 0;
  max-width: 66ch;
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.55;
}

/* ——— Rows ———
   Label and control on one line, control right-aligned. On narrow screens they
   stack so the label is never squeezed into a two-word column. */

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 13px 0;
}

/* A row that follows another control in the same card reads as part of it, so
   the divider is dropped and only the spacing remains. */
.settings-row--tight {
  padding-top: 11px;
}

.settings-row--tight + .settings-row--tight,
.settings-row--tight:first-child {
  border-top: none;
}

.settings-row + .settings-row {
  border-top: 1px solid var(--line);
}

.settings-row-copy {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.settings-row-label {
  font-size: 0.94rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--cream);
}

.settings-row-hint {
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--muted);
}

.settings-row-action {
  flex: 0 0 auto;
  min-height: 36px;
  text-decoration: none;
  white-space: nowrap;
}

/* ——— Switch ———
   A real switch rather than a checkbox: it is the control the rest of the
   product already uses for binary preferences, and the larger target suits a
   touch device. State is carried by aria-checked as well as the class. */

.settings-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  padding: 5px 5px 5px 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg-3);
  color: var(--cream-dim);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition:
    background-color 0.2s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.2s ease;
}

.settings-switch-track {
  position: relative;
  display: block;
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--cream) 12%, transparent);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: background-color 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.settings-switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--cream-dim);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition:
    transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.2s ease;
}

.settings-switch.is-on {
  color: var(--on-solid, #07111f);
  background-color: var(--gold-btn-to);
  background-image: linear-gradient(180deg, var(--gold-btn-from), var(--gold-btn-to));
  border-color: var(--gold-btn-border);
}

.settings-switch.is-on .settings-switch-track {
  background-color: rgba(7, 17, 31, 0.34);
}

.settings-switch.is-on .settings-switch-thumb {
  background: #ffffff;
  transform: translateX(18px);
}

.settings-switch:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--gold) 70%, transparent);
  outline-offset: 2px;
}

/* When the OS preference disables sound, say why rather than showing a
   control that silently does nothing. */
.settings-switch:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.settings-note {
  margin: 4px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, #f59e0b 30%, var(--line));
  background: color-mix(in srgb, #f59e0b 9%, transparent);
  color: var(--cream-dim);
  font-size: 0.82rem;
  line-height: 1.55;
}

/* ——— Sound sample ———
   Plays a tone and briefly lights up, so the click is confirmed visually as
   well as audibly. The animation is retriggered by removing and re-adding the
   class, so rapid presses restart the pulse instead of ignoring it. */

#settings-sound-test {
  position: relative;
  overflow: hidden;
  transition:
    border-color 0.2s ease,
    color 0.2s ease;
}

#settings-sound-test.is-played {
  border-color: var(--gold-btn-border);
  color: var(--gold-bright);
  animation: settings-tone-pulse 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes settings-tone-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--gold) 55%, transparent); }
  100% { box-shadow: 0 0 0 12px color-mix(in srgb, var(--gold) 0%, transparent); }
}

#settings-sound-test:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ——— Segmented control ——— */

.settings-segmented {
  display: inline-flex;
  flex: 0 0 auto;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--bg-3);
}

.settings-segment {
  min-height: 30px;
  padding: 0 15px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition:
    color 0.18s ease,
    background-color 0.18s ease;
}

.settings-segment:hover {
  color: var(--cream);
}

.settings-segment.is-on {
  color: var(--on-solid, #07111f);
  background-color: var(--gold-btn-to);
  background-image: linear-gradient(180deg, var(--gold-btn-from), var(--gold-btn-to));
  font-weight: 800;
}

.settings-segment:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--gold) 70%, transparent);
  outline-offset: 2px;
}

/* ——— Appearance block ———
   Reuses the trainer's .appearance-* components, but widens the swatch grid:
   four per row reads as a set of choices rather than a cramped list. */

.settings-block {
  margin-top: 4px;
  padding-top: 4px;
}

.settings-appearance {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

/* ——— Option swatches ———
   The shared .appearance-* components are 28px chips inherited from the trainer,
   which is too small to judge anything and reads as a row of grey boxes. Here
   each option gets a real miniature preview of what it actually changes: a
   four-square board patch for finishes, a full piece for sets, and a short
   arrow or highlight chip for the rest. The swatch label stays underneath. */

/* ——— Option swatches ———
   The shared .appearance-* components are defined in style_training.css, which
   this page does not load. Without the base rules below the swatch buttons fall
   back to the browser default button styling — a flat grey box with default
   border and 16px system text — which is exactly what they looked like. So the
   label, row, and button base are all restated here, scoped to this page, and
   then the previews are upgraded on top.

   Each option is a real miniature of what it changes: a four-square board patch
   for finishes, a full piece for sets, an arrow with a head, and a board patch
   with the highlight painted on it. */

.settings-appearance .appearance-label {
  margin: 0 0 8px;
  color: var(--cream-dim);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.settings-appearance .appearance-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px;
  margin-bottom: 16px;
}

.settings-appearance .appearance-swatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  min-height: 0;
  padding: 10px 8px 9px;
  /* Every button property is set explicitly: none of these come from a reset
     on this page, so relying on a default here is what produced the grey box. */
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--bg-3);
  color: var(--cream);
  font-family: var(--font);
  font-size: 0.72rem;
  font-weight: 650;
  line-height: 1.25;
  text-align: center;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition:
    border-color 0.18s ease,
    background-color 0.18s ease,
    transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.18s ease;
}

.settings-appearance .appearance-swatch:hover {
  border-color: color-mix(in srgb, var(--gold) 45%, var(--line));
  background: var(--hover-fill);
  transform: translateY(-1px);
}

.settings-appearance .appearance-swatch:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--gold) 70%, transparent);
  outline-offset: 2px;
}

/* Selected: a clear ring plus a check, so state does not rely on border hue
   alone for anyone who cannot distinguish the accent colour. */
.settings-appearance .appearance-swatch.is-on {
  border-color: var(--gold-btn-border);
  background: color-mix(in srgb, var(--gold) 9%, var(--bg-3));
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--gold) 35%, transparent),
    0 0 0 3px color-mix(in srgb, var(--gold) 12%, transparent);
}

/* The preview sits in a small well so it reads as a sample of the board
   rather than a floating icon. */
.settings-appearance .appearance-board,
.settings-appearance .appearance-arrow,
.settings-appearance .appearance-highlight,
.settings-appearance .appearance-swatch img {
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  border-radius: 6px;
}

/* Piece sets: no well, the piece itself is the sample. */
.settings-appearance .appearance-swatch img {
  background: none;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
}

/* Four squares instead of two, so a board finish reads as a board.

   The square colours are restated here rather than inherited: they live in
   style_training.css, which this page does not load. Without them the squares
   render transparent and every board option looks like an empty grey box —
   which is exactly the problem this replaces. */
.settings-appearance .appearance-board {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}

.settings-appearance .appearance-board i {
  display: block;
  background: transparent;
}

.settings-appearance .appearance-board i:nth-child(1),
.settings-appearance .appearance-board i:nth-child(4) {
  background: var(--swatch-light);
}

.settings-appearance .appearance-board i:nth-child(2),
.settings-appearance .appearance-board i:nth-child(3) {
  background: var(--swatch-dark);
}

.settings-appearance .appearance-arrow {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--swatch) 32%, #1a1d23), #2a2e36);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}

/* A real arrow head, so the arrow options can be told apart at a glance
   instead of being four identical coloured bars. */
.settings-appearance .appearance-arrow::before {
  content: "";
  position: absolute;
  left: 6px;
  right: 6px;
  top: 50%;
  height: 3px;
  border-radius: 999px;
  background: var(--swatch);
  box-shadow: 0 0 8px color-mix(in srgb, var(--swatch) 55%, transparent);
  transform: translateY(-50%) rotate(-20deg);
  transform-origin: left center;
}

.settings-appearance .appearance-arrow::after {
  content: "";
  position: absolute;
  right: 6px;
  top: 50%;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 7px solid var(--swatch);
  transform: translateY(-50%) rotate(-20deg);
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--swatch) 55%, transparent));
}

/* Highlights: a real board patch, with the selected effect painted on it. */
.settings-appearance .appearance-highlight {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--board-light) 90%, #000) 50%,
      color-mix(in srgb, var(--board-dark) 90%, #000) 50%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}

.settings-appearance .appearance-highlight::after {
  background: color-mix(in srgb, var(--swatch) 52%, transparent);
}

.settings-appearance .appearance-highlight[data-effect="ring"]::before {
  inset: 5px;
  border-width: 2px;
}

.settings-appearance .appearance-swatch > span:last-child {
  color: var(--cream-dim);
  font-size: 0.7rem;
  font-weight: 650;
  line-height: 1.25;
}

.settings-appearance .appearance-swatch.is-on > span:last-child {
  color: var(--cream);
}

.settings-footnote {
  margin: 2px 0 0;
  padding: 0 4px;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.6;
}

/* ——— Responsive ——— */

/* The board and its controls stop fitting side by side well before the phone
   breakpoint, so the preview goes full width above the controls. */
@media (max-width: 900px) {
  .settings-look {
    grid-template-columns: minmax(0, 1fr);
    gap: 18px;
  }

  .settings-preview {
    position: static;
    max-width: 340px;
  }
}

@media (max-width: 640px) {
  .settings-view {
    padding: 20px 0 44px;
  }

  .settings-card {
    padding: 16px 15px;
  }

  .settings-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  .settings-switch,
  .settings-segmented,
  .settings-row-action {
    align-self: stretch;
    justify-content: space-between;
  }

  .settings-segment {
    flex: 1 1 0;
    padding: 0 10px;
  }

  .settings-row-action {
    justify-content: center;
  }

  .settings-appearance .appearance-row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ——— Dialog on small screens ———
   A phone has no room for a centred dialog with a page behind it, so it becomes
   a sheet: edge to edge, anchored to the bottom, with the backdrop still there
   to say the page behind is not live. A dialog kept at the desktop size here
   would either be unusably narrow or cover everything anyway. */
@media (max-width: 640px) {
  .settings-dialog {
    width: 100%;
    max-width: 100%;
    height: 92vh;
    max-height: 92vh;
    /* Anchored to the bottom, so it reads as coming from the thumb rather than
       from nowhere. `margin: auto auto 0` is what a centred dialog uses, so
       the top margin is what has to be undone. */
    margin: auto auto 0;
    border-radius: 18px 18px 0 0;
    border-bottom: none;
  }

  .settings-dialog-head {
    padding: 15px 15px 12px;
  }

  .settings-dialog-body {
    padding: 13px 15px 18px;
    /* Clears the home indicator on a phone that has one. */
    padding-bottom: max(18px, env(safe-area-inset-bottom, 0px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .settings-switch,
  .settings-switch-track,
  .settings-switch-thumb,
  .settings-segment,
  .settings-preview-arrow,
  #settings-sound-test,
  .settings-appearance .appearance-swatch {
    transition: none;
  }

  .settings-appearance .appearance-swatch:hover {
    transform: none;
  }

  /* The live pip and the tone pulse are decoration, so they stop rather than
     just being shortened. */
  .settings-preview-caption::after,
  #settings-sound-test.is-played {
    animation: none;
  }

  /* The dialog and its backdrop fade. Dropping the backdrop's animation
     entirely would leave it opaque for the first frame, which is a flash of
     undimmed page — the same reason it is not simply removed. */
  .settings-dialog[open] {
    animation: none;
  }

  .settings-dialog::backdrop {
    animation: settings-backdrop-in 0.01s linear;
  }
}
