/* The Museum: one engine for a photographer's own hang. White walls, black
   type, the pictures and nothing else. Every museum's particulars (its name,
   its photographer, its rights line) are set in that museum's index.html; this
   file, museum.js, edit.js, plan.js and map.js are shared. The faces come from
   fonts.css, the one file to change for another typeface. */
:root{
  --wall:#fff;--ink:#111;--ink-2:rgba(17,17,17,.74);--faint:rgba(17,17,17,.58);--hair:rgba(17,17,17,.13);
  /* --faint is the lightest grey any words are set in (4.6:1 on the wall); --rule underlines a
     field (3:1); --hair only separates; --faint-line is for drawing, never for words */
  --rule:rgba(17,17,17,.45);--faint-line:rgba(17,17,17,.42);--tint:rgba(17,17,17,.035);
  --serif:"Timeless Serif",Georgia,serif;--sans:"Timeless Sans",system-ui,sans-serif;
  --ease:cubic-bezier(.22,1,.32,1);
  --hs:0;                            /* the headings' STYL: Display at large sizes; toward Text where they get small */
  --headgap2:1.6rem;                 /* under the plan's, the map's and the index's headings */
  --g:clamp(16px,4vw,56px);          /* the gutter: the air at the edge of the room */
  --top:calc(env(safe-area-inset-top) + clamp(14px,2.4vw,26px));
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* a focused item is never left under the fixed bar; the scroll bar's room is
   kept on every page, so the corner and the lists stay put between a page
   that scrolls and one that doesn't (Sha, Oct 9: Chile's bar pushed them over) */
html{background:var(--wall);color-scheme:light;scrollbar-gutter:stable;scroll-padding-top:calc(var(--top) + 3.6rem + var(--bar-x,0px));
  touch-action:manipulation}   /* no double-tap zoom anywhere (a pinch still zooms); iOS honors it only from the root down */
body{margin:0;background:var(--wall);color:var(--ink);font-family:var(--serif);font-variation-settings:"STYL" 100;
  font-size:17px;line-height:1.55;-webkit-font-smoothing:antialiased;overflow-x:hidden;
  font-feature-settings:"ss15" 1,"ss11" 1,"lnum" 1}   /* the vertical M, the alternate ampersand, lining figures (Type.md, Oct 9, 2026) */
/* the wall beneath an open viewer: still, and left where it is. Never pinned
   with position:fixed and an offset, which folds the page to one screen and
   makes closing scroll it back in the frame it regrows: iOS Safari then showed
   the wall unpainted, the bar over white, until the next touch scroll (Oct 10) */
html:has(> body.held){overflow:hidden;overscroll-behavior:none}
body:has(.editbar){scroll-padding-bottom:calc(env(safe-area-inset-bottom) + 4rem)}
a{color:inherit}
button,input,textarea{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer}
[hidden]{display:none!important}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.probe{position:fixed;top:0;left:0;width:0;height:100svh;visibility:hidden;pointer-events:none}
:focus-visible{outline:1px solid var(--ink);outline-offset:3px}
/* a heading or a dialog given the focus so a screen reader hears it: no ring */
[tabindex="-1"]:focus,[tabindex="-1"]:focus-visible{outline:none}
.bl{display:inline-block;width:0;height:0;vertical-align:baseline}

/* ═══ the corner: the name, small, once you are past the lobby; the four doors ═══ */
/* a corner too long for one line (a site's name on a small phone) puts the
   doors on a line of their own, still on the right; museum.js sets --bar-x,
   that line's height, and the page moves down by it */
.bar{position:fixed;z-index:10;top:0;left:0;right:0;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:.1rem .75rem;
  padding:var(--top) max(var(--g),env(safe-area-inset-right)) .7rem max(var(--g),env(safe-area-inset-left));
  background:var(--wall);pointer-events:none}
/* the lobby never scrolls */
body[data-view="lobby"] .bar{background:none}
/* nor bounces: iOS rubber-bands the document, which would slide the plan under the see-through bar */
html:has(body[data-view="lobby"]){overscroll-behavior-y:none}
.bar > *{pointer-events:auto}
.home{font-size:1.06rem;text-decoration:none;transition:opacity .4s var(--ease),visibility 0s}
/* hidden in the lobby but keeping its room, so the bar wraps (or not) the same
   on every page and the doors never jump a line on leaving the lobby */
body[data-view="lobby"] .home{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .4s var(--ease),visibility 0s linear .4s}
.doors{display:flex;gap:clamp(.9rem,2.4vw,1.8rem);font-size:1rem;margin-left:auto}
/* a phone: the doors closer together than the corner is to them, so most
   corners fit one line at 390 and the name never reads as a sixth door */
@media (max-width:430px){.doors{gap:.6rem}.bar{column-gap:1.1rem}}
.doors a{text-decoration:none;color:var(--faint);padding:.3rem 0;transition:color .3s var(--ease);touch-action:manipulation}
.doors a[aria-current="page"]{color:var(--ink)}
.doors .editing{color:var(--ink);font-style:italic}

main{min-height:100svh}
.view{padding:calc(var(--top) + 3.6rem + var(--bar-x,0px)) max(var(--g),env(safe-area-inset-right)) calc(5rem + env(safe-area-inset-bottom)) max(var(--g),env(safe-area-inset-left));
  animation:in .5s var(--ease) both}
.view.still{animation:none}
/* a map page to another layer's (museum.js mapXf, xfIn): the old page held over the new one is still, nothing
   in it coming in again or easing (the map's controls, its own fade in) */
.view.xfg,.view.xfg *{animation:none !important;transition:none !important}
/* a layer's page: the browser keeps no row in place as the list is made again (a work chosen, its row slides
   to the list's top: the page scrolls back up to the map on its own ease, museum.js layerStep) */
.view.layered{overflow-anchor:none}
/* after a docked head, whose fade it waits for (museum.js leave): held unseen until that starts, then in just after it */
.view.after{animation-delay:.18s}
.view.wait{animation-play-state:paused}
@keyframes in{from{opacity:0}to{opacity:1}}
@keyframes out{to{opacity:0}}
@media (prefers-reduced-motion:reduce){.view{animation:none}}

/* ═══ the lobby ═══ */
#lobby{height:100svh;padding:0;position:relative;overflow:hidden}
/* while editing, the room ends above the edit bar, so the name stays clear of it */
body:has(.editbar) #lobby{height:calc(100svh - 3.6rem - env(safe-area-inset-bottom))}
@media (max-width:359.98px){body:has(.editbar) #lobby{height:calc(100svh - 5.4rem - env(safe-area-inset-bottom))}}   /* the bar is two lines there */
/* the box above the name: the floor plan fills it (plan.js reads its height), one drawing easing in over the last */
.hung{position:absolute;left:max(var(--g),env(safe-area-inset-left));right:max(var(--g),env(safe-area-inset-right));
  top:calc(var(--top) + 3.2rem + 3vh + var(--bar-x,0px));bottom:calc(var(--title-h,22vh) + 3vh)}   /* the same air above the plan as below it */
.lplan{position:absolute;inset:0;opacity:0;transition:opacity .6s var(--ease)}
.lplan.in{opacity:1}
.lplan.now{transition:none}
.lplan.out{opacity:0;pointer-events:none}
.lplan > .none{position:absolute;inset:0;margin:auto;height:max-content;font-style:italic;color:var(--faint);text-align:center;max-width:28rem}
/* a museum with no galleries yet: one picture, a different one each visit */
.lplan > .lpic{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.lpic img{display:block;max-width:100%;max-height:100%;width:auto;height:auto;opacity:0;transition:opacity .9s var(--ease)}
.lpic img.in{opacity:1}
@media (prefers-reduced-motion:reduce){.lplan,.lpic img{transition:none}}
/* the name, typed: black, at the foot of the room, a fifth of it tall */
.title{position:absolute;left:max(var(--g),env(safe-area-inset-left));bottom:calc(env(safe-area-inset-bottom) + clamp(10px,2.2vh,28px));
  margin:0;font-weight:400;line-height:1;white-space:nowrap;letter-spacing:-.012em;font-size:var(--title-fs,20vh)}
.title.serif{font-family:var(--serif);font-variation-settings:"STYL" 0}
.title .measure{position:absolute;left:0;top:0;visibility:hidden;white-space:nowrap;pointer-events:none;font-size:100px}
.title .caret{display:inline-block;width:.045em;height:.74em;margin-left:.04em;background:var(--ink);vertical-align:-.02em;
  animation:blink 1.05s steps(2,start) infinite;transition:opacity .6s var(--ease)}
.title .caret.gone{opacity:0;animation:none}
/* the name typed: the cursor holds one beat, goes off, comes back once, and is gone,
   each step the blink's own half-period, so it never stops mid-blink (Sha, Oct 9) */
.title .caret.once{animation:caret-once 1.575s steps(1,end) forwards;transition:none}
@keyframes caret-once{0%{opacity:1}33.333%{opacity:0}66.667%{opacity:1}100%{opacity:0}}
@keyframes blink{to{visibility:hidden}}

/* ═══ a room: its name, its count, its text, then the hang ═══ */
.roomhead{max-width:44rem;margin:0 0 clamp(2.2rem,6vw,4.5rem)}
.kicker{margin:0 0 .5rem;color:var(--faint);font-size:.95rem;font-variant-numeric:lining-nums proportional-nums}
.kicker a{text-decoration:none}
.kicker .nw{white-space:nowrap}   /* a place's kicker: its steps break between them (museum.js crumbs) */
.roomhead h1,.roomhead .h1w{margin:0;font-weight:400;font-variation-settings:"STYL" var(--hs);font-size:clamp(2.3rem,6.4vw,4.6rem);line-height:1.02;letter-spacing:-.01em}
/* a camera's name as it would be set on its own lines, never seen: it alone sizes the name's column (.roomtop), so a name
   on one line stands in the width it always had and the drawing and its figures beside it keep their places */
.roomhead .h1w{display:block;height:0;overflow:hidden;visibility:hidden;pointer-events:none}
.roomhead .n{margin:.7rem 0 0;color:var(--ink-2);font-variant-numeric:lining-nums proportional-nums}
.roomhead .text{margin:1.2rem 0 0;font-size:1.06rem;line-height:1.7;max-width:36rem;white-space:pre-wrap}
/* from 720px a room's name is one line (museum.js fitTitle steps its size down to fit, never
   below a phone's 2.3rem); the head's other lines keep their measure, a gallery's text its own.
   Beside a camera's drawing the head keeps its width, and the name fits in it */
@media (min-width:720px){
  .roomhead:not(.roomtop > *):has(> h1.one){max-width:none}
  .roomhead:has(> h1.one) > :not(h1,.text){max-width:44rem}
  .roomhead h1.one{white-space:nowrap}
  .roomtop .roomhead h1.one{contain:inline-size}
  .roomhead h1.one.wraps{white-space:normal}
}
.roomhead .n a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.22em;text-decoration-color:var(--hair);transition:text-decoration-color .3s var(--ease)}
.hang{display:flex;flex-direction:column;gap:var(--rowgap,clamp(28px,5vw,72px))}
.hrow{display:flex;gap:var(--colgap,clamp(24px,4.4vw,64px));justify-content:center;align-items:flex-end}
.tile{display:block;flex:none;position:relative;background:var(--tint)}
.tile img{display:block;width:100%;height:100%;opacity:0;transition:opacity .7s var(--ease)}
.tile img.in{opacity:1}
.tile img.now{transition:none}   /* painted before the viewer's close fade uncovers it (museum.js ready) */
/* taken down: the picture dimmed, its note at full strength */
.tile.stored{background:transparent}
.tile.stored img.in{opacity:.38}
.tile.stored::after{content:"Not on view";position:absolute;left:0;bottom:-1.5rem;font-size:.84rem;font-style:italic;color:var(--ink-2)}
.empty{font-style:italic;color:var(--faint);max-width:30rem}

/* ═══ view headings shared by the map, the index and the cameras ═══ */
.maphead h1,.idxhead h1,.camhead h1{margin:0;font-weight:400;font-variation-settings:"STYL" var(--hs);font-size:clamp(2rem,5vw,3.4rem);line-height:1.05}
.maphead h1 .nw{white-space:nowrap}
/* a museum with other layers on its map (museum.js layersHTML): the switch under the heading's name, its two
   words in one hairline pill, the layer on view in ink on a faint tint (never a solid fill: two solid fills
   crossing in a map's crossfade read as one black pill, or cut through the old heading), so it reads as a choice between two maps and
   not as more of the bar's doors, whose "pictures" it shares (Sha, Oct 14: "maybe the label should look
   slightly different or something so that it doesn't come into conflict or confusion") */
.maphead .layers{display:flex;width:max-content;max-width:100%;margin:.55rem 0 0;padding:2px;border:1px solid var(--hair);border-radius:999px;font-size:.85rem;line-height:1.2}
.maphead .layers a{position:relative;display:block;padding:.16rem .66rem .2rem;border-radius:999px;text-decoration:none;color:var(--ink-2);transition:color .3s var(--ease),background-color .3s var(--ease)}
.maphead .layers a[aria-current],.maphead .layers a[aria-current]:hover{background:rgba(17,17,17,.07);color:var(--ink)}
/* the focus ring just outside its segment, inside the pill (the house ring's 3 px offset fell on the pill's own line) */
.maphead .layers a:focus-visible{outline-offset:0}
/* small, as Sha asked (Oct 14: "the toggle pill feels a little large"), and still a finger's reach: on a touch screen
   each segment takes taps 9 px above and below the pill without the pill growing */
@media (pointer:coarse){.maphead .layers a::after{content:"";position:absolute;inset:-12px -2px}}   /* 9 px past the pill: the segment sits 3 px inside it */

/* ═══ a level of the map (museum.js viewPlaceMap): the map resting on it, then its pictures ═══ */
/* "N pictures" just over them, nearer to them than to the map; at a place, its outline beside the count, as its room had it */
.hanghead{margin:clamp(1.4rem,3vw,2rem) 0 clamp(.9rem,2vw,1.2rem)}
.hanghead .n{margin:0;color:var(--ink-2);font-variant-numeric:lining-nums proportional-nums}
/* a place spaced as a region is (the room's .placetop margin never reaches here), and only under a drawing the wider gap */
.hanghead.placetop{margin:clamp(1.4rem,3vw,2rem) 0 clamp(.9rem,2vw,1.2rem)}
.hanghead.placetop:has(> .outline){margin-bottom:clamp(1.4rem,3.4vw,2.4rem)}
.hanghead.placetop > .n{grid-column:1;grid-row:1/span 3}
.hanghead .outline{margin-top:0}
/* a desktop's map page ends at the corner's gutter (map.css); under its pictures, the room's foot */
.view:has(.mmap.mm-fit) > .hang{margin-bottom:calc(5rem - var(--top))}

/* ═══ the lobby's levels: a directory, as in a lift ═══ */
/* on a wide screen beside the plan, the top level at the top; on a narrow one a
   row along the top of the plan. The level on view is in ink, its hairline black */
.lift ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column-reverse}
.lift li{position:relative;border-top:1px solid var(--hair)}
.lift-row{display:flex;align-items:baseline;justify-content:space-between;gap:.6rem;padding:.42rem 0 .46rem;text-decoration:none;color:var(--faint);
  transition:color .35s var(--ease)}
.lift-row::before{content:"";position:absolute;left:0;right:0;top:-1px;height:1px;background:var(--ink);opacity:0;pointer-events:none;transition:opacity .35s var(--ease)}
.lift-row[aria-current]{color:var(--ink)}
.lift-row[aria-current]::before{opacity:1}
.lift-t,.lift-c{font-variant-numeric:lining-nums proportional-nums}
.lift-t{min-width:0;overflow-wrap:anywhere}
.lift-c{flex:none;font-size:.84rem;white-space:nowrap}
.lift-row:focus-visible{outline:none}
.lift-row:focus-visible .lift-t{text-decoration:underline 1px;text-underline-offset:.22em}
/* over the box the plan is fitted to, which makes room for it */
.lobby-lift{position:absolute;z-index:2;top:calc(var(--top) + 3.2rem + 3vh + var(--bar-x,0px));bottom:calc(var(--title-h,22vh) + 3vh);right:max(var(--g),env(safe-area-inset-right));width:10rem;
  display:flex;flex-direction:column;justify-content:center;pointer-events:none;opacity:0;transition:opacity .6s var(--ease),transform .6s var(--ease)}
/* museum.js moves it in beside the drawing (besideLift); .snap: there at once (a first drawing, a resize) */
.lobby-lift.snap{transition:opacity .6s var(--ease)}
/* "all", every level at once: the foot of the column, a little apart from the levels */
.lobby-lift .lift-all{margin-top:.9rem}
/* the level whose floor is lifted apart there is in ink here too; the line stays the level on view's alone */
.lift li.hot .lift-row{color:var(--ink)}
.lobby-lift ol{pointer-events:auto}
.lobby-lift.in{opacity:1}
.lobby-lift.out{opacity:0;pointer-events:none}
#lobby.lifted .hung{right:calc(max(var(--g),env(safe-area-inset-right)) + 10rem + clamp(1.6rem,4vw,3.6rem))}
@media (max-width:899.98px){
  .lift ol{flex-direction:row;flex-wrap:wrap;gap:0 1.4rem}
  .lift li{border-top:0}
  .lift-row{padding:.2rem 0 .3rem}
  .lift-row::before{top:auto;bottom:0}
  .lift-c{display:none}
  .lobby-lift .lift-all{margin-top:0}
  .lobby-lift{left:max(var(--g),env(safe-area-inset-left));bottom:auto;width:auto;display:block}
  #lobby.lifted .hung{right:max(var(--g),env(safe-area-inset-right));top:calc(var(--top) + 3.2rem + 3vh + var(--bar-x,0px) + 2.6rem)}
}
@media (prefers-reduced-motion:reduce){.lift-row,.lift-row::before,.lobby-lift{transition:none}}
/* a level of two or more wings (plan.js stands them on a hall): each wing's name over it, as the arrange view sets it */
.mp-wn{font-family:var(--serif);font-size:12.5px;fill:var(--ink-2);font-variant-numeric:lining-nums proportional-nums}
/* edit mode's arrange view, on the index (it took the levels editor's place): arrange.css, which edit.js loads */

/* ═══ the index: every tag, with how many ═══ */
.idxhead{margin:0 0 var(--headgap2)}
.findl{display:block;margin:1.2rem 0 0;font-size:.9rem;line-height:1.4;color:var(--ink-2)}
.find{width:min(26rem,100%);border:0;border-bottom:1px solid var(--rule);border-radius:0;padding:.35rem 0 .5rem;margin:.15rem 0 0;background:transparent;outline:none;font-size:16px;
  -webkit-appearance:none;appearance:none;transition:border-color .3s var(--ease)}
.find::-webkit-search-cancel-button,.find::-webkit-search-decoration{-webkit-appearance:none}
.find:focus{border-color:var(--ink)}
.facets{columns:16rem auto;column-gap:clamp(2rem,5vw,4rem);margin-top:2.4rem}
.facet{break-inside:avoid;margin:0 0 2.2rem}
.facet h2{margin:0 0 .5rem;font-weight:400;font-size:1rem;color:var(--faint)}
.facet ul{list-style:none;margin:0;padding:0}
.facet li a{display:flex;justify-content:space-between;gap:1rem;padding:.3rem 0;text-decoration:none}
.facet li a .k{color:var(--faint);font-variant-numeric:lining-nums proportional-nums}   /* Timeless's tabular figures spread 11 to "1 1" */
.facet .none,.facets > .none,.findnone{color:var(--faint);font-style:italic;font-size:.95rem}
.findnone:empty{display:none}
/* edit mode: the pictures the last build left off the walls */
.heldback{margin:1.4rem 0 0;max-width:30rem}
.heldback h2{margin:0 0 .5rem;font-weight:400;font-size:1rem;color:var(--faint)}
.heldback .hmsg{margin:0 0 .6rem;color:var(--ink-2);font-size:.92rem}
.heldback ul{list-style:none;margin:0;padding:0}
.heldback li{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;padding:.35rem 0;border-top:1px solid var(--hair)}
.heldback .hid{color:var(--faint);font-size:.84rem;font-variant-numeric:tabular-nums}
.heldback button{flex:none;font-size:.88rem;border-bottom:1px solid var(--ink);padding:.1rem 0}
.foot{margin-top:4rem;color:var(--faint);font-size:.92rem}
.foot button{color:var(--faint);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em}

/* ═══ the cameras: line drawings, every one at --camk px to the mm (set by museum.js) ═══ */
.cam{position:relative;flex:none;width:calc(var(--w,0) * var(--camk,2.8) * 1px);height:calc(var(--h,0) * var(--camk,2.8) * 1px);
  color:var(--ink);opacity:0;transition:opacity .6s var(--ease)}
.cam.in{opacity:1}
.cam-v{position:absolute;left:calc(var(--x) * var(--camk,2.8) * 1px);top:calc(var(--y) * var(--camk,2.8) * 1px);
  width:calc(var(--w) * var(--camk,2.8) * 1px);height:calc(var(--h) * var(--camk,2.8) * 1px)}
.cam-v svg{display:block;width:100%;height:100%;overflow:visible}
/* hairlines: the outline, the edges, then the lines that only say where a surface turns */
.cam .cam-o{stroke-width:1}
.cam .cam-l{stroke-width:.7}
.cam .cam-s{stroke-width:.5;stroke-opacity:.6}
.cam .cam-logo{stroke-opacity:.5}
/* a camera's room: the name, then the drawing beside it with its facts at its foot, all on one line
   where they fit, so the pictures still start on the first screen */
.roomtop{display:grid;grid-template-columns:minmax(0,1fr);align-items:end;gap:clamp(1.6rem,4vw,2.4rem) clamp(2.6rem,6vw,6rem);margin:0 0 clamp(2.2rem,6vw,4.5rem)}
/* the name keeps its width; the plate takes what is left, and never less than its drawing */
@media (min-width:720px){.roomtop{grid-template-columns:minmax(0,max-content) minmax(min-content,1fr);justify-content:start}}
.roomhead h1 .nw{white-space:nowrap}
.roomtop .roomhead{margin:0}
.plate{display:flex;flex-wrap:wrap;align-items:flex-end;gap:1.3rem clamp(1.6rem,4vw,3.2rem);margin:0}
.plate figcaption{flex:1 1 9rem;min-width:9rem;max-width:30rem;color:var(--ink-2);font-variant-numeric:lining-nums proportional-nums}
.plate figcaption p{margin:0}
.plate:not(:has(.cam)) figcaption{flex:0 1 auto}   /* a camera not drawn: its facts, then its figures beside them, not spread across the line */
.plate .nw{white-space:nowrap}
/* the maker's specifications, beside the drawing and its figures */
.specs{font-size:.9rem;line-height:1.45;color:var(--ink-2);font-variant-numeric:lining-nums proportional-nums}
.plate .specs{flex:1 1 15rem;min-width:min(13rem,100%);max-width:25rem}
/* where they would wrap under the drawing, their own row, under it (museum.js placeSpecs) */
.roomtop.specrow > .specs{grid-column:2;max-width:25rem;align-self:start}
.specs dl{margin:0;display:grid;grid-template-columns:max-content minmax(0,1fr);column-gap:1rem;row-gap:.12rem}
.specs dl > div{display:contents}
.specs dt{color:var(--faint)}
.specs dd{margin:0;min-width:0}
.specs .src,.credit{font-size:.78rem;color:var(--faint)}
.specs .src{margin:.7rem 0 0}
.specs .src a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em;text-decoration-color:var(--hair);transition:text-decoration-color .3s var(--ease)}
/* every camera the owner has had, by year: the year, the drawing (every one at
   one scale, in a column as wide as the widest, --tlw), then the words */
.camhead{margin:0 0 clamp(2.4rem,6vw,4.2rem)}
.camhead .n{margin:.7rem 0 0;color:var(--ink-2);transition:opacity .5s var(--ease)}
.camhead .n.gone{opacity:0}
.timeline{list-style:none;margin:0;padding:0;max-width:62rem}
.tl{display:grid;grid-template-columns:4.5rem minmax(0,1fr);column-gap:1.5rem;align-items:start;padding:.9rem 0 1.2rem;border-top:1px solid var(--hair)}
.tl:last-child{border-bottom:1px solid var(--hair)}
.tl .y{color:var(--faint);font-variant-numeric:lining-nums proportional-nums}
.tl-a{display:grid;grid-template-columns:minmax(0,1fr);column-gap:clamp(1.4rem,3vw,2.4rem);row-gap:.9rem;align-items:end;text-decoration:none;min-width:0}
.timeline.has-drawn .tl-a{grid-template-columns:var(--tlw,0px) minmax(0,1fr)}
/* a drawn row's words stand at its top, level with its year, as an undrawn row's do */
.timeline.has-drawn .tl.drawn .tl-a{align-items:start}
.cam-none{display:block}
.tl-x{display:flex;flex-direction:column;min-width:0}
.tl-x .m{color:var(--ink-2);font-size:.92rem;font-variant-numeric:lining-nums proportional-nums}
.tl-x .k{color:var(--faint);font-size:.88rem;font-variant-numeric:lining-nums proportional-nums}
@media (max-width:719.98px){
  .tl{grid-template-columns:3.4rem minmax(0,1fr);column-gap:.8rem}
  .timeline.has-drawn .tl-a{grid-template-columns:minmax(0,1fr)}
  .cam-none{display:none}
  /* the drawing above the words: the year comes down to the name, past the drawing (--ch, its height in mm) and the gap */
  .tl.drawn .y{padding-top:calc(var(--ch,0) * var(--camk,2.8) * 1px + .9rem)}
}
/* a place's outline, beside its name: small at the top right on a phone, larger on a wide screen */
.placetop{--s:clamp(120px,13vw,200px);display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-rows:auto auto 1fr;column-gap:clamp(1.2rem,4vw,3.2rem);align-items:start;margin:0 0 clamp(2.2rem,6vw,4.5rem)}
.placetop .roomhead{grid-column:1;grid-row:1/span 3;margin:0}
.placetop .roomhead h1 .nw{white-space:nowrap}
.outline{grid-column:2;grid-row:1;opacity:0;transition:opacity .9s var(--ease)}
.outline svg{display:block;width:calc(var(--s) * min(1, var(--a,1)));height:auto;aspect-ratio:var(--a,1);overflow:visible;margin-left:auto}
.outline .ln{fill:none;stroke:var(--ink);stroke-width:1;stroke-linejoin:round;vector-effect:non-scaling-stroke}
.outline .pt{fill:none;stroke:var(--ink);stroke-width:5;stroke-linecap:round;vector-effect:non-scaling-stroke}
/* a place drawn with the shape it is in (a lake in its park): the place large, the shape small beside it, the place's spot marked */
.outline.pair{display:flex;align-items:flex-start;justify-content:flex-end;gap:clamp(.7rem,1.6vw,1.2rem)}
.outline.pair svg{margin-left:0}
.outline svg.loc{flex:none;width:calc(var(--s) * .42 * min(1, var(--a,1)))}
.outline .loc .pt{stroke-width:4}
.credit .cr{display:block}
/* under a pair, as wide as the two drawings (its own words never widen the column) */
.outline.pair + .credit{width:auto;min-width:0;justify-self:stretch;contain:inline-size}
/* as wide as the outline's box at most, so a long credit wraps rather than widening the column and narrowing the name */
.credit{grid-column:2;grid-row:2;justify-self:end;width:var(--s);min-width:min-content;margin:.6rem 0 0;text-align:right;opacity:0;transition:opacity .9s var(--ease)}
.credit a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em;text-decoration-color:var(--hair);transition:text-decoration-color .3s var(--ease)}
.outline.in,.credit.in{opacity:1}
@media (max-width:719.98px){
  .placetop{--s:76px}
  .outline{margin-top:1.9rem}
  .outline.pair{gap:.5rem}
  /* the credit stays under the outline it credits, small, wrapping in its column */
  .credit{font-size:.7rem;line-height:1.3;margin-top:.45rem}
  /* under a pair, too narrow for its two credits: one line under the whole head, still at the right */
  .outline.pair + .credit{grid-column:1 / -1;grid-row:4;width:auto;contain:none;justify-self:end}
  .outline.pair + .credit .cr{display:inline}
  .outline.pair + .credit .cr + .cr::before{content:"· "}
}
.facet h2 a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.22em;text-decoration-color:var(--hair);transition:text-decoration-color .3s var(--ease)}
@media (prefers-reduced-motion:reduce){.cam,.camhead .n,.outline,.credit{transition:none}}

/* ═══ the viewer: one picture, the label beside it, two arrows ═══ */
#viewer{position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;margin:0;padding:0;border:0;background:var(--wall);color:var(--ink);overflow:hidden;display:none;
  touch-action:manipulation}   /* two quick taps on an arrow never zoom the page */
#viewer[open]{display:block;animation:in .35s var(--ease)}
#viewer.closing{animation:out .3s var(--ease) forwards;pointer-events:none}
#viewer:focus{outline:none}
#viewer::backdrop{background:transparent}
.track{position:absolute;inset:0;right:var(--lw,0px);display:flex;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;overscroll-behavior:contain;scrollbar-width:none;touch-action:pan-x}
.track::-webkit-scrollbar{display:none}
/* a pinch on a picture never zooms the page (Sha, Oct 13: the whole page zoomed, the label out of reach, and it glitched back); a swipe still walks the pictures */
.slide{flex:0 0 100%;height:100%;margin:0;container-type:size;touch-action:pan-x;scroll-snap-align:center;scroll-snap-stop:always;display:flex;align-items:center;justify-content:center;
  padding:calc(env(safe-area-inset-top) + 64px) 16px calc(env(safe-area-inset-bottom) + var(--below,96px))}
/* a wide screen: the picture as large as the wall allows, the arrows just off its edges */
@media (min-width:900px){.slide{padding:calc(var(--top) + 2.8rem) calc(clamp(40px,4vw,64px) + 8px) 5vh}}
/* the picture's box comes from the picture (--ar, its width over its height) and its front file's size
   (--cw, set by museum.js fill), never from the file it holds just now: a smaller file standing in for
   the next one is drawn at the same size, and the bigger one only sharpens it. The slide's box comes
   as --bw and --bh, measured by museum.js (BOX): iOS Safari's 100cqw and 100cqh went stale while the
   slide's padding eased, and the picture squashed */
.slide img{display:block;width:min(var(--bw,100cqw),var(--bh,100cqh) * var(--ar,1),var(--cw,100cqw));height:auto;max-width:100%;max-height:100%;opacity:0;transition:opacity .45s var(--ease)}
.slide img.in{opacity:1}
.ctl{position:absolute;z-index:3;display:flex;align-items:center;justify-content:center;color:var(--faint);transition:color .25s var(--ease),opacity .3s var(--ease),visibility 0s}
.ctl svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.15;stroke-linecap:round;stroke-linejoin:round}
.ctl[disabled]{opacity:.15;pointer-events:none}
/* the way back: where the name sits in the bar, at its size and on its baseline, after the same chevron the map uses */
.ctl.close{line-height:1.55;top:calc(var(--top) + .175rem);   /* .175rem: measured, puts its baseline on the name's */
  left:max(var(--g),env(safe-area-inset-left));font-size:1.06rem;color:var(--ink-2);gap:.3rem;max-width:60vw;white-space:nowrap;
  justify-content:flex-start}
.ctl.close svg{width:16px;height:16px;flex:none;margin-left:-5px}
.ctl.close .bt{min-width:0;overflow:hidden;text-overflow:ellipsis}
.ctl.prev,.ctl.next{top:50%;transform:translateY(-50%);width:48px;height:48px}
.ctl.prev{left:4px}.ctl.next{right:calc(var(--lw,0px) + 4px)}
@media (min-width:900px){.ctl.prev,.ctl.next{width:clamp(40px,4vw,64px);height:76vh}}
/* a phone swipes; its two arrows wait at the foot, beside the label's line, never over the picture */
@media (max-width:899.98px){
  .ctl.prev,.ctl.next{top:auto;transform:none;bottom:calc(env(safe-area-inset-bottom) + 10px);width:44px;height:44px;z-index:5}
  .ctl.prev{left:auto;right:calc(max(var(--g),env(safe-area-inset-right)) + 40px)}
  .ctl.next{right:calc(max(var(--g),env(safe-area-inset-right)) - 8px)}
  .label:not(.open):not(.shut){padding-right:calc(max(var(--g),env(safe-area-inset-right)) + 96px)}
  /* lowering, the words keep the measure they had risen, so they fade where they stood; the line coming in keeps its room beside the arrows */
  .label.shut .gist{padding-right:96px}
  /* under the risen label the arrows are gone for the keyboard too */
  #viewer:has(.label.open) .ctl.prev,#viewer:has(.label.open) .ctl.next{opacity:0;pointer-events:none;visibility:hidden;transition:opacity .3s var(--ease),visibility 0s linear .3s}
}
.count{margin:0;line-height:1.55;position:absolute;z-index:5;top:calc(var(--top) + .175rem);right:max(var(--g),env(safe-area-inset-right));font-size:1.06rem;color:var(--faint);font-variant-numeric:lining-nums proportional-nums}

/* The label, as a museum hangs it: who, what, when, where, of what, and
   then the paragraph. On a wide screen it has its own column of wall to the
   right of the picture, its foot level with the picture's (--lb, measured by
   museum.js); on a phone a line sits under the picture and the whole label
   rises from the bottom when tapped. */
.label{position:absolute;z-index:4;background:var(--wall);font-size:.98rem;line-height:1.5;overflow-y:auto;overscroll-behavior:contain}
.label .what{margin:0;font-size:1.08rem;font-weight:600;line-height:1.5}
.label .row{margin:.05rem 0 0;color:var(--ink-2)}
.label .row a[href^="#/room/series/"]{font-style:italic}   /* the gallery's name in italic, set apart from "from the gallery" (Sha, Oct 13) */
.label .tech{margin:.15rem 0 0;color:var(--faint);font-size:.86rem;font-variant-numeric:tabular-nums}
.label .tech.more2{margin-top:0}
.label .tech a{font-variant-numeric:lining-nums proportional-nums}   /* a camera's name, not a setting: "F31fd", not "F3 1fd" */
.label .nw{white-space:nowrap}
.label .text{margin:.95rem 0 0;line-height:1.65;white-space:pre-wrap}
.label .tags{margin:.95rem 0 0;color:var(--ink-2);font-size:.92rem}
.label .acc{margin:.95rem 0 0;color:var(--faint);font-size:.84rem;font-variant-numeric:tabular-nums}
/* one way to underline a link on the label */
.label a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.22em;text-decoration-color:var(--hair);transition:text-decoration-color .3s var(--ease)}
.label .gist{display:none}
.form .lower{display:none}
@media (min-width:900px){
  #viewer{--lw:340px}
  .label{right:0;top:0;bottom:0;width:var(--lw);padding:calc(var(--top) + 4.2rem) max(var(--g),env(safe-area-inset-right)) var(--lb,7vh) 1.6rem;display:flex;flex-direction:column;justify-content:flex-end;
    transition:padding-bottom .45s var(--ease)}
  .label .more{display:block}
  .label .gist{display:none}
}
@media (min-width:900px) and (max-width:1279.98px){#viewer{--lw:280px}#viewer.editing{--lw:340px}.label{padding-left:1.2rem}}
@media (max-width:899.98px){
  .label{left:0;right:0;bottom:0;overflow:hidden;padding:.8rem max(var(--g),env(safe-area-inset-right)) calc(env(safe-area-inset-bottom) + .9rem) max(var(--g),env(safe-area-inset-left));
    transition:height .5s var(--ease)}
  .label.open{overflow-y:auto;box-shadow:0 -1px 0 var(--hair)}
  .label .gist{display:block;width:100%;text-align:left}
  .label .gist .t{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}
  .label .gist .m{display:block;color:var(--faint);font-size:.88rem}
  .label .gist .m:only-child{font-size:.95rem;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}   /* untitled: where and when, in regular type */
  .label .more{display:none}
  /* rising: the line fades as the whole label comes up under it; lowering, the reverse */
  .label.open .more,.label.shut .more{display:block}
  .label.open .more{animation:in .4s var(--ease) both}
  /* the words fade as the sheet comes down, on its clock (.5s, museum.js lowerLabel); an animation, not a transition:
     the rise's "in", held at its end (both), left a transition nothing to start from, and they went in one frame (MU-62) */
  .label.shut .more{animation:out .5s var(--ease) both}
  .label.open .gist{position:absolute;top:.8rem;left:max(var(--g),env(safe-area-inset-left));right:max(var(--g),env(safe-area-inset-right));width:auto;opacity:0;visibility:hidden;pointer-events:none}
  .label.shut .gist{animation:in .4s var(--ease) both}
  /* lowered with its words scrolled down (an edit form, from the Save at its foot): the line comes in at the
     top of what is seen as the sheet comes down, over the words going, not scrolled away until the end */
  .label.shut .gist{position:sticky;top:0;z-index:1;background:var(--wall);margin-bottom:calc(-1 * var(--gh,0px))}   /* top 0: at the label's own padding, where it rests; over the words, not above them (--gh, its height: museum.js lowerLabel) */
  .label.shut{overflow-anchor:none}   /* and the words' scroll is left as it was (Chrome would move it by the line's height) */
  /* the same picture's label drawn again in place (museum.js letter): nothing fades in again */
  .label.still .more,.label.still .gist{animation:none}
  .form .fhead{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;margin:0 0 1.2rem}
  .form .fhead .acc{margin:0}
  .form .lower{display:inline}
}
@media (prefers-reduced-motion:reduce){.label,.label.open .more,.label.shut .gist,#viewer.editing .slide{transition:none;animation:none}#viewer[open],#viewer.closing{animation:none}}

/* ═══ edit mode ═══ */
/* centered by its margins, so its width is its words, up to the room's width less 14px a side */
.editbar{position:fixed;z-index:30;left:14px;right:14px;margin:0 auto;width:fit-content;bottom:calc(env(safe-area-inset-bottom) + 14px);background:var(--ink);color:var(--wall);
  padding:.55rem 1rem;font-size:.9rem;display:flex;flex-wrap:wrap;justify-content:center;gap:.3rem 1rem;align-items:baseline}
.editbar button{color:var(--wall);text-decoration:underline;text-underline-offset:.2em;text-decoration-thickness:1px;white-space:nowrap}
.editbar span{opacity:.8;white-space:nowrap}
.editbar :focus-visible{outline-color:var(--wall)}
@media (max-width:640px){.editbar{gap:.3rem .85rem;padding:.5rem .85rem;font-size:.86rem}.editbar .ed{display:none}}
#viewer .editbar{display:none}
.form{display:block}
.form .f{margin:0 0 1.05rem}
.form .acc{margin:0 0 1.2rem;color:var(--faint);font-size:.84rem;font-variant-numeric:tabular-nums}
.form label,.form .lt{display:block;font-size:.84rem;color:var(--faint);margin:0 0 .15rem}
.form input[type=text],.form textarea{width:100%;border:0;border-bottom:1px solid var(--rule);background:transparent;padding:.2rem 0 .35rem;outline:none;font-size:16px;border-radius:0;resize:none;
  transition:border-color .3s var(--ease)}
.form input[type=text]:focus,.form textarea:focus{border-color:var(--ink)}
.form textarea{min-height:5.5rem;line-height:1.55;field-sizing:content;overflow:hidden}
.form ::placeholder{color:var(--faint);font-style:italic;opacity:1}
.form input[type=checkbox]{accent-color:var(--ink)}
.chips{display:flex;flex-wrap:wrap;gap:.3rem .35rem}
.form .f > input + .chips,.form .f > .lt + .chips{margin-top:.5rem}
.chips button{font-size:.86rem;padding:.12rem .55rem;border:1px solid var(--hair);border-radius:0;color:var(--ink-2);transition:background-color .25s var(--ease),border-color .25s var(--ease),color .25s var(--ease)}
.chips button[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--wall)}
.form .two{display:flex;gap:1.1rem;flex-wrap:wrap}
.form .note{margin:-.45rem 0 1.05rem;font-size:.84rem;color:var(--ink-2)}
.form .two label{display:flex;gap:.4rem;align-items:center;font-size:.92rem;color:var(--ink)}
.form .place{display:flex;gap:.8rem;align-items:baseline}
.form .place input{flex:1}
.form .chips + .place{margin-top:.6rem}
.form .place button,.form .save,.form .linky{font-size:.88rem;border-bottom:1px solid var(--ink);padding:.1rem 0;white-space:nowrap}
.form .rstatus{margin:.4rem 0 0;font-size:.86rem;color:var(--faint);font-style:italic}
.form .rstatus:empty{display:none}
.form .results{list-style:none;margin:.4rem 0 0;padding:0;font-size:.86rem}
.form .results:empty{display:none}
.form .results button{display:block;text-align:left;padding:.3rem 0;border-bottom:1px solid var(--hair);width:100%;color:var(--ink-2)}
.form .osm{margin:.35rem 0 0;font-size:.78rem;color:var(--faint)}
.form .osm a{text-decoration-color:var(--hair)}
.form .chosen{font-size:.86rem;color:var(--ink-2);margin:.3rem 0 .2rem}
.form .chosen .linky{margin-left:.7rem;color:var(--ink-2);border-color:var(--hair)}
.form .actions{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;margin-top:1.1rem;position:sticky;bottom:0;background:var(--wall);padding:.75rem 0 calc(env(safe-area-inset-bottom) + 1.1rem);border-top:1px solid var(--hair)}
.form .save{font-size:1rem}
.form .status{font-size:.84rem;color:var(--faint);font-style:italic}
#viewer.editing .label{scroll-padding-bottom:5rem}
@media (min-width:900px){
  #viewer.editing{--lw:400px}
  /* the form starts under the count, so nothing runs beneath it */
  #viewer.editing .label{top:calc(var(--top) + 2.6rem);padding-top:0;justify-content:flex-start;padding-bottom:0}
}
@media (min-width:900px) and (max-width:1279.98px){#viewer.editing{--lw:340px}}
@media (max-width:899.98px){
  #viewer.editing .label{padding-bottom:0}
  /* editing on a phone, the picture moves up into the wall left above the form, in step with it */
  #viewer.editing .slide{transition:padding-bottom .5s var(--ease)}
  #viewer.editing:has(.label.open) .slide{padding-bottom:calc(var(--sheet,62svh) + 12px)}
}
dialog.key{border:1px solid var(--hair);padding:1.6rem 1.6rem 1.2rem;max-width:min(26rem,calc(100% - 32px));background:var(--wall);color:var(--ink)}
dialog.key::backdrop{background:rgba(255,255,255,.82)}
dialog.key p{margin:0 0 1rem}
dialog.key input[type=password]{width:100%;border:0;border-bottom:1px solid var(--rule);padding:.3rem 0;outline:none;font-size:16px;background:transparent;border-radius:0;
  box-shadow:0 1px 0 transparent;transition:border-color .3s var(--ease),box-shadow .3s var(--ease)}
dialog.key input[type=password]:focus{border-color:var(--ink);box-shadow:0 1px 0 var(--ink)}
dialog.key .rem{display:flex;gap:.45rem;align-items:center;margin:.9rem 0 0;font-size:.9rem;color:var(--ink-2)}
dialog.key .rem input{accent-color:var(--ink)}
dialog.key .kmsg{margin:.8rem 0 0;font-size:.9rem;color:var(--ink-2)}
dialog.key .kmsg:empty{display:none}
dialog.key .act{display:flex;justify-content:flex-end;gap:1.2rem;margin-top:1.2rem}
dialog.key .act button{border-bottom:1px solid var(--ink)}
dialog.key .act button:disabled{opacity:.4;cursor:default}
dialog.key .act button.no{border-color:transparent;color:var(--faint)}
.roomedit{margin-top:1.2rem;max-width:36rem}
.roomedit .form .actions{position:static;border-top:0;padding:.6rem 0 0;margin-top:.4rem}
.roomedit .form textarea{min-height:2.6rem}
/* a level of the map's, under its count (museum.js mapEdit): its Save as far above the pictures as a room's head is from them at most */
.mapedit{margin-bottom:clamp(1.4rem,3vw,2rem)}

/* ═══ pointing ═══ */
/* hover marks only where there is a mouse: on a touch screen they stick to
   whatever is under the last tap. Focus rings are not hover and stay above. */
@media (hover:hover) and (pointer:fine){
  .doors a:hover,.kicker a:hover,.maphead .layers a:hover,.dk-k a:hover,.ctl:hover,.ctl.close:hover,.form .results button:hover{color:var(--ink)}
  .roomhead .n a:hover,.label a:hover{text-decoration-color:currentColor}
  .tile:hover img{opacity:.9}
  .tile.stored:hover img{opacity:.38}
  .facet li a:hover .v,a.tl-a:hover .v{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em}
  .specs .src a:hover,.credit a:hover{text-decoration-color:currentColor}
  .lift-row:hover{color:var(--ink)}
  .facet h2 a:hover{text-decoration-color:currentColor}
  .chips button:hover{border-color:var(--ink-2)}
}
/* a fingertip's reach: the hit area grows, the words stay where they are */
@media (pointer:coarse){
  .doors a{padding-block:.6rem;margin-block:-.3rem}
  /* on a page that docks, two pixels less of it below them, the same layout, so a docked line's ink under them is its own */
  html.docking .doors a{padding-bottom:calc(.6rem - 2px);margin-bottom:calc(2px - .3rem)}
  .ctl.close{padding-block:.6rem;margin-block:-.6rem}
  .chips button{padding:.45rem .7rem}
}
/* small headings take some of the Text cut's sturdier hairlines */
@media (max-width:640px){:root{--hs:35}}

/* the italic numbers its alternates differently: its vertical M is ss04, its
   ampersand ss09. The sans keeps its own shapes. */
i,em,.doors .editing,.hung .none,.tile.stored::after,.empty,.facet .none,.facets > .none,.findnone,.form .status,.form .rstatus,.form ::placeholder,.mm-list .sub,.mm-none{font-feature-settings:"ss04" 1,"ss09" 1,"lnum" 1}

/* a tile focused for the keyboard's sake after a tap closed the viewer shows no ring; nor does a phone's
   label line lowered by a finger (museum.js focusLine) */
.tile.calm:focus-visible,.gist.calm:focus-visible{outline:none}

/* a museum that is one part of a site: its home page's name before the museum's,
   so the corner reads as the address does (bymayao/museum) */
.where{display:flex;align-items:baseline;min-width:0}
.away{font-size:1.06rem;text-decoration:none;color:var(--ink);padding:.3rem 0}
.away:hover{color:var(--ink-2)}

/* ═══ the head that docks (museum.js dock) ═══ */
/* As the page scrolls, a copy of the kicker and of the name, laid over the
   words themselves, rides up with the page, shrinking, and settles in the bar
   at the gutter, under the corner; over the last of it the bar's white comes
   in under them, a still edge down to the name's foot, and the count (and a
   place's outline and credit, where that edge would cut across them) fades
   away, whole, before it reaches it. Scroll-driven, transform and opacity only:
   nothing runs while the page scrolls, and every frame is the compositor's.
   Per line (.dk): it rides the first pixels with the page (dk-ride), then
   --ty/--k are its docked offset and scale, --e the scroll over which it
   docks, --h0 where a one-line copy takes over (.hand: a line resting on more
   than one line), its first line in one step a pixel on
   and the rest of it, ellipsis and all, by --h3. A tap goes to the
   words as they are seen (dk-hit): the page's own at rest, the copies' once
   they move; the white takes any other on the bar or under it once it is
   mostly drawn, so none falls through to the page. At rest, on a
   page that doesn't dock (.flat) and on one whose timeline is inactive, no
   copy and no white is seen. Without scroll-driven animations none of this
   is drawn and the head scrolls away. The dock lives in the bar, under its
   corner and doors. */
:root{--dock-t:clamp(1.3rem,1rem + .5vw,1.45rem);--dock-k:.82rem;--dock-gap:1px}
@media (max-width:719.98px){:root{--dock-k:.78rem}}
html.docking{scroll-padding-top:calc(var(--dock-h,0px) + .6rem)}
.bar > .where,.bar > .doors{position:relative;z-index:1}
.bar > .dock{position:fixed;top:0;left:0;width:0;height:0;pointer-events:none;animation:in .5s var(--ease) both}
.bar > .dock.still{animation:none}
.bar > .dock.dk-wait{opacity:0}   /* taking over from a dock whose words changed in place, until its fade starts (museum.js dock, holdBegin) */
.bar > .dock.flat{display:none}
/* a line: as wide as the bar, so the bar's gutter clips a one-line copy on its way in; as tall
   as its words reach at rest (museum.js sets it: a browser finds a tap only inside a box clipped
   so), and never more, so no fixed box of the dock reaches the screen's foot, where iOS
   Safari takes a fixed box for a footer and keeps the white it last saw there, an opaque
   strip under its toolbar (seen after the viewer, a white fixed sheet, closed on a docked room) */
.dk{position:fixed;top:0;left:0;height:0;right:var(--gr,0px);overflow-x:clip;overflow-y:visible;pointer-events:none;font-weight:400;-webkit-user-select:none;user-select:none}
.dock-wall,.dk-s,.dk-1{position:fixed;margin:0;transform-origin:0 0}
/* the white: from the screen's top (white on the bar's white) down to the name's foot (museum.js sets its height) */
.dock-wall{top:0;left:0;right:0;background:var(--wall);opacity:0;pointer-events:none}
.dk-t{color:var(--ink)}
.dk-k{color:var(--faint);font-variant-numeric:lining-nums proportional-nums}
.dk a{text-decoration:none;pointer-events:none}
.dk .nw{white-space:nowrap}
.dk-a,.dk-o,.dk-c{opacity:0}
.dk-c{position:absolute;top:0;left:0}
.dk .dk-ghost,.dk .dk-ghost *{color:transparent!important;pointer-events:none!important}
.dk-o .dk-x{text-overflow:clip}
.dk-1,.dk-b{white-space:nowrap}
.dk-x{overflow:hidden;text-overflow:ellipsis;max-width:var(--mw);padding-block:.25em;margin-block:-.25em}   /* the padding keeps its descenders */
.dk-k .dk-x{padding-block:0 .25em;margin-block:0 -.25em}   /* and nothing above, where the doors' reach is */
.dock-sz{position:absolute;visibility:hidden;width:var(--dock-t);height:var(--dock-gap);font-size:var(--dock-k)}
@keyframes dk-ride{from{transform:translateY(0)}to{transform:translateY(-2px)}}   /* museum.js RIDE */
@keyframes dk-move{from{transform:none}to{transform:translateY(var(--ty)) scale(var(--k))}}
@keyframes dk-back{from{transform:translateY(var(--iy)) scale(var(--ik))}to{transform:none}}
@keyframes dk-on{from{opacity:0}to{opacity:1}}
@keyframes dk-off{from{opacity:1}to{opacity:0}}
@keyframes dk-hide{to{opacity:0}}
@keyframes dk-hit{from{pointer-events:none}to{pointer-events:auto}}
@keyframes dk-live{from,to{pointer-events:auto}}
@keyframes dk-unhit{from{pointer-events:auto}to{pointer-events:none}}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    /* the first two pixels: the copies ride exactly on the page's own words. At rest the words are seen, and from
       the first device pixel of scroll the copies instead, the two swapped by one step on one range, so they change
       in the same frame and are never drawn both at once: a gray kicker drawn twice is darker (iOS, Oct 11). The
       range is a quarter pixel: under a third (an iPhone's smallest scroll), and no shorter, for a range under a
       browser's own unit of length (1/64 px) is none at all, and swaps at rest */
    .dk{animation:dk-ride linear both;animation-timeline:scroll(root);animation-range:0px 2px}
    .dk-s .dk-a{animation:dk-on steps(1,jump-end) both;animation-timeline:scroll(root);animation-range:0px .25px}
    /* a map page's heading, whose words change in place (museum.js swapWords), goes whole: each word fades on its own
       element, and never on one that carries this too. On the same element, iOS Safari ran both on the page's thread: a
       fade froze through a long task (it was eaten by the change's first frame, Oct 12), and on a level reached in place,
       long after its fade, this swap came frames after the copies', so a scroll drew the page's words and the dock's
       together (simulator, Oct 13) */
    .roomhead.docked > h1,.roomhead.docked > .kicker,.maphead.docked{animation:dk-off steps(1,jump-end) both;animation-timeline:scroll(root);animation-range:0px .25px}
    .dk-s{animation:dk-move linear both;animation-timeline:scroll(root);animation-range:2px var(--e)}
    .dk-1{animation:dk-back linear both;animation-timeline:scroll(root);animation-range:2px var(--e)}
    /* the hand-over, over the last of it: the lines after the first fade (--h1 to --h0); the one-line copy's first
       line, lying exactly on the resting first line, takes over from it at --h0 + 1px, the two swapped by one step
       on one range as the words and the copies are, and the rest of the one line, ellipsis and all, comes in
       after it (--h0 to --h3) */
    .dk.hand .dk-r{animation:dk-off linear both;animation-timeline:scroll(root);animation-range:var(--h1) var(--h0)}
    .dk.hand .dk-o{animation:dk-on steps(1,jump-end) both;animation-timeline:scroll(root);animation-range:var(--h0) calc(var(--h0) + 1px)}
    .dk.hand .dk-b{animation:dk-off steps(1,jump-end) both;animation-timeline:scroll(root);animation-range:var(--h0) calc(var(--h0) + 1px)}
    .dk.hand .dk-c{animation:dk-on linear both;animation-timeline:scroll(root);animation-range:var(--h0) var(--h3)}
    .placetop.dk-side > .outline:not([data-leaving]),.placetop.dk-side > .credit:not([data-leaving]){animation:dk-hide linear both;animation-timeline:scroll(root);animation-range:var(--sf0) var(--sf1)}
    .roomhead.docked > .n{animation:dk-hide linear both;animation-timeline:scroll(root);animation-range:var(--nf0) var(--nf1)}
    .dock-wall{animation:dk-on linear both,dk-hit linear both;animation-timeline:scroll(root),scroll(root);animation-range:var(--w0) var(--w1),calc((var(--w0) + var(--w1)) / 2 - 1px) calc((var(--w0) + var(--w1)) / 2)}   /* taps from half drawn */
    /* a tap goes to the words as they are seen: the copies' from the first pixel (the lines that fade, until they are half
       gone), a one-line copy's first line as it takes over, the rest of it once it is half in, the page's own words' never
       once they have gone */
    .roomhead.docked > .kicker a,.maphead.docked > .kicker a{animation:dk-unhit linear both;animation-timeline:scroll(root);animation-range:1px 2px}
    .dk:not(.hand) .dk-s a{animation:dk-hit linear both;animation-timeline:scroll(root);animation-range:1px 2px}
    .dk.hand .dk-b a{animation:dk-live linear;animation-timeline:scroll(root);animation-range:1px calc(var(--h0) + 1px)}
    .dk.hand .dk-r a{animation:dk-live linear;animation-timeline:scroll(root);animation-range:1px calc((var(--h1) + var(--h0)) / 2)}   /* until it is half gone */
    .dk.hand .dk-o a{animation:dk-hit linear both;animation-timeline:scroll(root);animation-range:calc(var(--h0) + .5px) calc(var(--h0) + 1.5px)}   /* on at its middle: as it is seen, as the line under it goes */
    .dk.hand .dk-c a{animation:dk-hit linear both;animation-timeline:scroll(root);animation-range:calc((var(--h0) + var(--h3)) / 2 - 1px) calc((var(--h0) + var(--h3)) / 2)}
  }
  /* reduced motion: the docked head is information, so it still comes, but in place, on one line, fading in
     once the name has gone under the bar; the page's own words simply scroll away */
  @media (prefers-reduced-motion:reduce){
    .bar > .dock{animation:none}
    .dk-s{display:none}
    .dk-1{translate:0 -2px}   /* placed for the ride, which reduced motion has none of */
    .dk-o,.dk-c{animation:dk-on linear both;animation-timeline:scroll(root);animation-range:var(--r0) var(--r1)}
    .dock-wall{animation:dk-on linear both,dk-hit linear both;animation-timeline:scroll(root),scroll(root);animation-range:var(--r0) var(--r1),calc((var(--r0) + var(--r1)) / 2 - 1px) calc((var(--r0) + var(--r1)) / 2)}
    .dk-1 a{animation:dk-hit linear both;animation-timeline:scroll(root);animation-range:calc((var(--r0) + var(--r1)) / 2 - 1px) calc((var(--r0) + var(--r1)) / 2)}   /* once it is half in */
    .roomhead.docked > .n{animation:dk-hide linear both;animation-timeline:scroll(root);animation-range:var(--r0) var(--r1)}   /* on a page too short for it to have gone first */
    /* a place's outline and credit, where the white comes in across them: they go just before it, never under the name */
    .placetop.dk-rside > .outline,.placetop.dk-rside > .credit{animation:dk-hide linear both;animation-timeline:scroll(root);animation-range:var(--rf0) var(--rf1)}
  }
}
@supports not (animation-timeline:scroll()){.bar > .dock{display:none}}

/* ═══ the zoom, in the viewer (zoom.js, MuseumZoom, attached by museum.js) ═══
   Sha, Oct 13, 2026: "Push the Zoom prototype to the main page" (labs/museum-zoom, where he tried it; the
   zoom spec, tools/museum/specs/zoom.md). At fit nothing here moves a pixel: the slide is laid out as it
   always was, and only clipped, where nothing of it is drawn at fit. The module marks the viewer
   .mz-zoomed while zoomed and .mz-dragging while a mouse drags. */
/* The picture's own area (its slide) clips it: zoomed, it never slides under the label, past the track,
   or up into the band of wall the back control stands on (--band: down to just under that control's
   line, on a phone the control to zoom out's too), so those words are always on the wall's own white.
   The band is clipped off the slide, not laid out apart from it: a slide that began under it, its
   padding that much less, put its picture a 64th of a pixel off where it was, and on a 1024 px window
   moved the label beside it by a pixel (measured, Oct 13). museum.js reads the clip back, so a look
   around stops at the band's edge */
#viewer{--band:calc(var(--top) + 2.3rem)}
/* on a whole pixel (down, so never over a control's line): an edge partway through a device pixel let a
   framed print's face show through the mat beneath it, a darker hairline than either (the review, Oct 13) */
@supports (width:round(down,1.5px,1px)){#viewer{--band:round(down,calc(var(--top) + 2.3rem),1px)}}
.slide{position:relative;overflow:hidden;overflow:clip;clip-path:inset(var(--band) 0 0 0)}
.slide img{user-select:none;-webkit-user-select:none}
/* zoomed, the picture is never dragged out as an image nor held for its menu; at fit it is as it always was */
#viewer.mz-zoomed .slide img{-webkit-user-drag:none;-webkit-touch-callout:none}
/* a pinch on the picture is the picture's, never the page's (the track was pan-x pinch-zoom); while zoomed
   the track is held still and one finger looks around */
.track{touch-action:pan-x;user-select:none;-webkit-user-select:none}
#viewer.mz-zoomed .track{touch-action:none;cursor:grab}
#viewer.mz-dragging .track{cursor:grabbing}
@media (hover:hover) and (pointer:fine){#viewer:not(.mz-zoomed) .slide img.in,#viewer:not(.mz-zoomed) .slide > .fr:has(img.in){cursor:zoom-in}}
/* the way back to fit: a minus sign, set as the map's own − is (map.css .mm-z: 1.2rem, --ink-2, lining
   figures; Sha, Oct 14: "maybe make it say - instead of zoom out?"; it read "zoom out", Oct 13), still
   "Zoom out" to a screen reader. On the back control's baseline: its line box as tall as the back
   control's (1.06rem × 1.55), so its baseline stays where the words' was. On a wide screen on the label's
   column of wall, the glyph where the label's words begin; on a phone where the count was, the glyph at
   the margin. Its box reaches .4rem past the glyph on each side (a negative margin keeps the glyph where
   it is), so a mouse has more than the glyph to hit and the focus ring stands round it evenly; to a finger
   it is a finger's width and height (2.75rem, as the map's −). There, and reachable by Tab, only while
   zoomed */
.ctl.zout{z-index:5;top:calc(var(--top) + .175rem);right:max(var(--g),env(safe-area-inset-right));font-size:1.2rem;line-height:calc(1.06rem * 1.55);color:var(--ink-2);
  font-variant-numeric:lining-nums;white-space:nowrap;padding-inline:.4rem;margin-inline:-.4rem;justify-content:flex-end;
  opacity:0;visibility:hidden;transition:color .25s var(--ease),opacity .3s var(--ease),visibility 0s linear .3s}
@media (min-width:900px){.ctl.zout{right:auto;left:calc(100% - var(--lw,0px) + 1.6rem);justify-content:flex-start}}
@media (min-width:900px) and (max-width:1279.98px){.ctl.zout{left:calc(100% - var(--lw,0px) + 1.2rem)}}
@media (pointer:coarse){.ctl.zout{padding-block:.6rem;margin-block:-.6rem;min-width:2.75rem}}
#viewer.mz-zoomed .ctl.zout{opacity:1;visibility:visible;transition:color .25s var(--ease),opacity .3s var(--ease),visibility 0s}
/* on a phone the control and the count share a place: the one coming waits for the one going (.15 s, when the
   house ease has all but done), so the two are never seen over each other */
@media (max-width:899.98px){#viewer.mz-zoomed .ctl.zout{transition:color .25s var(--ease),opacity .3s var(--ease) .15s,visibility 0s}}
@media (hover:hover) and (pointer:fine){.ctl.zout:hover{color:var(--ink)}}
/* while zoomed the arrows fade out (the track is held still), and on a phone the count and the label's
   line too, so the picture has the screen; they fade back in on the way back to fit. Editing, a phone's
   label stays: it is the form */
#viewer.mz-zoomed .ctl.prev,#viewer.mz-zoomed .ctl.next{opacity:0;visibility:hidden;pointer-events:none;transition:color .25s var(--ease),opacity .3s var(--ease),visibility 0s linear .3s}
@media (max-width:899.98px){
  #viewer .count{transition:opacity .3s var(--ease) .15s,visibility 0s}
  #viewer .label{transition:height .5s var(--ease),opacity .3s var(--ease),visibility 0s}
  #viewer.mz-zoomed .count{opacity:0;visibility:hidden;transition:opacity .3s var(--ease),visibility 0s linear .3s}
  #viewer.mz-zoomed:not(.editing) .label{opacity:0;visibility:hidden;pointer-events:none;transition:height .5s var(--ease),opacity .3s var(--ease),visibility 0s linear .3s}
}
@media (prefers-reduced-motion:reduce){
  .ctl.zout,#viewer.mz-zoomed .ctl.zout,#viewer.mz-zoomed .ctl.prev,#viewer.mz-zoomed .ctl.next,#viewer .count,#viewer.mz-zoomed .count,#viewer .label,#viewer.mz-zoomed:not(.editing) .label{transition:none}
}
