/* ---- typefaces ----
   Self-hosted rather than fetched from fonts.googleapis.com. That request was
   render-blocking on a third origin — about 1.4s before the font files even
   started — and it disclosed every visitor's IP address to Google. These are
   the same faces, latin subset only, which is everything the site sets: the
   fallbacks below take anything outside it.

   Archivo and Bodoni Moda are variable fonts, so one file serves several
   weights. The upstream version is in each filename, so updating a face
   changes its URL and no one is left holding a stale one.
   Licences: public/fonts/LICENSE.md */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/archivo-v25-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/archivo-v25-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/archivo-v25-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bodoni-moda-v28-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/bodoni-moda-v28-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-v20-latin-400.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-v20-latin-500.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* art.klaushofrichter.net — lobby and rooms
   Gallery night: a single committed dark world, painted explicitly.
   Nothing the pointer drives carries a CSS transition; those values are
   driven by springs in app.js instead. */
:root {
  --ink:#0B1017; --line:#24303F;
  --bone:#EDE7DA; --mute:#8B95A6; --brass:#C9A227;
  --display:'Bodoni Moda',Didot,'Times New Roman',serif;
  --body:'Archivo',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,Menlo,monospace;
}
* { box-sizing:border-box; }
html, body { height:100%; }
body {
  margin:0; background:var(--ink); color:var(--bone);
  font-family:var(--body); font-size:16px; line-height:1.6;
  -webkit-font-smoothing:antialiased; overflow:hidden;
}
:focus-visible { outline:2px solid var(--brass); outline-offset:2px; }
@media (prefers-reduced-motion:reduce) { * { animation-duration:.01ms !important; transition-duration:.01ms !important; } }

#app { position:fixed; inset:0; overflow:hidden; }
.screen { position:absolute; inset:0; }
.screen[hidden] { display:none; }
.screen:focus { outline:none; }

/* ---- the rail ---- */
.rail { position:absolute; inset:0; touch-action:none; cursor:grab; }
.rail.grabbing { cursor:grabbing; }
.rail > .slide { position:absolute; inset:0; will-change:transform; backface-visibility:hidden; }

/* ---- LOBBY ---- */
.lpanel { position:relative; height:100%; overflow:hidden; display:flex; align-items:center; --mx:50%; --my:50%; }
.lpanel .bg { position:absolute; inset:0; background-size:cover; background-position:center;
  transform:scale(1.14); will-change:transform; filter:contrast(1.06) saturate(1.02);
  opacity:0; transition:opacity .6s ease; }
.lpanel .bg.in, .lpanel.nocover .bg { opacity:1; }
/* The spotlight takes shade away rather than adding light.
   An earlier version laid a pale wash over the cover and lifted the whole
   panel with it: the blacks went grey and the picture read flat. So the
   cover is now shown at full brightness and the scrim is a single dark veil
   over it, thinnest under the pointer and thickening outwards. Black at a
   given alpha scales every channel by the same factor, so the picture keeps
   its contrast wherever the veil is thin, and the pointer reveals rather
   than illuminates. The veil warms very slightly towards the middle — a
   lamp is warmer than the shadow it leaves — but never lightens.
   The left band stays: it is what the caption is read against. */
.lpanel .scrim { position:absolute; inset:0; pointer-events:none;
  background:
    radial-gradient(62% 76% at var(--mx) var(--my),
      rgba(18,14,8,.07), rgba(9,10,13,.50) 52%, rgba(6,9,14,.70) 100%),
    linear-gradient(to right, rgba(6,9,14,.84), rgba(6,9,14,.10) 58%, rgba(6,9,14,.30)); }
.lpanel .cap { position:relative; z-index:2; padding-left:6vw; max-width:60vw;
  transition:opacity .8s ease; }
/* while the welcome card is up, the room waits its turn */
#app.greeting .lpanel .cap, #app.greeting .abody { opacity:0; }
.lpanel .cap .s { font-family:var(--mono); font-size:clamp(9px,1.35vh,12px); letter-spacing:.16em; text-transform:uppercase; color:var(--brass); display:block; margin-bottom:1.1em; }
.lpanel .cap .n { font-family:var(--display); font-weight:400; font-size:clamp(34px,9vh,76px); line-height:.98; margin:0 0 .3em; }
.lpanel .cap .b { font-size:clamp(13px,1.85vh,17px); color:#C3CAD4; margin:0 0 1.6em; max-width:34ch; }
.enter { font-family:var(--mono); font-size:clamp(10px,1.3vh,12px); letter-spacing:.16em; text-transform:uppercase;
  background:transparent; color:var(--bone); border:1px solid rgba(237,231,218,.42); border-radius:2px;
  padding:.9em 1.6em; cursor:pointer; transition:background .25s, border-color .25s, color .25s; }
.enter:hover, .enter:focus-visible { background:var(--brass); border-color:var(--brass); color:#17120A; }
/* the About room has no photograph, so it gets its own ground */
.lpanel.about .bg { background-position:100% 50%; }
.lpanel.nocover .bg { background:radial-gradient(120% 90% at 78% 30%, #1B2635, #0A0E15 70%); filter:none; transform:none; }
.lpanel.nocover .scrim { background:radial-gradient(44% 56% at var(--mx) var(--my), rgba(255,251,244,.10), rgba(255,251,244,0) 60%); }

/* ---- ABOUT ROOM ----
   One picture and no navigation inside it, so it is not built like a picture
   room: the hero fills the frame and the text sits over the empty side of it,
   with nothing to page through and no full screen to enter. */
.aboutroom { position:absolute; inset:0; overflow:hidden; display:flex; align-items:center; }
.aboutroom .bg { position:absolute; inset:0; background-size:cover; background-position:100% 0; }
.aboutroom .scrim { position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to right,
    rgba(6,9,14,.93) 0%, rgba(6,9,14,.90) 24%, rgba(6,9,14,.66) 44%,
    rgba(6,9,14,.30) 58%, rgba(6,9,14,.07) 70%, rgba(6,9,14,0) 78%); }
.aboutroom.nocover .bg { background:radial-gradient(120% 90% at 78% 30%, #1B2635, #0A0E15 70%); }
.aboutroom .abody { max-width:min(52vw, 640px); }
@media (max-width:900px) {
  /* too narrow for a column beside the picture, so the band comes up from
     the foot instead and the text sits on it */
  .aboutroom { align-items:flex-end; }
  .aboutroom .scrim { background:linear-gradient(to bottom,
    rgba(6,9,14,.16) 0%, rgba(6,9,14,.55) 18%, rgba(6,9,14,.88) 38%, rgba(6,9,14,.95) 60%); }
  .aboutroom .abody { max-width:none; padding-bottom:8vh; }
}
.abody { position:relative; z-index:2; padding:0 6vw; max-width:74vw; transition:opacity .8s ease; }
.abody .n { font-family:var(--display); font-weight:400; font-size:clamp(30px,7vh,58px); line-height:1; margin:0 0 .22em; }
.abody .r { font-family:var(--mono); font-size:clamp(9px,1.3vh,12px); letter-spacing:.16em; text-transform:uppercase; color:var(--brass); margin:0 0 1.4em; }
.abody p { font-size:clamp(13px,1.8vh,16px); color:#C3CAD4; line-height:1.68; margin:0 0 .85em; max-width:58ch; }
.abody strong { color:#fff; font-weight:600; }
.abody em { color:var(--bone); }
.abody .mail { font-family:var(--mono); font-size:clamp(11px,1.5vh,14px); color:var(--brass); text-decoration:none; border-bottom:1px solid rgba(201,162,39,.45); }
.abody .fine { font-family:var(--mono); font-size:clamp(9px,1.1vh,11px); letter-spacing:.1em; text-transform:uppercase; color:var(--mute); margin-top:1em; }
.abody .ver { display:inline-block; margin-top:2.2em; font-family:var(--mono);
  font-size:clamp(9px,1.1vh,11px); letter-spacing:.12em; color:var(--mute);
  text-decoration:none; border-bottom:1px solid transparent; transition:color .2s, border-color .2s; }
.abody .ver:hover { color:var(--brass); border-bottom-color:rgba(201,162,39,.45); }

/* ---- the welcome card ---- */
.welcome { position:absolute; inset:0; z-index:20; pointer-events:none;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:.75em; padding:0 6vw; text-align:center;
  opacity:0; transform:translateY(12px); transition:opacity .9s ease, transform 1.1s cubic-bezier(.2,0,.2,1); }
.welcome.on { opacity:1; transform:translateY(0); }
/* just enough shade under the words to read over any cover */
.welcome::before { content:''; position:absolute; inset:0;
  background:radial-gradient(58% 42% at 50% 50%, rgba(6,9,14,.74), rgba(6,9,14,.32) 55%, rgba(6,9,14,0) 78%); }
.welcome .w-from { position:relative; font-family:var(--mono); font-size:clamp(9px,1.35vh,12px);
  letter-spacing:.24em; text-transform:uppercase; color:var(--brass); }
.welcome .w-title { position:relative; font-family:var(--display); font-weight:400;
  font-size:clamp(24px,4.6vw,58px); line-height:1.06; letter-spacing:-.005em; color:var(--bone);
  text-shadow:0 2px 34px rgba(0,0,0,.75); }

/* ---- ROOM ---- */
.plate { position:absolute; inset:0; overflow:hidden; background:var(--ink); }
.plate .ambient { position:absolute; inset:-8%; background-size:cover; background-position:center;
  filter:blur(52px) saturate(1.3) brightness(.38); transform:scale(1.1); }
.plate .ambient::after { content:''; position:absolute; inset:0; background:rgba(8,12,18,.4); }
/* Contain, so nothing is ever clipped — but at full width and height, so a
   small picture scales up instead of floating in empty space. */
.plate .art { position:absolute; inset:2.2vh 2vw; width:calc(100% - 4vw); height:calc(100% - 4.4vh);
  object-fit:contain; display:block; box-shadow:0 30px 90px rgba(0,0,0,.66);
  transition:inset .5s cubic-bezier(.3,0,.2,1), width .5s cubic-bezier(.3,0,.2,1),
    height .5s cubic-bezier(.3,0,.2,1), object-position .45s cubic-bezier(.3,0,.2,1); }
.room.bare .plate .art { inset:.6vh .6vw; width:calc(100% - 1.2vw); height:calc(100% - 1.2vh); box-shadow:none; }

/* full label, shown by default in a room; click-through so it never blocks a drag */
.info { position:absolute; inset:0; z-index:6; display:flex; align-items:flex-end; pointer-events:none; transition:opacity .38s; }
.info::before { content:''; position:absolute; inset:0;
  background:linear-gradient(to top, rgba(6,9,14,.94) 4%, rgba(6,9,14,.66) 20%, rgba(6,9,14,0) 35%); }
.info .sheet { position:relative; z-index:2; width:100%; padding:0 5vw 5.5vh;
  display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:3vw; align-items:end; }
.info h2 { font-family:var(--display); font-weight:400; font-size:clamp(24px,5vh,44px); margin:0 0 .16em; line-height:1.05; }
.info .by { font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.14em; text-transform:uppercase; color:var(--brass); margin:0 0 .9em; }
.info .desc { font-size:clamp(12px,1.7vh,16px); color:#D2D8E1; line-height:1.62; margin:0; max-width:52ch; }
.info .desc strong { color:#fff; font-weight:600; }
.info .desc em { color:var(--bone); }
.info dl { margin:0 0 1em; display:grid; grid-template-columns:auto 1fr; gap:.35em 1.2em; font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); }
.info dt { color:var(--mute); text-transform:uppercase; letter-spacing:.1em; }
.info dd { margin:0; color:var(--bone); }
.info dd.includes { color:var(--brass); line-height:1.7; }
.info .buyline { display:flex; align-items:center; gap:1.2vw; flex-wrap:wrap; }
/* small icon links in the label — a permalink and a download, not a
   paragraph of URL or a button saying "download" */
.iconlink { pointer-events:auto; display:inline-flex; align-items:center; justify-content:center;
  width:2.4em; height:2.4em; margin-left:.2em; border:1px solid rgba(237,231,218,.18); border-radius:2px;
  color:rgba(237,231,218,.6); text-decoration:none; transition:color .2s, border-color .2s; }
.iconlink:hover { color:var(--brass); border-color:rgba(201,162,39,.5); }
.iconlink svg { width:1.15em; height:1.15em; display:block; fill:none; stroke:currentColor;
  stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; }
.info .price { font-family:var(--mono); font-size:clamp(16px,2.5vh,22px); color:var(--brass); letter-spacing:.04em;
  margin-right:.7em; }
.info .status { font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.16em; text-transform:uppercase;
  border:1px solid var(--line); border-radius:100px; padding:.4em 1em; color:var(--mute); }
.info .status.sold { border-color:rgba(201,162,39,.42); color:var(--brass); }
.info .status.pending { pointer-events:auto; text-decoration:none;
  border-color:rgba(201,162,39,.5); color:var(--brass); transition:background .2s, color .2s; }
.info .status.pending:hover { background:var(--brass); color:#17120A; }
.buy { pointer-events:auto; display:inline-block; text-decoration:none;
  font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.16em; text-transform:uppercase;
  background:var(--brass); color:#17120A; border:0; border-radius:2px; padding:.9em 1.4em; cursor:pointer; transition:background .2s; }
.buy:hover { background:#E0B62D; }

/* the limited overlay — title and date, toggled with Space */
.mini { position:absolute; left:0; bottom:0; z-index:7; pointer-events:none;
  font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.15em; text-transform:uppercase;
  color:rgba(237,231,218,.94); text-shadow:0 1px 10px rgba(0,0,0,.8);
  /* padding carries the shade, the negative margin keeps the text where it
     was, so the pool grows around the caption instead of moving it */
  padding:6em 16em 5vh 4vw; margin:0;
  background:radial-gradient(78% 108% at 18% 78%,
    rgba(6,9,14,.92) 0%, rgba(6,9,14,.74) 26%, rgba(6,9,14,.34) 48%, rgba(6,9,14,.08) 68%, rgba(6,9,14,0) 84%);
  opacity:0; transform:translateY(6px); transition:opacity .3s, transform .3s; }
.mini.on { opacity:1; transform:translateY(0); }
.mini b { font-family:var(--display); font-weight:400; font-size:clamp(18px,3vh,28px); letter-spacing:.005em;
  text-transform:none; display:block; margin-bottom:.25em; color:var(--bone); }

.chrome { position:absolute; z-index:8; font-family:var(--mono); font-size:clamp(9px,1.25vh,12px);
  letter-spacing:.13em; text-transform:uppercase; color:rgba(237,231,218,.74);
  background:rgba(9,13,20,.44); -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  border:1px solid rgba(237,231,218,.13); border-radius:2px; padding:.7em 1em; cursor:pointer;
  text-decoration:none; transition:color .25s,border-color .25s,opacity .38s; }
.chrome:hover { color:var(--brass); border-color:rgba(201,162,39,.55); }
/* Clear of the Demo ribbon, which crosses this corner on every page, rather
   than on top of it: #app is position:fixed and so opens a stacking context,
   which traps this button's z-index inside it — it can never paint above a
   sibling of #app however high the number goes, and lifting #app instead
   would bury the ribbon under the whole gallery. A fixed offset because the
   ribbon is a fixed size too, so the gap should not breathe with the window. */
.c-tr { top:170px; right:3vw; }
@media (max-width: 720px) { .c-tr { top:124px; } }

/* The site shows prices, offers a hold and has an enquiry button, and none
   of it works yet. A corner ribbon rather than a discreet chip: someone
   arriving on a purchase page from a link should not have to look for this.
   It is the one thing on the site allowed to be loud — bone against the ink
   everything else is drawn in.

   Clipped by a square at the corner, so the band's ends are cut off by the
   edges of the page and it reads as a ribbon laid over the corner rather
   than a rectangle floating near it. Deaf to the pointer, so it can never
   swallow a click meant for the picture behind it. */
.demobadge { position:fixed; top:0; right:0; width:190px; height:190px;
  overflow:hidden; pointer-events:none; z-index:30; }
/* Far enough out from the corner that the band is at full width where the
   word sits — nearer in, the clipped tip squeezes it. */
.demobadge span { position:absolute; top:52px; right:-58px; width:250px;
  transform:rotate(45deg); display:block; text-align:center; padding:.85em 0;
  background:var(--bone); color:var(--ink);
  font-family:var(--mono); font-size:13px; font-weight:500;
  letter-spacing:.34em; text-indent:.34em; text-transform:uppercase;
  box-shadow:0 8px 26px rgba(0,0,0,.5); }
@media (max-width: 720px) {
  .demobadge { width:140px; height:140px; }
  .demobadge span { top:38px; right:-52px; width:190px; font-size:11px; letter-spacing:.24em;
    text-indent:.24em; padding:.7em 0; }
}
.chrome.icon { padding:.72em; line-height:0; }
.chrome.icon svg { width:1.15em; height:1.15em; display:block; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }
.navstack { position:absolute; top:3.4vh; left:3vw; z-index:8;
  display:flex; flex-direction:column; align-items:flex-start; gap:8px; }
.navstack .chrome { position:static; }
@media (hover:hover) { #app:not(:hover) .screen:not(.bare) .fade-idle { opacity:.3; } }

.dots { position:absolute; right:2.6vw; top:50%; transform:translateY(-50%); z-index:7; display:flex; flex-direction:column; gap:1.4vh; }
.dots i { width:6px; height:6px; border-radius:50%; background:rgba(237,231,218,.28); cursor:pointer; transition:background .3s, transform .3s; }
.dots i.on { background:var(--brass); transform:scale(1.6); }
.count { position:absolute; right:3vw; bottom:5vh; z-index:7; pointer-events:none;
  font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.16em; color:rgba(237,231,218,.42); }
.count b { color:var(--brass); font-weight:400; }


/* ---- THE SECOND AXIS ----
   Up and down move between works; left and right move around one work, and
   only for a work that has more than one photograph. Both are hidden
   outright otherwise (the element carries `hidden`), so nothing suggests a
   picture has more to show when it does not.

   Deliberately still there in `bare`, unlike the rest of the chrome: full
   screen is exactly where someone reads brushwork, so taking the way through
   the close-ups away at that moment would be backwards. */
.viewnav { position:absolute; top:50%; transform:translateY(-50%); z-index:8;
  width:2.6em; height:2.6em; display:flex; align-items:center; justify-content:center;
  font-family:var(--display); font-size:clamp(15px,2.1vh,21px); line-height:1;
  color:rgba(237,231,218,.62); background:rgba(9,13,20,.4);
  -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  border:1px solid rgba(237,231,218,.13); border-radius:50%; cursor:pointer;
  padding:0 0 .12em; transition:color .25s, border-color .25s, opacity .38s; }
.viewnav:hover { color:var(--brass); border-color:rgba(201,162,39,.55); }
/* `display:flex` above outranks the `display:none` a browser gives [hidden],
   so without this the arrows stay on screen for every work that has nothing
   behind them. */
.viewnav[hidden] { display:none; }

/* The arrows announce themselves the moment they appear, then get out of the
   way. A picture with more to show is the exception here rather than the
   rule, so the arrows arriving is news — but only the first time: paging from
   one work with views to another never hides them, and a control that lit up
   on every step would be a nag rather than a hint. Ends on exactly the
   resting values above, so there is no jump when the animation lets go.
   The global prefers-reduced-motion rule collapses this to nothing. */
@keyframes viewnav-arriving {
  0%   { background:#E8912A; border-color:#F2B23F; color:#0B1017;
         box-shadow:0 0 0 7px rgba(232,145,42,.30); }
  55%  { background:#E8912A; border-color:#F2B23F; color:#0B1017;
         box-shadow:0 0 0 3px rgba(232,145,42,.14); }
  100% { background:rgba(9,13,20,.4); border-color:rgba(237,231,218,.13);
         color:rgba(237,231,218,.62); box-shadow:0 0 0 0 rgba(232,145,42,0); }
}
.viewnav.arriving { animation:viewnav-arriving 1s ease-out both; }
.viewnav.prev { left:2.6vw; }
.viewnav.next { right:2.6vw; }
/* The dots own the right edge at this height, so the forward arrow steps in
   past them rather than sitting on top. */
.room .viewnav.next { right:calc(2.6vw + 22px); }

/* Above the picture, centred, where a wall label would be. The bottom of
   the screen is spoken for from both sides — the description on the left,
   the price and the counter on the right — and the top is empty in both the
   full state and `bare`. */
.viewcap { position:absolute; top:3.4vh; left:50%; transform:translateX(-50%);
  z-index:7; pointer-events:none; max-width:44vw; text-align:center;
  font-family:var(--mono); font-size:clamp(9px,1.25vh,12px); letter-spacing:.14em;
  color:rgba(237,231,218,.62);
  /* The same backing the arrows carry, and for a reason they do not have: in
     full screen this sits on the picture rather than beside it, and a pale
     one left it unreadable. */
  background:rgba(9,13,20,.4); -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  border-radius:2px; padding:.5em .9em; }
.viewcap b { color:var(--brass); font-weight:400; margin-right:.9em; letter-spacing:.16em; }

@media (max-width: 720px) {
  /* No hover to reveal them and less room to spare, so the arrows sit closer
     in and the caption gets the width the sheet is not using. */
  .viewnav.prev { left:1.6vw; }
  .room .viewnav.next { right:calc(1.6vw + 18px); }
  .viewcap { max-width:76vw; }
}

.room.bare .info, .room.bare .chrome, .room.bare .dots, .room.bare .count { opacity:0; pointer-events:none; }
.room.bare .navstack { pointer-events:none; }
.room.bare .backhint { opacity:1; }
.backhint { position:absolute; left:50%; bottom:3vh; transform:translateX(-50%); z-index:9;
  max-width:88vw; text-align:center;
  font-family:var(--mono); font-size:clamp(8px,1.05vh,11px); letter-spacing:.18em; text-transform:uppercase;
  color:rgba(237,231,218,.34); opacity:0; transition:opacity .5s .35s; pointer-events:none; }
/* a phone has no Space key and no Esc key, so it is told what it can do */
.backhint .by-touch { display:none; }
@media (hover: none) {
  .backhint .by-key { display:none; }
  .backhint .by-touch { display:inline; }
}

/* ---- side menu ---- */
.veil { position:absolute; inset:0; z-index:10; background:rgba(6,9,14,.5);
  -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px);
  opacity:0; pointer-events:none; transition:opacity .4s; }
.veil.on { opacity:1; pointer-events:auto; }
.menu { position:absolute; left:0; top:0; bottom:0; z-index:11; width:min(340px,80vw);
  transform:translateX(-101%);
  transition:transform .52s cubic-bezier(.33,1,.4,1); display:flex; flex-direction:column; }
.menu::before {
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to right,
    rgba(10,15,22,.97) 0%, rgba(10,15,22,.95) 58%, rgba(10,15,22,.66) 80%, rgba(10,15,22,0) 100%);
  -webkit-backdrop-filter:blur(18px); backdrop-filter:blur(18px);
  -webkit-mask-image:linear-gradient(to right, #000 0%, #000 64%, transparent 100%);
  mask-image:linear-gradient(to right, #000 0%, #000 64%, transparent 100%); }
.menu .mhead, .menu .mlist, .menu .mfoot { position:relative; z-index:1; }
.menu.on { transform:translateX(0); }
.menu .mhead { padding:4vh 6% 2vh;
  font-family:var(--mono); font-size:clamp(9px,1.3vh,12px); letter-spacing:.18em; text-transform:uppercase; color:var(--brass); }
/* Close sits at the foot of the list, aligned with the rows above it. */
.menu .mtitle { background:none; border:0; padding:0; cursor:pointer; font:inherit;
  letter-spacing:inherit; text-transform:inherit; color:var(--brass);
  border-bottom:1px solid transparent; transition:color .2s, border-color .2s; }
.menu .mtitle:hover { color:var(--bone); border-bottom-color:rgba(237,231,218,.45); }
.menu .mfoot { padding:2.4vh 6% 4vh; }
.menu .mclose { background:none; border:0; padding:0; cursor:pointer;
  font-family:var(--mono); font-size:clamp(9px,1.3vh,12px); letter-spacing:.18em; text-transform:uppercase;
  color:var(--mute); transition:color .2s; }
.menu .mclose:hover { color:var(--bone); }
.menu .mlist { flex:0 1 auto; min-height:0; overflow-y:auto; padding:0 6% 1vh; scrollbar-width:none; }
.menu .mlist::-webkit-scrollbar { display:none; }
.mitem { position:relative; isolation:isolate; display:flex; gap:13px; align-items:center; width:100%;
  padding:10px 8px 10px 0; background:none; border:0; cursor:pointer; text-align:left; color:inherit; font:inherit;
  opacity:0; transform:translateX(-14px);
  --enter-delay:0s;
  transition:opacity .45s var(--enter-delay), transform .5s cubic-bezier(.33,1,.4,1) var(--enter-delay),
    padding-left .22s; }
.menu.on .mitem { opacity:1; transform:translateX(0); }
.mitem::after { content:''; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:linear-gradient(to right, rgba(36,48,63,.8) 0%, rgba(36,48,63,.55) 48%, rgba(36,48,63,0) 100%); }
.mitem > * { position:relative; z-index:1; }
.mitem::before { content:''; position:absolute; inset:0; z-index:0; pointer-events:none;
  background:linear-gradient(to right,
    rgba(237,231,218,.085) 0%, rgba(237,231,218,.055) 42%, rgba(237,231,218,.015) 76%, rgba(237,231,218,0) 96%);
  opacity:0; transition:opacity .22s; }
.mitem:hover::before, .mitem:focus-visible::before { opacity:1; }
.mitem:hover, .mitem:focus-visible { padding-left:9px; }
.mitem .th { width:62px; height:44px; flex:0 0 auto; object-fit:cover; display:block; opacity:.82;
  outline:1px solid transparent; transition:opacity .22s, outline-color .22s; background:#131C27; }
.mitem:hover .th { opacity:1; }
.mitem .th.blank { background:radial-gradient(120% 100% at 70% 30%, #1D2837, #0C121A); }
.mitem .t { font-family:var(--display); font-size:clamp(15px,2.1vh,19px); line-height:1.2; }
.mitem .m { font-family:var(--mono); font-size:clamp(9px,1.1vh,11px); letter-spacing:.11em; text-transform:uppercase; color:var(--mute); margin-top:3px; }
.mitem .m .s { color:var(--brass); }
.mitem.on .t { color:var(--brass); }
.mitem.on .th { outline-color:var(--brass); opacity:1; }

@media (max-width:640px) {
  .lpanel .cap { padding-left:7vw; max-width:88vw; }
  .lpanel .cap .b { display:none; }
  .abody { padding:0 7vw; max-width:none; }
  .info .sheet { grid-template-columns:1fr; gap:1.6vh; padding:0 7vw 5vh; }
  .info .desc { max-width:none; }
  .count { display:none; }
  .plate .art { inset:1.4vh 1.4vw; width:calc(100% - 2.8vw); height:calc(100% - 2.8vh); }
}

/* Without JavaScript the gallery cannot run, so the page falls back to a
   plain, readable index of everything instead of an empty screen. */
.fallback { position:absolute; inset:0; overflow-y:auto; padding:8vh 6vw; background:var(--ink); }
.fallback h1 { font-family:var(--display); font-weight:400; font-size:clamp(32px,6vw,60px); margin:0 0 .4em; }
.fallback h2 { font-family:var(--display); font-weight:400; font-size:clamp(22px,3vw,32px); margin:2em 0 .5em; }
.fallback ul { list-style:none; padding:0; margin:0; display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:18px; }
.fallback img { width:100%; height:auto; display:block; }
.fallback .t { font-family:var(--mono); font-size:12px; letter-spacing:.1em; text-transform:uppercase; color:var(--mute); margin-top:6px; }

/* ---- purchase page: a document, not a gallery, so it scrolls ----
   `html, body { height:100% }` at the top of this file pins the body to
   exactly one viewport, and a body's `overflow` is propagated to the
   viewport rather than applied to the body itself — so `overflow:auto` here
   made a scroller out of something that could never have anything to
   scroll, and a document longer than the screen simply could not be
   reached. It went unnoticed because both of these pages used to fit.
   Document pages opt out of the fixed height and grow instead. */
html:has(body.buypage), html:has(body.legalpage) { height:auto; }
body.buypage { height:auto; min-height:100%; overflow:auto; }
.buywrap { max-width:1100px; margin:0 auto; padding:clamp(28px,7vh,72px) clamp(20px,5vw,48px) 10vh; }
.crumb { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--mute); text-decoration:none; display:inline-block; margin-bottom:clamp(24px,5vh,48px); }
.crumb:hover { color:var(--brass); }
.buygrid { display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr); gap:clamp(24px,4vw,56px); align-items:start; }
.buyart { width:100%; height:auto; display:block; box-shadow:0 30px 80px rgba(0,0,0,.6); }
.buyside h1 { font-family:var(--display); font-weight:400; font-size:clamp(28px,4.4vw,48px); line-height:1.05; margin:0 0 .2em; }
.buyside .by { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--brass); margin:0 0 1.4em; }
.buyside .desc { color:#C3CAD4; line-height:1.68; margin:0 0 1.6em; max-width:46ch; }
.buyside .desc strong { color:#fff; font-weight:600; }
.buyside .desc em { color:var(--bone); }
.buyside dl { margin:0 0 1.8em; display:grid; grid-template-columns:auto 1fr; gap:.5em 1.4em;
  font-family:var(--mono); font-size:12px; padding-top:1.4em; border-top:1px solid var(--line); }
.buyside dt { color:var(--mute); text-transform:uppercase; letter-spacing:.1em; }
.buyside dd { margin:0; color:var(--bone); }
.buyside .includes { list-style:none; margin:0 0 1.8em; padding:0; display:flex; flex-direction:column; gap:.5em; }
.buyside .includes li { font-family:var(--mono); font-size:12px; letter-spacing:.04em; color:var(--brass);
  padding-left:1.4em; position:relative; }
.buyside .includes li::before { content:'+'; position:absolute; left:0; color:rgba(201,162,39,.6); }
/* Price and what you get on one line, because they are one fact. They used
   to be a price with the terms stacked somewhere above it, and a reader had
   to assemble "$380, original, one of one" for themselves. */
.buyside .priceline { display:flex; align-items:baseline; flex-wrap:wrap; gap:.5em .9em; margin-bottom:.6em; }
.buyside .price { font-family:var(--mono); font-size:clamp(22px,3vw,30px); color:var(--brass); letter-spacing:.04em; }
.buyside .edition { font-family:var(--mono); font-size:12px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--mute); }
.buyside .edition::before { content:'\00b7'; margin-right:.9em; color:rgba(201,162,39,.5); }

/* The other photographs of the work: what it looks like framed, and what the
   paint actually does close up. Both are things a flat scan cannot say. */
.views { margin-top:clamp(40px,7vw,84px); }
.views h2 { font-family:var(--mono); font-size:11px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--mute); font-weight:400; margin:0 0 1.4em; }
.viewgrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:clamp(16px,2.4vw,32px); }
.viewgrid figure { margin:0; }
.viewgrid img { width:100%; height:auto; display:block; box-shadow:0 18px 44px rgba(0,0,0,.5); }
.viewgrid picture { display:block; }
.viewgrid figcaption { font-family:var(--mono); font-size:11px; letter-spacing:.1em; color:var(--mute);
  margin-top:.9em; }
.buyside .fine { font-family:var(--mono); font-size:11.5px; line-height:1.8; color:var(--mute); margin:0 0 1.8em; max-width:40ch; }
.buyside .pending-note { font-family:var(--mono); font-size:11.5px; line-height:1.8;
  color:var(--brass); margin:1.2em 0 0; max-width:40ch; }
.buyside .soldbox { font-family:var(--mono); font-size:13px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--brass); border:1px solid rgba(201,162,39,.42); border-radius:100px; padding:.7em 1.4em; display:inline-block; margin-bottom:1em; }
@media (max-width:760px) { .buygrid { grid-template-columns:1fr; } }

/* ---- terms and privacy ---- */
/* Long-form reading rather than a gallery: one narrow column, a plain
   measure, and nothing that moves. */
body.legalpage { height:auto; min-height:100%; overflow:auto; }
.legalwrap { max-width:720px; margin:0 auto; padding:clamp(28px,7vh,72px) clamp(20px,6vw,32px) 14vh; }
.legalwrap h1 { font-family:var(--display); font-weight:400; font-size:clamp(30px,5.5vw,46px);
  line-height:1.05; margin:0 0 .3em; }
.legalwrap .updated { font-family:var(--mono); font-size:11px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--mute); margin:0 0 2.4em; }
.legalwrap .lead p { color:var(--bone); font-size:clamp(15px,1.9vh,17px); line-height:1.7; margin:0 0 1em; }
.legalwrap section { margin-top:2.6em; padding-top:2.2em; border-top:1px solid var(--line); }
.legalwrap h2 { font-family:var(--mono); font-size:12px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--brass); font-weight:500; margin:0 0 1.2em; }
.legalwrap p { color:#C3CAD4; line-height:1.75; margin:0 0 1em; }
.legalwrap strong { color:#fff; font-weight:600; }
.legalwrap em { color:var(--bone); }
.legalwrap ul { margin:0 0 1em; padding:0; list-style:none; display:flex; flex-direction:column; gap:.7em; }
.legalwrap li { color:#C3CAD4; line-height:1.7; padding-left:1.4em; position:relative; }
.legalwrap li::before { content:'—'; position:absolute; left:0; color:var(--mute); }
.legalwrap a { color:var(--brass); text-decoration:none; border-bottom:1px solid rgba(201,162,39,.4); }
.legalwrap a.crumb { border-bottom:none; }
.legalalso { margin-top:3.4em; padding-top:2em; border-top:1px solid var(--line);
  display:flex; gap:2em; flex-wrap:wrap; }
.legalalso a { font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--mute); border-bottom:none; }
.legalalso a:hover { color:var(--brass); }

/* the pair of links under the version line in the About room */
.abody .legal { display:flex; gap:1.6em; margin-top:.9em; }
.abody .legal a { font-family:var(--mono); font-size:clamp(9px,1.1vh,11px); letter-spacing:.12em;
  color:var(--mute); text-decoration:none; border-bottom:1px solid transparent;
  transition:color .2s, border-color .2s; }
.abody .legal a:hover { color:var(--brass); border-bottom-color:rgba(201,162,39,.45); }
