/* synced from Editage by scripts/sync.mjs — do not edit here */

/* ====================================================================
   TOKENS — lifted from the SANROK brand guide (Figma node 2:976, `uix`).
   The numbered scale is the brand's own naming: 100 is the ink, 500 the
   lightest ground. Alphas are separate tokens there, so they are separate
   here — never rgba() written inline, or the palette stops being one.
   ==================================================================== */
:root{
  --100:#293b3c; --100-75:rgba(41,59,60,.75); --100-50:rgba(41,59,60,.5);
  --100-35:rgba(41,59,60,.35); --100-15:rgba(41,59,60,.15);
  /* 788:286 — the editor's ground. Not on the brand scale: a true neutral
     grey, so a picture's colour is judged against nothing tinted. */
  --editor-ground:#505050;
  --200:#cfcdc8; --300:#d9d7d2; --300-60:rgba(217,215,210,.6);
  --400:#e5e2dd; --500:#edeae6;
  /* One step brighter than --500, for a hover that answers without
     changing what a control is: about 4% of light, the least that reads. */
  --600:#f5f3f0;
  --error:#e23c2a; --accent:#706ce0; --confirm:#298233; --blue:#1f59d5; --warning:#df930f;
  /* The crop's outside, dimmed. */
  --shade:rgba(24,24,24,.55); --crop-line:rgba(237,234,230,.95); --crop-grid:rgba(237,234,230,.45);
  --1:4px; --2:6px; --3:8px; --4:12px; --4t:11px; --5:16px; --6:24px; --8:48px;
  --r:4px;
  /* The site's one curve: the flyout, the index, the board, the hover. */
  --ease:cubic-bezier(.45,.05,.25,1);
  --mono:'Chivo Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --serif:'Platypi',Georgia,'Times New Roman',serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  background:var(--300); color:var(--100);
  font:300 14px/normal var(--mono); letter-spacing:-.01em;
  overflow:hidden; overscroll-behavior:none;
  -webkit-font-smoothing:antialiased;
}
button{font:inherit;letter-spacing:inherit;color:inherit;background:none;border:0;cursor:pointer}
/* The flyout's actions are two anchors and a button that must read as one
   set — without this the anchors arrive in the UA's link blue with an
   underline, and the row stops looking like a row. */
a{color:inherit;text-decoration:none;cursor:pointer}
input,textarea{font:inherit;letter-spacing:inherit;color:inherit;background:none;border:0;outline:0}
img{display:block;max-width:100%}
:focus-visible{outline:1px solid var(--100);outline-offset:1px}
/* A FIELD paints its focus on its own box, so the global ring must not
   also land on the input inside it — that ring was the black rectangle
   hugging the search placeholder, sitting inside the violet one. The
   global rule stays for buttons and links, which have no box of their
   own to light up. */
input:focus-visible,textarea:focus-visible{outline:0}
.field:focus-within,.select>button:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}

/* Icons are MASKS, not <img> — one asset then serves every colour the
   design asks of it (the red trash and the ink trash are one file). */
.i{display:block;background:currentColor;-webkit-mask-size:contain;mask-size:contain;
   -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center}
.i-16{width:16px;height:16px} .i-18{width:18px;height:18px}
.i-22{width:22px;height:22px} .i-24{width:24px;height:24px}

/* ------------------------------------------------------------ the field --- */
/* Nothing in the field is selectable. A drag on a canvas is a PAN, and
   without this the browser reads the same gesture as a text selection:
   captions highlight blue, pictures pick up the drag-a-copy ghost, and a
   pan that crosses a card leaves the selection behind it. The overlays
   are not children of #field, so their text stays selectable. */
#field{position:fixed;inset:0;touch-action:none;cursor:grab;contain:strict;
  user-select:none;-webkit-user-select:none}
#field img{-webkit-user-drag:none;user-drag:none}
#field.is-panning{cursor:grabbing}
#plane{position:absolute;inset:0;transform-origin:0 0;will-change:transform}
.slot{position:absolute;top:0;left:0;width:350px;will-change:transform;
      transition:translate .18s ease-out}
/* 746:15838 — hover, on the site's own curve (the flyout's, --ease): the
   card lifts and the caption rises into its foot. In takes its time, out is
   a little quicker, so a pointer sweeping across the board never leaves a
   trail of cards still settling.
   The shadow is not animated as a box-shadow — that repaints a blur every
   frame. It is drawn once, on a layer under the card, and only its opacity
   and position move, which the compositor does alone. */
.slot::before{content:"";position:absolute;inset:0;border-radius:var(--r);pointer-events:none;
  box-shadow:0 8px 24px rgba(41,59,60,.12);opacity:0;
  transition:opacity .3s var(--ease),transform .3s var(--ease)}
.card{
  position:relative;width:350px;border-radius:var(--r);overflow:hidden;
  background:var(--200);cursor:pointer;
  transition:transform .3s var(--ease);
}
/* Hovered by the SLOT, which never moves, not the card, which lifts 8px.
   Keyed on the card, a pointer in its bottom 8px was left behind by the
   lift, the hover dropped, the card fell back under the pointer and the
   hover began again — the caption rising and falling without end. The slot
   keeps the card's resting box, and the lifted card is inside it, so the
   hover holds anywhere on either. And the slot takes the click there. */
.slot{cursor:pointer}
#field:not(.is-panning) .slot:hover > .card{transform:translateY(-8px);transition-duration:.42s}
#field:not(.is-panning) .slot:hover::before{opacity:1;transform:translateY(-8px);transition-duration:.42s}
/* Both absolute, and the picture LAST. A positioned box paints in a later
   layer than an in-flow one whatever the DOM order says — with the <img>
   in flow, the placeholder sat on top of it and every card rendered as a
   flat grey rectangle with the picture fully loaded behind it. */
.card .ph{position:absolute;inset:0;background:var(--200)}
.card img,.card video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* A card still waiting for its picture. The ground is already the
   picture's own average colour; over it the SANROK monogram turns — twelve
   21px frames (Figma 527:8343), drawn at half its own 900ms pace — in ink
   that reads on that colour (--ld, set per card: light on dark grounds, dark
   on light ones). It waits a quarter second before it shows, so a picture
   that is quick never flashes it, and the picture fades up over it when it
   lands.
   One element per card, its strip moved in steps by transform alone, so a
   board full of loading cards costs the compositor and not the page.
   Drawn at 42px — twice the 21px art, a whole multiple, so every pixel of
   the monogram lands on a whole number of screen pixels — and placed on
   whole pixels too. */
.card .ld{position:absolute;left:calc(50% - 21px);top:calc(50% - 21px);
  left:round(down, 50% - 21px, 1px);top:round(down, 50% - 21px, 1px);width:42px;height:42px;overflow:hidden;
  pointer-events:none;opacity:0;animation:ldIn .3s ease-out .25s forwards}
.card .ld::after{content:"";position:absolute;left:0;top:0;width:504px;height:42px;background:var(--ld,rgba(41,59,60,.4));
  -webkit-mask:url(/assets/loader-monogram.svg) 0 0/504px 42px no-repeat;mask:url(/assets/loader-monogram.svg) 0 0/504px 42px no-repeat;
  animation:ldRun 1800ms steps(12) infinite}
@keyframes ldIn{to{opacity:1}}
@keyframes ldRun{to{transform:translateX(-504px)}}
.card img{opacity:0;transition:opacity .32s var(--ease)}
.card.ready img{opacity:1}
.card.ready .ld{opacity:0;animation:none;transition:opacity .16s ease-out}
/* While the card's copy is in flight, the card is only its tone: the picture
   shows once, on the copy. Back in one frame when the copy lands on it. */
.card.inflight img,.card.inflight video,.card.inflight .ld{visibility:hidden !important;transition:none !important}
/* Behind an open panel the board is its colours alone: the scrim blurs
   everything back there anyway, so the pictures step aside and the tone
   each card was painted with shows through instead. */
#field.resting .card img,#field.resting .card video{opacity:0;transition:opacity .2s ease-out}
#field.resting .card .ld{opacity:0;animation:none}
/* Arrived before it was ever shown: no fade at all. */
.card.instant img{transition:none}
@media (prefers-reduced-motion:reduce){.card .ld{opacity:.8}.card .ld::after{animation:none;transform:none}}
/* 745:15830 — the hover caption. A solid bar across the foot of the card
   rather than a wash over the picture: 100px tall, --200 at 97%, 16px on
   every side, the title against the ink and the pixel size at 50%, pushed
   apart by space-between. The lift and the shadow are untouched.
   The ground is --400 flat — it was --200 at 97%, and the translucency is
   gone with it, so nothing of the picture shows through the bar.

   100 rather than the 120 first drawn: the frame it was drawn in is 1038
   tall, and against the real shelf nine cards in a hundred are under 240,
   where 120 took most of the picture. */
.card .caption{
  position:absolute;left:0;right:0;bottom:0;height:100px;
  display:flex;flex-direction:column;align-items:flex-start;justify-content:space-between;
  padding:var(--5);overflow:hidden;
  background:var(--400);
  font-size:14px;letter-spacing:-.14px;
  opacity:0;transform:translateY(12px);
  transition:opacity .24s var(--ease),transform .3s var(--ease);
}
/* The words follow the bar in, a beat apart. */
.card .caption p{transform:translateY(6px);transition:transform .3s var(--ease)}
/* Drawn as a clip, built as an ellipsis. The two are identical for a title
   that fits, which is every title in the frame; they differ only when one
   does not, and a clip there cuts mid-letter and reads as a bug. */
.card .caption p{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card .caption .dim{color:var(--100-50)}
#field:not(.is-panning) .slot:hover .caption{opacity:1;transform:none;transition-duration:.32s,.42s}
#field:not(.is-panning) .slot:hover .caption p{transform:none;transition-duration:.42s}
#field:not(.is-panning) .slot:hover .caption p + p{transition-delay:.04s}
@media (prefers-reduced-motion:reduce){
  .card,.slot::before,.card .caption,.card .caption p{transition-property:opacity}
  #field:not(.is-panning) .slot:hover > .card,.card .caption,.card .caption p,
  #field:not(.is-panning) .slot:hover::before{transform:none}
}

/* ----------------------------------------------------------- the headbar ---
   747:15980 — a 177px panel, not a bar. Logo and INDEX on one row, then
   #control, then the search. The drag handle is hidden in the design, so
   the panel is fixed and the grip and its stored position are gone. */
#headbar{
  /* 24 from the top and the left on load, then wherever it is dragged to.
     Set from JS so the drag and the default share one source. */
  position:fixed;z-index:40;
  width:177px;max-width:calc(100vw - 16px);
  display:flex;flex-direction:column;align-items:flex-start;
  padding:var(--3);border-radius:8px;
  /* 747:15980 — a rule along the bottom only, not a border all round. */
  background:var(--400);border-bottom:1px solid var(--100-15);
}
/* 842:3469 — the field's count, 24 in from the bottom left: shown/total,
   10px at 75% ink on --400, 4px in, with a rule along the bottom. */
#fieldCount{position:fixed;left:24px;bottom:calc(24px + env(safe-area-inset-bottom,0px));z-index:40;margin:0;
  padding:var(--1);border-radius:var(--r);background:var(--400);border-bottom:1px solid var(--100-15);
  font-size:10px;letter-spacing:-.1px;line-height:normal;color:var(--100-75);
  font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none;user-select:none}
#fieldCount:empty,#fieldCount[hidden]{display:none}
@media (max-width:767px){#fieldCount{left:16px;bottom:calc(16px + env(safe-area-inset-bottom,0px))}}
/* 747:16050 — the header, 18 tall: the grip at the left, EDITAGE in the
   middle, the logogram at the right, pushed apart. The whole row drags. */
#headbar .bar-top{display:flex;align-items:center;justify-content:space-between;width:100%;
  height:16px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}
/* 906:9802 — the fold. The body's rows go from its height to none on the
   site's curve (a grid row, so no height is ever measured), and the 12 above
   it goes with it, so folded the panel is exactly the header: 8 + 16 + 8.
   What is inside fades a beat ahead on the way in and behind on the way out,
   so the rows never slide past the edge half-drawn. */
#headbar .barwrap{display:grid;grid-template-rows:1fr;width:100%;transition:grid-template-rows .38s var(--ease)}
#headbar .barbody{min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:var(--4);width:100%;
  transition:opacity .22s ease-out .12s}
/* A margin, not padding: padding would hold the folded row open by 12. */
#headbar .barbody > :first-child{margin-top:var(--4)}
#headbar.open-done .barbody{overflow:visible}
#headbar.folded .barwrap{grid-template-rows:0fr}
#headbar.folded .barbody{opacity:0;transition:opacity .16s ease-out}
/* The minus and plus are one icon: the plus's upright folds away into the
   minus as the panel folds, and rises out of it as it opens. */
#headbar .bartoggle{position:relative;flex:none;width:16px;height:16px;padding:0;cursor:pointer;color:var(--100-75);border-radius:2px}
#headbar .bartoggle i{position:absolute;left:2px;top:7.5px;width:12px;height:1px;border-radius:1px;background:currentColor;
  transition:transform .38s var(--ease)}
#headbar .bartoggle .v{transform:rotate(90deg) scaleX(0)}
#headbar.folded .bartoggle .v{transform:rotate(90deg) scaleX(1)}
#headbar .bartoggle:hover{color:var(--100)}
#headbar .bartoggle:focus-visible{outline:1px solid var(--accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){#headbar .barwrap,#headbar .barbody,#headbar .bartoggle i{transition:none}}
#headbar.is-dragging .bar-top{cursor:grabbing}
/* The 9x15 dots turned a quarter, in a 15x9 box. */
#grip{display:flex;align-items:center;justify-content:center;width:15px;height:9px;flex-shrink:0;color:var(--100)}
#grip .i{width:9px;height:15px;flex:none;transform:rotate(-90deg)}
#grip:focus-visible{outline:1px solid var(--accent);outline-offset:2px;border-radius:2px}
#headbar .wordmark{font-size:12px;letter-spacing:-.12px;color:var(--100);white-space:nowrap}
.logo{display:flex;align-items:center;flex-shrink:0}
.logo img{width:18px;height:18px;display:block}

/* Two sections, same rhythm: the five filters under #categories, and
   /randomise and /index under #control. The 12px between them is the panel's
   own gap, because every block in here is a direct child of it. */
#categories,#control{display:flex;flex-direction:column;gap:var(--2);width:100%}
.filt{display:flex;align-items:center;gap:var(--3);width:100%;text-align:left;padding:0}

/* secondary-nav, juko's 109:1845 exactly: the CARET carries the state, not
   the underline. Hover shows it in ink with NO gap; selected shows it in
   --accent WITH a 6px gap — and the gap is the point, because it makes a
   selected row read as pushed open rather than merely recoloured. The
   label's underline stays at 35% throughout.

   This replaces an earlier guess of mine, where the active row took a
   full-ink underline. That was invented because the Figma component draws
   only the default state; juko had already answered it. */
.filt .nav{display:flex;flex:1 1 0;min-width:0;gap:0;align-items:flex-start}
.filt[aria-current="true"] .nav{gap:var(--2)}
/* The hover caret EASES in, as juko's does: it opens from nothing to its one
   character and pushes the label over as it goes, rather than appearing.
   max-width, not display, because display cannot transition; 1ch is exactly
   one Chivo Mono glyph, so at rest the row measures what it did before.
   160ms on the site's curve. Picking a row is slideCaret()'s, in app.js. */
.filt .caret{flex:none;white-space:nowrap;color:var(--100);display:block;max-width:0;opacity:0;overflow:hidden;
  transition:max-width .16s var(--ease),opacity .16s var(--ease)}
.filt:hover .caret{max-width:1ch;opacity:1}
.filt[aria-current="true"] .caret{max-width:1ch;opacity:1;color:var(--accent)}
/* For the one style change slideCaret measures across, so its own motion
   is the only one: a caret easing open would move the label it is sliding. */
.snap .filt .caret{transition:none}
@media (prefers-reduced-motion:reduce){.filt .caret{transition:none}}
.filt .label{
  flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  text-decoration:underline;text-underline-position:from-font;
  text-decoration-color:var(--100-35);
}
.filt:focus-visible{outline:2px solid var(--accent);outline-offset:0;border-radius:var(--r)}
.filt kbd{
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  width:16px;height:16px;border:1px solid var(--100-35);border-radius:2px;
  font:inherit;font-size:10px;letter-spacing:-.1px;color:var(--100-50);
}

/* The search box, juko's §8 exactly. One field is the whole text filter —
   no dropdown; completion is inline GHOST TEXT and Tab turns it into a
   chip. The drawn focus ring is on the BOX, painted from a class, which
   is why #q deliberately has no :focus rule of its own. Do not add one. */
.searchbox{
  display:flex;align-items:center;flex-wrap:wrap;gap:var(--3);
  width:100%;min-height:40px;padding:var(--4t) var(--4);border-radius:var(--r);
  background:var(--500);border-top:1px solid var(--100-35);
}
.searchbox.focus{outline:1px solid var(--accent);outline-offset:-1px}
.searchbox.blink{animation:searchBlink .3s ease 2}
@keyframes searchBlink{0%,100%{box-shadow:0 0 0 0 rgba(112,108,224,0)}
  50%{box-shadow:0 0 0 2px var(--accent)}}
@media (prefers-reduced-motion:reduce){.searchbox.blink{animation:none}}

.qwrap{position:relative;flex:1 0 40px;min-width:40px;height:18px}
.qwrap input{position:absolute;inset:0;width:100%;background:transparent;z-index:2}
.qwrap input::placeholder{color:var(--100-50)}
.qwrap .ghost{position:absolute;inset:0;line-height:18px;pointer-events:none;
  white-space:pre;color:var(--100-50);z-index:1}
.qwrap .ghost em{color:transparent;font-style:normal}

.chips{display:flex;gap:var(--1);flex-wrap:wrap}
/* 41:2334 — the tag: --300 ground, 4px corners, 4 / 6 padding, the word
   and its × in ink at 14px with 6 between. */
.chip{display:flex;gap:var(--2);align-items:center;justify-content:center;white-space:nowrap;
  background:var(--300);border-radius:var(--r);padding:var(--1) var(--2);
  font-size:14px;letter-spacing:-.14px;line-height:normal;color:var(--100)}
.chip b{font-weight:300}
.chip button{color:var(--100);padding:0;font:inherit;line-height:normal}
.chip button:focus-visible{outline:1px solid var(--accent);outline-offset:1px;border-radius:2px}

.shortcut{
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  height:16px;padding:0 var(--1);border:1px solid var(--100-15);border-radius:2px;
  font-size:10px;letter-spacing:-.1px;color:var(--100-50);
}
/* 36:647 — the search's ⌘K: a 10px Command glyph and the K, 2px in. Off a
   Mac the glyph gives way to "Ctrl". */
.shortcut.kmod{min-width:22px;padding:0 2px;gap:1px;overflow:hidden}
.shortcut.kmod .cmd{width:10px;height:10px;flex:none}
.shortcut.kmod .ctrl{display:none}
html.notmac .shortcut.kmod .cmd{display:none}
html.notmac .shortcut.kmod .ctrl{display:inline;margin-right:3px}
/* The search fields' placeholder runs out in an ellipsis, as drawn. */
.qwrap input,.field.search input{text-overflow:ellipsis}

/* ----------------------------------------------------------- the buttons ---
   741:13892's `buttonplain-icon-left` and the stroked one the empty state
   uses. Both lived inside the old headbar block and went with it when that
   was replaced — leaving two <a class="btn-plain"> as inline elements, so
   the 16px icon (a block) forced a line break and every action in the
   flyout stacked its icon above its label. They are separated out now
   because nothing about them belongs to the headbar. */
.btn-plain{
  display:flex;align-items:center;gap:var(--2);height:40px;flex-shrink:0;
  padding:0 var(--4) 0 var(--4t);border-radius:var(--r);white-space:nowrap;
  transition:background .12s;
}
.btn-plain:hover{background:var(--300)}
.btn-plain[disabled],.btn-plain.off{color:var(--100-35);cursor:default}
.btn-plain[disabled]:hover,.btn-plain.off:hover{background:none}

.btn-stroke{
  display:flex;align-items:center;justify-content:center;gap:var(--2);
  height:40px;padding:0 var(--4) 0 var(--4t);
  border:1px solid var(--100-35);border-radius:var(--r);
  white-space:nowrap;flex-shrink:0;transition:background .12s;
}
.btn-stroke:hover{background:var(--500)}

/* ---------------------------------------------------------- the overlays --- */
/* One wash for every overlay — juko's 285:11317 shape, with the ground at
   60% rather than 90%. At 90% only a tenth of the board came through and
   the field behind read as flat paper; at 60% the pictures are still there,
   just held back. The 12px blur does the rest of the work — it is what
   stops the board competing, not the opacity. Two different washes in one
   app would read as two different apps, so #index shares this. */
.scrim{position:fixed;inset:0;z-index:50;
       background:var(--300-60);
       backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
       /* Hidden with visibility, NOT display. display:none cannot be
          transitioned, so the wash used to vanish in a single frame on close
          while the picture was still flying back over a board that had
          already snapped into focus. Visibility waits for the fade. */
       visibility:hidden;opacity:0;
       transition:opacity .3s ease-out,visibility 0s linear .3s}
.scrim.open{visibility:visible;opacity:1;transition:opacity .14s ease-out,visibility 0s}
.bumper{display:flex;align-items:center;gap:var(--1);width:100%}
.bumper span{font-size:10px;letter-spacing:-.1px;color:var(--100-50);white-space:nowrap}
.bumper i{flex:1 1 0;min-width:0;height:1px;background:var(--100-15)}
/* A tool's top line: which step it is editing. */
.bumper .stepno{font-style:normal;font-size:10px;letter-spacing:-.1px;color:var(--100-50);white-space:nowrap}
.close{display:flex;align-items:center;justify-content:flex-end;gap:var(--2);flex-shrink:0}

/* #index — 781:16328. As wide as the quick look it opens into (80% of the
   window, between 1024 and 1280), so a row opening its picture and the
   picture closing back to the list stay one size; as tall as the window
   allows, 32px clear all round, centred on the wash. */
#index{position:fixed;inset:0;margin:auto;z-index:60;display:flex;flex-direction:column;
       width:min(clamp(1024px, 80vw, 1280px), 100% - 64px);height:calc(100% - 64px);
       border-radius:var(--r);overflow:hidden;box-shadow:0 12px 48px rgba(41,59,60,.18);
       /* Hidden with visibility, not display, so it can animate both ways:
          in at .22s scaling up from the /index row, out faster at .16s. */
       visibility:hidden;opacity:0;transform:scale(.96);
       transition:opacity .16s ease-out,transform .16s ease-out,visibility 0s linear .16s}
#index.open{visibility:visible;opacity:1;transform:none;
            transition:opacity .22s ease-out,transform .22s ease-out,visibility 0s}
@media (prefers-reduced-motion:reduce){#index,#index.open{transform:none}}
#index .control{
  display:flex;flex-direction:column;gap:var(--4);align-items:flex-start;
  padding:var(--4) var(--4) var(--6);background:var(--300);
  border-bottom:1px solid var(--100-15);
  border-radius:var(--r) var(--r) 0 0;
}
#index .row-top{display:flex;gap:10px;align-items:flex-start;width:100%}
#index .filters{display:flex;gap:var(--5);align-items:stretch;width:100%}
#index .filters .left{display:flex;flex-direction:column;justify-content:space-between;
                      gap:var(--5);flex:0 1 364px;min-width:0}
#index .filters .left .form{flex:none;width:100%}
#index .disclaimer{max-width:340px;font-size:10px;letter-spacing:-.1px;line-height:normal;color:var(--100-50)}
#index .disclaimer a{text-decoration:underline;text-underline-position:from-font}
#index .sorts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--3) var(--5);
              flex:1 1 0;min-width:0;align-items:start}
#index .sorts .form{width:100%}
.form{display:flex;flex-direction:column;gap:var(--1);align-items:flex-start;flex:1 1 0;min-width:0}
.form .label{display:flex;gap:var(--3);align-items:flex-end;width:100%}
.form .label b{font-weight:300;white-space:nowrap}
.form .label em{flex:1 1 0;min-width:0;font-style:normal;font-size:12px;
                letter-spacing:-.12px;color:var(--100-50);text-align:right}
.field{
  display:flex;align-items:center;gap:var(--3);width:100%;height:40px;
  padding:var(--4t) var(--4);border-radius:var(--r);
  background:var(--500);border-top:1px solid var(--100-35);
}
.field input{flex:1 1 0;min-width:0}
.field input::placeholder{color:var(--100-50)}
/* A native <select> carries the OS's own chevron and its own font. The
   drawn one is a button plus a list, because the design's caret and the
   platform's caret cannot both be right. */
.select{position:relative;width:100%}
.select>button{
  display:flex;align-items:center;gap:var(--3);width:100%;height:40px;
  padding:var(--4t) var(--4);border-radius:var(--r);text-align:left;
  background:var(--500);border-top:1px solid var(--100-35);color:var(--100-75);
}
/* `span`, unqualified, also matched the caret — which then took flex:1 and
   grew to 152px with its mask centred inside, so the chevron sat halfway
   across the field instead of at its right edge. The label only. */
/* Every drawn menu answers the pointer by lifting a little — brighter, not
   a different colour, so the field still reads as a field. Open, it stays
   lifted for as long as its menu is. */
.select>button{transition:background .12s ease-out}
.select>button:hover,.select.open>button{background:var(--600)}
.select>button span:not(.i){flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.select>button .i{transition:transform .15s}
.select.open>button .i{transform:rotate(180deg)}
.select ul{
  position:absolute;top:calc(100% + var(--1));left:0;right:0;z-index:5;
  list-style:none;border-radius:var(--r);overflow:hidden;
  background:var(--500);border:1px solid var(--100-15);
  box-shadow:0 8px 24px rgba(41,59,60,.14);
  /* Fades and slides 4px out of the field it belongs to. */
  visibility:hidden;opacity:0;translate:0 -4px;
  transition:opacity .12s ease-out,translate .12s ease-out,visibility 0s linear .12s;
}
.select.up ul{translate:0 4px}
.select.open ul{visibility:visible;opacity:1;translate:0 0;
  transition:opacity .12s ease-out,translate .12s ease-out,visibility 0s}
@media (prefers-reduced-motion:reduce){.select ul{translate:none !important}}
/* 737:13727 — stacked 40px rows ruled between, not a padded list of pills. */
.select li{display:flex;align-items:center;height:40px;padding:var(--4t) var(--4);
           border-bottom:1px solid var(--100-15);cursor:pointer;color:var(--100);white-space:nowrap}
.select li:last-child{border-bottom:0}
.select li:hover,.select li.hot{background:var(--400)}
/* No marker on the chosen row: the field above already reads it back, and
   the drawn menu is exactly as wide as the field — a dot pushed "smallest
   file first" past its edge. */

#indexList{flex:1 1 0;min-height:0;overflow-y:auto;background:var(--400);
           border-radius:0 0 var(--r) var(--r)}
.trow{display:flex;gap:var(--4);align-items:center;width:100%;
      padding:var(--3) var(--4);border-bottom:1px solid var(--100-15)}
/* Virtualised: a spacer the height of the whole list, and the ~20 rows in
   view positioned inside it. Every row is exactly 81 — app.js does its
   arithmetic with that number, so it is fixed here rather than left to
   whatever the content happens to measure. */
#indexList .vbody{position:relative}
#indexList .vrows{position:absolute;top:0;left:0;right:0;will-change:transform}
#indexList .vrows .trow{height:81px}
.trow.head{padding:var(--4);color:var(--100-50);position:sticky;top:0;background:var(--400);z-index:1}
.trow .thumb{width:80px;flex-shrink:0;display:flex;align-items:center}
.trow .thumb div{width:64px;height:64px;border-radius:var(--r);background:var(--200);overflow:hidden}
.trow .thumb img{width:100%;height:100%;object-fit:contain}
.trow .title{flex:1 1 0;min-width:0;overflow:hidden;
             display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}
.trow .usage{width:80px;flex-shrink:0}
/* The artist, beside the title it belongs to: at 50% like the other facts,
   clamped to the row's three lines. */
.trow .artist{width:180px;flex-shrink:0;min-width:0;color:var(--100-50);overflow:hidden;
              display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}
.trow .res{width:150px;flex-shrink:0;color:var(--100-50);white-space:nowrap}
.trow .size{width:100px;flex-shrink:0;color:var(--100-50)}
.trow .lic{width:100px;flex-shrink:0;color:var(--100-50);white-space:nowrap;overflow:hidden}
.trow .act{width:32px;height:32px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.trow.head .act{height:17px}
.trow .act.del{color:var(--error)}
.trow.head .act.del{color:var(--100-50)}
.trow:not(.head):hover{background:var(--500)}

/* #flyout — full-bleed, the picture on the left and the caption on the right */
/* Not full-bleed. A fixed 1024x682 panel centred in the frame, sitting on
   the same wash as every other overlay — the picture is a thing ON the
   field, not a replacement for it, and full bleed made opening one feel
   like navigating away. It shrinks below that only to stay on screen. */
#flyout{position:fixed;inset:0;z-index:70;display:flex;visibility:hidden;
        align-items:center;justify-content:center;padding:var(--5)}
#flyout.open{visibility:visible}
/* 80% of the window, kept between the drawn 1024 x 682 and a ceiling, so it
   grows on a big screen and still sits over the board as a panel rather
   than taking the screen. The editor is a workspace and may grow a little
   more; it glides between the two on the site's curve. */
#flyout .panel{
  width:clamp(1024px,80vw,1280px);height:clamp(682px,80vh,820px);max-width:100%;max-height:100%;

  display:flex;flex-direction:column;overflow:hidden;
  border-radius:var(--r);background:var(--400);
  border-bottom:1px solid var(--100-15);
  box-shadow:0 12px 48px rgba(41,59,60,.18);
}
#flyout .body{display:flex;flex:1 1 0;min-height:0;width:100%;align-items:stretch}
#flyout .img{flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;
             padding:var(--8);overflow:hidden;background:var(--200)}
/* BOTH copies fill the same box and contain themselves inside it, so the
   cached one and the sharp one occupy identical geometry.

   `width:auto` was the bug behind the jump: an <img> does not upscale past
   its natural size, so the 500px card face sat at 500px and the 1280 that
   replaced it filled 710 — the picture changed SIZE as it sharpened, which
   is what read as jaggy. Filling the box makes the swap a change of detail
   and nothing else. */
#flyout .img{position:relative}
#flyout .img > img,#flyout .img > video{position:absolute;inset:var(--8);
  width:calc(100% - var(--8) * 2);height:calc(100% - var(--8) * 2);
  max-width:none;max-height:none;object-fit:contain;border-radius:var(--r)}
/* Both copies wait, invisible, until they have DECODED — a picture that is
   still arriving paints itself top-down in strips, which is the loading
   you could see. A class reveals them, never an inline style. */
#flyout .img .base,#flyout .img .hi{opacity:0;transition:opacity .28s ease-out}
/* The sharp copy, when it arrives after the picture has landed: slower, so
   the detail comes up rather than the picture blinking to a second one. */
#flyout .img .hi{transition:opacity .6s ease-out}
#flyout .img .ready{opacity:1}
/* While the copy is in flight — either direction — the panel's own
   picture is hidden, or it appears twice for the length of the move. The
   earlier rule lost to the sharp copy's inline opacity whenever the hover
   prefetch had already cached it, which is exactly the double image in the
   recording. !important because nothing may out-rank "not now". And no
   transition: at landing the copy sits on precisely the same rectangle, so
   the real picture must appear under it in one frame, not fade up behind. */
#flyout.flying .img > *{opacity:0 !important;transition:none !important}

/* The card, in flight between where it sat on the field and where it lands
   in the panel. It is a COPY: the real card stays mounted and in place, so
   the board underneath is never disturbed and the flight can be reversed
   to exactly the same rectangle on the way out.

   Two stacked images rather than one, because the card crops (cover) and
   the panel shows the whole picture (contain), and object-fit does not
   animate. Cross-fading between the two says the same thing and does it in
   a property that does. */
.flight{position:fixed;z-index:75;pointer-events:none;overflow:hidden;
  border-radius:var(--r);will-change:transform,width,height}
.flight img{position:absolute;inset:0;width:100%;height:100%;display:block}
.flight .cover{object-fit:cover}
.flight .whole{object-fit:contain}

/* The picture LEADS. The panel's ground comes up quickly so the flight has
   somewhere to land, but the caption waits until the move is nearly over —
   otherwise three things animate at once and the eye, given no order to
   read them in, settles on none of them. */
#flyout{opacity:0;transition:opacity .26s ease-out,visibility 0s linear .26s}
#flyout.open{opacity:1;transition:opacity .2s ease-out,visibility 0s}
#flyout .side{opacity:0;transition:opacity .2s ease-out}
#flyout.open .side{opacity:1;transition-delay:.26s,0s}   /* opacity waits; width never does */
/* While the copy is in flight the panel's own picture area stays empty, so
   the ground does not flash a second rectangle behind the one moving. */
#flyout.flying .img{background:var(--200)}
@media (prefers-reduced-motion:reduce){
  #flyout,#flyout .side,#flyout .side > *,#flyout .img{transition:none !important}
  #flyout.open .side{transition-delay:0s}
  .flight{display:none}
}
/* The column beside the picture holds two panes, stacked: the details and
   the editor. Only its WIDTH is in the layout — 275 for details, 330 for
   the editor (788:285) — so swapping panes narrows the picture area, and
   the picture, which contains itself inside that area, glides to its new
   size with it instead of jumping. */
#flyout .side{position:relative;flex:0 0 275px;min-width:0;
              transition:opacity .2s ease-out,flex-basis .42s cubic-bezier(.45,.05,.25,1)}
#flyout.editing .side{flex-basis:330px}
#flyout.editing .panel{width:clamp(1024px,86vw,1680px);height:clamp(682px,80vh,960px)}
/* The size glides only while the flyout is switching between the details
   and the editor. A window being resized is followed exactly — animated,
   the panel trailed the window and hung off its edge mid-drag. */
#flyout.sizing .panel{transition:width .42s var(--ease),height .42s var(--ease)}
#flyout .side > *{position:absolute;inset:0;transition:opacity .18s ease-out,visibility 0s linear .18s}
#flyout .caption{display:flex;flex-direction:column;
                 align-items:flex-end;justify-content:space-between;padding:var(--5);overflow:hidden}
/* Out goes first and fast; in waits until the column has mostly settled,
   so the two never read as one muddle of text at half opacity. */
#flyout.editing .caption,#flyout:not(.editing) .editor,
#flyout.cropping .editor,#flyout.resizing .editor,#flyout.colouring .editor,#flyout.bgremoving .editor,#flyout.dithering .editor,#flyout.risoing .editor,#flyout.dotting .editor,#flyout.copying .editor,#flyout.kaleidoscoping .editor,#flyout.displacing .editor,#flyout.vectorising .editor,#flyout.blooming .editor,#flyout.crting .editor,#flyout.asciing .editor,#flyout.engraving .editor,#flyout.glitching .editor,#flyout.perspectiving .editor,#flyout.pixelsorting .editor,#flyout.texting .editor,#flyout.imaging .editor,
#flyout:not(.cropping) #flyCrop,#flyout:not(.resizing) #flyResize,#flyout:not(.colouring) #flyColour,
#flyout:not(.bgremoving) #flyBg,#flyout:not(.dithering) #flyDither,#flyout:not(.risoing) #flyRiso,#flyout:not(.dotting) #flyDots,#flyout:not(.copying) #flyCopy,#flyout:not(.kaleidoscoping) #flyKaleido,#flyout:not(.displacing) #flyDisplace,#flyout:not(.vectorising) #flyVector,#flyout:not(.blooming) #flyBloom,#flyout:not(.crting) #flyCrt,#flyout:not(.asciing) #flyAscii,#flyout:not(.engraving) #flyEtch,#flyout:not(.glitching) #flyGlitch,#flyout:not(.perspectiving) #flyPersp,#flyout:not(.pixelsorting) #flySort,#flyout:not(.texting) #flyText,#flyout:not(.imaging) #flyImage{opacity:0;visibility:hidden}
#flyout.editing.cropping #flyCrop,#flyout.editing.resizing #flyResize,
#flyout.editing.colouring #flyColour,#flyout.editing.bgremoving #flyBg,
#flyout.editing.dithering #flyDither,#flyout.editing.risoing #flyRiso,#flyout.editing.dotting #flyDots,#flyout.editing.copying #flyCopy,#flyout.editing.kaleidoscoping #flyKaleido,#flyout.editing.displacing #flyDisplace,#flyout.editing.vectorising #flyVector,#flyout.editing.blooming #flyBloom,#flyout.editing.crting #flyCrt,#flyout.editing.asciing #flyAscii,#flyout.editing.engraving #flyEtch,#flyout.editing.glitching #flyGlitch,#flyout.editing.perspectiving #flyPersp,#flyout.editing.pixelsorting #flySort,#flyout.editing.texting #flyText,#flyout.editing.imaging #flyImage{transition:opacity .22s ease-out .2s,visibility 0s}
#flyout.editing .editor{transition:opacity .22s ease-out .2s,visibility 0s}
#flyout:not(.editing) .caption{transition:opacity .22s ease-out .2s,visibility 0s}
/* The editor's picture area goes to a neutral grey (788:286). */
#flyout .img{transition:background-color .42s ease-out}
#flyout.editing .img{background:var(--editor-ground)}
/* 892:7697 — 64 clear below the picture rather than 48, so the zoom bar
   sits under it instead of over its lower edge. */
#flyout.editing .img{padding-bottom:64px}
#flyout.editing.flying .img{background:var(--editor-ground)}

/* 788:288 — 16 in, the sections pushed apart to fill the height. It
   scrolls only if a short window leaves it no room. */
/* space-between spreads the blocks; the gap is only the least they close to
   on a short screen, 12, so the tools and an MP4's two export lines fit. */
#flyout .editor{display:flex;flex-direction:column;justify-content:space-between;gap:var(--4);
                padding:var(--5);overflow-y:auto;overflow-x:hidden}
#flyout .editor .top{display:flex;align-items:center;gap:var(--3);width:100%}
#flyout .editor .back{display:flex;align-items:center;gap:var(--2);flex-shrink:0}
#flyout .editor .block{display:flex;flex-direction:column;gap:var(--1);width:100%}
#flyout .editor .tools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--1)}
#flyout .editor .tools .btn-plain{justify-self:start}
/* With Add PNG/SVG and Add Text the list is a row longer: on a short
   window (the drawn 682 panel) the tools close up a little so the editor,
   an MP4's two export lines included, still never scrolls. */
@media (max-height:940px){
  #flyout .editor{gap:var(--3)}
  #flyout .editor .tools .btn-plain{min-height:0;height:30px;padding-block:0}
}
#flyout .editor .row{display:flex;flex-wrap:wrap;gap:var(--3);align-items:flex-end;width:100%}
#flyout .editor .export{gap:var(--3)}
#flyout .editor .export .row{flex-wrap:nowrap;gap:var(--4)}
#flyout .editor .export .select{width:90px;flex-shrink:0}
#flyout .editor .export #exLoop{flex:1 1 0;width:auto;min-width:0}
#flyout .editor .export .exprog{width:100%}
/* 858:5908 — rendering: a progress bar, not a slider — the fill in accent at
   30%, no grip, and it eases between frames. */
#flyout .editor .export .exprog .track{cursor:default}
#flyout .editor .export .exprog .fill{min-width:0;background:rgba(112,108,224,.3);transition:width .2s ease-out}
#flyout .editor .export .btn-stroke{width:100%}
#flyout .editor .exinfo{display:flex;gap:var(--3);width:100%;font-size:12px;letter-spacing:-.12px;
                        color:var(--100-50);white-space:nowrap}
#flyout .editor .exinfo span:first-child{flex:1 1 0}
#flyout .editor .exnote{margin:-4px 0 0;width:100%;font-size:12px;letter-spacing:-.12px;color:var(--100-50);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#flyout .editor .exnote.warn{color:var(--warning)}
/* A menu near the foot of the panel opens upward, or the panel clips it. */
.select.up ul{top:auto;bottom:calc(100% + var(--1))}

/* 789:2371 — the slider. A 22px track, the filled part at 15% ink with a
   double-rule grip at its end, and the value set inside the track. */
.slider{display:flex;flex-direction:column;gap:var(--1);flex:1 1 0;min-width:0}
.slider .label{display:flex;align-items:flex-end;gap:var(--3);height:17px;white-space:nowrap}
.slider .label b{font-weight:300}
.slider .label em{flex:1 1 0;min-width:0;text-align:right;font-style:normal;
                  font-size:12px;letter-spacing:-.12px;color:var(--100-50)}
.slider .track{position:relative;height:22px;border-radius:var(--r);cursor:ew-resize;
               background:var(--500);border-top:1px solid var(--100-15);touch-action:none}
.slider .track:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}
.slider .fill{position:absolute;left:0;top:-1px;bottom:0;border-radius:var(--r) 0 0 var(--r);
              background:var(--100-15);min-width:8px}
.slider .fill i{position:absolute;top:50%;width:1px;height:16px;margin-top:-8px;background:var(--500)}
.slider .fill i:first-child{right:4px}
.slider .fill i:last-child{right:2px}
.slider .val{position:absolute;right:var(--3);top:50%;transform:translateY(-50%);
             font-size:12px;letter-spacing:-.12px;pointer-events:none}

/* 789:2389 — a flat bar centred under the picture, 10px off its bottom.
   The picture area sits between History (33px folded, 190px open) and the
   330px column, so the centre follows History as it slides. Editor only. */
#flyout .body{position:relative}
#flyout .viewctl{position:absolute;left:calc(33px + (100% - 33px - 330px) / 2);bottom:10px;transform:translateX(-50%);z-index:2;
  display:flex;flex-direction:row;gap:var(--4);padding:var(--3);
  border-radius:var(--r);background:var(--300);
  opacity:0;visibility:hidden;transition:opacity .18s ease-out,visibility 0s linear .18s}
/* 846:21472 — the zoom bar's buttons take a ground of their own under the
   pointer: --500 on the bar's --300, one step brighter. The ground is drawn
   past the icon with a spread rather than padding, so the row keeps the
   22px icons 12 apart it is drawn with. */
#flyout .viewctl button{position:relative;display:block;padding:0;color:var(--100)}
/* The ground is its own box, 4 past the icon on every side, with the app's
   own 4px corner — a spread would have added itself to the radius and
   rounded it to 8. Drawn behind the icon, so the row keeps the 22px icons
   12 apart it is drawn with. */
#flyout .viewctl button::before{content:"";position:absolute;inset:-4px;border-radius:var(--r);
  background:var(--500);opacity:0;transition:opacity .12s ease-out}
#flyout .viewctl button:hover::before{opacity:1}
#flyout .viewctl button .i{position:relative}
#flyout .viewctl button:focus-visible{outline:1px solid var(--accent);outline-offset:4px;border-radius:var(--r)}
#flyout [hidden]{display:none !important}
/* A clip: what needs one still picture is not offered for it. */
#flyout.movie [data-tool="remove-bg"]{display:none}
#flyout .viewctl .vdiv{align-self:center;width:1px;height:22px;background:var(--100-15)}
#flyout.editing .viewctl{opacity:1;visibility:visible;transition:opacity .22s ease-out .3s,visibility 0s,left .42s var(--ease)}
#flyout.editing .hist.open ~ .viewctl{left:calc(190px + (100% - 190px - 330px) / 2)}
#flyout.flying .viewctl{opacity:0 !important;transition:none !important}
/* One style change with no motion — the flyout reset to details between
   items, which must not be seen animating. */
#flyout.snap .side,#flyout.snap .side > *,#flyout.snap .crop,#flyout.snap .img,#flyout.snap .viewctl,#flyout.snap .panel{transition:none !important}
.slider.off{opacity:.35;pointer-events:none}
#flyout .details{display:flex;flex-direction:column;gap:var(--6);width:100%}
#flyout .block{display:flex;flex-direction:column;gap:var(--1);width:100%}
#flyout h1{font:300 18px/1.25 var(--serif);letter-spacing:-.01em;width:100%}
#flyout .specs{display:flex;flex-direction:column;gap:var(--2);width:100%;
               padding-top:var(--5);color:var(--100-50)}
/* 871:6711 — by, then the author in ink; resolution / size; the format. */
#flyout .specs .by{display:flex;gap:var(--3);align-items:baseline}
#flyout .specs .by span{flex:none}
#flyout .specs .by b{font-weight:300;color:var(--100);min-width:0}

/* 762:16244 — how often the file has been taken, and how. The total is in
   ink and its two parts hang off it at 50%, which is why they are drawn
   with a box-drawing elbow rather than indented: the elbow says "of the
   above" in a monospace face without needing a rule or a bullet. */
#flyout .feed{display:flex;flex-direction:column;gap:var(--2);width:100%;
              padding:var(--5) 0;white-space:nowrap}
#flyout .feed div{display:flex;gap:var(--2);align-items:center}
#flyout .feed .sub{color:var(--100-50)}
#flyout .actions{display:flex;flex-direction:column;gap:var(--1);width:100%}
#flyout .details .edit{width:100%}
#flyout .details .edit[disabled]{color:var(--100-35);border-color:var(--100-15);cursor:default}
#flyout .details .edit[disabled]:hover{background:none}
#flyout .caption .disclaimer{width:100%;font-size:10px;letter-spacing:-.1px;line-height:12px;color:var(--100-50)}
#flyout .caption .disclaimer a{text-decoration:underline;text-underline-position:from-font}

/* --------------------------------------------------------------- states --- */
#message{
  position:fixed;inset:0;display:none;flex-direction:column;
  align-items:center;justify-content:center;pointer-events:none;
}
#message.show{display:flex}
#message .page-message{display:flex;flex-direction:column;gap:var(--4);align-items:flex-start;
                       width:410px;padding:var(--4);pointer-events:auto}
#message .title-caption{display:flex;flex-direction:column;width:100%}
#message .title-caption p+p{color:var(--100-50)}
#message .btn-stroke{padding:0 var(--4) 0 var(--4t)}

#hud{position:fixed;left:12px;bottom:12px;z-index:30;font-size:10px;letter-spacing:-.1px;
     color:var(--100-50);pointer-events:none}

/* ---------------------------------------------------------------- phone --- */
/* B, the column. The plane wraps on BOTH axes, which on a 390 screen mounts
   several screens of cards and loads every picture. One scrolling column
   instead — and a 16px grid gutter, so the next column peeks at rest. */
@media (max-width:767px){
  /* The panel keeps its 177 on a phone — it was stretched edge to edge back
     when the headbar was a wide bar, and that rule outlived the bar: with
     JS setting `left` inline and this still setting `right`, the panel
     spanned the whole screen. 177 fits a 375 phone with room to spare, and
     it is draggable if it is ever in the way. */
  .searchbox .shortcut,.field.search .shortcut{display:none}
  #index{width:calc(100% - 16px)}   /* the 32px above and below holds here too */
  #index .filters{flex-direction:column;gap:var(--4)}
  #index .filters .left{flex-basis:auto}
  #index .sorts{gap:var(--3)}
  .trow .usage,.trow .res,.trow .size,.trow .lic,.trow .artist{display:none}
}
/* The flyout stacks — picture over its column — on a phone, and on a
   tablet held upright, where side by side leaves the picture a sliver. */
@media (max-width:767px),(max-width:1100px) and (orientation:portrait){
  #flyout{padding:var(--2)}
  #flyout .panel{width:100%;height:100%}
  #flyout .body{flex-direction:column}
  #flyout .img{padding:var(--5)}
  #flyout.editing .img{padding-bottom:var(--5)}   /* the zoom bar is top-right here */
  #flyout .side{flex:0 0 auto;height:auto;max-height:55%}
  #flyout.editing .side{flex-basis:auto}
  #flyout .side > *{position:relative;inset:auto}
  /* The column is capped (55%), so what is in it has to be allowed to be
     shorter than its content — then the details scroll inside it rather
     than running out of the bottom of the panel. */
  #flyout .side{display:flex;flex-direction:column}
  #flyout .side > :not(.scroll-thumb){flex:1 1 auto;min-height:0}
  #flyout .caption{overflow-y:auto}
  #flyout.editing .caption,#flyout:not(.editing) .editor,
  #flyout.cropping .editor,#flyout.resizing .editor,#flyout.colouring .editor,#flyout.bgremoving .editor,#flyout.dithering .editor,#flyout.risoing .editor,#flyout.dotting .editor,#flyout.copying .editor,#flyout.kaleidoscoping .editor,#flyout.displacing .editor,#flyout.vectorising .editor,#flyout.blooming .editor,#flyout.crting .editor,#flyout.asciing .editor,#flyout.engraving .editor,#flyout.glitching .editor,#flyout.perspectiving .editor,#flyout.pixelsorting .editor,#flyout.texting .editor,#flyout.imaging .editor,
  #flyout:not(.cropping) #flyCrop,#flyout:not(.resizing) #flyResize,#flyout:not(.colouring) #flyColour,
  #flyout:not(.bgremoving) #flyBg,#flyout:not(.dithering) #flyDither,#flyout:not(.risoing) #flyRiso,#flyout:not(.dotting) #flyDots,#flyout:not(.copying) #flyCopy,#flyout:not(.kaleidoscoping) #flyKaleido,#flyout:not(.displacing) #flyDisplace,#flyout:not(.vectorising) #flyVector,#flyout:not(.blooming) #flyBloom,#flyout:not(.crting) #flyCrt,#flyout:not(.asciing) #flyAscii,#flyout:not(.engraving) #flyEtch,#flyout:not(.glitching) #flyGlitch,#flyout:not(.perspectiving) #flyPersp,#flyout:not(.pixelsorting) #flySort,#flyout:not(.texting) #flyText,#flyout:not(.imaging) #flyImage{display:none}
  #flyout .crop{justify-content:flex-start;max-height:100%}
  #flyout .editor{justify-content:flex-start;max-height:100%}
  #flyout .viewctl,#flyout.editing .hist.open ~ .viewctl{left:auto;right:12px;top:12px;bottom:auto;transform:none}
}

/* ------------------------------------------------------- the editor view ---
   editor.js draws the picture in this layer while the editor is open: a
   clipping FRAME the size of the visible region, and inside it the same
   decoded image, scaled and offset. The flyout's own copies step back
   underneath so there is only ever one picture. */
#flyout .img.has-eview > img{visibility:hidden}
#flyout .eview{position:absolute;inset:0;overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none}
#flyout .eview .frame{position:absolute;overflow:hidden;border-radius:var(--r)}
#flyout .eview .frame img{position:absolute;left:0;top:0;max-width:none;transform-origin:0 0;pointer-events:none}
#flyout .eview.zoomed{cursor:grab}
#flyout .eview.drag-pan{cursor:grabbing}
#flyout.flying .eview{visibility:hidden}

/* The crop box. Everything outside it is shaded by its own shadow, which
   the layer clips; the rule of thirds shows only while it is being moved
   or pulled. Handles are drawn small and hit large. */
#flyout .cropbox{position:absolute;display:none;cursor:move;outline:none;
  border:1px solid var(--crop-line)}
#flyout .eview .shade{position:absolute;display:none;pointer-events:none;box-shadow:0 0 0 100vmax var(--shade)}
#flyout.cropping .eview .shade{display:block}
#flyout.cropping .cropbox{display:block}
#flyout.cropping .eview .frame{border-radius:0}
#flyout .cropbox:focus-visible{border-color:var(--accent)}
#flyout .cropbox .grid{position:absolute;inset:0;opacity:0;transition:opacity .12s ease-out;pointer-events:none;
  background:
    linear-gradient(90deg,transparent calc(33.333% - .5px),var(--crop-grid) calc(33.333% - .5px),var(--crop-grid) calc(33.333% + .5px),transparent calc(33.333% + .5px),
                          transparent calc(66.666% - .5px),var(--crop-grid) calc(66.666% - .5px),var(--crop-grid) calc(66.666% + .5px),transparent calc(66.666% + .5px)),
    linear-gradient(180deg,transparent calc(33.333% - .5px),var(--crop-grid) calc(33.333% - .5px),var(--crop-grid) calc(33.333% + .5px),transparent calc(33.333% + .5px),
                          transparent calc(66.666% - .5px),var(--crop-grid) calc(66.666% - .5px),var(--crop-grid) calc(66.666% + .5px),transparent calc(66.666% + .5px))}
#flyout .eview.drag-move .grid,#flyout .eview.drag-resize .grid{opacity:1}
#flyout .cropbox b{position:absolute;width:28px;height:28px;margin:-14px 0 0 -14px}
#flyout .cropbox b::before{content:"";position:absolute;left:50%;top:50%}
#flyout .cropbox b[data-h=nw]{left:0;top:0;cursor:nwse-resize}
#flyout .cropbox b[data-h=ne]{left:100%;top:0;cursor:nesw-resize}
#flyout .cropbox b[data-h=se]{left:100%;top:100%;cursor:nwse-resize}
#flyout .cropbox b[data-h=sw]{left:0;top:100%;cursor:nesw-resize}
#flyout .cropbox b[data-h=n]{left:50%;top:0;cursor:ns-resize}
#flyout .cropbox b[data-h=s]{left:50%;top:100%;cursor:ns-resize}
#flyout .cropbox b[data-h=e]{left:100%;top:50%;cursor:ew-resize}
#flyout .cropbox b[data-h=w]{left:0;top:50%;cursor:ew-resize}
/* Corners: an L, 14px arms, 3px thick, sitting ON the frame's corner. */
#flyout .cropbox b[data-h=nw]::before,#flyout .cropbox b[data-h=ne]::before,
#flyout .cropbox b[data-h=se]::before,#flyout .cropbox b[data-h=sw]::before{width:14px;height:14px;border:0 solid var(--crop-line)}
#flyout .cropbox b[data-h=nw]::before{margin:-2px 0 0 -2px;border-width:3px 0 0 3px}
#flyout .cropbox b[data-h=ne]::before{margin:-2px 0 0 -12px;border-width:3px 3px 0 0}
#flyout .cropbox b[data-h=se]::before{margin:-12px 0 0 -12px;border-width:0 3px 3px 0}
#flyout .cropbox b[data-h=sw]::before{margin:-12px 0 0 -2px;border-width:0 0 3px 3px}
/* Edges: an 18px bar across the middle of each side. */
#flyout .cropbox b[data-h=n]::before,#flyout .cropbox b[data-h=s]::before{width:18px;height:3px;margin:-2px 0 0 -9px;background:var(--crop-line)}
#flyout .cropbox b[data-h=n]::before{margin-top:-2px}
#flyout .cropbox b[data-h=s]::before{margin-top:-1px}
#flyout .cropbox b[data-h=e]::before,#flyout .cropbox b[data-h=w]::before{width:3px;height:18px;margin:-9px 0 0 -2px;background:var(--crop-line)}
#flyout .cropbox b[data-h=e]::before{margin-left:-1px}
@media (pointer:coarse){#flyout .cropbox b{width:44px;height:44px;margin:-22px 0 0 -22px}}

/* 795:2741 — the crop panel. */
#flyout .crop:focus{outline:none}
/* The blocks are spread apart (space-between); `gap` is only the least they
   close to on a short screen — 12, and 8 on the densest panel, so a panel
   with #motion still fits the 682px editor without scrolling. */
#flyout .crop{display:flex;flex-direction:column;align-items:center;justify-content:space-between;gap:var(--4);
              padding:var(--5);overflow-y:auto;overflow-x:hidden}
#flyout .crop .top{width:100%}
#flyout .crop .title{font:300 18px/1.25 var(--serif);letter-spacing:-.18px;white-space:nowrap}
#flyout .crop .block{display:flex;flex-direction:column;gap:var(--1);width:100%}
#flyout .crop .presets{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--3)}
#flyout .crop .preset{position:relative;width:100%;padding:0 var(--4)}
/* 795:3086's active-indicator: a 4px dot, 9px in from the top right. */
#flyout .crop .preset.active::after{content:"";position:absolute;top:9px;right:9px;width:4px;height:4px;
  border-radius:4px;background:var(--error)}
#flyout .crop .precise{display:flex;gap:var(--4);width:100%}
#flyout .crop .precise .form{flex:1 1 0;min-width:0}
#flyout .crop .fields{display:flex;flex-direction:column;gap:var(--3);width:100%}
/* 797:1386 — colours: five sliders 12 apart, then the duotone switch and
   its two colours, each a 40px swatch and a hex field, crossed by an X. */
#flyout .crop .sliders{display:flex;flex-direction:column;gap:var(--4);width:100%}
#flyout .crop .sliders .slider{flex:none;width:100%}
/* 871:6271 — each slider resets itself: a 14px counter-clockwise arrow at
   the right of its label, in 35% ink; darker under the pointer when there
   is something to reset. The word stays for screen readers only. */
#flyout .crop .sreset{flex:none;margin-left:auto;align-self:flex-end;width:14px;height:14px;padding:0;margin-bottom:1px;
  font-size:0;color:transparent;overflow:hidden;background:var(--100-35);
  -webkit-mask:url(/assets/icon-restart.svg) center/14px 14px no-repeat;mask:url(/assets/icon-restart.svg) center/14px 14px no-repeat}
#flyout .crop .sreset:not([disabled]):hover{background:var(--100-75)}
#flyout .crop .sreset:focus-visible{outline:1px solid var(--accent);outline-offset:1px}
#flyout .crop .sreset[disabled]{cursor:default}
#flyout .crop .duotone{gap:var(--3)}
#flyout .crop .duo{display:flex;align-items:center;gap:var(--3);width:100%;transition:opacity .16s ease-out}
#flyout .crop .duo.off{opacity:.5}
#flyout .crop .duo .pick{display:flex;align-items:center;gap:var(--1);flex:1 1 0;min-width:0}
#flyout .crop .duo .field{flex:1 1 0;min-width:0}
#flyout .crop .duo .field input{text-transform:uppercase}
#flyout .crop .duo .x{flex-shrink:0;font-size:10px;letter-spacing:-.1px;color:var(--100-50)}
#flyout .crop .swatch{position:relative;flex-shrink:0;width:40px;height:40px;border-radius:var(--r);
  border:1px solid var(--300);cursor:pointer;overflow:hidden}
#flyout .crop .swatch input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:0;padding:0}
#flyout .crop .swatch:focus-within{outline:1px solid var(--accent);outline-offset:1px}
#flyout .crop .field.bad{box-shadow:inset 0 0 0 1px var(--error)}

/* 797:1433 — remove background. */
#flyout .crop .refine{gap:var(--3)}
#flyout .crop .detect{display:flex;flex-direction:column;gap:var(--5);width:100%}
#flyout .crop .note{max-width:245px;font-size:10px;letter-spacing:-.1px;color:var(--100-50)}
#flyout .crop .note a{text-decoration:underline;text-underline-position:from-font}
#flyout .crop #bgDetect{width:100%}
#flyout .crop #bgDetect[disabled]{color:var(--100-50);cursor:default}
#flyout .crop #bgDetect[disabled]:hover{background:none}
#flyout .crop #bgDetect.busy .i{animation:bgSpin 1.2s linear infinite}
@keyframes bgSpin{to{transform:rotate(360deg)}}
/* Nothing to refine, and no background to choose, until a subject is found. */
#flyout .crop .pending{opacity:.4;pointer-events:none}
#flyout .crop .background{gap:var(--4)}
#flyout .crop .choice{display:flex;gap:var(--6);align-items:center}
/* 796:14597 — the radio: an 18px dial, a 1.5px ring and a 10px dot when on. */
.radio{display:flex;align-items:center;gap:var(--3);padding:0;white-space:nowrap}
.radio i{position:relative;width:18px;height:18px;border-radius:9px;flex-shrink:0;
  background:var(--500);border:1px solid var(--100-35)}
.radio[aria-checked="true"] i{border:1.5px solid var(--100-75)}
.radio[aria-checked="true"] i::after{content:"";position:absolute;inset:2.5px;border-radius:50%;background:var(--100-75)}
.radio:focus-visible i{outline:1px solid var(--accent);outline-offset:2px}
#flyout .crop .pick.solid{display:flex;align-items:center;gap:var(--1);width:100%;transition:opacity .16s ease-out}
#flyout .crop .pick.solid .field{flex:1 1 0;min-width:0}
#flyout .crop .pick.solid .field input{text-transform:uppercase}
#flyout .crop .pick.solid.off{opacity:.4}

/* 800:1854 — dither: two labelled selects and the duotone colours, which
   step back unless the palette is Duotone. The menus are long, so they
   scroll, with the groups named. */
#flyout .crop .settings{gap:var(--4)}
#flyout .crop .settings .form{width:100%;flex:none}
#flyout .crop .settings .label em{text-align:right}
#flyout .crop .settings .duo.off{opacity:.4}
#flyout .crop .settings .formpair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--4);width:100%}
#flyout .crop .settings .formpair .label em{display:none}
/* The menus open the pair's full width, from whichever side they belong to. */
#flyout .crop .settings .formpair .form:first-child .select ul{right:auto;width:calc(200% + var(--4))}
#flyout .crop .settings .formpair .form:last-child .select ul{left:auto;width:calc(200% + var(--4))}
#flyout .crop .select.fx ul{max-height:260px;overflow-y:auto}
#flyout .crop .select.fx li.grp{height:28px;padding:var(--2) var(--4) 0;cursor:default;
  font-size:10px;letter-spacing:-.1px;color:var(--100-50);text-transform:lowercase;background:none;border-bottom:0}
#flyout .crop .select.fx li[aria-selected="true"],#flyout .crop .select.sets li[aria-selected="true"]{background:var(--400)}
/* 844:4546 — #motion. One row — the motion, and how many times it repeats
   in the loop — and an amount only for the motions that go somewhere; what
   does not apply is left out rather than dimmed, so a still step costs the
   panel one row. The menu's rows carry a one-line hint. */
#flyout .crop .motion .mline{display:flex;align-items:center;gap:var(--3);width:100%}
#flyout .crop .motion .mline > .select{flex:1 1 0;min-width:96px}
#flyout .crop .motion .mline > .select > button{padding-left:var(--3);padding-right:var(--3)}
#flyout .crop .motion .mrow{display:flex;gap:var(--3);flex:0 0 104px}
#flyout .crop .motion .mrow:has([data-k="mamount"]:not(.off)){flex-basis:182px}
#flyout .crop .motion .mrow .slider{flex:1 1 0;min-width:0}
#flyout .crop .motion .mrow [data-k="mamount"]{flex-grow:1.12}
#flyout .crop .motion .mrow .val{right:5px;letter-spacing:-.24px}
/* Beside the 40px select, the sliders stand 40px too. */
#flyout .crop .motion .mrow .track{height:40px}
/* The menu keeps its width while the select shares its row with the sliders. */
#flyout .crop .motion [data-fx="motion"] ul{right:auto;min-width:100%;width:298px;max-width:calc(100vw - 64px)}
#flyout .crop .motion .off{display:none}

/* ------------------------------------------------------------ layers ---
   Add Text and Add PNG/SVG. Their panels speak the shader panels' language;
   on the picture, the layer being edited wears a box — drag inside to move,
   a corner to scale, the knob above to turn — and thin guides show where
   it snaps to the picture's centre and edges. */
#flyout .crop .lrow{display:flex;align-items:center;gap:var(--3);width:100%}
#flyout .crop .lrow > .pick.single{flex:1 1 0;min-width:0}
#flyout .crop .lrow .fontsel{flex:1 1 0;min-width:0}
#flyout .crop .lrow .weightsel{flex:0 0 112px}
#flyout .crop .lrow .blendsel{flex:0 0 112px}
#flyout .crop .lrow .select.grow{flex:1 1 0;min-width:0}
/* A word at the end of a bumper: what a panel is waiting on. */
#flyout .crop .bumper .bnote{flex:none;font-style:normal;font-size:10px;letter-spacing:-.1px;color:var(--100-50);white-space:nowrap}
#flyout .crop .bumper .bnote:empty{display:none}
#flyout .crop .lstack{display:flex;flex-direction:column;gap:var(--6);width:100%}
#flyout .crop .lsel ul{max-height:260px;overflow-y:auto}
#flyout .crop .lsel li.grp{height:28px;padding:var(--2) var(--4) 0;cursor:default;font-size:10px;letter-spacing:-.1px;color:var(--100-50);background:none;border-bottom:0}
#flyout .crop .lsel li[aria-selected="true"]{background:var(--400)}
#flyout .crop .lsel li.off{opacity:.35;pointer-events:none}
#flyout .crop .field.area{height:auto;padding:var(--3) var(--4)}
#flyout .crop .field.area textarea{flex:1 1 0;min-width:0;height:40px;resize:none;border:0;background:transparent;font:inherit;letter-spacing:inherit;color:inherit;outline:none;line-height:20px}
#flyout .crop .field.lname{flex:1 1 0;min-width:0}
#flyout .crop .field.lname span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--100-75)}
#flyout .crop .lreplace{flex:0 0 auto;padding:0 var(--4)}
#flyout .crop .presets.four{grid-template-columns:repeat(4,minmax(0,1fr))}
/* 36:655, the drop zone — shorter than drawn, so Add PNG/SVG fits the 682 panel. */
#flyout .crop .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:96px;
  padding:var(--5);background:var(--400);border:1px dashed var(--100-35);border-radius:var(--r);
  font-size:14px;font-weight:300;letter-spacing:-.14px;line-height:normal;color:var(--100);cursor:pointer;overflow:hidden;transition:background .12s}
#flyout .crop .dropzone span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#flyout .crop .dropzone .dim{color:var(--100-50)}
#flyout .crop .dropzone:hover{background:var(--300)}
#flyout .crop .dropzone:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}
#flyout .crop .dropzone.over{border:1px solid var(--accent);background:rgba(112,108,224,.12)}
#flyout .crop .dropzone.bad [data-dz="note"]{color:var(--error)}
#flyout .crop.layerpane.empty .needs{opacity:.4;pointer-events:none}
/* #levels — a histogram with its input handles below, their numbers beside
   the channel and Auto, and the output range as a bar with two. */
#flyout .crop .levels .lvgraph{position:relative;height:48px;border-radius:var(--r);background:var(--500);border-top:1px solid var(--100-15);overflow:hidden;cursor:default}
#flyout .crop .levels .lvgraph canvas{position:absolute;inset:0;width:100%;height:100%}
#flyout .crop .levels .lvshade{position:absolute;top:0;bottom:0;width:0;background:var(--100-15);pointer-events:none}
#flyout .crop .levels .lvshade.lo{left:0}
#flyout .crop .levels .lvshade.hi{right:0}
#flyout .crop .levels .lvhandles,#flyout .crop .levels .lvout{position:relative;touch-action:none;cursor:ew-resize}
#flyout .crop .levels .lvhandles{height:12px;margin-top:-4px}
#flyout .crop .levels b[data-lv]{position:absolute;top:1px;width:0;height:0;margin-left:-6px;border:6px solid transparent;border-top:0;border-bottom:10px solid var(--100);outline:none}
#flyout .crop .levels b[data-lv="1"]{border-bottom-color:var(--100-50)}
#flyout .crop .levels b[data-lv="2"],#flyout .crop .levels b[data-lv="4"]{border-bottom-color:var(--100-35)}
#flyout .crop .levels b[data-lv]:focus-visible{border-bottom-color:var(--accent)}
#flyout .crop .levels .lvrow{display:flex;align-items:center;gap:var(--1);width:100%;height:22px}
#flyout .crop .levels .lvrow .field{flex:none;width:48px;height:22px;padding:0 var(--2);font-size:12px;letter-spacing:-.12px}
#flyout .crop .levels .lvrow .field input{text-align:center}
#flyout .crop .levels .lvrow .select{flex:1 1 0;min-width:0}
#flyout .crop .levels .lvrow .select > button{height:22px;padding:0 var(--2) 0 var(--3);font-size:12px;letter-spacing:-.12px}
#flyout .crop .levels .lvrow .btn-stroke{height:22px;padding:0 var(--3);font-size:12px;letter-spacing:-.12px}
#flyout .crop .levels .lvrow.out{margin-top:var(--1)}
#flyout .crop .levels .lvout{flex:1 1 0;height:22px}
#flyout .crop .levels .lvout .bar{position:absolute;left:0;right:0;top:3px;height:6px;border-radius:3px;background:linear-gradient(90deg,#000,#fff);box-shadow:inset 0 0 0 1px var(--100-15)}
#flyout .crop .levels .lvout .bar[data-ch="r"]{background:linear-gradient(90deg,#000,#f00)}
#flyout .crop .levels .lvout .bar[data-ch="g"]{background:linear-gradient(90deg,#000,#0c0)}
#flyout .crop .levels .lvout .bar[data-ch="b"]{background:linear-gradient(90deg,#000,#00f)}
#flyout .crop .levels .lvout b[data-lv]{top:10px}
#flyout .crop .cta .btn-stroke[disabled]{color:var(--100-35);border-color:var(--100-15);cursor:default}
#flyout .crop .cta .btn-stroke[disabled]:hover{background:none}
#flyout .crop .cellpick{display:flex;gap:var(--1);height:22px}
#flyout .crop .cellpick .swatch{width:22px;height:22px}
#flyout .crop .cellpick .field{flex:1 1 0;min-width:0;height:22px;padding:0 var(--3);font-size:12px;letter-spacing:-.12px}
#flyout .crop .cellpick .field input{text-transform:uppercase}
#flyout .crop .slider.cell .segs{display:flex;height:22px;border-radius:var(--r);background:var(--500);border-top:1px solid var(--100-15);overflow:hidden}
#flyout .crop .slider.cell .segs button{flex:1 1 0;min-width:0;padding:0;font-size:12px;letter-spacing:-.12px;color:var(--100-50)}
#flyout .crop .slider.cell .segs button[aria-pressed="true"]{background:var(--100-15);color:var(--100)}
/* 955:5204 — the stepper: − and + in 32px squares, ruled off from the
   value between them; the value is a field, so a number can be typed. The
   align cell beside it grows to the same 32px, with icons for words. */
#flyout .crop .stepbox{display:flex;align-items:stretch;height:32px;border-radius:var(--r);background:var(--500);border-top:1px solid var(--100-35);overflow:hidden}
#flyout .crop .stepbox button{flex:none;display:flex;align-items:center;justify-content:center;width:32px;padding:0;color:var(--100-75)}
#flyout .crop .stepbox button:first-child{border-right:1px solid var(--300)}
#flyout .crop .stepbox button:last-child{border-left:1px solid var(--300)}
#flyout .crop .stepbox button:hover{background:var(--600);color:var(--100)}
#flyout .crop .stepbox button:active{background:var(--300)}
#flyout .crop .stepbox button:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}
#flyout .crop .stepbox .val{position:static;transform:none;pointer-events:auto;height:100%;flex:1 1 0;min-width:0;width:0;padding:0 var(--1);text-align:center;font-size:14px;letter-spacing:-.14px;color:var(--100)}
#flyout .crop .stepbox .val:focus{outline:none;background:var(--600)}
#flyout .crop .stepbox .val.bad{color:var(--warning)}
#flyout .crop .sliders.steps{gap:var(--4)}
#flyout .crop .sliders.steps .slider.cell .segs{height:32px}
#flyout .crop .sliders.steps .slider.cell .cellsel > button,#flyout .crop .sliders.steps .slider.cell .cellpick,
#flyout .crop .sliders.steps .slider.cell .cellpick .swatch,#flyout .crop .sliders.steps .slider.cell .cellpick .field{height:32px}
#flyout .crop .sliders.steps .slider.cell .segs button{display:flex;align-items:center;justify-content:center;color:var(--100-35)}
#flyout .crop .sliders.steps .slider.cell .segs button:hover{color:var(--100-75)}
#flyout .crop .sliders.steps .slider.cell .segs button[aria-pressed="true"]{color:var(--100)}
#flyout .crop .slider.cell .cellsel > button{height:22px;padding:0 var(--3);font-size:12px;letter-spacing:-.12px}
#flyout .eview .layerbox{position:absolute;left:0;top:0;display:none;box-sizing:border-box;z-index:4;cursor:move;
  outline:1px solid var(--accent);transform-origin:50% 50%}
#flyout.texting .eview .layerbox,#flyout.imaging .eview .layerbox{display:block}
#flyout .eview .layerbox b{position:absolute;width:9px;height:9px;margin:-5px 0 0 -5px;background:var(--500);border:1px solid var(--accent);border-radius:1px}
#flyout .eview .layerbox b[data-lh="nw"]{left:0;top:0;cursor:nwse-resize}
#flyout .eview .layerbox b[data-lh="ne"]{left:100%;top:0;cursor:nesw-resize}
#flyout .eview .layerbox b[data-lh="se"]{left:100%;top:100%;cursor:nwse-resize}
#flyout .eview .layerbox b[data-lh="sw"]{left:0;top:100%;cursor:nesw-resize}
#flyout .eview .layerbox .rot{position:absolute;left:50%;top:-26px;width:11px;height:11px;margin-left:-6px;border-radius:50%;background:var(--500);border:1px solid var(--accent);cursor:grab}
#flyout .eview .layerbox .rot::after{content:"";position:absolute;left:4px;top:10px;width:1px;height:15px;background:var(--accent)}
#flyout .eview.dup,#flyout .eview.dup .layerbox{cursor:copy}
#flyout .eview .layerbox .ltype{display:none;position:absolute;top:0;margin:0;padding:0;border:0;border-radius:0;background:transparent;resize:none;overflow:hidden;
  white-space:pre;outline:none;caret-color:#706CE0;cursor:text;font-kerning:normal;font-variant-ligatures:none;box-shadow:none}
#flyout .eview .layerbox.typing .ltype{display:block}
#flyout .eview .layerbox.typing{background:rgba(112,108,224,.06)}
#flyout .eview .lguide{position:absolute;display:none;z-index:4;background:var(--accent);pointer-events:none}
#flyout .eview .lguide.v{width:1px}
#flyout .eview .lguide.h{height:1px}
#flyout .eview .lguide.on{display:block}
#flyout .eview.drop{outline:2px dashed var(--accent);outline-offset:-8px}
/* 862:5945 — three sliders or more sit in two columns, 12 apart; a switch
   below them takes the whole row. */
#flyout .crop .sliders.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--4)}
#flyout .crop .sliders.two > .slider{min-width:0}
#flyout .crop .sliders.two > .switch{grid-column:1 / -1}
/* A label too long for half the row (misregistration) takes the whole of
   it, track and all; the rest close up beside each other. */
#flyout .crop .sliders.two{grid-auto-flow:row dense}
#flyout .crop .sliders.two > .slider.wide{grid-column:1 / -1}
#flyout .crop .sliders.two .slider .label b{overflow:hidden;text-overflow:ellipsis}
#flyout #flyAscii{gap:var(--3)}
/* The amount says its own name inside its track, so it costs one 22px row. */
#flyout .crop .motion .slider .label{display:none}
#flyout .crop .select li em{flex:1 1 0;min-width:0;margin-left:var(--3);font-style:normal;text-align:right;
  font-size:10px;letter-spacing:-.1px;color:var(--100-50);overflow:hidden;text-overflow:ellipsis}
/* The dithered picture: drawn small and shown with hard pixel edges. */
#flyout .eview .frame canvas.fx{position:absolute;inset:0;width:100%;height:100%;display:none;
  image-rendering:pixelated;image-rendering:crisp-edges}
#flyout .eview .frame canvas.fx.on{display:block}
/* 800:1938 — risograph: the inks as swatches, four across, each with its
   checkbox; at four chosen the rest step back, and the last one left
   cannot be cleared. */
#flyout .crop .inks{gap:var(--3)}
#flyout .crop .swatches{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--3);width:100%}
#flyout .crop .ink{position:relative;height:40px;border-radius:var(--r);border:1px solid var(--300);
  padding:0;transition:opacity .16s ease-out}
#flyout .crop .ink i{position:absolute;left:11px;top:50%;translate:0 -50%;width:18px;height:18px;border-radius:4px;
  background:var(--400);border:1px solid var(--100-15)}
#flyout .crop .ink[aria-checked="true"] i{border:0;background:rgba(41,59,60,.75) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cpath d='M3.5 9.64 7.17 13.5 14.5 4.5' fill='none' stroke='%23EDEAE6' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") center/18px no-repeat}
#flyout .crop .ink.full{opacity:.4}
#flyout .crop .ink.last{cursor:default}
#flyout .crop .ink:focus-visible{outline:1px solid var(--accent);outline-offset:2px}
/* 800:2022 dot matrix and 800:1980 photocopy: three presets across, the
   colours bare under their bumper, a switch under the sliders. */
#flyout .crop .shape .presets{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--3)}
#flyout .crop .sliders .switch{margin-top:var(--1)}
/* 800:2190 kaleidoscope, 800:2064 bloom, 800:2106 CRT, 800:2148 displace,
   800:2232 vectorise. Controls that mean nothing in the current state —
   a tint colour with tint off, colours in black & white — step back. */
#flyout .crop .segments .presets{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--3)}
#flyout .crop .look .presets,#flyout .crop .maps .presets{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--3)}
#flyout .crop .maps .presets.four{grid-template-columns:repeat(4,minmax(0,1fr))}
#flyout .crop .sliders .swap.off{display:none}
#flyout .crop .tint{gap:var(--4)}
#flyout .crop .pick.single{display:flex;align-items:center;gap:var(--1);width:100%;transition:opacity .16s ease-out}
#flyout .crop .pick.single .field{flex:1 1 0;min-width:0}
#flyout .crop .pick.single .field input{text-transform:uppercase}
#flyout .crop .pick.single.off,#flyout .crop .slider.off{opacity:.4}
#flyout .crop .slider{transition:opacity .16s ease-out}
#flyout .crop .modes{gap:var(--4)}
#flyout .crop .modes .choice + .choice{margin-top:0}
/* ASCII is drawn at its own size with real letterforms: smooth it. */
#flyout .eview .frame canvas.fx.smooth{image-rendering:auto}
/* 800:1896 — ASCII: the typeface beside the characters it draws with;
   the colour select stands alone above the pickers. */
#flyout .crop .characters{gap:var(--4)}
#flyout .crop .characters .row{display:flex;flex-wrap:nowrap;gap:var(--4);width:100%}
#flyout .crop .characters .select{flex:1 1 0;min-width:0}
#flyout .crop .characters .field{flex:none;width:120px}
#flyout .crop .characters .field input{white-space:pre}
#flyout .crop .palrow{display:flex;gap:var(--3);width:100%}
#flyout .crop .palrow .select{flex:1 1 0;min-width:0}
#flyout .crop .btn-stroke.icon{width:40px;padding:0;flex:none}
#flyout .crop .btn-stroke.icon.done .i{-webkit-mask-image:url(/assets/icon-check.svg) !important;mask-image:url(/assets/icon-check.svg) !important}
#flyout .crop .btn-stroke.icon.sm{width:26px;height:26px}
#flyout .crop .btn-stroke[disabled]{color:var(--100-35);border-color:var(--100-15);cursor:default}
#flyout .crop .btn-stroke[disabled]:hover{background:none}
#flyout .crop .btn-stroke[disabled] .i{opacity:.45}
#flyout .crop .stylerow{display:flex;align-items:center;gap:var(--1);width:100%;height:26px}
#flyout .crop .stylerow .slabel{flex:none;width:52px;font-size:12px;letter-spacing:-.12px;color:var(--100-50)}
#flyout .crop .stylerow .schips{display:flex;gap:var(--1);flex:1 1 0;min-width:0;height:26px;align-items:center}
#flyout .crop .stylerow .snone{font-size:12px;letter-spacing:-.12px;color:var(--100-35);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#flyout .crop .stylerow .schip{position:relative;flex:0 1 52px;min-width:0;height:26px;padding:0 10px 0 6px;border-radius:var(--r);background:var(--500);border-top:1px solid var(--100-15);font-size:15px;line-height:1;color:var(--100);white-space:nowrap;overflow:hidden}
#flyout .crop .stylerow .schip::after{content:"";position:absolute;right:5px;top:50%;width:6px;height:6px;margin-top:-3px;border-radius:50%;background:var(--c);box-shadow:inset 0 0 0 1px var(--100-15)}
#flyout .crop .stylerow .schip:hover{background:var(--300)}
#flyout .crop .stylerow .schip[aria-pressed="true"]{box-shadow:inset 0 0 0 1px var(--100-35)}
#flyout .crop .colours{gap:var(--4)}
#flyout .crop .colours .select{width:100%}
#flyout .crop .colours .duo.off{opacity:.4}
/* 805:16544 — what else ASCII can be: the text itself, copied or saved. */
#flyout .crop .extra{flex-direction:row;justify-content:space-between;align-items:center}

/* A removed background shows as a checkerboard behind the picture, or as
   the chosen solid colour. */
#flyout .eview .frame.checker{background:
  repeating-conic-gradient(#e9e9e9 0% 25%, #fafafa 0% 50%) 0 0 / 20px 20px}

/* 796:14128 — the switch. A 40x22 track, accent when on, with a 14px knob
   carrying two short rules; the knob slides rather than jumps. */
.switch{display:flex;align-items:center;gap:var(--3);padding:0;white-space:nowrap}
.switch .track{position:relative;display:block;width:40px;height:22px;border-radius:var(--r);
  background:var(--100-15);transition:background .16s ease-out}
.switch .knob{position:absolute;left:4px;top:4px;width:14px;height:14px;border-radius:2px;background:var(--500);
  transition:transform .2s cubic-bezier(.45,.05,.25,1)}
.switch .knob::before,.switch .knob::after{content:"";position:absolute;top:1px;width:1px;height:12px;background:var(--300)}
.switch .knob::before{right:8px}
.switch .knob::after{right:5px}
.switch[aria-checked="true"] .track{background:var(--accent)}
.switch[aria-checked="true"] .knob{transform:translateX(18px)}
.switch:focus-visible .track{outline:1px solid var(--accent);outline-offset:2px}
#flyout .crop .field.num{justify-content:space-between}
#flyout .crop .field.num .unit{flex-shrink:0;font-size:12px;letter-spacing:-.12px;color:var(--100-50)}
#flyout .crop .field.num.empty .unit{display:none}
#flyout .crop .sizes{display:flex;flex-direction:column;gap:var(--5);width:100%}
#flyout .crop .detail{display:flex;gap:var(--2);width:100%;white-space:nowrap}
#flyout .crop .detail span:first-child{flex:1 1 0;min-width:0}
#flyout .crop .detail.dim{color:var(--100-50)}
#flyout .crop .ctl{gap:var(--3)}
#flyout .crop .row{display:flex;flex-wrap:wrap;gap:var(--3)}
#flyout .crop .cta,#discard .cta,#flyout .editor .resetask .cta{display:flex;gap:var(--4);width:100%}
#flyout .crop .cta .btn-stroke,#discard .cta .btn-stroke,#flyout .editor .resetask .cta .btn-stroke{flex:1 1 0;min-width:0}
#flyout .crop .confirm{color:var(--confirm)}
#flyout .btn-plain[disabled]{color:var(--100-35);cursor:default}
#flyout .btn-plain[disabled]:hover{background:none}

/* ------------------------------------------------ History & Presets ---
   788:285 folded, 818:17153 open. Takes no room outside the editor; in it,
   the rail's 33px, or 190 open, gliding like the column on the right. */
#flyout .hist{position:relative;flex:0 0 0;min-width:0;overflow:hidden;background:var(--400);
  transition:flex-basis .42s var(--ease)}
#flyout.editing .hist{flex-basis:33px}
#flyout.editing .hist.open{flex-basis:190px}
#flyout .hist .rail{position:absolute;left:0;top:0;bottom:0;width:33px;padding:0;color:var(--100);
  transition:opacity .22s ease-out .2s,visibility 0s}
#flyout .hist .rail > .i{position:absolute;left:8px;top:16px}
#flyout .hist .rail .railtext{position:absolute;left:8px;top:255px;width:17px;height:199px;
  display:flex;align-items:center;justify-content:center;
  writing-mode:vertical-rl;transform:rotate(180deg);white-space:nowrap;
  font-size:14px;letter-spacing:-.14px;color:var(--100-50)}
#flyout .hist .rail:hover .railtext{color:var(--100-75)}
#flyout .hist.open .rail{opacity:0;visibility:hidden;transition:opacity .12s ease-out,visibility 0s linear .12s}
#flyout .hist .histpanel{position:absolute;left:0;top:0;bottom:0;width:190px;padding:var(--5);
  display:flex;flex-direction:column;gap:var(--5);
  opacity:0;visibility:hidden;transition:opacity .16s ease-out,visibility 0s linear .16s}
#flyout .hist.open .histpanel{opacity:1;visibility:visible;transition:opacity .22s ease-out .2s,visibility 0s}
#flyout .hist .hide{display:flex;align-items:center;gap:var(--2);height:17px;padding:0;align-self:flex-start;
  font-size:14px;letter-spacing:-.14px;color:var(--100)}
/* 818:17305 — Hide, #layers-to-preset, #loaded-presets and #layers 16 apart down
   the top; #share-this-edits held at the foot. The list is what gives when
   the panel runs short: it scrolls. */
#flyout .hist .histmain{flex:1 1 0;min-height:0;display:flex;flex-direction:column;gap:var(--5)}
#flyout .hist .histmain > .presets{flex:none}
#flyout .hist .histfoot{margin-top:auto}
#flyout .hist .stepsbox{position:relative;display:flex;flex-direction:column;min-height:0}
#flyout .hist .history{display:flex;flex-direction:column;gap:var(--4);min-height:0;flex:0 1 auto}
#flyout .hist .steps{display:flex;flex-direction:column;gap:var(--3);min-height:0;overflow-y:auto;
  list-style:none;scrollbar-width:none;
  /* The list scrolls, so it clips — room all round for what reaches past
     a tag: the moving-step badge over its corner (6px up and right), and
     the focus ring (3px below and left). The margins take it back, so
     nothing moves. */
  padding:6px 6px 4px 4px;margin:-6px -6px -4px -4px}
#flyout .hist .steps::-webkit-scrollbar{display:none}
/* juko's drawn scrollbar (406:15141) — app.js pairs each scroller with its
   thumb. The native bar is hidden; scrolling stops at the scroller's end
   instead of carrying on into the page behind it. */
.scroll-body{scrollbar-width:none;overscroll-behavior:contain}
.scroll-body::-webkit-scrollbar{width:0;height:0;display:none}
.scroll-thumb,#flyout .side > .scroll-thumb{position:absolute !important;inset:auto;width:4px;border-radius:100px;background:var(--100-15);pointer-events:none;z-index:8}
#flyout .hist .step{display:flex;align-items:center;gap:var(--1);width:100%;flex:none}
#flyout .hist .step .tag{height:24px;padding:var(--1) var(--2);flex:none;border:1px solid var(--100-15);border-radius:var(--r);
  background:var(--300);font-size:12px;letter-spacing:-.12px;color:var(--100);white-space:nowrap;
  transition:opacity .22s var(--ease)}
#flyout .hist .step .tag.blue{background:rgba(31,89,213,.15);border-color:var(--blue)}
#flyout .hist .step .tag.green{background:rgba(41,130,51,.15);border-color:var(--confirm)}
#flyout .hist .step .tag.orange{background:rgba(223,147,15,.15);border-color:var(--warning)}
#flyout .hist .step.hidden .tag{opacity:.25}
/* 844:4546 — a step that moves: a small dark disc on the tag's corner with
   a play mark in it. */
#flyout .hist .step .tag{position:relative}
#flyout .hist .step .tag .mv{position:absolute;right:-5px;top:-5px;width:12px;height:12px;border-radius:6px;background:var(--100);pointer-events:none}
#flyout .hist .step .tag .mv::after{content:"";position:absolute;inset:2px;background:var(--500);
  -webkit-mask:url(/assets/icon-play-fill.svg) center/8px no-repeat;mask:url(/assets/icon-play-fill.svg) center/8px no-repeat}
#flyout .hist .step .tag:focus-visible,#flyout .hist .step .hx:focus-visible,#flyout .hist .step .he:focus-visible{outline:1px solid var(--accent);outline-offset:1px}
#flyout .hist .step .rule{flex:1 1 0;min-width:4px;height:1px;background:rgba(41,59,60,.07)}
#flyout .hist .step .hx,#flyout .hist .step .he,#flyout .hist .step .hw{flex:none;width:16px;height:16px;padding:0}
/* 818:17391 — the grip, and the row it lifts. */
#flyout .hist .step .grip{flex:none;display:flex;align-items:center;justify-content:center;width:10px;height:24px;margin:0 -2px;padding:0;
  color:var(--100-75);cursor:grab;touch-action:none;transition:color .15s ease-out}
#flyout .hist .step .grip .i{width:6px;height:10px}
#flyout .hist .step .grip:hover{color:var(--100)}
#flyout .hist .step .grip:focus-visible{outline:1px solid var(--accent);outline-offset:1px}
#flyout .hist .steps.sorting{cursor:grabbing}
#flyout .hist .steps.sorting .step{position:relative;transition:transform .2s var(--ease)}
#flyout .hist .steps.sorting .step.lifted{z-index:1;transition:none;background:var(--400)}
#flyout .hist .steps.sorting .step.lifted .grip{color:var(--100);cursor:grabbing}
#flyout .hist .steps.sorting .step.lifted .tag{box-shadow:0 4px 12px rgba(41,59,60,.16)}
#flyout .hist .steps.sorting .step.settling{z-index:1;background:var(--400)}
#flyout .hist .steps.sorting .step .tag{transition:opacity .22s var(--ease),box-shadow .2s var(--ease)}
#flyout .hist .step .hx{color:var(--error);margin-right:2px}
#flyout .hist .step .he{color:var(--100-75)}
/* 980:16994 — the swap on the Img Source row: another picture under the
   same edits is a step away, so it answers the pointer like the eye. */
#flyout .hist .step .hw{color:var(--100-50);transition:color .15s ease-out}
#flyout .hist .step .hw:hover{color:var(--100)}
#flyout .hist .step .hw:focus-visible{outline:1px solid var(--accent);outline-offset:1px}
#flyout .hist .steps .empty{font-size:10px;letter-spacing:-.1px;color:var(--100-50)}
/* 871:6606 — the picture under every layer. No grip, no delete, no eye —
   it cannot move, go or hide; what it can do is be swapped for another. */
#flyout .hist .step.original{padding-left:10px}
#flyout .hist .step .tag.original{display:flex;align-items:center;font-size:12px;letter-spacing:-.12px;cursor:default}
/* 980:16994 — where another picture can be had, the tag is a way to it:
   the same ground as any step's, and pressing the words does what the
   swap beside them does. */
#flyout .hist .step button.tag.original{cursor:pointer}
#flyout .hist .step button.tag.original:hover{background:var(--400)}
/* 823:18772 — the foot: presets, then sharing, plain buttons. */
#flyout .hist .histfoot{display:flex;flex-direction:column;gap:var(--4)}
#flyout .hist .presets{display:flex;flex-direction:column;gap:var(--3)}
#flyout .hist .pbtns{display:flex;flex-direction:column;align-items:flex-start;gap:var(--3)}
#flyout .hist .pbtns .btn-plain[disabled] .i{opacity:.5}
/* 818:17305 — #loaded-presets. The field reads the preset applied, or none;
   the menu is none, then this session's presets, each with a × that takes
   it off the list. Five rows show; more scroll. */
#flyout .hist .recent{width:100%}
#flyout .hist .recent ul{max-height:200px;overflow-y:auto;z-index:6}
#flyout .hist .recent li{padding:0;gap:0;cursor:default}
#flyout .hist .recent li .pick{flex:1 1 0;min-width:0;height:100%;padding:0 0 0 var(--4);text-align:left;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--100);font:inherit;letter-spacing:inherit}
#flyout .hist .recent li .rm{flex:none;width:36px;height:100%;display:flex;align-items:center;justify-content:center;padding:0;color:var(--100-50)}
#flyout .hist .recent li .rm:hover{color:var(--error)}
#flyout .hist .recent li[aria-selected="true"] .pick{color:var(--100)}
#flyout .hist .recent li[aria-selected="false"] .pick{color:var(--100-75)}
#flyout .hist .recent li .pick:focus-visible,#flyout .hist .recent li .rm:focus-visible{outline:1px solid var(--accent);outline-offset:-2px}
/* While a tool is open the list is left as it is, and steps back. */
/* While a tool is open the list steps back to half strength, as it always
   did, and only the step being edited stays at full. Its tag, like the
   others, opens its step; delete, hide and drag wait for the tool to close,
   and presets and sharing step back. */
#flyout .hist .histmain.sessioning > .presets,#flyout .hist .histmain.sessioning > .histfoot{opacity:.5}
#flyout .hist .histmain.sessioning .step{opacity:.5;transition:opacity .2s ease-out}
#flyout .hist .histmain.sessioning .step.editing{opacity:1}
#flyout .hist .histmain.sessioning .step .grip,#flyout .hist .histmain.sessioning .step .hx,#flyout .hist .histmain.sessioning .step .he{pointer-events:none}
#flyout .hist .histmain.sessioning .step.editing .grip,#flyout .hist .histmain.sessioning .step.editing .hx,#flyout .hist .histmain.sessioning .step.editing .he{opacity:.5}
#flyout .hist .history{transition:opacity .2s ease-out}
/* 818:17880 — delete a step? Laid over the top of the list itself. */
#flyout .hist .stepsbox > .histask{position:absolute;left:0;top:0;width:100%;z-index:5;
  display:flex;flex-direction:column;gap:var(--4);padding:var(--4);border-radius:var(--r);
  background:var(--200);border-bottom:1px solid var(--100-15);
  font-size:14px;letter-spacing:-.14px;line-height:17px;color:var(--100);
  opacity:0;visibility:hidden;transition:opacity .22s var(--ease),visibility 0s linear .22s}
#flyout .hist .stepsbox > .histask.open{opacity:1;visibility:visible;transition:opacity .3s var(--ease),visibility 0s}
#flyout .hist .stepsbox > .histask .cta{display:flex;flex-direction:column;gap:var(--3)}
#flyout .hist .stepsbox > .histask .cta .btn-stroke{width:100%}
#flyout.snap .hist,#flyout.snap .hist *{transition:none !important}
@media (prefers-reduced-motion:reduce){#flyout .hist{transition:none}}
/* Phone: History & Presets folds flat between the picture and the tools —
   a 40px bar, and open, a short sheet whose list scrolls. */
@media (max-width:767px),(max-width:1100px) and (orientation:portrait){
  #flyout .panel,#flyout.editing .panel{width:100%;height:100%;transition:none}
  #flyout .img{order:0}
  #flyout .hist{order:1;flex:0 0 auto;display:none;transition:none;border-top:1px solid var(--100-15)}
  #flyout .side{order:2}
  #flyout.editing .hist,#flyout.editing .hist.open{display:block;flex-basis:auto}
  #flyout .hist .rail{position:relative;inset:auto;width:100%;height:40px;display:flex;align-items:center;gap:var(--3);padding:0 var(--5)}
  #flyout .hist .rail > .i{position:static;transform:rotate(90deg)}
  #flyout .hist .rail .railtext{position:static;width:auto;height:auto;writing-mode:horizontal-tb;transform:none}
  #flyout .hist.open .rail{display:none}
  #flyout .hist .histpanel{display:none;position:relative;inset:auto;width:100%;gap:var(--5);opacity:1;visibility:visible}
  #flyout .hist.open .histpanel{display:flex}
  #flyout .hist .hide > .i{transform:rotate(90deg)}
  #flyout .hist .histmain{flex:none;justify-content:flex-start;gap:var(--5)}
  #flyout .hist .steps{max-height:22vh}
  #flyout .hist .histfoot{flex-direction:row;flex-wrap:wrap;column-gap:var(--6)}
  #flyout .hist .pbtns{flex-direction:row;flex-wrap:wrap}
}

/* 814:16736 — Reset? Asked inside the panel, 70 up from its foot. */
#flyout .crop > .resetask,#flyout .editor .control > .resetask{position:absolute;left:var(--5);right:var(--5);bottom:70px;z-index:5;
  display:flex;flex-direction:column;gap:var(--4);padding:var(--4);border-radius:var(--r);
  background:var(--200);border-bottom:1px solid var(--100-15);
  font-size:14px;letter-spacing:-.14px;color:var(--100);
  opacity:0;visibility:hidden;transition:opacity .22s var(--ease),visibility 0s linear .22s}
#flyout .crop > .resetask.open,#flyout .editor .control > .resetask.open{opacity:1;visibility:visible;transition:opacity .3s var(--ease),visibility 0s}
#flyout .crop > .resetask .cta,#flyout .editor .control > .resetask .cta{gap:var(--3)}
#flyout .crop > .resetask p,#flyout .editor .control > .resetask p{margin:0;line-height:17px}
/* 840:3427 — Reset all edits? Over the editor's #control block, centred on it. */
#flyout .editor .control{position:relative}
#flyout .editor .control > .resetask{left:0;right:0;bottom:auto;top:50%;transform:translateY(-50%)}

/* 795:3305 — leaving the editor: /attention and the logogram, a title
   with its caption, Cancel / I’m Done. */
#discard{position:fixed;inset:0;z-index:90;display:flex;align-items:center;justify-content:center;
         padding:var(--5);visibility:hidden}
#discard.open{visibility:visible}
#discard .wash{position:absolute;inset:0;background:var(--300-60);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);opacity:0;transition:opacity .2s ease-out}
#discard.open .wash{opacity:1;transition-duration:.14s}
#discard .notif{position:relative;width:323px;max-width:100%;display:flex;flex-direction:column;gap:var(--5);
  padding:var(--4);border-radius:var(--r);background:var(--500);border-bottom:1px solid var(--100-15);
  box-shadow:0 12px 48px rgba(41,59,60,.18);transform-origin:50% 50%}
#discard .top{display:flex;align-items:center;justify-content:space-between;height:18px}
#discard .top span{font-family:var(--mono);font-size:12px;letter-spacing:-.12px;color:var(--100-50)}
#discard .top img{display:block;width:18px;height:18px}
#discard .copy p{margin:0;font-size:14px;letter-spacing:-.14px;line-height:17px;color:var(--100)}
#discard .copy p + p{color:var(--100-50)}
@media (max-width:767px),(max-width:1100px) and (orientation:portrait){#flyout .crop{justify-content:flex-start}}
/* An upright tablet has height to spare: the picture keeps most of it and
   the column scrolls within the rest. */
@media (min-width:768px) and (max-width:1100px) and (orientation:portrait){
  #flyout .side{max-height:40%}
  #flyout .hist .steps{max-height:14vh}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
