/*
 * The room.
 *
 * A ground behind the page, and boards hung in front of it. The ground is a
 * plain colour with the page's own counter laid on it; it has been a
 * photograph of a wooden room, blurred photographs of the four counters, and
 * before either a room assembled out of planes.
 *
 * Every colour is a token; tokens.css is still the only file allowed a literal,
 * and spec/design/palette_spec.rb enforces it.
 *
 * ── The rule that still shapes this file ───────────────────────────────────
 *
 * THE BACKDROP IS A SIBLING OF THE CONTENT, NEVER AN ANCESTOR OF IT.
 *
 * A 3D transform, perspective or filter on any ancestor makes that ancestor the
 * containing block for position:fixed descendants, and breaks position:sticky
 * the same way. Two things depend on those:
 *
 *   .till-bar    (till.css)       "Take payment", pinned to the viewport so a
 *                                 ten-line bill cannot push it out of reach
 *   .connection  (components.css) the banner saying the till is offline
 *
 * spec/design/room_spec.rb fails if that stops being true.
 */

/* ── The backdrop ──────────────────────────────────────────────────────────── */

/*
 * Fixed and viewport-sized, behind everything: a plain ground, white by day and
 * a dark warm hue at night (--room-ground), and on it the things of the counter
 * the page belongs to. data-scene says which (shared/_room); a page that
 * belongs to no counter is "all", and gets a supermarket instead.
 *
 * The things are cut-out photographs (script/build-brand-assets.rb), placed
 * around the edges where the boards leave the ground showing. Sizes and offsets
 * are in viewport units so the same arrangement holds on a phone and a desktop,
 * and the offsets let a few hang off the edge, the way a display would be
 * cropped by a doorway. They sit on a ::before so --motif-opacity can quiet them
 * without touching the ground under them.
 *
 * One fetch per image named here, and only for the page's own scene: a
 * background on a selector that does not match is never loaded.
 */
.room {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--room-ground);
}

.room::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: var(--motif-opacity);
  background-repeat: no-repeat;
}

/* Four to a counter, two down each side: one high, one low, so whatever the
   screen's shape there is something either side of the boards. */
.room[data-scene="cereals"]::before {
  background-image:
    url("/assets/brand/motif-cereals-wheat-bunch-6f1dbefb.webp"),
    url("/assets/brand/motif-cereals-maize-4eb7e771.webp"),
    url("/assets/brand/motif-cereals-beans-19b9159b.webp"),
    url("/assets/brand/motif-cereals-wheat-bundle-0e3cda72.webp");
  background-position:
    left -2vmin top 10vh,
    right -4vmin top 10vh,
    left 1vmin bottom 4vh,
    right -3vmin bottom 2vh;
  background-size: auto 42vmin, 34vmin auto, 26vmin auto, auto 40vmin;
}

.room[data-scene="butchery"]::before {
  background-image:
    url("/assets/brand/motif-butchery-beef-e26bea49.webp"),
    url("/assets/brand/motif-butchery-skewers-9c52c1a9.webp"),
    url("/assets/brand/motif-butchery-chicken-2100f151.webp"),
    url("/assets/brand/motif-butchery-steaks-ac36a9fd.webp");
  background-position:
    left -5vmin top 12vh,
    right -4vmin top 10vh,
    left 2vmin bottom 4vh,
    right -4vmin bottom 5vh;
  background-size: 34vmin auto, 30vmin auto, 26vmin auto, 30vmin auto;
}

.room[data-scene="hotel"]::before {
  background-image:
    url("/assets/brand/motif-hotel-tea-0f7c1651.webp"),
    url("/assets/brand/motif-hotel-samosas-4df7bad0.webp"),
    url("/assets/brand/motif-hotel-chapati-c5f9fafe.webp"),
    url("/assets/brand/motif-hotel-spices-c4511617.webp");
  background-position:
    left 3vmin top 12vh,
    right -4vmin top 10vh,
    left -6vmin bottom 4vh,
    right -3vmin bottom 3vh;
  background-size: 22vmin auto, 32vmin auto, 34vmin auto, 30vmin auto;
}

.room[data-scene="general"]::before {
  background-image:
    url("/assets/brand/motif-general-eggs-c976249b.webp"),
    url("/assets/brand/motif-general-fruit-bag-6a46c0a4.webp"),
    url("/assets/brand/motif-general-groceries-64d0095b.webp"),
    url("/assets/brand/motif-general-oil-724ea833.webp");
  background-position:
    left 2vmin top 14vh,
    right -4vmin top 10vh,
    left -5vmin bottom 3vh,
    right 3vmin bottom 5vh;
  background-size: 24vmin auto, 28vmin auto, 42vmin auto, 18vmin auto;
}

/* Every page that is no counter's own: the supermarket, sharp but faded behind
   a veil so the boards and any words on the ground stay first. No motifs. The
   veil is heaviest down the middle, where the content column stands, and
   thins toward the sides, so the shop shows most where nothing competes. */
.room[data-scene="all"] {
  background:
    linear-gradient(
      to right,
      var(--backdrop-veil),
      var(--backdrop-veil-center) 22%,
      var(--backdrop-veil-center) 78%,
      var(--backdrop-veil)
    ),
    url("/assets/brand/backdrop-all-5ed7d015.webp") center / cover no-repeat,
    var(--room-ground);
}

/*
 * .gate paints its own opaque --color-canvas over the whole viewport, which hid
 * the room completely on the sign-in and PIN screens. Worth knowing why it only
 * bit there: body's background propagates to the canvas and therefore paints
 * BELOW a z-index:-1 backdrop, but any ordinary element's background paints
 * above it. So the gate stands down and lets the room show.
 */
.room-lit .gate {
  background: none;
}

/*
 * The shop's name sits on the room, not on a painted bar.
 *
 * .room-lit and not .room-full, which is a REVERSAL. This read ".room-full" and
 * the comment said the topbar keeps its terracotta on admin because "admin and
 * the till are tools, and a tool wants a chrome that stays put". Half of that
 * still holds and the half that does is the till — .room-plain, which keeps the
 * painted bar and its counter edge below.
 *
 * Admin was the wrong half. It stands in the same room as the storefront: the
 * SAME photograph, the same veil and the same opacity, because .room-ground has
 * no rules of its own in this file and never did — it is a marker meaning "no
 * plaques", nothing more. So a terracotta band across the top of it was a strip
 * of a different shop laid over the one behind it, and the boards below it —
 * the light switch, and now the menu — were already the room's.
 *
 * Everything the scrim below measures was measured against those same pixels,
 * so widening this selector moves no wood and changes no contrast.
 *
 * The words stay --color-text-inverse.
 */
.room-lit .topbar {
  position: relative;
  background: none;
}

/*
 * ...but "no bar" cannot mean "no contrast". Measured on the real page, the
 * brightest wood behind the shop's name reaches L 0.373 on a desktop and L 0.573
 * on a phone, which puts --color-text-inverse at 2.26:1 and 1.53:1. The comment
 * this replaces claimed the top of the frame was the dark ceiling; it is not,
 * because the room is anchored to its floor and a wide viewport crops the
 * ceiling away entirely.
 *
 * The scrim extends BELOW the bar and fades out, so there is no edge to read as
 * a bar and the planks stay visible through it.
 */
.room-lit .topbar::before {
  content: "";
  position: absolute;
  inset: 0 0 -2.5rem;
  background: linear-gradient(to bottom,
              var(--topbar-scrim) 0%,
              var(--topbar-scrim) 58%,
              transparent 100%);
  pointer-events: none;
}

/* Both are positioned, so DOM order decides: the bar's contents come after the
   ::before and paint over it. */
.room-lit .topbar__inner {
  position: relative;
}

/*
 * The till has no room, but it does stand on a counter. One plank edge under the
 * topbar, the thickness of a real counter's lip — enough that the till belongs
 * to the same shop as the storefront, and not enough to put anything behind a
 * total.
 */
.room-plain .topbar {
  border-block-end: 4px solid var(--counter-edge);
  box-shadow: inset 0 -5px 4px -4px rgb(0 0 0 / 35%);
}

/*
 * Goods on a shelf: a card in the room casts the room's shadow. Admin cards get
 * this and nothing else — see the plaques below for why they stop there.
 */
.room-lit .card,
.room-lit .good,
.room-lit .gate__card {
  box-shadow: var(--shadow-card), inset -1px 1px 0 var(--rim-light);
}

/* ── The plaques ───────────────────────────────────────────────────────────── */

/*
 * A card on the storefront is a board hung on the wall: dark oiled wood, pale
 * lettering, a lit top edge and a shadowed bottom one.
 *
 * .room-full and not .room-lit, deliberately. Admin is in the same room but its
 * cards hold tables of figures, and a table of figures on a dark board is worse
 * than one on paper. The till has no room at all.
 *
 * The page header and the storefront footer are in this list because otherwise
 * they are the only two blocks of words standing on bare wood, and they were
 * carrying a pale near-opaque "reading ground" to survive it — the one element
 * on the page that looked like a sticky note rather than a shop.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal) {
  background:
    linear-gradient(var(--plaque-veil), var(--plaque-veil)),
    var(--plaque-image) center / cover no-repeat;
  border: 1px solid var(--plaque-edge-dark);
  border-radius: var(--radius-lg);
  color: var(--color-on-plaque);
  box-shadow:
    inset 0 1px 0 var(--plaque-edge-lit),
    inset 0 -3px 6px -3px var(--plaque-edge-dark),
    var(--shadow-card);
}

/* The two that were not cards need a card's padding to become boards. */
.room-full :is(.page-header, .storefront-footer) {
  padding: var(--space-4);
  margin-block-end: var(--space-4);
}

/*
 * The heading above a plaque's content, and every quiet line inside it.
 *
 * The last four are the INVERSE of the hazard documented further down. That one
 * is a component bringing a light BACKGROUND and inheriting its colour; this is
 * a component hard-setting a light-theme COLOUR and bringing no background.
 * --color-text-muted is a mid warm brown by day, and on a board it measures
 * under 2:1.
 * `.figure dt` is the hours on the front page, and it only escaped notice
 * because the shop has no hours entered yet and the list never renders.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  :is(.card__title, .muted, .figure dt, .timeline__step--todo, .field__hint),
.room-full :is(.card, .good, .gate__card) .table--stacked td[data-label]::before,
.room-full .gate__aside {
  color: var(--color-on-plaque-muted);
}

/*
 * A link on a board is a TAB RAISED OUT of it — the exact inverse of the light
 * switch's knob, which is a block pressed into it.
 *
 *   pressed in   a whole block, sunk    the switch's chosen position
 *   raised out   a whole block, proud   a link
 *
 * Compare .counter-tab--on: it is `inset 0 2px 3px` dark along the top, where
 * the rim of the hole shadows what has gone into it, and a thin lit line along
 * the bottom where the floor of the socket catches the bulb. This is that read
 * backwards — lit along the TOP face, which is the face turned toward a bulb in
 * the top right, its own underside in shadow, and a shadow thrown down and left
 * onto the board it is standing on.
 *
 * The first attempt put this on the LETTERFORMS with text-shadow. Wrong effect:
 * the toggle's intrusion is a block, so the inverse has to be a block too. Glyph
 * relief is so subtle at reading size that it read as flat text next to a
 * plainly recessed knob.
 *
 * The tab is cut from the same board at the same veil, so the wood under a link
 * is the wood everywhere else and --color-link-on-plaque still measures the
 * 5.11:1 by day and 5.77:1 by night that spec/design/plaque_spec.rb checks. What
 * makes it a separate piece of wood is the lit edge and the cast shadow, not a
 * different colour — and `cover` on a small box lands on a different part of the
 * grain than the big board behind it, so the two do not line up, which is what
 * a real tab would do.
 *
 * No underline. A raised tab is a shape, not a colour, so it distinguishes a
 * link without one — the same way nobody underlines the words on a button.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  :is(a:not(.button), .counter__more, .socials-plaque__tab--soon) {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-link-on-plaque);
  text-decoration: none;
  background:
    linear-gradient(var(--plaque-veil), var(--plaque-veil)),
    var(--plaque-image) center / cover no-repeat;
  /*
   * Six layers, and each one is a face of the same block.
   *
   * The bulb is top-right, so the top and right bevels catch it and the bottom
   * and left are in their own shadow — inset offsets read backwards, so
   * `inset -1px 0 0` paints the RIGHT inner edge and `inset 1px 0 0` the left.
   * Bevelling all four rather than two is most of what makes it look like a
   * block rather than a lighter patch.
   *
   * Then TWO cast shadows, which is the trick that reads as height: a tight
   * dark one for where the tab nearly touches the board, and a wide soft one
   * for the light it blocks from everywhere else. One shadow says "offset";
   * two say "lifted".
   *
   * Note what is NOT here: the tab's face is not lightened, and that is a
   * measurement rather than a preference. Lifting the face more than about 14%
   * by day takes --color-link-on-plaque from 5.12:1 to 4.34:1 and fails, so a
   * visible face lift is simply not available. All of the contrast therefore
   * comes from --tab-bevel on the two lit edges and from the pair of cast
   * shadows, neither of which ever sits behind a glyph. The face stays exactly
   * the board's wood, and the words on it keep the 5.11:1 by day and 5.77:1 by
   * night that plaque_spec measures.
   */
  box-shadow:
    inset 0 1px 0 var(--tab-bevel),
    inset -1px 0 0 var(--tab-bevel),
    inset 0 -1px 0 var(--relief-shadow),
    inset 1px 0 0 var(--relief-shadow),
    -1px 2px 3px rgb(0 0 0 / 55%),
    -4px 8px 16px rgb(0 0 0 / 50%);
}

/*
 * Pressed, it goes in — and goes in as the knob does, with the same two inset
 * edges the switch uses. The tab drops onto the board and its cast shadow goes
 * with it.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  a:not(.button):active,
/* A socials tab is the board's raised tab with a mark beside the name, so it
   lays out as a row rather than the tab rule's inline-block. One class
   heavier than that rule, so it wins wherever the two land in the file. */
.room-full .socials-plaque .socials-plaque__list :is(a, span).socials-plaque__tab {
  display: inline-flex;
}

/*
 * The photo credits in the footer are small print, and nine raised tabs in a
 * row read as nine buttons. Plain underlined text instead, in the
 * same colour, which plaque_spec already measures on this wood.
 */
.room-full .storefront-footer .storefront-footer__credits a:not(.button) {
  display: inline;
  padding: 0;
  background: none;
  box-shadow: none;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.room-full :is(.counter, .device-plaque):active .counter__more {
  box-shadow:
    inset 0 2px 3px var(--relief-shadow),
    inset 0 -1px 0 var(--relief-light);
}

/*
 * THE HAZARD OF A DARK SURFACE IN A LIGHT THEME.
 *
 * A component that paints its own light background but inherits its text colour
 * is invisible on a plaque: it keeps its cream surface and takes the board's
 * bone lettering. The delivery pills did exactly this, and only in daylight —
 * at night --color-surface-sunken is dark, so the inherited bone was right by
 * accident and the bug hid.
 *
 * The list is not guesswork: it is every selector in the stylesheets that sets a
 * --color-surface/-sunken/-canvas background and no colour of its own.
 * spec/design/plaque_spec.rb runs that same scan and fails if one appears that
 * is not named here.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  :is(.pill, .tile, .table, .choice, .disclosure__body, .line__section,
      .receipt-line, .stk-status, .order-alert__count) {
  color: var(--color-text);
}

/* ...and the quiet text inside those keeps the page's muted, not the board's. */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  :is(.pill, .tile, .table, .choice, .disclosure__body) .muted {
  color: var(--color-text-muted);
}

/*
 * A quantity box and an add button on a plaque bring their own pale background
 * and their own colour, so they only need their borders redrawn: they were drawn
 * for paper and are now sitting on wood.
 */
.room-full .good :is(.add-measure__qty, .button--secondary) {
  border-color: var(--plaque-edge-dark);
}

/*
 * The rule between two lines on a board is a groove cut across the grain, not
 * a pencil line. It was --color-border, a paper colour, and on wood it all but
 * vanished. A groove reads by its two walls, exactly as the etched letters do,
 * and takes the same two edges from tokens.css: with the bulb top-right, the
 * upper wall of a cut across the board is in shadow and the lower wall catches
 * the light — dark above, lit beneath.
 *
 * The first line has nothing above it to be parted from, so it is not cut. A
 * groove under the board's own top edge would divide nothing.
 */
.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  :is(.line, .figure--strong) {
  border-block-start-color: var(--relief-shadow);
  box-shadow: inset 0 1px 0 var(--relief-light);
}

.room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
  .line:first-child {
  border-block-start: 0;
  box-shadow: none;
}

/* ── Etching ───────────────────────────────────────────────────────────────── */

/*
 * A fact cut into the board: a phone number, an address, the opening hours. For
 * things that INFORM and do not link — a link has a job and should look like it
 * has one, so nothing interactive is ever etched.
 *
 * The depth is the two shadows, not a dimmer colour: see tokens.css. The letter
 * keeps a measured 5.18:1 by day and 5.86:1 by night, which
 * spec/design/plaque_spec.rb re-measures against the real board.
 */
.room-full .etched {
  color: var(--color-etched);
  text-shadow:
    1px -1px 1px var(--relief-shadow),
    -1px 1px 0 var(--relief-light);
}

/* A shop's number, painted big on the board the way it is on a shopfront. It is
   not a link: the button underneath it is, and a dialer shows the number back
   to you anyway. */
.room-full .etched--number {
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  margin-block-end: var(--space-3);
}

/* ── The front page ────────────────────────────────────────────────────────── */

/*
 * The basket stands in the room and the words hang beside it on a board. It
 * used to be a photograph of a DIFFERENT room with the words scrimmed on top,
 * which is why the page never quite settled: two rooms, one above the other.
 *
 * Side by side where there is room, stacked where there is not — the same rule
 * as everywhere else on a phone.
 */
.landing-hero {
  display: grid;
  gap: var(--space-4);
  align-items: center;
  margin-block-end: var(--space-5);
}

@media (min-width: 52rem) {
  .landing-hero {
    grid-template-columns: 1.05fr 1fr;
    gap: var(--space-6);
  }
}

/*
 * Cut out, on nothing, so the room shows around it. The drop shadow is what
 * stands it ON the floor instead of floating it in front — same direction as
 * every other shadow in the app.
 *
 * Capped at 22rem and centred in its column because the kiondo's original is
 * only 220px. The file is a 2x upscale of it, and it stays sharp up to about
 * this size. Across the full column it would look soft.
 */
.landing-hero__basket {
  display: block;
  width: 100%;
  max-width: 22rem;
  height: auto;
  margin-inline: auto;
  filter: drop-shadow(-6px 14px 18px rgb(0 0 0 / 45%));
}

.landing-hero__words {
  margin: 0;
  text-align: center;
}

/*
 * Press-to-lift. A customer's tap should move the thing they touched, the way
 * taking something off a shelf does. Storefront only — the till is a tool and a
 * seller in a hurry does not need the merchandise moving.
 */
/*
 * The whole board is a link now, so it has to answer a pointer — and the edge
 * catching the light is the cue, deliberately, because a colour change is not
 * motion. Someone who has asked for reduced motion still gets an answer.
 */
.room-full :is(.counter, .device-plaque):hover {
  border-color: var(--plaque-edge-lit);
}

/*
 * The settings plaques: the one set of boards in admin. Admin stays off the
 * wood because a table of figures reads worse on it — but a settings plaque
 * holds a name, a line and a count, which is exactly what a board is for, and
 * the forms it opens are on paper (.sheet--paper). The same wood, veil and
 * lettering as the storefront's boards, so the contrast plaque_spec measures
 * holds here too.
 */
.room-lit .settings-plaque {
  background:
    linear-gradient(var(--plaque-veil), var(--plaque-veil)),
    var(--plaque-image) center / cover no-repeat;
  border: 1px solid var(--plaque-edge-dark);
  color: var(--color-on-plaque);
  box-shadow:
    inset 0 1px 0 var(--plaque-edge-lit),
    inset 0 -3px 6px -3px var(--plaque-edge-dark),
    var(--shadow-card);
}

.room-lit .settings-plaque__blurb { color: var(--color-on-plaque-muted); }
.room-lit .settings-plaque:hover { border-color: var(--plaque-edge-lit); }

@media (prefers-reduced-motion: no-preference) {
  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque) {
    transition: box-shadow 120ms ease-out, translate 120ms ease-out,
                border-color 120ms ease-out;
  }

  /* Lifted toward you under the pointer, pressed back down under a thumb. */
  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque):hover {
    translate: 0 -2px;
  }

  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque):active {
    translate: 0 1px;
    box-shadow: 0 1px 2px rgb(0 0 0 / 12%), -2px 3px 8px rgb(0 0 0 / 10%);
  }
}

/* ── When the room has to get out of the way ───────────────────────────────── */

/*
 * Motion is a new category in this app — there were no transitions, no
 * animations and no reduced-motion handling anywhere before the room. So it is
 * spelled out rather than assumed. These selectors match the ones that ADD the
 * motion character for character: `.room-lit .card` would score 0,2,0 against
 * the 0,3,0 that adds it, lose the cascade, and leave the transition running.
 */
@media (prefers-reduced-motion: reduce) {
  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque) {
    transition: none;
  }

  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque):hover,
  .room-lit :is(.landing-counters .card, .device-plaque, .settings-plaque):active {
    translate: none;
  }
}

/* The staff screens keep a white veil by day (tokens.css says why). */
.room-ground .room[data-scene="all"] {
  --backdrop-veil: var(--staff-veil);
  --backdrop-veil-center: var(--staff-veil-center);
}

/*
 * Words that stand on the supermarket rather than on a board: a page's heading
 * and the line under it, as on the basket when it is empty. The colour is set
 * on main and inherited, which is safe on these pages because every board and
 * every pale island inside one sets its own; the shadow goes only on the
 * page's own lines, so no board's lettering picks it up. :where() keeps all of
 * it below any rule a board or a component brings.
 */
:where(.room-full:has(> .room[data-scene="all"])) main {
  color: var(--backdrop-ink);
}

:where(.room-full:has(> .room[data-scene="all"])) main > :is(h1, h2, h3, p) {
  text-shadow: 0 1px 3px var(--backdrop-ink-shadow);
}

:where(.room-full:has(> .room[data-scene="all"])) main > p:is(.muted) {
  color: var(--backdrop-ink-muted);
}

:where(.room-full:has(> .room[data-scene="all"])) main > p a:not(.button) {
  color: var(--backdrop-link);
}

/*
 * Someone who has asked for more contrast, or for less transparency, is telling
 * you they are struggling to read the screen. The photographs go first: the
 * tokens alone are already measured at AA in both lights, and the pictures are
 * the part that is decoration.
 */
@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .room,
  .room[data-scene] {
    background: var(--color-canvas);
  }

  .room::before {
    content: none;
  }

  :where(.room-full) main {
    color: var(--color-text);
  }

  :where(.room-full) main > :is(h1, h2, h3, p) {
    text-shadow: none;
  }

  :where(.room-full) main > p:is(.muted) {
    color: var(--color-text-muted);
  }

  :where(.room-full) main > p a:not(.button) {
    color: var(--color-link);
  }

  .room-lit .topbar {
    background: var(--color-action);
  }

  .room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal) {
    background: var(--color-surface);
    color: var(--color-text);
  }

  .room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
    :is(.card__title, .muted),
  .room-full .gate__aside {
    color: var(--color-text-muted);
  }

  .room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
    :is(a:not(.button), .counter__more) {
    padding: 0;
    color: var(--color-link);
    background: none;
    box-shadow: none;
    text-decoration: underline;
  }

  .room-full .gate__brand {
    color: var(--color-action);
  }

  .room-lit .settings-plaque {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-card);
  }

  .room-lit .settings-plaque__blurb { color: var(--color-text-muted); }

  .landing-hero__basket,
  .counter__picture,
  .page-header__picture {
    filter: none;
  }

  /* Nothing is carved into a flat surface. */
  .room-full .etched {
    color: var(--color-text-muted);
    text-shadow: none;
  }
}

/* ── Print ─────────────────────────────────────────────────────────────────── */

@media print {
  .room { display: none; }

  /* Pale letters on dark wood is a photograph of a board, and a printer would
     lay down a page of ink to say so. On paper a card is a card. */
  .room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal) {
    background: none;
    color: var(--color-text);
    box-shadow: none;
  }

  .room-full :is(.card, .good, .gate__card, .page-header, .storefront-footer, .sheet:modal)
    :is(a:not(.button), .muted, .card__title, .counter__more) {
    padding: 0;
    color: var(--color-text);
    background: none;
    box-shadow: none;
    text-shadow: none;
  }

  .landing-hero__basket,
  .counter__picture,
  .page-header__picture { filter: none; }

  .room-lit .settings-plaque {
    background: none;
    color: var(--color-text);
    box-shadow: none;
  }

  .room-lit .settings-plaque__blurb { color: var(--color-text); }

  .room-full .etched {
    color: var(--color-text);
    text-shadow: none;
  }
}
