/* The works page's own styling, lifted out of the page on 2026-11-07 (D8).
   Nothing in it names a show — it is page-type styling, so every show's
   works page links this one file instead of carrying its own copy.
   The ground every page shares (background, wash, mat, notch) is in
   ground.css, which is linked BEFORE this and must stay that way: these
   rules came after it inside the page and some of them rely on that. */

#page-wash {
      position: fixed;
      /* NOT `inset: 0`, and the long reason is on `#page-wash` in `text.css`:
         this is a translucent layer over the mat, `inset: 0` makes it as tall as
         the window IS, and on a touch device that changes as Safari's toolbar
         slides back in — so the whole screen had to be re-blended on every frame
         of that animation. `100vh` is the LARGE viewport, the biggest the window
         ever gets, so the wash always covers what can be seen and never resizes.
         On a desktop it is simply the window. */
      top: 0;
      right: 0;
      left: 0;
      height: 100vh;
      background-color: rgba(255, 255, 255, 0.6);
      z-index: 1; pointer-events: none;
    }

    body {
      margin: 0; padding: 0;
      height: 100%; width: 100%;
      overflow: hidden;
      font-family: Georgia, "Times New Roman", serif;
      color: black;
    }

    /* ── THE BOX, AND THE COLUMN BESIDE IT ────────────────────
       The same box as the landing page and the installation views next door: top
       edge 21px down, level with the top of "Mikhael Subotzky" in the menu; left
       edge where every page's content begins; 40px off the right and the bottom.

       THE WORDS GO BESIDE THE PICTURE, NOT UNDER IT (his, 2026-11-05). That one
       move is the whole of this layout, and it is worth saying why, because three
       earlier versions of this page were built the other way round and every one
       of them fought the same fight.

       With a caption and a strip of thumbnails UNDER the picture, the picture's
       bottom edge has to hold still or the words move every time you step. Making
       it hold still took a band locked to a fixed height, a picture box cut to the
       shape of the widest of the forty, and every picture stretched to that box's
       full height — three pieces of machinery, all of them there to stop one edge
       moving. With the words BESIDE the picture there is nothing underneath it, so
       the bottom edge is free and all three come out. What is left is a picture
       that fits its corner and stops where it stops.

       TWO EDGES ARE FIXED AND THAT IS ENOUGH: top and left, the same on all forty
       pictures, works and details alike. Standing rule 23 is the top one. The
       right and bottom edges follow the shape of what you are looking at, which
       is what they should do.

       THE COLUMN IS THE SAME WIDTH ON EVERY WORK and the picture takes what is
       left. 360px is a line length for the caption, and wide enough for two
       thumbnails side by side; the thumbnails WRAP down it instead of running off
       to the right, so a work with ten details shows all ten at once on a laptop.
       That was the cost of the old arrangement and it is paid off here.

       AND IT GROWS WITH THE WINDOW NOW (his, 2026-11-07): "at a small laptop size
       the layout of the captions and thumbnails on desktop makes sense. but when
       you make the screen full on a 16 inch laptop there is too much space... can
       the caption and the thumbnails expand when you do this, with the thumbnails
       getting bigger?"

       WHAT HE WAS LOOKING AT, MEASURED. A 16-inch screen is 1728x1117. The works
       are upright, so the picture is bound by the HEIGHT of the window and not by
       the width: this one renders 797px wide inside a column 1059px wide, and the
       262px to its right is simply empty. The column beside it stayed at 360 and
       the thumbnails at 84 however much room there was.

       SO THE RAMP IS THE WINDOW'S AND NOT THE WORK'S, and that distinction is the
       whole care of it. Sized to the slack beside each picture the column would be
       a different width on every work and would jump sideways every time he
       stepped — and two fixed edges, the same on all forty pictures, is what this
       page is. It reads 100vw and nothing else.

       BOTH ENDS ARE NUMBERS THE SITE ALREADY OWNS. It holds 360 up to 1440, which
       is the laptop he says is right, and reaches 440 by 1728, which is the width
       of one column of the site's own two-column measure (--text-width: 920px is
       440 + 40 + 440, and About and Contact are set in it). So on a big screen
       this column is the same column the rest of the site writes in.

       THE COST, NAMED. The upright works lose nothing: their slack pays for it.
       The PANORAMIC works do pay — they are bound by the width, so the ten-panel
       work renders 1059px wide at 1440 and 979px at 1728, about 7% smaller than
       it would have been. That is the trade, and it is the right way round: the
       works that were wasting space give it up, and the ones that were not give
       up a little so the column can be one width for all of them. */
    #stage {
      width: 100vw;
      height: 100vh;
      position: relative;
      z-index: 6;
      box-sizing: border-box;
      padding: 21px 40px 40px var(--content-left, 229px);
      display: grid;
      grid-template-columns: minmax(0, 1fr) var(--aside-w);
      /* THE ROW IS SPELLED OUT, and it has to be. Left to size itself the single
         row is `auto`, which is indefinite — so `height: 100%` inside it has
         nothing to resolve against, the picture falls back to its own natural
         1800px, and the row grows to meet it. The upright works then ran 300px
         past the bottom of the screen. `minmax(0, 1fr)` makes the row a measured
         share of a box that already knows its height, and the 0 floor stops a
         tall picture pushing it open again. */
      grid-template-rows: minmax(0, 1fr);
      grid-template-areas: "work aside";
      column-gap: 40px;

      /* 360 up to 1440, then straight up to 440 by 1728 — see the note above.
         Written as one clamp so there is one ramp and the thumbnails can hang
         off it rather than carry a second copy of the same two numbers.

         THIS IS NOW THE FLOOR AND NOT THE WIDTH (his, 2026-11-07). He looked at
         the upright work on a 16-inch screen and said the column still does not
         grow — and he was right about what he was seeing: 440px closed 80 of the
         262px of empty mat beside that picture and left 182. So the column is
         allowed to go on growing until it MEETS THE WORK, and the gap it stops
         at is the one the panoramic works already have — the 40px column-gap
         below, and nothing else. fitAside() in viewer.js works the width out per
         work and writes --aside-w on this element; this is what it falls back to
         when the work is bound by the width instead of the height, when the
         script has not run, and on a narrow laptop.

         THE THUMBNAILS STAY ON THIS ONE, deliberately, and not on the width the
         script writes. Their size should answer the screen, as it did yesterday;
         hung off the per-work width they would grow to 167px on an upright work
         and shrink back to 112 on the next panorama, and the strip would resize
         under his hand every time he stepped. */
      --aside-base: clamp(360px, 360px + (100vw - 1440px) * 0.2778, 440px);
      --aside-w: var(--aside-base);
      /* THE CLICK ZONES LIE UNDERNEATH AND MUST STILL BE REACHED. The other two
         pages of this show put the zones last in the file and had to move the
         play sign outside the box to get at it — a box with a z-index of its own
         is painted over wholesale by a later sibling, however high the z-index
         inside it goes. Here the zones come FIRST and the box lets clicks fall
         through to them; the thumbnails, the box over the picture, and the
         column of words take their own back. The column does it by covering
         only its words rather than the whole right-hand side — see the note on
         `#work-aside`, which is where that distinction was bought. */
      pointer-events: none;
    }

    /* Two layers taking turns, the same 1200ms cross-fade as everywhere else.
       Both fill the picture's corner of the grid and both hold their picture at
       the top left of it, so one fades into the next without anything sliding.

       TOP LEFT, AND THAT IS THE WHOLE LAYOUT OF THIS PAGE (his, 2026-11-05).
       Every work, every detail and the top of the column beside them begin at the
       same two edges, and nothing moves sideways or up when you step. Centring
       was tried first and he threw it out in one word: too much jumping around.
       He was right, and the arithmetic says why. The works are portrait and
       landscape in the same set, so a centred picture starts at a different place
       on almost every one of the fifteen. One corner costs nothing, needs no
       measuring, and holds still.

       This reverses the note of 2026-10-24 that said an upright work is centred
       rather than held against the left edge — FOR THIS PAGE ONLY. The landing
       page and the installation page show one picture with nothing beside it and
       keep their centring. */
    .picture-layer {
      grid-area: work;
      width: 100%;
      height: 100%;
      min-width: 0;
      opacity: 0;
      transition: opacity 1200ms ease;
      pointer-events: none;
    }

    .picture-layer.is-current { opacity: 1; }

    /* FIT THE CORNER AND STOP WHERE YOU STOP. No fixed height, no fixed shape:
       whichever of the two edges it meets first is the one that sizes it. This
       is the whole of what replaced the three pieces of machinery described on
       #stage above.

       OBJECT-FIT, AND NOT max-width/max-height, WHICH WAS TRIED FIRST AND IS
       BROKEN HERE. With the picture as a flex item set to `max-width: 100%;
       max-height: 100%`, the five upright works came out 771 wide and over a
       thousand tall and ran off the bottom of the screen: once flex has settled
       the width, the max-height is not allowed to shrink it back. Measured, not
       guessed — works 1, 2, 6, 7 and 11, bottoms at 1042 to 1119 on an 860px
       box. The element here is simply the whole corner and the picture is drawn
       inside it, held to its top left, which no layout mode can argue with.

       The consequence to know: the ELEMENT is the full corner, so its edges are
       not the picture's edges. Anything measuring where a picture ends has to
       work it out from the file's own shape, not from the box. */
    .picture-layer img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: contain;
      object-position: left top;
    }

    /* The spare layer before it has ever been given a picture: a full-size empty
       box would otherwise be a full-size broken-image mark in some browsers. */
    .picture-layer img:not([src]) { display: none; }

    /* While a picture is being fetched. A plain dim, not a spinner, because
       nothing else on this site has one. */
    .picture-layer.is-loading img {
      opacity: 0.6;
      transition: opacity 200ms ease;
    }

    /* ── THE COLUMN ──────────────────────────────────────
       The caption, and under it the work's details. It starts at the same height
       as the picture and is the same width on every work, so neither of them
       moves when you step.

       IT SCROLLS ONLY IF IT HAS TO. A work with ten details and a four-line
       caption is the tallest case and it fits a laptop; the overflow is here so
       that a short window shortens the column rather than pushing it off the
       bottom of the screen. */
    #work-aside {
      grid-area: aside;
      min-width: 0;
      /* AS TALL AS ITS WORDS, AND NO TALLER — capped at the screen, where it
         starts to scroll. It was `height: 100%` and a full-height box, which is
         what forced it to be transparent to clicks: a full-height box over the
         right-hand half of the screen would have swallowed every tap meant for
         the mat. Sized to its content it covers only the words, so it can take
         its own touches and the mat below it still steps. See the note under
         the rule below for why that mattered. */
      align-self: start;
      max-height: 100%;
      display: flex;
      flex-direction: column;
      gap: 18px;
      overflow-y: auto;
      overscroll-behavior-y: contain;
      scrollbar-width: thin;
      scrollbar-color: rgba(0, 0, 0, 0.25) transparent;
      /* AND IT CAN BE GRABBED. A scroller that is transparent to pointers
         cannot be dragged on a touch screen at all — see below. */
      pointer-events: auto;
    }

    /* ── WHY THE COLUMN TAKES ITS OWN TOUCHES (his, twice, 2026-11-09) ──
       His first report, on his own iPad held sideways: on a work with a wall
       text the column "is not scrolling down". It was not scrolling at all.

       WHAT WAS WRONG. The column is a scroller, and it carried
       `pointer-events: none` so that the mat beside the picture went on
       stepping from work to work. Hit-testing skips an element with no pointer
       events, so a finger dragged down the wall text never reached the
       scroller. Measured on An Idea of Africa at 1024x768: the column is 707px
       tall and its content 1087, so 380px of his wall text sat below the bottom
       of the screen with no way to get to it, and the drag stepped to the next
       work instead.

       AND THE FIRST FIX DID NOT WORK, WHICH IS THE PART WORTH KEEPING. It gave
       the caption and the wall text `pointer-events: auto` and left the
       scroller itself transparent, on the reasoning that a touch landing on a
       paragraph would pan its nearest scrollable ancestor. **A mouse wheel in
       the browser pane does exactly that, which is how it passed; iOS Safari
       does not.** He looked at it on the real iPad and said: *"still not
       scrolling at all."* A scroller that cannot itself be hit is not a
       scroller a finger can use, whatever is inside it. Rule 6 is in this file
       for a reason and the pane cannot stand in for the device.

       SO THE SCROLLER TAKES ITS OWN TOUCHES, and the full-height box that made
       that impossible is gone: `align-self: start` with `max-height: 100%`
       above, so the column is as tall as its words and no taller. It covers
       the caption, the thumbnails and the wall text, and nothing else — the mat
       below it, beside it and under the picture is untouched and goes on
       stepping, which is the behaviour that had to survive.

       WHAT IT COSTS, NAMED: a tap on the words themselves no longer steps. On
       the twelve works with no wall text that is about sixty pixels of caption;
       on the three that have one, at a size where the text fills the screen, it
       is the column. The "Next work" control sits outside the column's right
       edge and the mat under the picture still steps, so nothing is out of
       reach. This is not something a session can split more finely: being able
       to drag the words and being able to tap through them are the same
       property, and he asked for the drag. */

    /* THE CAPTION IS THE WORK'S AND DOES NOT MOVE when you step into a detail
       (his, 2026-11-04) — which is also what stops a detail sitting there
       unlabelled. It is Mikhael's own Lightroom caption, read off the file:
       title and year, materials, dimensions, edition, one per line. */
    #work-caption {
      margin: 0;
      font-size: 13px;
      line-height: 1.5;
      white-space: pre-line;
      color: black;
      opacity: 0.75;
    }

    /* ── THE WALL TEXT (his, 2026-11-07) ─────────────────────
       "i'd like to add explanatery text underneath the captions in this view of
       some of the works" — of SOME of them, so it lives on the work and not on
       the page: a work with no `essay` in its entry leaves this hidden and its
       column is exactly what it was.

       UNDER THE THUMBNAILS (his, 2026-11-07). It went above them on the first
       try, which is where his words put it — underneath the caption — and he
       looked at it and said under the thumbnails. It is the better order for a
       second reason: the details are how you go INTO a work, and a long read
       above them pushed them down the column, so on a 900px-tall laptop the
       thumbnails for this work started below the fold.

       IT IS BIGGER THAN THE CAPTION NOW, and that is a change of mind. Yesterday
       it was 13px, the caption's size, on the grounds that one voice about one
       work should not be set in two sizes. He asked whether it was readable at
       that size, which is the answer: the caption is four lines of data read at
       a glance and this is two paragraphs read in sentences, so they are not one
       thing and need not be one size.

       AND IT GROWS WITH THE COLUMN, because the column is no longer one width.
       fitAside() can take it to 680px on an upright work, and 13px across 680 is
       a hundred characters to the line, which is past reading. 15px at the floor
       to 19px at the ceiling holds the line at roughly 55 characters on a narrow
       laptop and 72 at the widest, which is the usual range. Black at 0.75, as everything in this column is — standing
       rule 24, and the menu and the index are the site's only two exceptions. */
    #work-essay {
      font-size: clamp(15px, calc(15px + (var(--aside-w) - 360px) * 0.0125), 19px);
      line-height: 1.65;
      color: black;
      opacity: 0.75;
    }

    #work-essay[hidden] { display: none; }

    /* The flex gap above does the separating, so the first paragraph carries no
       top margin of its own and the block starts where the column says. */
    #work-essay p { margin: 0 0 0.9em 0; }
    #work-essay p:last-child { margin-bottom: 0; }

    /* The work's details. THEY WRAP DOWN THE COLUMN now (his, 2026-11-05),
       where before they ran off to the right in a single row that scrolled. The
       old note here said a second row stopped reading as the parts of the work
       and started reading as a grid of its own; that was true when the row sat
       under the picture and ran the width of the screen. In a column 360px wide,
       two abreast, they read as what they are.

       THEY STAND IN FIXED COLUMNS, NOT WHEREVER THEY FALL (his, 2026-11-05).
       Packed loosely, one wide picture pushed every upright after it out of
       true, so the three uprights on the top row stood nowhere near the five
       below them and the slack collected at the right-hand end of the row. Now
       the uprights set a column width and the wide picture spans whole columns
       of it, which puts the slack between the wide picture and the upright
       after it and leaves every other row standing on the same lines.

       The column width is `--thumb-col`, measured per work by layOutStrip() in
       viewer.js — it cannot be a constant here, because each work's details are
       a different shape. Since 2026-11-12 that function also chooses how many
       columns a work uses and writes each thumbnail's place, so that the rows
       end on one line; the note there says how.

       `auto-fill` and not `auto-fit`, so a short row keeps the columns of a
       long one instead of stretching to swallow them.

       `justify-items: start` so a picture that spans two columns is the picture
       and not the two columns: without it the button stretches to the cell and
       the dead space to its right is clickable. */
    #detail-strip {
      display: grid;
      grid-template-columns: repeat(auto-fill, var(--thumb-col, 84px));
      justify-items: start;
      align-items: start;
      gap: 6px;
      margin: 0;
      padding: 0;
      pointer-events: auto;
    }

    #detail-strip[hidden] { display: none; }

    /* THE FIRST THUMBNAIL IS THE WORK ITSELF, which is how you come back out of
       a detail — no extra control, and the strip reads as the work and then its
       parts. The one you are on is at full strength and the rest at 0.55, the
       value this site uses everywhere for a quiet mark. */
    .detail-thumb {
      border: 0;
      margin: 0;
      padding: 0;
      background: none;
      line-height: 0;
      cursor: pointer;
      opacity: 0.55;
      transition: opacity 200ms ease;
    }

    .detail-thumb img {
      display: block;
      /* THE THUMBNAILS GROW WITH THE COLUMN (his, 2026-11-07) — 84px while it is
         360 wide, 112px once it reaches 440. Derived from --aside-base rather
         than given a clamp of its own, so there is one ramp on this page and not
         two that can drift apart: 80px of column buys 28px of thumbnail. The
         BASE and not the width the script writes — the reason is on #stage.

         THE FILES WERE RE-EXPORTED FOR THIS AND THE OLD ONES ARE GONE. They were
         160px tall, chosen when 84px was the only size — 1.90x, just inside what
         a retina screen asks for. At 112px that same file is a 1.4x upscale and
         goes soft, which is the one thing a page of paintings cannot do. The 40
         thumbnails are now 320px tall in works_thumbs_v2/, which is 2x the 112
         with room over, and AVIF took four times the pixels for 404 KB -> 781 KB.
         A NEW DIRECTORY AND NOT NEW NAMES IN THE OLD ONE: the path is the cache
         key (standing rule 3), so works_thumbs/ -> works_thumbs_v2/ gives all 40
         a new URL in one move and keeps the filenames readable.

         layOutStrip() in viewer.js READS this height off the DOM rather than
         being told it, and runs again on resize, so the column widths and the
         spans follow on their own and nothing here has to tell it the number. */
      height: calc(84px + (var(--aside-base) - 360px) * 0.35);
      width: auto;
      /* AND NEVER WIDER THAN THE COLUMN IT SITS IN. layOutStrip() already clamps
         a thumbnail's grid SPAN to the number of columns the aside holds, but the
         image inside that cell had only a height and a free width, so a very wide
         one still hung off the side: work 5 cropped to its eight framed panels is
         6.14 to 1, and at 100px tall it wanted 614px of a 404px strip — measured,
         207px over. `object-fit: contain` is what keeps the shape while max-width
         does the clamping; without it the picture would simply be squashed.

         The explicit `height` stays, and must: layOutStrip() reads it back off
         this first thumbnail to size every column. Letting the box shrink instead
         would hand it 66px and quietly shrink the whole strip. */
      max-width: 100%;
      object-fit: contain;
    }

    /* A WIDE THUMBNAIL GIVEN ONE COLUMN FEWER THAN IT ASKED FOR — a landscape set
       on two columns, which is a shade narrower than it is — fills that box and
       loses a sliver from each side, so its edges are the grid's (his,
       2026-11-12). layOutStrip() says which. Everything else stays `contain`. */
    .detail-thumb.is-trimmed img { object-fit: cover; }

    .detail-thumb.is-current,
    .detail-thumb:hover { opacity: 1; }

    .detail-thumb:focus-visible {
      outline: 1px solid rgb(80, 25, 30);
      outline-offset: 2px;
    }

    /* The two halves of the screen you click to step through, with the same drawn
       cursors as the works, the views and the book. They lie UNDER the box —
       see the note on #stage. The second level has its own pair, inside its own
       panel, so while it is open these are covered rather than competing with
       it; they are the same thing and so they are the same rules. */
    .step-back, .step-on,
    .second-back, .second-on {
      position: absolute;
      top: 0;
      height: 100%;
      width: 50%;
      z-index: 5;
    }

    .step-back, .second-back {
      left: 0;
      cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Ctext x='10' y='25' font-size='16' fill='%23501219' font-family='Helvetica, sans-serif'%3E%E2%86%90%3C/text%3E%3C/svg%3E") 12 12, w-resize;
    }

    .step-on, .second-on {
      right: 0;
      cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Ctext x='10' y='25' font-size='16' fill='%23501219' font-family='Helvetica, sans-serif'%3E%E2%86%92%3C/text%3E%3C/svg%3E") 12 12, e-resize;
    }

    /* ── THE PICTURE ITSELF IS A WAY IN ───────────────────────────────────
       His, 2026-11-05: hovering and clicking the big picture should do what a
       thumbnail does — open the second level — while the two halves of the
       screen go on stepping from work to work over the mat around it.

       IT IS ITS OWN BOX AND VIEWER.JS SIZES IT. The picture layer is the whole
       corner of the grid with the picture drawn inside it by object-fit, so its
       edges are not the picture's edges (see the note on .picture-layer img).
       Letting the layer take clicks would make the empty mat beside a portrait
       work clickable too and put the arrows out of reach. This button is held
       at the same top left corner and given the picture's own width and height
       by fitPictureHit(), so it covers the picture and nothing else. */
    .picture-hit {
      grid-area: work;
      align-self: start;
      justify-self: start;
      width: 0;
      height: 0;
      border: 0;
      margin: 0;
      padding: 0;
      background: none;
      cursor: pointer;
      pointer-events: auto;
    }

    .picture-hit:focus-visible {
      outline: 1px solid rgb(80, 25, 30);
      outline-offset: 2px;
    }

    /* The phone's column of every work and every detail, built by script and
       empty on a wide screen, where it is display:none and so never fetches
       anything. */
    #picture-scroll { display: none; }

    #error-message {
      position: absolute;
      top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      background-color: rgba(0, 0, 0, 0.8);
      color: white;
      padding: 15px 20px;
      border-radius: 2px;
      font-size: 14px;
      z-index: 20;
      display: none;
    }

    #error-message.visible { display: block; }

    /* ── THE SECOND LEVEL ─────────────────────────────────────────────────
       His, 2026-11-05, from Artlogic's private view: click a thumbnail and the
       work's pictures fill the window, one at a time, big.

       IT COVERS EVERYTHING, THE MENU INCLUDED (z-index 30 against the menu's
       20 and 23). That is the point of it — there is nothing to read here but
       the picture — and it is why the way out has to be plain: the mark at the
       top right, or Escape.

       `is-open` CARRIES BOTH THE FADE AND THE VISIBILITY, and `hidden` is kept
       for the hard off. Fading something out with `hidden` cannot be done —
       `display: none` lands the instant it is set — and doing it with a timer
       races against a second click. `visibility` transitions in one step, so it
       is held back until the fade has finished on the way out and applied at
       once on the way in. It also takes the panel out of the tab order while it
       is closed, which `opacity: 0` alone would not. */
    #second-level {
      position: fixed;
      inset: 0;
      z-index: 30;
      box-sizing: border-box;
      /* THE 40px MARGIN IS ON WHAT IS INSIDE, NOT ON THIS — and that is not a
         preference. An absolutely positioned child is laid out against its
         ancestor's PADDING box, so a padding here would hold the two click
         halves 40px in from every edge and leave a dead band all the way round
         that looks clickable and is not. */
      padding: 0;
      /* A wash, not flat white: the mat and the menu stay faintly visible
         underneath, so this reads as something laid over the page rather than a
         new page. All three values are his, 2026-11-05, in this order: 0.97
         covered too much of what is behind, 0.90 let too much through, 0.95 is
         where he settled. */
      background-color: rgba(255, 255, 255, 0.95);

      /* NOT TWO ROWS OF A GRID ANY MORE (his, 2026-11-05). The caption used to
         have a row of its own with the picture in the row above, and a row above
         can only ever put the picture ABOVE the words. He wants an upright
         picture to come all the way down to the line the words end on, with the
         words standing beside it — so the picture and the words are each placed
         against this box's own edges and viewer.js works out how much height the
         picture may take, in fitPanelPicture(). */

      opacity: 0;
      visibility: hidden;
      transition: opacity 300ms ease, visibility 0s linear 300ms;
    }

    #second-level.is-open {
      opacity: 1;
      visibility: visible;
      transition: opacity 300ms ease, visibility 0s;
    }

    #second-level[hidden] { display: none; }

    /* AND WHILE IT IS CLOSED IT TAKES NO CLICKS. A GUARD, NOT A FIX — AND THE
       FAULT IT WAS WRITTEN FOR TURNED OUT NOT TO EXIST.

       WHAT WAS REPORTED, AND WHY IT WAS WRONG. B30 found that after one visit to
       the second level the panel stayed in the page at `opacity: 0` with
       `visibility: visible`, its two click halves lying over the whole screen, so
       every click on the first level landed on `second-on` and did nothing. It
       was measured two full seconds after the close, on www.subotzkystudio.com
       itself, with no class and no inline style on the element, and Mikhael was
       told the works page stops responding until it is reloaded. **IT DOES NOT.**
       The browser pane those measurements were taken in was running at about one
       animation frame a second, so the `visibility 0s linear 300ms` transition
       never advanced and `getComputedStyle` went on returning the value it
       started from. Driven to its end by hand — `getAnimations().finish()` — the
       panel reaches `visibility: hidden`, the page centre returns `picture-hit`
       and the right-hand half returns `step-on`, which is what they return before
       the panel is ever opened. The stylesheet was right all along. Standing rule
       30 is this lesson.

       WHY THE RULE STAYS ANYWAY. It costs nothing, it is true of a closed panel
       whether or not a transition has run, and it closes the one real gap left:
       for the 300ms the fade takes, the panel is still hit-testable, so a click
       on the side of the screen in that moment goes to the second level's halves
       rather than the first level's. Hit-testing should not be waiting on an
       animation to end. If he would rather the page carried only what it needs,
       this comes out in one move and nothing visible changes.

       IT HAS TO REACH THE CHILDREN, which is why the second selector is here:
       `pointer-events: none` on a parent is overridden by any descendant that
       sets it back to `auto`, and both click halves do. */
    #second-level:not(.is-open),
    #second-level:not(.is-open) * { pointer-events: none; }

    /* Two layers taking turns, as everywhere else on the site — but at 300ms, a
       quarter of the 1200ms the first level and the landing page use. Ten panels
       of one work are something you step through quickly, comparing them, and a
       long double exposure between each is the wrong speed for that. 600ms was
       tried first; 300 is his, 2026-11-05.

       21px AT THE TOP IS THE FIRST LEVEL'S OWN TOP LINE (his, 2026-11-05) —
       #stage's top padding, which is where the menu's name starts too. Every
       picture on both levels hangs from that one line now, so opening the second
       level does not move the top of the picture you were already looking at.

       70px AT THE SIDES, so that nothing ever runs underneath the two work
       marks. Measured: on a TALL window — 1600 × 1200, which is a desk screen —
       the widest pictures here (1800 × 1132) fill the box's width and their left
       edge lands at exactly 40, which is the line the left mark now stands on.
       70 leaves 15px of air beside it and the same at the other end. It costs a
       width-filling picture 60px, and only on a window that shape; on a laptop
       every picture is held by its height and never comes near either mark.

       `bottom` IS THE NO-SCRIPT FALLBACK AND NOTHING ELSE: fitPanelPicture()
       sets an explicit `height`, and top plus height wins over it. */
    .second-layer {
      position: absolute;
      left: 70px;
      right: 70px;
      top: 21px;
      bottom: 40px;
      opacity: 0;
      transition: opacity 300ms ease;
      pointer-events: none;
    }

    .second-layer.is-current { opacity: 1; }

    .second-layer img {
      display: block;
      width: 100%;
      height: 100%;
      /* CENTRED ACROSS AND HELD TO THE TOP. Across, because there is nothing
         beside it here to line up with; to the top, because the first level
         holds every picture to the top of the same line and he wants the two
         levels to agree. The box is the whole of what the picture may use, so
         holding it to the top is also what lets an upright one reach the bottom
         of the words. */
      object-fit: contain;
      object-position: center top;
    }

    .second-layer img:not([src]) { display: none; }

    /* ON THE WINDOW'S OWN BOTTOM EDGE, not under the picture — which is what
       lets an upright picture come down the middle and the words stand beside
       it rather than below it. */
    .second-words {
      position: absolute;
      left: 40px;
      right: 40px;
      bottom: 40px;
      display: flex;
      align-items: flex-end;
      justify-content: space-between;
      gap: 24px;
      pointer-events: none;
    }

    /* The same type as the caption in the first level, because it is the same
       caption: the work's, not the detail's. */
    #second-caption, #second-count {
      margin: 0;
      font-size: 13px;
      line-height: 1.5;
      white-space: pre-line;
      color: black;
      opacity: 0.75;
    }

    #second-count { white-space: nowrap; }

    /* THE MARK ON A DETAIL'S CAPTION — `DETAIL:` AT THE HEAD OF THE TITLE'S OWN
       LINE (his, 2026-11-11: "the image size jumps when you go from a full work
       to a detail because the word DETAIL is an extra line in the caption. Can
       we please change this to DETAIL: followed by the title on the same
       line?"). From 2026-11-05 it stood on a line of its own above the caption;
       where the caption sits under the picture that line came out of the
       picture's height, so stepping from the work to its first detail made the
       picture 23px shorter. On the title's line it costs nothing.

       WHAT IS KEPT FROM THE FIRST VERSION: smaller, spaced out and quieter, so
       it still reads as something said ABOUT the caption rather than as one of
       the caption's own words, which are the work's and are set exactly as he
       wrote them. 0.7 inside the caption's own 0.75 comes to about 0.52, the
       strength this site gives a quiet mark everywhere else. 11px inside a 13px
       line does not make the line any taller. The word is written in the script
       as `Detail:` and set in capitals here, so a screen reader says a word. */
    #second-caption .detail-tag {
      margin-right: 6px;
      font-size: 11px;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      opacity: 0.7;
    }

    #second-close {
      position: absolute;
      top: 10px;
      right: 16px;
      z-index: 6;
      border: 0;
      margin: 0;
      padding: 6px 10px;
      background: none;
      cursor: pointer;
      font-family: inherit;
      font-size: 22px;
      line-height: 1;
      color: black;
      opacity: 0.55;
      transition: opacity 200ms ease;
      pointer-events: auto;
    }

    #second-close:hover { opacity: 1; }

    #second-close:focus-visible {
      outline: 1px solid rgb(80, 25, 30);
      outline-offset: 2px;
    }

    /* ⚠ AND THEY WERE OFF THIS PAGE FOR ONE AFTERNOON, 2026-11-08, WHICH WAS A
       MISREADING. His instruction was *"the previous work and next work buttons
       need to be taken off this page"*, meaning the grid — and he said so
       plainly when he saw them gone from the slideshow too: *"Once you click
       into any of the works i want them to return and then the slideshow
       operates exactly like it used to."* So this block is exactly what it was,
       restored from ff857f4, and the ONE line below is the whole change: they
       are hidden while the grid is up, where there is no work to step from.
       viewer.js puts `grid-is-up` on the root; see openGrid(). */
    html.grid-is-up .work-step { display: none; }

    /* ── THE TWO WORK MARKS ───────────────────────────────────────────────
       His, 2026-11-05: a way to the next and the previous WORK that is there on
       both levels of the slideshow, halfway up the page.

       THEY ARE ONE PAIR, NOT TWO, and that is the whole of their position. They
       are fixed to the window above both levels (z-index 40, over the second
       level's 30), so they are in the same place whichever level you are on and
       nothing jumps when you open or close it.

       THEY ARE WORDS, NOT ARROWS, BECAUSE THE ARROWS ARE TAKEN. The two halves
       of the screen already show a drawn ← and → on hover, and in the second
       level those step from one picture of a work to the next. A third and a
       fourth arrow meaning something else would be four arrows and two
       meanings. Words say which is which and need no key.

       THEY READ UP THE LEFT EDGE AND DOWN THE RIGHT, like the spine of a book —
       which is also what makes them fit. Set across, "Previous work" is about
       85px wide and there is no 85px anywhere on the left: the menu runs to
       about 176px and the page's text begins at 229. Set up the edge it is
       20px wide and sits in the gap between them, measured rather than guessed.

       The left one hangs off `--content-left`, the measurement nav.js takes of
       the menu, so a longer menu moves it rather than running into it. */
    .work-step {
      position: fixed;
      top: 50%;
      transform: translateY(-50%);
      z-index: 40;
      border: 0;
      margin: 0;
      padding: 12px 3px;
      background: none;
      cursor: pointer;
      font-family: inherit;
      font-size: 12px;
      letter-spacing: 0.08em;
      line-height: 1;
      color: black;
      opacity: 0.55;
      transition: opacity 200ms ease, left 300ms ease;
    }

    .work-step:hover { opacity: 1; }

    .work-step:focus-visible {
      outline: 1px solid rgb(80, 25, 30);
      outline-offset: 2px;
    }

    .work-step span {
      display: block;
      white-space: nowrap;
      writing-mode: vertical-rl;
    }

    /* Bottom to top on the left, top to bottom on the right: the two read
       outwards from the picture, the way the two halves of the screen do. */
    .work-prev { left: calc(var(--content-left, 229px) - 40px); }
    .work-prev span { transform: rotate(180deg); }

    .work-next { right: 14px; }

    /* IN THE SECOND LEVEL THE LEFT ONE MOVES OUT TO THE CAPTION'S LINE (his,
       2026-11-05). The first level's picture begins at --content-left and the
       mark sits in the gap before it; the second level's picture is only 40px
       from the window on every side, and at some window sizes a wide panel
       reached back underneath the mark. The caption below it starts at 40, so
       the mark lines up with it: 37 plus the 3px of padding round the glyph.
       It slides rather than jumps, on the same 300ms as the wash it moves
       against. The right one does not move — the picture never reaches it. */
    #second-level.is-open ~ .work-prev { left: 37px; }

    /* ── THE WAY BACK OUT OF A WORK ───────────────────────────────────────
       His, 2026-11-08: "the previous work and next work buttons need to be taken
       off this page." What stood here was a pair of words set up the left edge
       and down the right — Previous work, Next work — fixed above both levels so
       that moving along the show never depended on which level you were standing
       in. They came from 2026-11-05, when the works page's first level WAS the
       way through the show. It is not any more: the grid in front of it is, and
       a work is a thing you open from there and close again.

       SO THERE IS ONE MARK, AND IT IS THE SECOND LEVEL'S OWN, ONE LEVEL OUT.
       Same glyph, same corner, same strength, because it means the same thing a
       step further back — close this, go to what it was in front of. Nothing is
       invented and nothing new has to be learnt. It hides while the second level
       is open, so a cross never sits under a cross, and it hides on the grid,
       where there is nothing to close. */
    #work-close {
      position: fixed;
      top: 14px;
      /* IN THE MAT, NOT OVER THE WORDS. The stage keeps 40px off the right of
         the window and the caption column runs right up to that line, so a mark
         at the second level's own 16px sat on top of the caption's longest
         lines — measured at 1440 wide, where the column ends at 1400 and the
         mark ran 1390 to 1424. 3px puts the whole of it in the margin beyond the
         column, at every window width, because that 40px does not change. */
      right: 3px;
      /* Above the second level's wash (30) for the same reason the work marks
         were: it is a control of the page, not of a level inside it. */
      z-index: 41;
      border: 0;
      margin: 0;
      padding: 6px 10px;
      background: none;
      cursor: pointer;
      font-family: inherit;
      /* BIGGER AND BOLDER THAN THE SECOND LEVEL'S (his, 2026-11-08). The two
         were deliberately identical at first, so that one cross meant one thing
         wherever it stood — but this one closes a work over the page's own pale
         mat, where 22px at 0.55 reads as a mark someone forgot to delete, while
         the second level's sits on a wash with a photograph behind it. So this
         is 30px, at 500, at 0.7. It is the same glyph in the same corner, which
         is what carries the meaning; it is only easier to see and to hit. */
      font-size: 30px;
      font-weight: 500;
      line-height: 1;
      color: black;
      opacity: 0.7;
      transition: opacity 200ms ease;
    }

    #work-close:hover { opacity: 1; }

    #work-close:focus-visible {
      outline: 1px solid rgb(80, 25, 30);
      outline-offset: 2px;
    }

    #work-close[hidden] { display: none; }

    /* THE PHONE'S WASH IS OFF EVERYWHERE ELSE, and this is where that is said —
       before the phone block, because the two rules have the same weight and the
       later one wins. A wide screen has level two for this job. */
    #work-wash { display: none; }

    /* AND SO ARE THE TWO WORDS. A wide screen has the work marks for this and
       has had them since the page was built; these exist because a phone had a
       swipe and nothing that said so. */
    #work-steps { display: none; }

    /* While the second level is open, its own cross is the one that means
         something — and the two would otherwise sit in the same corner. */
    #second-level.is-open ~ #work-close,
    #second-level.is-open ~ #work-steps { display: none; }

    /* A NARROW LAPTOP GIVES THE COLUMN BACK TO THE PICTURE. Between 800px (where
       the phone's scroll takes over) and 1200px the picture is the thing being
       squeezed, not the words: at 1280 the full column leaves it 611px and this
       leaves it 691. The caption wraps one line more and that is the cheaper
       loss. The thumbnails still sit two abreast. */
    @media (min-width: 801px) and (max-width: 1200px) {
      #stage { --aside-base: 280px; column-gap: 28px; }
    }

    /* An iPad is touched but not short, so it keeps the slideshow and only needs
       the measured screen height — the same exception the other two pages make. */
    @media (pointer: coarse) and (min-width: 768px) {
      #stage { height: calc(var(--vh, 1vh) * 100); }
      .step-back, .step-on { height: calc(var(--vh, 1vh) * 100); top: 0; }
    }

    /* ── THE PHONE: A SCROLL, NOT A SLIDESHOW ─────────────────────────────
       The treatment the landing page, the works and the views all take (his,
       2026-10-24), to the same measurements. There is no strip here and nothing
       to click into: a work is followed by its caption and then by its own
       details, and the next work begins after them. The hierarchy is read by
       position, which is what a scroll is good at. */
    @media (max-width: 800px), (orientation: portrait) and (pointer: coarse), (max-height: 500px) and (pointer: coarse) {
      /* ================= B39 — THE WASH GOES TO THE TOP =================
         HIS, 2026-11-08: "i actually think that the wash should go all the way
         to the top on mobile and the X to close the slideshow can go over the
         Mi of Mikhael Subotzky that is under the wash.... please also move the
         line that the scroll disappears under proportional up with it."

         THE WHOLE CHANGE IS FOUR VALUES AND TWO RULES, AND THE OLD ONES ARE
         WRITTEN HERE SO IT CAN BE PUT BACK WITHOUT READING ANY HISTORY — he
         asked for that in as many words. To undo it, either `git revert` the
         one commit, or set these four back:

             #stage      top     calc(var(--nav-bottom, 40px) + 44px)
             #stage      height  calc(... - var(--nav-bottom, 40px) - 44px)
             #stage      z-index 25 → delete the line (6 is inherited)
             #work-wash  top     calc(var(--nav-bottom, 40px) - 4px)
             #work-wash  z-index 24 → 5
             #work-close top     calc(var(--nav-bottom, 40px) - 1px)

         and delete the two `html.nav-is-open` rules below. Nothing else on the
         site is touched: every value here is inside the phone block of this one
         file, and a wide screen never reads any of it.

         WHAT THE 44px WAS, since it is gone. The close mark had to be fixed — a
         work with ten details is a long scroll and a mark at the top of it would
         be gone by the second picture — and it could not go in the menu bar,
         where the name is at one end and the two lines that open the menu at the
         other. So it stood in a strip of its own between them, 44px deep,
         because that is the mark's own box. The mark is now ON the name, which
         is the thing he decided, so the strip has no job left and the scroll
         takes it: that is the "proportional up" he asked for, and it is 34px of
         screen back on every work. 10px is what is left, and it is not a new
         number — `#work-grid` already starts at `--nav-bottom + 10`, so the grid
         and the column now begin on exactly the same line. */
      #stage {
        position: fixed;
        top: calc(var(--nav-bottom, 40px) + 10px);
        left: 0;
        padding: 0;
        box-sizing: border-box;
        height: calc(var(--screen-height, 100vh) - var(--nav-bottom, 40px) - 10px);
        /* ABOVE THE MENU BAR (23), because the wash now has to be above it too —
           see #work-wash. The column must stay over the wash or the pictures
           would be washed out themselves. */
        z-index: 25;
        width: 100vw;
        display: block;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
        pointer-events: auto;
      }

      /* LEVEL TWO'S WASH, BEHIND THE PHONE'S ONE WORK (his, 2026-11-08: "i
         think we should try this with the same white overlay that is behind the
         images and text (over the cutting matt) on level two of the desktop
         slideshow"). The value is his settled one from 2026-11-05 and is written
         here the same way it is written on `#second-level` — 0.95, over the
         page's own 0.6 wash, which is exactly the stack the desktop panel sits
         on, so the two match without either having to know about the other.
         Change one and change both; there is no shared token for it yet.

         IT IS AN ELEMENT OF ITS OWN, OUTSIDE #stage, AND THAT IS NOT TIDINESS —
         IT IS THE BUG. It was a `#stage::before` first. That works in a desktop
         browser and does not work on an iPhone: #stage is the scrolling box, and
         WebKit makes a scroller with `-webkit-overflow-scrolling: touch` the
         containing block for a fixed child, so the wash was clipped to the stage
         and began exactly where the first picture begins — no wash above the
         photograph, a white page below it. He sent a screenshot of it. The
         markup for `#work-wash` is in the works page, with the same note.

         It cannot be a background on #stage either, for the older reason: the
         stage starts 44px below the menu, in the strip the close mark stands in,
         so a background there would leave a seam with the cross above it on bare
         mat. The menu itself is left clear: on a phone it is the way out, which
         is the opposite of the desktop panel's reason for covering it.

         ITS TOP EDGE IS HALFWAY BETWEEN THE MENU AND THE CLOSE MARK, and that is
         what the -4px is (his, 2026-11-08: "the wash should extend to halfway
         between the X and the Mikhael Subotzky and humberguer on mobile"). It
         began at `--nav-bottom` exactly, which measured: the menu's lowest ink —
         the descender of "Subotzky" — ends 9.4px above that line, and the
         cross's own ink begins 2.5px below it. So the edge was sitting in the
         bottom quarter of the gap and reading as if it were cutting the cross
         off. Halfway is 3.45px up; 4 is that, rounded, and it is written against
         `--nav-bottom` rather than as a number because both the menu and the
         mark are placed off that line and move with it. */
      #work-wash {
        display: block;
        position: fixed;
        /* THE TOP OF THE SCREEN, NOT THE BOTTOM OF THE MENU BAR (B39, his). It
           began 4px above `--nav-bottom`, at the midpoint of the gap between the
           menu's ink and the cross's — the edge he drew on 2026-11-08. He looked
           at it and went further: there is no edge now, and the white is one
           field from the top of the screen to the bottom. */
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(255, 255, 255, 0.95);
        /* OVER THE MENU BAR (23), WHICH IS THE POINT AND IS NOT FREE. It was 5 —
           over the page's own 0.6 wash and under the column — and at 5 a wash at
           `top: 0` would have slid UNDER the name and the two lines, leaving them
           crisp black on white. He asked for the opposite in as many words: "the
           Mi of Mikhael Subotzky THAT IS UNDER THE WASH". So the name is seen
           through the 0.95, at the same strength as the mat behind it, and the
           cross can stand on it without two black marks colliding.

           THE COST, AND IT IS WHY THE TWO RULES BELOW EXIST: the two lines that
           open the menu are in that same bar and go just as faint. That is fine
           while a work is being read and NOT fine once the menu is open, so the
           menu's own class drops both this and the column back under it. */
        z-index: 24;
        pointer-events: none;
      }

      /* THE MENU WINS WHILE IT IS OPEN. `nav-is-open` is the site's own class,
         put on <html> by the menu itself, so this needs nothing new to be kept
         in step. Without it the menu opens BEHIND the column — tested, and it is
         unreadable. The numbers are the ones this file used before B39. */
      html.nav-is-open #work-wash { z-index: 5; }
      html.nav-is-open #stage { z-index: 6; }

      /* AND THE WORK'S CROSS GOES, for the reason the second level's rule above
         already gives: a cross never sits under a cross, and the menu's own is
         the one that means something while it is open. This only became a
         collision when the mark moved onto the name — the menu's name is crisp,
         and the mark was landing on its "M". */
      html.nav-is-open #work-close { display: none; }
      /* Nothing to stand on the grid: the grid has its own ground, and the two
         washes over each other would be flatter than either. The class is the
         one viewer.js already puts on <html> when the grid is up, so there is
         one description of where the grid's furniture appears. */
      html.grid-is-up #work-wash { display: none; }

      #picture-scroll {
        display: flex;
        flex-direction: column;
        width: 100%;
        box-sizing: border-box;
        padding-left: max(14px, env(safe-area-inset-left));
        padding-right: max(14px, env(safe-area-inset-right));
        padding-bottom: calc(30px + env(safe-area-inset-bottom));
      }

      .picture-scroll-item { margin-bottom: 26px; }
      /* `:last-child`, NOT `:last-of-type`, AND THAT ONE WORD WAS THE CAPTION
         OVERLAP (his, 2026-11-08: "on the vertical images like jacaranda and
         wendy house the caption is overlapping with the bottom of the images").
         The rule only means "no trailing margin at the very end of the column",
         and `:last-child` says exactly that: it matches a picture that nothing
         follows. `:last-of-type` matched the last DIV among the children, which
         in a column of the whole show was the final detail of the final work —
         harmless enough, and nobody looked again when the column became ONE
         WORK. On a work with no details that one picture then became the last
         div, lost its 26px, and the caption's own -14px pulled it up across the
         photograph. It showed on every work without details; he saw it on the
         two upright ones.

         IT WAS ALSO MISDIAGNOSED ONCE, an hour before this, as the <picture>
         wrapper the grid briefly used — because the four works that wrapper
         touched are also upright. It was fixed by measuring the two boxes in
         the page instead: margin-bottom 0 against a caption at -14. */
      .picture-scroll-item:last-child { margin-bottom: 0; }

      /* More air before each new work than between a work and its own details,
         so the groups read as groups without a rule or a heading. */
      .picture-scroll-item[data-detail="0"] { margin-top: 22px; }
      .picture-scroll-item[data-detail="0"]:first-child { margin-top: 0; }

      #picture-scroll img {
        display: block;
        width: 100%;
        height: auto;
      }

      /* The caption sits directly under its work and above that work's details,
         which is what says which details belong to which work. */
      #picture-scroll .column-caption {
        margin: -14px 0 4px 0;
        font-size: 13px;
        line-height: 1.5;
        white-space: pre-line;
        color: black;
        opacity: 0.75;
      }

      /* A CAPTION WITH NO WALL TEXT UNDER IT WAS 4px OFF THE NEXT PICTURE (his,
         2026-11-08, from his own phone: "the gap between the bottom of the 10
         panels etc text line (the bottom of the caption where no wall text is
         present) and the top of the image underneath it should be bigger - ie
         the same size as the gap between DETAIL and the image below it").

         THE 4px WAS NEVER MEANT TO BE A GAP BEFORE A PICTURE. It is the space
         between the caption and the wall text that follows it, which the essay
         then adds its own 10px to — and on the eleven works with no wall text
         nothing was there to add the rest, so the picture came straight up
         against the words. The works WITH a wall text were already right: the
         essay carries `margin-bottom: 26px`, which is the same 26 the detail
         mark carries. So this is the one case that was missing it.

         22px, NOT 26, AND NOT ON THE CAPTION. Put on the picture, so that the
         caption's own 4px still does its job above a wall text and nothing
         about those works changes. 4 + 22 = the 26 everything else uses, and
         they ADD rather than collapse because `#picture-scroll` is a flex
         column. Measured against what he was comparing it with: ink to picture
         was 6.43px under a caption and 28.32px under a DETAIL, and this brings
         the caption's to 28.43 — a tenth of a pixel apart.

         INK, NOT BOXES, and that is why the number is not simply 26 - 4: the
         caption sets 13px on a 19.5px line and the mark 11px on a 12.65px one,
         so their boxes end at different distances below their last letters.
         The same trap as the cross in B40. */
      #picture-scroll .column-caption + .picture-scroll-item { margin-top: 22px; }

      /* The wall text, where a phone reads it. A PHONE KEEPS IT UNDER THE
         CAPTION, where a wide screen now puts it under the thumbnails: there are
         no thumbnails here. The phone's answer is one scroll (his, 2026-10-24),
         so a work's details are five full-width photographs, and the same move
         would push the text below all of them and a screen away from the work it
         is about. Same size as the wide screen's floor, 15px, for the same
         reason — it is read in sentences. */
      #picture-scroll .column-essay {
        margin: 10px 0 26px 0;
        font-size: 15px;
        line-height: 1.65;
        color: black;
        opacity: 0.75;
      }

      #picture-scroll .column-essay p { margin: 0 0 0.9em 0; }
      #picture-scroll .column-essay p:last-child { margin-bottom: 0; }

      /* THE SAME MARK ON A DETAIL, HERE (his, 2026-11-05). On a wide screen it
         heads the title's line in the second level; on a phone there is no
         second level and a detail has no caption of its own, so it goes UNDER
         the picture it names — the word on its own and nothing else, which is
         what he asked for. 0.52 is the 0.7-inside-0.75 of the desktop mark
         written out, so the two read at the same strength. */
      #picture-scroll .column-detail-tag {
        margin: -18px 0 26px 0;
        font-size: 11px;
        letter-spacing: 0.12em;
        text-transform: uppercase;
        color: black;
        opacity: 0.52;
      }

      /* Nothing here steps, so nothing here has a control — and nothing opens
         into a second level either: the column already shows every detail at
         full width, in its own work's order. */
      .picture-layer,
      .picture-hit,
      .step-back,
      .step-on,
      #work-aside,
      #second-level,
      .work-step {
        display: none;
      }
    }

    /* ── THE FIRST LEVEL: EVERY WORK AT ONCE ───────────────────────────────
       A draft, B37. The works page has three levels now: every work at once,
       then one work with its details in the column beside it, then one picture
       large. This styles the first. viewer.js builds it from the same `works`
       array the stage uses and shows it whenever the address carries no ?work=.

       THREE COLUMNS OF ONE SHAPE, AND THE PICTURES WERE CHANGED TO GET IT
       (his, 2026-11-08: "equal area but with three columns rather than four.
       and lets crop every thumbnail ... so they are nice and visible"). Two
       drafts came before this and both tried to make a field out of fifteen
       shapes running from 0.70 to 6.14. A contact sheet on a common height gave
       the eight-panel photograph a row to itself. Equal area evened the weight —
       every work at 36,000 px² — but left every row a different height and the
       titles at their own levels. His answer was to stop solving it in the
       stylesheet: each work now has a TILE, one fixed shape, so the grid is one
       regular field and this block is three columns, a gap, and nothing else.

       THE SHAPE IS 4:3, AND IT IS HIS, DECIDED AT THE CROP (2026-11-08: "in
       cropping (and looking at the preview page) i thought that 4:3 might work
       better than 3:2"). The first set was cut 3:2 by a script from the files
       already on the site; he then cut all fifteen himself in Lightroom and
       found the squarer shape held the work better — an upright loses a third
       of its height to 4:3 rather than a half, and the two long panel works gain
       a band of picture back. The number below follows his crop; it is not a
       layout choice that the pictures were then made to fit.

       THE TILES ARE HIS OWN EXPORTS NOW, not a centre crop taken by a script —
       so where a work is badly served by a square-ish frame, the answer is to
       re-cut that one tile, and nothing here has to change with it. */
    #work-grid {
      position: relative;
      z-index: 6;
      box-sizing: border-box;

      /* IT SCROLLS ITSELF, AND IT HAS TO. This page's body is `overflow: hidden`
         and exactly one screen tall, because the level underneath is a slideshow
         that never scrolls — so a grid left to grow past the fold simply had its
         last five works cut off with no way to reach them. Found by looking, not
         by reasoning: the page said scrollHeight 1664 against a clientHeight of
         982 and the wheel did nothing. A level that needs to scroll scrolls
         inside itself here, which is already what the phone's column does. */
      height: 100vh;
      overflow-y: auto;
      /* The page behind it cannot scroll anyway, so this only stops the rubber
         band at the ends from reaching the window. */
      overscroll-behavior: contain;

      /* The same left edge as the stage and every other page: the column the
         whole site writes in, measured off the menu by nav.js. */
      padding: 21px 40px 72px var(--content-left, 229px);

      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      /* THE GAP IS WHAT SIZES THE TILE, which is why the column gap is a
         percentage and not a number of pixels (his, 2026-11-08: "the thumbnails
         need a tiny bit more space between them so can you reduce their size to
         about 90%"). Three columns always fill the width between the menu and
         the right margin, so a tile is only ever made smaller by taking the
         space off it and putting it in the gutter. 4.6% of the grid's own width,
         twice, leaves 90.8% for three tiles — 95% of the 95.5% they had at a
         26px gutter — and because it is a percentage it stays 95% at every
         width rather than only at the one this was measured at.

         IT WENT TO 90% FIRST AND THAT WAS TOO FAR (his, same day: "it looks
         better but has gone a bit far... so if this roughly 90% of what it was
         before, lets go to 95% - ie half the change you just made"). Both
         numbers are kept here because the second only makes sense against the
         first: 7% gutter, then half of it.

         More air between the rows than between the columns is the older rule,
         and it is about the titles: a title has to read with the tile above it
         and not with the row below. The row gap carries that on its own now,
         because the caption sits in it — one line of 13px and its 10px margin
         come to 27px, so 45px of gap puts 72px between a tile and the one under
         it against 53px between the columns, and the title still belongs
         upwards. Change the column gap and this number has to be looked at
         again; it took half its own step back when the gutter did. */
      gap: 45px 4.6%;
      align-content: start;
    }
    /* #work-grid is display:grid and so is #stage, and both of those beat the
       browser's own [hidden] rule. Without these two lines the level being
       hidden stays on the screen underneath the one being shown. */
    #work-grid[hidden],
    #stage[hidden] { display: none; }

    .grid-work {
      /* Each work's own address, so it opens in a new tab and copies like a link. */
      display: block;
      text-decoration: none;
      color: #000;
      min-width: 0;
    }
    .grid-frame {
      display: block;
      width: 100%;
      /* The tiles are cut to this, so the box and the picture agree and the
         shape is stated in both places rather than inferred from the file.
         CHANGE THIS AND THE EXPORTS TOGETHER, never one alone: a frame that
         disagrees with the file letterboxes every tile on the page. */
      aspect-ratio: 4 / 3;
      /* A faint box while the tile is still coming, so the page does not
         jump as each one lands. */
      background: rgba(0, 0, 0, 0.045);
    }
    .grid-frame img {
      display: block;
      width: 100%;
      height: 100%;
      /* `contain`, never `cover`: the tile is already cut to the box's shape, so
         these agree today — and if a tile he cuts himself comes in at some other
         shape, this shows it whole with air round it rather than silently
         cropping a work a second time. */
      object-fit: contain;
    }
    .grid-title {
      display: block;
      margin-top: 10px;
      font-size: 13px;
      line-height: 1.32;
      /* Black, like everything else on the site except the menu and the index
         (standing rule 24). */
      color: #000;
    }
    /* The work lifts very slightly under the pointer — enough to say it is a
       door, not enough to be an effect. Nothing moves for anyone who has asked
       their system for less movement. */
    .grid-work .grid-frame { transition: opacity 180ms ease; }
    .grid-work:hover .grid-frame,
    .grid-work:focus-visible .grid-frame { opacity: 0.74; }
    .grid-work:focus-visible { outline: 1px solid rgba(0, 0, 0, 0.55); outline-offset: 6px; }
    @media (prefers-reduced-motion: reduce) {
      .grid-work .grid-frame { transition: none; }
    }

    /* THE PHONE: one work to a row, full width, in the order they are listed.
       The same breakpoint the rest of this page turns on, so the grid and the
       stage never disagree about which layout is running. */
    @media (max-width: 800px), (orientation: portrait) and (pointer: coarse), (max-height: 500px) and (pointer: coarse) {
      /* THE SAME BOX AS THE STAGE, TO THE SAME MEASUREMENTS. The menu bar is
         fixed across the top of a phone, so a grid that simply flowed from the
         top of the document had its first work behind it — the draft of
         2026-11-07 did, and the fault was at the top of the page where it is
         least likely to be scrolled back to. Both levels are now held in the
         same place by the same two variables, so neither can drift from the
         other. --vh, not vh, because a phone's address bar slides in and out:
         see fitToNav() in viewer.js. */
      #work-grid {
        position: fixed;
        top: calc(var(--nav-bottom, 40px) + 10px);
        left: 0;
        width: 100vw;
        height: calc(var(--vh, 1vh) * 100 - var(--nav-bottom, 40px) - 10px);
        padding: 2px 16px 56px;
        padding-left: max(16px, env(safe-area-inset-left));
        padding-right: max(16px, env(safe-area-inset-right));
        /* ONE COLUMN, not three. Three tiles across a phone would be 100px of
           picture each, which is the fault the tile crop was made to cure. */
        grid-template-columns: minmax(0, 1fr);
        gap: 28px;
      }
      .grid-title { font-size: 15px; margin-top: 8px; }

      /* ===================== B40 — THE PHONE'S TOP BAR =====================
         HIS, 2026-11-08, after looking at B39: "its fine that neither mikhael
         subotzky nor the two lines are clickable in this slideshow mode. but i
         think we need to make it clearer that you can swipe right and left for
         next work so how about the following: the X moves to the right to be
         over the two lines and gets bigger so that it is the same size as the X
         in the normal menu when it expands. and over the Mikhael Subotzky (at
         the same size but black) please write the following: Previous work |
         Next work with the words tappable to advance / go back in addition to
         the swipe still working".

         So while a work is open the menu bar is read as this page's bar: the two
         words where his name is, the cross where the two lines are. Both sit on
         the wash, and the faint name and lines underneath are what they sit on.
         A tap on the cross therefore closes the work rather than opening the
         menu — he settled that in his first sentence.

         TO UNDO IT: `git revert` the one commit. The cross was `left: max(8px,
         …)`, `right: auto`, `font-size: 32px` and no box of its own; the words
         did not exist. B39's own undo is in the block above and is unaffected. */

      /* OVER THE TWO LINES, AND THE SAME SIZE AS THE CROSS THEY BECOME. The
         menu's cross is those two bars rotated 45° — 28px long, 2px thick —
         which is a cross 21.2px corner to corner. The × glyph in Georgia draws
         21.1px of ink at 48px, so 48 is not a round number picked by eye, it is
         the match. 44px square, flex-centred and sat on the burger's own
         footprint (44px wide, 4px in from the right, centred on the bar), so
         the two crosses land in exactly the same place.

         FONT-SIZE 48 IN A 44px BOX IS DELIBERATE: the box is the touch target
         and the ink is what has to match, so the glyph is allowed to be bigger
         than the box that carries it. `overflow: visible` is the browser's
         default and nothing here changes it.

         AND THE -3.5px IS WHY IT LOOKED LOW (his, 2026-11-08: "the X looks two
         low... please make sure it is exactly in line with the Previous / next
         work and the middle of the X is in the middle of the double lines
         underneath it"). Centring a flex child centres its LINE BOX, and a line
         box is not its ink: the × hangs above the baseline, and in Georgia at
         48px its ink centre comes out 25.4px down a 44px box whose middle is 22.
         So the box was dead centre on the two lines and the mark inside it was
         3.4px below them — the measurement agreed with itself and disagreed
         with his eye, and his eye was right.

         The two things he asked it to line up with are 0.54px apart: the words'
         own ink centres on 19.46 and the two lines on 20.00. -3.5px puts the
         cross's ink on 19.89, which is within half a pixel of both. Measured,
         not guessed — and it is a transform rather than a `top` so that the
         44px touch target keeps sitting on the burger's own footprint.

         WEIGHT: 400 AND 0.55, WHICH IS WHAT `.work-step` IS (his, same message:
         "can you make them look the same weight / boldness as the Previous work
         and Next work are on the desktop version"). The desktop marks are plain
         Georgia, black at 0.55, and this now draws at the same strength. It
         inherited 500 at 0.7 from the wide-screen rule above, which is what made
         it shout at 48px. The SIZE is unchanged — he asked about weight, and 48
         is the measured match to the menu's own cross. */
      #work-close {
        top: calc(var(--nav-bottom, 40px) / 2 - 22px);
        left: auto;
        right: max(4px, env(safe-area-inset-right));
        width: 44px;
        height: 44px;
        padding: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 48px;
        font-weight: 400;
        opacity: 0.55;
        transform: translateY(-3.5px);
      }

      /* THE TWO WORDS, WHERE HIS NAME IS. Same family, same 19px, same weight —
         everything the name is except the colour, which he asked to be black.
         Centred on the bar the same way the cross is, and starting on the left
         gutter the name starts on, so they sit over "Mikhael Subotzky" and read
         as a line of type rather than as buttons.

         `min(19px, 5.2vw)` RATHER THAN A FLAT 19px, and it is a guard and not a
         design: at 19px the pair measures 259px, which clears the cross easily
         on every phone made in years — 54px of air at 375 wide — and would meet
         it at about 330. Below that the words come down a little instead of
         colliding. Every real phone sees exactly 19px, the name's own size. */
      #work-steps {
        display: flex;
        align-items: center;
        gap: 7px;
        position: fixed;
        top: calc(var(--nav-bottom, 40px) / 2 - 22px);
        height: 44px;
        left: max(14px, env(safe-area-inset-left));
        /* Above the wash (24) and the column (25), like the cross at 41, because
           it is furniture of the page and not of anything inside it. */
        z-index: 41;
        font-size: min(19px, 5.2vw);
        line-height: 1;
        white-space: nowrap;
        pointer-events: auto;
        /* THE DESKTOP MARKS' OWN STRENGTH, on the whole row at once (his,
           2026-11-08: "can you make them look the same weight / boldness as the
           Previous work and Next work are on the desktop version"). `.work-step`
           is black at 0.55 and that is what this is. They were the name's 700 at
           full black, which is the name's job and not theirs: the name is the
           site's masthead, these are a control. Still black ink — the colour he
           asked for — drawn at the strength the same two words are drawn at on a
           wide screen. */
        opacity: 0.55;
      }

      #work-steps button {
        border: 0;
        margin: 0;
        /* The vertical padding is the touch target and costs nothing visually;
           the horizontal is 0 so the gap above is the only space between the
           words and the rule, and the first word starts exactly on the gutter. */
        padding: 11px 0;
        background: none;
        cursor: pointer;
        font-family: inherit;
        font-size: inherit;
        /* 400, like `.work-step`. The row's own 0.55 does the rest. */
        font-weight: 400;
        line-height: 1;
        color: black;
      }

      /* A shade lighter again than the words it separates, so it reads as a
         mark between them rather than as a third thing. It multiplies with the
         row's 0.55, so this is 0.39 of black on the screen. */
      #work-steps .work-steps-rule {
        font-weight: 400;
        color: black;
        opacity: 0.7;
      }

      #work-steps button:focus-visible {
        outline: 1px solid rgb(80, 25, 30);
        outline-offset: 2px;
      }

      /* Gone with the cross while the menu is open, and for the same reason: the
         menu puts his name back at full strength and these would sit on it. */
      html.nav-is-open #work-steps { display: none; }

      /* And gone on the grid, where there is no work to step from. viewer.js
         sets `hidden` on it exactly as it does on the cross. */
      #work-steps[hidden] { display: none; }
    }
