/* The explorer's own layout, on top of the site stylesheet rather than inside it.
   Loaded only by this page: the article does not run code and does not need the rules
   for a page that does.

   ## This page is dark, and it is the only one that is

   `site.css` sets a white reading surface with dark image wells, and every article page
   keeps it. This page is not a reading surface — there is no prose on it at all — and it
   is nearly all picture: a thousand wallpapers on the left, a render on the right, the
   atlas plate in place of either. A white mat between them is a light box around dark
   pictures, which is the exact thing the well tokens exist to avoid. So the studio is
   one large well, and it is spelled with the same six tokens a figure's well uses rather
   than with a second palette: `--well` is the ground, `--well-rule` the rules, and the
   two ink tokens carry every word on the page. Nothing here is a new colour, except the
   three the render-state bar on the Download row says its state with: a status light is
   the one thing on the page whose colour is its meaning.

   It is forced rather than asked for. There is no `prefers-color-scheme` branch on this
   site and this page does not open one: a reader who arrives from an article page should
   find the tool the colour it always is, not the colour their laptop is set to.

   ## The page is the window

   Two panels side by side, each scrolling on its own, and the document does not scroll at
   all. The viewer is the wider of the two because it holds the picture being made; the
   side panel is wide enough for a grid of wallpapers to read as a grid. Below the
   breakpoint the two stack, viewer first, and nothing more is owed to a narrow window —
   this is a tool for a desktop and says so by what it shows rather than by refusing. */

.studio-body {
  --side: 40fr;
  --viewer: 60fr;
  --studio-gap: 1px;
  /* Where the two panels stop being side by side. The site's own breakpoint is about the
     contents rail, which this page does not have, so the number is this page's own: below
     it a grid of wallpaper tiles and a canvas cannot both be worth looking at. */
  --studio-stack: 60rem;
  /* The render-state bar: drawing the field, the one-sample picture up while the final
     pass runs, and the final picture. Red, yellow, green, so the order is read off the
     colour alone. */
  --state-rendering: #e0605a;
  --state-sharpening: #e8c84a;
  --state-final: #5cc47a;
  /* The absolute palette scale: the switch's pressed half and the strip's frame while it
     is in force. Its own colour, and none of the three above, so that it cannot be read as
     a render state. */
  --scale-absolute: #f0913f;

  margin: 0;
  padding: 0;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--well);
  color: var(--well-ink);
  display: flex;
  flex-direction: column;
}

[hidden] { display: none !important; }

/* ------------------------------------------------------------------------ the bar */

/* Thin, because it is not the page. The site's own `.topbar` carries the reading
   column's metrics and a bottom rule sized for paper; this is the same two jobs — say
   where you are, offer the way back — in one line of the well's own furniture. */
.studio-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex: none;
  padding: 0.45rem var(--gutter);
  border-bottom: 1px solid var(--well-rule);
  font-family: var(--sans);
  font-size: 0.85rem;
}

.studio-site {
  color: var(--well-ink);
  text-decoration: none;
  font-weight: 600;
}
.studio-site:hover { color: var(--well-link); }

/* **The page's `<h1>`, at the size of the bar it sits in.** Every other page on the site
   opens with a masthead; this one is a tool and has no room for one, and its outline
   started at `<h2>` until now (`explorer_bug_hunt_ckpt138`, finding 7). `site.css` sets an
   `h1` at 1.75rem serif, which would break the bar's single line, so the whole of this
   rule is taking that back — the heading is the bar's own furniture and reads as such. */
.studio-bar-name { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.studio-title {
  margin: 0;
  font: inherit;
  font-weight: 400;
  letter-spacing: inherit;
  color: var(--well-ink-dim);
  white-space: nowrap;
}
.studio-title::before { content: "/ "; }

.studio-bar-links { display: flex; align-items: center; gap: 1rem; }
.studio-bar-links a { color: var(--well-ink-dim); text-decoration: none; }
.studio-bar-links a:hover { color: var(--well-link); text-decoration: underline; }

/* ---------------------------------------------------------------------- the panels */

.studio {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--side) var(--viewer);
  gap: var(--studio-gap);
  background: var(--well-rule);
}

.side, .viewer {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  background: var(--well);
}

.side { display: flex; flex-direction: column; overflow-y: hidden; }

@media (max-width: 60rem) {
  .studio {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    overflow-y: auto;
  }
  /* Stacked, the viewer comes first: the picture is what the page is for, and a reader
     who has just followed a link should not have to scroll past a thousand thumbnails to
     see what the link said. */
  .viewer { order: 1; }
  .side { order: 2; overflow-y: visible; }
  .side .tiles, .side .tabpanel { overflow: visible; }
}

/* ------------------------------------------------------------------------ the tabs */

/* The panel's one header row: which of the three panels is showing, and — on the right,
   where a row's controls go — which gallery the gallery panel is showing.

   **The dropdown is the Collection label.** It sat in a section of its own under the tabs,
   with a `COLLECTION` header over it and a footer under the tiles saying the same count a
   third time; the option's own text reads *General gallery · 1000*, which is the label,
   the collection and its size in the one control. A row of its own for one select was a
   row of the panel spent saying what the select already said. */
.side-head {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem var(--gutter);
  border-bottom: 1px solid var(--well-rule);
  font-family: var(--sans);
}

.tabs {
  display: flex;
  gap: 0.25rem;
  min-width: 0;
}

/* Right-aligned, and it gives way first: the tabs are two short words and this is a name
   with a count on it, so a narrow panel shortens the select rather than the tabs. */
.collection {
  margin: 0 0 0 auto;
  min-width: 0;
  font: inherit;
  font-size: 0.75rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.15rem 0.3rem;
}
.collection:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }
.collection[hidden] { display: none; }

/* The screensaver's one way in, beside what it shows *(gallery_screensaver_ckpt141)*. */
.collection-action {
  font: inherit;
  font-size: 0.75rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.15rem 0.4rem;
  cursor: pointer;
}
.collection-action:hover { border-color: var(--well-ink); }
.collection-action:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }
.collection-action[hidden] { display: none; }

/* **The screensaver takes the whole page**, over the studio rather than instead of it, so
   the viewer underneath keeps its size and nothing there redraws for the layer coming or
   going. The pictures are letterboxed on black at their own aspect; `screensaver.js` sizes
   them, and the one on top fades in over the other. */
.screensaver {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  background: #000;
  cursor: none;
}
.screensaver[hidden] { display: none; }
.screensaver.is-awake { cursor: auto; }
.screensaver-picture {
  grid-area: 1 / 1;
  opacity: 0; /* the fade's length is `SCREENSAVER_FADE_MS`, set from the script */
}
.screensaver-picture.is-up { opacity: 1; }
.screensaver-controls {
  position: absolute;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms linear;
}
.screensaver.is-awake .screensaver-controls { opacity: 1; pointer-events: auto; }
.screensaver-controls select,
.screensaver-controls button {
  font: inherit;
  color: inherit;
  background: transparent;
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.1rem 0.4rem;
}
/* The select wears the well rather than being see-through, because its option list is the
   operating system's and takes the select's colours: transparent over light ink put pale
   text on the list's own white *(screensaver_polish_ckpt143)*. */
.screensaver-controls select { background: var(--well); }
.screensaver-controls option { color: var(--well-ink); background: var(--well); }
.screensaver-controls button:disabled { opacity: 0.6; }
.screensaver-note:empty { display: none; }

/* **Browse takes the whole page too** *(explorer_browse_ckpt153)*, over the studio as the
   screensaver does, but it is a well rather than black: it is the gallery panel at the
   window's size, the same dropdown, chips and tiles, and it keeps their furniture. The
   tiles run at the size they are drawn at, in as many columns as fit. */
.browse {
  --browse-tile: 316px;
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  background: var(--well);
  color: var(--well-ink);
  font-family: var(--sans);
}
.browse[hidden] { display: none; }
/* **It keeps the chrome** *(browse_chrome_ckpt153)*: the layer starts under the bar, whose
   bottom the page sets as `top`, and the panel's own header row is moved into its top.
   **It is Browse's one header row** *(browse_header_ckpt153)*: the tabs, Browse's own
   Collection dropdown, and on the right Screensaver and the one way out, which stands where
   Browse stood. Browse's three live in the row and are shown only while it is here; the
   panel's dropdown and Browse itself stand aside. The row sits over the preview's mat,
   since it stays live there too. */
.browse > .side-head { position: relative; z-index: 3; background: var(--well); }
.side > .side-head > .browse-only { display: none; }
.browse #gallery-collection, .browse #gallery-browse { display: none; }
.browse #browse-collection { margin: 0; }
.browse #gallery-screensaver { margin-left: auto; }
.collection-action[aria-pressed="true"] {
  color: var(--well);
  background: var(--well-ink);
  border-color: var(--well-ink);
}
.browse-note { font-size: 0.75rem; color: var(--well-ink-dim); }
.browse-note:empty { display: none; }
/* The five rows side by side where the window has room for them, and stacked where not:
   each row is as wide as its chips, so the two yes-or-no rows share a line. Spelled with
   both classes because `.filters`, below, is a column and would otherwise win. */
.filters.browse-filters { flex-direction: row; flex-wrap: wrap; gap: 0.5rem 1.5rem; }
.browse-filters .chip-group { flex: 1 1 auto; max-width: 100%; }
.browse-tiles {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0.75rem var(--gutter) 1.5rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--browse-tile), 100%), var(--browse-tile)));
  justify-content: center;
  gap: 0.35rem;
  align-content: start;
  grid-auto-rows: max-content;
  align-items: start;
}

/* The preview: one picture on the mat, fit to the window, and the bar under it. The tile
   sits under the canvas at the canvas's size, so the first thing up is the picture's own
   tile scaled, and each stage covers it. */
.browse-preview {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1rem var(--gutter);
  background: rgb(0 0 0 / 0.92);
}
.browse-preview[hidden] { display: none; }
.browse-stage { position: relative; flex: none; background: var(--well-pending); }
.browse-under, .browse-picture {
  position: absolute;
  inset: 0;
  display: block;
}
.browse-under { object-fit: cover; }
.browse-picture[hidden] { display: none; }
.browse-bar {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  font-size: 0.75rem;
  color: var(--well-ink-dim);
}

/* **The dropdown draws itself here, so that a colour family's entry can wear its colour.**
   A native drop-down is the operating system's list and takes no markup inside an option,
   which left the one control that chooses a colour collection as the only place on the
   panel naming a family without showing it — the chips under it have carried the wheel's
   dots from the start. `base-select` hands the control and its picker to this stylesheet,
   and then an option is a box with a span in it like anything else.

   It is an enhancement and reads as one. Where the browser does not know `base-select`,
   `::picker(select)` is not a selector it knows either, so every rule in this block is
   dropped whole and the control stays the browser's own with the option text it has
   always had; `@supports` says that out loud rather than leaving it to that accident.
   `gallery.js` gates the two pieces of markup that only mean anything in here — the button
   the closed control becomes, and the `<legend>` a group heading is spelled with — on the
   same question. */
@supports (appearance: base-select) {
  .collection, .collection::picker(select) { appearance: base-select; }

  /* The closed control is the button, and the `.collection` rules above still draw it: all
     that is owed here is the row — the clone of the chosen option, then the marker. */
  .collection {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    text-align: left;
  }
  .collection::picker-icon { color: var(--well-ink-dim); transition: none; }
  .collection:open::picker-icon { transform: rotate(180deg); }

  /* The list is the well, a rule and a shadow — the same furniture the panel is made of,
     because it opens over it. */
  .collection::picker(select) {
    background: var(--well);
    border: 1px solid var(--well-rule);
    border-radius: 3px;
    padding: 0.2rem 0;
    font-family: var(--sans);
    font-size: 0.75rem;
    color: var(--well-ink);
    box-shadow: 0 6px 18px rgb(0 0 0 / 0.45);
    max-height: min(60vh, 28rem);
    overflow-y: auto;
  }

  /* One text column whatever an entry wears: a dot takes exactly the indent every other
     entry is given, so the names line up down the list rather than stepping in at the
     families. `--dot` is that width — the dot and the gap after it — and the gap is spelled
     here rather than on the dot because base appearance lays an option's own contents out
     as a flex row with a gap of its own, which is six pixels this stylesheet never asked
     for and cannot see from the dot's margin. */
  .collection option {
    --dot: 0.9rem;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.15rem 0.6rem 0.15rem calc(0.6rem + var(--dot));
    color: var(--well-ink-dim);
    cursor: pointer;
  }
  .collection option .hue { margin-right: 0; }
  .collection option:has(.hue) { padding-left: 0.6rem; }
  .collection option:hover { color: var(--well-ink); background: var(--well-rule); }
  .collection option:checked { color: var(--well-link); }
  .collection option:focus, .collection option:focus-visible {
    outline: 2px solid var(--well-link);
    outline-offset: -2px;
  }
  /* The control says what is chosen, and the list marks it in the accent. A checkmark
     column as well would be a second indent on every row to say it a third time. */
  .collection option::checkmark { display: none; }

  /* A group heading, in the panel's own section-header voice — the words are the same
     words the filter rows below carry, so they are set the same way. */
  .collection optgroup { padding: 0; }
  .collection optgroup legend {
    padding: 0.4rem 0.6rem 0.15rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--well-link);
  }
}

/* Two filled buttons rather than two words on a rule. The tabs choose what the whole
   panel is, and drawn as folder tabs in the dim ink they read as a caption over the chips
   and were walked past. So both are light rectangles with the ground's colour for ink,
   which is the one light surface in the row; the one showing is filled in the accent the
   section heads use, and the other in the dim ink, which lightens to the full ink under
   the pointer. Both are the same weight so choosing one does not shift the other. */
.tab {
  appearance: none;
  border: none;
  border-radius: 4px;
  background: var(--well-ink-dim);
  color: var(--well);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
  padding: 0.3rem 0.9rem;
  cursor: pointer;
}
.tab:hover { background: var(--well-ink); }
.tab[aria-selected="true"] { background: var(--well-link); }
.tab:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }

.tabpanel {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* --------------------------------------------------------------------- the gallery */

.filters {
  flex: none;
  padding: 0.6rem var(--gutter) 0.5rem;
  border-bottom: 1px solid var(--well-rule);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* A filter group: a section header, and — where the group has more entries than a couple
   of rows will hold — a fixed height it scrolls inside. Thirteen modes wrap to three lines
   otherwise, and three lines of chips is a third of the panel spent on what is being
   filtered rather than on the pictures. The box that used to be drawn around each group is
   gone: the header's rule is the divider now, on this side as on the viewer's. */
.chip-group { min-width: 0; }

/* ---------------------------------------------------------------- a section header */

/* One class for every section on the page — Mode and Color family on the gallery side;
   Mode, Palette, Shade and Details under the viewer. The label, in the accent, and a
   hairline that runs from it to the section's right edge; a section's one action, where
   it has one, sits on the rule at the right. The rule is what divides one section from
   the next, which is why the sections carry no border and little gap of their own.

   **One accent, because this page has one surface.** The studio is a single dark well
   (see the top of this file) and there is no light version of it to spell a second
   accent for. `--head` is the one token the header reads, so a light surface is one
   declaration of it and not a restyle. */
.section-head {
  --head: var(--well-link);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.35rem;
  font-family: var(--sans);
}

.section-head::after {
  content: "";
  order: 1;
  flex: 1 1 auto;
  min-width: 1rem;
  border-top: 1px solid var(--well-rule);
}

.section-head h2 {
  order: 0;
  flex: none;
  margin: 0;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--head);
}

.section-head .head-action {
  order: 2;
  flex: none;
  font: inherit;
  font-size: 0.75rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.05rem 0.5rem;
  cursor: pointer;
}
.section-head .head-action:hover { border-color: var(--well-ink-dim); color: var(--well-link); }
.section-head .head-action:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
.section-head .head-action[aria-expanded="true"] { border-color: var(--well-ink-dim); }
.section-head .head-action:disabled { opacity: 0.45; cursor: not-allowed; }
.section-head .head-action:disabled:hover { border-color: var(--well-rule); color: var(--well-ink); }

/* Details folds, so its header is a summary: the marker is drawn ahead of the label rather
   than left to the browser, which would put it outside the flex row. */
summary.section-head { list-style: none; cursor: pointer; }
summary.section-head::-webkit-details-marker { display: none; }
summary.section-head::before {
  content: "▸";
  order: -1;
  font-size: 0.7rem;
  color: var(--head);
}
details[open] > summary.section-head::before { content: "▾"; }
summary.section-head:hover h2 { color: var(--well-ink); }
summary.section-head:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }

/* Two rows of chips, and the rest is a scroll. A fixed height rather than a max: the row
   under it should not move when a filter narrows what is above it. */
.chip-group.is-scrolling .chips {
  height: 3.4rem;
  overflow-y: auto;
  align-content: start;
}

.chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }

/* A chip is a filter and a count in one control. The count is what makes the row worth
   having: a reader picking `threads` should be able to see, before they pick, that it is
   a hundred pictures and not six. */
.chip {
  appearance: none;
  border: 1px solid var(--well-rule);
  border-radius: 999px;
  background: none;
  color: var(--well-ink-dim);
  font-family: var(--sans);
  font-size: 0.75rem;
  line-height: 1.5;
  padding: 0.1rem 0.55rem;
  cursor: pointer;
  white-space: nowrap;
}
.chip:hover { color: var(--well-ink); border-color: var(--well-ink-dim); }
.chip[aria-pressed="true"] {
  color: var(--well);
  background: var(--well-ink);
  border-color: var(--well-ink);
}
.chip:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
.chip .count { font-variant-numeric: tabular-nums; opacity: 0.7; margin-left: 0.3rem; }

/* The family's own colour, ahead of its name. It keeps its colour when the chip is
   pressed, which is the point of it: the row still reads as a wheel.

   **One rule, and no ancestor in the selector.** The same dot marks a colour family
   wherever the panel names one — on a filter chip here, and on the Collection dropdown's
   entry for that family's gallery, where what the closed control shows is a *clone* of the
   chosen option's content. The colour itself arrives as `--c` on the element, which is
   what survives that clone; the shape is this rule's, once, so the two cannot drift. */
.hue {
  display: inline-block;
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  margin-right: 0.35rem;
  vertical-align: -0.02em;
  background: var(--c);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35) inset;
}

/* Pictures and nothing else. No caption, no name, no score: the grid is for finding one
   worth opening, and everything a tile could say about itself is something the viewer
   says better once it is open. */
.tiles {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0.5rem var(--gutter) 1rem;
  display: grid;
  /* Three to a row, whatever the panel is worth. A track with a minimum in rem gives a
     column count that changes with the window — four tiles at one width, two at another,
     which is what a 440-pixel panel was doing — and a share of the panel does not: a
     third each, so the pictures grow with the panel and the row does not change shape. */
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
  gap: 0.35rem;
  align-content: start;

  /* **The rows are sized by what is in them, and that has to be said out loud.** An auto
     row asks its items for a *minimum* height, and a block holding one replaced element
     at `width: 100%` answers zero — so the track comes out two pixels, which is the
     border and nothing else. Stretched into it, every wallpaper is a sliver; left at
     their own height, the tiles overflow the track and paint over each other, which is
     the same picture with more steps. `max-content` is the one that asks the question
     whose answer is the picture's own height. */
  grid-auto-rows: max-content;
  align-items: start;
}

.tile {
  appearance: none;
  padding: 0;
  border: 1px solid transparent;
  background: var(--well-pending);
  cursor: pointer;
  overflow: hidden;
  line-height: 0;
}
/* **The shape comes from the picture, not from a rule.** An `aspect-ratio` here is
   circular inside an auto-sized grid row — the row asks the image how tall it is, the
   image works it out from a width that depends on the row — and Chrome settles that by
   giving the row two pixels while the tile computes its own 107, so every tile overflows
   onto the ones below and the grid paints as a stack of bands. The `width` and `height`
   attributes on the element carry the same 16:9 and carry it intrinsically, which is
   what a row can size itself from, before the picture has loaded as well as after. */
.tile img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  /* Held back until the picture is whole: a half-received JPEG paints as a band of
     scanlines, and a grid of those looks like a grid of broken pictures. The tile's own
     ground is what shows until then, and the box never changes size. */
  opacity: 0;
  transition: opacity 120ms ease-out;
}
.tile.is-ready img { opacity: 1; }
.tile:hover { border-color: var(--well-ink-dim); }
.tile:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }
.tile.is-open { border-color: var(--well-ink); }

/* A tile with a control of its own beside it *(saved_tab_ckpt131)*: the cell is the grid's
   item and the tile fills it, so the grid is the same grid whether a tile carries a mark or
   not. The mark and the remove button sit over the tile's top-right corner. */
.tile-cell { position: relative; min-width: 0; }
.tile-cell > .tile { display: block; width: 100%; }

/* The save mark: a bookmark, hollow until the picture is saved and filled once it is. It
   shows on a tile that is pointed at or focused, and always once saved, so a grid reads at
   a glance for which of its pictures are kept without every tile wearing a control. On a
   screen with no pointer to hover it always shows, because there is no other way to it. */
.save-mark, .tile-remove {
  position: absolute;
  top: 0.2rem;
  right: 0.2rem;
  width: 1.6rem;
  height: 1.6rem;
  padding: 0.2rem;
  border: none;
  border-radius: 3px;
  background: rgb(0 0 0 / 0.55);
  color: var(--well-ink);
  cursor: pointer;
  line-height: 1;
  opacity: 0;
  transition: opacity 120ms ease-out;
}
.save-mark svg { display: block; width: 100%; height: 100%; }
.save-mark path { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
.save-mark[aria-pressed="true"] { color: var(--well-link); opacity: 1; }
.save-mark[aria-pressed="true"] path { fill: currentColor; }
.save-mark[hidden] { display: none; }
.tile-cell:hover > .save-mark, .tile-cell:focus-within > .save-mark,
.slot-cell:hover > .save-mark, .slot-cell:focus-within > .save-mark,
.tile-cell:hover > .tile-remove, .tile-cell:focus-within > .tile-remove { opacity: 1; }
.save-mark:hover, .tile-remove:hover { background: rgb(0 0 0 / 0.8); color: var(--well-link); }
.save-mark:focus-visible, .tile-remove:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; opacity: 1; }
@media (hover: none) {
  .save-mark, .tile-remove { opacity: 1; }
}
.tile-remove { font: inherit; font-size: 1.1rem; }

/* What a saved tile is, in the corner the walk's score takes on a found one. */
.tile-label {
  position: absolute;
  left: 0.2rem;
  bottom: 0.2rem;
  max-width: calc(100% - 0.4rem);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0.05rem 0.3rem;
  border-radius: 2px;
  background: rgb(0 0 0 / 0.65);
  color: var(--well-ink);
  font-family: var(--sans);
  font-size: 0.65rem;
  line-height: 1.3;
}
.saved-tile { position: relative; }
.saved-tile.is-refused { background: var(--well-rule); }

.side-note {
  flex: none;
  margin: 0;
  padding: 0.4rem var(--gutter) 0.6rem;
  border-top: 1px solid var(--well-rule);
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--well-ink-dim);
}
.side-note:empty { display: none; }
/* A side note's way back into the article *(walk_tab_ckpt140)*: the well's own link colour,
   because `site.css`'s `a` is coloured for a white reading surface and these panels are
   dark. The same reason `.notice a` carries it. */
.side-note a { color: var(--well-link); }

/* ----------------------------------------------------------------------- saved */

/* The Saved tab's head: the count and what can be done with the list, a line for what the
   last action did, and the import box when it is open. It does not scroll with the tiles. */
.saved-head {
  flex: none;
  padding: 0.5rem var(--gutter) 0.3rem;
  font-family: var(--sans);
  font-size: 0.8rem;
}
.saved-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.6rem; }
.saved-count { color: var(--well-link); font-weight: 600; font-variant-numeric: tabular-nums; }
.saved-count:empty { display: none; }
.saved-actions { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-left: auto; }
.saved-head button, .saved-head select {
  font: inherit;
  font-size: 0.78rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.15rem 0.5rem;
  cursor: pointer;
}
.saved-head button:hover { border-color: var(--well-ink-dim); color: var(--well-link); }
.saved-head button:disabled, .saved-head select:disabled { opacity: 0.45; cursor: not-allowed; }
.saved-head button:disabled:hover { border-color: var(--well-rule); color: var(--well-ink); }
.saved-head button:focus-visible, .saved-head select:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
#saved-download { border-color: var(--well-ink-dim); font-weight: 600; }
#saved-download.is-running { border-color: var(--well-link); color: var(--well-link); }
.saved-import { display: flex; flex-direction: column; gap: 0.35rem; margin-top: 0.45rem; }
.saved-import[hidden] { display: none; }
.saved-import textarea {
  font-family: var(--mono);
  font-size: 0.72rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.3rem;
  resize: vertical;
}
.saved-import-go { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; color: var(--well-ink-dim); }
.saved-file input { font: inherit; font-size: 0.72rem; color: var(--well-ink-dim); max-width: 14rem; }
.saved-progress, .saved-warning {
  margin: 0.35rem 0 0;
  font-size: 0.75rem;
  color: var(--well-ink-dim);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.saved-warning { color: var(--state-sharpening); }
.saved-progress:empty, .saved-warning:empty { display: none; }
.saved-empty {
  flex: none;
  margin: 0;
  padding: 0.6rem var(--gutter);
  font-family: var(--sans);
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--well-ink-dim);
}
.saved-empty[hidden] { display: none; }
/* A collection whose rows are still on their way *(period_slider_ckpt155)*: one line where
   the grid will be, set as Saved's empty line is, across every column of either grid. */
.tiles-loading {
  grid-column: 1 / -1;
  margin: 0;
  padding: 0.6rem 0;
  font-family: var(--sans);
  font-size: 0.8rem;
  color: var(--well-ink-dim);
}

/* ----------------------------------------------------------------------- the atlas */

/* The frame sizes itself to this box, which is the whole of what the panel owes it. */
.atlas-host {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem var(--gutter);
}

/* ------------------------------------------------------------------------ the walk */

/* The config, the button and the console above; what the walk found below, as the gallery's
   own tiles. The head does not scroll with the tiles, and the console is short on purpose:
   it is the last few things the walk did, not a record of them. */
.walk-head {
  flex: none;
  padding: 0.5rem var(--gutter) 0.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  font-family: var(--sans);
  font-size: 0.8rem;
  color: var(--well-ink);
}

.walk-config summary { cursor: pointer; }
.walk-fields {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding-top: 0.4rem;
  max-height: 40vh;
  overflow-y: auto;
}
.walk-group {
  margin: 0;
  padding: 0.3rem 0.5rem 0.4rem;
  border: 1px solid var(--well-rule);
  border-radius: 3px;
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.8rem;
}
.walk-group legend {
  padding: 0 0.3rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--well-link);
}
.walk-check { white-space: nowrap; color: var(--well-ink-dim); }
/* A family's radio wears the wheel's own dot, the same mark the gallery panel's hue chips
   wear. `.hue` above is the dot and is not restated here; the map count that used to
   follow it is gone (`explorer_ui_text_ckpt139` addendum 2). */
.walk-check .hue { margin-left: 0.3rem; }

.walk-go { display: flex; align-items: center; gap: 0.6rem; }
.walk-start {
  appearance: none;
  border: none;
  border-radius: 4px;
  background: var(--well-link);
  color: var(--well);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.3rem 1.1rem;
  cursor: pointer;
}
.walk-start:hover { background: var(--well-ink); }
.walk-start:disabled { background: var(--well-ink-dim); cursor: progress; }
.walk-start:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }
.walk-progress { color: var(--well-ink-dim); font-size: 0.75rem; }

/* Back to the walk (walk_detach_ckpt131): the viewer's way back to the walk, beside the
   process's own button and drawn as the lesser of the two, because it stops nothing. */
.walk-back {
  appearance: none;
  border: 1px solid var(--well-link);
  border-radius: 4px;
  background: none;
  color: var(--well-link);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.25rem 0.8rem;
  cursor: pointer;
  white-space: nowrap;
}
.walk-back:hover { color: var(--well-ink); border-color: var(--well-ink); }
.walk-back:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }
.walk-back[hidden] { display: none; }

/* The spinner beside Back to the walk (walk_tab_ckpt140): while the reader has the viewer
   and the walk carries on behind it, this says the walk is still computing. It is one
   element and one keyframe — an arc of a ring, turning — because a library for a spinner is
   a library on a page that has none. It rides with Back to the walk, so it is on screen in
   exactly the case it is about: the viewer is the reader's and nothing else on the page is
   moving. Paused, the ring stops and dims; it is still shown, because a stopped indicator
   beside a Start button is the state and an absent one is no information. */
.walk-spinner {
  flex: none;
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  border: 2px solid var(--well-rule);
  border-top-color: var(--well-link);
  animation: walk-spin 0.9s linear infinite;
}
.walk-spinner[hidden] { display: none; }
.walk-spinner.is-paused { animation: none; border-top-color: var(--well-ink-dim); opacity: 0.6; }
@keyframes walk-spin { to { transform: rotate(1turn); } }

/* How far this walk is through its step budget (walk_tab_ckpt140). It is a count and not an
   estimate: a step is a card in the strip, the budget is `STEPS` plus the twin's reserve
   where the plane has a twin, and a walk that peaks early completes the bar rather than
   abandoning it part-drawn. It sits under the buttons and stays on screen while the walk is
   paused, so the reader can see where it stopped. */
.walk-steps { display: flex; align-items: center; gap: 0.5rem; }
.walk-steps[hidden] { display: none; }
.walk-steps-bar {
  flex: 1;
  height: 0.3rem;
  border-radius: 2px;
  background: var(--well-rule);
  overflow: hidden;
}
.walk-steps-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--well-link);
  transition: width 0.25s linear;
}
.walk-steps.is-paused .walk-steps-fill { background: var(--well-ink-dim); }
.walk-steps-said {
  flex: none;
  color: var(--well-ink-dim);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ the walk view */

/* While a walk runs or is paused with the viewer its own, this is the region under the
   picture, and the controls are not on the page (walk_view_ckpt132). It is two strips, the
   walk above its candidates, each running right and scrolling when it overflows
   (walk_strip_ckpt132). */
.walk-view {
  --walk-card: 9.5rem;
  --walk-tile: 9.5rem;
  flex: 1 1 auto;
  padding: 0.5rem var(--gutter) 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  font-family: var(--sans);
  color: var(--well-ink);
}
.walk-view-half { display: flex; flex-direction: column; min-width: 0; }

/* The picture gives up height where the window is short, so both strips are in sight: a
   big picture is good, and not necessary. `--walk-room` is what the strips, their rules, the
   site bar and the status line take. Stacked, the page scrolls instead. */
.viewer.is-walking {
  --walk-room: 29rem;
}
.viewer.is-walking .stage {
  width: min(calc(100% - 2 * var(--gutter)), calc((100dvh - var(--walk-room)) * 16 / 9));
  margin-inline: auto;
}

.walk-strip, .walk-candidates {
  position: relative;
  display: flex;
  gap: 0.4rem;
  margin: 0;
  padding: 0 0 0.35rem;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}
.walk-strip { list-style: none; align-items: stretch; }

/* One card a frame: its own P≥3, its picture boxed as the viewer boxes it, the four
   quarters' P≥3 in their places, and a sentence. */
.walk-card {
  flex: none;
  width: var(--walk-card);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.3rem;
  border: 1px solid var(--well-rule);
  border-radius: 3px;
  font-size: 0.7rem;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
  color: var(--well-ink-dim);
}
.walk-card canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; }
.walk-card-head { display: flex; align-items: center; gap: 0.3rem; min-height: 1.1rem; }
.walk-card-score { font-size: 0.85rem; font-weight: 700; color: var(--well-ink); }
.walk-card-quarters { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
.walk-card-said { color: var(--well-ink); }
.walk-strip.is-running .walk-card.is-live { border-color: var(--well-ink-dim); background: rgb(255 255 255 / 0.06); }
.walk-card.is-peak.is-over { border-color: #ffd166; box-shadow: 0 0 0 1px #ffd166; }
.walk-card.is-peak.is-under { border-style: dashed; border-color: var(--well-ink-dim); }
.walk-card.is-peak .walk-card-said { font-weight: 600; }

/* The root search, and a plane giving out: words only, until the root lands. */
.walk-card.is-text { justify-content: center; font-size: 0.75rem; }
.walk-card.is-text .walk-card-said { color: #6cb6ff; }

/* The Julia twin's cards follow a slim card that says so, in the same strip. */
.walk-card.is-divider {
  width: auto;
  padding: 0.4rem 0.15rem;
  align-items: center;
  justify-content: center;
  border-style: dashed;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: #c49bff;
  letter-spacing: 0.04em;
}
.walk-best {
  margin-left: auto;
  padding: 0 0.3rem;
  border: 1px solid #ffd166;
  border-radius: 2px;
  color: #ffd166;
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* A quarter's chip, in the color that quarter is always boxed in on the picture. */
.walk-chip {
  min-width: 0;
  padding: 0 0.2rem;
  border: 1px solid var(--ink);
  border-radius: 2px;
  color: var(--ink);
  text-align: center;
}
.walk-chip.is-empty { border-style: dashed; opacity: 0.55; }
.walk-chip.is-chosen { box-shadow: 0 0 0 1px var(--ink); font-weight: 700; }
.walk-into-name { color: var(--ink); font-weight: 600; }

/* The candidates: a place's tiles, one per mode, the kept ones outlined in the found ink.
   The place they are of sits on the rule, where a section's aside goes. */
.walk-candidates-place {
  order: 2;
  flex: none;
  font-size: 0.7rem;
  color: var(--well-ink-dim);
  font-variant-numeric: tabular-nums;
}
.walk-candidate {
  flex: none;
  width: var(--walk-tile);
  margin: 2px;
  outline: 1px solid var(--well-rule);
}
.walk-candidate canvas { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; }
.walk-candidate figcaption {
  display: flex;
  justify-content: space-between;
  gap: 0.3rem;
  padding: 0.15rem 0.3rem;
  font-size: 0.7rem;
  color: var(--well-ink-dim);
}
.walk-candidate-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.walk-candidate-score { flex: none; color: var(--well-ink); font-variant-numeric: tabular-nums; }
.walk-candidate.is-kept { outline: 2px solid #ffd166; }
.walk-candidate.is-waiting { aspect-ratio: 16 / 9; background: rgb(255 255 255 / 0.04); }

@media (max-width: 60rem) {
  .walk-view { --walk-card: 8rem; --walk-tile: 8rem; }
  .viewer.is-walking .stage { width: auto; margin-inline: var(--gutter); }
}

.walk-found-head { flex: none; padding: 0 var(--gutter); }

.walk-tile { position: relative; }
.walk-score {
  position: absolute;
  left: 0.2rem;
  bottom: 0.2rem;
  padding: 0.05rem 0.3rem;
  border-radius: 2px;
  background: rgb(0 0 0 / 0.65);
  color: var(--well-ink);
  font-family: var(--sans);
  font-size: 0.65rem;
  line-height: 1.3;
}

/* ---------------------------------------------------------------------- the viewer */

.viewer { display: flex; flex-direction: column; }

/* The stage holds the canvas at the aspect the link asks for, so the picture's shape is
   the link's and not the window's. The canvas is rendered at its own display size — the
   picture is made at the resolution it is shown at. */
.stage {
  position: relative;
  flex: none;
  margin: var(--gutter) var(--gutter) 0;
  aspect-ratio: 16 / 9;
  max-height: 60vh;
  background: var(--well);
  border: 1px solid var(--well-rule);
}

/* The picture's own canvas, and not the preview card's — which is why the child
   combinator is spelled out on both of these. */
.stage > canvas {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: none;
}
.stage > canvas:active { cursor: grabbing; }
/* Armed, the canvas is a target rather than something to take hold of, and `:active` has
   nothing to say about a tool that works in clicks. */
.stage > canvas.is-boxing,
.stage > canvas.is-boxing:active { cursor: crosshair; }

/* The Julia preview under the pointer. It sits in a bottom corner of the stage — the one
   farthest from the pointer, which is what `is-right` switches — so it covers neither the
   hand aiming it nor anything outside the picture. It takes no pointer events at all: a
   card that could be hovered would be a card the pointer could fall into, and the click
   it is previewing belongs to the canvas underneath. Its own × is the exception. */
.julia-preview {
  position: absolute;
  bottom: 0.5rem;
  left: 0.5rem;
  pointer-events: none;
  background: rgb(0 0 0 / 0.75);
  border: 1px solid var(--well-rule);
  padding: 0.3rem;
}
.julia-preview.is-right { left: auto; right: 0.5rem; }

/* A share of the stage rather than the 320px it is drawn at, so the card is the same size
   against the picture on every display, and it never grows past a quarter of the canvas. */
.julia-preview-picture {
  display: block;
  width: min(20rem, 30vw);
  height: auto;
  aspect-ratio: 16 / 9;
}

.julia-preview-said {
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
  margin: 0.25rem 0 0;
  font-family: var(--mono);
  font-size: 0.65rem;
  line-height: 1.3;
  color: var(--well-ink-dim);
  font-variant-numeric: tabular-nums;
}

/* Said only where the mode fell back, because the picture is then not the one entering
   gives and the card has no business implying it is. */
.julia-preview-fell {
  margin-left: auto;
  font-family: var(--sans);
  color: var(--state-sharpening);
}

.julia-preview-off {
  position: absolute;
  top: 0;
  right: 0;
  pointer-events: auto;
  width: 1.2rem;
  height: 1.2rem;
  padding: 0;
  border: none;
  background: rgb(0 0 0 / 0.55);
  color: var(--well-ink-dim);
  font-family: var(--sans);
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
}
.julia-preview-off:hover { color: var(--well-ink); }

.status {
  flex: none;
  margin: 0.4rem var(--gutter) 0;
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--well-ink-dim);
  min-height: 1.2em;
}

/* --------------------------------------------------------------------- the controls */

/* Only what one would turn. Each group is a heading and its own row of controls. The
   grid of four comes first (its own rule is with the Deep tab's, below), and then the
   colour the picture is spent on and how it is spent, then the place. The place is last
   and folded, because a reader who wants to move moves the picture. */
.controls {
  flex: 1 1 auto;
  padding: 0.5rem var(--gutter) 2rem;
}

/* Download is the first section and one row, always open: a button per format first, then
   size, samples, and a few words of estimate taking what is left. Nothing folds, because
   what to save is the last thing a reader decides and the first thing they look for, and
   the buttons lead because they are the one thing on the row everybody presses. On a
   phone the two buttons leave the rest no room, and the row wraps rather than running off
   the side of the page. */
.bar.download { flex-wrap: wrap; gap: 0.5rem; }
.bar.download select { flex: 0 1 auto; min-width: 0; }
.bar.download .group { gap: 0.25rem; }
.bar.download .times { color: var(--well-ink-dim); }
.bar.download input.param { width: 4rem; }
.download .samples { display: inline-flex; gap: 0.25rem; flex: none; }
/* What the canvas is showing, as a bar: the shallow view's Render cell, where the Deep tab
   has its own *(explorer_shallow_deep_parity_ckpt144)*. It sat on the Download row before
   the estimate until then. Its word is its tooltip, and it is as wide as the Deep tab's.

   **It was a dot until this prompt** *(Matt, explorer_box_zoom_and_download_row_ckpt140,
   2026-09-22)*. The colour said which of three stages the pass was in and nothing said how
   far through one it was, so a slow frame and a stuck one looked the same for as long as
   anybody was willing to wait. The bar fills instead, the reading keeps its colour, and
   `--done` is the one thing that moves — written on this element, where the harnesses'
   `data-state` also lives, which is safe because both observers filter on that attribute.

   Full is the resting state, not the empty one: nothing rendering means the picture is
   finished, so the bar sits full in the colour of the last reading. */
.render-state {
  flex: none;
  width: 4rem;
  height: 0.35rem;
  border-radius: 0.2rem;
  overflow: hidden;
  background: var(--well-rule);
}
.render-fill {
  display: block;
  height: 100%;
  width: calc(var(--done, 1) * 100%);
  border-radius: inherit;
  background: var(--state-rendering);
}
.render-state[data-state="sharpening"] .render-fill { background: var(--state-sharpening); }
.render-state[data-state="final"] .render-fill { background: var(--state-final); }
.render-state[data-state="stopped"] .render-fill { background: var(--well-pending); }
/* The shallow Render cell holds the bar and nothing else, so it keeps a button's height and
   the heading beside it on the same line as Navigation's. */
.shallow-go { min-height: 1.9rem; }
.download .estimate {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--well-ink-dim);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* The view buttons are the shallow view's Navigation cell *(explorer_shallow_deep_parity_ckpt144)*,
   the Deep tab's row in look and in order: Box (b), Root (r), the Julia button (j) and
   Find minibrots lead, and what only this view has follows. They were the right end of the
   Download row until then. The Julia preview box is the last item, beside nothing it
   previews any more but still the thing that goes to a second line first. */
.bar.view-toggles { gap: 0.25rem; }
.view-toggles button { white-space: nowrap; }
/* Box (b), armed: the one button in this row that is a state rather than an action, so it
   is lit while it is waiting for the two clicks it takes.

   **Green, and a glow rather than a tint** *(walk_root_frame_and_box_armed_ckpt141)*. It was
   the link blue on the border and the word, which is exactly what `:hover` paints, so the
   press that armed it left the pointer on a button that looked the same as before the
   press. The green is `--state-final`, the one the Download arrow already spends, and the
   `:hover` spelling keeps the glow up while the pointer is still resting on it. */
.view-toggles button.is-armed,
.view-toggles button.is-armed:hover,
.deep-group .deep-actions button.is-armed,
.deep-group .deep-actions button.is-armed:hover {
  border-color: var(--state-final);
  color: var(--state-final);
  box-shadow: 0 0 0 1px var(--state-final), 0 0 8px 1px color-mix(in srgb, var(--state-final) 60%, transparent);
}

/* The preview box among the buttons: a label and a checkbox rather than a button, so it
   takes its own alignment and the label's dim ink. `.bar.shade` used to give it both. */
.view-toggles .group.level {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  flex: none;
  color: var(--well-ink-dim);
  font-size: 0.75rem;
}

/* The button is the progress bar: `--done` fills it from the left while a render draws,
   and its label is how far along it is. A fixed minimum width, so a label going from
   "PNG" to "7%" does not pull the row about.

   **The word "Download" is a green arrow** *(Matt, explorer_box_zoom_and_download_row_ckpt140,
   2026-09-22)*. Saying it twice on one row under a heading that already says it was most of
   what made these two the widest things in the bar; the arrow says the same in one glyph,
   and the button keeps `Download PNG` as its accessible name. The arrow is a span of its
   own so that neither the percentage nor the restore after a render writes over it.

   **And the glyph is drawn rather than typed** *(Matt, explorer_box_shortcuts_ckpt140,
   2026-09-22)*. It was the character `↓`, which every font here renders as a hairline a
   pixel wide at this size — a stroke, beside a solid word, reading as a stray mark rather
   than as the button's verb. One filled path on a 24 box, `currentColor` so the green is
   the span's, sized in `em` off the button's own font so the glyph stands at about the
   text's cap height whatever the row's size does. Same markup the Save bookmark uses. */
.bar button.download-go {
  flex: none;
  min-width: 4.25rem;
  position: relative;
  overflow: hidden;
  border-color: var(--well-ink-dim);
}
.bar button.download-go::before {
  content: "";
  position: absolute;
  inset: 0;
  width: calc(var(--done, 0) * 100%);
  background: var(--well-link);
  opacity: 0.35;
  pointer-events: none;
}
.bar button.download-go .download-label {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.3em;
  font-variant-numeric: tabular-nums;
}
.bar button.download-go .download-arrow {
  color: var(--state-final);
  align-self: center;
  display: block;
  width: 0.95em;
  height: 0.95em;
}
.bar button.download-go .download-arrow svg { display: block; width: 100%; height: 100%; }
.bar button.download-go .download-arrow path { fill: currentColor; }

/* The render stat line, first under Details. */
.stats {
  margin: 0 0 0.4rem;
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--well-ink-dim);
}
.stats:empty { display: none; }

.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.9rem;
  font-family: var(--sans);
  font-size: 0.8rem;
}
.bar + .bar { margin-top: 0.4rem; }
.bar .group { display: inline-flex; align-items: center; gap: 0.35rem; }
.bar .group:empty { display: none; }
.bar label { color: var(--well-ink-dim); }

.bar select,
.bar input {
  font: inherit;
  font-size: 0.8rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.15rem 0.3rem;
  max-width: 100%;
}
.bar select:focus-visible,
.bar input:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }
.bar input.constant { width: 13rem; font-family: var(--mono); font-size: 0.75rem; }
.bar input.param { width: 5rem; }
.bar input.flag { width: auto; accent-color: var(--well-link); }
.bar input.slider {
  width: 8rem;
  padding: 0;
  border: none;
  background: none;
  accent-color: var(--well-link);
}

/* Reverse and Mirror are toggle chips, which carry their own look from the gallery's
   filters; the bar's button rule is kept off them. */
.bar button:not(.chip) {
  font: inherit;
  font-size: 0.8rem;
  color: var(--well-ink);
  background: var(--well);
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.15rem 0.5rem;
  cursor: pointer;
}
.bar button:not(.chip):hover { border-color: var(--well-ink-dim); color: var(--well-link); }

/* Save, beside the downloads: the same bookmark a tile's mark is, and the word for what it
   will do, filled in the accent once the view is on the Saved tab. */
.bar button.save-view { display: inline-flex; align-items: center; gap: 0.3rem; }
.bar button.save-view svg { width: 0.85rem; height: 0.85rem; }
.bar button.save-view path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linejoin: round; }
.bar button.save-view[aria-pressed="true"] { color: var(--well-link); border-color: var(--well-link); }
.bar button.save-view[aria-pressed="true"] path { fill: currentColor; }
/* `aria-disabled` is faded exactly as `disabled` is, for a button that has to keep its hover
   title while it is unavailable — a natively disabled button takes no pointer events in
   Chromium, so the title that says why never shows. Shallow mode is the one today. */
.bar select:disabled,
.bar input:disabled,
.bar button:disabled,
.bar button[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.bar button:not(.chip):disabled:hover,
.bar button:not(.chip)[aria-disabled="true"]:hover { border-color: var(--well-rule); color: var(--well-ink); }
.bar .chip:disabled:hover { border-color: var(--well-rule); color: var(--well-ink-dim); }


.studio-bar button {
  font: inherit;
  font-size: 0.8rem;
  color: var(--well-ink);
  background: none;
  border: 1px solid var(--well-rule);
  border-radius: 2px;
  padding: 0.1rem 0.5rem;
  cursor: pointer;
}
.studio-bar button:hover { border-color: var(--well-ink-dim); color: var(--well-link); }

.help, .readout, .provenance {
  margin: 0.35rem 0 0;
  font-family: var(--sans);
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--well-ink-dim);
  max-width: var(--measure);
}
.help:empty, .readout:empty, .provenance:empty { display: none; }
.readout { font-family: var(--mono); overflow-wrap: anywhere; }

/* --------------------------------------------------------------------- the palettes */

/* One group for the colour: the map's name in the header, the map as this view spends it,
   the settings that change how it is spent, and then the picker. The shade settings sit
   between the strip and the picker because the strip is what they move, and because the
   controls a reader turns belong nearer the picture than a list they scroll through. */

/* The palette in force, drawn the way the view spends it, above the tabs so it is on show
   whichever tab is open. */
canvas.palette-final {
  display: block;
  width: 100%;
  height: 1.4rem;
  margin-bottom: 0.4rem;
  border: 1px solid var(--well-rule);
  image-rendering: auto;
}

.bar.shade { gap: 0.3rem 0.9rem; margin-bottom: 0.4rem; }

/* The scale switch: Leveled | Absolute, two halves of one pill. It opens the row because it
   decides which of the controls after it are there at all, the way the Render mode select
   decides the mode's parameters. Absolute is meant to be impossible to miss — the colours
   stop fitting themselves to the frame, and a reader who did not notice the switch would
   read a flat or noisy picture as a broken one — so its pressed half is filled in its own
   colour and the strip above takes the same colour as a frame while it is in force. The
   orange sentence that used to sit under the row is the Absolute half's title now *(Matt,
   palette_absolute_tidy_ckpt144)*. */
.scale-switch { display: inline-flex; gap: 0; }
.bar .scale-switch button:not(.chip) {
  border-radius: 0;
  margin: 0;
}
.bar .scale-switch button:not(.chip):first-child { border-radius: 999px 0 0 999px; }
.bar .scale-switch button:not(.chip):last-child {
  border-radius: 0 999px 999px 0;
  border-left-width: 0;
}
.bar .scale-switch button[aria-checked="true"] {
  color: var(--well);
  background: var(--well-ink);
  border-color: var(--well-ink);
}
.bar .scale-switch button[data-scale="absolute"][aria-checked="true"] {
  background: var(--scale-absolute);
  border-color: var(--scale-absolute);
  font-weight: 600;
}
.palette-group[data-scale="absolute"] canvas.palette-final {
  border: 2px solid var(--scale-absolute);
}
.palette-group .help { margin: 0 0 0.4rem; }

/* A family tab strip, because the library is a thousand maps and a reader wants the one
   that is the colour they are thinking of. Popular is first and is the record's own
   answer to which maps this pool actually seats; the families after it are what each map
   most often produces, which is a reading of the ledger rather than of the gradient. */
.palette-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
  margin-bottom: 0.4rem;
}

.palette-tab {
  appearance: none;
  border: 1px solid transparent;
  border-radius: 2px;
  background: none;
  color: var(--well-ink-dim);
  font-family: var(--sans);
  font-size: 0.75rem;
  padding: 0.1rem 0.45rem;
  cursor: pointer;
  white-space: nowrap;
}
.palette-tab:hover { color: var(--well-ink); }
.palette-tab[aria-selected="true"] {
  color: var(--well-ink);
  border-color: var(--well-rule);
  background: var(--well-pending);
}
.palette-tab:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }
.palette-tab .count { font-variant-numeric: tabular-nums; opacity: 0.6; margin-left: 0.3rem; }

/* The tabs that hold the map in force. A reader who arrived on a link can see where the
   colour they are looking at lives without opening every tab to find it. */
.palette-tab.holds::after {
  content: "";
  display: inline-block;
  width: 0.3rem;
  height: 0.3rem;
  margin-left: 0.3rem;
  vertical-align: 0.05em;
  border-radius: 50%;
  background: var(--well-link);
}

/* As many columns as the panel holds, a row filling before the list scrolls. One column
   under a strip this wide was a thousand maps in a shaft: the All tab is the case that
   matters, and a reader scanning names wants them side by side. */
.swatches {
  max-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--well-rule);
  padding: 0.25rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.75rem, 1fr));
  align-content: start;
  gap: 0.15rem 0.4rem;
}

/* One row: the gradient, and the name under a reader's eye rather than beside a color
   chip. The strip is drawn from the same control points the renderer bakes, so what the
   row shows is what the picture will be spent on. */
.swatch {
  appearance: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  border: 1px solid transparent;
  border-radius: 2px;
  background: none;
  padding: 0.15rem 0.25rem;
  cursor: pointer;
  text-align: left;
}
.swatch canvas {
  display: block;
  width: 5.5rem;
  height: 0.9rem;
  flex: none;
  border: 1px solid var(--well-rule);
}
.swatch .name {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--well-ink-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.swatch:hover { border-color: var(--well-ink-dim); }
.swatch:hover .name { color: var(--well-ink); }
.swatch:focus-visible { outline: 2px solid var(--well-link); outline-offset: -1px; }
.swatch.is-picked { border-color: var(--well-ink); }
.swatch.is-picked .name { color: var(--well-ink); font-weight: 600; }

/* ----------------------------------------------------------------------- the notice */

/* The boot message, and every refusal after it. It is the whole page when it is showing,
   because a page that cannot draw has nothing else to be. */
.notice {
  margin: auto;
  padding: var(--gutter);
  max-width: var(--measure);
  font-family: var(--sans);
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--well-ink);
}
.notice p { margin: 0 0 0.6em; }
.notice a { color: var(--well-link); }
.notice code {
  font-family: var(--mono);
  font-size: 0.85em;
  background: var(--well-pending);
  padding: 0.05em 0.3em;
  border-radius: 2px;
}


/* ---------------------------------------------------------------- the Deep tab
   The Mandelbrot set below the f64 floor. The panel is the controls — Render, the frame
   it would draw, and the iteration cap — because the viewer beside it is the picture and
   a deep picture is the one thing on this page worth the whole column.

   What is NOT here is a second Palette section, and since deep_cap_policy_ckpt138 not a
   second Download row either. A deep field is a smooth field and the engine colours it
   unchanged, so the Palette group under the canvas serves both; and the Download row draws
   whichever view owns the canvas, so it serves both too. The only sections that go away are
   the ones that would be lying: Mode and the family, which have one value each down here.

   And since deep_ui_ckpt140 the panel is NOT where Render is: the Render group sits under
   the canvas, first in the controls, because pressing it is watching the picture. It is the
   one control group that appears only while this tab owns the canvas, which is why it is
   hidden by default and shown rather than the other way about. */
.viewer.is-deep .control-group:not(.palette-group):not(.download-group):not(.deep-group):not(.deep-details):not(.minibrots-under),
.viewer.is-deep #details {
  display: none;
}
.deep-group, .deep-details { display: none; }
.viewer.is-deep .deep-group, .viewer.is-deep .deep-details { display: block; }

/* The tab's intro opens the panel, over the Dive block *(deep_micro_ckpt156)*, so there is no
   rule above it to draw, the way the Phoenix tab's opens *(deep_caption_and_controls_right_ckpt141)*. */
#deep-side-note { border-top: none; }

/* The line over the controls holds a whole line of text while it is empty, not 1.2em: the
   probe's *Raised the cap* lands there during a pass, and the few pixels between the two
   moved the whole grid down and back. Both views, so the grid starts at one height in each. */
.viewer .status { min-height: 1lh; }

/* The control block is a two-by-two grid *(Matt, deep_tab_controls_grid_ckpt144)*: Render
   and Navigation over Iterations and Download, each cell a heading and its row. **Both
   views have it since explorer_shallow_deep_parity_ckpt144**, the shallow one with Render
   mode where Deep has Iterations. Each view's three cells are in a group that is
   `display: contents` while that view owns the canvas, so its cells and the Download group
   are the grid's four items in document order, and auto-placement lays them out.
   Everything else under the canvas runs the width of both columns. The rows are the
   grid's, so a cell's heading lines up with the one beside it.

   **The columns are not equal.** The left cells are short rows of fixed things, and
   Navigation and Download are the long ones, so the left column is as wide as its content
   and the right takes the rest: at an even split the Download row put its estimate on a
   line of its own at 1600 wide. The Deep tab's left column cannot change width with state,
   because Render, Render again and Cancel share one button width (below). **And it is
   never narrower than 21rem**, which is the Deep tab's own measured 20.8: the shallow
   cells are narrower, and without the floor Navigation stood 185 px further left in one
   view than in the other. With it the right column starts at one place in both. Where the viewer
   is narrower than 44rem there is no room for the two, and it is one column in document
   order: Render, Navigation, the cell under Render, Download. */
.viewer { container-type: inline-size; }
.controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem 1.6rem;
  align-content: start;
}
@container (min-width: 44rem) {
  .controls { grid-template-columns: minmax(21rem, max-content) minmax(0, 1fr); }
}
.viewer.is-deep .deep-go .deep-render { min-width: 7.5rem; }
.controls > * { grid-column: 1 / -1; }
.shallow-group { display: contents; }
.viewer.is-deep .deep-group:not(.deep-under) { display: contents; }
.deep-cell,
.shallow-cell,
.controls > .download-group { grid-column: auto; min-width: 0; }
.viewer.is-deep .deep-under:not(:has(> :not(:empty):not([hidden]))) { display: none; }
.minibrots-under:not(:has(> :not(:empty):not([hidden]))) { display: none; }

/* **A mode's parameters wrap, and never widen the column** *(Matt,
   explorer_nav_layout_ckpt145)*. The column is `max-content`, and `threads` has two
   parameters, a label, a slider and a box each: laid out on one line they made the left
   column wide enough to squeeze Navigation and Download, so the right column moved with the
   mode picked. Contained, the cell contributes nothing to the column's width and takes
   whatever the column is; the parameters are items of the row, so they wrap inside it. */
.shallow-cell-mode { contain: inline-size; }
.shallow-cell-mode #params { display: contents; }

/* Render, Auto-render and the bar, on one row. What the pass is doing is the bar's hover
   title, and the live region a screen reader hears is clipped out of the layout: the
   stage name and the time left used to take a line of their own while a pass ran, which
   moved the whole block down and back each time. The spinner keeps its place when it is
   down, for the same reason. */
.deep-go { gap: 0.4rem 0.9rem; }
.deep-go .deep-progress {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The pass in progress, beside the button that stops it. The shallow row's bar, moved:
   full at rest when the picture up is the frame, and in the Download row's three readings
   *(Matt, deep_stall_ckpt143)*. It was one colour, `--well-link`, and that blue said only
   "the Deep tab's bar": the one bar on the page that read differently from the rest. Red
   is nothing of the result up yet (the probe, the orbit, the quarter pass, a file, a
   minibrot search); yellow is a picture of this frame up and a finer one coming (the full
   pass); green is at rest on the frame. `deep.js` writes `data-state`. */
.deep-bar {
  flex: none;
  width: 4rem;
  height: 0.35rem;
  border-radius: 0.2rem;
  overflow: hidden;
  background: var(--well-rule);
}
.deep-bar-fill {
  display: block;
  height: 100%;
  width: calc(var(--done, 0) * 100%);
  border-radius: inherit;
  background: var(--state-rendering);
}
.deep-bar[data-state="sharpening"] .deep-bar-fill { background: var(--state-sharpening); }
.deep-bar[data-state="final"] .deep-bar-fill { background: var(--state-final); }
.deep-bar { --done: 0; }

/* Up whenever a worker is doing something, which is what tells a reader that a line which
   has not changed for a second is still a live frame. */
.deep-spinner {
  flex: none;
  width: 0.7rem;
  height: 0.7rem;
  border: 2px solid var(--well-rule);
  border-top-color: var(--well-link);
  border-radius: 50%;
  animation: deep-spin 0.9s linear infinite;
}
.deep-spinner.is-idle { visibility: hidden; }
@keyframes deep-spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) {
  .deep-spinner { animation-duration: 3s; }
}

/* Render is the one action this tab has, so it is drawn the way Start is on the Walk tab.
   Running, it is Cancel and carries its own progress as a fill, because a button that is
   also the bar is one thing to look at rather than two. */
/* Spelled against `.bar` because the row is a `.bar` now: `.bar button:not(.chip)` is the
   page's own outline button and would take the accent fill straight back off this one. */
.bar button.deep-render {
  appearance: none;
  border: none;
  border-radius: 4px;
  background: var(--well-link);
  color: var(--well);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.3rem 1.1rem;
  cursor: pointer;
  flex: none;
  min-width: 6rem;
}
.bar button.deep-render:hover { background: var(--well-ink); color: var(--well); }
.bar button.deep-render:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }
.bar button.deep-render.is-running { background: var(--well-ink-dim); }
.bar button.deep-render:disabled { opacity: 0.45; cursor: not-allowed; }

.deep-progress {
  min-width: 0;
  color: var(--well-ink-dim);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The watchdog's sentence: a pool that has said nothing for ten seconds reads differently
   from a slow one, in the ink the page already spends on a warning. */
.deep-progress.is-stalled { color: var(--state-sharpening); }

.deep-note {
  margin: 0.4rem 0 0;
  color: var(--well-ink-dim);
  font-size: 0.75rem;
  line-height: 1.5;
}
.deep-note:empty { display: none; }

/* Details' coordinates. A deep centre is up to sixty-four digits and is the one number on
   the page worth reading digit by digit, so its box is wide enough to hold one whole rather
   than scroll it — and wraps onto its own line where the row is narrower than that. */
.bar.deep-coordinates { gap: 0.3rem 0.5rem; }
.bar.deep-coordinates input.constant { width: min(100%, 31rem); }

/* Navigation's buttons are the bar's own outline buttons, the shallow row's look, and Box
   (b) is lit while armed exactly as the shallow one is. */
.deep-group .deep-actions { gap: 0.25rem; }
.deep-group .deep-actions button { white-space: nowrap; }
.deep-under .deep-note { margin: 0; }
.deep-group .side-note,
.minibrots-under .side-note { border-top: none; padding: 0.4rem 0 0; }
.deep-iterations { gap: 0.4rem; }
.deep-iterations input { width: 6.5rem; text-align: right; }

/* The one thing under the canvas a reader can press: the offer at the zoom stop. */
.say-action {
  appearance: none;
  border: 1px solid var(--well-link);
  border-radius: 4px;
  background: none;
  color: var(--well-link);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.1rem 0.6rem;
  cursor: pointer;
  white-space: nowrap;
}
.say-action:hover { background: var(--well-link); color: var(--well); }
.say-action:focus-visible { outline: 2px solid var(--well-link); outline-offset: 2px; }

/* A saved deep picture carries no thumbnail — drawing one needs the perturbation kernel
   and a wait of seconds a tile — so its cell is the label over the well it would have
   filled, which says what it is rather than showing a broken image. */
.saved-tile.is-deep { background: var(--well-pending); }
.saved-tile.is-deep img { visibility: hidden; }

/* ------------------------------------------------------- Find minibrots, in either view

   An ephemeral list: nothing here is stored, nothing reaches Saved, and the whole thing is
   cleared by the next search and by any change of location. It sits under the picture,
   straight under the row that opens it *(deep_caption_and_controls_right_ckpt141)*, where
   the column is wide: as many across as leave each entry about the width the side panel
   gave two of, so the line of text under a picture is never wider than the picture. */
.minibrots {
  padding: 0.4rem 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 0.4rem;
  /* The gallery's ruling, for the gallery's reason: an auto row asks a block holding one
     replaced element for a minimum height and is told zero. */
  grid-auto-rows: max-content;
  align-items: start;
}

.minibrot {
  appearance: none;
  padding: 0;
  border: 1px solid transparent;
  background: none;
  color: var(--well-ink-dim);
  cursor: pointer;
  text-align: left;
  font: inherit;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.minibrot:hover { border-color: var(--well-ink-dim); color: var(--well-ink); }
.minibrot:focus-visible { outline: 2px solid var(--well-link); outline-offset: -2px; }

/* The well a tile lands in, which is also what says why one has not. It holds the tile's
   own 16:9 from the start so the list does not reflow as pictures arrive — a row of
   entries that jumped every time a forty-second render landed would be unusable. */
.minibrot-tile {
  aspect-ratio: 16 / 9;
  background: var(--well-pending);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.4rem;
  text-align: center;
  font-size: 0.7rem;
  line-height: 1.25;
  overflow: hidden;
}
.minibrot-tile canvas { display: block; width: 100%; height: auto; }

.minibrot-said { font-size: 0.7rem; font-variant-numeric: tabular-nums; }

/* An entry whose centre is past what a link can spell. It is still listed — the search
   found it and saying so is the honest thing — but there is nowhere to send a reader. */
.minibrot:disabled { cursor: default; opacity: 0.55; }
.minibrot:disabled:hover { border-color: transparent; color: var(--well-ink-dim); }

/* The Dive block *(deep_dive_block_ckpt154)*: at the top of the Deep tab's panel, over the
   tab's sentence and its gallery, because it chooses which view is up — the studio's rule
   for the left side. One sentence with its two blanks as dropdowns and Go at its end, the
   New coloring box, and the one bar, Cancel and status line a press runs under. Go is the
   Render button's accent: it is this block's one action. */
.dive { flex: none; padding: 0.6rem var(--gutter) 0.55rem; }
.dive .bar + .bar { margin-top: 0.35rem; }
.dive-sentence { gap: 0.3rem 0.4rem; }
.dive-sentence label { color: var(--well-ink); }
.bar button.deep-render.dive-go { min-width: 0; padding: 0.2rem 0.9rem; }
.bar button.deep-render.dive-go[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.dive-progress { gap: 0.5rem; min-height: 1.4rem; }
.dive-progress .deep-bar { width: 8rem; }
.dive-status {
  margin: 0.3rem 0 0;
  color: var(--well-ink-dim);
  font-family: var(--sans);
  font-size: 0.75rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.dive-status:empty { display: none; }

/* The two slots *(dive_slots_ckpt154)*: a thumbnail with its mode buttons stacked beside it,
   the lit one the mode. The thumbnail is 16:9 like every picture in the well, with a word
   across its foot saying what it holds; it is a button where it holds a frame to go to. */
.dive-words { color: var(--well-ink); }
.dive-slot { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.3rem; }
.dive-slot[hidden] { display: none; }
.dive-thumb {
  position: relative;
  flex: none;
  width: 6.4rem;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 1px solid var(--well-ink-dim);
  border-radius: 2px;
  background: var(--well-pending);
  overflow: hidden;
  cursor: pointer;
}
/* A thumbnail with no frame to go to is still a picture, and is never faded
   *(dive_mixture_ckpt154)*: the bar's rule for a faded button read the Random slot's plate as
   a greyed control. What is lit is the mode button, filled below. */
.dive-thumb[aria-disabled="true"] { cursor: default; }
.bar button.dive-thumb[aria-disabled="true"] { opacity: 1; }
.dive-thumb:not([aria-disabled="true"]):hover { border-color: var(--well-ink); }
.dive-thumb:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
.dive-thumb canvas, .dive-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.dive-thumb [hidden] { display: none; }
.dive-thumb-said {
  position: absolute;
  inset: auto 0 0 0;
  padding: 0.05rem 0.3rem;
  background: rgb(0 0 0 / 0.6);
  color: var(--well-ink);
  font-family: var(--sans);
  font-size: 0.65rem;
  line-height: 1.3;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dive-modes { display: inline-flex; flex-direction: column; gap: 0.12rem; }
.bar .dive-modes button { padding: 0 0.4rem; font-size: 0.7rem; line-height: 1.35; }
.bar .dive-modes button[aria-pressed="true"] {
  color: var(--well);
  background: var(--well-link);
  border-color: var(--well-link);
  font-weight: 600;
}
.bar .dive-modes button.is-barred { opacity: 0.45; }
.dive-paste { flex: 1 0 100%; min-width: 0; font: inherit; font-size: 0.75rem; }

/* ------------------------------------------------------------ the Deep tab's gallery

   Under the tab's sentence *(deep_gallery_build_ckpt144)*, and always open, the way the
   Gallery tab is *(explorer_nav_layout_ckpt145)*: it was a `<details>` folded until a click.
   It takes the height the panel has left and scrolls inside it, the starting points'
   ruling: three tiles to a row, each subject's name over its run of them. **The panel is
   the scroller, not the grid**, which is what it had to be while it was a `<details>` and
   is kept: one scroller, and the heading stays put over the tiles as they scroll. */
.deep-gallery {
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--well-ink-dim) transparent;
}
.deep-gallery > .section-head {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 0 var(--gutter);
  background: var(--well);
}
.deep-gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* The minibrots' ruling, for the minibrots' reason. */
  grid-auto-rows: max-content;
  gap: 0.4rem;
  padding: 0.2rem var(--gutter) 0.6rem;
  align-items: start;
}
.deep-gallery-subject {
  grid-column: 1 / -1;
  margin: 0.4rem 0 0;
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--well-ink-dim);
}
.deep-gallery-subject:first-child { margin-top: 0; }
/* The switch between the gallery, Dive results and Random dives *(dive_slots_ckpt154,
   random_dives_ckpt155)*: three buttons, the lit one the list that is up, and Clear at the
   far end while Dive results is. The panel's `data-show` names the list and the stylesheet
   shows it, so no list's own code has to know the others are there. */
.deep-lower-head { display: flex; align-items: center; gap: 0.5rem; padding-block: 0.3rem; }
.deep-switch { display: inline-flex; gap: 0.25rem; }
.deep-lower-head button {
  padding: 0.1rem 0.55rem;
  border: 1px solid transparent;
  border-radius: 3px;
  background: none;
  color: var(--well-ink-dim);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}
.deep-lower-head button:hover { color: var(--well-ink); }
.deep-switch button[aria-pressed="true"] { color: var(--well-ink); border-color: var(--well-ink-dim); }
.deep-lower-head button:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
#dive-results-count { font-variant-numeric: tabular-nums; }
#dive-results-clear { margin-left: auto; font-weight: 400; }
#dive-results-clear[hidden] { display: none; }
.deep-gallery:not([data-show="results"]) > .dive-results,
.deep-gallery:not([data-show="results"]) > #dive-results-note,
.deep-gallery:not([data-show="random"]) > .random-dives,
.deep-gallery:not([data-show="random"]) > #random-dives-note,
.deep-gallery:not([data-show="gallery"]) > #deep-gallery-grid,
.deep-gallery:not([data-show="gallery"]) > #deep-gallery-note { display: none; }
#dive-results-note,
#random-dives-note { padding: 0 var(--gutter); }
/* **Two to a row** *(dive_mixture_ckpt154)*: a result is a picture to judge, and at the
   gallery's three it was too small to judge. A narrow panel wraps them to one. */
.deep-gallery-grid.dive-results { grid-template-columns: repeat(auto-fill, minmax(min(100%, 12rem), 1fr)); }
.dive-result { display: flex; flex-direction: column; gap: 0.1rem; }
.dive-result > .minibrot { width: 100%; }
.dive-foot { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.dive-variant {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--well-ink);
  font-size: 0.7rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dive-copy {
  flex: none;
  align-self: flex-start;
  padding: 0;
  border: none;
  background: none;
  color: var(--well-ink-dim);
  font: inherit;
  font-size: 0.68rem;
  cursor: pointer;
}
.dive-copy:hover { color: var(--well-link); }
.dive-copy:focus-visible { outline: 2px solid var(--well-link); outline-offset: 1px; }
.deep-gallery-tile .minibrot-tile { padding: 0; }
.deep-gallery-tile .minibrot-tile img { display: block; width: 100%; height: auto; }

/* ------------------------------------------------------------------- the Phoenix tab */

/* The plane is the panel's picture, so it takes the panel's width and a 16:9 share of it,
   and the controls under it are the viewer's own bar. The first note sits at the top of
   the panel, where there is no rule above it to draw. */
.phoenix-says { border-top: none; }
.phoenix-plane {
  flex: none;
  position: relative;
  margin: 0 var(--gutter);
  border: 1px solid var(--well-rule);
  background: var(--well);
}
.phoenix-canvas {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  cursor: crosshair;
  touch-action: none;
}
.phoenix-canvas.is-dragging { cursor: grabbing; }

/* The starting points: the Find-minibrots tile, three to a row, under the plane and its
   `p`. The plane is the panel's picture and keeps its place at the top, so the panel does
   not scroll; the grid takes what height is left and scrolls inside it. Three across a side
   panel keeps them small, which is the point: these are ways in, and the plane is what gets
   looked at. */
.phoenix-points-head { flex: none; padding: 0 var(--gutter); }
.phoenix-points {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--well-ink-dim) transparent;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* The minibrots' ruling, for the minibrots' reason. */
  grid-auto-rows: max-content;
  gap: 0.4rem;
  padding: 0.2rem var(--gutter) 0.6rem;
  align-items: start;
}
.phoenix-point .minibrot-tile { padding: 0; }
.phoenix-point .minibrot-tile img,
.phoenix-point .minibrot-tile canvas { display: block; width: 100%; height: auto; }
.bar.phoenix-p { padding: 0.5rem var(--gutter); }
.bar.phoenix-p input.slider { flex: 1 1 6rem; width: auto; }
.bar.phoenix-p .phoenix-preview-on { margin-left: auto; }
/* Im p, beside the box that holds Re p: read, never typed, and there only while a starting
   point put it there. */
.phoenix-p-im { font-size: 0.8rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.phoenix-p-im[hidden] { display: none; }

/* The card sits over a plane a panel wide rather than over the stage, so it is sized to the
   plane: a picture half as wide as it, in the corner away from the pointer. */
.phoenix-preview .julia-preview-picture { width: 45cqi; min-width: 8rem; }
.phoenix-plane { container-type: inline-size; }
