@charset "utf-8";
/* ==========================================================================
   tell.yolfez.com  ·  site.css
   ==========================================================================
   One stylesheet, five pages. It is built out of thirteen components and not
   out of per-page rules, because the pages that come after this one are
   assembled from the same parts:

     .shell      the page shell and its bands
     .keys       the key strip: the apparatus, declared once at the top
     .beat       a beat of the reading: two channels, HEARD and READ
     .lens       the loupe: an opening in a dark room, at beat.at
     .leader     a hairline from the ring to the words, where they are apart
     .slug       the apparatus slug: cue id, name, region, polarity
     .rel        the reliability mark, out of five
     .pol        the polarity mark: a shape and a word, never a colour
     .caveat     the caveat block: READS WRONG WHEN
     .cue        a cue entry, as the cues page sets it
     .btn        buttons
     .foot       the footer
     .guide      the cues page: a region rail, and a header that says where
                 in the body the reader currently is

   The colour law is the game's. The ground is harbour night and the
   paintings supply every warm colour on the page. No red and no green in the
   cue grammar: comfort and discomfort are a shape and a word. Insufficient
   evidence owns --calibration and is never a coward grey. Brass is for the
   things a visitor does.

   The six names /assets /canon /data /js /css /tools are answered out of the
   game by the Worker, so this file sits at the root and the fonts live under
   /font.
   ========================================================================== */

/* --- the game's own typewriter face, OFL, licence shipped alongside ------ */
@font-face {
  font-family: 'Courier Prime';
  src: url('/font/CourierPrime-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Courier Prime';
  src: url('/font/CourierPrime-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   TOKENS
   ========================================================================== */

:root {
  /* ground */
  --ink: #0a1418;
  --ink-deep: #070e12;
  --deep: #0e1c22;
  --teal: #16323b;
  --teal-bright: #1e4e56;
  /* the quietest legible type, and legible is the load-bearing word: this
     measures 4.84:1 on the ground, above the 4.5:1 floor, because it carries
     "Nothing said here." on the silent beats and the polarity word in every
     slug, and those are not decoration */
  --slate: #748491;
  --rain: #8fa7ad;

  /* signal */
  --silver: #c9d2d4;
  --white: #f4f7f9;
  --gold: #b9a67c;

  /* points */
  --brass: #c9973f;
  --calibration: #7d93b2;

  /* type */
  --prose: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  --type: 'Courier Prime', ui-monospace, 'Courier New', monospace;

  /* measure */
  --wide: 76rem;
  --measure: 34rem;
  --gutter: clamp(1.15rem, 4.5vw, 3.25rem);

  /* lines */
  --rule: rgba(30, 78, 86, 0.55);
  --rule-soft: rgba(30, 78, 86, 0.3);
  --hair: rgba(143, 167, 173, 0.5);

  /* the dark room the lens opens in */
  --matte: rgba(5, 10, 13, 0.62);

  /* the gap between the two channels, which is the design */
  --channel-gap: clamp(1.25rem, 3.4vw, 3.25rem);

  /* the caveats are the honest part and never the smallest type here */
  --small: 0.875rem;
}

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

html {
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: clip;
}

body {
  margin: 0;
  overflow-x: clip;
  background: var(--ink);
  color: var(--silver);
  font-family: var(--prose);
  font-size: clamp(1.02rem, 0.98rem + 0.25vw, 1.14rem);
  line-height: 1.66;
  -webkit-font-smoothing: antialiased;
  background-image: radial-gradient(120% 62% at 50% -8%, rgba(30, 78, 86, 0.22), transparent 62%);
}

img { display: block; max-width: 100%; }
h1, h2, h3, h4 { font-weight: 400; margin: 0; color: var(--white); line-height: 1.12; }
p, figure, figcaption, blockquote, ul, ol, dl, dd { margin: 0; }
a { color: var(--rain); }
::selection { background: rgba(201, 151, 63, 0.3); color: var(--white); }
:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }

/* a name for a screen reader where the visible text is a code or is repeated
   seven times over. It is never used to say something the page does not. */
.vh {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 60;
  background: var(--brass); color: var(--ink-deep);
  font-family: var(--type); font-size: 0.72rem; letter-spacing: 0.18em;
  text-transform: uppercase; text-decoration: none; padding: 0.7rem 1.1rem;
}
.skip:focus { left: 0; }

/* a small, unmoving grain so the flat fields of ink do not band */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 50; pointer-events: none;
  opacity: 0.5;
  background-image: repeating-linear-gradient(0deg, rgba(143, 167, 173, 0.016) 0 1px, transparent 1px 6px);
}

/* ==========================================================================
   1. THE SHELL
   One width, one gutter, one vertical rhythm. Everything sits in it.
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* A page that is only prose is one column, centred, and the prose fills it.
   /reading/ and /chapters/ used to set a 34rem measure at the left edge of the
   full 76rem shell, which left half the screen empty with no painting in it. */
.shell--tight { max-width: 44rem; }
.shell--tight .lede,
.shell--tight .lede--wide { max-width: none; }

.band { padding-block: clamp(2.75rem, 8vw, 6.5rem); }
.band--rule { border-top: 1px solid var(--rule-soft); }
.band--close { padding-block: clamp(2.25rem, 5vw, 4rem); }

.label {
  font-family: var(--type);
  font-size: 0.7rem; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--rain);
  margin-bottom: 1.15rem;
  display: flex; align-items: center; gap: 0.9rem;
}
.label::after {
  content: ''; flex: 1 1 2rem; min-width: 1.5rem; height: 1px; background: var(--rule);
}

.head {
  font-size: clamp(1.9rem, 5.2vw, 3.1rem);
  letter-spacing: -0.015em;
  max-width: 18ch;
}
.lede {
  margin-top: clamp(1.2rem, 2.4vw, 1.8rem);
  max-width: var(--measure);
  color: var(--silver);
}
.lede--wide { max-width: 44rem; }
.lede + .lede { margin-top: 1rem; }
.say {
  margin-top: clamp(1.8rem, 4vw, 2.75rem);
  font-size: clamp(1.15rem, 2.6vw, 1.45rem);
  line-height: 1.46;
  color: var(--white);
  max-width: 34ch;
}
.band > .shell > .say:first-child { margin-top: 0; }

/* the masthead */
.mast { border-bottom: 1px solid var(--rule-soft); }
.mast .shell {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 0.75rem 1.5rem; flex-wrap: wrap; padding-block: 1rem;
}
.mast-word {
  font-family: var(--type); font-weight: 700;
  letter-spacing: 0.42em; font-size: 0.85rem;
  color: var(--white); text-decoration: none;
}
.mast nav {
  font-family: var(--type); font-size: 0.74rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  display: flex; flex-wrap: wrap; gap: 0.45rem 1.4rem;
}
.mast nav a { color: var(--rain); text-decoration: none; }
.mast nav a:hover, .mast nav a:focus-visible { color: var(--white); }
.mast nav a[aria-current] { color: var(--white); }
/* brass is for the things a visitor does, and this is the only one in the
   masthead. It is also the only word above the fold that says the thing at the
   end of this is played rather than read. */
.mast nav .mast-play {
  color: var(--brass);
  border-bottom: 1px solid rgba(201, 151, 63, 0.45);
  padding-bottom: 0.2rem;
}
.mast nav .mast-play:hover, .mast nav .mast-play:focus-visible {
  color: var(--white); border-bottom-color: var(--white);
}

/* the open: one painting, one line */
.open-hero { position: relative; }
.open-art {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 76vh;
  overflow: hidden;
  background: var(--ink-deep);
}
.open-art img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 44%; }
.open-say {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding-block: clamp(2rem, 8vh, 5rem) clamp(1.25rem, 4vh, 2.5rem);
  background: linear-gradient(to top, rgba(7, 14, 18, 0.94), rgba(7, 14, 18, 0.6) 46%, rgba(7, 14, 18, 0));
}
.open-line {
  font-size: clamp(1.75rem, 5vw, 3.4rem);
  line-height: 1.06;
  letter-spacing: -0.015em;
  max-width: 17ch;
  color: var(--white);
}
.open-sub {
  margin-top: clamp(0.9rem, 2vw, 1.3rem);
  max-width: 42ch;
  font-size: 0.97rem;
  color: var(--rain);
}
@media (max-width: 40rem) {
  /* the taller crop belongs to the hero, where the painting is the screen.
     /reading/ borrows .open-art for a figure inside its prose, and a figure
     keeps the shape of the painting it is showing. */
  .open-hero .open-art { aspect-ratio: 4 / 3; max-height: none; }
  .open-say {
    position: static;
    padding-block: 1.75rem 0;
    background: none;
  }
}

/* ==========================================================================
   2. THE KEY STRIP
   The apparatus, declared once before it is used. Four lines, then never
   again. It does not narrate the design.
   ========================================================================== */

.keys {
  margin-top: clamp(2rem, 5vw, 3.5rem);
  border-top: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  padding-block: clamp(1.1rem, 2.4vw, 1.5rem);
  display: grid;
  gap: 0.95rem clamp(1.5rem, 3.4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.key { display: flex; gap: 0.75rem; align-items: flex-start; }
.key-fig { flex: none; margin-top: 0.2rem; display: flex; align-items: center; gap: 0.4rem; }
.key-said {
  font-family: var(--type);
  font-size: var(--small);
  line-height: 1.6;
  color: var(--rain);
}
.key-said b {
  display: block; font-weight: 400;
  color: var(--white);
  letter-spacing: 0.16em; text-transform: uppercase;
  font-size: 0.66rem; margin-bottom: 0.3rem;
}
.key-ring {
  width: 20px; height: 13px;
  background: rgba(143, 167, 173, 0.16);
  box-shadow: 0 0 0 3px rgba(5, 10, 13, 0.85);
}
/* the three marks are declared the way they are used: each shape immediately
   in front of the word it means, never a row of shapes with a list beside it */
.key-pols {
  display: flex; flex-wrap: wrap;
  gap: 0.25rem 1.1rem;
  margin-bottom: 0.5rem;
}

/* ==========================================================================
   3. A BEAT
   Two channels side by side. The left is what was said. The right is the
   painting, the lens and what the game writes. The gap is the design.
   ========================================================================== */

.channels {
  position: sticky; top: 0; z-index: 20;
  background: var(--ink);
  border-block: 1px solid var(--rule-soft);
}
.channels .shell {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) 1px minmax(0, 1.25fr);
  column-gap: var(--channel-gap);
  padding-block: 0.6rem;
}
.channels .spine { grid-column: 2; }
.chan {
  font-family: var(--type); font-weight: 700;
  font-size: 0.68rem; letter-spacing: 0.28em; text-transform: uppercase;
}
.chan--heard { grid-column: 1; color: var(--gold); }
.chan--read { grid-column: 3; color: var(--rain); }
.chan small {
  display: block; margin-top: 0.15rem;
  font-family: var(--prose); font-weight: 400;
  font-size: 0.78rem; letter-spacing: 0; text-transform: none;
  color: var(--slate);
}

.reading { padding-bottom: clamp(1rem, 3vw, 2rem); }

.beat {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) 1px minmax(0, 1.25fr);
  column-gap: var(--channel-gap);
  width: 100%; max-width: var(--wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
  /* every beat is addressable by its cue id, and the cues page links to it
     that way, so a landing has to clear the sticky two-word channel header */
  scroll-margin-top: 3.25rem;
}
.beat .spine { grid-column: 2; grid-row: 1 / span 2; width: 1px; justify-self: center; }
.spine { background: var(--rule); }

.beat-head {
  grid-column: 1 / -1; grid-row: 1;
  display: flex; align-items: baseline; gap: 0.8rem;
  padding-top: clamp(2.4rem, 6vw, 4.25rem);
  padding-bottom: 1.1rem;
  font-family: var(--type);
  font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--slate);
}
.beat-num { font-size: 1.25rem; font-weight: 700; color: var(--silver); letter-spacing: 0.04em; }

/* the words hold their place beside the painting while it goes past */
.heard {
  grid-column: 1; grid-row: 2;
  padding-bottom: clamp(2.5rem, 6vw, 4rem);
  position: sticky; top: 4.6rem; align-self: start;
}
.read { grid-column: 3; grid-row: 2; padding-bottom: clamp(2.5rem, 6vw, 4rem); }

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

/* what was said */
.said { max-width: 32ch; }
.said + .said { margin-top: 1.1rem; }
.who {
  display: block;
  font-family: var(--type); font-size: 0.64rem;
  letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--gold); margin-bottom: 0.3rem;
}
.said q { quotes: none; display: block; font-size: 1.04rem; line-height: 1.54; color: var(--white); }

/* and where nothing was */
.silent {
  font-family: var(--type);
  font-size: var(--small); line-height: 1.7; letter-spacing: 0.08em;
  color: var(--slate);
  max-width: 32ch;
}
.silent::before {
  content: ''; display: block; width: 2.2rem; height: 1px;
  background: var(--rule); margin-bottom: 0.85rem;
}

/* the turn, on the first beat only, and only where there is script */
.turn-invite, .turn-cross, .turn-hit { display: none; }
.turn-said {
  font-family: var(--type);
  font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--brass);
  margin-top: 1rem;
}
.turn-said .t-in, .turn-said .t-out { display: none; }
/* held, not collapsed: the answer arrives in the space that was already
   waiting for it and the reading under it does not jump */
.js .beat--turn .turn-said { visibility: hidden; min-height: 1.66em; }
.js .beat--turn.answered .turn-said { visibility: visible; }
.js .beat--turn.found .t-in { display: inline; }
.js .beat--turn.missed .t-out { display: inline; }

.js .beat--turn .turn-invite {
  display: block;
  position: absolute; left: 50%; top: 1.25rem; z-index: 5;
  transform: translateX(-50%);
  padding: 0.6rem 1.15rem;
  border: 1px solid rgba(201, 151, 63, 0.8);
  background: rgba(7, 14, 18, 0.78);
  font-family: var(--type);
  font-size: 0.66rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--brass); text-align: center;
  max-width: calc(100% - 2rem);
}
.js .beat--turn .turn-hit {
  display: block; position: absolute; inset: 0; z-index: 6;
  width: 100%; height: 100%;
  margin: 0; padding: 0; border: 0; background: transparent;
  font: inherit; color: transparent; cursor: crosshair;
  text-indent: -9999px; overflow: hidden;
}
/* The one control the turn is built on fills a frame that clips, so the
   default ring at outline-offset 3px was drawn outside the clip and never
   painted. This one is drawn inside the button, where it survives. */
.js .beat--turn .turn-hit:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: -6px;
}
.js .beat--turn .turn-cross {
  display: block; position: absolute; inset: 0; z-index: 4;
  pointer-events: none; opacity: 0;
}
.js .beat--turn.aiming .turn-cross { opacity: 1; }
.js .beat--turn .turn-cross::before,
.js .beat--turn .turn-cross::after {
  content: ''; position: absolute; background: rgba(201, 151, 63, 0.45);
}
.js .beat--turn .turn-cross::before { left: var(--px, 50%); top: 0; bottom: 0; width: 1px; }
.js .beat--turn .turn-cross::after { top: var(--py, 50%); left: 0; right: 0; height: 1px; }
.js .beat--turn.answered .turn-invite,
.js .beat--turn.answered .turn-cross,
.js .beat--turn.answered .turn-hit { display: none; }

/* The light is withheld until the visitor has pointed, and so is everything
   that names the answer: a turn whose answer is set in prose in the same
   screen as the question is not a turn. The space is held, not collapsed, so
   nothing on the page moves when it arrives. With no script none of this
   applies and the beat is simply the first beat of the reading. */
.js .beat--turn:not(.answered) .lens-light,
.js .beat--turn:not(.answered) .leader,
.js .beat--turn:not(.answered) .slug,
.js .beat--turn:not(.answered) .note,
.js .beat--turn:not(.answered) .caveat { visibility: hidden; }

/* the ending: the grid breaks for the last beat, and only for the last beat */
.beat--last {
  grid-template-columns: minmax(0, 1fr);
  border-top: 1px solid var(--rule-soft);
  --last-w: clamp(15rem, 42vw, 30rem);
}
.beat--last .spine { display: none; }
.beat--last .beat-head { justify-content: center; padding-top: clamp(2rem, 5vw, 3.25rem); }
.beat--last .heard,
.beat--last .read { grid-column: 1; }
.beat--last .heard {
  grid-row: 2; padding-bottom: clamp(1.5rem, 4vw, 2.5rem);
  display: flex; justify-content: center;
  position: static;
}
.beat--last .said { text-align: center; max-width: 36ch; }
.beat--last .read { grid-row: 3; }
.beat--last .plate { margin-inline: auto; max-width: var(--last-w); }
.beat--last .slug,
.beat--last .note,
.beat--last .caveat { margin-inline: auto; max-width: var(--last-w); }
.beat--last .note { font-size: 1.12rem; }

/* ==========================================================================
   4. THE LENS
   Not an outline. An opening in a dark room: the region is lit and the rest
   of the painting falls into shadow. The four percentages come from
   beat.at and are used exactly as given. No arithmetic on top of them.
   ========================================================================== */

/* The painting is the best thing on the page, so it takes the whole of the
   column it was given. It used to be capped at 29rem, which left 139px of the
   READ column empty beside every portrait plate and made the lens on the small
   boxes too small to find. */
.plate { max-width: none; }

.lens {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ar);
}
.lens-frame {
  position: absolute; inset: 0;
  display: block; overflow: hidden;
  background: var(--ink-deep);
  border: 1px solid var(--rule-soft);
  isolation: isolate;
}
.lens-frame img { width: 100%; height: 100%; object-fit: cover; }

/* An opening has an edge, not an outline. The pale line that used to run the
   whole perimeter read as a selection marquee pasted on the painting, so the
   perimeter is now only the shadow falling off and a short inner fall of light
   at the rim; the four gold ticks are the sight, and they are the only drawn
   line on the picture. */
.lens-light {
  position: absolute;
  left: var(--l); top: var(--t); width: var(--w); height: var(--h);
  box-shadow:
    0 0 34px 100vmax var(--matte),
    inset 0 0 9px 1px rgba(5, 10, 13, 0.34);
  pointer-events: none;
}
/* THE LIGHT IS A PICTURE, NOT A FILTER.
   backdrop-filter: brightness() was the first way this worked and it failed
   twice: amplifying a near-black region live brought the eight-bit banding up
   with it, so the darkest cue rendered as a blue-violet block, and the whole
   device depended on a compositor that is not always there. So the lit region
   is cut out of the painting and lifted in tools/build-reading.mjs, by an
   amount measured from that region, and this simply lays it back down in the
   place it came from. No filter, no blend, no GPU, and it is the same picture
   in every browser. */
.lens-lit {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  object-fit: fill;
}

/* An opening has an edge, not a border. The lit picture is laid down with a
   hard rectangular cut, which reads as pasted, so a short fall of shade inside
   the rim lets the light arrive at its own boundary instead of stopping at it.
   It goes over the lit image, and the ticks go over both. */
.lens-light::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  box-shadow: inset 0 0 11px 2px rgba(5, 10, 13, 0.5);
  pointer-events: none;
}
.lens-tick { z-index: 2; }

.lens-tick { position: absolute; width: 9px; height: 9px; border: 0 solid var(--gold); }
.lens-tick:nth-child(1) { left: -1px; top: -1px; border-left-width: 1px; border-top-width: 1px; }
.lens-tick:nth-child(2) { right: -1px; top: -1px; border-right-width: 1px; border-top-width: 1px; }
.lens-tick:nth-child(3) { left: -1px; bottom: -1px; border-left-width: 1px; border-bottom-width: 1px; }
.lens-tick:nth-child(4) { right: -1px; bottom: -1px; border-right-width: 1px; border-bottom-width: 1px; }

/* ==========================================================================
   5. THE LEADER
   A hairline that leaves the ring's column, crosses the gap under the
   painting and dies in a small dot at the first word of the slug. It is
   drawn in the gap and never on the painting: a line down the middle of a
   plate is a scratch on the best thing on the page, not a connector.

   It is on wherever the lit box covers less than two per cent of its
   painting and has to be hunted for, which on the reading as it stands is
   the throat and the walk home, two beats of seven. Everywhere else the
   words are already twenty-two pixels under the picture and a connector
   between them would be a border. The threshold lives in
   tools/build-home.mjs, said in percentages of the painting, because the
   version before it was an area tuned to a beat the reading no longer has
   and it quietly turned the connector off everywhere.
   ========================================================================== */

.leader {
  display: none;
  position: absolute; z-index: 3;
  left: 0; right: 0;
  top: 100%;
  height: clamp(1.1rem, 2.6vw, 1.6rem);
  pointer-events: none;
}
/* the corner: down out of the ring's column, then left to the words */
.leader::before {
  content: ''; position: absolute;
  left: 0; top: 0; bottom: 0;
  width: calc(var(--l) + var(--w) / 2);
  border-right: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
}
/* the dot, sitting on the first word of the slug */
.leader::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 5px; height: 5px; background: var(--rain);
}
.lens--lead .leader { display: block; }
/* and not below 62rem, where the two channels have stacked and the words are
   already twenty-two pixels under the plate. A connector between two things
   that are touching is a border. This rule has been the documented behaviour
   since the connector was built and was never written down, because the
   threshold above it had stopped firing and nothing was ever drawn to notice. */
@media (max-width: 61.99rem) {
  .lens--lead .leader { display: none; }
}

/* ==========================================================================
   6. THE APPARATUS SLUG
   Cue id, cue name, body region, polarity. Printed once per beat, under the
   painting, in the game's own typewriter face.
   ========================================================================== */

.slug { margin-top: clamp(1.1rem, 2.6vw, 1.6rem); }
.slug-id {
  font-family: var(--type); font-size: 0.72rem;
  letter-spacing: 0.22em; color: var(--gold);
}
/* A cue id is the address of a cue, so where the same cue is set out in full
   somewhere else the id is the link to it. It keeps the gold it already has
   and takes a hairline, which is the site's way of saying a word goes
   somewhere. Used on the reading, never on the cues page, where the id is
   the entry's own name and has nowhere further to go. */
.id-link {
  color: inherit; font: inherit; letter-spacing: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 0.2rem;
}
.id-link:hover, .id-link:focus-visible {
  color: var(--white); border-bottom-color: var(--hair);
}

.slug-name {
  font-family: var(--type); font-size: 1.05rem;
  letter-spacing: 0.02em; color: var(--white);
  margin-top: 0.45rem;
}
.slug-meta {
  margin-top: 0.6rem;
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  font-family: var(--type); font-size: 0.68rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--slate);
}
.slug-meta .sep { color: var(--rule); }

/* the author's note, which is the sentence the game writes */
.note {
  margin-top: clamp(1rem, 2.4vw, 1.4rem);
  padding-top: clamp(1rem, 2.4vw, 1.4rem);
  border-top: 1px solid var(--rule-soft);
  max-width: 44ch;
  font-size: 1.05rem; line-height: 1.6;
  color: var(--white);
}

/* ==========================================================================
   7. THE RELIABILITY MARK
   Out of five, in squares, with the number said in words beside it. Two or
   under is thin evidence and wears --calibration, because saying the
   evidence is thin is the same act as saying it is insufficient.
   ========================================================================== */

/* The score and the word thin evidence are the honest part in miniature, so
   they sit at the 13px floor, above the region and the polarity beside them
   and above every label on the page. The thing that tells a reader not to
   trust a cue is not the hardest thing on the page to read. */
.rel {
  display: inline-flex; align-items: center; gap: 0.55rem;
  font-family: var(--type); font-size: 0.8125rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--rain);
}
.rel-pips { display: inline-flex; gap: 3px; }
.pip { display: block; width: 8px; height: 8px; box-shadow: inset 0 0 0 1px var(--slate); }
.pip--on { background: var(--rain); box-shadow: none; }
.rel--thin { color: var(--calibration); }
.rel--thin .pip--on { background: var(--calibration); }
.rel-tag {
  font-family: var(--type); font-size: 0.8125rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--calibration);
  border: 1px solid var(--calibration);
  padding: 0.05rem 0.45rem;
}

/* ==========================================================================
   8. THE POLARITY MARK
   Never a colour, always a shape and a word.
   ========================================================================== */

.pol { display: inline-flex; align-items: center; gap: 0.45rem; color: var(--rain); }
.pol i { flex: none; display: block; }
.pol--discomfort i { width: 9px; height: 9px; border: 1px solid currentColor; transform: rotate(45deg); }
.pol--comfort i { width: 9px; height: 9px; border: 1px solid currentColor; border-radius: 50%; }
.pol--neutral i { width: 11px; height: 1px; background: currentColor; }

/* ==========================================================================
   9. THE CAVEAT BLOCK
   The honest part. Never the smallest type on the page, and it sits with its
   cue. The caveats are conditional, not accusations.
   ========================================================================== */

.caveat {
  margin-top: clamp(1.1rem, 2.6vw, 1.5rem);
  padding-left: 1rem;
  border-left: 1px solid rgba(125, 147, 178, 0.45);
  max-width: 46ch;
}
.caveat-label {
  font-family: var(--type); font-size: 0.8125rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--calibration);
  margin-bottom: 0.6rem;
}
.caveat ul { list-style: none; padding: 0; }
.caveat li {
  font-family: var(--type);
  font-size: var(--small); line-height: 1.65;
  color: #96a8bd;
}
.caveat li + li { margin-top: 0.5rem; }

/* ==========================================================================
   10. A CUE ENTRY
   One cue as the cues page sets it: id, name, region, reliability, what it
   looks like, what its absence is called, and the reasons it is wrong. The
   cues page is twenty of these.
   ========================================================================== */

.cue {
  border-top: 1px solid var(--rule);
  padding-top: clamp(1.1rem, 2.4vw, 1.5rem);
  max-width: 46rem;
}
.cue-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 0.6rem 1.5rem; flex-wrap: wrap;
}
.cue-id {
  font-family: var(--type); font-weight: 700;
  font-size: 0.8rem; letter-spacing: 0.2em; color: var(--gold);
}
.cue-name {
  font-family: var(--type); font-size: 1.15rem;
  letter-spacing: 0.02em; color: var(--white); margin-top: 0.7rem;
}
.cue-meta {
  margin-top: 0.55rem;
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem 0.75rem;
  font-family: var(--type); font-size: 0.68rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--slate);
}
.cue-looks {
  margin-top: 1rem;
  max-width: 52ch;
  font-size: 1rem; line-height: 1.6;
  color: var(--silver);
}
.cue-absent {
  margin-top: 0.75rem;
  font-family: var(--type); font-size: var(--small);
  color: var(--rain);
}

/* the read menu, with the insufficient line at the top where the game puts it */
.menu { list-style: none; padding: 0; max-width: 46rem; margin-top: clamp(1.4rem, 3vw, 2rem); }
.menu li {
  border-top: 1px solid var(--rule-soft);
  border-left: 2px solid transparent;
  padding-block: 0.95rem;
  padding-left: 1rem;
  display: grid; gap: 0.35rem 1.25rem;
  grid-template-columns: minmax(0, 1fr);
}
.menu li:last-child { border-bottom: 1px solid var(--rule-soft); }
.menu .kind {
  font-family: var(--type); font-size: 0.66rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--slate);
}
.menu .opt { color: var(--silver); }
.menu .first .kind { color: var(--calibration); }
.menu .first .opt { color: var(--white); }
.menu .first { border-left-color: var(--calibration); }
@media (min-width: 46rem) {
  .menu li { grid-template-columns: 10.5rem minmax(0, 1fr); align-items: baseline; }
}

/* the twelve, set as a ledger */
.ledger {
  list-style: none; padding: 0;
  margin-top: clamp(1.4rem, 3vw, 2rem);
  max-width: 46rem;
  columns: 2; column-gap: clamp(1.5rem, 4vw, 3.5rem);
  font-family: var(--type);
  font-size: var(--small); letter-spacing: 0.06em;
  color: var(--silver);
}
.ledger li {
  break-inside: avoid;
  border-bottom: 1px solid var(--rule-soft);
  padding-block: 0.55rem;
}
@media (max-width: 34rem) { .ledger { columns: 1; } }

.held {
  margin-top: clamp(1.6rem, 3.5vw, 2.5rem);
  padding-left: clamp(1rem, 2vw, 1.5rem);
  border-left: 1px solid var(--gold);
  max-width: 40rem;
  font-size: clamp(1.1rem, 2.4vw, 1.3rem);
  line-height: 1.46;
  color: var(--white);
}

/* the four acts */
.acts {
  list-style: none; padding: 0;
  margin-top: clamp(1.4rem, 3vw, 2rem);
  display: grid; gap: 1px;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  background: var(--rule-soft);
  border: 1px solid var(--rule-soft);
}
.acts li {
  background: var(--ink);
  padding: clamp(1rem, 2.4vw, 1.6rem);
  font-family: var(--type);
  font-size: 0.95rem; letter-spacing: 0.04em;
  color: var(--white);
}
.acts .n {
  display: block; margin-bottom: 0.6rem;
  font-size: 0.64rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--slate);
}

/* ==========================================================================
   11. BUTTONS
   Brass is for the things a visitor does, and nothing else on the page is
   brass.
   ========================================================================== */

.btn {
  display: inline-block;
  font-family: var(--type);
  font-size: 0.75rem; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--ink-deep); background: var(--brass);
  padding: 0.95rem 1.8rem;
  text-decoration: none;
  border: 1px solid var(--brass);
}
.btn:hover, .btn:focus-visible { background: var(--white); border-color: var(--white); color: var(--ink-deep); }
.btn--quiet {
  background: none; color: var(--brass);
}
.btn--quiet:hover, .btn--quiet:focus-visible { background: var(--brass); color: var(--ink-deep); border-color: var(--brass); }
.btn-row { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: clamp(1.4rem, 3vw, 2rem); }
.fine {
  margin-top: 1.15rem;
  font-family: var(--type); font-size: var(--small);
  color: var(--slate); max-width: 40ch;
}
/* The link that carries a reader to the next page. It is the single
   invitation at the bottom of a long page and it sat at 11.52px under a
   49.6px heading, which is a ratio that tells the reader the invitation is a
   footnote. It is now above the cue ids and the scores it follows. */
.onward {
  display: inline-block;
  margin-top: clamp(1.4rem, 3vw, 2rem);
  font-family: var(--type); font-size: 0.82rem;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--brass); text-decoration: none;
  border-bottom: 1px solid rgba(201, 151, 63, 0.5);
  padding-bottom: 0.3rem;
}
.onward:hover, .onward:focus-visible { color: var(--white); border-bottom-color: var(--white); }

/* ==========================================================================
   12. THE FOOTER
   ========================================================================== */

.foot {
  border-top: 1px solid var(--rule-soft);
  padding-block: clamp(2rem, 5vw, 3.25rem);
}
.foot .shell {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 1rem 2rem;
}
.foot-word {
  font-family: var(--type); font-weight: 700;
  letter-spacing: 0.42em; font-size: 0.78rem; color: var(--slate);
}
.foot nav {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem;
  font-family: var(--type); font-size: 0.68rem;
  letter-spacing: 0.2em; text-transform: uppercase;
}
.foot nav a { color: var(--rain); text-decoration: none; }
.foot nav a:hover, .foot nav a:focus-visible { color: var(--white); }

/* ==========================================================================
   13. THE GUIDE
   The cues page sets twenty entries, grouped by the regions of the body they
   belong to, and two plain things keep a reader placed inside it. A rail of
   those regions, which is a list of anchors and needs no script to move
   anybody anywhere. And a region header
   that holds at the top of the screen for as long as the reader is inside
   that region, so somebody who arrives in the middle of the page from a
   search can see which part of the body they are reading about and how to
   get to the reading.
   ========================================================================== */

.guide {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.75rem, 4vw, 2.5rem);
  margin-top: clamp(1.75rem, 4vw, 2.75rem);
  padding-bottom: clamp(2rem, 5vw, 3.5rem);
}
@media (min-width: 62rem) {
  .guide {
    grid-template-columns: 14rem minmax(0, 1fr);
    column-gap: clamp(2rem, 4.5vw, 4rem);
    align-items: start;
  }
}

/* the rail: one anchor per region, and the way out */
.rail { min-width: 0; scroll-margin-top: 1rem; }
@media (min-width: 62rem) {
  .rail {
    position: sticky; top: 0;
    max-height: 100vh; overflow-y: auto;
    padding-block: 1.35rem;
    /* overflow-y: auto makes overflow-x auto as well, and the clip that
       comes with it falls exactly on the edges of every control in here:
       the site's ring sits at outline-offset 3px, so a keyboard reader on
       the page's own navigation got two brass bars where the rail already
       draws hairlines, a search box with no left edge and a Clear button
       with no right one. This is the same failure DESIGN-NOTES records
       being found once on .turn-hit. The padding moves the clip four pixels
       out on each side and the negative margin puts the rail back where it
       was, so nothing on the page moves and the ring is drawn whole. */
    padding-inline: 4px;
    margin-inline: -4px;
  }
}
.rail-list {
  list-style: none; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.4rem;
}
.rail-a {
  display: flex; align-items: baseline; gap: 0.5rem;
  text-decoration: none;
  font-family: var(--type); font-size: 0.68rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--rain);
  border: 1px solid var(--rule);
  padding: 0.34rem 0.5rem;
}
.rail-n { color: var(--slate); }
.rail-a:hover, .rail-a:focus-visible { color: var(--white); border-color: var(--hair); }
/* A rail link whose region the box has emptied. The dimming is a 1.52:1 step
   and on its own it was the whole signal, which is nothing to a reader using
   their ears and very little to one who is not: the count beside it is the
   thing that changed, so it is the thing that has to stay readable. The
   script writes the live count into it and marks the link as leading
   nowhere; this keeps that count legible rather than fading it to a hairline
   the moment it starts saying something. */
.rail-a--none { color: var(--slate); border-color: var(--rule-soft); }
.rail-a--none .rail-n { color: var(--slate); }
.rail-a[aria-disabled='true'] { cursor: default; }
/* the way out of the page, where the rail is held on the screen and can hold
   it; narrow gets the same link from every region header instead */
.rail-out { display: none; }
/* The rail's own heading sits inside the <nav> it names, as its
   aria-labelledby, so there is no `.rail nav + .label` any more: that rule was
   written for a label after the nav and never matched anything. */
/* Narrow, the rail is everything a reader walks through between the end of
   the argument and the first entry, and at twenty entries there is not much
   being indexed. Neither the box nor the twelve regions goes: both answer a
   question the page is asked. The air between them is what is out of scale
   with what it is holding. */
@media (max-width: 61.99rem) {
  .guide { margin-top: clamp(1.1rem, 3vw, 2rem); gap: clamp(1.2rem, 3vw, 2rem); }
  .sift { margin-bottom: 0.9rem; }
  .rail .label { margin-bottom: 0.75rem; }
  .rail-a { padding: 0.3rem 0.45rem; }
}
@media (min-width: 62rem) {
  .rail-list { display: block; }
  .rail-a {
    justify-content: space-between;
    border: 0; border-bottom: 1px solid var(--rule-soft);
    padding: 0.45rem 0;
  }
  .rail-a--none { border-bottom-color: var(--rule-soft); }
  .rail-out { display: block; }
}

/* the filter, which exists only where there is script to run it */
.sift { display: none; }
.js .sift { display: block; margin-bottom: 1.4rem; }
.sift-lab {
  display: block;
  font-family: var(--type); font-size: 0.66rem;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--rain); margin-bottom: 0.5rem;
}
.sift-row { display: flex; gap: 0.4rem; }
.sift-in {
  flex: 1 1 auto; min-width: 0;
  background: var(--deep); color: var(--white);
  border: 1px solid var(--rule); border-radius: 0;
  font-family: var(--type); font-size: 0.82rem;
  padding: 0.5rem 0.6rem;
  -webkit-appearance: none; appearance: none;
}
.sift-in::placeholder { color: var(--slate); }
.sift-clear {
  flex: none;
  background: none; border: 1px solid var(--rule); color: var(--rain);
  font-family: var(--type); font-size: 0.64rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  padding: 0 0.7rem; cursor: pointer;
}
.sift-clear:hover, .sift-clear:focus-visible { color: var(--white); border-color: var(--hair); }
.sift-count {
  margin-top: 0.55rem; min-height: 1.3em;
  font-family: var(--type); font-size: var(--small);
  letter-spacing: 0.06em; color: var(--slate);
}

/* a region of the body, and its header */
.region + .region { margin-top: clamp(2.25rem, 5vw, 3.5rem); }
.region-head {
  position: sticky; top: 0; z-index: 15;
  background: var(--ink);
  border-bottom: 1px solid var(--rule);
  padding-block: 0.6rem;
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: 0.2rem 1rem;
}
/* The count is beside the heading and not inside it: a heading that swallows
   its own count is announced as one word, "arms26 cues", to the reader who
   arrived here from a search and cannot see the page. */
.region-said { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.2rem 0.9rem; }
.region-name {
  font-family: var(--type); font-weight: 700;
  font-size: 0.82rem; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--white);
}
.region-count {
  font-family: var(--type); font-weight: 400;
  font-size: 0.72rem; letter-spacing: 0.18em;
  color: var(--slate);
}
.region-go {
  display: flex; align-items: baseline; gap: 0.55rem;
  font-family: var(--type); font-size: 0.64rem;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.region-go a { color: var(--rain); text-decoration: none; }
.region-go a:hover, .region-go a:focus-visible { color: var(--white); }
.region-go .sep { color: var(--rule); }
@media (min-width: 62rem) {
  /* The rail is pinned to the screen at this width and holds both of these
     links permanently in the corner of the eye, so printing them again under
     every one of twelve headers is twelve lines that say nothing new. Narrow,
     the rail has scrolled off the top and the header is the only way out,
     which is the width this line was drawn for. */
  .region-go { display: none; }
}
/* A region the filter has emptied gives up its height, so five rows of zeroes
   do not stand between a reader and the five answers they asked for. It is not
   taken out of the page: the section keeps its id and its place in the
   document, so every anchor that points at it still lands exactly where it
   would have. */
.region--none {
  margin: 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}
.region + .region.region--none { margin-top: 0; }

/* The one line in the entries column that is not an entry: what the column
   says when the box has emptied it, and what it says to a reader who arrived
   at the address of a cue this page does not set out. It is where the reader
   is already looking, which the count in the rail is not. */
.entries-none {
  border-top: 1px solid var(--rule);
  padding-top: clamp(1.2rem, 2.6vw, 1.8rem);
  margin-bottom: clamp(1.4rem, 3vw, 2rem);
  font-family: var(--prose);
  font-size: 1rem; line-height: 1.6;
  color: var(--silver);
  max-width: var(--measure);
}

/* the entries under it */
.cues { padding-top: clamp(1.2rem, 2.6vw, 1.8rem); }
/* Clear of the sticky region header on arrival, at every width. The header is
   39px wide and wraps to 60px at 320, where 4rem left five pixels between the
   pinned bar and the id and the score the reader came for. */
.cue { scroll-margin-top: 5.5rem; }
.cue + .cue { margin-top: clamp(1.4rem, 3vw, 2rem); }
.cue--thin { border-top-color: rgba(125, 147, 178, 0.5); }
.cue-absent { display: flex; flex-wrap: wrap; gap: 0.2rem 0.6rem; }
.cue-absent b {
  font-weight: 400; color: var(--slate);
  font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
}
/* The way from an entry to the beat that uses it. It is one of the two links
   that carry a reader off this page, and it used to be the smallest type on
   it with a border in --rule, which on the ground is 1.4:1 and effectively
   not drawn. An invitation set smaller than the ids and the scores around it
   reads as a footnote. */
.cue-seen {
  display: inline-block; margin-top: 0.9rem;
  font-family: var(--type); font-size: 0.75rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--rain); text-decoration: none;
  border-bottom: 1px solid var(--hair);
  padding-bottom: 0.25rem;
}
.cue-seen:hover, .cue-seen:focus-visible { color: var(--white); border-bottom-color: var(--hair); }
.rel--none { color: var(--slate); }

/* ==========================================================================
   NARROW
   The two channels stack, the spine moves to the left of each one, and the
   channel labels stop being invisible because they are now the only thing
   saying which is which.
   ========================================================================== */

@media (max-width: 62rem) {
  .channels { display: none; }

  .beat { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
  .beat .spine { display: none; }
  .beat-head { grid-column: 1; }
  .heard { grid-column: 1; grid-row: 2; padding-bottom: 1.75rem; position: static; }
  .read { grid-column: 1; grid-row: 3; }

  .beat .chan {
    position: static; width: auto; height: auto;
    margin: 0 0 0.7rem; overflow: visible; clip-path: none;
    font-family: var(--type); font-weight: 700;
    font-size: 0.64rem; letter-spacing: 0.28em; text-transform: uppercase;
  }
  .beat .chan--heard { color: var(--gold); }
  .beat .chan--read { color: var(--rain); }

  .heard { border-left: 2px solid rgba(185, 166, 124, 0.32); padding-left: 0.9rem; }
  .read { border-left: 2px solid rgba(143, 167, 173, 0.24); padding-left: 0.9rem; }

  .said, .silent { max-width: none; }
  .plate { max-width: min(100%, 34rem); margin-inline: 0; }

  /* narrow, the score takes its own line rather than wrapping and leaving the
     separator that introduced it hanging at the end of the one above */
  .slug-meta .sep--rel { display: none; }
  .slug-meta .rel { flex-basis: 100%; }

  /* The ending keeps its ending. Below 62rem the two channels stack, so the
     last beat cannot break a grid that is no longer there; it breaks the
     stack instead. It gives up the coloured channel rules, pulls back out to
     the full width the beats before it are indented from, centres its number
     and its line, and stands its plate alone with air on both sides. After a
     run of beats that all look the same, this one does not. */
  .beat--last { padding-inline: 0; --last-w: clamp(14rem, 72vw, 30rem); }
  .beat--last .heard,
  .beat--last .read {
    border-left: 0; padding-left: var(--gutter); padding-right: var(--gutter);
  }
  .beat--last .heard { display: flex; justify-content: center; }
  /* the two channels have become one centred column here, so the labels stop
     being the thing that tells them apart and go back to being read aloud */
  .beat--last .chan {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  .beat--last .said { text-align: center; max-width: 32ch; }
  .beat--last .beat-head {
    justify-content: center;
    padding-inline: var(--gutter);
  }
  .beat--last .plate { margin-inline: auto; max-width: var(--last-w); }
  .beat--last .slug,
  .beat--last .note,
  .beat--last .caveat { margin-inline: auto; max-width: var(--last-w); }
  .beat--last .note { font-size: 1.05rem; }
}

@media (max-width: 30rem) {
  .head, .open-line { max-width: none; }
  .keys { grid-template-columns: minmax(0, 1fr); }
  .btn { padding: 0.85rem 1.2rem; letter-spacing: 0.16em; }
  .js .beat--turn .turn-invite {
    top: 0.75rem; font-size: 0.58rem; letter-spacing: 0.12em; padding: 0.45rem 0.7rem;
  }
}

/* ==========================================================================
   THE OWNER'S MACHINE
   The same page, held still. Not a degraded one: every word, every painting
   and every ring is where it was. The only thing taken away is movement.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .beat--turn .turn-cross { display: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
