/* ==========================================================================
   site — the document that sits in front of the temple
   ==========================================================================

   THE CANVAS IS BEHIND EVERYTHING AND OWNS NOTHING. Every word, every price
   and the whole of the commerce lives in real HTML in normal document flow.
   The 3D is a fixed backdrop that the document scrolls over. That ordering is
   not an implementation detail — it is what makes the site survive with no
   WebGL, on a slow connection, in a screen reader, and in a search index.
   ========================================================================== */

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

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

body {
  margin: 0;
  background: var(--naos);
  color: var(--pentelic);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img,
canvas,
video {
  display: block;
  max-width: 100%;
}

/* Focus is Egyptian blue, always visible, never removed. */
:focus-visible {
  outline: 2px solid var(--kyanos-lit);
  outline-offset: 3px;
}

::selection {
  background: var(--kyanos);
  color: var(--pentelic);
}

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 1rem;
  top: 1rem;
  z-index: 90;
  padding: 0.7rem 1rem;
  background: var(--pentelic);
  color: var(--naos);
}

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

/* ── the stage ───────────────────────────────────────────────────────────── */

#stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  /* The canvas never takes a pointer. Every control on this site is a real
     DOM element in front of it. */
  pointer-events: none;
}

/* When there is no WebGL the canvas is removed and this takes over: the
   painted-catalogue fallback, which is a designed answer rather than a hole.
   Museums present the polychromy reconstructions exactly this way — the white
   version beside the painted one — so the argument survives intact. */
.no-gl #stage {
  display: none;
}

/* ── layout ──────────────────────────────────────────────────────────────── */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gut);
}

main {
  position: relative;
  z-index: 1;
}

.beat {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: var(--sec);
  scroll-margin-top: 4rem;
}

/* The copy sits in a column so the temple is never entirely covered. Which
   side it takes alternates, following the camera's two turns. */
.beat__panel {
  max-width: 33rem;
  padding: clamp(1.4rem, 3vw, 2.2rem);
  background: color-mix(in srgb, var(--naos) 78%, transparent);
  backdrop-filter: blur(14px);
  border: 1px solid var(--line);
  border-radius: 2px;
}
.beat--right .beat__panel {
  margin-left: auto;
}
.beat--wide .beat__panel {
  max-width: 46rem;
}

/* ── type ────────────────────────────────────────────────────────────────── */

h1,
h2,
h3 {
  margin: 0;
  font-family: var(--f-display);
  font-weight: 400;
  line-height: 1.05;
}
h1 {
  font-size: var(--t-hero);
}
h2 {
  font-size: var(--t-h2);
}
h3 {
  font-size: var(--t-h3);
}

p {
  margin: 0 0 1em;
  max-width: 58ch;
}
p:last-child {
  margin-bottom: 0;
}

.lead {
  font-size: var(--t-lead);
  color: var(--pentelic-2);
}

a {
  color: var(--kyanos-lit);
  text-underline-offset: 0.2em;
}
a:hover {
  color: var(--pentelic);
}

/* ── stoichedon ──────────────────────────────────────────────────────────
   The real 5th-century Attic system: one letter per cell of a strict grid,
   columns aligning down the face as well as across, and NO WORD SPACES — the
   reader separates the words. It is a layout engine, so it is implemented as
   one: a CSS grid whose cell is a token, fed by greek.js.

   Set in capitals with no diacritics, because accents and breathings are a
   Hellenistic invention centuries after anything was cut in stone. An acute
   on an inscription is the same order of anachronism as a serif on cuneiform. */

.stoich {
  display: grid;
  grid-auto-flow: row;
  gap: 0.14em;
  font-family: var(--f-body);
  font-size: var(--stoich);
  letter-spacing: 0;
  line-height: 1.25;
  color: var(--kinnabari);
}
.stoich span {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  font-variant-numeric: tabular-nums;
}
.stoich[data-lit] span {
  color: var(--pentelic);
}

/* Boustrophedon: alternate lines run the other way, as the ox turns in
   ploughing. The reversal is a transform so the text stays in true reading
   order for a screen reader and for select-and-copy. */
.boustro > :nth-child(even) {
  transform: scaleX(-1);
  direction: rtl;
}

.marker {
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--kinnabari);
}

.num {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  color: var(--chrysos);
}

.gloss {
  color: var(--pentelic-3);
  font-size: var(--t-small);
}

/* ── the bar ─────────────────────────────────────────────────────────────── */

.bar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem var(--gut);
  background: color-mix(in srgb, var(--naos) 72%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.bar__mark {
  font-family: var(--f-display);
  font-size: 1.4rem;
  letter-spacing: 0.06em;
  color: var(--pentelic);
  text-decoration: none;
}
.bar nav {
  display: none;
  gap: 1.1rem;
}
@media (min-width: 60rem) {
  .bar nav {
    display: flex;
  }
}
.bar nav a {
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  color: var(--pentelic-3);
  text-decoration: none;
  padding-block: 0.4rem;
  border-bottom: 1px solid transparent;
}
.bar nav a[data-on],
.bar nav a:hover {
  color: var(--pentelic);
  border-bottom-color: var(--kyanos-lit);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0 1.1rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: transparent;
  color: var(--pentelic);
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color 0.35s var(--walk),
    color 0.35s var(--walk),
    background-color 0.35s var(--walk);
}
.btn:hover {
  border-color: var(--kyanos-lit);
  color: var(--kyanos-lit);
}
/* The confirm is the one purple control on the site. */
.btn--confirm {
  background: var(--porphyra);
  border-color: var(--porphyra-lit);
  color: var(--pentelic);
}
.btn--confirm:hover {
  background: var(--porphyra-lit);
  border-color: var(--porphyra-lit);
  color: var(--pentelic);
}

/* ── the goods ───────────────────────────────────────────────────────────── */

.goods {
  display: grid;
  gap: 1px;
  margin-top: 2rem;
  background: var(--line);
  border: 1px solid var(--line);
}
@media (min-width: 46rem) {
  .goods {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 72rem) {
  .goods {
    grid-template-columns: repeat(4, 1fr);
  }
}

.good {
  display: flex;
  flex-direction: column;
  padding: 1.1rem;
  background: color-mix(in srgb, var(--naos) 88%, transparent);
  /* Four of these sit across a half-width panel, so the card — not the
     viewport — is what decides whether its take button has room for an
     English gloss. See `.good__take-en`. */
  container-type: inline-size;
}
.good__name {
  font-family: var(--f-display);
  font-size: 1.55rem;
  line-height: 1.1;
}
.good__latin {
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pentelic-3);
  margin-top: 0.3rem;
}
.good__line {
  margin-top: 0.7rem;
  font-size: var(--t-small);
  color: var(--pentelic-2);
  line-height: 1.6;
}
.good__foot {
  margin-top: auto;
  padding-top: 1rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.8rem;
  border-top: 1px solid var(--line);
}
.good__price {
  font-family: var(--f-mono);
  font-size: 1.15rem;
  color: var(--chrysos);
}
.good__cubits {
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  color: var(--pentelic-3);
}

/* ── the tiers: dye is the price ladder ──────────────────────────────────── */

.tiers {
  display: grid;
  gap: 1px;
  margin-top: 2rem;
  background: var(--line);
  border: 1px solid var(--line);
}
@media (min-width: 52rem) {
  .tiers {
    grid-template-columns: repeat(4, 1fr);
  }
}
.tier {
  padding: 1.1rem;
  background: color-mix(in srgb, var(--naos) 88%, transparent);
  border-top: 3px solid var(--swatch, var(--line));
}
.tier__name {
  font-family: var(--f-display);
  font-size: 1.35rem;
}
.tier__from {
  font-family: var(--f-mono);
  font-size: var(--t-small);
  color: var(--chrysos);
  margin-top: 0.35rem;
}
.tier__who {
  font-size: var(--t-small);
  color: var(--pentelic-2);
  margin-top: 0.55rem;
  line-height: 1.55;
}
/* Tier four wears its own colour, and nothing else on the page may. */
.tier--iv {
  background: color-mix(in srgb, var(--porphyra) 30%, var(--naos));
}

/* ── the ledger (checkout as votive offering) ────────────────────────────── */

.ledger {
  margin-top: 2rem;
  border: 1px solid var(--line);
  padding: 1.2rem;
  background: color-mix(in srgb, var(--naos) 88%, transparent);
}
.ledger table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--f-mono);
  font-size: var(--t-small);
}
.ledger th,
.ledger td {
  text-align: left;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
  font-weight: 400;
}
.ledger th {
  color: var(--pentelic-3);
  font-size: var(--t-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.ledger td:last-child,
.ledger th:last-child {
  text-align: right;
}
.ledger tr:last-child td {
  border-bottom: 0;
  color: var(--chrysos);
}

/* ── the fallback catalogue ──────────────────────────────────────────────── */

.plate {
  display: grid;
  gap: clamp(1rem, 3vw, 2rem);
  margin-top: 2rem;
}
@media (min-width: 52rem) {
  .plate {
    grid-template-columns: 1fr 1fr;
  }
}
.plate figure {
  margin: 0;
}
.plate img {
  width: 100%;
  border: 1px solid var(--line);
}
.plate figcaption {
  margin-top: 0.6rem;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pentelic-3);
}

/* Shown only when there is no WebGL, because then the reveal has to be made
   as a picture instead of as a camera move. */
.only-no-gl {
  display: none;
}
.no-gl .only-no-gl {
  display: block;
}
.no-gl .beat {
  min-height: auto;
}
.no-gl .beat__panel {
  backdrop-filter: none;
  background: color-mix(in srgb, var(--naos) 92%, transparent);
}

/* ── footer ──────────────────────────────────────────────────────────────── */

.foot {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  padding-block: clamp(2.5rem, 6vh, 4rem);
  background: var(--naos);
}
.foot__note {
  max-width: 62ch;
  font-size: var(--t-small);
  color: var(--pentelic-3);
}

/* ── the cut ──────────────────────────────────────────────────────────────
   THE DOCUMENT'S ONE VERB, AND IT IS THE BUILDING'S VERB.

   `setWipe` in stage.js sweeps a soft-edged threshold along the temple and
   the pigment comes back behind it. That is the site's established visual
   argument, so the copy is revealed the same way rather than by inventing a
   second one. `--cut` moves a gradient stop across the type through
   `background-clip: text`: what travels is the PAINT. The letters never
   move, never fade as glyphs, and are in normal flow the entire time —
   selectable, findable, and identical to a crawler before and after. Carved
   text does not slide; a translateY is exactly the tell this site argues
   against, and it is what used to be here.

   EVERY CUSTOM PROPERTY IS DECLARED TWICE ON PURPOSE — once in `@property`
   for the initial value and the ability to TRANSITION it, and again as a
   plain declaration in the rule that uses it. A browser without `@property`
   would otherwise resolve `var(--cut)` to nothing, invalidate the gradient,
   and leave `-webkit-text-fill-color: transparent` painting invisible text
   over a background that no longer exists. The second declaration is the
   difference between a graceful jump and a blank page.

   And all of it is scoped behind `.js`, because the runtime that hides this
   copy is the only thing that can unhide it. See the inline script in the
   head of index.html. */

@property --cut {
  syntax: '<percentage>';
  inherits: false;
  initial-value: -6%;
}
@property --paint {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}
@property --rev {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}
@property --lamp {
  syntax: '<number>';
  inherits: true;
  initial-value: 0.9;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .js .cut {
    --cut: -6%;
    /* The ±6% band is the document's `uEdge`: soft enough to read as paint
       arriving, hard enough that nobody mistakes it for a fade. */
    background-image: linear-gradient(
      100deg,
      currentcolor calc(var(--cut) - 6%),
      transparent calc(var(--cut) + 6%)
    );
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    /* NOT `color: transparent`. That would resolve `currentcolor` in the
       gradient above to transparent as well, and the text would never
       appear at all — the paint has to keep knowing what colour it is. */
    -webkit-text-fill-color: transparent;
    transition: --cut 0.9s var(--walk);
    transition-delay: var(--d, 0ms);
  }
  .js .cut:is(h1, h2, h3) {
    transition-duration: 0.7s;
  }
  .js .beat.is-cut .cut {
    --cut: 106%;
  }
  /* The opening invitation, held back at scroll 0. See reveal.js. */
  .js .beat.is-cut .cut.cut--held {
    --cut: -6%;
  }
}

/* Older Safari and anything else without `background-clip: text`. The
   grammar is unavailable, so the honest substitute is the plainest possible
   arrival — no travel, no stagger beyond the delay the beat already sets. */
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .js .cut {
    opacity: 0;
    transition: opacity 0.5s var(--walk);
    transition-delay: var(--d, 0ms);
  }
  .js .beat.is-cut .cut {
    opacity: 1;
  }
  .js .beat.is-cut .cut.cut--held {
    opacity: 0;
  }
}

/* ── the mason's line ─────────────────────────────────────────────────────
   Section labels are cut letter by letter, and they STEP rather than fade:
   a chisel strike is discrete — the letter is there or it is not — so the
   easing is `steps(1)` and the stagger is the mason working along the line.
   Only labels. Splitting a heading or a paragraph this way breaks
   copy-paste and makes some screen readers spell the words out; reveal.js
   restates the real string in an `.sr` span and hides these from the
   accessibility tree entirely. */

.js .marker__cut > span {
  opacity: 0;
  transition: opacity 90ms steps(1);
  transition-delay: calc(var(--i, 0) * 40ms);
}
.js .beat.is-marked .marker__cut > span {
  opacity: 1;
}

/* ── ΧΡΩΜΑ: the one heading that rides the wipe ───────────────────────────
   Written every frame from the same `transit` that drives `setWipe`, so it
   scrubs backwards and lands exactly where it left. It is also the only
   place cinnabar is permitted near a headline — tokens.css confines the
   pigment to marks, rules and borders and forbids it as body text, and a
   display heading is neither. This is the sentence whose whole subject is
   that the paint came back; the exception is stated rather than left to be
   found later and mistaken for drift. */

.js .cut--driven {
  --paint: 0;
  transition: none;
  color: color-mix(in srgb, var(--kinnabari) calc(var(--paint) * 100%), var(--pentelic));
}

/* ── ΑΔΥΤΟΝ: lit, not swept ───────────────────────────────────────────────
   The sanctum arrives out of the dark under one lamp rather than being
   wiped in, so the panel itself carries the reveal and breathes on the
   closed-form `flicker()` the naos is already lit by. Three per cent, which
   is a room and never a strobe. */

.js #adyton .beat__panel {
  --rev: 0;
  opacity: calc(var(--rev) * (0.97 + var(--lamp, 0.9) * 0.03));
  transition: --rev 1.4s var(--walk);
}
.js #adyton.is-cut .beat__panel {
  --rev: 1;
}

/* ── less motion: the finished inscription ────────────────────────────────
   Not "disabled". The page as the stone reads after the film is over —
   every cut complete, every letter struck, the lamp steady. */

@media (prefers-reduced-motion: reduce) {
  .js .cut,
  .js .beat.is-cut .cut,
  .js .beat.is-cut .cut.cut--held {
    --cut: 106%;
    opacity: 1;
    transition: none;
  }
  .js .marker__cut > span {
    opacity: 1;
    transition: none;
  }
  .js #adyton .beat__panel,
  .js #adyton.is-cut .beat__panel {
    --rev: 1;
    --lamp: 0.9;
    transition: none;
  }
}

/* ── the altar: taking, reckoning, putting back ───────────────────────────
   THE TAKE BUTTON DOES NOT EXIST UNTIL IT WORKS. It ships in the markup so
   that it sits in the document order a screen reader walks, and needs no
   scripting to be placed correctly — but it is display:none until order.js
   puts `cart-ready` on <html>. With JavaScript off the four cards end at
   their price, the altar shows its worked example, and nothing on the page
   is a control that does nothing when pressed. */

.good__take {
  display: none;
}
.cart-ready .good__take {
  display: inline-flex;
  justify-content: center;
  gap: 0.4em;
  width: 100%;
  margin-top: 0.8rem;
  padding: 0 0.5rem;
  letter-spacing: 0.1em;
  text-align: center;
}
/* The gloss is the first thing to go. Below this the button is one Greek
   word and a numeral, which fits on a single line in the narrowest card the
   four-up grid produces; the aria-label still reads the whole sentence. */
.good__take-en {
  display: none;
}
@container (min-width: 15rem) {
  .good__take-en {
    display: inline;
  }
}
/* Held: the garment is on the altar. Gold rather than purple — purple is the
   confirm at the altar and nowhere else. */
.good__take--held {
  border-color: var(--chrysos-dim);
  color: var(--chrysos);
}
.good__take[disabled] {
  cursor: default;
  opacity: 0.55;
}
.good__take[disabled]:hover {
  border-color: var(--chrysos-dim);
  color: var(--chrysos);
}
@keyframes take-struck {
  from {
    border-color: var(--chrysos);
    background-color: color-mix(in srgb, var(--chrysos) 14%, transparent);
  }
  to {
    border-color: var(--chrysos-dim);
    background-color: transparent;
  }
}
.good__take--struck {
  animation: take-struck 0.25s var(--walk);
}

/* --- the running total in the bar --- */
.btn--tallied {
  border-color: var(--chrysos-dim);
}
.btn--tallied [data-tally-value] {
  color: var(--chrysos);
}
@keyframes tally-struck {
  from { opacity: 0.45; }
  to { opacity: 1; }
}
.bar__tally--struck {
  animation: tally-struck 0.3s var(--walk);
}

/* --- the ledger --- */
.ledger__state {
  margin-bottom: 0.7rem;
}
.ledger__empty a {
  color: var(--kyanos-lit);
}
/* The put-back column carries no header text and should take no more width
   than its four letters need. */
.ledger__put {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}
.ledger__putback {
  border: 0;
  background: none;
  padding: 0.2rem 0;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  color: var(--pentelic-3);
  cursor: pointer;
  transition: color 0.35s var(--walk);
}
.ledger__putback:hover {
  color: var(--kyanos-lit);
}
/* The English gloss appears only where there is room for it; below that the
   aria-label carries the whole meaning. */
@media (min-width: 46rem) {
  .ledger__putback::after {
    content: ' · put back';
    text-transform: none;
    letter-spacing: 0.04em;
  }
}

.altar__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}
.ledger__copy {
  border: 0;
  background: none;
  padding: 0;
  font-family: var(--f-body);
  font-size: var(--t-small);
  color: var(--pentelic-3);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  cursor: pointer;
}
.ledger__copy:hover {
  color: var(--kyanos-lit);
}

@media (prefers-reduced-motion: reduce) {
  .good__take--struck,
  .bar__tally--struck {
    animation: none;
  }
}

/* ── the fitting room ─────────────────────────────────────────────────────
   `.only-gl` is the mirror of `.only-no-gl` above, and it waits for
   `fitting-ready` rather than for `gl-ready`: the swatches dye a figure, so
   they appear when there is a figure to dye and not one frame before. A
   control that does nothing is the same lie whether the cause is a missing
   GPU or cloth that has not finished settling. */

.only-gl {
  display: none;
}
.fitting-ready .only-gl {
  display: block;
}

/* The garment name is the selector. It is a real button so that the whole
   fitting room can be driven from the keyboard without inventing a single
   control that is not already in the catalogue. */
.good__pick {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  color: inherit;
  cursor: pointer;
}
.good__pick:focus-visible {
  outline: 2px solid var(--kyanos-lit);
  outline-offset: 3px;
}
/* Which one is being worn. A left rule rather than a fill: the cards sit on
   a translucent panel over a moving temple, and a filled state at this size
   reads as a different card rather than as the same card, chosen. */
.good {
  border-left: 2px solid transparent;
  transition: border-color 0.4s var(--walk);
}
.good--wearing {
  border-left-color: var(--chrysos);
}

.fitting {
  margin-top: 1.1rem;
}
.fitting__hint {
  color: var(--pentelic-3);
}
.swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}
/* The chip is the dye. The label on it is the tier numeral from the ΒΑΦΗ
   beat, so the control cites the ladder rather than restating it. */
.swatch {
  width: 2.4rem;
  height: 2.4rem;
  min-height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--swatch);
  color: var(--pentelic);
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  cursor: pointer;
  transition:
    border-color 0.3s var(--walk),
    transform 0.3s var(--walk);
}
.swatch:hover {
  border-color: var(--kyanos-lit);
}
.swatch--is {
  border-color: var(--chrysos);
  border-width: 2px;
}
.swatch:focus-visible {
  outline: 2px solid var(--kyanos-lit);
  outline-offset: 3px;
}
.fitting__note {
  margin-top: 0.7rem;
  color: var(--chrysos);
}
/* Four upright figures want four columns, not the plate's usual two — they
   are portraits, and a 3:4 image in a half-width cell is taller than the
   copy beside it. */
@media (min-width: 52rem) {
  .plate--figures {
    grid-template-columns: repeat(4, 1fr);
    gap: clamp(0.7rem, 1.6vw, 1.2rem);
  }
  .plate--figures figcaption {
    letter-spacing: 0.08em;
  }
}

/* Purple is shown and then refused — see the adyton. The control stays
   legible; it just stops being an invitation. */
.good__take--forbidden {
  opacity: 0.5;
  border-color: var(--porphyra-lit);
}

@media (prefers-reduced-motion: reduce) {
  .good,
  .swatch {
    transition: none;
  }
}
