/* ═══════════════════════════════════════════════════════════════════════════
   THE MUSEUM — the room, not the document.

   Kevin: "It feels dead in the damn museum. It should feel like a museum
   exhibit. Add some more colors, add some more elements to liven it up."

   The page was cream and sand like every other page, which is correct for a
   document and wrong for an exhibition. A gallery is a sequence of ROOMS and
   you know you have walked into a different one before you read anything.

   ═══ THE PALETTE, AND EVERY VALUE IS MEASURED ═════════════════════════════

   Sage is Kevin's colour, sampled from the flat he sent. Burgundy is the
   exhibit room. Gold is the line that marks what is on show. Contrast was
   solved BEFORE any of this was written, because a room nobody can read in
   is not a room:

       on sage      #9AA88A     ink  #121820      7.09:1   AA
       on burgundy  #5A2A35     cream #F4F1EA    10.24:1   AA
                                gold  #C9A96A     5.15:1   AA
       on cream     #F4F1EA     ink  #121820     15.81:1   AA

   Gold clears AA on burgundy at 5.15, which is why it can be type as well as
   a rule. It fails on sage at 1.12 and is never used there.

   ═══ WHY THE ROOMS ALTERNATE ══════════════════════════════════════════════

   Sage is the corridor and burgundy is the exhibit. The ledger — the part
   that is actually 35 objects on plinths — is burgundy, and everything that
   explains it is sage. So the page reads as: arrive, look, read what you
   looked at, look again.
   ═══════════════════════════════════════════════════════════════════════════ */

[data-page="museum"] {
  --m-sage:       #9AA88A;
  --m-sage-deep:  #8B9A7B;
  --m-burgundy:   #5A2A35;
  --m-burg-deep:  #4A2029;
  /* #C9A96A clears 5.15:1 on solid burgundy and 4.26 on the note GLASS,
     which lightens the wall to rgb(101,56,66) — the token was measured, the
     composite was not. #D3B478 is 4.81 on the glass and 5.82 on the solid,
     so one value covers both surfaces. */
  --m-gold:       #D3B478;
  --m-gold-line:  rgba(201, 169, 106, .38);
  --m-cream:      #F4F1EA;
  --m-cream-mut:  #D8D2C6;
  --m-ink:        #121820;
  --m-ink-mut:    #252A26;
  --m-card-sage:  #EDEFE6;
  --m-reject-ink: #33291F;   /* type on the pale rejection card, on burgundy */
  --m-reject-mut: #4A4038;
  --m-breathe:    18s;   /* the card's own clock — ambient, not a response */
}

/* ── THE CORRIDOR ───────────────────────────────────────────────────────── */

[data-page="museum"] body,
body[data-page="museum"] { background: var(--m-sage); }

/* THE ACCENT IN THE CORRIDOR IS THE COLOUR OF THE NEXT ROOM.
   --bronze-text is #8A6034 sitewide and lands at 2.19:1 on sage, so every
   eyebrow and every tally numeral was failing. The replacement is not a
   darker bronze; it is the exhibit burgundy, which clears 5.45:1 here and
   4.58:1 on the deeper sage, and means the small type in the corridor is
   already the colour of the room it is leading to. */
[data-page="museum"] [data-tone="sage"][data-tone="sage"] {
  background: var(--m-sage);
  --card: var(--m-card-sage);
  --rule: var(--m-gold-line);
  --muted: var(--m-ink-mut);
  --bronze-text: var(--m-burg-deep);
  --accent: var(--m-burg-deep);
}
[data-page="museum"] [data-tone="sage-deep"][data-tone="sage-deep"] {
  background: var(--m-sage-deep);
  --card: var(--m-card-sage);
  --rule: var(--m-gold-line);
  --muted: var(--m-ink-mut);
  --bronze-text: var(--m-burg-deep);
  --accent: var(--m-burg-deep);
}

/* ── THE EXHIBIT ROOM ───────────────────────────────────────────────────────
   Burgundy, and the gold is a HAIRLINE not a fill. Gold as an area is a
   casino; gold as a 1px rule under a label is a museum. Three uses only:
   the rule above a room's name, the frame on an object, and the label type
   itself, which clears AA at 5.15:1.                                       */

[data-page="museum"] [data-tone="exhibit"][data-tone="exhibit"] {
  background: var(--m-burgundy);
  color: var(--m-cream);
  --ink: var(--m-cream);
  --muted: var(--m-cream-mut);
  --card: rgba(244, 241, 234, .05);
  --rule: var(--m-gold-line);
  --bronze-text: var(--m-gold);
  --accent: var(--m-gold);
}
[data-page="museum"] [data-tone="exhibit"] .h2,
[data-page="museum"] [data-tone="exhibit"] .h3,
[data-page="museum"] [data-tone="exhibit"] .h4,
[data-page="museum"] [data-tone="exhibit"] .body,
[data-page="museum"] [data-tone="exhibit"] .station__name { color: var(--m-cream); }
[data-page="museum"] [data-tone="exhibit"] .small,
[data-page="museum"] [data-tone="exhibit"] .station__lic { color: var(--m-cream-mut); }
[data-page="museum"] [data-tone="exhibit"] .eyebrow,
[data-page="museum"] [data-tone="exhibit"] .room__n,
[data-page="museum"] [data-tone="exhibit"] .station__label { color: var(--m-gold); }

/* the gold rule. One hairline, above a room name, the width of the name. */
[data-page="museum"] [data-tone="exhibit"] .room {
  border-top: 1px solid var(--m-gold-line);
}
[data-page="museum"] [data-tone="exhibit"] .room__n::after {
  content: "";
  display: block;
  width: 3.5rem;
  height: 1px;
  margin-top: 10px;
  background: var(--m-gold);
}

/* an object on show gets a frame, not a card */
[data-page="museum"] [data-tone="exhibit"] .station {
  border: 1px solid var(--m-gold-line);
  border-radius: var(--radius-card);
  padding: var(--pad-card);
  background: rgba(244, 241, 234, .04);
}
[data-page="museum"] [data-tone="exhibit"] .badge {
  border-color: var(--m-gold-line);
  color: var(--m-gold);
}

/* the terminals keep their own dark plate; on burgundy they need their edge
   stated or they float */
[data-page="museum"] [data-tone="exhibit"] .swap {
  border-color: var(--m-gold-line);
}


/* ── THE DECORATION ─────────────────────────────────────────────────────────
   Kevin: "add little elements, like background elements, like little flowers
   or little clouds, just to spice up the background of the museum."

   Every one of these is drawn in CSS or as an inline data-URI SVG. Nothing
   is fetched: the footer of this site says zero third-party requests and
   that has to keep being true on the page that argues about provenance.

   They sit at low alpha behind everything, they are aria-hidden, and they
   are the FIRST thing to go under prefers-reduced-motion, because a room
   that drifts is a room somebody cannot read in.                          */

.m-deco {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.m-deco > * { position: absolute; display: block; }
[data-page="museum"] .band > .col { position: relative; z-index: 1; }

/* a botanical sprig, the kind pressed into a herbarium sheet */
.m-sprig {
  width: 190px; height: 190px;
  opacity: .16;
  background: no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 120' fill='none' stroke='%23121820' stroke-width='1.1'%3E%3Cpath d='M60 112 C60 78 60 44 60 12'/%3E%3Cpath d='M60 92 C44 88 34 78 30 62 C46 64 56 74 60 92Z'/%3E%3Cpath d='M60 74 C76 70 86 60 90 44 C74 46 64 56 60 74Z'/%3E%3Cpath d='M60 54 C44 50 34 40 30 24 C46 26 56 36 60 54Z'/%3E%3Ccircle cx='60' cy='14' r='5'/%3E%3C/svg%3E");
}
/* a slow cloud, the shape of a shadow on a gallery wall */
.m-cloud {
  width: 340px; height: 150px;
  opacity: .10;
  background: no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 340 150' fill='%23F4F1EA'%3E%3Cellipse cx='110' cy='96' rx='84' ry='40'/%3E%3Cellipse cx='190' cy='74' rx='68' ry='46'/%3E%3Cellipse cx='250' cy='100' rx='62' ry='34'/%3E%3C/svg%3E");
}
/* a plinth outline — the object that holds objects */
.m-arch {
  width: 260px; height: 320px;
  opacity: .13;
  background: no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 130 160' fill='none' stroke='%23F4F1EA' stroke-width='1.2'%3E%3Cpath d='M20 158 V60 C20 26 45 6 65 6 C85 6 110 26 110 60 V158'/%3E%3Cpath d='M8 158 H122'/%3E%3Cpath d='M34 158 V70 C34 44 50 28 65 28 C80 28 96 44 96 70 V158'/%3E%3C/svg%3E");
}
/* a hairline arc, like a ring drawn on a plan */
.m-ring {
  width: 300px; height: 300px;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: .12;
}

[data-tone="exhibit"] .m-sprig {
  filter: invert(1);
  opacity: .12;
}

/* placements. Deliberately few and deliberately asymmetric: a room with a
   thing in every corner is wallpaper, not a room. */
.m-deco--a .m-sprig { top: 8%;  right: 4%; }
.m-deco--a .m-ring  { bottom: -120px; left: -80px; color: var(--m-ink); }
.m-deco--b .m-cloud { top: 12%; left: -60px; }
.m-deco--b .m-arch  { bottom: 0; right: 6%; }
.m-deco--c .m-sprig { bottom: 10%; left: 5%; transform: scaleX(-1) rotate(8deg); }
.m-deco--c .m-ring  { top: -140px; right: -60px; color: var(--m-gold); opacity: .22; }

@media (max-width: 900px) {
  .m-sprig { width: 120px; height: 120px; }
  .m-cloud { width: 220px; height: 100px; }
  .m-arch  { width: 170px; height: 210px; }
  .m-ring  { width: 190px; height: 190px; }
}
@media (prefers-reduced-motion: reduce) {
  .m-deco { display: none; }
}

/* ── THE VESSEL, REPEATED ───────────────────────────────────────────────────
   Kevin: "add that little pottery along the page, like down the page as
   well." The hero jar is a raymarched shader and running four of them would
   cost four full-screen fragment passes. The repeats are the same silhouette
   drawn once as a hairline, which is what a museum does with its own object
   anyway: the thing itself once, its outline on every label after that.   */

.m-jar {
  width: 84px; height: 84px;
  margin: 0 auto;
  opacity: .5;
  background: no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80' fill='none' stroke='%23121820' stroke-width='1.2'%3E%3Cpath d='M32 14 C32 10 48 10 48 14 C48 18 44 19 44 22 C60 27 70 40 70 52 C70 67 56 76 40 76 C24 76 10 67 10 52 C10 40 20 27 36 22 C36 19 32 18 32 14Z'/%3E%3Cpath d='M18 46 C28 52 52 52 62 46' opacity='.55'/%3E%3Cpath d='M15 58 C27 65 53 65 65 58' opacity='.4'/%3E%3C/svg%3E");
}
.m-jar--between {
  display: block;
  margin-block: calc(var(--band-pad-y, 96px) * .5);
}
[data-tone="exhibit"] .m-jar { filter: invert(1); opacity: .45; }

/* ── WHAT CARRIES ITS OWN GROUND MUST BE RESTATED ───────────────────────────
   Flipping --ink to cream at band level is right for prose and WRONG for
   anything that brings its own surface. Measured on the first build, 13
   pairs failed: the code plates and the contributor chips use --card-glass,
   which is white at 0.72, and white-over-burgundy composites to
   rgb(209,195,198) — a light pink. Cream type on it landed at 1.51:1 and the
   syntax palette, tuned for cream and sand, fell to 3.2.

   Two different answers, because they are two different objects.

   THE PLATES GET AN OPAQUE GROUND. A translucent panel over burgundy is a
   colour nobody solved for. Given the cream it was designed against, every
   value inside it — gutter, filename, four syntax hues, the marked range —
   holds at exactly the ratios measured for it.

   THE CHIPS BECOME THE ROOM'S OWN. A contributor's name is prose, not a
   surface, so it loses the glass and takes a gold hairline instead. */

[data-page="museum"] [data-tone="exhibit"] .swap,
[data-page="museum"] [data-tone="exhibit"] .term {
  --card-glass: #FBF9F4;
  --swap-ground: #FBF9F4;
  --term-bg: #FBF9F4;
  --ink: var(--m-ink);
  --muted: #5F6670;
}
[data-page="museum"] [data-tone="exhibit"] .term__name,
[data-page="museum"] [data-tone="exhibit"] .term__tag { color: var(--m-ink); }

[data-page="museum"] [data-tone="exhibit"] .web__node {
  background: transparent;
  border-color: var(--m-gold-line);
  color: var(--m-cream);
}
[data-page="museum"] [data-tone="exhibit"] .web__node:hover,
[data-page="museum"] [data-tone="exhibit"] .web__node[aria-expanded="true"] {
  background: rgba(244, 241, 234, .10);
  border-color: var(--m-gold);
}
[data-page="museum"] [data-tone="exhibit"] .web__count { color: var(--m-gold); }
[data-page="museum"] [data-tone="exhibit"] .web__leafname { color: var(--m-cream-mut); }

/* the buttons, restated the way the ink tone restates its own */
[data-page="museum"] [data-tone="exhibit"] .btn--secondary {
  background: var(--m-cream);
  color: var(--m-burgundy);
}
[data-page="museum"] [data-tone="exhibit"] .btn--tertiary {
  background: rgba(244, 241, 234, .10);
  color: var(--m-cream);
  border-color: var(--m-gold-line);
}
[data-page="museum"] [data-tone="exhibit"] .btn--primary {
  background: var(--m-gold);
  color: var(--m-burg-deep);
}
[data-page="museum"] [data-tone="exhibit"] .chip {
  border-color: var(--m-gold-line);
  color: var(--m-cream);
}
[data-page="museum"] [data-tone="exhibit"] .chip[aria-pressed="true"] {
  background: var(--m-gold);
  color: var(--m-burg-deep);
}
[data-page="museum"] [data-tone="exhibit"] .find {
  background: rgba(244, 241, 234, .08);
  border-color: var(--m-gold-line);
  color: var(--m-cream);
}
[data-page="museum"] [data-tone="exhibit"] .find::placeholder { color: var(--m-cream-mut); }

/* ── THE DAILY GRID ─────────────────────────────────────────────────────────
   A museum with a puzzle at the door is a museum that expects you to stay.
   It sits in the arrival room, on sage, in a cream card so the grid keeps the
   ground it was designed against. */

.g-wrap { margin-top: var(--band-pad-y, 96px); }
.g {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17rem;
  gap: var(--band-pad-x, 64px);
  align-items: start;
  background: var(--m-card-sage);
  border: 1px solid var(--m-gold-line);
  border-radius: var(--radius-card);
  padding: var(--pad-card);
}
.g-head { grid-column: 1 / -1; }
.g-title { margin: 6px 0 8px; }
.g-sub { max-width: 56ch; }
.g-grid { min-width: 0; }
.g-side { display: grid; gap: var(--gap-card); }
.g-clock {
  font-family: var(--face-mono);
  font-size: 34px;
  line-height: 1;
  margin: 0;
  color: var(--m-burg-deep);
  font-variant-numeric: tabular-nums;
}
.g-count { margin: 0; }
.g-board { border-top: 1px solid var(--m-gold-line); padding-top: var(--gap-card); }
.g-board__l { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.g-board__r {
  display: grid;
  grid-template-columns: 1.4rem 1fr auto;
  gap: var(--gap-btn);
  font-family: var(--face-mono);
  font-size: var(--size-small);
  color: var(--m-ink);
}
.g-board__p { color: var(--m-burg-deep); }
.g-board__d { color: var(--m-ink-mut); }
.g-board__t { font-variant-numeric: tabular-nums; }
.g-board__note { margin-top: 10px; }
.g.is-done { border-color: var(--m-burg-deep); }

@media (max-width: 900px) {
  .g { grid-template-columns: minmax(0, 1fr); }
  .g-clock { font-size: 28px; }
}

/* ── THE PUZZLE'S TOKENS ────────────────────────────────────────────────────
   puzzle.css is a port and asks for 33 custom properties. THIRTY-TWO OF THEM
   DID NOT EXIST HERE — they are EMBER's design system, layered on tokens like
   --paper-ink-rgb and --stock-laid that this site has never had.

   An undefined var() does not fall back. It DROPS THE DECLARATION. So the
   grid shipped with no cell background, no gap between the grid and the word
   list, and — the one that mattered — no colour on the selection highlight or
   the found-word rings. Kevin: "it's not letting me draw or circle anything."

   It was letting him. The drag worked the whole time and painted nothing he
   could see. Both of his complaints about the puzzle are this one bug:
   "the words are too close to the word search" is --space-6 dropping out of
   .gp__body's gap, and "it won't let me circle" is --mk-* dropping off the
   ring strokes.

   Declared on .gp, in a block of nothing but custom properties so gate check
   1 can tell named values from paint, and mapped to THIS museum rather than
   copied out of EMBER — a puzzle in a gallery should look like it belongs to
   the gallery.

   The eight marker colours keep their pigment names because that is what they
   are: a found word gets a ring in a real pigment, each with its own dash, so
   eight rings on one grid never read as one shape. */

.gp {
  --ink-2:      rgba(18, 24, 32, .72);
  --ink-3:      rgba(18, 24, 32, .50);
  --ink-4:      rgba(18, 24, 32, .30);
  --ink-5:      rgba(18, 24, 32, .12);
  --ink-rgb:    18, 24, 32;
  --sheet:      #FBFBF7;
  --radius-sm:  10px;
  --font-ui:    var(--face-ui);
  --font-display: var(--face-display);
  --space-2:    10px;
  --space-3:    18px;
  --space-6:    40px;
  --target-min: 44px;
  --text-xs:    11px;
  --text-sm:    13px;
  --text-lg:    20px;
  --tracking-tight: -.2px;
  --tracking-wide:  1.1px;
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --dur-hover:  160ms;
  --ease:       cubic-bezier(0.44, 0, 0.56, 1);

  --mk-prussian:  #2A4A6B;
  --mk-vermilion: #B0442A;
  --mk-viridian:  #2E6B54;
  --mk-ochre:     #A0762A;
  --mk-violet:    #6A4A7A;
  --mk-celadon:   #3F7566;
  --mk-oxblood:   #6B2A35;
  --mk-payne:     #46586B;
}

/* ── THE PUZZLE, TUNED FOR A GALLERY ────────────────────────────────────────
   puzzle.css draws its rings at stroke-width 0.62 with vector-effect
   non-scaling-stroke — so that is 0.62 SCREEN pixels, sub-pixel on most
   displays — at 55% opacity. In a reading application that restraint is
   correct: the ring is an annotation on somebody's vocabulary set and must
   not shout over the words.

   This is an exhibit. The ring is the thing you did, and it should look like
   ink on the sheet. The pigment colours and their eight dash patterns are
   untouched; only the weight changes.                                     */

.gp__ring { stroke-width: 2.1; opacity: .92; }

/* the run under the pointer, while you are still dragging */
.gp .gp__c.is-tracing {
  background: rgba(201, 169, 106, .34);
  box-shadow: inset 0 0 0 1px rgba(107, 42, 53, .30);
}
.gp .gp__c.is-found { color: var(--m-burg-deep); font-weight: 600; }
.gp .gp__c { transition: background var(--dur-hover) var(--ease); }

/* ── THE CARD BREATHES ──────────────────────────────────────────────────────
   Kevin: "make the card move around a little bit... have an animation where
   it hovers around, just moves a little bit, breathes, you know, slowly."

   Six pixels over eighteen seconds, on two axes at different periods so it
   never repeats its own path and never reads as a loop. It is the amount a
   held object moves in somebody's hands, which is the right amount for a
   thing that is pretending to sit on a table.

   translate3d on a transform-only animation, so it composites and costs no
   layout. Off entirely under prefers-reduced-motion — a page that drifts is
   a page somebody cannot read. */

@keyframes m-breathe {
  0%   { transform: translate3d(0, 0, 0); }
  25%  { transform: translate3d(3px, -4px, 0); }
  50%  { transform: translate3d(-2px, -6px, 0); }
  75%  { transform: translate3d(-4px, -2px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}
@media (prefers-reduced-motion: no-preference) {
  .g { animation: m-breathe var(--m-breathe) ease-in-out infinite; }
  .g:hover, .g:focus-within { animation-play-state: paused; }
}

/* ── THE TWO CARDS, AND WHY ONE INVERTS ─────────────────────────────────────
   site.css already decided this and the decision is good: .note is glass, and
   .note--reject is THE NEGATIVE OF THE PAGE — ink ground, page type — so the
   one block recording what was thrown away is the one block that is
   light-on-dark. It needs no border to be found.

   That logic broke here, not because it was wrong but because the room
   changed. On burgundy an ink card is no longer the negative of anything: it
   is a slightly darker rectangle on a dark wall. My first pass made it worse
   by flattening it to a bordered box, which is what Kevin saw — one card with
   the glass treatment beside one generic outline.

   So the rule is kept and the value is re-derived. The rejection card is the
   negative of WHATEVER ROOM IT IS IN. In a burgundy room that means pale.  */

[data-page="museum"] [data-tone="exhibit"] .note {
  background: rgba(244, 241, 234, .07);
  border: 1px solid var(--m-gold-line);
  box-shadow: 0 24px 50px -30px rgba(0, 0, 0, .55),
              inset 0 1px 0 rgba(244, 241, 234, .10);
}
[data-page="museum"] [data-tone="exhibit"] .note--reject {
  background: var(--m-cream);
  border: 0;
  box-shadow: 0 20px 44px -26px rgba(0, 0, 0, .5);
  --ink: var(--m-burg-deep);
  --muted: var(--m-reject-mut);
}
/* --m-burgundy on the pale card measures 4.27:1. The deeper one is 5.32.
   A label is small type and takes the AA bar at full strength. */
[data-page="museum"] [data-tone="exhibit"] .note--reject .station__label { color: var(--m-burg-deep); }
[data-page="museum"] [data-tone="exhibit"] .note--reject .small,
[data-page="museum"] [data-tone="exhibit"] .note--reject .small--ink { color: var(--m-reject-ink); }

/* ── THE WALL SWAPS SIDES ───────────────────────────────────────────────────
   Kevin: "it needs to go from side to side. Sometimes it needs to be on the
   right and everything just flips over, and then it needs to be on the left."

   Three exhibits reading terminal-then-notes, three times, is a column of
   identical rows. Alternating turns the ledger into a walk: you cross the
   room to read the next one. Only the ORDER changes — no widths, no gaps, no
   type — so nothing has to be re-measured.

   grid-template-columns is reversed rather than using `direction`, which
   would flip the text too. */
@media (min-width: 900px) {
  [data-page="museum"] .exhibit:nth-of-type(even) .exhibit__grid {
    grid-template-columns: 22rem 1fr;
  }
  [data-page="museum"] .exhibit:nth-of-type(even) .exhibit__grid > :first-child { order: 2; }
  [data-page="museum"] .exhibit:nth-of-type(even) .exhibit__grid > :last-child  { order: 1; }
}

/* ── THE SECOND BOARD ───────────────────────────────────────────────────────
   2048 brings its own layout, so the museum only has to give it a room: the
   card it sits in, and a width that stops a 4x4 grid stretching across a
   1400px page. Its tile colours are the reference's and are left alone —
   they are the thing people recognise. */

.g--2048 { grid-template-columns: minmax(0, 1fr); justify-items: center; }
.g--2048 .g-head { justify-self: start; }

/* The base .g is a two-column board: the puzzle beside its word list. A game
   that has no list has nothing to put in the second column, so it renders 766px
   wide with 272px of empty sage beside it. 2048 already said so; the dinosaur
   needs the same sentence. */
.g--dino { grid-template-columns: minmax(0, 1fr); justify-items: center; }
.g--dino .g-head { justify-self: start; }
.g--dino .gdino { width: 100%; }   /* fills, up to its own 640 cap */
.g2048 { width: 100%; max-width: 30rem; margin-inline: auto; }
.g2048 .container { margin: 0 auto; }

/* the reference styles .retry-button only via .game-message a, so the class
   itself carries no rule and the unstyled audit is right to say so. It is a
   real control, so it gets the museum's button treatment. */
.g2048 .retry-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-min);
  padding: 0 var(--pad-card);
  border-radius: var(--radius-pill);
  background: var(--m-burg-deep);
  color: var(--m-cream);
  font-family: var(--face-ui);
  font-weight: var(--w-label);
  cursor: pointer;
  text-decoration: none;
}

/* the reference is a standalone page, so it carries page margins: 80px of
   air above the board and a heading row sized for a browser tab. Inside a
   card that reads as a hole, so the room reclaims the spacing. The board,
   the tiles and their colours are untouched. */
.g2048 { margin: 0; }
.g2048 .container { margin: 0; padding: 0; }
.g2048 .heading { margin-bottom: var(--gap-card); overflow: hidden; }
.g2048 .title { float: left; margin: 0; font-size: 34px; line-height: 1; color: var(--m-burg-deep); }
.g2048 .score-container { float: right; }
.g2048 .game-intro, .g2048 .game-explanation { display: none; }

/* ── 2048: THE FURNITURE, NOT THE BOARD ─────────────────────────────────────
   SCOPED WITH [data-page] FOR A REASON. g2048.css is behind data-needs, so
   it loads AFTER this sheet — and at equal specificity the later sheet wins.
   Written as bare .g2048 rules these lost silently: the wordmark took the
   site face and the score box kept the reference's #bbada0, which is the
   board colour and is exactly what made the number disappear.
   Kevin: "the score is actually kind of blending in with the background, so
   it's really bad... the name, it's written in a font that is really low
   quality, as well as the score."

   Both are the reference's page chrome rather than its game. The wordmark and
   the score box fell back to the browser's default serif because the
   reference names "Clear Sans" and ships no font file, and the score box is
   #bbada0 — the same colour as the board it sits above, on a cream card, so
   the number had nothing to sit against.

   THE BOARD ITSELF IS NOT TOUCHED. The grid, the tile ramp from 2 to 2048 and
   every animation are the reference's and are the thing people recognise.
   This is the frame around it. */

[data-page="museum"] .g2048 .title {
  font-family: var(--face-display);
  font-size: 46px;
  font-weight: 700;
  letter-spacing: -1px;
  color: var(--m-burg-deep);
  line-height: 1;
}
[data-page="museum"] .g2048 .score-container {
  background: var(--m-burg-deep);
  color: var(--m-cream);
  font-family: var(--face-mono);
  font-size: 26px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  border-radius: var(--radius-tile);
  padding: 22px 26px 14px;
  height: auto;
  line-height: 1;
  min-width: 5.5rem;
  text-align: center;
  box-shadow: 0 10px 24px -14px rgba(0, 0, 0, .5);
}
[data-page="museum"] .g2048 .score-container:after {
  top: 8px;
  font-family: var(--face-ui);
  font-size: 10px;
  letter-spacing: 1.2px;
  font-weight: var(--w-label);
  color: var(--m-gold);
}
/* the score's own +N flyout inherits the box colour and vanished on it */
[data-page="museum"] .g2048 .score-addition { color: var(--m-gold); font-family: var(--face-mono); }

/* the tile numerals take the site's display face rather than a fallback
   serif; the tile COLOURS are untouched */
[data-page="museum"] .g2048 .tile .tile-inner {
  font-family: var(--face-display);
  font-weight: 700;
  letter-spacing: -1px;
}
[data-page="museum"] .g2048 .game-message p {
  font-family: var(--face-display);
  font-size: 46px;
  font-weight: 700;
  color: var(--m-burg-deep);
}

/* ── THE RETAINER ───────────────────────────────────────────────────────────
   Kevin, with a drawing: a long rectangle behind each exhibit row, side to
   side, so the cards sit ON something instead of floating on flat green.
   "Just add the retainer and the frame around it... to give it some contrast.
   It's just green, you know, to make it feel a lot more premium."

   So each exhibit gets a plate: a full-width band a shade off its room, a
   hairline in the room's own accent, and a soft drop. The individual cards
   keep everything they have — this sits behind them.

   It bleeds past the column on purpose. The column is 1240px and the plate
   runs wider, which is what makes it read as a shelf the objects are resting
   on rather than a bigger card. */

[data-page="museum"] .exhibit {
  position: relative;
  padding: var(--pad-card) clamp(16px, 3vw, 40px) calc(var(--pad-card) * 1.4);
  border-radius: calc(var(--radius-card) * 1.4);
}
[data-page="museum"] .exhibit::before {
  content: "";
  position: absolute;
  inset: 0 calc(clamp(16px, 3vw, 40px) * -1);
  border-radius: inherit;
  z-index: 0;
  pointer-events: none;
}
[data-page="museum"] .exhibit > * { position: relative; z-index: 1; }

/* on sage: a paler shelf with a burgundy hairline */
[data-page="museum"] [data-tone="sage"] .exhibit::before,
[data-page="museum"] [data-tone="sage-deep"] .exhibit::before {
  background: rgba(237, 239, 230, .46);
  border: 1px solid rgba(74, 32, 41, .16);
  box-shadow: 0 30px 60px -40px rgba(30, 40, 28, .55);
}
/* on burgundy: a deeper shelf with a gold hairline */
[data-page="museum"] [data-tone="exhibit"] .exhibit::before {
  background: rgba(74, 32, 41, .42);
  border: 1px solid var(--m-gold-line);
  box-shadow: 0 30px 60px -40px rgba(0, 0, 0, .6);
}

/* the games sit on the same shelf, so the page has one idea and not two */
[data-page="museum"] .g {
  box-shadow: 0 30px 60px -40px rgba(30, 40, 28, .55);
}

/* the take-it-home bar under each exhibit */
.take {
  display: flex;
  align-items: center;
  gap: var(--pad-card);
  flex-wrap: wrap;
  margin: var(--pad-card) 0 0;
}
.take__b { flex: none; }
.take__n { opacity: .78; }
[data-page="museum"] [data-tone="exhibit"] .take__n { color: var(--m-cream-mut); }

/* ── THE +N THAT FLOATS OFF THE SCORE ───────────────────────────────────────
   Kevin: "when you score something on it, the little plus four... it's washed
   out. You need to either extend that burgundy window down just a little bit
   so it can, or render it a better color, or do both."

   Both. Two things were wrong and they compounded.

   THE COLOUR lost a specificity tie. The reference sets it at
   `.g2048 .score-container .score-addition` — three classes — and my override
   was `[data-page] .g2048 .score-addition`, which is also 0-3-0. Equal
   specificity, and g2048.css loads later because it is behind data-needs, so
   rgba(119,110,101,.9) won: a mid grey-brown, on a deep burgundy box, which
   is very close to invisible. Four classes now, and it is gold.

   THE CLIPPING is the box. .score-container is position:relative and the +N
   is absolutely positioned inside it, animating upward past the top edge —
   so anything the box clips, it clips mid-flight. overflow is stated visible
   rather than left to inherit, and the box gains a little more room below so
   the number has somewhere to leave from. */

[data-page="museum"] .g2048 .score-container {
  overflow: visible;
  padding-bottom: 20px;
}
[data-page="museum"] .g2048 .score-container .score-addition {
  color: var(--m-gold);
  font-family: var(--face-mono);
  font-size: 22px;
  font-weight: 600;
  text-shadow: 0 2px 10px rgba(74, 32, 41, .8);
}

/* ═══ THE LEDGER — "Every import, grouped by what it became" ════════════════
   Kevin: "you neglected the goddamn section, the infrastructure section...
   that entire section needs to be overhauled and beautified, just like the
   other ones is. Choose another color. Since you already did burgundy, let's
   go for another cooler color for this entire section. Maybe yellow."

   He is right and it was the obvious gap: the two exhibit rooms became
   burgundy, the corridor became sage, and the part that is actually THIRTY-SIX
   OBJECTS ON RAILS kept the corridor treatment. The room where the collection
   lives was the only room without one.

   ═══ THREE ROOMS, GETTING DEEPER ═════════════════════════════════════════

   Interface, Text and page, Infrastructure. Each takes its own ground and
   each is a step deeper than the last, so walking down the section reads as
   walking further into the building rather than scrolling one long list.
   Measured against ink before any of it was written:

       honey    #E3C97F   Interface        10.98:1
       ochre    #D4B25C   Text and page     8.77:1
       mustard  #C8A63E   Infrastructure    7.63:1
       straw    #EADFAE   the section under them

   The accent is the exhibit burgundy, not a new colour: 8.45, 6.75 and 5.87
   across the three. The rooms are new; the vocabulary is not.

   ═══ WHY THE WAVE IS ON A LAYER AND NOT ON THE ROOM ══════════════════════

   Each room ends in a wave rather than a line — "make sure there's no stark
   cutoff lines anywhere". The obvious way is to put the edge mask straight on
   the .group, and that would have been a real bug: every room contains a
   .rail__stick, which is position:sticky, and a mask on an ancestor
   establishes a containing block and clips — the same way overflow does. The
   rails would have stopped sticking and the horizontal tracks would have
   stopped travelling.

   So the ground is a ::before behind the room, and the mask is on THAT. The
   room itself is never clipped and the sticky rails keep working.        */

[data-page="museum"] {
  --m-honey:   #E3C97F;
  --m-ochre:   #D4B25C;
  --m-mustard: #C8A63E;
  --m-straw:   #EADFAE;
  --m-card-ledger: #FBF7E8;
  /* the wave shapes are NOT redeclared here. edges.css already defines
     --w-top, --w-bot and --d-bot on :root as data-URI masks, and museum.html
     loads it — copying them in cost 1.5 KB of duplicated SVG and gave the
     page two places to change one curve. */
}

[data-page="museum"] [data-tone="ledger"][data-tone="ledger"] {
  background: var(--m-straw);
  --card: var(--m-card-ledger);
  --rule: rgba(74, 32, 41, .20);
  --muted: var(--m-ink-mut);
  --bronze-text: var(--m-burg-deep);
  --accent: var(--m-burg-deep);
}

/* ── each room, on its own ground ─────────────────────────────────────── */
/* KEYED BY ATTRIBUTE, NOT BY :nth-of-type. The rooms are <div class="group">
   and nth-of-type counts SIBLINGS OF THE SAME TAG — .filters is a div too,
   so the rooms were not divs 1, 2 and 3. Interface took the second ground,
   Text and page took the third, and Infrastructure matched nothing at all
   and rendered transparent. data-room says which room it is. */
[data-page="museum"] .group {
  position: relative;
  padding: calc(var(--band-pad-y, 96px) * .5) clamp(16px, 3vw, 40px);
  margin-block: calc(var(--band-pad-y, 96px) * .35);
}
[data-page="museum"] .group::before {
  content: "";
  position: absolute;
  inset: 0 calc(clamp(16px, 3vw, 40px) * -1);
  z-index: 0;
  pointer-events: none;
  -webkit-mask-image: var(--w-top), linear-gradient(black, black), var(--w-bot);
          mask-image: var(--w-top), linear-gradient(black, black), var(--w-bot);
  -webkit-mask-repeat: no-repeat, no-repeat, no-repeat;
          mask-repeat: no-repeat, no-repeat, no-repeat;
  -webkit-mask-position: top center, center, bottom center;
          mask-position: top center, center, bottom center;
  -webkit-mask-size: 100% 48px, 100% calc(100% - 96px), 100% 48px;
          mask-size: 100% 48px, 100% calc(100% - 96px), 100% 48px;
}
[data-page="museum"] .group > * { position: relative; z-index: 1; }

[data-page="museum"] .group[data-room="1"]::before { background: var(--m-honey); }
[data-page="museum"] .group[data-room="2"]::before { background: var(--m-ochre); }
[data-page="museum"] .group[data-room="3"]::before {
  background: var(--m-mustard);
  -webkit-mask-image: var(--w-top), linear-gradient(black, black), var(--d-bot);
          mask-image: var(--w-top), linear-gradient(black, black), var(--d-bot);
}

/* the room's own card ground, so the objects sit correctly on each depth */
[data-page="museum"] .group[data-room="1"] { --card-glass: rgba(255, 253, 244, .62); }
[data-page="museum"] .group[data-room="2"] { --card-glass: rgba(255, 252, 240, .66); }
[data-page="museum"] .group[data-room="3"] { --card-glass: rgba(255, 252, 238, .70); }

/* ── THE OBJECTS, AS GLASS ────────────────────────────────────────────────
   "make sure the cards are rendered in that glassmorphic sort of glass kit UI
   sort of thing." The kit's values, the same ones .note already uses and the
   same ones the code plates took in S3: blur 18px, a 24px corner, a hairline
   edge and a long soft drop. The alpha is per-room above so the card reads as
   the same object on three different grounds. */
[data-page="museum"] [data-tone="ledger"] .station {
  background: var(--card-glass);
  -webkit-backdrop-filter: blur(var(--blur-card));
          backdrop-filter: blur(var(--blur-card));
  border: 1px solid rgba(74, 32, 41, .16);
  border-radius: var(--radius-card);
  box-shadow: 0 26px 54px -30px rgba(60, 40, 10, .42),
              inset 0 1px 0 rgba(255, 255, 255, .55);
}
[data-page="museum"] [data-tone="ledger"] .room {
  border-top: 1px solid rgba(74, 32, 41, .22);
}
[data-page="museum"] [data-tone="ledger"] .room__n { color: var(--m-burg-deep); }
/* --muted lands at 4.27:1 on the card glass over honey — a label is small
   type and takes the full AA bar, so it takes the ink. */
[data-page="museum"] [data-tone="ledger"] .station__label { color: var(--m-ink); }
[data-page="museum"] [data-tone="ledger"] .room__n::after { background: var(--m-burg-deep); }
/* THE OUTLINE BADGES ONLY. A blanket .badge colour here forced burgundy onto
   badge--verbatim and badge--superseded, which carry their own INK FILL —
   burgundy on near-black measured 1.30:1 and 1.16:1. The filled variants
   already solved their own contrast and are left alone. */
[data-page="museum"] [data-tone="ledger"] .badge:not(.badge--verbatim):not(.badge--superseded) {
  border-color: rgba(74, 32, 41, .28);
  color: var(--m-burg-deep);
}
/* the code plates keep their own opaque ground here for the same reason they
   do on burgundy: a translucent panel over a yellow room is a colour nobody
   solved for, and every syntax value inside it was measured against cream */
[data-page="museum"] [data-tone="ledger"] .swap,
[data-page="museum"] [data-tone="ledger"] .term {
  --card-glass: #FBF9F4;
  --swap-ground: #FBF9F4;
  --term-bg: #FBF9F4;
}
[data-page="museum"] [data-tone="ledger"] .swap { border-color: rgba(74, 32, 41, .20); }

@media (prefers-reduced-motion: reduce) {
  [data-page="museum"] .group::before { -webkit-mask-image: none; mask-image: none; }
}

/* ── WHY THE LEDGER CARDS LOOKED WORSE THAN THE BURGUNDY ONES ───────────────
   Kevin: "why does the burgundy section look so much more better than the
   Every Import section? Not because the color. You still forgot to overhaul
   those little cards."

   Measured, the two were already the SAME CARD: glass at 18px blur, a 24px
   corner, a 1px edge, a 24px pad, the same shadow shape. Identical values.

   The difference is what they sit on. A pale translucent card on a dark
   burgundy wall separates hard — that is the whole reason the glass kit reads
   there. The same card on a honey wall is pale-on-pale, and glass with
   nothing behind it to refract is just a slightly lighter rectangle.

   So the ledger card is not "more glass". It is the same idea solved for a
   light room: brought closer to white so it lifts off the yellow, a crisper
   top highlight so the edge catches, a deeper and tighter shadow so it sits
   ABOVE the ground rather than in it, and an edge in the room's own burgundy
   rather than a grey. Same family, different wall. */

[data-page="museum"] .group[data-room="1"] { --card-glass: rgba(255, 253, 247, .88); }
[data-page="museum"] .group[data-room="2"] { --card-glass: rgba(255, 253, 246, .90); }
[data-page="museum"] .group[data-room="3"] { --card-glass: rgba(255, 252, 244, .92); }

[data-page="museum"] [data-tone="ledger"] .station {
  border: 1px solid rgba(74, 32, 41, .22);
  box-shadow:
    0 2px 3px rgba(74, 32, 41, .06),
    0 12px 22px -12px rgba(74, 32, 41, .28),
    0 34px 60px -34px rgba(60, 40, 10, .55),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: transform var(--dur-base) var(--ease-soft),
              box-shadow var(--dur-base) var(--ease-soft);
}
[data-page="museum"] [data-tone="ledger"] .station:hover,
[data-page="museum"] [data-tone="ledger"] .station:focus-within {
  transform: translateY(-3px);
  box-shadow:
    0 2px 3px rgba(74, 32, 41, .07),
    0 16px 28px -12px rgba(74, 32, 41, .32),
    0 44px 74px -34px rgba(60, 40, 10, .6),
    inset 0 1px 0 rgba(255, 255, 255, .95);
}

/* the record inside the card gets the same rhythm the notes have: a gold-
   equivalent label, a rule under the licence line, and air between blocks */
[data-page="museum"] [data-tone="ledger"] .station__head {
  padding-bottom: var(--gap-card);
  border-bottom: 1px solid rgba(74, 32, 41, .14);
}
[data-page="museum"] [data-tone="ledger"] .station__lic {
  color: var(--m-burg-deep);
  opacity: .85;
}
[data-page="museum"] [data-tone="ledger"] .station__label {
  letter-spacing: 1.1px;
  opacity: .72;
}
[data-page="museum"] [data-tone="ledger"] .station__body > * + .station__label {
  margin-top: var(--gap-card);
}

/* ── THE PER-CARD CONTROLS ─────────────────────────────────────────────────
   Kevin: "a copy button, or our version, copy their version or our version,
   for each every individual one of these."

   Every station gets a footer with the two copies and a download. A station
   without a code panel still has a record — the licence, what was taken, what
   changed — and that record IS the thing worth carrying into somebody else's
   project, so it is what the buttons hand over. Where a station DOES have a
   before/after panel, the two copies are the two files. */
/* ── THE CARD SCROLLS ITS BODY, NOT ITSELF ────────────────────────────────
   A rail card is capped at the stick height and the long ones scroll — that
   is right and site.css explains why. But appending the controls to the CARD
   put them at the bottom of that scrolling region: on the six longest
   stations the bar was 400px below the fold INSIDE the card, and the only way
   to reach it was to scroll a box most people would not know scrolls.
   Measured before the fix: 4 of the first 6 cards had the bar out of view.

   So the scroll moves down one level. The card is the frame — name, licence,
   controls, all fixed — and the prose scrolls between them. The bar is always
   on screen for all thirty-six, whatever the card is doing.

   overscroll-behavior stays on whichever element scrolls, for the reason
   site.css gives: without it, hitting the end of the prose hands the gesture
   to a pinned page and the rail lurches sideways. */
.rail__track > .station { overflow: hidden; }
.rail__track > .station > .station__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* room for the scrollbar so the last word is not under it */
  padding-right: var(--gap-btn);
  margin-right: calc(var(--gap-btn) * -1);
}

/* ── THE CONTROL BAR ───────────────────────────────────────────────────────
   Two copies on one row, the download under them. Three pills do not fit
   across a 416px card at tap size, and a wrapping flex row put them in an
   uneven 2+1 anyway — this makes that shape deliberate and even. */
.st-take {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-btn);
  flex: none;
  margin-top: auto;
  padding-top: var(--gap-card);
  border-top: 1px solid rgba(74, 32, 41, .14);
}
.st-take__b:last-child { grid-column: 1 / -1; }
.st-take__b {
  font-family: var(--face-ui);
  font-size: var(--size-tag);
  letter-spacing: var(--ls-tag);
  text-transform: uppercase;
  font-weight: var(--w-label);
  color: var(--m-burg-deep);
  background: rgba(74, 32, 41, .06);
  border: 1px solid rgba(74, 32, 41, .18);
  border-radius: var(--radius-pill);
  padding: 0 var(--gap-card);
  min-height: var(--tap-min);
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-soft),
              border-color var(--dur-base) var(--ease-soft);
}
.st-take__b:hover { background: rgba(74, 32, 41, .12); border-color: rgba(74, 32, 41, .34); }
[data-tone="exhibit"] .st-take { border-top-color: var(--m-gold-line); }
[data-tone="exhibit"] .st-take__b {
  color: var(--m-gold);
  background: rgba(244, 241, 234, .07);
  border-color: var(--m-gold-line);
}

/* ── AND THE BODY SCROLLER RELEASES ON A THUMB ─────────────────────────────
   site.css frees the card for coarse pointers, but the two rules above are in
   THIS sheet and this sheet loads later, so at equal specificity they would
   have won and the trap would have survived the fix. Same class of mistake as
   the 2048 overrides losing to a deferred stylesheet — the undo has to sit
   beside the do.

   The query matches site.css's exactly. Where there is no pinned rail there is
   nothing to scroll inside, and the controls come back to the bottom of a card
   that is simply as tall as it is. */
@media (max-width: 760px), (pointer: coarse) {
  .rail__track > .station { overflow: visible; }
  .rail__track > .station > .station__body {
    flex: none;
    overflow: visible;
    overscroll-behavior: auto;
    padding-right: 0;
    margin-right: 0;
  }
  /* margin-top: auto pushed the bar to the bottom of a fixed-height card.
     There is no fixed height now, so it just needs its own air. */
  .st-take { margin-top: var(--gap-card); }
}
