/* ============================================================================
   THE GALLERY WALL — /shop and /shop/art (2026-09-19)

   Loaded after store.css, only on the wall page (render/wall.mjs puts the
   link in shopchrome.py's {extra_head} slot). store.css still owns the white
   ground, the chips and the button tokens; this file owns the wall.

   ONE UNIT: --cm. The admin stores every work's box in centimetres on a
   300 cm wall. The stage measures its own height in pixels (wall.js writes
   --wallh; the calc() below is the no-script fallback) and divides by the
   centimetres of wall that should be visible (--wall-cm): that quotient is
   one centimetre in CSS pixels, and every size on the wall is a multiple of
   it. A 60 cm painting is 60 * --cm wide on every screen, next to a 20 cm
   object that is 20 * --cm -- the works keep their real proportions to each
   other, which is the whole point of a wall instead of a grid.

   THE STAGE IS A REAL SCROLL CONTAINER. overflow-x:auto, so a trackpad, a
   sideways swipe, the keyboard's focus-into-view and a dead script all pan it
   natively; wall.js only ADDS the vertical gestures (wheel, vertical swipe)
   on top. Positions use inset-inline-start, and the stage carries dir="ltr"
   in both languages (Ilai, 2026-09-20): the wall starts at the LEFT.

   Laws kept: every font-size is multiplied by --a11y-scale; every new
   component has a doubled html[data-a11y-contrast][data-a11y-contrast] rule;
   nothing is hidden behind a transition (the one transition is a 1px hover
   lift); no reduced-motion media query anywhere; the phone block is LAST.
   ========================================================================== */

html[data-store] body.wall{
  position:relative;display:flex;flex-direction:column;
  height:100vh;height:100dvh;min-height:0;overflow:hidden}
/* align-items:stretch, said out loud: page.css's main is a column flex that
   CENTRES its children, and a centred scroller grows to its content width
   (20,000px) and hangs off both sides of the screen */
html[data-store] body.wall main{
  /* the unit lives on main so the stage, the hint and the copyright all see it;
     --floor is the floor strip in cm and must match nothing else: the works'
     y is measured from ITS top edge */
  --floor:14;
  --wall-cm:300;
  --wallh:calc(100vh - 48px);
  --cm:calc(var(--wallh) / var(--wall-cm));
  position:relative;display:flex;flex-direction:column;flex:1 1 auto;
  align-items:stretch;justify-content:flex-start;
  /* z-index:auto, not page.css's 1: a stacking context on main would trap
     the fixed panel under the bar and the copyright line */
  z-index:auto;
  min-height:0;width:100%;padding:0;overflow:hidden}
/* THE COPYRIGHT LINE sits at the very bottom-start of the page, where every
   other tab keeps it (Ilai, 2026-09-20: "at the bottom of the page on PC
   just like the home tab"). It used to stand ON the wall above the skirting;
   down here it lies on the oak floor, so it takes the walk's light ink and
   the walk's shadow instead of the store's dark ink. It is a child of body;
   wall.js moves it into main -- both end at the bottom of the viewport, so
   the line lands in the same place either way.
   The PHONE keeps it up on the wall (the phone block at the end of this
   file): down here it would run into the position bar. */
html[data-store] body.wall .copy{
  position:absolute;inset-inline-start:14px;bottom:10px;z-index:2;margin:0;padding:0;
  font-size:calc(10px * var(--a11y-scale));
  color:rgba(243,236,227,.82);text-shadow:0 1px 2px rgba(20,16,13,.75);pointer-events:none}
html[data-store] body.wall main > .copy{bottom:10px}

/* ---- the chips float over the middle of the wall's top edge -----------------
   CENTRED, not in the start corner (Ilai, 2026-09-20: "move the 2 buttons to
   the middle of the screen so they will not move and change position when
   switching between them"). /shop/design centres its row -- it is the store's
   ordinary sticky .hrow inside a centred .wrap -- so a corner-anchored row
   here made the pair jump across the screen on every switch. Centred, and at
   the same height, they hold still. */
html[data-store] .wtop{
  position:absolute;top:0;left:0;right:0;z-index:3;
  padding:max(10px, calc(1 * var(--fit))) var(--pad);pointer-events:none}
html[data-store] body.wall .hrow{
  position:static;background:transparent;box-shadow:none;padding:0;justify-content:center}
html[data-store] body.wall .cats{pointer-events:auto}

/* ---- the stage ------------------------------------------------------------- */
html[data-store] .wstage{
  position:relative;flex:1 1 auto;min-height:0;
  width:100%;max-width:100%;min-width:0;
  overflow-x:auto;overflow-y:hidden;
  overscroll-behavior-x:contain;
  -webkit-overflow-scrolling:touch;
  touch-action:pan-x;
  scrollbar-width:none;
  cursor:grab;outline:none}
html[data-store] .wstage::-webkit-scrollbar{display:none}
html[data-store] .wstage.is-dragging{cursor:grabbing}
html[data-store] .wstage:focus-visible{box-shadow:inset 0 0 0 3px var(--accent)}

/* the plaster: a warm off-white with a whisper of grain, lit from above */
html[data-store] .wsurf{
  position:relative;height:100%;width:calc(var(--len) * var(--cm));
  background-color:#f4f1ec;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 0 0 0 .05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px}
html[data-store] .wlight{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to bottom, rgba(255,255,255,.5) 0, rgba(255,255,255,0) 32%, rgba(25,23,20,0) 70%, rgba(25,23,20,.05) 100%)}
/* the floor strip and the skirting board above it */
html[data-store] .wfloor{
  position:absolute;left:0;right:0;bottom:0;height:calc(var(--floor) * var(--cm));
  background:linear-gradient(to bottom, #dcd6cc, #cfc8bd);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55)}
html[data-store] .wbase{
  position:absolute;left:0;right:0;bottom:calc(var(--floor) * var(--cm));height:calc(6 * var(--cm));
  background:linear-gradient(to bottom, #fbfaf7, #ece8e1);
  box-shadow:0 1px 0 rgba(25,23,20,.18), 0 calc(.4 * var(--cm)) calc(.8 * var(--cm)) rgba(25,23,20,.10)}

/* ---- a work ----------------------------------------------------------------- */
/* HOW HIGH A WORK HANGS, in one place. --y is the admin's height above the
   floor line; --yy is what everything measures from, so the phone block at
   the end of this file can drop a work (and its light with it) by the
   --down that render/wall.mjs's ADJUST puts on both. Declared in a rule,
   not inline, precisely so a media query can restate it: an inline --y
   would outrank any rule. */
html[data-store] .work,
html[data-store] .wspot{--yy:var(--y)}
html[data-store] .work{
  position:absolute;display:block;
  inset-inline-start:calc(var(--x) * var(--cm));
  bottom:calc((var(--yy) + var(--floor)) * var(--cm));
  width:calc(var(--w) * var(--cm));height:calc(var(--h) * var(--cm));
  -webkit-tap-highlight-color:transparent;text-decoration:none}
html[data-store] .work picture{display:block;width:100%;height:100%}
html[data-store] .work img{
  display:block;width:100%;height:100%;object-fit:contain;object-position:center bottom;
  filter:drop-shadow(0 calc(.5 * var(--cm)) calc(1.1 * var(--cm)) rgba(25,23,20,.26))
         drop-shadow(0 calc(.12 * var(--cm)) calc(.25 * var(--cm)) rgba(25,23,20,.16));
  transition:transform .15s ease}
html[data-store] .work:hover img{transform:translateY(-1px)}
/* a work shown as a looping video (render/wall.mjs VIDEOS): the same box,
   the same shadow as a painting's */
html[data-store] .work .wvid{
  display:block;width:100%;height:100%;object-fit:contain;object-position:center bottom;background:transparent;
  filter:drop-shadow(0 calc(.5 * var(--cm)) calc(1.1 * var(--cm)) rgba(25,23,20,.26))}
html[data-store] body.wall .work .wvid{
  filter:drop-shadow(0 calc(1.2 * var(--cm)) calc(1.8 * var(--cm)) rgba(14,10,6,.34))}
html[data-store] .work:focus-visible{outline:3px solid var(--accent);outline-offset:4px;border-radius:2px}
/* a standing piece throws a longer, lower shadow and a contact shadow on
   whatever it stands on */
html[data-store] .work.is-sculpture img{
  object-position:center bottom;
  filter:drop-shadow(calc(.3 * var(--cm)) calc(1.2 * var(--cm)) calc(1.4 * var(--cm)) rgba(25,23,20,.30))}
html[data-store] .work.is-sculpture::after{
  content:"";position:absolute;left:6%;right:6%;bottom:calc(-.5 * var(--cm));height:calc(1.2 * var(--cm));
  border-radius:50%;background:radial-gradient(ellipse at center, rgba(25,23,20,.30), rgba(25,23,20,0) 70%);
  pointer-events:none;z-index:-1}

/* ---- furniture: a plinth, a console, a shelf, all in CSS -------------------- */
html[data-store] .furn{
  position:absolute;pointer-events:none;
  inset-inline-start:calc(var(--x) * var(--cm));
  bottom:calc((var(--y) + var(--floor)) * var(--cm));
  width:calc(var(--w) * var(--cm));height:calc(var(--h) * var(--cm))}
/* the plinth: a pale block, its top face a shade lighter, its end face a
   shade darker, and a soft shadow on the floor */
html[data-store] .furn.is-plinth{
  background:linear-gradient(to right, #f6f3ee, #ebe6de 70%, #e1dbd1);
  box-shadow:0 calc(1 * var(--cm)) calc(2 * var(--cm)) rgba(25,23,20,.18), inset 0 -1px 0 rgba(25,23,20,.10)}
html[data-store] .furn.is-plinth i{
  position:absolute;left:0;right:0;top:0;height:calc(2.5 * var(--cm));
  background:linear-gradient(to bottom, #fbfaf7, #f1eee8);box-shadow:0 1px 0 rgba(25,23,20,.12)}
/* the console: a dark wooden top on two slender legs */
html[data-store] .furn.is-console{
  border-top:calc(3.5 * var(--cm)) solid #3a2f28;
  background:linear-gradient(to right, #3a2f28 0, #3a2f28 calc(3 * var(--cm)), transparent calc(3 * var(--cm)),
    transparent calc(100% - 3 * var(--cm)), #3a2f28 calc(100% - 3 * var(--cm)));
  box-shadow:0 calc(1.2 * var(--cm)) calc(2.4 * var(--cm)) rgba(25,23,20,.16)}
html[data-store] .furn.is-console i{
  position:absolute;left:0;right:0;top:calc(-3.5 * var(--cm));height:calc(3.5 * var(--cm));
  background:linear-gradient(to bottom, #5a4a3f, #3a2f28 55%, #2b221d);box-shadow:0 1px 0 rgba(0,0,0,.25)}
/* the shelf: a slab with a shadow beneath it */
html[data-store] .furn.is-shelf{
  background:linear-gradient(to bottom, #fbfaf7, #e9e5de);
  box-shadow:0 1px 0 rgba(25,23,20,.18), 0 calc(1.2 * var(--cm)) calc(2 * var(--cm)) rgba(25,23,20,.20)}
html[data-store] .furn.is-shelf i{display:none}

/* ---- the nudge to slide --------------------------------------------------------
   Ilai, 2026-09-20: "instead of the text scroll sideways just add a logo
   fade in and out on the right side like a slide icon". So: no words. Three
   chevrons on the RIGHT edge (right, not inset-inline-end -- the wall runs
   left to right in both languages), in a glass disc, breathing in and out,
   each chevron a beat behind the one before it so the set reads as a hand
   going that way. wall.js hides it outright on the first pan.
   It is aria-hidden and decorative: the stage's own label carries the count
   and the instruction, so nothing is behind the animation. */
html[data-store] .whint{
  position:absolute;right:max(12px, calc(1.2 * var(--fit)));top:50%;transform:translateY(-50%);
  z-index:2;margin:0;padding:0;pointer-events:none;
  width:52px;height:52px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.16);box-shadow:inset 0 0 0 1px rgba(255,255,255,.28);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  animation:wbreathe 2.8s ease-in-out infinite}
html[data-store] .whint[hidden]{display:none}
html[data-store] .wslide{display:block;width:30px;height:24px}
html[data-store] .wslide svg{
  display:block;width:100%;height:100%;fill:none;
  stroke:rgba(255,252,246,.95);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
html[data-store] .wslide .c1{animation:wchev 2.8s ease-in-out infinite}
html[data-store] .wslide .c2{animation:wchev 2.8s ease-in-out .18s infinite}
html[data-store] .wslide .c3{animation:wchev 2.8s ease-in-out .36s infinite}
@keyframes wbreathe{0%,100%{opacity:.18}45%,60%{opacity:1}}
@keyframes wchev{0%,100%{opacity:.25}50%{opacity:1}}
/* the site's one motion switch (never a reduced-motion query): the disc
   simply sits there, fully visible, until the first pan takes it away */
html[data-a11y-motion] .whint{animation:none;opacity:1}
html[data-a11y-motion] .wslide .c1,
html[data-a11y-motion] .wslide .c2,
html[data-a11y-motion] .wslide .c3{animation:none;opacity:1}

/* ---- the position bar ----------------------------------------------------------
   Where you stand on the wall, left to right like the wall itself: a thin
   frosted pill centred on the floor strip, a hairline track and a dark
   thumb as wide as the share of the wall on screen. The element is a tall
   invisible hit area (a finger needs ~30px); only the 5px track shows, and
   it thickens under the finger. direction:ltr in both languages -- the wall
   runs left to right, so does its bar. */
html[data-store] .wbar{
  position:absolute;left:50%;transform:translateX(-50%);z-index:2;
  bottom:max(4px, calc(var(--floor) * var(--cm) / 2 - 15px));
  width:min(380px, calc(100% - 64px));height:30px;
  direction:ltr;display:flex;align-items:center;
  padding:0 12px;border-radius:15px;
  background:rgba(255,255,255,.52);
  -webkit-backdrop-filter:blur(14px) saturate(170%);backdrop-filter:blur(14px) saturate(170%);
  box-shadow:0 1px 2px rgba(25,23,20,.08), inset 0 0 0 .5px rgba(25,23,20,.10);
  cursor:pointer;touch-action:none;-webkit-tap-highlight-color:transparent;user-select:none;-webkit-user-select:none}
html[data-store] .wbar[hidden]{display:none}
html[data-store] .wbar-track{
  position:relative;flex:1 1 auto;height:5px;border-radius:3px;
  background:rgba(25,23,20,.12);transition:height .15s ease}
html[data-store] .wbar-thumb{
  position:absolute;left:0;top:0;bottom:0;width:28px;border-radius:3px;
  background:rgba(29,29,31,.72);will-change:transform}
html[data-store] .wbar:hover .wbar-track,
html[data-store] .wbar.is-active .wbar-track{height:7px}
html[data-store] .wbar.is-active .wbar-thumb{background:rgba(29,29,31,.86)}

/* ---- the panel ---------------------------------------------------------------
   A CARD THAT NEVER COVERS THE WORK (Ilai, 2026-09-20: "like a pop-up and it
   will never hide the selected art piece ... if the artwork is on the left
   side put the pop-up text on the right side ... very clean and simple ...
   without sharp edges").

   So it is no longer a full-height slab pinned to the end of the screen. It
   is a floating card, half the height, on ONE SIDE -- and which side is
   decided per work by wall.js, which puts it opposite the work and then
   glides the wall until the work sits clear of it. The scrim it used to lie
   under is gone on a desktop: a 36 % black wash over everything dimmed the
   very work you had just asked to see. It stays on a phone, where the sheet
   really does take the bottom of the screen.

   Clean, in the sense asked for: no boxed-in alert, no hairline outlines, one
   accent mark under the title and nothing else coloured. Frosted white, a
   22 px radius, a soft deep shadow, and the two actions at the foot -- the
   first filled, the second quiet.

   Shipped hidden; wall.js opens it, and with the script dead the hash opens
   it through :target (the work's href is /shop/art#<slug>) and the close is
   a link -- which is why every rule here works without a class from JS. */
html[data-store] .wscrim{position:fixed;inset:0;z-index:29;background:transparent}
html[data-store] .wscrim[hidden]{display:none}
html[data-store] .wp{
  position:fixed;z-index:30;
  top:50%;transform:translateY(-50%);
  right:max(18px, calc(1.4 * var(--fit)));left:auto;
  width:min(392px, 34vw);min-width:302px;
  max-height:min(74vh, 640px);
  display:flex;flex-direction:column;gap:max(13px, calc(.9 * var(--fit)));
  padding:max(26px, calc(1.9 * var(--fit))) max(26px, calc(1.9 * var(--fit))) max(20px, calc(1.5 * var(--fit)));
  overflow-y:auto;overscroll-behavior:contain;
  border-radius:22px;
  background:rgba(253,252,250,.82);color:var(--ink);
  -webkit-backdrop-filter:blur(30px) saturate(180%);backdrop-filter:blur(30px) saturate(180%);
  box-shadow:0 24px 64px rgba(18,12,6,.26), 0 2px 10px rgba(18,12,6,.10),
             inset 0 0 0 .5px rgba(255,255,255,.75)}
/* wall.js flips it to the start side when the work is on the end side */
html[data-store] .wp.is-start{right:auto;left:max(18px, calc(1.4 * var(--fit)))}
html[data-store] .wp[hidden]{display:none}
html[data-store] .wp[hidden]:target{display:flex}
html[data-store] .wpx{
  position:absolute;top:14px;inset-inline-end:14px;width:30px;height:30px;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
  color:rgba(25,23,20,.55);background:rgba(25,23,20,.06);box-shadow:none;text-decoration:none;
  transition:background .15s ease, color .15s ease}
html[data-store] .wpx svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round}
html[data-store] .wpx:hover{background:rgba(25,23,20,.12);color:var(--ink)}
html[data-store] .wpname{
  margin:0;padding-inline-end:34px;
  font-family:var(--display);font-weight:400;line-height:1.12;text-align:start;
  letter-spacing:-.01em;
  font-size:calc(clamp(23px, 2.1 * var(--fit), 30px) * var(--a11y-scale))}
html[data-store] .wpname::after{
  content:"";display:block;width:34px;height:2px;border-radius:2px;
  background:var(--accent);margin:max(12px, calc(.9 * var(--fit))) 0 0}
html[data-store] .wpblurb{
  margin:0;color:rgba(25,23,20,.72);line-height:1.6;
  font-size:calc(clamp(14.5px, .9 * var(--fit), 16px) * var(--a11y-scale))}
/* the line that matters -- the price is at the gallery -- said quietly */
html[data-store] .wpask{
  margin:0;padding:0;border-radius:0;background:none;box-shadow:none;
  color:var(--ink);font-weight:500;line-height:1.55;
  font-size:calc(clamp(14px, .88 * var(--fit), 15.5px) * var(--a11y-scale))}
html[data-store] .wpact{
  display:flex;gap:9px;margin-top:auto;padding-top:max(10px, calc(.8 * var(--fit)))}
/* BOTH ACTIONS ARE THE SITE'S BUTTON, WHOLE (Ilai, 2026-09-20, over four
   rounds: "change the style of the buttons Contact us and WhatsApp … so it
   will look like the buttons in the gallery tab", then twice more that they
   still did not). This file now says almost nothing about them, which is the
   point: page.css owns the button and store.css owns its colour on a light
   ground, so the two only need to share the row. Everything that used to be
   restated here — 44 px instead of 54, 12 px of padding, a 14.5 px label, and
   a RANK that left WhatsApp a bare label with no surface at all — was what
   made them read as a different control from the one on /space.
   Why they are the light glass and not the dark one is written at length in
   store.css, above the --glass-* tokens. */
html[data-store] .wpact .btn{
  flex:1 1 0px;padding-inline:max(10px, calc(1.2 * var(--fit)))}

/* ============================================================================
   THE ROOM (2026-09-20) -- ONE room for everyone (Ilai: plaster wall, black
   skirting, a wooden floor; the brick/concrete switch is gone). Scoped with
   body.wall, which the server renders, so it is there before any script.
   The wall becomes a lit room, all in the one unit --cm:
   * .wwall  -- the plaster, real-size tiles rasterised from shopassets/room/plaster.svg
   * .wrail  -- a black ceiling track along the top of the wall
   * .wspot  -- per work, a warm pool of light and the scallop a ceiling can
                throws, under the works; its ::before is the can itself
   * .wroom  -- the floor: a plane in 3D perspective seen from eye height
                (150 cm) at 3 m, one screen wide, OUTSIDE the scroller;
                wall.js slides it with the wall (a translateX), so the far
                edge keeps pace with the works and the near edge runs ahead
   * .wsh    -- a standing piece's shadow on the wall behind it: the cut-out
                itself, blacked, blurred and pushed down-right, away from
                the light
   Shadows all fall away from one light: above and in front of the wall.
   ========================================================================== */
html[data-store] body.wall main{--floor:36;--wall-cm:324}
/* overflow clipped: a lamp's 2 m glow or a scaled figure near either end
   would otherwise widen the scroller past the wall into bare page */
html[data-store] body.wall .wsurf{background:none;overflow:hidden}
html[data-store] body.wall .wfloor{display:none}

/* the wall's material -------------------------------------------------------- */
html[data-store] body.wall .wwall{
  display:block;position:absolute;left:0;right:0;top:0;bottom:calc(var(--floor) * var(--cm));
  /* two bitmaps made from plaster.svg by scripts/raster-room.cjs: the fine
     grain on a quarter tile over the soft blotches (Safari ran the SVG's
     noise filter on the CPU per painted tile) */
  background:
    url("room/plaster-fine.webp") 0 0 / calc(50 * var(--cm)) calc(50 * var(--cm)),
    #efebe4 url("room/plaster-lo.webp") 0 0 / calc(200 * var(--cm)) calc(200 * var(--cm))}
/* the room's light: dimmer under the ceiling and toward the floor, so the
   pools read as light */
html[data-store] body.wall .wlight{
  bottom:calc(var(--floor) * var(--cm));
  background:linear-gradient(to bottom, rgba(22,16,10,.52) 0, rgba(22,16,10,.34) 16%, rgba(22,16,10,.26) 45%, rgba(22,16,10,.30) 80%, rgba(22,16,10,.40) 100%)}
/* the ceiling track */
html[data-store] body.wall .wrail{
  display:block;position:absolute;left:0;right:0;top:0;height:calc(1.8 * var(--cm));z-index:1;
  background:linear-gradient(to bottom, #2b2926, #121110);box-shadow:0 calc(.6 * var(--cm)) calc(1 * var(--cm)) rgba(0,0,0,.28)}

/* MUSEUM LIGHT ------------------------------------------------------------------
   Per work, from the ceiling track: a spot head that looks lit (a satin black
   can on a stem, its lens glowing with a bloom), a faint beam from the lens
   down to the work, a bright pool on the wall around the work, and -- inside
   the work's own anchor -- the light landing ON the work (.wlit, below).
   The room around it is kept dim (.wlight) so the works carry the light. */
html[data-store] body.wall .wspot{
  display:block;position:absolute;pointer-events:none;z-index:0;
  left:calc((var(--x) + var(--w) / 2 - (var(--w) + 110) / 2) * var(--cm));
  width:calc((var(--w) + 110) * var(--cm));
  top:0;bottom:calc((var(--yy) + var(--floor) - 35) * var(--cm))}
/* the pool on the wall: a hot oval around the work, fading wide, and the
   soft start of the cone just under the head */
html[data-store] body.wall .wspot::after{
  content:"";position:absolute;inset:0;mix-blend-mode:screen;
  background:
    radial-gradient(ellipse 40% 36% at 50% 66%, rgba(255,228,184,.70), rgba(255,228,184,.34) 42%, rgba(255,228,184,.08) 75%, rgba(255,228,184,0) 100%),
    radial-gradient(ellipse 16% 22% at 50% 7%, rgba(255,232,196,.34), rgba(255,232,196,0) 100%)}
/* the head: stem from the track, a satin black can, lit from the room */
html[data-store] body.wall .wcan{
  position:absolute;left:50%;top:calc(3.4 * var(--cm));z-index:2;
  width:calc(6.4 * var(--cm));height:calc(12 * var(--cm));margin-left:calc(-3.2 * var(--cm));
  border-radius:calc(1 * var(--cm)) calc(1 * var(--cm)) calc(.7 * var(--cm)) calc(.7 * var(--cm));
  background:linear-gradient(90deg, #050505 0%, #262422 20%, #5a5651 36%, #2a2826 55%, #0f0e0d 80%, #050505 100%);
  box-shadow:0 calc(.8 * var(--cm)) calc(1.4 * var(--cm)) rgba(0,0,0,.40)}
html[data-store] body.wall .wcan::before{
  content:"";position:absolute;left:50%;top:calc(-1.8 * var(--cm));
  width:calc(1.4 * var(--cm));height:calc(2 * var(--cm));margin-left:calc(-.7 * var(--cm));
  background:linear-gradient(90deg, #0a0a0a, #3a3835 50%, #0a0a0a)}
/* the lens: white-hot at its heart, warm at its rim, blooming into the air */
html[data-store] body.wall .wcan::after{
  content:"";position:absolute;left:calc(-2.4 * var(--cm));right:calc(-2.4 * var(--cm));
  bottom:calc(-2.6 * var(--cm));height:calc(5.2 * var(--cm));border-radius:50%;
  background:radial-gradient(ellipse 30% 22% at 50% 50%, #fffef6 0, #fff0c8 34%, rgba(255,220,160,.60) 58%, rgba(255,205,130,.18) 78%, rgba(255,200,120,0) 100%);
  filter:blur(calc(.18 * var(--cm)))}
/* the beam: a faint cone in the air from the lens to the work */
html[data-store] body.wall .wbeam{
  position:absolute;left:50%;top:calc(15.4 * var(--cm));z-index:1;
  width:calc((var(--w) + 40) * var(--cm));transform:translateX(-50%);
  height:calc((var(--wall-cm) - var(--floor) - 15.4 - var(--yy) - var(--h) * .5) * var(--cm));
  filter:blur(calc(1.4 * var(--cm)));mix-blend-mode:screen;opacity:.85}
html[data-store] body.wall .wbeam::before{
  content:"";position:absolute;inset:0;
  clip-path:polygon(calc(50% - 2.4 * var(--cm)) 0, calc(50% + 2.4 * var(--cm)) 0, 100% 100%, 0 100%);
  background:linear-gradient(to bottom, rgba(255,238,206,.34) 0, rgba(255,238,206,.16) 45%, rgba(255,238,206,.05) 85%, rgba(255,238,206,0) 100%)}

/* a lamp that is a work lights itself (render/wall.mjs SELF_LIT): the glow
   of its own bulb on the wall, centred on the bulb (--gy % down the work)
   and thrown the way the bulb faces -- up the wall from a trumpet's bell,
   down and around from the bulb in a trombone's bell */
html[data-store] .wglow{display:none}
html[data-store] body.wall .wglow{
  display:block;position:absolute;pointer-events:none;z-index:0;mix-blend-mode:screen;
  left:calc((var(--x) + var(--w) / 2 - 100) * var(--cm));width:calc(200 * var(--cm));
  bottom:calc((var(--y) + var(--floor) + var(--h) * (1 - var(--gy) / 100) - 100) * var(--cm));
  height:calc(200 * var(--cm))}
/* every ellipse ends inside the box (centre +/- radius stays within 0..100%),
   so the glow fades to nothing before the box's edge -- no visible rectangle */
html[data-store] body.wall .wglow.is-up{
  background:
    radial-gradient(ellipse 8% 6% at 50% 50%, rgba(255,242,210,1), rgba(255,220,160,.6) 55%, rgba(255,205,140,0) 100%),
    radial-gradient(ellipse 26% 34% at 50% 36%, rgba(255,208,140,.85), rgba(255,196,120,.40) 40%, rgba(255,190,110,.10) 75%, rgba(255,190,110,0) 100%),
    radial-gradient(ellipse 40% 40% at 50% 48%, rgba(255,200,130,.40), rgba(255,190,110,0) 100%)}
html[data-store] body.wall .wglow.is-down{
  background:
    radial-gradient(ellipse 6% 5% at 50% 50%, rgba(255,244,215,1), rgba(255,220,160,.6) 55%, rgba(255,205,140,0) 100%),
    radial-gradient(ellipse 24% 32% at 50% 64%, rgba(255,208,140,.80), rgba(255,196,120,.36) 40%, rgba(255,190,110,.08) 75%, rgba(255,190,110,0) 100%),
    radial-gradient(ellipse 38% 38% at 50% 52%, rgba(255,200,130,.40), rgba(255,190,110,0) 100%)}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wglow{display:none}

/* the light ON the work: brightest at the top edge (the spot is above),
   falling off down the work, a touch of shade at the foot -- masked by the
   work's own cut-out (inline mask-image), so only the work is lit */
html[data-store] .work .wlit{display:none}
/* a wash still waiting for its mask (render/wall.mjs litLayer): hidden until
   wall.js hangs one on it, because unmasked it would lay the spot's warm
   light over the transparent air around a cut-out as well as over the work */
html[data-store] body.wall .work .wlit[data-m]{display:none}
html[data-store] body.wall .work .wlit{
  display:block;position:absolute;inset:0;z-index:1;pointer-events:none;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-position:center bottom;mask-position:center bottom;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  mix-blend-mode:soft-light;
  background:linear-gradient(to bottom, rgba(255,240,210,.95) 0, rgba(255,236,200,.55) 28%, rgba(255,236,200,.18) 60%, rgba(0,0,0,.30) 100%)}
html[data-store] body.wall .work .wlit::after{
  content:"";position:absolute;inset:0;mix-blend-mode:screen;
  background:radial-gradient(ellipse 70% 38% at 50% 0%, rgba(255,236,200,.26), rgba(255,236,200,0) 100%)}

/* the works: one light, above and in front -- a painting's shadow falls a
   little below it, close and soft, with a hard contact line at the edge */
html[data-store] body.wall .work{z-index:1}

html[data-store] body.wall .work img{
  filter:drop-shadow(0 calc(1.2 * var(--cm)) calc(1.8 * var(--cm)) rgba(14,10,6,.34))
         drop-shadow(0 calc(.2 * var(--cm)) calc(.3 * var(--cm)) rgba(14,10,6,.30))}
html[data-store] body.wall .work.is-sculpture img{
  filter:drop-shadow(0 calc(.3 * var(--cm)) calc(.5 * var(--cm)) rgba(14,10,6,.30))}
/* A FRAME, for the seven works Ilai named (render/wall.mjs FRAMED). Drawn,
   not baked into the PNG, and BORDER-BOX: the moulding eats into the
   admin's box instead of growing it, so a framed work hangs at exactly the
   size and place on the wall it already had.
   Four border colours, not one: the browser mitres a border's corners
   diagonally, so four tones make a real moulding with the light coming from
   above and a little to the left -- lit along the top, deepest along the
   bottom. The inset line is the rebate the picture sits behind; the outer
   shadow is the frame's own, standing off the plaster. */
html[data-store] body.wall .work.is-framed picture{
  box-sizing:border-box;
  border-style:solid;
  border-width:calc(2.2 * var(--cm));
  border-color:#6d5c47 #4f4234 #3a3127 #5b4c3b;
  box-shadow:
    inset 0 0 0 calc(.35 * var(--cm)) rgba(16,11,6,.50),
    0 calc(1.2 * var(--cm)) calc(1.9 * var(--cm)) rgba(14,10,6,.34),
    0 calc(.2 * var(--cm)) calc(.3 * var(--cm)) rgba(14,10,6,.30)}
/* the canvas inside a frame has no shadow of its own -- the frame carries it */
html[data-store] body.wall .work.is-framed img{filter:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .work.is-framed picture{
  border-color:#fff;box-shadow:none}

/* the standing piece's own shadow on the wall behind it.
   `.is-sculpture img.wsh`, NOT `.work .wsh` (fixed 2026-09-20): .wsh IS an
   img, so the two rules just above -- which are also `... .work img` -- were
   more specific and won the `filter`. The shadow never got its brightness(0)
   at all: what stood behind every sculpture was its own PHOTOGRAPH, blurred
   and faint, which is exactly the "colour in the shadow" Ilai saw. Any rule
   that dresses .wsh has to out-specify `.work.is-sculpture img`. */
html[data-store] body.wall .work.is-sculpture img.wsh{
  display:block;position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1;
  object-fit:contain;object-position:center bottom;pointer-events:none;
  filter:brightness(0) blur(calc(1.1 * var(--cm)));opacity:.30;
  transform:translate(calc(2.2 * var(--cm)), calc(1.4 * var(--cm))) scale(1.02);transform-origin:50% 100%}

/* STANDING IN THE ROOM -- IN REAL 3D (Ilai, 2026-09-20: first "the stands
   look stuck on the wall", then "they look distorted"). The wall surface is
   the camera: perspective 300 cm, its origin at eye height -- 150 cm above
   the floor line -- and, as the wall pans, at the middle of the screen
   (wall.js writes it as perspective-origin, never through an inherited
   custom property -- that restyled the whole wall every frame). A plinth is a real box (.furn, preserve-3d, five
   faces) pushed out from the wall by its --zc and turned by its --turn
   (render/wall.mjs stance()); the browser projects it, so it drops onto the
   floor, grows as it comes forward, shows its top and the side it is turned
   to, and its perspective shifts as you walk along the wall. A piece on a
   plinth, or on the floor, is pushed out by the same --zc. Nothing is faked
   in 2D any more, so nothing distorts. */
html[data-store] body.wall .wsurf{
  perspective:calc(300 * var(--cm));
  perspective-origin:var(--px, 50vw) calc(100% - (var(--floor) + 150) * var(--cm))}
html[data-store] body.wall .furn{
  /* z 2: a stand stands IN FRONT of the wall, so it must cover a painting
     it overlaps once the camera has spread it (Ilai's screenshot: a tiger
     painted over a plinth) */
  z-index:2;background:none;border:0;border-radius:0;box-shadow:none;
  transform-style:preserve-3d;
  transform:translateZ(calc(var(--zc) * var(--cm))) rotateY(calc(var(--turn) * 1deg))}
html[data-store] body.wall .work.is-sculpture{
  z-index:3;
  transform:translateZ(calc(var(--zc) * var(--cm))) translateY(calc(var(--sink, 0) * var(--cm)))}
/* a hand tilt (render/wall.mjs ADJUST) turns the piece about its own base */
html[data-store] body.wall .work.is-sculpture picture,
html[data-store] body.wall .work.is-sculpture .wlit{
  transform:rotate(calc(var(--tilt, 0) * 1deg));transform-origin:50% 100%}

/* THE STANDS' MATERIAL AND LIGHT (Ilai: "they look poor next to the wood
   and the wall -- the bottom is blurred and black"). Remade after looking
   at them closely, round by round:
   * the floor shadow was rotated about its own middle, 20 % of the stand's
     depth ABOVE the floor, so it hung in the air across the stand's foot as
     a dark blur; it now lies exactly on the floor (centred on the floor
     line), a crisp contact line plus a soft pool reaching back to the wall
   * the blurred shade on the wall behind is gone (a smudge, not a shadow)
   * the faces carry the wall's own fine plaster grain, so they are made of
     the same world as the wall; matte warm white, the top lit brightest by
     the spot, the front falling off gently toward the foot, the sides in
     shade, a hairline of light on the top edges
   Two kinds (render/wall.mjs stance()): .is-box, a square plinth, and
   .is-drum, a round column. */

/* THE MATERIALS (Ilai, 2026-09-20: "more variations of textures of the
   stands so it will look more realistic, right now it's completely white").
   render/wall.mjs draws one slot per stand from its slug and writes the four
   face colours inline -- --mf front, --mt top, --ml left, --mr right, all
   derived from one base so a stand is one object in one material. It also
   puts a kind class on the stand, and the only thing a kind adds here is its
   own grain over the shared plaster: --mgrain, a layer in every face's
   stack, `none` unless a material fills it in. */
html[data-store] body.wall .furn{
  --mf:#cfc9bf;--mt:#e2ddd4;--ml:#bdb6ab;--mr:#b0a99d;
  --mgrain:none}
/* oak: boards about 19 cm wide, the grain running the height of the block.
   Soft, and only just there -- at 12 cm with the tones it had first, the
   repeat read as corduroy rather than as wood. A board's edge is the only
   line with any weight; everything between it is a breath. */
html[data-store] body.wall .furn.is-mo{
  --mgrain:repeating-linear-gradient(90deg,
    rgba(72,44,18,.13) 0,
    rgba(72,44,18,.02) calc(1 * var(--cm)),
    rgba(255,240,216,.05) calc(6 * var(--cm)),
    rgba(72,44,18,.05) calc(13 * var(--cm)),
    rgba(72,44,18,.13) calc(19 * var(--cm)))}
/* concrete and stone: a wide, soft cloud so the face is never one flat tone */
html[data-store] body.wall .furn.is-mc,
html[data-store] body.wall .furn.is-mg{
  --mgrain:radial-gradient(ellipse 60% 40% at 30% 20%, rgba(255,255,255,.10), rgba(255,255,255,0) 70%),
           radial-gradient(ellipse 50% 45% at 78% 72%, rgba(20,18,14,.09), rgba(20,18,14,0) 70%)}
/* charcoal: a satin sheen down the face, the way painted MDF catches a spot */
html[data-store] body.wall .furn.is-mk{
  --mgrain:linear-gradient(to right, rgba(255,248,236,0) 12%, rgba(255,248,236,.13) 38%, rgba(255,248,236,0) 62%)}

html[data-store] body.wall .furn i{
  display:block;position:absolute;margin:0;box-shadow:none;clip-path:none;
  -webkit-backface-visibility:hidden;backface-visibility:hidden}
html[data-store] body.wall .furn .fw{display:none}
/* the box */
html[data-store] body.wall .furn .ff{
  left:0;top:0;width:100%;height:100%;
  transform:translateZ(calc(var(--d) * .5 * var(--cm)));
  background:
    linear-gradient(to bottom, rgba(255,250,240,.40) 0, rgba(255,250,240,0) 5%),
    linear-gradient(to bottom, rgba(30,22,14,0) 0, rgba(30,22,14,.05) 50%, rgba(30,22,14,.14) 94%, rgba(30,22,14,.34) 100%),
    linear-gradient(to right, rgba(255,248,236,.10), rgba(255,248,236,0) 60%),
    var(--mgrain),
    url("room/grain.webp") 0 0 / calc(40 * var(--cm)) calc(40 * var(--cm)),
    var(--mf);
  box-shadow:inset 0 1px 0 rgba(255,252,246,.6)}
html[data-store] body.wall .furn .ft{
  left:0;top:0;width:100%;height:calc(var(--d) * var(--cm));margin-top:calc(var(--d) * -.5 * var(--cm));
  transform:rotateX(90deg);
  background:
    linear-gradient(to bottom, rgba(60,45,30,.12), rgba(60,45,30,0) 70%),
    var(--mgrain),
    url("room/grain.webp") 0 0 / calc(40 * var(--cm)) calc(40 * var(--cm)),
    var(--mt)}
html[data-store] body.wall .furn .fl,
html[data-store] body.wall .furn .fr{
  top:0;height:100%;left:50%;width:calc(var(--d) * var(--cm));margin-left:calc(var(--d) * -.5 * var(--cm))}
html[data-store] body.wall .furn .fl{
  transform:rotateY(-90deg) translateZ(calc(var(--w) * .5 * var(--cm)));
  background:
    linear-gradient(to bottom, rgba(30,22,14,0) 30%, rgba(30,22,14,.16) 94%, rgba(30,22,14,.34) 100%),
    var(--mgrain),
    url("room/grain.webp") 0 0 / calc(40 * var(--cm)) calc(40 * var(--cm)),
    var(--ml)}
html[data-store] body.wall .furn .fr{
  transform:rotateY(90deg) translateZ(calc(var(--w) * .5 * var(--cm)));
  background:
    linear-gradient(to bottom, rgba(30,22,14,0) 30%, rgba(30,22,14,.18) 94%, rgba(30,22,14,.36) 100%),
    var(--mgrain),
    url("room/grain.webp") 0 0 / calc(40 * var(--cm)) calc(40 * var(--cm)),
    var(--mr)}
/* the floor shadow, lying on the floor (centred ON the floor line, so
   rotating it flat lays it on the wood). It is larger than the stand's
   footprint and dark out to the footprint's edge, then fades: the stand
   hides the middle, and what shows is the soft grey rim around its foot
   that a real plinth has. (A blurred box-shadow does not render on a face
   turned in 3D -- it came out as a hairline.) */
html[data-store] body.wall .furn .fs{
  left:-40%;width:180%;top:100%;
  height:calc(var(--d) * 2.2 * var(--cm));margin-top:calc(var(--d) * -1.1 * var(--cm));
  transform:rotateX(90deg);
  -webkit-backface-visibility:visible;backface-visibility:visible;
  /* seen nearly edge-on, only the ring just around the foot shows: keep it
     strong past the footprint (which ends at ~55 %) and fade only outside */
  background:radial-gradient(closest-side, rgba(10,6,2,.60) 58%, rgba(10,6,2,.34) 68%, rgba(10,6,2,.13) 82%, rgba(10,6,2,0) 100%)}
/* the drum's floor shadow is round and, being round, shows all the way
   round: lighter than the box's, so it reads as shade, not a black pool */
html[data-store] body.wall .furn.is-drum .fs{
  border-radius:50%;
  background:radial-gradient(closest-side, rgba(10,6,2,.62) 50%, rgba(10,6,2,.30) 64%, rgba(10,6,2,.10) 80%, rgba(10,6,2,0) 100%)}
/* the drum is a CYLINDER: DRUM_FACES narrow faces set around the circle
   (render/wall.mjs gives each its width --fw and its own shade), with an
   ellipse for its top. Body and top are the same circle, so the top no
   longer overhangs like a cap, and the faces at different depths curve the
   foot by themselves. */
/* the core, shaded across the drum by render/wall.mjs: it fills the
   hairlines between faces and the little notches their feet leave, because
   each face's foot lands at its own depth */
html[data-store] body.wall .furn.is-drum .fk{
  position:absolute;left:0;top:0;width:100%;height:100%}
html[data-store] body.wall .furn.is-drum .fc{
  position:absolute;top:0;height:100%;left:50%;
  width:calc(var(--fw) * var(--cm));margin-left:calc(var(--fw) * -.5 * var(--cm));
  transform:rotateY(calc(var(--i) * 20deg)) translateZ(calc(var(--d) * .5 * var(--cm)))}
/* NO semi-transparent overlay on a face: neighbouring faces overlap a
   little so no hairline of wall shows between them, and a translucent layer
   would double in that overlap and draw a seam down the drum. Each face
   carries only its own opaque tone (render/wall.mjs), so the cylinder is
   one smooth surface. */
html[data-store] body.wall .furn.is-drum .ft{
  border-radius:50%;
  background:
    radial-gradient(ellipse 72% 72% at 46% 46%, rgba(255,252,246,.5), rgba(255,252,246,0) 80%),
    var(--mgrain),
    url("room/grain.webp") 0 0 / calc(40 * var(--cm)) calc(40 * var(--cm)),
    var(--mt);
  box-shadow:inset 0 0 0 1px rgba(60,45,30,.07)}
/* the drum's floor shadow is round, and being round it shows all the way
   round: lighter than the box's */
html[data-store] body.wall .furn.is-drum .fs{
  border-radius:50%;
  background:radial-gradient(closest-side, rgba(10,6,2,.46) 50%, rgba(10,6,2,.22) 64%, rgba(10,6,2,.07) 80%, rgba(10,6,2,0) 100%)}
/* a shelf: the same box, 4 cm high */
html[data-store] body.wall .furn.is-shelf .ff{background:linear-gradient(to bottom, var(--mt), var(--mf))}

/* a figure standing on the floor: its shadow pooled at its feet on the wood */
html[data-store] body.wall .work.is-sculpture::after{
  left:-6%;right:-6%;bottom:calc(-1.6 * var(--cm));height:calc(4.4 * var(--cm));
  background:radial-gradient(ellipse 50% 50% at 50% 55%, rgba(8,5,2,.38), rgba(8,5,2,.14) 50%, rgba(8,5,2,0) 100%)}
/* its shadow on the wall 35 cm behind it: the light is above, so the
   shadow falls a little LOWER than the piece and to the side, and it
   carries the piece's own tilt.
   DARK AND COLOURLESS (Ilai, 2026-09-20: "remove the colour from the
   shadow, make it more dark and without colours shadow"). The colour was
   the specificity bug fixed above -- the shadow was the photo itself. With
   brightness(0) finally biting it is black, and a shade heavier than the
   .16 it was asked for when it was only ever a faint tint, blurred tighter
   so it reads as a shadow with an edge rather than a smudge. */
html[data-store] body.wall .work.is-sculpture img.wsh{
  filter:brightness(0) blur(calc(1.8 * var(--cm)));opacity:.30;
  transform:translate(calc(3 * var(--cm)), calc(1.4 * var(--cm)))
            rotate(calc(var(--tilt, 0) * 1deg)) scale(.97)}

/* the skirting: black (Ilai), a satin board 8 cm high -- a lit top edge,
   a soft sheen, and its shadow on the floor */
html[data-store] body.wall .wbase{
  bottom:calc(var(--floor) * var(--cm));height:calc(8 * var(--cm));z-index:0;
  background:linear-gradient(to bottom, #3a3835 0, #1f1e1c 12%, #161514 60%, #0d0c0b 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14), 0 calc(.6 * var(--cm)) calc(1.4 * var(--cm)) rgba(8,5,2,.40)}

/* the floor ------------------------------------------------------------------- */
html[data-store] body.wall .wroom{
  display:block;position:absolute;left:0;right:0;bottom:0;z-index:0;
  height:calc(var(--floor) * var(--cm));overflow:hidden;
  perspective:calc(300 * var(--cm));perspective-origin:50% calc(-150 * var(--cm));
  background:#6d5238}
html[data-store] body.wall .wplane{
  position:absolute;top:0;left:-3000px;width:calc(100% + 6000px);height:calc(400 * var(--cm));
  transform-origin:50% 0;transform:rotateX(90deg);
  background:#9c7250 url("room/oak-v1.jpg") 3000px 0 / calc(120 * var(--cm)) calc(240 * var(--cm))}
/* the floor's light: a dark line where it meets the skirting (no light
   reaches the corner), then the ceiling light's sheen on the lacquer --
   brightest a little way out, where a real floor mirrors the lit wall --
   and falling off toward the viewer. A second layer warms the sheen. */
html[data-store] body.wall .wroom::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to bottom, rgba(8,5,2,.62) 0, rgba(8,5,2,.22) 5%, rgba(8,5,2,0) 14%, rgba(8,5,2,0) 60%, rgba(8,5,2,.30) 100%),
    linear-gradient(to bottom, rgba(255,236,206,0) 8%, rgba(255,236,206,.20) 24%, rgba(255,236,206,.06) 50%, rgba(255,236,206,0) 70%)}

/* the stage lets the floor show through its bottom strip */
html[data-store] body.wall .wstage{position:relative;z-index:1}

/* ---- accessibility ------------------------------------------------------------
   Doubled attribute, as everywhere on this site. The wall goes black, the
   floor white, every work gets a white edge, the panel is black on white. */
html[data-a11y-contrast][data-a11y-contrast] body.wall .wsurf{background:#000}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wlight{display:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wfloor{background:#fff;box-shadow:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wbase{background:#000;box-shadow:0 -2px 0 #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .work img{filter:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .work{outline:2px solid #fff;outline-offset:2px}
html[data-a11y-contrast][data-a11y-contrast] body.wall .work.is-sculpture::after{display:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .furn,
html[data-a11y-contrast][data-a11y-contrast] body.wall .furn i{background:#000;border-color:#fff;box-shadow:inset 0 0 0 2px #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .whint{background:#000;color:#fff;box-shadow:inset 0 0 0 2px #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wp{
  background:#000;color:#fff;box-shadow:inset 0 0 0 2px #fff;
  -webkit-backdrop-filter:none;backdrop-filter:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpblurb,
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpx{color:#fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpx{background:#000;box-shadow:inset 0 0 0 2px #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpact .btn{background:#000;color:#fff;box-shadow:inset 0 0 0 2px #fff;
  -webkit-backdrop-filter:none;backdrop-filter:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpx{background:#000;color:#fff;box-shadow:inset 0 0 0 2px #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpask{background:#000;color:#fff;box-shadow:inset 0 0 0 2px #fff}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wpname::after{background:#fff}
/* in contrast mode the copyright lies on the floor, which is WHITE here --
   except where a plinth's floor shadow is painted solid black across it.
   Neither ink is safe on its own, so the line takes the same plate every
   other piece of chrome takes in this mode. */
html[data-a11y-contrast][data-a11y-contrast] body.wall .copy{
  color:#fff;text-shadow:none;background:#000;box-shadow:inset 0 0 0 2px #fff;
  padding:2px 7px;border-radius:2px}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wbar{background:#000;box-shadow:inset 0 0 0 2px #fff;-webkit-backdrop-filter:none;backdrop-filter:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wbar-track{background:#555}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wbar-thumb{background:#fff}
/* in contrast mode the room is switched off: black wall, white floor, no light play */
html[data-a11y-contrast][data-a11y-contrast] body.wall .wwall,
html[data-a11y-contrast][data-a11y-contrast] body.wall .wspot,
html[data-a11y-contrast][data-a11y-contrast] body.wall .wrail,
html[data-a11y-contrast][data-a11y-contrast] body.wall .wroom{display:none}
/* the same `.is-sculpture img.wsh` the room rules use, for the same reason:
   a plain `.work .wsh` no longer out-specifies them, so it could not switch
   the shadow off here */
html[data-a11y-contrast][data-a11y-contrast] body.wall .work.is-sculpture img.wsh{display:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .work .wlit{display:none}
html[data-a11y-contrast][data-a11y-contrast] body.wall .wfloor{display:block}
html[data-a11y-links] .work{outline:2px solid var(--accent);outline-offset:2px}
html[data-a11y-motion] .work img{transition:none}
html[data-a11y-motion] .wbar-track{transition:none}

/* ============================================================================
   THE PHONE. LAST IN THE FILE, ON PURPOSE.
   The bar is the walk's: 12+46+14 above the menu, two rows of 48 + 10, 14
   below -- about 190px, which is the fallback; wall.js measures the truth.
   240 cm of the 300 are shown, so hang heights never change and a 30 cm work
   is 82px on a 390x844 phone; the crop is empty plaster at the top.
   ========================================================================== */
@media (max-width: 900px){
  html[data-store] body.wall main{--wall-cm:240;--wallh:calc(100vh - 190px)}
  html[data-store] .wtop{padding:8px 16px}
  html[data-store] .whint{bottom:calc(var(--floor) * var(--cm) + 10px);font-size:calc(12px * var(--a11y-scale))}
  /* THE CARD BECOMES A SHEET. A side card cannot work at 390 px, so on a
     phone it sits at the bottom, still rounded on every corner and still
     floating clear of the edges, and it is kept SHORT (52 vh) for the same
     reason the desktop card moved: what is above it has to stay visible.
     wall.js centres the work in the space left over. */
  html[data-store] .wp{
    top:auto;transform:none;
    left:10px;right:10px;width:auto;min-width:0;
    bottom:calc(10px + env(safe-area-inset-bottom));
    max-height:52vh;max-height:52dvh;
    border-radius:24px;
    padding:22px 20px 18px;
    box-shadow:0 -10px 44px rgba(18,12,6,.30), inset 0 0 0 .5px rgba(255,255,255,.75)}
  html[data-store] .wp.is-start{left:10px;right:10px}
  html[data-store] .wpx{top:12px}
  html[data-store] .wpname{font-size:calc(clamp(21px, 5.6vw, 26px) * var(--a11y-scale))}
  html[data-store] .wpact{margin-top:0}
  /* the sheet does take the bottom of the screen, so here the scrim is worth
     having: it says the wall is behind, and it is light enough to see through */
  html[data-store] .wscrim{background:rgba(25,23,20,.22)}

  /* the room on a phone: 260 cm on screen, 26 of them floor (restated after
     this block's 240 above) */
  html[data-store] body.wall main{--wall-cm:270;--floor:34}
  /* A PHONE SHOWS 270 cm OF A 324 cm WALL, so the top of the wall is cropped
     and a tall painting hung at eye level ends up under the category chips.
     render/wall.mjs's ADJUST gives such a work a --down, and here -- and only
     here -- every work measures from --y less that drop. The work's spot
     carries the same --down, so the light, the beam and the pool come with
     it; a work without one is unmoved (--down falls back to 0). */
  html[data-store] .work,
  html[data-store] .wspot{--yy:calc(var(--y) - var(--down, 0))}
  /* the copyright stays up on the wall above the skirting: the floor down
     here belongs to the position bar, which is only 32px clear of the edge */
  html[data-store] body.wall .copy{
    inset-inline-start:10px;color:rgba(25,23,20,.62);text-shadow:none}
  html[data-store] body.wall main > .copy{bottom:calc((var(--floor) + 6) * var(--cm) + 4px)}
}
/* a short phone: show less wall so the works stay big enough to tap */
@media (max-width: 900px) and (max-height: 700px){
  html[data-store] body.wall main{--wall-cm:220}
}
/* a phone turned sideways: the whole wall height fits, bar and all */
@media (max-width: 900px) and (max-height: 560px){
  html[data-store] body.wall main{--wall-cm:270}
  html[data-store] .wp{max-height:86vh}
}
/* a big touch target for a small work without moving it */
@media (pointer: coarse){
  html[data-store] .work::before{content:"";position:absolute;inset:min(0px, calc(50% - 22px))}
}
