/* Eigendrum - Bauhaus preliminary-course study sheet.
 *
 * Plaster ground, hard fields of vermilion / ultramarine / chrome yellow, 3px
 * black rules, one geometric sans set lowercase. No cards, no shadows, no
 * gradients, no rounded corners: the composition is made of fields and rules.
 *
 * The colour plan gives every primary a job, and each owns a whole region rather
 * than accenting one:
 *   vermilion  = the bench, where you act
 *   ultramarine = the ledger, where the measurements are
 *   chrome yellow = the remarkable thing, and whatever is selected
 *   plaster + ink = the study itself
 */

:root {
  --plaster: #f0ede6;
  --plate: #e8e3d6;
  --ink: #14120f;
  --ink-soft: #55504a;
  --vermilion: #c62d1a;
  --vermilion-bright: #d8321c;
  --ultramarine: #1b39a8;
  --ultramarine-tint: #c9d2f5;
  --chrome: #f2c300;

  --rule: 3px;
  --hair: 1px;
  --masthead-h: 4.75rem;

  --font: 'Jost', 'Futura', 'Century Gothic', 'Avenir Next', system-ui, sans-serif;
}

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

/* A class selector that sets `display` outranks the UA stylesheet's
   `[hidden] { display: none }`, which once left an invisible overlay on top of
   the page swallowing every pointer event. Make the attribute win, always. */
[hidden] {
  display: none !important;
}

html {
  background: var(--plaster);
}

body {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--plaster);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 40;
  background: var(--chrome);
  color: var(--ink);
  padding: 0.7rem 1.1rem;
  font-weight: 600;
  text-decoration: none;
}
.skip:focus {
  left: 0;
}

:focus-visible {
  outline: var(--rule) solid var(--ink);
  outline-offset: 2px;
}
.bench :focus-visible,
.ledger :focus-visible {
  outline-color: #fff;
}

/* ---------------------------------------------------------------- masthead */

.masthead {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 1.5rem;
  min-height: var(--masthead-h);
}

.mark {
  width: 2.35rem;
  height: 2.35rem;
  flex: none;
}

.masthead-titles {
  min-width: 0;
}

.masthead-titles h1 {
  font-size: clamp(1.45rem, 2.4vw, 2rem);
  line-height: 1;
  letter-spacing: -0.035em;
  font-weight: 600;
}

.masthead-titles p {
  margin: 0.15rem 0 0;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}

.masthead-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* The source address and the support link are chips, not underlined text. They were
   underlined text, which was readable but did not look pressable, and on this sheet a
   thing you can do carries a keyline. `.chip` already resets text-decoration and
   inverts on hover, so an <a> needs nothing beyond it. Neither takes a hue: vermilion
   is the bench, ultramarine the ledger and chrome yellow selection, and a link in the
   masthead is none of those. */

/* The address is spelled out where there is room, so a viewer of a screen recording
   can read it and type it in, and collapses to one word where there is not. */
.narrow-only {
  display: none;
}
@media (max-width: 78rem) {
  .wide-only {
    display: none;
  }
  .narrow-only {
    display: inline;
  }
}

/* ------------------------------------------------------------------- chips */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  /* Chips are also used on <a>, where the UA underline has to go: the keyline is
     already carrying "this is pressable", and both marks together reads as a link
     wearing a button. */
  text-decoration: none;
  padding: 0.4rem 0.75rem;
  border: var(--hair) solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background-color 110ms linear, color 110ms linear;
}
/* Hover tints, pressed fills. They used to render identically, which made a
   pressed chip indistinguishable from a hovered unpressed one. */
.chip:hover {
  background: rgba(20, 18, 15, 0.09);
}
.chip svg {
  width: 1.05rem;
  height: 1.05rem;
  flex: none;
}
.chip[aria-pressed='true'] {
  background: var(--ink);
  color: var(--plaster);
}


.chip-solid {
  background: var(--ink);
  color: var(--plaster);
}
.chip-solid:hover {
  background: var(--vermilion);
  color: #fff;
}

/* On the saturated fields the chip inverts: white keyline, white text. */
.chip-invert {
  border-color: #fff;
  color: #fff;
}
.chip-invert:hover {
  background: #fff;
  color: var(--ink);
}

/* ------------------------------------------------------------------ sheet */

/* A bounded app shell: the first row takes whatever height is left after the
   masthead and the bench, so the mode index scrolls inside itself rather than
   pushing the vermilion band off the bottom of the screen. */
.sheet {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 21.5rem;
  grid-template-rows: minmax(0, 1fr) auto;
  border-top: var(--rule) solid var(--ink);
  min-height: 0;
}

/* On a wide screen this is an instrument, not a document: pin it to the viewport
   so the drum, the index and the bench are all present at once, and let the
   columns scroll inside themselves. Below the breakpoint the page stacks and
   scrolls normally. */
@media (min-width: 62.0625rem) {
  body {
    height: 100svh;
    overflow: hidden;
  }
}

/* -------------------------------------------------------------- the study */

/* Big square plate flush left, text column beside it. Two things fall out: the
   drum fills its plate instead of floating in a wide box, and the readout and the
   form list cost no vertical space, which is what keeps the vermilion bench
   inside the first viewport. */
.study {
  grid-row: 1;
  display: grid;
  /* A definite track, not `auto`. With an auto track, the plate's own
     `min(..., 100%)` width would depend on a column width that depends on the
     plate, and the whole thing collapses to zero. */
  grid-template-columns: min(56vh, 600px) minmax(0, 1fr);
  gap: 1.1rem 1.75rem;
  align-content: start;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  padding: 1.15rem 1.5rem 1.25rem;
  border-right: var(--rule) solid var(--ink);
}

/* Square, sized from the viewport rather than from the grid, so nothing can
   stretch it out of shape. Explicit width and height beat aspect-ratio here:
   a stretched grid item silently overrides aspect-ratio. */
.plate {
  position: relative;
  width: 100%;
  height: min(56vh, 600px);
  background: var(--plate);
  border: var(--hair) solid var(--ink);
}

/* Anchored to the bottom of the column, so its baseline lines up with the foot of
   the plate. That turns the leftover space into a deliberate interval instead of
   a hole in the middle of the sheet. */
.forms {
  margin-top: auto;
  padding-top: 1.25rem;
}

#board {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: crosshair;
}
/* Inset, so the focus ring does not read as a second border on the plate. */
#board:focus-visible {
  outline-offset: -4px;
}

.study-side {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  min-width: 0;
}

/* A vertical study-sheet annotation rather than a floating pill. */
.prompt {
  position: absolute;
  left: 0.55rem;
  bottom: 0.9rem;
  margin: 0;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.26em;
  color: var(--ink-soft);
  pointer-events: none;
}

.solving {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  background: var(--plate);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  color: var(--ink-soft);
}
.solving-rule {
  display: block;
  width: min(52%, 18rem);
  height: var(--rule);
  background: var(--ink);
  transform-origin: left center;
  animation: sweep 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes sweep {
  0% {
    transform: scaleX(0);
  }
  55% {
    transform: scaleX(1);
  }
  100% {
    transform: scaleX(1);
    opacity: 0;
  }
}

/* An ink field, not a yellow one. Chrome yellow already means "selected" and
   "the remarkable thing" here, and rendering a failure in the celebration colour
   is a lie about what happened. */
.notice {
  margin: 0;
  padding: 0.6rem 0.85rem;
  background: var(--ink);
  color: var(--plaster);
  font-size: 0.95rem;
  font-weight: 500;
}

.readout {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.45;
  max-width: 40ch;
  min-height: 4.4rem;
  color: var(--ink);
}
.readout b {
  font-weight: 600;
}
.readout .note {
  color: var(--ink-soft);
}

/* The spectrum as a comb on a log-frequency axis. Bars measured from zero cannot
   show interval, and interval is the whole character of a drum: this shows the
   overtones crowding together as they climb. For the isospectral pair the
   partner's spectrum is drawn above the same axis, so its coincidence is
   something you see rather than something we assert. */
.comb {
  margin: 0;
  padding-top: 0.8rem;
  border-top: var(--hair) solid rgba(20, 18, 15, 0.25);
}
.comb figcaption {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--ink-soft);
}
.comb-axis {
  position: relative;
  height: 3rem;
  margin-top: 0.6rem;
}
.comb-axis::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: var(--ink);
}
.comb-tick {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 0.8rem;
  margin-left: -1px;
  background: var(--ink);
}
.comb-tick.is-selected {
  width: 4px;
  margin-left: -2px;
  top: 20%;
  height: 1.9rem;
}
.comb-tick.is-partner {
  top: auto;
  bottom: 50%;
  background: var(--ultramarine);
}
.comb-ends {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

.aside-note {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  max-width: 44ch;
  color: var(--ink-soft);
}

.key {
  list-style: none;
  margin: 0;
  padding: 0.7rem 0 0;
  border-top: var(--hair) solid rgba(20, 18, 15, 0.25);
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.82rem;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
}
.key li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.sw {
  width: 0.9rem;
  height: 0.9rem;
  flex: none;
}
.sw-pos {
  background: var(--vermilion-bright);
}
.sw-neg {
  background: var(--ultramarine);
}
.sw-nodal {
  background: var(--plate);
  box-shadow: inset 0 0 0 1px var(--ink);
}

.forms h2 {
  margin-bottom: 0.5rem;
}

h2 {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--ink-soft);
  margin-bottom: 0.6rem;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* Preset buttons carry a drawn glyph of the form itself. */
.form-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.32rem 0.7rem 0.32rem 0.4rem;
  border: var(--hair) solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background-color 110ms linear, color 110ms linear;
}
.form-chip svg {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
}
.form-chip:hover {
  background: var(--ink);
  color: var(--plaster);
}
.form-chip:hover svg [data-fill] {
  fill: var(--plaster);
}
.form-chip[aria-pressed='true'] {
  background: var(--chrome);
  border-color: var(--ink);
  color: var(--ink);
  font-weight: 600;
}
/* Solid, because on this surface drawing your own is the real invitation. */
.form-chip-draw {
  background: var(--ink);
  color: var(--plaster);
}
.form-chip-draw:hover {
  background: var(--vermilion);
  border-color: var(--vermilion);
  color: #fff;
}
.form-chip-draw[aria-pressed='true'] {
  background: var(--chrome);
  border-color: var(--ink);
  color: var(--ink);
}

/* ------------------------------------------------------ the equation panel */

/* A region, not a card: plaster ground with a 3px ink rule above it, so it is
   separated by adjacency and rule weight like everything else here. It takes no
   hue of its own, because the three primaries already have jobs and this is a
   place to write rather than a bench, a ledger or a remarkable thing. */
.formula {
  border-top: var(--rule) solid var(--ink);
  padding-top: 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.formula h2 {
  margin-bottom: 0;
}
.formula-kinds {
  display: flex;
  gap: 0.4rem;
}

.formula-fields {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.formula-field {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
/* Tabular figures and a fixed width, so r(t), x(t) and y(t) put their inputs on
   the same left edge and the two parametric rows read as one pair. */
.formula-var {
  flex: none;
  width: 3.1rem;
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--ink-soft);
}

/* White ground on plaster: this is the one place on the sheet you write, and
   paper is what you write on. No radius, 1px keyline like every other component
   keyline, and the page's own face - there is no monospace in this system. */
.formula input[type='text'] {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--ink);
  background: #fff;
  border: var(--hair) solid var(--ink);
  border-radius: 0;
  padding: 0.34rem 0.5rem;
}
.formula input[type='text']:focus-visible {
  outline: var(--rule) solid var(--ink);
  outline-offset: 1px;
}

.formula-hint {
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: 48ch;
}

.formula-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.formula-examples {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}
/* The gallery is a set of starting points, not a set of presets, so its chips are
   deliberately quieter than the form chips above. */
.chip-tiny {
  font-size: 0.78rem;
  padding: 0.24rem 0.5rem;
}

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

/* One scroll region for the whole right column. Two nested scrollers (a list
   inside a panel) is worse than one, and this stays predictable on short
   viewports where the ledger would otherwise be clipped out of reach. */
.index {
  grid-row: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
}

/* Takes the column's slack and scrolls inside itself, so the ledger below it is
   always fully visible and never painted over the list. Previously the ledger was
   sticky here and covered the last five rows: they were unreachable and, since the
   rows became playable, un-pressable - elementFromPoint on mode 16 returned a
   ledger term. The narrow-viewport rules already avoided this; desktop did not. */
.modes {
  padding: 1.25rem 1.25rem 1rem;
  flex: 1 1 auto;
  /* A floor, so a tall Kac panel can never squeeze the list away to nothing. If the
     three sections together still do not fit, `.index` scrolls as a backstop. */
  min-height: 8rem;
  display: flex;
  flex-direction: column;
}
.modes h2 {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
}
#modes-count {
  font-weight: 400;
  letter-spacing: 0.08em;
}

/* The rows do not read as buttons at a glance, and their most interesting property
   - that each one sounds - should not have to be discovered by accident. */
.modes-hint {
  margin: 0.35rem 0 0.55rem;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
}

.spectrum {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--hair) solid var(--ink);
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* A caption, not a field. The solid ink field means "something went wrong and here
   is what to do"; staleness is a quieter kind of truth and must not borrow that
   voice. It heads the whole column, because the mode list, the comb and the
   measurements are all equally out of date while you are tracing. */
.stale-note {
  flex: none;
  margin: 0;
  padding: 0.6rem 1.25rem;
  border-bottom: var(--hair) solid rgba(20, 18, 15, 0.3);
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.mode-row {
  position: relative; /* anchors the excitation rule */
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr) 4.4rem;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.3rem 0.35rem;
  border: 0;
  border-bottom: var(--hair) solid rgba(20, 18, 15, 0.22);
  background: transparent;
  font: inherit;
  font-size: 0.82rem;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background-color 110ms linear;
}
.mode-row:hover {
  background: rgba(20, 18, 15, 0.07);
}
.mode-row[aria-pressed='true'] {
  background: var(--chrome);
  font-weight: 600;
}

.mode-n {
  font-variant-numeric: tabular-nums;
  font-size: 0.74rem;
  color: var(--ink-soft);
}
.mode-row[aria-pressed='true'] .mode-n {
  color: var(--ink);
}

/* The ratio to the fundamental, which is the number that actually characterises a
   drum. A bar measured from zero looked like information and was not: at these
   frequencies eight consecutive rows differ by a few percent of their length. */
.mode-ratio {
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  font-size: 0.82rem;
}
.mode-row[aria-pressed='true'] .mode-ratio {
  color: var(--ink);
}

.mode-hz {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* How much of the sound now ringing this mode actually is. The one quantity that
   ties the mode list to the drum: a strike is not one of these rows, it is this
   whole set of lengths at once. A bar is honest here in a way it was not for
   frequency - these values really do run from zero to one, and the exact zeros are
   the interesting part.

   Drawn as a field filling the row from the left, not as a rule along its foot. At
   30px per row a footer rule lands 3px from the divider and 12px from its own
   numbers, so proximity says "divider" and the eye assigns it to the row below. I
   misattributed it that way twice while reviewing screenshots and concluded the
   readout contradicted the bars when it did not. If the author cannot attribute the
   mark, a reader cannot either; inside the row there is nothing to confuse. */
.mode-drive {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  background: rgba(20, 18, 15, 0.14);
  /* Scaled rather than resized: transform stays off the layout path, so sixteen of
     these updating on every strike cost nothing. */
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 90ms linear;
}
/* Positioned, and later in DOM order than the field, so the numbers stay above it. */
.mode-n,
.mode-ratio,
.mode-hz {
  position: relative;
}

/* A mode the strike could not reach: its nodal line was under the mallet. A
   full-height stub at the left edge, at full ink, because a measured zero is a
   result and should not look like missing data. Deliberately not expressed by
   fading the numbers - that would drop real information below AA contrast. The
   readout names these modes in words too, so the mark is never the only channel. */
.mode-row.is-mute::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--ink);
}

/* Chrome-yellow field: the theorem. It sits at the top of the column, because
   when it applies it is the most interesting thing on the page and its action
   must not be pushed below the fold. */
.kac {
  flex: none;
  background: var(--chrome);
  color: var(--ink);
  padding: 1.1rem 1.25rem 1.25rem;
  border-bottom: var(--rule) solid var(--ink);
}
.kac h2 {
  color: var(--ink);
  letter-spacing: 0.12em;
}
.kac p {
  margin: 0 0 0.85rem;
  font-size: 0.86rem;
  line-height: 1.45;
}
.kac .kac-match {
  font-weight: 600;
  border-top: var(--hair) solid rgba(20, 18, 15, 0.4);
  padding-top: 0.6rem;
}
.kac .chip-invert {
  border-color: var(--ink);
  color: var(--ink);
}
.kac .chip-invert:hover {
  background: var(--ink);
  color: var(--chrome);
}

/* Ultramarine field: the measurements. */
/* Pinned to the foot of the scrolling column: the measurements are the honesty of
   this thing, so they stay in view while the mode list scrolls behind them. */
.ledger {
  flex: none;
  background: var(--ultramarine);
  color: #fff;
  padding: 1.1rem 1.25rem 1.3rem;
  border-top: var(--rule) solid var(--ink);
}
.ledger h2 {
  color: var(--ultramarine-tint);
}
.ledger dl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.28rem 0.9rem;
  margin: 0;
  font-size: 0.82rem;
}
.ledger dt {
  color: var(--ultramarine-tint);
}
.ledger dd {
  margin: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}
.ledger dd.flag {
  color: var(--chrome);
  font-weight: 600;
}

/* -------------------------------------------------------------- the bench */

.bench {
  grid-row: 2;
  grid-column: 1 / -1;
  background: var(--vermilion);
  color: #fff;
  border-top: var(--rule) solid var(--ink);
  padding: 1.05rem 1.5rem 1.15rem;
  display: grid;
  grid-template-columns: minmax(0, 17rem) minmax(0, 1fr) auto;
  gap: 0.9rem 2.25rem;
  align-items: start;
}

/* Full white, no opacity: this is the heading that names the honesty boundary, and
   at 0.85 it fell to 4.37:1 against the vermilion. */
.bench h2 {
  color: #fff;
}
.bench-head p {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.5;
  max-width: 46ch;
}
.bench-head em {
  font-style: normal;
  font-weight: 600;
  border-bottom: 2px solid #fff;
}

.dials {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem 1.75rem;
}

.dial {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
}
.dial label {
  font-size: 0.8rem;
  letter-spacing: 0.08em;
}
.dial output {
  font-size: 0.8rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Ruled track, square handle. */
input[type='range'] {
  grid-column: 1 / -1;
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 1.25rem;
  margin: 0.15rem 0 0;
  background: transparent;
  cursor: pointer;
}
/* 0.9 rather than 0.55: the track is the only mark showing a slider's extent, so
   it is a UI component and owes 3:1. At 0.55 it was 2.24:1. */
input[type='range']::-webkit-slider-runnable-track {
  height: 2px;
  background: rgba(255, 255, 255, 0.9);
}
input[type='range']::-moz-range-track {
  height: 2px;
  background: rgba(255, 255, 255, 0.9);
}
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1rem;
  height: 1rem;
  margin-top: -0.44rem;
  background: #fff;
  border: 2px solid var(--ink);
  border-radius: 0;
}
input[type='range']::-moz-range-thumb {
  width: 1rem;
  height: 1rem;
  background: #fff;
  border: 2px solid var(--ink);
  border-radius: 0;
}

.bench-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.55rem;
}

.toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  cursor: pointer;
}
.toggle input {
  appearance: none;
  -webkit-appearance: none;
  width: 1.05rem;
  height: 1.05rem;
  margin: 0;
  border: 2px solid #fff;
  background: transparent;
  cursor: pointer;
}
.toggle input:checked {
  background: #fff;
  box-shadow: inset 0 0 0 3px var(--vermilion);
}

.takeaways {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.bench-status {
  margin: 0;
  font-size: 0.8rem;
  min-height: 1.1rem;
  text-align: right;
}

/* ------------------------------------------------------------------ about */

dialog {
  border: var(--rule) solid var(--ink);
  background: var(--plaster);
  color: var(--ink);
  padding: 0;
  max-width: 46rem;
  width: calc(100% - 2rem);
  max-height: 86svh;
  overflow: auto;
}
dialog::backdrop {
  background: rgba(20, 18, 15, 0.62);
}

.sheet-prose {
  padding: 1.6rem 1.75rem 0.5rem;
}
.sheet-prose h2 {
  font-size: 1.6rem;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-bottom: 1rem;
}
.sheet-prose h3 {
  margin: 1.75rem 0 0.4rem;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--vermilion);
}
.sheet-prose p {
  margin: 0 0 0.8rem;
  font-size: 0.95rem;
  line-height: 1.6;
  max-width: 68ch;
}
/* The embedded face ships upright only, so italic would be a synthesised oblique.
   Emphasis comes from weight instead. */
.sheet-prose em {
  font-style: normal;
  font-weight: 600;
}
.sheet-prose strong {
  font-weight: 600;
}

/* Notation set in the page's own face, tracked out, with lining figures. A system
   monospace here would be the one voice on the page that was not chosen - and a
   geometric sans is the right register for this world anyway: the Bauhaus set its
   own mathematics this way. */
.equation {
  background: var(--ink);
  color: var(--plaster);
  font-size: 1.05rem !important;
  font-weight: 500;
  letter-spacing: 0.07em;
  font-variant-numeric: tabular-nums lining-nums;
  text-align: center;
  padding: 0.95rem 0.75rem;
  max-width: none !important;
}
.tex {
  font-weight: 500;
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--ultramarine);
}

dialog form {
  display: flex;
  justify-content: flex-end;
  padding: 0 1.75rem 1.6rem;
}

/* ------------------------------------------------------------ responsive */

@media (max-width: 62rem) {
  /* Stacked and free-flowing: the page scrolls, so nothing is bounded or clipped. */
  .sheet {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
  }
  .study {
    grid-row: auto;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.1rem;
    overflow: visible;
    border-right: 0;
    padding-bottom: 1.25rem;
  }
  .index {
    grid-row: auto;
    overflow: visible;
  }
  .bench {
    grid-row: auto;
  }
  .plate {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
  }
  .readout {
    max-width: 60ch;
    min-height: 0;
  }
  .key {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.3rem 1.2rem;
  }
  .index {
    border-top: var(--rule) solid var(--ink);
  }
  /* No nested scrollers on touch: the page itself scrolls, so the mode list is let
     out to full height and every row is reached by scrolling the document. Bound the
     measure too, or a full-width row leaves the ratio and the frequency half a
     screen apart. */
  .modes {
    padding: 1.1rem 1.25rem 1rem;
    flex: none;
    min-height: 0;
    display: block;
  }
  .spectrum {
    max-width: 26rem;
    flex: none;
    overflow-y: visible;
  }
  .ledger dl,
  .kac p,
  .kac .chip-invert {
    max-width: 34rem;
  }
  .kac {
    border-top: var(--rule) solid var(--ink);
  }
  .bench {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.1rem;
  }
}

@media (max-width: 34rem) {
  :root {
    --masthead-h: auto;
  }
  .masthead {
    padding: 0.8rem 1rem;
    gap: 0.7rem;
  }
  .masthead-titles p {
    display: none;
  }
  /* Four chips do not fit beside the wordmark on a phone, and the controls win. The
     source is the one to drop, because it is also in the explainer's colophon and the
     support link is not reachable any other way. */
  #link-source {
    display: none;
  }
  /* Only the explainer loses its label. The sound button keeps its words, because
     a 2px diagonal inside a 17px glyph is not a visible mute. */
  #btn-about span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  #btn-sound {
    font-size: 0.8rem;
  }
  .study,
  .modes,
  .kac,
  .ledger {
    padding-left: 1rem;
    padding-right: 1rem;
  }
  .bench {
    padding: 1.1rem 1rem 1.35rem;
  }
  .readout {
    font-size: 0.95rem;
  }
  .bench-status {
    text-align: left;
  }
  .sheet-prose {
    padding: 1.25rem 1.15rem 0.5rem;
  }
  dialog form {
    padding: 0 1.15rem 1.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .solving-rule {
    animation: none;
    transform: scaleX(1);
  }
}
