/* ──────────────────────────────────────────────────────────────
   Retouching portfolio

   One visual world, deliberately: a neutral ground the visitor
   sets themselves with the slider in the bar. Every ink and rule
   colour is solved at runtime from that ground for a fixed
   contrast ratio (see applyGround in app.js), so there is no
   light/dark pair to keep in sync — the ground IS the theme.
   The values below are the white-ground defaults, used for the
   first paint before the script runs.
   ────────────────────────────────────────────────────────────── */

:root{
  --bg:#ffffff;
  /* Frosted glass, for every piece of chrome that can sit over a
     photograph: the ground at 52% over a blur of what lies beneath.
     --glass is recomputed with the ground; GLASS in app.js. */
  --glass:rgba(255,255,255,0.52);
  --frost:blur(20px);
  /* A very subtle grain on the glass: desaturated fractal noise, tiled,
     blended as overlay so it is lightness-neutral on any ground. The
     opacity is the whole of its strength. Dom asked, 18 September 2026. */
  --grain:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n' x='0' y='0' width='100%25' height='100%25'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  --grain-opacity:.13;   /* .09 at first; Dom asked for a little more, 19 September 2026 */
  /* The bars sit a little above the page: a tight contact shadow and a
     wide soft one, cast down from the top bar and up from the bottom
     one. Black at low alpha, so it fades on a dark ground rather than
     turning into a glow. Dom asked, 19 September 2026. */
  --shadow-down:0 1px 2px rgba(0,0,0,.05), 0 10px 28px rgba(0,0,0,.09);
  --shadow-up:0 -1px 2px rgba(0,0,0,.05), 0 -10px 28px rgba(0,0,0,.09);
  /* The ground itself carries a fainter grain — the same noise at 4.5%
     alpha, blended into the background colour of the page and of the
     full screen view (background-blend-mode, no extra layer to
     composite), so it scrolls with the page like paper. Dom asked, 19
     September 2026. */
  --grain-ground:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n' x='0' y='0' width='100%25' height='100%25'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/><feComponentTransfer><feFuncA type='linear' slope='0.045'/></feComponentTransfer></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  --ink:#3c3c3c;      /* 11.0:1  — headings, body */
  --ink-2:#747474;    /*  4.8:1  — captions, notes */
  --ink-3:#9a9a9a;    /*  2.8:1  — quiet marks */
  --rule-2:#bcbcbc;   /*  1.9:1  — slider track, focus */
  --rule:#e3e3e3;     /* 1.28:1  — hairlines */
  /* The canvas behind a full screen frame steps a fixed distance in L*
     from the ground instead — 5, 9 and 35 — see CANVAS in app.js. */
  --canvas-minor:#f0f0f0;
  --canvas-major:#e5e5e5;
  --canvas-mark:#9e9e9e;

  /* --pad is the text gutter. --pad-l/r add the side safe-area insets,
     which are zero in portrait and clear the notch in landscape. Frames
     cancel only --pad, so they bleed to the usable edge in both. */
  --pad:clamp(16px,2.6vw,34px);
  --pad-l:calc(var(--pad) + env(safe-area-inset-left,0px));
  --pad-r:calc(var(--pad) + env(safe-area-inset-right,0px));
  --gap:clamp(10px,1.6vw,20px);
  --bar:54px;

  --ease:cubic-bezier(.2,.6,.3,1);
  --tone:180ms linear;

  --sans:"Archivo",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  color-scheme:light;
}
@media (min-width:800px){ :root{ --bar:60px } }

*,*::before,*::after{ box-sizing:border-box }

html{
  background:var(--bg);
  -webkit-text-size-adjust:100%;
  padding-top:env(safe-area-inset-top,0px);
  padding-bottom:env(safe-area-inset-bottom,0px);
}
html,body{ margin:0 }

body{
  background-color:var(--bg);
  background-image:var(--grain-ground); background-blend-mode:overlay;   /* the ground's grain */
  color:var(--ink);
  font-family:var(--sans);
  font-size:15px;
  line-height:1.55;
  letter-spacing:-.004em;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  transition:background-color var(--tone),color var(--tone);
}

img{ display:block; max-width:100% }

/* Class rules below set display:flex on the menu and the full screen
   view, which would otherwise out-specify the hidden attribute. */
[hidden]{ display:none !important }

/* While the full screen view is open, two fingers running past the
   edge must not become the browser's back swipe — they are panning
   the canvas. app.js cancels every wheel event in the view, which is
   what Safari goes by; this is what Chrome and Firefox go by. Dom
   asked on 18 September 2026. */
html[data-lb="true"],html[data-lb="true"] body{ overscroll-behavior:none }
/* The view: no browser gesture from a finger on it either (Dom, 20 September 2026). Domshop's own chrome is handled with its rules, below the clients cut. */
html:fullscreen,html:fullscreen body,#lb{ overscroll-behavior:none }
::selection{ background:var(--ink); color:var(--bg) }

/* Focus rings only after a Tab: the browser's own heuristic shows one
   after any key, so a Space to swap or an R for the rulers drew a box
   round whichever button held the focus. app.js sets data-tabbing on
   Tab and clears it on any pointer press. Keyboard navigators keep
   their rings. Dom, 18 September 2026. */
:focus-visible{ outline:none }
html[data-tabbing="true"] :focus-visible{ outline:1px solid var(--ink); outline-offset:3px }

/* Navigation carries its target in data-go rather than href, so the
   browser draws no address bubble on hover (see `go` in app.js). Give
   it back what a real link has by default; the component rules below
   take the underline away again where they always did. */
[data-go]{ cursor:pointer; text-decoration:underline }

.skip{
  position:absolute; left:-9999px; top:0; z-index:200;
  background:var(--bg); color:var(--ink);
  padding:12px 16px; border:1px solid var(--ink);
  font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase;
}
.skip:focus{ left:var(--pad-l); top:calc(env(safe-area-inset-top,0px) + 8px) }

/* ── Shared type ─────────────────────────────────────────────── */

.eyebrow{
  margin:0;
  font-family:var(--mono); font-weight:400; font-size:10.5px;
  letter-spacing:.2em; text-transform:uppercase; color:var(--ink-2);
  transition:color var(--tone);
}

/* ── Glass grain ─────────────────────────────────────────────── */

/* Every glass surface carries the grain as a layer of its own, under
   its content: the bar and the menu are stacking contexts, so a
   negative z-index sits the layer above their background and beneath
   their type; the sheet in the full screen view has no content and is
   clipped with it. */
.bar::after,.menu::after,.lb__glass::after{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background-image:var(--grain);
  opacity:var(--grain-opacity);
  mix-blend-mode:overlay;
}

/* The glass can be switched off — the Glass button in the full screen
   bar, remembered per visitor — for the original look: solid ground,
   no blur, no grain, everywhere at once. Dom asked to be able to
   compare the two, 18 September 2026. */
html[data-glass="off"] .bar,html[data-glass="off"] .menu,html[data-glass="off"] .lb__glass{
  background:var(--bg);
  -webkit-backdrop-filter:none; backdrop-filter:none;
}
html[data-glass="off"] .bar::after,html[data-glass="off"] .menu::after,html[data-glass="off"] .lb__glass::after{ display:none }


/* ── Top bar ─────────────────────────────────────────────────── */

.bar{
  position:fixed; top:0; left:0; right:0; z-index:80;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center;
  gap:clamp(10px,3vw,32px);
  height:calc(var(--bar) + env(safe-area-inset-top,0px));
  padding:env(safe-area-inset-top,0px) var(--pad-r) 0 var(--pad-l);
  background:var(--glass);
  -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost);
  border-bottom:1px solid var(--rule);
  box-shadow:var(--shadow-down);
  transition:transform 320ms var(--ease),background-color var(--tone),border-color var(--tone);
}
.bar[data-tucked="true"]{ transform:translateY(-100%) }

.mark{
  font-size:12px; font-weight:500; letter-spacing:.26em; text-transform:uppercase;
  color:var(--ink); text-decoration:none; white-space:nowrap;
  transition:color var(--tone);
}
@media (max-width:400px){ .mark{ letter-spacing:.16em; font-size:11px } }

.menu-btn{
  appearance:none; background:none; border:0; cursor:pointer; color:var(--ink);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.2em; text-transform:uppercase;
  padding:12px 0; transition:color var(--tone);
}

/* ── Ground slider ───────────────────────────────────────────── */

.tone{
  display:flex; align-items:center; gap:10px;
  justify-self:center; width:min(100%,280px);
}
/* Colour mode: the ground is a colour set by hue, saturation and value.
   The mode switch is the first thing in the block; the H and S fields
   appear only in colour mode, and the main slider then sets value. The
   value track shows what it runs through — black to the colour — the
   one place the interface itself is allowed colour, by Dom's amendment
   of 18 September 2026. H and S were sliders with a spectrum and a
   grey-to-hue track until 19 September 2026, when Dom asked for typed
   fields like the code field instead. */
.tone .tone__mode{ font-family:var(--mono); font-size:10px; letter-spacing:.16em; text-transform:uppercase; white-space:nowrap }
.tone__hsv{ display:none; flex:1.4; gap:8px; min-width:0 }
html[data-tone="colour"] .tone__hsv{ display:flex }
html[data-tone="colour"] .tone{ width:min(100%,520px) }
html[data-tone="colour"] .tone__tick{ display:none }
.tone__key{ font-family:var(--mono); font-size:9px; letter-spacing:.1em; color:var(--ink-3); margin-right:4px }
/* The colour by code: a field that reads the ground as hex and takes
   any code back — click, type, Enter. Dom asked on 18 September 2026. */
.tone__code{
  appearance:none; background:none; border:0; border-bottom:1px solid var(--rule-2); border-radius:0;
  font-family:var(--mono); font-size:10px; letter-spacing:.06em; color:var(--ink); text-transform:none;
  width:8ch; padding:2px 0 3px; margin:0; flex:0 0 auto;
  transition:border-color 160ms var(--ease),color var(--tone);
}
.tone__code:focus{ outline:none; border-bottom-color:var(--ink) }
.tone__code[data-bad="true"]{ border-bottom-color:var(--ink); text-decoration:line-through }
@media (max-width:600px){ .tone__code{ width:7ch } }
/* Hue and saturation by number: the same field as the code, three
   characters wide, with its unit after it. Enter applies, Escape puts
   the value back, the arrow keys nudge by one (ten with Shift). */
.tone__field{ display:flex; align-items:baseline; flex:0 0 auto }
.tone__num{
  appearance:none; background:none; border:0; border-bottom:1px solid var(--rule-2); border-radius:0;
  font-family:var(--mono); font-size:10px; letter-spacing:.06em; color:var(--ink); text-align:right;
  font-variant-numeric:tabular-nums; width:3.4ch; padding:2px 0 3px; margin:0;
  transition:border-color 160ms var(--ease),color var(--tone);
}
.tone__num:focus{ outline:none; border-bottom-color:var(--ink) }
.tone__num[data-bad="true"]{ border-bottom-color:var(--ink); text-decoration:line-through }
.tone__unit{ font-family:var(--mono); font-size:9px; color:var(--ink-3); margin-left:2px }
html[data-tone="colour"] .range--main::-webkit-slider-runnable-track{ height:3px; background:var(--track-v,var(--rule-2)) }
html[data-tone="colour"] .range--main::-moz-range-track{ height:3px; background:var(--track-v,var(--rule-2)) }
html[data-tone="colour"] .range--main::-webkit-slider-thumb{ margin-top:-5px }
@media (max-width:600px){ .tone__key{ display:none } }
.tone__label,.tone__val{
  font-family:var(--mono); font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-3); white-space:nowrap; transition:color var(--tone);
}
.tone__val{ font-variant-numeric:tabular-nums; min-width:3ch; text-align:right }
.tone__label{ display:none }
@media (min-width:880px){ .tone__label{ display:block } }
@media (max-width:420px){ .tone__val{ display:none } }

/* The track carries a detent at L* 50 — an 18% grey card, sRGB 119.
   The mark sits below the track so the thumb never hides it. */
.tone__slot{ position:relative; flex:1; display:flex; align-items:center; min-width:0 }
.tone__tick{
  position:absolute; left:50%; top:calc(50% + 7px);
  width:1px; height:5px; transform:translateX(-50%);
  background:var(--rule-2); pointer-events:none;
  transition:background-color 160ms var(--ease),height 160ms var(--ease);
}
.tone[data-neutral="true"] .tone__tick{ background:var(--ink); height:8px }
.tone[data-neutral="true"] .tone__val{ color:var(--ink) }

.range{
  -webkit-appearance:none; appearance:none;
  background:none; border:0; margin:0; padding:0;
  width:100%; height:30px; cursor:pointer; accent-color:var(--ink);
}
.range::-webkit-slider-runnable-track{ height:1px; background:var(--rule-2); border:0 }
.range::-moz-range-track{ height:1px; background:var(--rule-2); border:0 }
.range::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none;
  width:13px; height:13px; margin-top:-6px;
  border:0; border-radius:50%; background:var(--ink);
  transition:transform 140ms var(--ease);
}
.range::-moz-range-thumb{
  width:13px; height:13px; border:0; border-radius:50%; background:var(--ink);
  transition:transform 140ms var(--ease);
}
.range:active::-webkit-slider-thumb{ transform:scale(1.3) }
.range:active::-moz-range-thumb{ transform:scale(1.3) }
.range:focus{ outline:none }
html[data-tabbing="true"] .range:focus-visible::-webkit-slider-thumb{ box-shadow:0 0 0 1px var(--bg),0 0 0 2px var(--ink) }
html[data-tabbing="true"] .range:focus-visible::-moz-range-thumb{ box-shadow:0 0 0 1px var(--bg),0 0 0 2px var(--ink) }

/* ── Menu overlay ────────────────────────────────────────────── */

.menu{
  position:fixed; inset:0; z-index:70;
  background:var(--glass);
  -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost);
  display:flex; flex-direction:column;
  justify-content:center;
  /* `safe` falls back to start rather than clipping the top links
     when the viewport is too short to centre them. */
  justify-content:safe center;
  gap:clamp(20px,5vh,46px);
  padding:calc(var(--bar) + env(safe-area-inset-top,0px) + 4vh) var(--pad-r) calc(4vh + env(safe-area-inset-bottom,0px)) var(--pad-l);
  overflow-y:auto;
  transition:background-color var(--tone);
}
.menu__list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column }
.menu__link{
  display:flex; align-items:baseline; gap:14px;
  text-decoration:none; color:var(--ink);
  font-size:clamp(28px,7vw,60px); font-weight:300; letter-spacing:-.03em; line-height:1.18;
  padding:2px 0;
  transition:color var(--tone),opacity 160ms var(--ease);
}
.menu__link[aria-current="page"]{ color:var(--ink-2) }
.menu__n{
  font-family:var(--mono); font-size:10px; letter-spacing:.14em; color:var(--ink-3);
  font-variant-numeric:tabular-nums;
}
.menu__foot{
  display:flex; flex-wrap:wrap; gap:6px 22px;
  border-top:1px solid var(--rule); padding-top:16px;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-2);
}
.menu__foot a{ color:inherit }
.menu__fs{
  appearance:none; background:none; border:0; padding:0; margin:0;
  font:inherit; color:inherit; cursor:pointer;
  text-decoration:underline; text-underline-offset:3px; text-decoration-thickness:1px;
  transition:color 160ms var(--ease);
}
@media (hover:hover){ .menu__fs:hover{ color:var(--ink) } }
@media (hover:hover){ .menu__link:hover{ opacity:.55 } }
@media (prefers-reduced-motion:no-preference){
  .menu[data-menu-open="true"] .menu__link{ animation:rise 420ms var(--ease) both }
}
@keyframes rise{ from{ opacity:0; transform:translateY(14px) } to{ opacity:1; transform:none } }

/* ── Frames: the before / after unit ─────────────────────────── */

.app{
  padding:calc(var(--bar) + var(--gap)) var(--pad-r) 0 var(--pad-l);
}

.frame{ margin:0 }

.stage{
  display:block; position:relative; width:100%; overflow:hidden;
  margin:0; padding:0; border:0; background:none;
  aspect-ratio:var(--ar,3/2);
  cursor:pointer; touch-action:manipulation;
  -webkit-tap-highlight-color:transparent;
  -webkit-touch-callout:none;   /* no Save Image sheet on a long press: a tap or a pan is what a finger means here */
  /* Without this a mouse drag starts a native image drag, which fires
     pointercancel and freezes a pan after its first few pixels. */
  -webkit-user-select:none; user-select:none;
}
.shot{ -webkit-user-drag:none; user-drag:none }
.shots{ position:absolute; inset:0; display:block }
.shot{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:contain;
  opacity:0;
  transition:opacity 170ms var(--ease);
}
.shot.is-on{ opacity:1 }
.frame--fit .stage{ aspect-ratio:auto; height:var(--h,60vh); height:var(--h,60svh) }

.cap{
  display:flex; align-items:center; gap:14px;
  /* Frames run to the edge, so the caption carries the gutter that
     keeps its text off the screen edge. */
  padding:9px var(--pad-r) 0 var(--pad-l);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-2);
  transition:color var(--tone);
}
.cap__id{ font-variant-numeric:tabular-nums }
.cap__state{ margin-left:auto; color:var(--ink); transition:color var(--tone) }

.icon{
  appearance:none; background:none; border:0; padding:4px; margin:-4px -5px -4px 0;
  cursor:pointer; color:var(--ink-3); line-height:0;
  transition:color 160ms var(--ease);
}
.icon svg{ display:block; width:13px; height:13px }
@media (hover:hover){ .icon:hover{ color:var(--ink) } }

/* ── Home ────────────────────────────────────────────────────── */

/* The hero fits the first screen. It cancels the page gutter and the top
   gap so it can meet the bar and both edges — but if the frame's own
   ratio would push it below the fold, it is sized to the height left
   under the bar (with room for its caption) and centred instead. Nothing
   is cropped either way: the whole photograph is always shown, and a
   square or portrait frame simply leaves ground on both sides. Dom
   asked for the height cap on 18 September 2026; before that the hero
   ran full width at any height. */
.hero{ margin-inline:calc(var(--pad) * -1); margin-top:calc(var(--gap) * -1) }
.hero .frame{ width:100% }
.hero .stage{
  --hero-room:44px;   /* the caption row and a little air above the fold */
  width:min(100%, calc((100vh - var(--bar) - env(safe-area-inset-top,0px) - var(--hero-room)) * (var(--ar,3/2))));
  margin-inline:auto;
}
/* svh is the height with the phone's browser chrome showing — the true
   first screen. vh above is the fallback where it is unsupported. */
@supports (height:1svh){
  .hero .stage{ width:min(100%, calc((100svh - var(--bar) - env(safe-area-inset-top,0px) - var(--hero-room)) * (var(--ar,3/2)))) }
}

/* A true heading for search engines and screen readers that the page
   does not draw. It states what the page is and nothing more — this is
   not a place to bury keywords. */
.seo-heading{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden; white-space:nowrap;
}

.band{ padding-block:clamp(44px,8vh,92px) 0 }
.band__head{
  display:flex; align-items:baseline; justify-content:space-between; gap:16px;
  padding-bottom:calc(var(--gap) + 2px);
}

/* Columns, not rows: frames of mixed shape pack down each column
   instead of leaving a void under every short one. They are real
   columns, dealt by gridHTML() in app.js, shortest first — not CSS
   multicol, whose balancing pushed the fifth of five equal squares into
   a phantom column off the right edge of the page. --cols is what the
   script reads; change the counts here, not there. */
:root{ --cols:1 }
@media (min-width:700px){ :root{ --cols:2 } }
@media (min-width:1200px){ :root{ --cols:3 } }
.grid{ display:flex; align-items:flex-start; gap:var(--gap); margin-inline:calc(var(--pad) * -1) }
.grid__col{ flex:1 1 0; min-width:0 }
.grid .frame{ margin-bottom:calc(var(--gap) * 1.6) }

.index__list{ list-style:none; margin:0; padding:0; border-top:1px solid var(--rule) }
.index__link{
  display:grid; grid-template-columns:1fr auto; gap:2px 22px;
  align-items:baseline;
  padding:clamp(15px,2.4vw,24px) 0;
  border-bottom:1px solid var(--rule);
  text-decoration:none; color:var(--ink);
  transition:border-color var(--tone),color var(--tone);
}
/* Every cell is placed explicitly. Left to auto-placement, the count
   takes the wide column first — an item with a definite row is placed
   before the auto ones — and the category name gets squeezed into the
   narrow one meant for the count. */
.index__name{
  grid-column:1; grid-row:1;
  margin:0;   /* it is an h2 now; the layout wants none of the default */
  font-size:clamp(25px,4.6vw,44px); font-weight:300; letter-spacing:-.03em; line-height:1.06;
  transition:transform 200ms var(--ease);
}
.index__note{
  grid-column:1; grid-row:2;
  color:var(--ink-2); font-size:13.5px; max-width:54ch;
  transition:color var(--tone);
}
.index__n{
  grid-column:2; grid-row:1 / span 2; align-self:center;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.14em; color:var(--ink-3);
  font-variant-numeric:tabular-nums; transition:color var(--tone);
}
@media (hover:hover){
  .index__link:hover .index__name{ transform:translateX(7px) }
  .index__link:hover .index__n{ color:var(--ink) }
}
@media (prefers-reduced-motion:reduce){ .index__name{ transition:none } }

/* ── Page heads, category nav ────────────────────────────────── */

.head{ padding-block:clamp(18px,4vh,46px) clamp(22px,4vh,42px); max-width:72ch }
.head h1{
  margin:10px 0 0;
  font-size:clamp(30px,6vw,58px); font-weight:300; letter-spacing:-.035em; line-height:1.04;
  text-wrap:balance;
}
.lede{ margin:14px 0 0; color:var(--ink-2); font-size:clamp(14px,1.6vw,17px); max-width:56ch; transition:color var(--tone) }

.catnav{
  display:flex; justify-content:space-between; gap:16px;
  border-top:1px solid var(--rule);
  margin-top:clamp(44px,8vh,92px); padding-top:18px;
}
.catnav a{
  color:var(--ink); text-decoration:none;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
}
.catnav span{ color:var(--ink-3); font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase }

/* ── Contact ─────────────────────────────────────────────────── */

.contact{ display:grid; gap:clamp(34px,6vw,72px); grid-template-columns:1fr; padding-bottom:20px }
@media (min-width:860px){ .contact{ grid-template-columns:minmax(0,1.3fr) minmax(220px,.7fr) } }

.form{ display:flex; flex-direction:column; gap:22px; max-width:56ch }
.field{ display:flex; flex-direction:column; gap:7px }
.field > span{
  font-family:var(--mono); font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-2);
  transition:color var(--tone);
}
.field input,.field textarea{
  appearance:none; background:none; color:var(--ink);
  border:0; border-bottom:1px solid var(--rule-2); border-radius:0;
  font-family:var(--sans); font-size:16px; line-height:1.5;
  padding:6px 0 9px; width:100%;
  transition:border-color 160ms var(--ease),color var(--tone);
}
.field textarea{ resize:vertical; min-height:110px }
.field input:focus,.field textarea:focus{ outline:none; border-bottom-color:var(--ink) }
.field input::placeholder,.field textarea::placeholder{ color:var(--ink-3) }

.submit{
  align-self:flex-start;
  appearance:none; background:none; cursor:pointer;
  border:1px solid var(--ink); color:var(--ink);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.2em; text-transform:uppercase;
  padding:13px 26px;
  transition:background-color 160ms var(--ease),color 160ms var(--ease),border-color var(--tone);
}
@media (hover:hover){ .submit:hover{ background:var(--ink); color:var(--bg) } }

.note{ margin:0; font-size:13px; color:var(--ink-2); max-width:48ch; transition:color var(--tone) }

.facts{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:20px }
.facts div{ display:flex; flex-direction:column; gap:4px }
.facts dt{
  font-family:var(--mono); font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-3);
  transition:color var(--tone);
}
.facts dd{ margin:0; font-size:14.5px; color:var(--ink); transition:color var(--tone) }
.facts a{ color:inherit }

a{ color:var(--ink); text-decoration-thickness:1px; text-underline-offset:3px }

/* ── Footer ──────────────────────────────────────────────────── */

.foot{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:10px 26px;
  border-top:1px solid var(--rule);
  margin-top:clamp(48px,9vh,110px);
  padding:20px 0 calc(28px + env(safe-area-inset-bottom,0px));
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-2);
  transition:color var(--tone),border-color var(--tone);
}
.foot a{ color:inherit; text-decoration:none }
@media (hover:hover){ .foot a:hover{ color:var(--ink) } }
.foot__end{ margin-left:auto; color:var(--ink-3) }

/* ── Full screen view ────────────────────────────────────────── */

/* The phone's insets — the notch at the top, the home indicator at the
   bottom — belong to the bars, not to the view: the bars carry them as
   extra padding and so run to the screen's edges, over anything the
   frame puts there. With the padding on the view instead, the frame
   showed through above the top bar. Dom found it on a phone, 18
   September 2026. */
.lb{
  position:fixed; inset:0; z-index:90;
  display:flex; flex-direction:column;
  background-color:var(--bg);
  background-image:var(--grain-ground); background-blend-mode:overlay;   /* the ground's grain, as on the page */
  transition:background-color var(--tone);
}
/* The bars sit above the stage and its one sheet of glass (.lb__glass),
   so a frame panned under them shows through softly rather than
   covering them. They carry no glass of their own: two panes meeting
   make a visible seam, since each blurs its own backdrop. */
.lb__top,.lb__bottom{
  position:relative; z-index:1;
  display:flex; align-items:center; gap:10px 16px;
  padding:8px var(--pad-r) 8px var(--pad-l);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-2);
  transition:color var(--tone);
}
.lb__bottom{ flex-wrap:wrap; border-top:1px solid var(--rule); box-shadow:var(--shadow-up); padding-block:10px calc(10px + env(safe-area-inset-bottom,0px)); transition:border-color var(--tone) }
/* The top bar stands above everything on the stage — the panel, the
   crop box, the ants — so Domshop's menus, which hang from it, drop
   over them and their glass blurs what lies beneath (the options bar
   and the ruler showed through crisp; Dom, 19 September 2026). */
.lb__top{ z-index:9; justify-content:space-between; border-bottom:1px solid var(--rule); box-shadow:var(--shadow-down); padding-top:calc(8px + env(safe-area-inset-top,0px)); transition:color var(--tone),border-color var(--tone) }   /* the same hairline the bottom bar carries — Dom, 18 September 2026 */
/* The image's number, state and zoom sit in the top bar, between the
   count and Back; the bottom bar keeps the controls. Dom, 18 September
   2026. */
.lb__info{ display:flex; flex-wrap:wrap; align-items:center; gap:4px 16px; justify-content:center }
.lb__count{ font-variant-numeric:tabular-nums }
.lb__count #lb-index{ color:var(--ink) }
.lb__state{ color:var(--ink); transition:color var(--tone) }
.tone--lb{ margin-left:auto; width:min(230px,42vw); justify-self:auto }

.lb__stage{
  flex:1; min-height:0; position:relative;
  padding:var(--gap) env(safe-area-inset-right,0px) var(--gap) env(safe-area-inset-left,0px);
}
/* The ruler strips read as one surface with the top bar — its
   extension, Dom's words, 19 September 2026 — so the shadow falls from
   the strips' inner edges onto the canvas (and onto the picture when it
   runs under them), not from the bar onto the strips: with the rulers
   on, the top bar's own shadow stands down and these two bands take
   over, one along the top strip's lower edge, one along the left
   strip's right edge. They match --shadow-down in weight. With the
   rulers off the strips are gone and the bar's shadow returns. */
.lb__stage::before,.lb__stage::after{
  content:""; position:absolute; z-index:2; pointer-events:none; display:none;
}
.lb__stage::before{
  left:0; right:0; top:var(--ruler,0px); height:24px;
  background:linear-gradient(to bottom,rgba(0,0,0,.10),rgba(0,0,0,.035) 40%,rgba(0,0,0,0));
}
.lb__stage::after{
  top:0; bottom:0; left:calc(var(--ruler,0px) + env(safe-area-inset-left,0px)); width:24px;
  background:linear-gradient(to right,rgba(0,0,0,.10),rgba(0,0,0,.035) 40%,rgba(0,0,0,0));
}
.lb[data-rulers="on"] .lb__stage::before,.lb[data-rulers="on"] .lb__stage::after{ display:block }
.lb[data-rulers="on"] .lb__top{ box-shadow:none }
/* Two canvases sandwich the frame: a grid beneath it and rulers above
   it, both in the photograph's own pixel space with 0,0 at its top left
   corner, drawn by drawCanvas() in app.js. DOM order does the layering;
   neither takes pointer events, so every gesture still reaches the
   frame. Dom asked for the grid and the rulers on 18 September 2026. */
.lb__grid,.lb__ruler{ position:absolute; inset:0; width:100%; height:100%; pointer-events:none }
/* One sheet of frosted glass for all the chrome of the view — the top
   bar, both ruler strips and the bottom bar — with a hole cut where the
   picture shows, so the blur is computed once and there is no seam
   where one pane would meet another. It lives inside the stage, between
   the frame and the ruler canvas, and reaches up under the top bar and
   down under the bottom one (--lb-top, --lb-bottom, measured by
   sizeCanvases in app.js). The hole is the evenodd polygon's inner
   rectangle: the frame's box. Dom disliked the seam, 18 September
   2026. */
.lb__glass{
  position:absolute; left:0; right:0;
  /* A pixel past each bar's outer edge, which is off the screen, so no
     sub-pixel sliver of the frame shows at the screen's bottom edge. */
  top:calc(-1 * var(--lb-top,0px) - 1px); bottom:calc(-1 * var(--lb-bottom,0px) - 1px);
  pointer-events:none;
  background:var(--glass);
  -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost);
  --band-top:calc(var(--lb-top,0px) + 1px + var(--ruler,0px));     /* the sheet starts a pixel above the bar */
  --band-left:calc(var(--ruler,0px) + env(safe-area-inset-left,0px));
  --band-bottom:calc(100% - var(--lb-bottom,0px) - 1px);
  clip-path:polygon(evenodd,
    0 0, 100% 0, 100% 100%, 0 100%, 0 0,
    var(--band-left) var(--band-top),
    var(--band-left) var(--band-bottom),
    100% var(--band-bottom),
    100% var(--band-top),
    var(--band-left) var(--band-top));
  transition:background-color var(--tone);
}
/* The frame's box starts at the inner corner of the rulers (--ruler is
   their depth, set by paintLb in app.js), so a frame at home sits with
   its top left corner exactly where the two 0 marks meet. */
.lb__stage .frame{
  position:absolute;
  inset:calc(var(--ruler,0px) + var(--meta,0px)) env(safe-area-inset-right,0px) var(--gap) calc(var(--ruler,0px) + env(safe-area-inset-left,0px));
}
/* The file facts above the frame — bit depth, profile, mode, size,
   ppi — one to a line, stacked upward from the picture's top edge
   (column-reverse: the first fact sits nearest the picture), set on
   the picture's top left corner by drawCanvas in app.js and riding
   with it; --meta is the room the box leaves for the stack at home
   (META_LINE and META_PAD in app.js match the line height and the
   padding here). Under the glass like the picture. Dom, 19 September
   2026. */
.lb__meta{
  position:absolute; left:0; top:0; padding:0 0 7px 6px; pointer-events:none; white-space:nowrap;   /* 6px off the 0 axis, 7px above the picture */
  display:flex; flex-direction:column-reverse; align-items:flex-start;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; line-height:16.5px;
  will-change:transform;
}
.lb__stage .stage{ height:100% }
/* The frame's box starts inside the rulers, but the frame itself must
   run out of it — under the glass of the strips and the bars, and off
   the screen — or a pan just clips it at the box's edge and the glass
   has nothing beneath it. The grid's frames keep overflow:hidden. */
.lb__stage .stage{ overflow:visible }
/* Raw pointer events: the browser must not claim the gestures. */
.lb__stage .stage{ touch-action:none }
/* No focus ring round the full screen frame: a tap focuses its button
   and the next Space would draw a rectangle round the whole box, seen
   as a stray line above the bottom bar. The state readout is the
   feedback there; the grid's frames keep their ring. Dom, 18 September
   2026. */
.lb__stage .stage:focus-visible{ outline:none }
.lb__stage .shots{ transition:transform 180ms var(--ease); will-change:transform }
/* Past 100% the pixels are drawn as pixels, not smoothed. */
.lb__stage[data-pixelated="true"] .shot{ image-rendering:pixelated }
.lb__stage .stage{ cursor:grab }
.lb__stage .stage[data-panning="true"]{ cursor:grabbing }
/* The swap is instant in the view: the grid's short crossfade costs a
   phone a re-composite of two very large images on every tap. Dom, 19
   September 2026 — and his rule: a tap swaps, never delayed. */
.lb__stage .shot{ transition:none }
/* The eyedropper: a crosshair while it is on; the readout in the top
   bar, in the zoom's tone. */
.lb__stage[data-pick="true"] .stage{ cursor:crosshair }
.lb__pixel{ color:var(--ink-3); font-variant-numeric:tabular-nums; white-space:nowrap; transition:color var(--tone) }

/* The zoom readout, and the two text buttons beside it. The readout is
   one image pixel per screen pixel at 100%, the way a retoucher counts,
   so it reads about 15% at fit. The buttons are plain type that lift to
   full ink on hover, and the one that describes the current view stays
   lit. Dom asked for them on 18 September 2026. */
.lb__zoom{ color:var(--ink-3); font-variant-numeric:tabular-nums; min-width:4ch; transition:color var(--tone) }
.act,.lb__act{
  appearance:none; background:none; border:0; padding:0; margin:0;
  font:inherit; letter-spacing:inherit; text-transform:inherit; color:var(--ink-3); cursor:pointer;
  font-variant-numeric:tabular-nums;
  transition:color 160ms var(--ease);
}
@media (hover:hover){ .act:hover,.lb__act:hover{ color:var(--ink) } }
.act[aria-pressed="true"],.lb__act[aria-pressed="true"]{ color:var(--ink); text-decoration:underline; text-underline-offset:3px; text-decoration-thickness:1px }
/* The Background toggle, in a caption or the full screen bar: lit while
   the background shows; off, the cutout sits on the page's own ground. */
.cap__bg{ margin-left:2px }
/* The scroll toggle states a mode rather than a destination, so it is
   never underlined; and it is for devices with a scroll surface, so a
   phone never sees it. */
.lb__act--wheel{ margin-left:6px }
.lb__act--wheel[aria-pressed="true"]{ text-decoration:none }
.lb__act--glass{ margin-left:6px }
.lb__act--rulers{ margin-left:6px }
.lb__act--unit{ margin-left:6px; min-width:2.4ch; text-transform:none }   /* the unit as written: px, in, mm */
.lb__act--grid{ margin-left:6px }
.lb__act--fs{ margin-left:6px }
@media (pointer:coarse){ .lb__act--wheel{ display:none } }

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important }
}

/* ── Landscape on a phone ──────────────────────────────────────────
   Wide and very short: roughly 844 x 390. Height, not width, is the
   scarce axis here, so the chrome shrinks, type scales off vh, the
   grid takes more columns so a whole frame fits on screen at once,
   and the menu splits into two so every link stays reachable.
   ────────────────────────────────────────────────────────────────── */
@media (orientation:landscape) and (max-height:520px){
  :root{ --bar:44px; --gap:clamp(8px,1.2vw,14px) }

  .band{ padding-block:clamp(26px,7vh,52px) 0 }

  /* Two columns below 700px, three above, so frames stay near the
     height of the viewport instead of towering well past it. */
  :root{ --cols:2 }

  .head{ padding-block:clamp(10px,3vh,20px) clamp(12px,3vh,24px) }
  .head h1{ font-size:clamp(26px,7vh,44px) }
  .lede{ font-size:14px }

  .menu{ padding-block:calc(var(--bar) + env(safe-area-inset-top,0px) + 12px) 12px; gap:14px }
  .menu__list{ display:grid; grid-template-columns:repeat(2,1fr); column-gap:clamp(20px,4vw,56px) }
  .menu__link{ font-size:clamp(18px,4.4vh,28px) }
  .menu__foot{ padding-top:10px }

  .lb__top,.lb__bottom{ padding-block:4px }
  .lb__stage{ padding-block:5px }

  .foot{ margin-top:clamp(30px,8vh,64px); padding-top:16px }
}
@media (orientation:landscape) and (max-height:520px) and (min-width:700px){
  :root{ --cols:3 }
}

/* clients:cut-to-end — everything below is Domshop's: tools/sections.mjs drops it from the client sections' stylesheet. Keep Domshop's rules at the end of this file so that stays true. */
/* The editor: no browser gesture from a finger on its chrome either — the lists still scroll up and down (Dom, 20 September 2026). */
html[data-shop-on],html[data-shop-on] body{ overscroll-behavior:none }
html[data-shop-on] .shop__panel,html[data-shop-on] .shop__history,html[data-shop-on] .shop__dialog,html[data-shop-on] .shop__menu,html[data-shop-on] .shop__options,html[data-shop-on] .lb__top,html[data-shop-on] .lb__bottom{ touch-action:pan-y }
/* ── Domshop ─────────────────────────────────────────────────── */
/* The editor in shop.js, opened from the footer's last word. It
   borrows the full screen view whole and adds: its tools, brush fields,
   colour chips and file actions in the bottom bar (.shop__bar); a
   Layers panel on the stage's right, in the same glass as the bars;
   and the brush's outline in place of the pointer. Dom asked on 19
   September 2026. */
.shop__bar{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px }
/* The tools as icons: pixel art in currentColor, crisp at 1× and 2×.
   The chosen tool sits on a hairline, as the text buttons underline. */
.shop__tool{ padding:3px 2px 2px; line-height:0; border-bottom:1px solid transparent; margin-right:-2px }
.shop__tool svg{ display:block; width:16px; height:16px; shape-rendering:crispEdges }
.shop__tool[aria-pressed="true"]{ color:var(--ink); border-bottom-color:currentColor; text-decoration:none }
.shop__sep{ width:1px; height:14px; background:var(--rule); opacity:.9 }
.shop__chips{ position:relative; display:inline-flex; width:44px; height:24px; flex:0 0 auto }
.shop__chip-mini{ position:absolute; appearance:none; border:0; background:none; padding:0; margin:0; color:var(--ink-3); cursor:pointer; font:inherit; font-size:9px; line-height:1; width:12px; height:12px }
.shop__chip-mini--default{ left:0; bottom:-2px } .shop__chip-mini--swap{ left:30px; top:0 }
.shop__chip-mini:hover{ color:var(--ink) }
/* The view's own bottom buttons stand down in Domshop: the zoom tool, the View menu, ⌘R, a click on a ruler and F do their jobs (Dom, 20 September 2026). */
html[data-shop-on] #lb-fit, html[data-shop-on] #lb-one, html[data-shop-on] #lb-wheel, html[data-shop-on] #lb-glass, html[data-shop-on] #lb-rulers, html[data-shop-on] #lb-unit, html[data-shop-on] #lb-pick, html[data-shop-on] #lb-fs{ display:none !important }
.shop__chip{
  position:absolute; width:16px; height:16px; border:1px solid var(--ink-3); border-radius:0; padding:0; cursor:pointer;
  background:#000; box-shadow:0 0 0 1px var(--bg);
}
.shop__chip--fg{ left:12px; top:0; z-index:1 }
.shop__chip--bg{ left:22px; top:6px; background:#fff }
.shop__colour{ position:absolute; width:1px; height:1px; opacity:0; left:0; bottom:0; pointer-events:none }
.lb__stage[data-shop-on="true"] .stage{ touch-action:none }
.lb__stage[data-tool="brush"] .stage,.lb__stage[data-tool="eraser"] .stage,.lb__stage[data-tool="pencil"] .stage,.lb__stage[data-tool="colorReplace"] .stage,.lb__stage[data-tool="bgEraser"] .stage,.lb__stage[data-tool="clone"] .stage,.lb__stage[data-tool="patternStamp"] .stage,.lb__stage[data-tool="history"] .stage,.lb__stage[data-tool="artHistory"] .stage,.lb__stage[data-tool="blur"] .stage,.lb__stage[data-tool="sharpen"] .stage,.lb__stage[data-tool="smudge"] .stage,.lb__stage[data-tool="dodge"] .stage,.lb__stage[data-tool="burn"] .stage,.lb__stage[data-tool="sponge"] .stage,.lb__stage[data-tool="heal"] .stage,.lb__stage[data-tool="spotHeal"] .stage,.lb__stage[data-tool="remove"] .stage,.lb__stage[data-tool="quickSelect"] .stage,.lb__stage[data-tool="redEye"] .stage{ cursor:none }
.lb__stage[data-tool="wand"] .stage,.lb__stage[data-tool="objectSelect"] .stage,.lb__stage[data-tool="magicEraser"] .stage,.lb__stage[data-tool="polyLasso"] .stage,.lb__stage[data-tool="magneticLasso"] .stage,.lb__stage[data-tool="frame"] .stage,.lb__stage[data-tool="sampler"] .stage,.lb__stage[data-tool="count"] .stage,.lb__stage[data-tool="ruler"] .stage,.lb__stage[data-tool="pen"] .stage,.lb__stage[data-tool="freePen"] .stage,.lb__stage[data-tool="curvePen"] .stage,.lb__stage[data-tool="addAnchor"] .stage,.lb__stage[data-tool="deleteAnchor"] .stage,.lb__stage[data-tool="convertPoint"] .stage,.lb__stage[data-tool^="shape"] .stage,.lb__stage[data-tool="patch"] .stage,.lb__stage[data-tool="caMove"] .stage{ cursor:crosshair }
.lb__stage[data-tool="pathSelect"] .stage,.lb__stage[data-tool="directSelect"] .stage{ cursor:default }
/* Cursors for what a press would do, over a warp mesh or puppet pins: Domshop's own icons (Dom, 20 September 2026). */
.lb__stage[data-hover="warp-anchor"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Crect x='8' y='8' width='8' height='8' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 2v4M12 18v4M2 12h4M18 12h4' stroke='%23fff' stroke-width='3'/%3E%3Cpath d='M12 2v4M12 18v4M2 12h4M18 12h4' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, move }
.lb__stage[data-hover="warp-handle"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M4 20L20 4' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M4 20L20 4' stroke='%23000' stroke-width='1.5'/%3E%3Ccircle cx='12' cy='12' r='4' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, move }
.lb__stage[data-hover="warp-inside"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M3 8q9-8 18 0M3 16q9 8 18 0M3 8v8M21 8v8' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M3 8q9-8 18 0M3 16q9 8 18 0M3 8v8M21 8v8' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, grab }
.lb__stage[data-hover="pin-add"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='9' cy='9' r='4.5' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M9 13.5V22' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M9 13.5V22' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M18 14v8M14 18h8' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M18 14v8M14 18h8' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 9 9, crosshair }
.lb__stage[data-hover="pin-move"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.5' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 1v5M12 18v5M1 12h5M18 12h5' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M12 1v5M12 18v5M1 12h5M18 12h5' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, move }
.lb__stage[data-hover="pin-rotate"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='3' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 4a8 8 0 1 1-7.4 5' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M12 4a8 8 0 1 1-7.4 5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M2.5 5.5l2.1 3.9 3.9-2.1' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M2.5 5.5l2.1 3.9 3.9-2.1' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, alias }   /* Alt over a pin: turn it */
.lb__stage[data-hover="xf-rotate"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 12a7 7 0 0 1 12-5' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M5 12a7 7 0 0 1 12-5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M19 12a7 7 0 0 1-12 5' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M19 12a7 7 0 0 1-12 5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M17 3v4h-4' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M17 3v4h-4' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M7 21v-4h4' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M7 21v-4h4' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, grab }   /* outside a corner of the transform box, and while a rotation is on */
.lb__stage[data-hover="xf-move"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M12 3v18M3 12h18' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M12 3v18M3 12h18' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M9 6l3-3 3 3M9 18l3 3 3-3M6 9l-3 3 3 3M18 9l3 3-3 3' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M9 6l3-3 3 3M9 18l3 3 3-3M6 9l-3 3 3 3M18 9l3 3-3 3' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, move }
.lb__stage[data-hover="xf-skew"] .stage, .lb__stage[data-hover="xf-skew"] .shop__xform-handle{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M4 17h16M8 7h12' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M4 17h16M8 7h12' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M17 4l3 3-3 3M7 14l-3 3 3 3' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M17 4l3 3-3 3M7 14l-3 3 3 3' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, col-resize }
.lb__stage[data-hover="xf-distort"] .stage, .lb__stage[data-hover="xf-distort"] .shop__xform-handle{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 5l7 3 7-3-3 7 3 7-7-3-7 3 3-7z' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Ccircle cx='12' cy='12' r='2' fill='%23000'/%3E%3C/svg%3E") 12 12, crosshair }
.lb__stage[data-hover="xf-anchor"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Ccircle cx='12' cy='12' r='4' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 2v5M12 17v5M2 12h5M17 12h5' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M12 2v5M12 17v5M2 12h5M17 12h5' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 12 12, crosshair }
.lb__stage[data-hover="pin-remove"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='9' cy='9' r='4.5' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M14 18h8' stroke='%23fff' stroke-width='3.5'/%3E%3Cpath d='M14 18h8' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 9 9, not-allowed }
.lb__stage[data-tool^="text"] .stage{ cursor:text }
.lb__stage[data-tool="dropper"] .stage{ cursor:crosshair }
.lb__stage[data-tool="zoom"] .stage{ cursor:zoom-in }
.lb__stage[data-tool="hand"] .stage{ cursor:grab }
@media (pointer:coarse){ .lb__stage[data-tool="brush"] .stage,.lb__stage[data-tool="eraser"] .stage{ cursor:auto } }
/* The brush outline: a ring in the chrome's tone with a hairline of the
   opposite beneath it, so it reads on any picture. */
.shop__cursor{
  position:absolute; left:0; top:0; z-index:4; pointer-events:none; box-sizing:border-box;
  border:1px solid rgba(255,255,255,.9); border-radius:50%;
  box-shadow:0 0 0 1px rgba(0,0,0,.55), inset 0 0 0 1px rgba(0,0,0,.35);
}
/* The brush HUD: the tip previewed at the drag's origin — a disc whose
   feather is the hardness — with its numbers beside it. */
.shop__hud{ position:absolute; left:0; top:0; z-index:5; pointer-events:none }
.shop__hud-tip{ border-radius:50%; box-shadow:0 0 0 1px rgba(255,255,255,.9), 0 0 0 2px rgba(0,0,0,.45) }
.shop__hud-text{
  position:absolute; left:0; top:0; white-space:nowrap;
  font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; color:#fff;
  text-shadow:0 0 2px rgba(0,0,0,.9), 0 0 6px rgba(0,0,0,.6);
}
/* Domshop's menu bar, in the top bar's left, Photoshop's shape: the
   app's name then the menus; a menu drops in the bars' glass, items in
   sentence case with their keys at the right, the ones still waiting
   for a feature drawn quiet. */
.shop__menubar{ position:relative; display:flex; flex-wrap:wrap; align-items:center; gap:0 4px }
.shop__menutitle{
  appearance:none; background:none; border:0; cursor:pointer; margin:0; padding:4px 7px;
  font:inherit; letter-spacing:inherit; text-transform:inherit; color:var(--ink-2); transition:color 160ms var(--ease);
}
.shop__menutitle--app{ color:var(--ink); padding-left:0 }
@media (hover:hover){ .shop__menutitle:hover{ color:var(--ink) } }
.shop__menutitle[aria-expanded="true"]{ color:var(--ink); text-decoration:underline; text-underline-offset:3px }
.shop__menu{
  position:absolute; top:100%; z-index:20; min-width:240px; max-height:70vh; overflow:auto; overscroll-behavior:contain;
  padding:4px 0; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost);
  border:1px solid var(--rule); box-shadow:var(--shadow-down);
  text-transform:none; letter-spacing:.04em; font-size:11.5px;
}
.shop__menu-item{
  appearance:none; background:none; border:0; cursor:pointer; margin:0; width:100%; text-align:left;
  display:flex; align-items:baseline; gap:12px; padding:5px 12px 5px 8px;
  font:inherit; letter-spacing:inherit; color:var(--ink);
}
/* A gutter for Photoshop's check marks, so labels line up whether or not one is checked. */
.shop__menu-check{ flex:0 0 12px; text-align:center; font-size:10px }
.shop__menu-label{ flex:1 1 auto; white-space:nowrap }
.shop__menu-item[aria-disabled="true"]{ color:var(--ink-3); opacity:.45; cursor:default }
@media (hover:hover){ .shop__menu-item:not([aria-disabled="true"]):hover{ background:rgba(127,127,127,.16) } }
.shop__menu-key{ color:var(--ink-3); opacity:.6; font-variant-numeric:tabular-nums; white-space:nowrap }
.shop__menu-sep{ border:0; border-top:1px solid var(--rule); margin:4px 0 }
.shop__submenu{ z-index:21 }
/* The tool's values as sliders in a window of their own, and a slight radius on every floating window (Dom, 20 September 2026). */
.shop__sliders{ position:absolute; left:calc(var(--ruler,0px) + 12px + env(safe-area-inset-left,0px)); top:36%; z-index:8; width:236px; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); box-shadow:var(--shadow-down); color:var(--ink); font-family:var(--mono); font-size:11px; letter-spacing:.06em }
.shop__sliders-head{ display:flex; align-items:center; justify-content:space-between; padding:6px 8px 6px 12px; border-bottom:1px solid var(--rule); cursor:move; -webkit-user-select:none; user-select:none; letter-spacing:.16em; text-transform:uppercase; font-size:10.5px }
.shop__sliders-close{ appearance:none; background:none; border:0; color:var(--ink); font:inherit; font-size:14px; cursor:pointer; padding:0 4px; opacity:.7 }
.shop__sliders-body{ padding:6px 12px 8px }
.shop__sliders-row{ display:flex; align-items:center; gap:8px; min-height:24px }
.shop__sliders-label{ flex:0 0 66px; text-transform:uppercase; letter-spacing:.1em; font-size:9.5px }
.shop__sliders-row input[type="range"]{ flex:1; min-width:60px; accent-color:var(--ink) }
.shop__sliders-value{ flex:0 0 5ch; text-align:right; font-variant-numeric:tabular-nums }
.shop__panel, .shop__dialog, .shop__menu, .shop__context, .shop__history, .shop__navigator, .shop__histogram, .shop__taskbar, .shop__sliders, .shop__blendmenu, .shop__opacitymenu, .shop__adjustmenu, .shop__fontmenu{ border-radius:6px }
.shop__dialog-head, .shop__sliders-head{ border-radius:6px 6px 0 0 }
/* Type › Panels › Glyphs, the Measurement Log's table, the Contextual Task Bar (20 September 2026). */
.shop__fontmenu{ top:auto; z-index:30; min-width:260px; max-height:min(70vh, 640px) }
.shop__fontsearch{ display:block; width:calc(100% - 16px); margin:4px 8px 6px; padding:4px 6px; font:inherit; font-size:11px; letter-spacing:.04em; color:var(--ink); background:rgba(127,127,127,.14); border:1px solid var(--rule); outline:none }
.shop__glyphs{ display:flex; flex-wrap:wrap; gap:2px; margin:4px 0 8px }
.shop__glyph{ appearance:none; background:rgba(127,127,127,.12); border:1px solid var(--rule); color:var(--ink); width:28px; height:28px; font-size:15px; cursor:pointer; padding:0 }
.shop__glyph:hover{ border-color:var(--ink) }
.shop__log{ overflow:auto; max-height:50vh }
.shop__store-row{ display:flex; gap:8px; align-items:baseline; padding:5px 0; border-bottom:1px solid var(--rule); font-size:11px; line-height:1.5 }   /* the pixel store's self test: a row a check, the tick or cross in ink — no colour (rule 1) */
.shop__store-row b{ flex:none; width:1em; text-align:center }
.shop__store-row[data-state="run"]{ opacity:.55 }
.shop__store-row[data-state="skip"]{ opacity:.7 }   /* a check that could not run here: never green */
.shop__store-row[data-state="bad"] span{ font-weight:600 }
.shop__store-row:last-child{ border-bottom:0 }
.shop__store-copy{ padding-top:8px }
.shop__log table{ border-collapse:collapse; font-size:10.5px; white-space:nowrap }
.shop__log th, .shop__log td{ text-align:left; padding:3px 8px; border-bottom:1px solid var(--rule) }
.shop__log th{ color:var(--ink-3); font-weight:normal; letter-spacing:.08em; text-transform:uppercase; font-size:9.5px }
.shop__taskbar{ position:absolute; left:50%; bottom:calc(var(--gap, 12px) + 12px); transform:translateX(-50%); z-index:8; display:flex; gap:2px; padding:4px; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); box-shadow:var(--shadow-up) }
.shop__task{ appearance:none; background:none; border:0; color:var(--ink); font:inherit; font-size:10.5px; letter-spacing:.08em; text-transform:uppercase; padding:6px 10px; cursor:pointer }
.shop__task:hover{ background:rgba(127,127,127,.16) }
.lb__stage.is-panels-hidden .shop__panel, .lb__stage.is-panels-hidden .shop__history, .lb__stage.is-panels-hidden .shop__taskbar{ display:none }
/* The document's shadow, under the picture: it lifts the canvas off
   the ground, and stays the same softness at any zoom. */
.shop__shadow{
  position:absolute; left:0; top:0; pointer-events:none; box-shadow:0 2px 6px rgba(0,0,0,.16), 0 18px 48px rgba(0,0,0,.22);
  /* Photoshop's transparency grid beneath the document: 8px checks in
     screen pixels, whatever the zoom, showing wherever the picture is
     clear. Dom asked, 19 September 2026. */
  background:repeating-conic-gradient(#cccccc 0 25%, #ffffff 0 50%) 0 0 / 16px 16px;
}
/* The view's canvas: the stage's size in device pixels, the part of the
   document on screen drawn onto it at the zoom (the pixel store's step
   four); over the frame and its shadow, under the meta, the glass and
   the rulers by document order. The frame's own shot stays as an empty
   picture whose box the geometry reads. */
/* The picture. It is placed and sized by sizeVp, which reaches it under the bars
   so their frosted glass has the picture to blur — the band .lb__glass covers. */
.shop__vp{ position:absolute; left:0; top:0; pointer-events:none; display:block }
/* The marching ants, over the picture in screen space. */
.shop__ants{ position:absolute; inset:0; width:100%; height:100%; z-index:2; pointer-events:none }
/* The options bar under the menus: the tool's icon and name, then its
   settings — each group shown only while its tool is the tool. Drawn
   like the top bar, in the same glass and tone. */
/* One line, one height, whatever the tool: 36px, nothing wrapping —
   a tool with more than fits scrolls sideways (Dom, 19 September
   2026: the bar was jumping between two and three lines by tool). */
.shop__options{
  position:relative; z-index:1; display:flex; flex-wrap:nowrap; align-items:center; gap:0 14px;
  height:36px; box-sizing:border-box; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; white-space:nowrap;
  padding:0 var(--pad-r) 0 var(--pad-l); border-bottom:1px solid var(--rule);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-2);
  transition:color var(--tone),border-color var(--tone);
}
.shop__options::-webkit-scrollbar{ display:none }
.shop__options > *, .shop__opts > *{ flex:none }   /* nothing squeezes: the groups are display:contents, so their children are the flex items */
.shop__options-tool{ display:inline-flex; align-items:center; gap:8px; color:var(--ink); margin-right:6px }
.shop__options-icon svg{ display:block; width:16px; height:16px; shape-rendering:crispEdges }
.shop__opts{ display:contents }
.shop__readout{ color:var(--ink-3); letter-spacing:.08em; text-transform:none; font-size:11px }
.shop__readout{ color:var(--ink-2); font-variant-numeric:tabular-nums }
.shop__options:not([data-kind="paint"]):not([data-kind="process"]):not([data-kind="spot"]):not([data-kind="select"]) .shop__opts--brush{ display:none }
.shop__options:not([data-kind="tone"]) .shop__opts--tone{ display:none }
.shop__options:not([data-kind="shape"]) .shop__opts--shape{ display:none }
.shop__options:not([data-kind="path"]) .shop__opts--path{ display:none }
.shop__options:not([data-kind="marks"]) .shop__opts--marks{ display:none }
.shop__options:not([data-kind="frame"]) .shop__opts--frame{ display:none }
.shop__options:not([data-kind="object"]) .shop__opts--object{ display:none }
.shop__options[data-tool="objectSelect"] .shop__opts--sel .tone__field{ display:none }   /* no feather on the object tool, as in Photoshop */
.shop__objmode{ flex:none; width:auto; min-width:8ch; max-width:120px; padding-right:14px; background-image:linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position:calc(100% - 8px) 55%, calc(100% - 4px) 55%; background-size:4px 4px; background-repeat:no-repeat }
.shop__obj-status{ min-width:12ch }
.shop__ibtn{ display:inline-flex; align-items:center; justify-content:center; width:22px; height:20px; padding:2px 2px 1px; line-height:0; border-bottom:1px solid transparent; font-size:12px }   /* an icon in the options bar — the selection modes, the Object Finder's controls (Dom, 21 September 2026) */
.shop__ibtn svg{ display:block; width:16px; height:16px; shape-rendering:crispEdges }
.shop__ibtn[aria-pressed="true"]{ color:var(--ink); border-bottom-color:currentColor; text-decoration:none }
.shop__objengine{ width:14px; margin-left:-4px }
.shop__options:not([data-tool="clone"]):not([data-tool="heal"]) .shop__opts--clone{ display:none }
.shop__options:not([data-tool="remove"]) .shop__opts--remove{ display:none }
.shop__options:not([data-tool="clone"]):not([data-tool="heal"]):not([data-tool="spotHeal"]):not([data-tool="remove"]):not([data-tool="patch"]):not([data-tool="caMove"]) .shop__opts--sample{ display:none }   /* Sample: Current Layer / Current & Below / All Layers, on every tool that samples the picture */
.shop__options:not([data-tool="clone"]):not([data-tool="heal"]) .shop__ignoreadj{ display:none }   /* Ignore Adjustment Layers: Photoshop has it on the clone stamp and the healing brush alone */
.shop__sample{ max-width:150px }
.shop__remove-go{ font-size:13px }
.shop__options:not([data-tool="shapeRect"]) [data-shop-shape="radius"]{ display:none }
.shop__options:not([data-tool="shapePolygon"]) [data-shop-shape="sides"]{ display:none }
.shop__options:not([data-tool="shapeCustom"]) .shop__shape-custom{ display:none }
.shop__options:not([data-tool="sponge"]) .shop__tone-mode{ display:none }
.shop__options[data-tool="sponge"] .shop__tone-range{ display:none }
.shop__options:not([data-tool="ruler"]) [data-shop-act="straighten"]{ display:none }
.shop__options:not([data-tool="lasso"]):not([data-tool="marquee"]):not([data-tool="polyLasso"]):not([data-tool="magneticLasso"]):not([data-tool="wand"]):not([data-tool="quickSelect"]):not([data-tool="objectSelect"]) .shop__opts--sel{ display:none }
.shop__options:not([data-tool="marquee"]) .shop__opts--marquee{ display:none }
.shop__options:not([data-tool="hand"]):not([data-tool="zoom"]) .shop__opts--view{ display:none }
.shop__options:not([data-tool="crop"]) .shop__opts--crop{ display:none }
.shop__options:not([data-tool="bucket"]):not([data-kind="wandlike"]):not([data-tool="quickSelect"]):not([data-tool="bgEraser"]):not([data-tool="colorReplace"]) .shop__opts--bucket{ display:none }
.shop__options:not([data-tool="gradient"]) .shop__opts--gradient{ display:none }
.shop__options .shop__gradmode, .shop__options .shop__gradtype, .shop__options .shop__gradblend, .shop__options .shop__gradmethod{ flex:none; width:auto; min-width:8ch; padding-right:14px; background-image:linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position:right 6px top 50%, right 2px top 50%; background-size:4px 4px; background-repeat:no-repeat }   /* the gradient tool's menus, sized to their words like the object tool's */
.shop__options .shop__gradmode{ max-width:190px } .shop__options .shop__gradtype{ max-width:100px } .shop__options .shop__gradblend{ max-width:130px } .shop__options .shop__gradmethod{ max-width:110px }
.lb__stage[data-tool="bucket"] .stage,.lb__stage[data-tool="gradient"] .stage{ cursor:crosshair }
.shop__options:not([data-tool="text"]) .shop__opts--type{ display:none }
.shop__crop-size{ font-variant-numeric:tabular-nums; min-width:11ch }
.shop__check{ display:inline-flex; align-items:center; gap:6px; cursor:pointer; color:var(--ink-2) }
.shop__check input{ appearance:none; width:11px; height:11px; margin:0; border:1px solid var(--ink-3); background:none; cursor:pointer }
.shop__check input:checked{ background:var(--ink); border-color:var(--ink) }
.shop__font{ max-width:150px }
.lb__stage[data-tool="crop"] .stage{ cursor:crosshair }
.lb__stage[data-tool="text"] .stage{ cursor:text }
.lb__stage[data-tool="zoom"] .stage{ cursor:zoom-in }
/* The crop box: the shield darkens everything outside it, the box is
   ruled, its handles sit on the corners and sides. */
.shop__crop{
  position:absolute; left:0; top:0; z-index:4; box-sizing:border-box;
  border:1px solid rgba(255,255,255,.9); box-shadow:0 0 0 1px rgba(0,0,0,.6), 0 0 0 9999px rgba(0,0,0,.5); cursor:move;
}
.shop__crop-handle{ position:absolute; width:9px; height:9px; background:#fff; border:1px solid rgba(0,0,0,.7); box-sizing:border-box }
.shop__crop-handle--nw{ left:-5px; top:-5px; cursor:nwse-resize } .shop__crop-handle--se{ right:-5px; bottom:-5px; cursor:nwse-resize }
.shop__crop-handle--ne{ right:-5px; top:-5px; cursor:nesw-resize } .shop__crop-handle--sw{ left:-5px; bottom:-5px; cursor:nesw-resize }
.shop__crop-handle--n{ left:calc(50% - 4px); top:-5px; cursor:ns-resize } .shop__crop-handle--s{ left:calc(50% - 4px); bottom:-5px; cursor:ns-resize }
.shop__crop-handle--w{ left:-5px; top:calc(50% - 4px); cursor:ew-resize } .shop__crop-handle--e{ right:-5px; top:calc(50% - 4px); cursor:ew-resize }
/* The type editor: over the type at the zoom's scale, the letters
   themselves drawn on the layer beneath, so only the caret shows here. */
.shop__type{
  position:absolute; left:0; top:0; z-index:5; white-space:pre; outline:none; color:transparent;
  min-height:1em; padding:0; margin:0; border:0; background:none; cursor:text;
}
.shop__type::selection{ background:rgba(127,127,127,.35) }
/* The layers' right-click menu, on the stage where it was called for. */
.shop__context{ position:absolute; z-index:7 }
.lb__stage[data-tool="lasso"] .stage,.lb__stage[data-tool="marquee"] .stage{ cursor:crosshair }
.lb__stage[data-tool="move"] .stage{ cursor:move }
/* The tool wheel: its variants fanned round the point where the key
   was held, in the bars' glass; the one the pointer leans towards is lit. */
.shop__wheel{ position:absolute; left:0; top:0; z-index:6; width:0; height:0 }
/* The tool wheel: a frosted disc with a hole, cut into a section a tool, the tool's pixel icon in each; the section under the pointer lights and its name reads beneath. */
.shop__wheel-disc{ position:absolute; left:-78px; top:-78px; width:156px; height:156px; border-radius:50%; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); box-shadow:var(--shadow-down); -webkit-mask-image:radial-gradient(circle, transparent 23px, #000 24px); mask-image:radial-gradient(circle, transparent 23px, #000 24px) }
.shop__wheel-svg{ position:absolute; left:-78px; top:-78px; overflow:visible }
.shop__wheel-sector{ fill:transparent; stroke:var(--rule); stroke-width:1 }
.shop__wheel-sector.is-hot{ fill:rgba(127,127,127,.28); stroke:var(--ink-3) }
.shop__wheel-item{ position:absolute; left:0; top:0; width:28px; height:28px; display:flex; align-items:center; justify-content:center; padding:0; border:0; background:none; color:var(--ink-2); cursor:pointer; pointer-events:none }
.shop__wheel-item svg{ display:block }
.shop__wheel-item--text{ width:auto; padding:0 6px; font-family:var(--mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; white-space:nowrap }
.shop__wheel-item[aria-selected="true"]{ color:var(--ink) }
.shop__wheel-label{ position:absolute; left:0; top:0; white-space:nowrap; padding:3px 8px; border:1px solid var(--rule); background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); font-family:var(--mono); font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink); pointer-events:none }
.shop__wheel-label:empty{ display:none }
.shop__panel{
  position:absolute; z-index:3; top:calc(var(--ruler,0px) + var(--meta,0px) + 12px); right:calc(12px + env(safe-area-inset-right,0px));
  width:236px; max-height:100%;   /* the grip may take it to the stage's bottom edge, and its left (Dom, 21 September 2026 — a margin under the default place kept it short of the bottom); the resize itself keeps it within the stage */
  display:flex; flex-direction:column;
  background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost);
  border:1px solid var(--rule); box-shadow:var(--shadow-down);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-2);
}
.shop__panel-head{ display:flex; align-items:center; gap:10px; padding:8px 10px; border-bottom:1px solid var(--rule); cursor:move; -webkit-user-select:none; user-select:none }   /* every panel moves by its head */
.shop__panel-head button, .shop__panel-head .shop__tab{ cursor:pointer }
.shop__panel-title{ color:var(--ink); margin-right:auto; letter-spacing:.16em }
.shop__panel-row{ display:flex; align-items:center; gap:10px; padding:7px 10px; border-bottom:1px solid var(--rule) }
.shop__blend{
  appearance:none; background:none; border:0; border-bottom:1px solid var(--rule-2); border-radius:0; padding:2px 0 3px; margin:0;
  font:inherit; letter-spacing:.06em; text-transform:none; color:var(--ink); flex:1; min-width:0; cursor:pointer;
}
.shop__blend:focus{ outline:none; border-bottom-color:var(--ink) }
.shop__blend option{ color:#1b1b1b; background:#fff; text-transform:none }
.shop__layers{ flex:1 1 auto; overflow:auto; min-height:0; overscroll-behavior:contain; position:relative }
/* Drag to arrange: the bar where the layer will land (indented for inside a group), a group's row lit for into it, a grabbing hand meanwhile. */
.shop__drop{ position:absolute; left:8px; right:8px; height:2px; background:var(--ink); pointer-events:none; z-index:2; box-shadow:0 0 0 1px rgba(0,0,0,.35) }
.shop__drop--in{ left:30px }
.shop__layer.is-drop{ box-shadow:inset 0 0 0 1.5px var(--ink) }
.shop__layers.is-arranging, .shop__layers.is-arranging .shop__layer, .shop__layers.is-arranging .shop__thumb{ cursor:grabbing }
.shop__layers.is-arranging .shop__layer{ -webkit-user-select:none; user-select:none }
.shop__layer .shop__thumb{ touch-action:none }   /* a finger holds a thumbnail to lift the row; the name still scrolls the list */
.shop__layers.is-carrying-mask .shop__layer.is-drop{ box-shadow:inset 0 0 0 1.5px var(--ink) }   /* its scroll never chains into a back swipe; it takes the room, so the foot stays at the bottom */
.shop__panel{ overscroll-behavior:none }
/* No text selection anywhere in the editor's chrome: a Shift-click or
   ⌘-click on a layer's name selects layers, and without this the
   browser was lighting the names as text instead (Dom, 19 September
   2026). Fields stay editable. */
html[data-shop-on] .lb, html[data-shop-on] .shop__panel, html[data-shop-on] .shop__options, html[data-shop-on] .shop__menu, html[data-shop-on] .shop__context{ -webkit-user-select:none; user-select:none }
html[data-shop-on] .lb input, html[data-shop-on] .lb textarea, html[data-shop-on] .lb [contenteditable]{ -webkit-user-select:text; user-select:text }
/* No grid in Domshop: the button goes with it (Dom, 19 September 2026). */
html[data-shop-on] #lb-grid{ display:none }
.shop__layer{
  display:flex; align-items:center; gap:10px; padding:6px 10px; cursor:default;
  border-bottom:1px solid var(--rule); color:var(--ink-2);
}
/* Selected rows: a bar at the left edge and a tint, so several selected
   layers read at a glance; the active one carries the full bar, the
   deepest tint and a bold name (Dom, 21 September 2026: "hard to see if
   not impossible to tell which layers are selected … still keeping the
   main selected layer highlighted as usual"). Greyscale, rule 1. */
.shop__layer[aria-selected="true"]{ color:var(--ink); background:rgba(127,127,127,.22); box-shadow:inset 4px 0 0 var(--ink-2) }
.shop__eye{ appearance:none; background:none; border:0; padding:0; margin:0; color:inherit; font:inherit; cursor:pointer; width:12px }
.shop__thumb{ width:var(--thumb,44px); height:var(--thumb,44px); flex:0 0 auto; background:rgba(127,127,127,.15); border:1px solid var(--rule); cursor:pointer }   /* --thumb: the panel's slider */
.shop__thumbsize{ margin-left:auto; width:64px; height:12px; accent-color:var(--ink-2); cursor:pointer }
.shop__link{ height:var(--thumb,44px) }
/* The one being painted — pixels or mask — is framed; a mask switched
   off is struck through. */
.shop__thumb[aria-selected="true"]{ border-color:var(--ink); box-shadow:0 0 0 1px var(--ink) }
.shop__thumb--mask[aria-disabled="true"]{ opacity:.55; background-image:linear-gradient(to top right,transparent 47%,var(--ink) 47%,var(--ink) 53%,transparent 53%) }
/* Photoshop's chain between a layer's two thumbnails: shown when the mask is linked, a click unlinks; the empty gap clicked links again. */
.shop__link{ appearance:none; background:none; border:0; padding:0; margin:0 -4px; width:16px; height:44px; display:inline-flex; align-items:center; justify-content:center; color:var(--ink-2); cursor:pointer; flex:none }
.shop__link svg{ display:block; transform:scale(.75) }
.shop__link[aria-pressed="false"] svg{ opacity:0 }
@media (hover:hover){ .shop__link:hover{ color:var(--ink) } .shop__link[aria-pressed="false"]:hover svg{ opacity:.35 } }
/* The panel's tabs — Layers and Channels — and its foot, Photoshop's
   row of layer actions. */
.shop__tabs{ gap:0 }
.shop__tab{ appearance:none; background:none; border:0; cursor:pointer; padding:0 12px 0 0; margin:0; font:inherit; letter-spacing:.16em; text-transform:inherit; color:var(--ink-3); opacity:.55 }
.shop__tab[aria-selected="true"]{ color:var(--ink); opacity:1 }
.shop__panel-tools{ display:inline-flex; gap:10px; margin-left:auto }
.shop__thumbsize + .shop__panel-tools{ margin-left:12px }   /* the slider takes the free space; the tools sit after it */
.shop__panel-foot{ margin-top:auto; flex:none; display:flex; align-items:center; justify-content:space-between; gap:8px; padding:6px 10px; border-top:1px solid var(--rule) }   /* locked to the panel's bottom (Dom, 19 September 2026) */
.shop__foot-act--phone{ display:none }   /* Dup, Up, Down, Merge: the head's on a desktop, the foot tray's on a phone */
.shop__foot-act{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:22px; color:var(--ink-2) }   /* Photoshop's row of icons; the bitmaps are 16 × 16 */
.shop__foot-act svg{ display:block }
.shop__foot-act[aria-pressed="true"]{ color:var(--ink); text-decoration:none }
.shop__foot-act[aria-disabled="true"]{ color:var(--ink-3); opacity:.55; cursor:default }
.shop__adjustmenu{ top:auto; z-index:30; min-width:220px; max-height:min(80vh, 720px) }
.shop__channels{ flex:1 1 auto; overflow:auto; min-height:0; overscroll-behavior:contain }
.shop__channel{ display:flex; align-items:center; gap:10px; padding:6px 10px; cursor:default; border-bottom:1px solid var(--rule); color:var(--ink-2) }
.shop__channel[aria-selected="true"]{ color:var(--ink); background:rgba(127,127,127,.12) }
/* Several layers selected: each lit; the active one a shade more. */
.shop__layer.is-active[aria-selected="true"]{ background:rgba(127,127,127,.38); box-shadow:inset 4px 0 0 var(--ink) }
.shop__layer.is-active[aria-selected="true"] .shop__name{ font-weight:600 }
/* ── Domshop's sheets, the transform box, the extra panels ──── */
/* A dialog is a sheet of glass over the stage, centred, dragged by
   its head; its fields are the panel's own controls. */
.shop__dialog{
  position:absolute; z-index:6; left:50%; top:50%; transform:translate(-50%,-50%); width:340px; max-width:calc(100% - 32px); max-height:calc(100% - 32px);
  display:flex; flex-direction:column; margin:0; padding:0; border:1px solid var(--rule); color:var(--ink-2);
  background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); box-shadow:var(--shadow-down);
  font-family:var(--mono); font-size:11px; letter-spacing:.06em;
}
.shop__dialog--wide{ width:520px }
.shop__dialog-head{ padding:8px 12px; border-bottom:1px solid var(--rule); color:var(--ink); letter-spacing:.16em; text-transform:uppercase; font-size:10.5px; cursor:move; -webkit-user-select:none; user-select:none }
.shop__dialog-body{ overflow:auto; min-height:0; padding:8px 12px; display:flex; flex-direction:column; gap:6px; overscroll-behavior:contain }
.shop__dialog-foot{ display:flex; align-items:center; gap:10px; padding:8px 12px; border-top:1px solid var(--rule) }
.shop__dialog-spacer{ flex:1 }
.shop__dialog-ok{ color:var(--ink) }
.shop__field{ display:flex; align-items:center; gap:8px; min-height:22px }
.shop__field-label{ flex:0 0 118px; color:var(--ink-3); letter-spacing:.1em; text-transform:uppercase; font-size:9.5px; line-height:1.2 }
.shop__dialog--wide .shop__field-label{ flex-basis:150px }
.shop__field input[type="range"]{ flex:1; min-width:60px; accent-color:var(--ink) }
.shop__field-num{ width:5ch; text-align:right }
.shop__field-text{ flex:1; min-width:0; text-align:left }
.shop__field-select{ flex:1; min-width:0 }
.shop__field-check{ padding:2px 0; color:var(--ink-2) }
.shop__dialog .shop__check{ color:var(--ink-2) }
.shop__field-chip{ width:22px; height:16px; border:1px solid var(--ink-3); cursor:pointer; padding:0 }
.shop__field-head{ margin-top:8px; padding-top:6px; border-top:1px solid var(--rule); color:var(--ink); letter-spacing:.14em; text-transform:uppercase; font-size:9.5px }
.shop__field-head:first-child{ margin-top:0; border-top:0; padding-top:0 }
.shop__field-note{ color:var(--ink-3); opacity:.75; font-size:10px; line-height:1.4; letter-spacing:.04em; text-transform:none }
.shop__kernel{ display:grid; grid-template-columns:repeat(5, 30px); gap:3px }
.shop__kernel input{ width:26px; text-align:center }
.shop__anchor{ display:grid; grid-template-columns:repeat(3, 24px); gap:2px }
.shop__anchor button{ appearance:none; width:24px; height:22px; border:1px solid var(--rule); background:none; color:var(--ink-3); opacity:.55; cursor:pointer; font:inherit }
.shop__anchor button[aria-pressed="true"]{ color:var(--ink); opacity:1; border-color:var(--ink) }
.shop__field--curves{ flex-direction:column; align-items:stretch }
/* The gradient editor in the Gradient Fill sheet: the bar with its stops, the chosen stop's fields under it. */
.shop__field--gradedit{ flex-direction:column; align-items:stretch }
.shop__gradedit{ display:flex; flex-direction:column; gap:8px }
.shop__gradtop{ display:flex; gap:8px; align-items:center }
.shop__gradbar{ display:block; width:320px; height:64px; touch-action:none; cursor:default; outline:none }
.shop__gradstop{ display:flex; flex-wrap:wrap; gap:6px 14px; align-items:center; min-height:22px }
.shop__gradstop .shop__field{ margin:0 }
.shop__gradstop .shop__field-label, .shop__field--gradedit > .shop__field-label{ flex-basis:auto }   /* the column field's label must not take the 118px row basis as a height; the stop's little fields keep their labels short */
.shop__gradstop .shop__chip{ position:static }
.shop__facts{ white-space:normal; line-height:1.55; font-variant-numeric:tabular-nums; max-width:420px }   /* the Singularity sheet's physics, wrapped */
.shop__perf{ border-collapse:collapse; font-variant-numeric:tabular-nums; margin-top:8px }   /* Help › Performance: the log's table */
.shop__perf th,.shop__perf td{ text-align:right; padding:3px 8px; border-bottom:1px solid var(--rule); font-weight:normal }
.shop__perf th:first-child,.shop__perf td:first-child{ text-align:left; text-transform:none; letter-spacing:.04em }
.shop__curves-tools{ display:flex; align-items:center; gap:4px; width:256px; align-self:center; margin-top:6px }   /* Photoshop's row under the curve: the targeted tool, the readout, the three eyedroppers (Dom, 21 September 2026) */
.shop__curves-readout{ flex:1 1 auto; font-size:11px; color:var(--ink-2); font-variant-numeric:tabular-nums; min-height:1em }
.shop__curves-eyes{ display:inline-flex; gap:2px }
.shop__curves-beneath{ width:256px; align-self:center; margin-top:2px }   /* which picture the row's tools sample: beneath the layer, or as displayed (Dom, 1 October 2026) */
.shop__curves-eye{ position:relative }
.shop__eye-chip{ position:absolute; right:1px; bottom:1px; width:6px; height:6px; border:1px solid var(--ink-3); box-sizing:border-box }
.lb__stage[data-hover="curve-target"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.5' fill='none' stroke='%23fff' stroke-width='3.5'/%3E%3Ccircle cx='12' cy='12' r='4.5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 1v5M12 18v5M9.5 3.5L12 1l2.5 2.5M9.5 20.5L12 23l2.5-2.5' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linejoin='round'/%3E%3Cpath d='M12 1v5M12 18v5M9.5 3.5L12 1l2.5 2.5M9.5 20.5L12 23l2.5-2.5' fill='none' stroke='%23000' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12, ns-resize }
.lb__stage[data-hover="dropper"] .stage{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M3 21l1-4 9-9 3 3-9 9z' fill='%23fff' stroke='%23000' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M13 8l2-2 3 3-2 2M15 4l5 5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") 3 21, crosshair }
.shop__curves{ width:256px; height:256px; align-self:center; border:1px solid var(--rule); background:rgba(127,127,127,.08); touch-action:none }
.shop__curves-ch{ align-self:flex-start }
/* The transform box: the quad drawn as an SVG polygon over the stage, eight handles, the centre point. */
.shop__xform{ position:absolute; inset:0; z-index:4; pointer-events:none }
.shop__xform-svg{ position:absolute; left:0; top:0; overflow:visible }
/* Two tones, Photoshop's: a dark halo under a white line, white handles ringed dark — legible on any ground (Dom, 20 September 2026). */
.shop__xform-svg polygon{ fill:none; stroke:#fff; stroke-width:1; vector-effect:non-scaling-stroke }
.shop__xform-svg .shop__xform-halo{ stroke:rgba(0,0,0,.62); stroke-width:3 }
.shop__xform-handle{ position:absolute; left:-5px; top:-5px; width:10px; height:10px; border:1px solid #000; background:#fff; box-shadow:0 0 0 1.5px rgba(0,0,0,.62); pointer-events:auto; touch-action:none; box-sizing:border-box }
.shop__xform-handle:hover{ background:#000; border-color:#fff }
.shop__xform-handle--nw, .shop__xform-handle--se{ cursor:nwse-resize } .shop__xform-handle--ne, .shop__xform-handle--sw{ cursor:nesw-resize }
.shop__xform-handle--n, .shop__xform-handle--s{ cursor:ns-resize } .shop__xform-handle--e, .shop__xform-handle--w{ cursor:ew-resize }
.shop__xform-centre{ position:absolute; left:-4px; top:-4px; width:8px; height:8px; border:1px solid #000; background:#fff; box-shadow:0 0 0 1.5px rgba(0,0,0,.62); border-radius:50%; box-sizing:border-box }
.shop__options:not([data-xf="on"]) .shop__opts--xform{ display:none }
.shop__xform-fields{ display:inline-flex; align-items:center; gap:12px; margin-right:6px }   /* Photoshop's transform bar: X Y W (linked) H, the angle, the skews */
.shop__xform-fields[hidden]{ display:none }
.shop__xf-link{ display:inline-flex; align-items:center; margin:0 -4px; color:var(--ink-3) } .shop__xf-link[aria-pressed="true"]{ color:var(--ink) } .shop__xf-link svg{ transform:scale(.75) }
.shop__xform-readout{ color:var(--ink); font-variant-numeric:tabular-nums }
/* The Navigator and Histogram panels, at the lower right above History's old place. */
.shop__navigator, .shop__histogram{ top:auto; bottom:calc(var(--gap) + 12px); width:236px }
.shop__histogram{ right:calc(12px + env(safe-area-inset-right,0px) + 250px) }
.shop__navigator-canvas, .shop__histogram-canvas{ display:block; width:220px; margin:8px; border:1px solid var(--rule) }
.shop__navigator-canvas{ cursor:crosshair; touch-action:none }
/* Edit › Search: a field and its hits, top centre. */
.shop__search{ position:absolute; z-index:7; left:50%; top:calc(var(--ruler,0px) + 24px); transform:translateX(-50%); width:360px; max-width:calc(100% - 32px); background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); box-shadow:var(--shadow-down) }
.shop__search-input{ width:100%; box-sizing:border-box; padding:10px 12px; border:0; border-bottom:1px solid var(--rule); background:none; color:var(--ink); font:inherit; font-family:var(--mono); font-size:12px; letter-spacing:.06em; outline:none }
.shop__search-item{ appearance:none; display:block; width:100%; text-align:left; padding:7px 12px; border:0; border-bottom:1px solid var(--rule); background:none; color:var(--ink-2); font:inherit; font-family:var(--mono); font-size:11px; letter-spacing:.06em; cursor:pointer }
.shop__search-item[aria-current="true"], .shop__search-item:hover{ color:var(--ink); background:rgba(127,127,127,.12) }
/* Groups fold, members indent, adjustment layers wear a glyph, badges for locks, links and styles. */
.shop__fold{ appearance:none; border:0; background:none; color:var(--ink-3); cursor:pointer; padding:0 2px; font:inherit; font-size:11px }
.shop__layer--member{ padding-left:22px }
/* Clipping masks in the panel, as Photoshop shows them: a clipped
   layer indented under a bent arrow, its base's name underlined; with
   Alt held over the line between two layers the clip cursor appears. */
.shop__layer--clip{ padding-left:20px }
.shop__layer--member.shop__layer--clip{ padding-left:42px }
.shop__layer--clip::before{ content:'↴'; position:absolute; left:6px; top:50%; transform:translateY(-55%); color:var(--ink-3); font-size:13px; line-height:1 }
.shop__layer--member.shop__layer--clip::before{ left:28px }
.shop__layer--base .shop__name{ text-decoration:underline; text-decoration-color:var(--ink-3); text-underline-offset:3px }
.shop__layers.is-clipline .shop__layer{ cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M8.5 4.5h11v11h-11z' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M4.5 8.5h11v11h-11z' fill='%23fff' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12 11v4l-2-1.5M12 15l2-1.5' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 4 8, alias }
.shop__thumb--adj{ background:rgba(127,127,127,.12) }
.shop__badge{ margin-left:auto; color:var(--ink-3); opacity:.7; font-size:9.5px; letter-spacing:.06em; padding-left:6px }
/* A smart object's filters under its row (20 September 2026): the
   stack's eye and the filter mask on a head row, then one row a
   filter, indented, the blending options at the right. */
.shop__sfrow{ display:flex; align-items:center; gap:8px; padding:3px 10px 3px 30px; color:var(--ink-2); border-bottom:1px solid var(--rule); cursor:default; position:relative }
.shop__sfrow--head{ padding-left:22px; gap:6px }
.shop__sfrow--head .shop__name{ color:var(--ink-3); opacity:.7; font-size:10.5px; letter-spacing:.06em }
.shop__sfrow .shop__thumb{ width:32px; height:32px }
.shop__sfrow.is-off .shop__name{ opacity:.45 }
.shop__sfrow .shop__eye{ font-size:10px }
.shop__fold--sf{ margin:0 -2px }
.shop__badge--sf{ margin-left:0; flex:0 0 auto }
.shop__sfblend{ appearance:none; background:none; border:0; padding:0 2px; margin-left:auto; color:var(--ink-3); font:inherit; font-size:12px; cursor:pointer; line-height:1 }
.shop__sfblend:hover{ color:var(--ink) }
.shop__badge + .shop__badge{ margin-left:0 }
/* The blend mode list: a window under its button; the mode under the pointer lit. */
.shop__blendpick{ text-align:left }
.shop__blendmenu{ top:auto; z-index:30; min-width:200px; max-height:min(70vh, 640px) }
.shop__blendmenu .shop__menu-item[aria-selected="true"]{ color:var(--ink) }
.shop__blendmenu .shop__menu-item[aria-selected="true"] span::before{ content:'✓ '; }
.shop__blendmenu .shop__menu-item.is-hover{ background:rgba(127,127,127,.16) }
.shop__menu-head{ padding:6px 14px 2px; color:var(--ink-3); opacity:.7; font-size:9.5px; letter-spacing:.14em; text-transform:uppercase }
/* The opacity slider window and the scrubby label. */
.shop__opacitymenu{ top:auto; z-index:30; width:236px; padding:12px 14px 10px; display:flex; align-items:center; gap:12px }
.shop__opacity-track{ position:relative; flex:1; height:18px; cursor:ew-resize; touch-action:none }
.shop__opacity-track::before{ content:''; position:absolute; left:0; right:0; top:8px; height:2px; background:var(--rule-2) }
.shop__opacity-fill{ position:absolute; left:0; top:8px; height:2px; background:var(--ink) }
.shop__opacity-knob{ position:absolute; top:3px; width:12px; height:12px; margin-left:-6px; border-radius:50%; background:var(--ink); pointer-events:none }
.shop__opacity-read{ min-width:4ch; text-align:right; color:var(--ink); font-variant-numeric:tabular-nums }
.shop__scrub{ cursor:ew-resize; -webkit-user-select:none; user-select:none }
.shop__opacity-pick{ appearance:none; background:none; border:0; padding:0 0 0 4px; margin:0; color:var(--ink-3); cursor:pointer; font:inherit; font-size:10px }
.shop__opacity-pick:hover{ color:var(--ink) }
.shop__cursor[data-off="true"]{ display:none !important }
html[data-shop-checker="off"] .shop__shadow{ background:none }
.shop__menu-item[aria-disabled="true"][title]{ cursor:help }
/* The History panel, under the Layers panel: one row per state, the
   current one lit, the ones ahead (undone) quiet. */
/* History sits at the lower left, inside the vertical ruler — Dom's
   call, 19 September 2026; the Layers panel keeps the right. */
.shop__history{ top:auto; bottom:calc(var(--gap) + 12px); right:auto; left:calc(var(--ruler,0px) + 12px + env(safe-area-inset-left,0px)); max-height:34%; width:236px }
.shop__history-count{ color:var(--ink-3); opacity:.7; font-size:9.5px }
.shop__states{ overflow:auto; min-height:0; overscroll-behavior:contain }
.shop__state{
  appearance:none; background:none; border:0; border-bottom:1px solid var(--rule); width:100%; text-align:left; cursor:pointer;
  padding:5px 10px; font:inherit; letter-spacing:.06em; text-transform:none; font-size:11px; color:var(--ink-2);
}
.shop__state[aria-current="true"]{ color:var(--ink); background:rgba(127,127,127,.12) }
.shop__state[data-ahead="true"]{ color:var(--ink-3); opacity:.5 }
.shop__state[data-parked="true"]::after{ content:"·"; float:right; opacity:.6 }   /* a state on disk (the pixel store's step three): a dot at the row's end, loaded when reached */
.shop__layer[data-paged] .shop__name::after{ content:" ·"; opacity:.6 }   /* a hidden layer whose pixels are on disk (the pixel store's step four): the same dot; back the moment it is shown or chosen */
@media (hover:hover){ .shop__state:hover{ color:var(--ink) } }
/* The grip in the panel's lower-left corner: drag to resize. */
.shop__grip{ position:absolute; left:0; bottom:0; width:14px; height:14px; cursor:nesw-resize; background:linear-gradient(to top right,transparent 40%,var(--ink-3) 40%,var(--ink-3) 50%,transparent 50%,transparent 70%,var(--ink-3) 70%,var(--ink-3) 80%,transparent 80%); opacity:.7; touch-action:none }   /* touch-action none: the panel scrolls vertically (pan-y), which took a finger's drag off the grip (Dom, 21 September 2026) */
@media (pointer:coarse){ .shop__grip{ width:30px; height:30px; background-size:14px 14px; background-repeat:no-repeat; background-position:left bottom } }   /* a thumb's target; the stripes stay in the corner */
.shop__panel-head,.shop__dialog-head,.shop__sliders-head{ touch-action:none }   /* the heads drag their windows: a finger's drag is theirs, not a scroll's */
.shop__panel{ resize:none }
.shop__layer{ position:relative }
.shop__name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-transform:none; letter-spacing:.04em; font-size:11px }
/* The name being renamed, in place (Dom, 20 September 2026). */
.shop__rename{ flex:1 1 auto; min-width:0; appearance:none; background:rgba(127,127,127,.18); border:1px solid var(--ink-3); border-radius:0; color:var(--ink); font:inherit; font-size:11px; letter-spacing:.04em; text-transform:none; padding:1px 4px; margin:-2px 0; outline:none }
@media (max-width:700px), (pointer:coarse) and (max-height:500px){ .shop__panel{ width:200px } }

/* ── PHONE: Domshop on a phone (Dom, 21 September 2026) ──────────
   "theres barely any canvas real estate": the twelve menu titles
   become one Menu button that pulls them down as a column, the
   name reads on one line, the tools sit on a tray with a handle a
   thumb pulls down to put away and up to bring back, and the ground
   slider hides behind one button that floats it over the picture.
   The same elements exist on a desktop, undisplayed. */
.shop__menutoggle,.shop__tray,.shop__tonebtn,.shop__undoredo{ display:none }
/* PHONE is narrow, or touch and short: a phone in either orientation — turned sideways it is 800 px wide and 375 tall, and
   width alone gave it the desktop's chrome (Dom, 21 September 2026). A tablet is neither, both ways round. The same
   query is `PHONE` in shop.js: keep the two the same. */
@media (max-width:760px), (pointer:coarse) and (max-height:500px){
  html[data-shop-on] .shop__menutoggle{ display:inline-block; color:var(--ink); flex:none }
  html[data-shop-on] .shop__undoredo{ display:inline-flex; gap:2px; flex:none }   /* undo and redo always in reach (Dom, 21 September 2026) */
  html[data-shop-on] .shop__undoredo .shop__ibtn{ color:var(--ink) }
  html[data-shop-on] .lb__bottom .shop__chips{ position:sticky; left:0; z-index:1; background:var(--glass); box-shadow:6px 0 8px -4px var(--glass) }   /* the swatches stay at the tray's left while the tools scroll by (Dom, 21 September 2026) */
  html[data-shop-on] .shop__menutoggle[aria-expanded="true"]{ text-decoration:underline; text-underline-offset:3px }
  html[data-shop-on] .shop__menubar{ display:none }
  html[data-shop-on] .shop__menubar.is-open{ display:flex; flex-direction:column; flex-wrap:nowrap; align-items:stretch; gap:0; position:absolute; left:0; right:0; top:100%; z-index:20; padding:4px var(--pad-l) 8px; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border-bottom:1px solid var(--rule); box-shadow:var(--shadow-down); max-height:calc(100vh - 60px); overflow:auto; overscroll-behavior:contain }
  html[data-shop-on] .shop__menubar.is-open .shop__menutitle{ text-align:left; padding:10px 0 }
  html[data-shop-on] .shop__menubar.has-menu .shop__menutitle:not([aria-expanded="true"]){ display:none }
  html[data-shop-on] .shop__menubar .shop__menu{ position:static; left:auto !important; top:auto !important; width:100%; min-width:0; max-height:none; box-shadow:none; border-left:0; border-right:0; background:none; -webkit-backdrop-filter:none; backdrop-filter:none }
  html[data-shop-on] .shop__menubar .shop__submenu{ position:absolute; left:var(--pad-l) !important; right:var(--pad-l); top:auto !important; bottom:8px; width:auto; max-height:50vh; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); box-shadow:var(--shadow-down) }
  html[data-shop-on] .shop__menu-item{ padding-block:9px }
  html[data-shop-on] .shop__thumbsize{ display:none }   /* no thumbnail slider on a phone (Dom, 21 September 2026) */
  html[data-shop-on] .shop__thumbsize + .shop__panel-tools{ margin-left:0 }
  /* the Layers panel on a phone (Dom, 21 September 2026): Dup ↑ ↓ Merge as icons on the foot, which scrolls as a tray; one tab shown, with a ▾ — a tap or a hold switches to the other */
  html[data-shop-on] .shop__panel-tools[data-for="layers"]{ display:none }
  html[data-shop-on] .shop__foot-act--phone{ display:inline-flex }
  html[data-shop-on] .shop__panel-foot{ justify-content:flex-start; flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; gap:4px; touch-action:pan-x }
  html[data-shop-on] .shop__panel-foot::-webkit-scrollbar{ display:none }
  html[data-shop-on] .shop__panel-foot .shop__foot-act{ flex:none; width:30px; height:28px }
  html[data-shop-on] .shop__tab[aria-selected="false"]{ display:none }
  html[data-shop-on] .shop__tab[aria-selected="true"]::after{ content:' ▾'; opacity:.6 }
  html[data-shop-on] .shop__panel-head{ min-height:36px }
  html[data-shop-on] .shop__menubar .shop__submenu--inline{ position:static; left:auto !important; right:auto; bottom:auto; width:100%; max-height:none; padding:0 0 4px; border:0; border-bottom:1px solid var(--rule); box-shadow:none; background:none; -webkit-backdrop-filter:none; backdrop-filter:none }   /* a submenu unfolds below its item, full width, no indent (Dom, 21 September 2026) */
  html[data-shop-on] .shop__menu-item[aria-expanded="true"]{ color:var(--ink) }
  html[data-shop-on] .lb__top{ position:relative; gap:8px 10px }
  html[data-shop-on] .lb__info{ flex:1 1 auto; min-width:0; flex-wrap:nowrap; gap:0 8px; overflow:hidden; justify-content:flex-start }
  html[data-shop-on] #lb-id{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
  html[data-shop-on] .lb__pixel{ display:none }
  /* the tray */
  html[data-shop-on] .lb__bottom{ position:relative; flex-wrap:nowrap; gap:0 10px; padding-top:16px; overflow:visible }
  html[data-shop-on] .lb__bottom .shop__bar{ flex:1 1 auto; min-width:0; flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; padding-bottom:2px; touch-action:pan-x }
  html[data-shop-on] .lb__bottom .shop__bar::-webkit-scrollbar{ display:none }
  html[data-shop-on] .shop__tray{ display:block; position:absolute; left:50%; top:0; transform:translateX(-50%); width:64px; height:16px; margin:0; padding:0; border:0; background:none; cursor:grab; touch-action:none }
  html[data-shop-on] .shop__tray::before{ content:''; position:absolute; left:16px; right:16px; top:5px; height:4px; border-radius:2px; background:var(--ink-3); opacity:.7 }
  html[data-shop-on] .lb__bottom[data-tray="closed"]{ padding-block:14px calc(2px + env(safe-area-inset-bottom,0px)) }
  html[data-shop-on] .lb__bottom[data-tray="closed"] > :not(.shop__tray){ display:none !important }
  html[data-shop-on] .shop__tonebtn{ display:inline-flex; flex:none; font-size:15px; width:26px; height:24px }
  /* the ground control: in the bar it is hidden; floated, it sits over the picture above the bar */
  html[data-shop-on] .lb__bottom .tone--lb{ display:none }
  html[data-shop-on] .lb__stage .tone--lb.is-open{ display:flex; flex-wrap:wrap; position:absolute; right:10px; bottom:10px; left:10px; z-index:8; padding:10px 12px; gap:8px 14px; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); border-radius:6px; box-shadow:var(--shadow-up); font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-2) }
}

/* Blend If, in the Blending Options sheet: two double sliders whose
   halves pull apart. The ramp under the track is the factor itself —
   full height where the layer shows, nothing where it is hidden. */
.shop__field--blendif { display: grid; gap: 6px; }
.shop__bi-row { display: grid; grid-template-columns: 8.5em 1fr 6.5em; align-items: center; gap: 8px; }
.shop__bi-label { font-size: 11px; letter-spacing: .04em; opacity: .75; }
.shop__bi-track { position: relative; height: 26px; border: 1px solid var(--ink-4); border-radius: 3px; background: linear-gradient(90deg, #000, #fff); touch-action: none; }
.shop__bi-ramp { position: absolute; inset: 0; background: var(--ink); opacity: .18; pointer-events: none; }
.shop__bi-stop { position: absolute; top: -4px; width: 11px; height: 34px; margin-left: -5.5px; padding: 0; border: 1px solid var(--ink); border-radius: 2px; background: var(--glass-solid, #808080); cursor: ew-resize; }
.shop__bi-stop[data-stop="0"], .shop__bi-stop[data-stop="1"] { background: #111; }
.shop__bi-stop[data-stop="2"], .shop__bi-stop[data-stop="3"] { background: #eee; }
.shop__bi-stop[data-stop="1"], .shop__bi-stop[data-stop="2"] { top: -4px; height: 17px; }
.shop__bi-stop[data-stop="0"], .shop__bi-stop[data-stop="3"] { top: 13px; height: 17px; }
.shop__bi-stop[data-holding] { outline: 2px solid var(--ink); }
.shop__bi-read { font-size: 11px; opacity: .7; text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 760px) { .shop__bi-row { grid-template-columns: 1fr; } .shop__bi-stop { width: 22px; margin-left: -11px; } }

/* The Layer Style window: Photoshop's list down the left, the chosen
   row's controls beside it. The list is empty until an effect is
   added from the fx menu at its foot. */
.shop__dialog:has(.shop__dialog-body--aside) { width: min(760px, calc(100vw - 32px)); max-width: none; }
.shop__dialog-body--aside { display: grid; grid-template-columns: minmax(150px, 190px) minmax(0, 1fr); gap: 14px; align-items: start; }
.shop__dialog-aside { position: sticky; top: 0; }
.shop__dialog-main { min-width: 0; display: grid; gap: 8px; align-content: start; }
.shop__dialog-main[data-empty="true"]::before { content: 'Nothing to set here'; opacity: .5; font-size: 12px; }
.shop__ls { display: flex; flex-direction: column; gap: 6px; }
.shop__ls-rows { display: flex; flex-direction: column; border: 1px solid var(--ink-4); border-radius: 3px; overflow: hidden; }
.shop__ls-row { appearance: none; border: 0; background: none; color: inherit; font: inherit; text-align: left; padding: 5px 8px; cursor: pointer; }
.shop__ls-row:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.shop__ls-row[aria-current="true"] { background: color-mix(in srgb, var(--ink) 16%, transparent); font-weight: 600; }
.shop__ls-fx { display: flex; align-items: center; gap: 6px; padding-left: 8px; border-top: 1px solid color-mix(in srgb, var(--ink) 12%, transparent); }
.shop__ls-fx .shop__ls-row { flex: 1; padding-left: 0; }
.shop__ls-foot { display: flex; gap: 4px; align-items: center; }
.shop__ls-foot .lb__act { padding: 3px 7px; min-width: 0; }
.shop__ls-add { font-variant: small-caps; letter-spacing: .06em; }
.shop__ls-foot svg { width: 14px; height: 14px; }
.shop__check.is-na { opacity: .45; cursor: not-allowed; }
@media (max-width: 760px) { .shop__dialog-body--aside { grid-template-columns: 1fr; } .shop__dialog-aside { position: static; } }

/* The loading disc (Dom, 23 September 2026: a window for "when any loading
   occurs" — a circle that "fills radially" with progress up to 100%. A pizza
   of eight slices came first and was not what he meant.) Greyscale like every
   other surface: rule 1 keeps colour for the photographs. */
.shop__loading { position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); z-index:14; display:flex; flex-direction:column; align-items:center; gap:9px; padding:18px 26px 15px; background:var(--glass); -webkit-backdrop-filter:var(--frost); backdrop-filter:var(--frost); border:1px solid var(--rule); box-shadow:var(--shadow-down); border-radius:6px; color:var(--ink); font-family:var(--mono); pointer-events:none }
.shop__disc { width:88px; height:88px; display:block; color:var(--ink) }
.shop__disc-ring { fill:none; stroke:currentColor; stroke-width:2.5; opacity:.32 }
.shop__disc-fill { fill:currentColor; fill-opacity:.62 }
.shop__disc-tick { fill:none; stroke:currentColor; stroke-width:3; stroke-linecap:round; opacity:.75 }
.shop__loading-t { font-size:11px; letter-spacing:.09em; max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.shop__loading-p { font-size:10px; letter-spacing:.14em; text-transform:uppercase; opacity:.62; font-variant-numeric:tabular-nums; min-height:1.2em }

/* The file's own composite, shown while its layers decode (see "The picture
   first" in shop.js). Over the stage, under the loading window, and inert —
   it is a picture, never a document. */
.shop__preview { position:absolute; inset:0; z-index:13; display:flex; align-items:center; justify-content:center; pointer-events:none }
.shop__preview-box { display:flex; flex-direction:column; align-items:flex-start; max-width:100%; max-height:100% }
.shop__preview-box > .lb__meta { position:static; transform:none; will-change:auto; color:var(--ink) }   /* the same stack the document gets, stacked above the picture rather than placed by drawCanvas */
.shop__preview canvas { display:block; box-shadow:var(--shadow-down) }
/* While the preview is up it **is** the canvas: the document being replaced,
   its grid, rulers, shadow, ants and its own stack of facts all stand down, or
   the last document shows around the new one (Dom, 23 September 2026).
   `visibility`, not `display` — the geometry is still measured from them. */
html[data-shop-preview] #lb-stage .lb__grid,
html[data-shop-preview] #lb-stage .lb__ruler,
html[data-shop-preview] #lb-stage .frame,
html[data-shop-preview] #lb-stage .shop__vp,
html[data-shop-preview] #lb-stage .shop__shadow,
html[data-shop-preview] #lb-stage .shop__ants,
html[data-shop-preview] #lb-stage > .lb__meta { visibility:hidden }
.shop__loading-n { font-size:10px; letter-spacing:.1em; opacity:.45; min-height:0; font-style:italic }

/* A panel in a window of its own (step 4 of the shell, 25 September 2026): it
   fills that window, so the stage's anchoring, the glass and the shadow all
   stand down — there is nothing behind it to frost, and its own window's title
   bar is what moves it now. */
/* **It keeps every surface it has on the stage** (Dom, 25 September 2026: "can
   we make the floating layers panel look exactly like the one we had in the
   window with glass effect and all"). The first cut took the glass, the border,
   the radius and the shadow away, reasoning that a `backdrop-filter` in a
   window of its own has nothing behind it to blur — true, and the wrong
   conclusion: the answer is to put the **ground** behind it, which is what the
   stage shows under a panel that is not over the picture. So only the place and
   the size are overridden here, and the glass, the frost, the grain, the rule
   and the shadow all come from `.shop__panel` itself and cannot drift from it.
   The inset is what lets the border and the shadow read against that ground. */
.shop__panel[data-popped], .shop__history[data-popped]{
  position:absolute; inset:10px; width:auto; height:auto; max-height:none;
}
.shop__panel[data-popped] .shop__panel-head{ cursor:default }
.shop__panel[data-popped] .shop__grip{ display:none }
