/* zg-ui.css: the shared chrome of Shapesynth, Paint and Porcelanato (contract: scratch_bake/ui/ZG_UI_DESIGN.md).
   One look: Archivo, electric blue on white, 2 px rules, no radii; six regions in the same places on every page (brand bar, tool rail,
   side panel, stage, status strip, toast) in four modes that zg-ui.js sets on <html data-zg-mode>: wide (desktop and iPad landscape),
   mid (iPad portrait: the panel is a bottom sheet), narrow (phone portrait: a bottom sheet and a tool strip above it), short (phone
   landscape: a tool strip on top and a side column). Pages add only what they alone need in their own <style>; nothing in this file names
   a page element. Without the data-zg-mode attribute (before zg-ui.js ran) the rules below lay out as wide. */

/* ---- 2a colour ---- */
:root {
  --bg: #ffffff; --ink: #0033ff; --cut: #00ff00; --cut-ink: var(--ink); --stage: #e9edfb;
  --panel: color-mix(in srgb, var(--bg) 90%, transparent);
  --soft: color-mix(in srgb, var(--ink) 12%, transparent);
  --faint: color-mix(in srgb, var(--ink) 6%, transparent);
  --hair: color-mix(in srgb, var(--ink) 30%, transparent);
  --ink-2: color-mix(in srgb, var(--ink) 65%, var(--bg));
  --ink-3: color-mix(in srgb, var(--ink) 40%, var(--bg));
  --scrim: color-mix(in srgb, var(--bg) 70%, transparent);
  color-scheme: light;
  /* 2b type */
  --font: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --t-hero: 30px; --t-title: 16px; --t-h2: 12px; --t-lab: 11px; --t-btn: 12px; --t-body: 13px; --t-num: 13px; --t-rail: 9px; --t-key: 9px; --t-micro: 10px;
  /* 2c space, size, shape */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;
  --gut: clamp(16px, 2vw, 24px); --rule: 2px; --radius: 0px; --blur: 8px;
  --tap: 44px; --tap-fine: 32px; --ic: 22px;
  --rail-w: calc(2 * var(--tap) + 3 * var(--rule));
  --strip-h: calc(var(--tap) + 14px);
  --panel-w: 336px; --dock-h: clamp(220px, 34vh, 380px); --brand-h: 56px; --bar-h: 36px; --grab-h: 0px; --sheet-h: 0px; --kbd: 0px;
  --ease: 160ms;
  --safe-t: env(safe-area-inset-top, 0px); --safe-r: env(safe-area-inset-right, 0px); --safe-b: env(safe-area-inset-bottom, 0px); --safe-l: env(safe-area-inset-left, 0px);
  --field-cols: minmax(96px, 36%) 1fr 56px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --bg: #0a1680; --ink: #ffffff; --cut: #00ff00; --cut-ink: var(--bg); --stage: #050d5c; color-scheme: dark; }
}
:root[data-theme="dark"] { --bg: #0a1680; --ink: #ffffff; --cut: #00ff00; --cut-ink: var(--bg); --stage: #050d5c; color-scheme: dark; }
html.no-cut { --cut-ink: var(--bg); }
/* Safari before 16.2 has no color-mix: the seven derived tokens as literals (porcelain's ci.js writes the same inline per theme) */
@supports not (color: color-mix(in srgb, red, blue)) {
  :root { --panel: rgba(255, 255, 255, .9); --soft: rgba(0, 51, 255, .12); --faint: rgba(0, 51, 255, .06); --hair: rgba(0, 51, 255, .3); --ink-2: #597aff; --ink-3: #99adff; --scrim: rgba(255, 255, 255, .7); }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) { --panel: rgba(10, 22, 128, .9); --soft: rgba(255, 255, 255, .12); --faint: rgba(255, 255, 255, .06); --hair: rgba(255, 255, 255, .3); --ink-2: #a9add3; --ink-3: #6c73b3; --scrim: rgba(10, 22, 128, .7); }
  }
  :root[data-theme="dark"] { --panel: rgba(10, 22, 128, .9); --soft: rgba(255, 255, 255, .12); --faint: rgba(255, 255, 255, .06); --hair: rgba(255, 255, 255, .3); --ink-2: #a9add3; --ink-3: #6c73b3; --scrim: rgba(10, 22, 128, .7); }
}
@media (min-width: 1440px) { :root { --panel-w: 360px; } }
@media (any-pointer: coarse) { :root { --tap-fine: 44px; --bar-h: 44px; } }
/* translucency is a wide thing: a blur over a live WebGL canvas costs frames on phones and touch tablets */
@media (max-width: 699px), ((any-pointer: coarse) and (max-width: 1023px)) { :root { --blur: 0px; --panel: var(--bg); } }
@media (prefers-reduced-motion: reduce) { :root { --ease: 0ms; } }
html[data-zg-mode="mid"] { --grab-h: 20px; --field-cols: 1fr 56px; }
html[data-zg-mode="narrow"] { --grab-h: 20px; --brand-h: 44px; --field-cols: 1fr 56px; }
html[data-zg-mode="short"] { --brand-h: 0px; --panel-w: min(50vw, 336px); }

/* ---- base ---- */
html, body { height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; }
body { background: var(--bg); color: var(--ink); font-family: var(--font); font-size: var(--t-body); line-height: 1.45; -webkit-text-size-adjust: 100%; }
a { color: inherit; text-decoration: none; }
[hidden] { display: none !important; }
.zg-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
summary { list-style: none; } summary::-webkit-details-marker { display: none; }
kbd, output, .zg-num, .zg-status__read, dd, #readout { font-variant-numeric: tabular-nums; }
kbd { font-family: inherit; }
button, select, input, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
:focus-visible { outline: 2px solid var(--cut); outline-offset: 2px; }
html.no-cut :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; box-shadow: 0 0 0 1px var(--bg); }
.zg-ic { display: block; flex: none; width: var(--ic); height: var(--ic); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
/* one tap, no callout, no double-tap zoom on the chrome; labels, sub-heads and metas are not prose either (a mouse drag in the sheet highlighted them) */
.zg-tool, .zg-btn, .zg-tab, .zg-status, .zg-gl, .zg-step, .zg-x, .zg-keys, .zg-rail__fold, .zg-panel__fold, .zg-sec > summary, .zg-check, .zg-base button, .zg-link {
  -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; touch-action: manipulation; }
.zg-field > label, .zg-sub, .zg-sec__meta { user-select: none; -webkit-user-select: none; }
.zg-brand, .zg-rail, .zg-panel, .zg-box, .zg-fly, .zg-status, .zg-toast, .zg-overlay, .zg-dialog { box-sizing: border-box; }
.zg-brand *, .zg-rail *, .zg-panel *, .zg-box *, .zg-fly *, .zg-status *, .zg-toast *, .zg-overlay *, .zg-dialog * { box-sizing: border-box; }

/* ---- type ---- */
.zg-lab, .zg-field > label, .zg-sub, dt, .zg-brand__kicker, .zg-note.zg-note--lab { font-size: var(--t-lab); line-height: 1.2; letter-spacing: .2em; text-transform: uppercase; font-weight: 400; }
.zg-sub { margin: var(--sp-2) 0 0; color: var(--ink-2); display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); }
.zg-sub small { font-size: var(--t-lab); letter-spacing: .1em; text-transform: none; color: var(--ink-2); }
.zg-note { margin: 0; color: var(--ink-2); font-size: var(--t-body); line-height: 1.45; }
.zg-note a, .zg-warn a { color: inherit; text-decoration: underline; }
.zg-num, output { font-size: var(--t-num); line-height: 1.2; }
h2.zg-h2, .zg-sec > summary h2, .zg-overlay__bar h2, .zg-dialog__box > header h3 { margin: 0; font-size: var(--t-h2); line-height: 1; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; }
.zg-hero { font-size: var(--t-hero); line-height: 1; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; margin: 0; }
html[data-zg-mode="narrow"] .zg-hero { font-size: 24px; }

/* ---- controls ---- */
.zg-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: var(--tap-fine); padding: 0 var(--sp-3); position: relative;
  border: var(--rule) solid currentColor; border-radius: var(--radius); background: var(--bg); color: var(--ink); cursor: pointer;
  font-size: var(--t-btn); line-height: 1; letter-spacing: .1em; text-transform: uppercase; text-align: center; text-decoration: none; }
.zg-btn.on, .zg-tool.on, .zg-tab.on { background: var(--ink); color: var(--bg); }
.zg-btn.primary { background: var(--cut); border-color: var(--cut); color: var(--cut-ink); }
.zg-btn.danger { border-style: dashed; }
.zg-btn:disabled, .zg-tool:disabled, .zg-step:disabled, .zg-link:disabled { opacity: .3; pointer-events: none; }
.zg-btn--ic { min-width: var(--tap); min-height: var(--tap); padding: 0 var(--sp-2); gap: var(--sp-1); }
.zg-btn--ic .zg-lab { font-size: var(--t-btn); letter-spacing: .1em; }
@media (hover: hover) and (pointer: fine) {
  .zg-btn:not(.on):not(.primary):not(:disabled):hover, .zg-tool:not(.on):not(:disabled):hover, .zg-tab:not(.on):hover, .zg-step:hover, .zg-x:hover, .zg-keys:hover, .zg-rail__fold:hover, .zg-panel__fold:hover, .zg-status__cancel:hover, .zg-base button:hover, .zg-sec > summary:hover { background: var(--soft); }
  .zg-btn.primary:hover { background: var(--ink); border-color: var(--ink); color: var(--bg); }
}
.zg-btn:not(.on):active, .zg-tool:not(.on):active, .zg-tab:not(.on):active, .zg-step:active, .zg-x:active, .zg-keys:active, .zg-rail__fold:active, .zg-panel__fold:active, .zg-status__cancel:active, .zg-base button:active, .zg-sec > summary:active { background: var(--soft); }
.zg-btns { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.zg-btns > .zg-btn { flex: 1 0 auto; }
/* key badges: top-right of the cell, shown with a hovering pointer or once a key was pressed (html.zg-kbd) */
.zg-key { display: none; position: absolute; top: 2px; right: 3px; margin: 0; font-size: var(--t-key); line-height: 1; font-weight: 700; letter-spacing: 0; text-transform: none; color: var(--ink-2); pointer-events: none; }
.on > .zg-key, .primary > .zg-key { color: var(--ink-3); }
.zg-btn:not(.zg-btn--ic) > .zg-key { position: static; margin-left: var(--sp-1); }
.zg-keys > .zg-key { top: 4px; right: 2px; }
@media (hover: hover) { .zg-key { display: inline-block; } }
html.zg-kbd .zg-key { display: inline-block; }
/* label / control / value grid (56 px fits "-150.0"); the label stacks above the control in the sheet modes (--field-cols: 1fr 56px). The label column is 36 %
   (109–118 px of a 336/360 px panel: "sun around", "scan detail" and "thin below mm" fit on one line); a longer label ("preview smooth", "spray boxes max") wraps
   to a second line inside the 44 px row instead of ending in an ellipsis, and only a single word too long for the column is still cut */
.zg-field { display: grid; grid-template-columns: var(--field-cols); align-items: center; column-gap: var(--sp-2); row-gap: 0; min-height: var(--tap); }
.zg-field > label { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: normal; }
html[data-zg-mode="mid"] .zg-field > label, html[data-zg-mode="narrow"] .zg-field > label { grid-column: 1 / -1; padding-top: var(--sp-1); }
/* a field with −/+ step buttons stacks its label in every mode: on one row the label, two 44 px buttons and the value left the range 34–51 px of a 336/360 px
   panel (6–23 px of thumb travel for a 300 mm span); stacked it gets 132–156 px */
.zg-field:has(> .zg-step) { grid-template-columns: var(--tap) 1fr var(--tap) 56px; }
.zg-field:has(> .zg-step) > label { grid-column: 1 / -1; padding-top: var(--sp-1); }
.zg-field > output, .zg-field > .zg-num, .zg-field > input[type=number] { text-align: right; font-size: var(--t-num); font-variant-numeric: tabular-nums; }
.zg-field > .zg-note, .zg-field > span.zg-hint { font-size: var(--t-lab); color: var(--ink-2); text-align: right; letter-spacing: .05em; }
.zg-field > output { overflow-wrap: anywhere; }
.zg-field > select, .zg-field > input[type=text], .zg-field > input[type=password], .zg-field > input[type=file], .zg-field > .zg-btns, .zg-field > .zg-check, .zg-field > textarea { grid-column: 2 / -1; }
html[data-zg-mode="mid"] .zg-field > select, html[data-zg-mode="narrow"] .zg-field > select, html[data-zg-mode="mid"] .zg-field > input[type=text], html[data-zg-mode="narrow"] .zg-field > input[type=text], html[data-zg-mode="mid"] .zg-field > input[type=password], html[data-zg-mode="narrow"] .zg-field > input[type=password], html[data-zg-mode="mid"] .zg-field > input[type=file], html[data-zg-mode="narrow"] .zg-field > input[type=file], html[data-zg-mode="mid"] .zg-field > .zg-btns, html[data-zg-mode="narrow"] .zg-field > .zg-btns, html[data-zg-mode="mid"] .zg-field > textarea, html[data-zg-mode="narrow"] .zg-field > textarea { grid-column: 1 / -1; }
.zg-field > select ~ span:empty, .zg-field > input[type=text] ~ span:empty, .zg-field > input[type=password] ~ span:empty, .zg-field > output ~ span:empty, .zg-field > input[type=file] ~ span:empty { display: none; }
.zg-field > input[type=text] ~ .zg-note, .zg-field > select ~ .zg-note, .zg-field > input[type=password] ~ .zg-note { display: none; }
/* a number input (not the twin of a range) sits in the value column, its note beside it; stacked: note left, number right on the second row */
.zg-field > input[type=number]:not(.num) { grid-column: -2 / -1; }
.zg-field > input[type=number]:not(.num) ~ .zg-note { grid-column: 2; grid-row: 1; text-align: left; }
html[data-zg-mode="mid"] .zg-field > input[type=number]:not(.num) ~ .zg-note, html[data-zg-mode="narrow"] .zg-field > input[type=number]:not(.num) ~ .zg-note { grid-column: 1; grid-row: 2; }
.zg-field > output { grid-column: -2 / -1; }
select, input[type=number], input[type=text], input[type=password], input[type=search], input[type=url], input[type=email], input[type=tel], textarea {
  width: 100%; min-height: var(--tap-fine); margin: 0; padding: 0 var(--sp-2); border: var(--rule) solid currentColor; border-radius: var(--radius); background: var(--bg); color: var(--ink); box-sizing: border-box; }
select { font-size: var(--t-btn); letter-spacing: .1em; text-transform: uppercase; cursor: pointer; padding-right: 28px; -webkit-appearance: none; appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%); background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%; background-size: 5px 5px; background-repeat: no-repeat; }
select option { text-transform: none; letter-spacing: 0; }
input[type=number] { text-align: right; font-size: var(--t-num); font-variant-numeric: tabular-nums; -moz-appearance: textfield; appearance: textfield; }
input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
textarea { padding: var(--sp-2); line-height: 1.45; resize: vertical; }
input::placeholder, textarea::placeholder { color: var(--ink-3); opacity: 1; }
input[type=file] { border: 0; padding: 0; min-height: var(--tap-fine); font-size: var(--t-lab); }
input[type=file]::file-selector-button { font: inherit; color: inherit; background: var(--bg); border: var(--rule) solid currentColor; min-height: var(--tap-fine); padding: 0 var(--sp-3); letter-spacing: .1em; text-transform: uppercase; margin-right: var(--sp-2); cursor: pointer; }
input[type=range] { accent-color: var(--ink); }
.zg-field input[type=range], .zg-panel input[type=range], .zg-box input[type=range] { -webkit-appearance: none; appearance: none; width: 100%; height: var(--tap); margin: 0; padding: 0; background: none; touch-action: pan-y; cursor: pointer; }
.zg-field input[type=range]::-webkit-slider-runnable-track, .zg-panel input[type=range]::-webkit-slider-runnable-track, .zg-box input[type=range]::-webkit-slider-runnable-track { height: var(--rule); background: linear-gradient(currentColor, currentColor) 11.5px 0 / calc(100% - 23px) 100% no-repeat; }
.zg-field input[type=range]::-moz-range-track, .zg-panel input[type=range]::-moz-range-track, .zg-box input[type=range]::-moz-range-track { height: var(--rule); background: linear-gradient(currentColor, currentColor) 11.5px 0 / calc(100% - 23px) 100% no-repeat; }
/* the line is drawn from the thumb's centre at the minimum to its centre at the maximum (11.5 px in from each end), so 0 sits on the line's start.
   the thumb: a 3 px bar drawn as a centred gradient in a 23 px wide box to touch (the 44 px tall input and zg-ui's fine drag do the rest); no border and
   no shadow, which iOS Safari otherwise draws round it. Its colour is --zg-thumb (the cut colour while focused). 28 px tall for fingers; with a mouse
   (hover and a fine pointer) it is the height of a letter, 12 px */
.zg-field input[type=range]::-webkit-slider-thumb, .zg-panel input[type=range]::-webkit-slider-thumb, .zg-box input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; box-sizing: border-box; width: 23px; height: 28px; margin-top: -13px; border: 0; border-radius: 0; box-shadow: none; -webkit-filter: none; filter: none;
  background: linear-gradient(var(--zg-thumb, var(--ink)), var(--zg-thumb, var(--ink))) center / 3px 100% no-repeat; }
.zg-field input[type=range]::-moz-range-thumb, .zg-panel input[type=range]::-moz-range-thumb, .zg-box input[type=range]::-moz-range-thumb { box-sizing: border-box; width: 23px; height: 28px; border: 0; border-radius: 0; box-shadow: none; background: linear-gradient(var(--zg-thumb, var(--ink)), var(--zg-thumb, var(--ink))) center / 3px 100% no-repeat; }
.zg-field input[type=range], .zg-panel input[type=range], .zg-box input[type=range] { -webkit-tap-highlight-color: transparent; }
.zg-field input[type=range]:focus-visible, .zg-panel input[type=range]:focus-visible, .zg-box input[type=range]:focus-visible { --zg-thumb: var(--cut); }
@media (hover: hover) and (pointer: fine) {
  .zg-field input[type=range]::-webkit-slider-thumb, .zg-panel input[type=range]::-webkit-slider-thumb, .zg-box input[type=range]::-webkit-slider-thumb { height: 12px; margin-top: -5px; }
  .zg-field input[type=range]::-moz-range-thumb, .zg-panel input[type=range]::-moz-range-thumb, .zg-box input[type=range]::-moz-range-thumb { height: 12px; }
}
.zg-field input[type=range]:focus-visible, .zg-panel input[type=range]:focus-visible, .zg-box input[type=range]:focus-visible { outline: none; }
.zg-step { width: var(--tap); height: var(--tap); padding: 0; border: var(--rule) solid currentColor; background: var(--bg); color: inherit; display: grid; place-items: center; cursor: pointer; position: relative; }
.zg-seg { display: flex; }
.zg-seg > .zg-btn { flex: 1 1 0; margin-left: calc(-1 * var(--rule)); }
.zg-seg > .zg-btn:first-child { margin-left: 0; }
.zg-check { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); cursor: pointer; color: var(--ink); font-size: var(--t-btn); letter-spacing: .1em; text-transform: uppercase; position: relative; }
.zg-check input[type=checkbox] { width: 20px; height: 20px; margin: 0; flex: none; accent-color: var(--ink); cursor: pointer; }
.zg-check .zg-ic { margin-right: var(--sp-1); }
.zg-secret input { border-style: dashed; }
.zg-x { width: var(--tap); height: var(--tap); padding: 0; border: 0; background: none; color: inherit; display: grid; place-items: center; cursor: pointer; font-size: 20px; line-height: 1; flex: none; }
.zg-x .zg-ic + * { display: none; }
.zg-link { border: 0; padding: 0; margin: 0; background: none; color: inherit; font: inherit; text-decoration: underline; cursor: pointer; display: inline-flex; align-items: center; gap: var(--sp-1); min-height: var(--tap-fine); }
.zg-warn { color: var(--ink); }
.zg-warn:not(:empty):not(.zg-status) { background: var(--cut); color: var(--cut-ink); padding: var(--sp-2) var(--sp-3); }
.zg-status.zg-warn { background: var(--cut); color: var(--cut-ink); }
html.no-cut .zg-status.zg-warn, html.no-cut .zg-warn:not(:empty):not(.zg-status) { background: var(--ink); color: var(--bg); }

/* ---- brand bar ---- */
.zg-brand { position: fixed; z-index: 11; left: 0; top: 0; max-width: calc(100% - var(--panel-w) - 2 * var(--gut)); height: calc(var(--brand-h) + var(--safe-t)); padding: var(--safe-t) max(var(--gut), var(--safe-r)) 0 max(var(--gut), var(--safe-l));
  display: flex; align-items: center; gap: var(--sp-3); pointer-events: none; white-space: nowrap; }
.zg-logo { display: block; flex: none; width: 98px; height: 18px; padding-block: 13px; box-sizing: content-box; background: currentColor; pointer-events: auto;
  -webkit-mask: url(zeitguised.svg) no-repeat center / contain; mask: url(zeitguised.svg) no-repeat center / contain; }
.zg-brand__name { font-size: var(--t-title); line-height: 1; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; }
.zg-brand__kicker { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; min-width: 0; }
html[data-zg-mode="narrow"] .zg-brand, html[data-zg-mode="mid"] .zg-brand { max-width: 100%; }   /* the panel is a bottom sheet there: nothing sits to the brand bar's right */
html[data-zg-mode="narrow"] .zg-brand__kicker { display: none; }
html[data-zg-mode="short"] .zg-brand { display: none; }

/* ---- tool rail: a 2-column grid of 44 px cells per group, group words hanging above; wide and mid ---- */
.zg-rail { position: fixed; z-index: 10; left: calc(var(--gut) + var(--safe-l)); top: calc(var(--brand-h) + var(--safe-t) + var(--sp-2)); width: var(--rail-w);
  max-height: max(calc(100vh - var(--brand-h) - var(--safe-t) - var(--sp-2) - var(--grab-h) - var(--bar-h) - var(--safe-b) - var(--sheet-h, 0px) - var(--sp-2)), calc(2 * var(--tap)));
  max-height: max(calc(100dvh - var(--brand-h) - var(--safe-t) - var(--sp-2) - var(--grab-h) - var(--bar-h) - var(--safe-b) - var(--sheet-h, 0px) - var(--sp-2)), calc(2 * var(--tap)));
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; scrollbar-width: none; }
.zg-rail::-webkit-scrollbar { display: none; }
.zg-rail[data-scroll="top"] { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 12px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 12px), transparent); }
.zg-rail[data-scroll="bottom"] { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12px); mask-image: linear-gradient(to bottom, transparent, #000 12px); }
.zg-rail[data-scroll="mid"] { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12px, #000 calc(100% - 12px), transparent); mask-image: linear-gradient(to bottom, transparent, #000 12px, #000 calc(100% - 12px), transparent); }
.zg-grp { position: relative; display: grid; grid-template-columns: repeat(2, var(--tap)); gap: var(--rule); margin-top: 13px; background: var(--hair); border: var(--rule) solid currentColor; flex: none; }
.zg-rail .zg-grp:not(:has(.zg-tool:not([hidden]))) { display: none; } /* a group whose cells are all hidden (porcelanato's focaccia without a focaccia) is not drawn empty */
.zg-gl { position: absolute; left: 0; bottom: 100%; padding-bottom: 4px; font-size: var(--t-rail); line-height: 1; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2); white-space: nowrap; pointer-events: none; }
.zg-grp__sub { display: contents; }
/* a group folds on its name (zg-ui: data-closed); a cell with options (data-fly) shows a corner mark; its flyout sits beside the rail */
.zg-rail .zg-gl { pointer-events: auto; cursor: pointer; }
.zg-rail .zg-gl::after { content: " ▾"; }
.zg-grp[data-closed] > :not(.zg-gl) { display: none; }
.zg-grp[data-closed] { border-width: var(--rule) 0 0; min-width: calc(2 * var(--tap)); background: none; }
.zg-grp[data-closed] > .zg-gl::after { content: " ▸"; }
.zg-has-fly::after { content: ""; position: absolute; right: 2px; bottom: 2px; width: 0; height: 0; border-style: solid; border-width: 0 0 7px 7px; border-color: transparent transparent currentColor transparent; opacity: .7; pointer-events: none; }
.zg-has-fly[data-fly-open] { outline: var(--rule) solid var(--cut); outline-offset: -2px; }
.zg-fly { position: fixed; z-index: 30; width: 340px; max-width: calc(100vw - 16px); max-height: calc(100dvh - 16px); overflow-y: auto; overscroll-behavior: contain; padding: 0 var(--sp-4) var(--sp-4);
  background: var(--panel); -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur)); border: var(--rule) solid currentColor; color: var(--ink); display: grid; gap: var(--sp-2); align-content: start; }
.zg-fly[hidden] { display: none; }
.zg-fly > .zg-x { position: absolute; top: 0; right: 0; }
.zg-fly > .zg-sub:nth-child(2) { margin: 0; min-height: var(--tap); display: flex; align-items: center; padding-right: var(--tap); }
.zg-fly input[type=range] { -webkit-appearance: none; appearance: none; width: 100%; height: var(--tap); margin: 0; padding: 0; background: none; touch-action: pan-y; cursor: pointer; }
html[data-zg-mode="narrow"] .zg-fly, html[data-zg-mode="short"] .zg-fly { width: auto; max-height: 60dvh; }
.zg-tool { position: relative; width: var(--tap); height: var(--tap); padding: 0; margin: 0; border: 0; border-radius: var(--radius); background: var(--panel); color: var(--ink); cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; }
.zg-tool .zg-lab { max-width: 100%; padding: 0 1px; font-size: var(--t-rail); line-height: 1; letter-spacing: .04em; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zg-rail__fold { width: var(--tap); height: var(--tap); padding: 0; border: var(--rule) solid currentColor; background: var(--panel); color: inherit; display: grid; place-items: center; cursor: pointer; position: relative; flex: none; }
.zg-rail__fold .zg-ic { transform: rotate(90deg); transition: transform var(--ease); }
.zg-rail[data-folded] .zg-rail__fold .zg-ic { transform: rotate(-90deg); }
.zg-rail[data-folded] > :not(.zg-rail__fold) { display: none; }
.zg-rail[data-folded] { width: var(--tap); max-height: none; overflow: visible; }
/* touch: the rail hangs from the bottom-left, the first group in the DOM (history) lowest, nearest the thumbs */
@media (any-pointer: coarse) {
  html[data-zg-mode="wide"] .zg-rail, html:not([data-zg-mode]) .zg-rail { top: auto; bottom: calc(var(--grab-h) + var(--bar-h) + var(--safe-b) + var(--sheet-h, 0px) + var(--sp-2)); flex-direction: column-reverse; }
}
html[data-zg-mode="mid"] .zg-rail { top: auto; bottom: calc(var(--grab-h) + var(--bar-h) + var(--safe-b) + var(--sheet-h, 0px) + var(--sp-2)); flex-direction: column-reverse; transition: bottom var(--ease); }
html[data-zg-mode="mid"] .zg-panel[data-sheet="full"] ~ .zg-rail, html[data-zg-mode="narrow"] .zg-panel[data-sheet="full"] ~ .zg-rail, html[data-zg-sheet="full"][data-zg-mode="mid"] .zg-rail, html[data-zg-sheet="full"][data-zg-mode="narrow"] .zg-rail { visibility: hidden; }
/* the horizontal strip: narrow (bottom, above the status strip) and short (top) */
html[data-zg-mode="narrow"] .zg-rail, html[data-zg-mode="short"] .zg-rail { left: 0; right: 0; top: auto; width: auto; height: var(--strip-h); max-height: none; flex-direction: row; align-items: flex-end; gap: var(--sp-3);
  overflow-x: auto; overflow-y: hidden; scroll-snap-type: x proximity; touch-action: pan-x; padding-inline: max(var(--safe-l), 16px) max(var(--safe-r), 16px); scroll-padding-inline: max(var(--safe-l), 16px) max(var(--safe-r), 16px);   /* the snapport matches the padding: with scroll-padding 0 the first group snapped to the edge (scrollLeft 16) and sat in the notch and Safari's back-swipe zone */
  -webkit-mask-image: none; mask-image: none; background: var(--panel); -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur)); }
html[data-zg-mode="narrow"] .zg-rail { bottom: calc(var(--sheet-h) + var(--grab-h) + var(--bar-h) + var(--safe-b)); transition: bottom var(--ease); }
html[data-zg-mode="short"] .zg-rail { top: var(--safe-t); }
html[data-zg-mode="narrow"] .zg-rail__fold, html[data-zg-mode="short"] .zg-rail__fold { display: none; }
html[data-zg-mode="narrow"] .zg-grp, html[data-zg-mode="short"] .zg-grp { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: var(--tap); margin-top: 10px; scroll-snap-align: start; }
html[data-zg-mode="narrow"] .zg-gl, html[data-zg-mode="short"] .zg-gl { padding-bottom: 1px; }
html[data-zg-mode="narrow"] .zg-grp[aria-label="history" i], html[data-zg-mode="short"] .zg-grp[aria-label="history" i] { order: 99; position: sticky; right: 0; margin-left: auto; background: var(--panel); box-shadow: -8px 0 0 var(--panel); }
html[data-zg-mode="narrow"] .zg-grp[aria-label="history" i] .zg-tool, html[data-zg-mode="short"] .zg-grp[aria-label="history" i] .zg-tool { background: var(--bg); }
/* history is first in the DOM, so the hanging words of the groups scrolled under it would paint over its own word: it gets a z-index, and its word the panel
   background across the group's width plus the 8 px shadow to its left */
html[data-zg-mode="narrow"] .zg-grp[aria-label="history" i], html[data-zg-mode="short"] .zg-grp[aria-label="history" i] { z-index: 1; }
html[data-zg-mode="narrow"] .zg-grp[aria-label="history" i] .zg-gl, html[data-zg-mode="short"] .zg-grp[aria-label="history" i] .zg-gl { left: calc(-1 * var(--sp-2)); right: 0; padding-left: var(--sp-2); background: var(--panel); }
/* the group sticks at the strip's content edge, so the cells scrolled under it came out again in the 16 px (or safe-inset) padding to its right: a pseudo-element
   in the group's own stacking context covers that padding, from the words' row down to the group's bottom border */
html[data-zg-mode="narrow"] .zg-grp[aria-label="history" i]::after, html[data-zg-mode="short"] .zg-grp[aria-label="history" i]::after { content: ""; position: absolute; left: calc(100% + var(--rule)); top: calc(-10px - var(--rule)); bottom: calc(-1 * var(--rule)); width: max(var(--safe-r), 16px); background: var(--panel); }

/* ---- side panel: wide ---- */
.zg-panel { position: fixed; z-index: 10; right: calc(var(--gut) + var(--safe-r)); top: calc(var(--gut) + var(--safe-t)); bottom: calc(var(--bar-h) + var(--safe-b) + var(--gut)); width: var(--panel-w);
  display: flex; flex-direction: column; background: var(--panel); -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur)); border: var(--rule) solid currentColor; overflow: hidden; }
.zg-panel__fold { position: absolute; z-index: 2; right: 0; top: 0; width: var(--tap); height: var(--tap); padding: 0; border: 0; background: none; color: inherit; display: grid; place-items: center; cursor: pointer; }
/* folded: nothing of the panel's own box is left to paint (its two 2 px borders drew a full-height line beside the fold tab); the fold tab, fixed at the right
   edge, is the one visible child */
.zg-panel[data-folded] { width: 0; min-width: 0; border-width: 0; border-color: transparent; background: none; -webkit-backdrop-filter: none; backdrop-filter: none; overflow: visible; visibility: hidden; }
.zg-panel[data-folded] > :not(.zg-panel__fold) { display: none !important; }
.zg-panel[data-folded] .zg-panel__fold { position: fixed; right: var(--safe-r); top: calc(var(--gut) + var(--safe-t)); background: var(--panel); border: var(--rule) solid currentColor; border-right: 0; visibility: visible; }
.zg-panel__tabs { display: none; flex: none; }
.zg-panel__head { flex: none; padding: var(--sp-3) var(--sp-4) var(--sp-2); display: grid; gap: var(--sp-1); border-bottom: var(--rule) solid currentColor; }
/* the head on every tool page (10 Oct 2026, porcelanato's order): kicker, the title, a show line. .zg-titlepick is the title: a hero line with
   an invisible select laid over it (a picker: porcelanato's versions, Paint's pieces; a caret with .multi), or an input styled as the title
   (Shapesynth's project name). In the sheet modes a page moves its head to the top of the scroll area, so it scrolls with the sections */
.zg-panel__head .zg-lab { color: var(--ink-2); }
html[data-zg-mode="wide"] .zg-panel > .zg-panel__head > :first-child, html:not([data-zg-mode]) .zg-panel > .zg-panel__head > :first-child { padding-right: var(--tap); }
.zg-panel__scroll > .zg-panel__head { padding-inline: 0; margin-bottom: var(--sp-2); }
.zg-titlepick { position: relative; display: flex; align-items: baseline; gap: 6px; min-width: 0; margin: var(--sp-1) 0; }
.zg-titlepick > .zg-hero { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 1; }
.zg-titlepick__caret { display: none; color: var(--ink); font-size: 18px; line-height: 1; }
.zg-titlepick.multi > .zg-titlepick__caret { display: block; }
.zg-titlepick > select { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; font-size: 16px; }
.zg-titlepick > select:disabled { display: none; }
.zg-titlepick.multi:hover > .zg-hero, .zg-titlepick.multi:focus-within > .zg-hero { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
input.zg-hero { font-family: inherit; color: inherit; background: none; border: 0; border-bottom: var(--rule) solid transparent; border-radius: 0; padding: 0 0 2px; width: 100%; min-width: 0; }
input.zg-hero:hover, input.zg-hero:focus { border-bottom-color: currentColor; outline: none; }
input.zg-hero::placeholder { color: var(--ink-3); opacity: 1; }
.zg-panel .zg-panel__head .zg-hero { font-size: var(--t-title); }   /* the head's title, the same small size on every page (it fits its line below that, down to 12 px); porcelanato's clean phone caption keeps the hero size */
html[data-zg-mode="wide"] .zg-panel > .zg-panel__head > .zg-titlepick, html:not([data-zg-mode]) .zg-panel > .zg-panel__head > .zg-titlepick { padding-right: var(--tap); }   /* the title (its caret, the end of a long name) clears the fold tab too */
.zg-panel__scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; padding: 0 var(--sp-4) calc(var(--safe-b) + var(--kbd)); scrollbar-width: none; }
.zg-panel__scroll::-webkit-scrollbar { display: none; } /* no bar to run into while dragging a slider; wheel, trackpad and touch scroll it */
/* wide: the fold tab owns a 44 px band above the scroll area (a margin, not padding: padding scrolls with the content), so a section head or button row scrolled
   to the top never sits under the tab; a panel with a head (porcelain) clears the tab inside the head instead */
html[data-zg-mode="wide"] .zg-panel:not(:has(> .zg-panel__head)) > .zg-panel__scroll, html:not([data-zg-mode]) .zg-panel:not(:has(> .zg-panel__head)) > .zg-panel__scroll { margin-top: var(--tap); }
.zg-panel__foot { flex: none; border-top: var(--rule) solid currentColor; padding: 0 var(--sp-4); }
.zg-panel__foot:empty { display: none; }
.zg-sec { border-top: var(--rule) solid currentColor; }
.zg-sec:first-child { border-top: 0; }
.zg-sec > summary { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); padding: 0; cursor: pointer; position: relative; margin: 0 calc(-1 * var(--sp-2)); padding: 0 var(--sp-2); }
.zg-sec > summary h2 { flex: none; }
.zg-sec__meta { flex: 1 1 auto; min-width: 0; text-align: right; font-size: var(--t-lab); line-height: 1.2; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.zg-sec__meta:empty { flex: 1; }
.zg-sec__chev { transform: rotate(-90deg); transition: transform var(--ease); color: var(--ink-2); }
.zg-sec[open] > summary .zg-sec__chev { transform: none; }
.zg-sec__body { display: grid; gap: var(--sp-2); padding: 0 0 var(--sp-4); align-content: start; }
.zg-sec__body > .zg-sub:first-child { margin-top: 0; }
.zg-panel__scroll > .zg-sec:first-child > summary { padding-top: var(--sp-1); }
.zg-panel__scroll > .zg-sec:first-child { margin-top: 0; }

/* ---- side panel: the bottom sheet of mid and narrow ---- */
html[data-zg-mode="mid"] .zg-panel, html[data-zg-mode="narrow"] .zg-panel { left: 0; right: 0; top: auto; bottom: 0; width: auto; height: var(--sheet-h); border: 0; transition: height var(--ease); }
html[data-zg-mode="mid"] .zg-panel__fold, html[data-zg-mode="narrow"] .zg-panel__fold, html[data-zg-mode="short"] .zg-panel__fold { display: none; }
html[data-zg-mode="mid"] .zg-panel__tabs, html[data-zg-mode="narrow"] .zg-panel__tabs { display: flex; height: var(--tap); border-bottom: var(--rule) solid currentColor; touch-action: none; padding-inline: max(var(--safe-l), var(--sp-2)) max(var(--safe-r), var(--sp-2)); overflow: hidden; }
html[data-zg-mode="mid"] .zg-panel__scroll, html[data-zg-mode="narrow"] .zg-panel__scroll { padding-inline: max(var(--gut), var(--safe-l)) max(var(--gut), var(--safe-r)); }
html[data-zg-mode="mid"] .zg-sec > summary, html[data-zg-mode="narrow"] .zg-sec > summary, html[data-zg-mode="short"] .zg-sec > summary { display: none; }
html[data-zg-mode="mid"] .zg-sec, html[data-zg-mode="narrow"] .zg-sec, html[data-zg-mode="short"] .zg-sec { border-top: 0; }
html[data-zg-mode="mid"] .zg-sec__body, html[data-zg-mode="narrow"] .zg-sec__body, html[data-zg-mode="short"] .zg-sec__body { padding-top: var(--sp-2); }
html[data-zg-mode="mid"] .zg-panel__foot, html[data-zg-mode="narrow"] .zg-panel__foot, html[data-zg-mode="short"] .zg-panel__foot { display: none; }
.zg-tab { flex: 0 0 auto; min-width: var(--tap); height: var(--tap); padding: 0 var(--sp-2); border: 0; background: none; color: inherit; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); position: relative; font-size: var(--t-btn); letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }
.zg-tab__word { line-height: 1; }
.zg-tab__meta { font-size: var(--t-lab); letter-spacing: .05em; color: var(--ink-2); text-transform: none; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.zg-tab.on .zg-tab__meta { color: var(--ink-3); }
.zg-tab__meta:empty { display: none; }
/* mid: every tab at its picto and word plus an equal share of the slack, so the active tab's meta rides in the slack (an equal split gave seven Shapesynth
   tabs 115 px at 820 px and cut "2 / 4" to "2 …"); the inactive tabs never shrink, their words stay whole, and when the row is tight the active tab gives
   way first and its meta ellipsises */
html[data-zg-mode="mid"] .zg-tab { flex: 1 0 auto; min-width: 0; }
html[data-zg-mode="mid"] .zg-tab.on { flex: 1 1 auto; overflow: hidden; }
html[data-zg-mode="mid"] .zg-tab__word { flex: none; }
html[data-zg-mode="mid"] .zg-tab__meta { display: none; }
html[data-zg-mode="mid"] .zg-tab.on .zg-tab__meta { display: inline; flex: 0 1 auto; }
html[data-zg-mode="narrow"] .zg-tab { width: var(--tap); padding: 0; }
html[data-zg-mode="narrow"] .zg-tab:not(.on) .zg-tab__word, html[data-zg-mode="narrow"] .zg-tab:not(.on) .zg-tab__meta { display: none; }
html[data-zg-mode="narrow"] .zg-tab.on { width: auto; flex: 1 1 auto; min-width: var(--tap); padding: 0 var(--sp-2); overflow: hidden; }
html[data-zg-mode="narrow"] .zg-tab.on .zg-tab__word { flex: none; }
html[data-zg-mode="narrow"] .zg-tab.on .zg-tab__meta { flex: 0 1 auto; }

/* ---- side panel: the short column (phone landscape) ---- */
html[data-zg-mode="short"] .zg-panel { left: auto; right: 0; top: calc(var(--safe-t) + var(--strip-h)); bottom: calc(var(--bar-h) + var(--safe-b)); width: var(--panel-w); border: 0; border-left: var(--rule) solid currentColor;
  display: grid; grid-template-columns: var(--tap) 1fr; grid-template-rows: 1fr; }
html[data-zg-mode="short"] .zg-panel__tabs { display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; border-right: var(--rule) solid currentColor; touch-action: pan-y; scrollbar-width: none; }
html[data-zg-mode="short"] .zg-panel__tabs::-webkit-scrollbar { display: none; }
html[data-zg-mode="short"] .zg-tab { width: var(--tap); height: auto; flex: 1 1 var(--tap); min-height: 36px; max-height: var(--tap); padding: 0; }   /* seven 44 px tabs are 308 px, the column 267–296: they shrink to fit (≥ 36 px) rather than scroll with no cue */
html[data-zg-mode="short"] .zg-tab__word, html[data-zg-mode="short"] .zg-tab__meta { display: none; }
html[data-zg-mode="short"] .zg-panel__head { grid-column: 2; }
html[data-zg-mode="short"] .zg-panel__scroll { grid-column: 2; min-width: 0; padding-inline: var(--sp-3) max(var(--sp-3), var(--safe-r)); }   /* min-width: a grid item's min-content (a wide select) must not widen the 1fr track past the panel */
html[data-zg-mode="short"] .zg-panel:has(.zg-panel__head) { grid-template-rows: auto 1fr; }
html[data-zg-mode="short"] .zg-panel:has(.zg-panel__head) .zg-panel__tabs { grid-row: 1 / 3; }
html[data-zg-mode="short"] .zg-panel[data-folded] { display: none; }

/* ---- status strip: the text row, plus the sheet's grab row in the sheet modes; rides on the sheet's top edge ---- */
.zg-status { position: fixed; z-index: 12; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; background: var(--panel); -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur));
  border-top: var(--rule) solid currentColor; padding: 0 max(var(--gut), var(--safe-r)) var(--safe-b) max(var(--gut), var(--safe-l)); transition: bottom var(--ease); }
html[data-zg-mode="mid"] .zg-status, html[data-zg-mode="narrow"] .zg-status { bottom: var(--sheet-h); }
.zg-status__grab { display: none; height: var(--grab-h); align-items: center; justify-content: center; touch-action: none; cursor: grab; flex: none; }
.zg-status__grab::before { content: ""; width: 36px; height: 4px; background: currentColor; }
html[data-zg-mode="mid"] .zg-status__grab, html[data-zg-mode="narrow"] .zg-status__grab { display: flex; }
.zg-status__row { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--bar-h); }
.zg-status__hint { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--t-btn); line-height: 1; letter-spacing: .1em; text-transform: uppercase; cursor: default; }
/* the readout keeps its own width up to half the row (40 % in short, where the logo sits in the row too) and the hint takes the loss: the hint has its tap-to-toast,
   the numbers have nothing else. One block with inline spans, not an inline-flex row: text-overflow only works on a block's own line, so the spans (Shapesynth's
   three) or a bare text (Paint) end in one ellipsis instead of being cut mid-word; the middle dots are the spans' ::before */
.zg-status__read { flex: 0 0 auto; max-width: 50%; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--t-num); line-height: 1.2; color: var(--ink-2); }
.zg-status__read > span:empty { display: none; }
.zg-status__read > span + span:not(:empty)::before { content: "·"; margin: 0 var(--sp-2); }
html[data-zg-mode="short"] .zg-status__read { max-width: 40%; }
.zg-status__cancel { height: var(--bar-h); min-height: var(--bar-h); padding: 0 var(--sp-2) 0 var(--sp-1); border: var(--rule) solid currentColor; background: var(--bg); color: inherit; display: inline-flex; align-items: center; gap: var(--sp-1); cursor: pointer; font-size: var(--t-btn); letter-spacing: .1em; text-transform: uppercase; flex: none; }
.zg-keys, .zg-status__btn { width: var(--tap); height: var(--bar-h); padding: 0; border: 0; background: none; color: inherit; display: grid; place-items: center; cursor: pointer; position: relative; flex: none; margin-right: calc(-1 * var(--sp-2)); }
.zg-status__btn { margin-right: 0; }
.zg-status .zg-logo { display: none; margin-left: calc(-1 * var(--sp-2)); width: 76px; height: 14px; padding-block: calc((var(--bar-h) - 14px) / 2); }
html[data-zg-mode="short"] .zg-status .zg-logo { display: block; }
html[data-zg-mode="short"] .zg-status { cursor: pointer; }
/* narrow: the readout lives in the active tab's meta; zg-ui.js sets data-zg-read on the strip while the tabs are out of sight (sheet collapsed) or the tab has
   no room beside its word (seven Shapesynth tabs), and the strip shows it again */
html[data-zg-mode="narrow"] .zg-status:not([data-zg-read]) .zg-status__read { display: none; }

/* ---- toast: events only, bottom-left over the stage ---- */
.zg-toast { position: fixed; z-index: 30; left: calc(var(--gut) + var(--safe-l)); bottom: calc(var(--bar-h) + var(--grab-h) + var(--safe-b) + var(--sheet-h) + var(--sp-3)); max-width: min(480px, calc(100% - 2 * var(--gut)));
  background: var(--panel); -webkit-backdrop-filter: blur(var(--blur)); backdrop-filter: blur(var(--blur)); border: var(--rule) solid currentColor; padding: var(--sp-2) var(--sp-3); font-size: var(--t-body); line-height: 1.45;
  display: flex; align-items: flex-start; gap: var(--sp-2); transition: bottom var(--ease); }
.zg-toast > .zg-x { margin: calc(-1 * var(--sp-2)) calc(-1 * var(--sp-3)) calc(-1 * var(--sp-2)) 0; }
.zg-toast > .zg-x[hidden] { display: none !important; }
.zg-toast .zg-btn { min-height: var(--tap-fine); }
html[data-zg-mode="narrow"] .zg-toast:not(.zg-toast--centre) { bottom: calc(var(--bar-h) + var(--grab-h) + var(--safe-b) + var(--sheet-h) + var(--strip-h) + var(--sp-3)); }
/* where the rail hangs from the bottom-left (mid, and wide under a coarse pointer) the toast sat over its lowest cells (history, the fold cell): it moves past the
   rail, past the 44 px stub when the rail is folded (the rail precedes the toast in the markup); at full the rail is hidden and the toast keeps the gutter */
html[data-zg-mode="mid"] .zg-toast:not(.zg-toast--centre) { left: calc(var(--gut) + var(--safe-l) + var(--rail-w) + var(--sp-3)); max-width: min(480px, calc(100% - 2 * var(--gut) - var(--safe-l) - var(--rail-w) - var(--sp-3))); }
html[data-zg-mode="mid"] .zg-rail[data-folded] ~ .zg-toast:not(.zg-toast--centre) { left: calc(var(--gut) + var(--safe-l) + var(--tap) + var(--sp-3)); max-width: min(480px, calc(100% - 2 * var(--gut) - var(--safe-l) - var(--tap) - var(--sp-3))); }
html[data-zg-mode="mid"][data-zg-sheet="full"] .zg-toast:not(.zg-toast--centre) { left: calc(var(--gut) + var(--safe-l)); max-width: min(480px, calc(100% - 2 * var(--gut))); }
@media (any-pointer: coarse) {
  html[data-zg-mode="wide"] .zg-toast:not(.zg-toast--centre) { left: calc(var(--gut) + var(--safe-l) + var(--rail-w) + var(--sp-3)); max-width: min(480px, calc(100% - 2 * var(--gut) - var(--safe-l) - var(--rail-w) - var(--sp-3))); }
  html[data-zg-mode="wide"] .zg-rail[data-folded] ~ .zg-toast:not(.zg-toast--centre) { left: calc(var(--gut) + var(--safe-l) + var(--tap) + var(--sp-3)); max-width: min(480px, calc(100% - 2 * var(--gut) - var(--safe-l) - var(--tap) - var(--sp-3))); }
}
/* at full the sheet covers the stage and the formula above would lift the toast off the top of the screen: it stays at the bottom-left of the viewport,
   above the home indicator and the on-screen keyboard (--kbd) */
html[data-zg-sheet="full"] .zg-toast:not(.zg-toast--centre) { bottom: calc(var(--safe-b) + var(--kbd) + var(--sp-3)); }
.zg-toast--centre { left: 50%; bottom: 50%; transform: translate(-50%, 50%); }

/* ---- overlays (full screen: bar, body, cap) and dialogs (scrim and box) ---- */
.zg-overlay { position: fixed; z-index: 40; inset: 0; background: var(--bg); color: var(--ink); display: flex; flex-direction: column; }
.zg-overlay__bar { flex: none; display: flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); padding: var(--safe-t) max(var(--gut), var(--safe-r)) 0 max(var(--gut), var(--safe-l)); border-bottom: var(--rule) solid currentColor; }
.zg-overlay__bar h2, .zg-overlay__bar .ttl { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zg-overlay__bar .zg-x { margin-right: calc(-1 * var(--sp-2)); }
.zg-overlay__bar .zg-btn { flex: none; white-space: nowrap; }   /* a bar button ("Download SVG") keeps one line on a phone; the title beside it is what shrinks */
.zg-overlay__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; padding: var(--sp-4) max(var(--gut), var(--safe-r)) var(--sp-4) max(var(--gut), var(--safe-l)); }
.zg-overlay__cap { flex: none; display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) max(var(--gut), var(--safe-r)) calc(var(--sp-2) + var(--safe-b)) max(var(--gut), var(--safe-l)); border-top: var(--rule) solid currentColor; }
.zg-dialog { position: fixed; z-index: 50; inset: 0; background: var(--scrim); display: grid; place-items: center; padding: calc(16px + var(--safe-t)) max(16px, var(--safe-r)) calc(16px + var(--safe-b)) max(16px, var(--safe-l)); touch-action: none; }
.zg-dialog__box { background: var(--bg); color: var(--ink); border: var(--rule) solid currentColor; width: min(1040px, 100%); max-height: 100%; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; display: grid; gap: var(--sp-3); padding: var(--sp-4); align-content: start; }
.zg-dialog__box > header { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); margin: calc(-1 * var(--sp-2)) 0 0; }
.zg-dialog__box > header > h3, .zg-dialog__box > header > h2 { flex: 1 1 auto; min-width: 0; }
.zg-dialog__box > header .zg-x { margin-right: calc(-1 * var(--sp-2)); }
html[data-zg-mode="narrow"] .zg-dialog, html[data-zg-mode="short"] .zg-dialog { padding: 0; background: var(--bg); place-items: stretch; }
html[data-zg-mode="narrow"] .zg-dialog__box, html[data-zg-mode="short"] .zg-dialog__box { width: 100%; height: 100%; max-height: none; border: 0; padding: 0 max(var(--gut), var(--safe-r)) calc(var(--sp-4) + var(--safe-b)) max(var(--gut), var(--safe-l)); }
html[data-zg-mode="narrow"] .zg-dialog__box > header, html[data-zg-mode="short"] .zg-dialog__box > header { position: sticky; top: 0; z-index: 1; margin: 0 calc(-1 * max(var(--gut), var(--safe-r))) var(--sp-2) calc(-1 * max(var(--gut), var(--safe-l))); padding: var(--safe-t) max(var(--gut), var(--safe-r)) 0 max(var(--gut), var(--safe-l)); background: var(--bg); border-bottom: var(--rule) solid currentColor; }
/* the key map: above the dialogs (50), so ? answers from inside a dialog too and Esc closes the map first, then the dialog */
.zg-keymap { z-index: 55; }
.zg-keymap__grp { margin: 0 0 var(--sp-4); }
.zg-keymap__grp h3 { margin: 0 0 var(--sp-1); }
.zg-keymap__row { display: grid; grid-template-columns: var(--ic) 1fr auto; align-items: center; gap: var(--sp-3); min-height: 32px; border-top: 1px solid var(--hair); }
.zg-keymap__row:first-of-type { border-top: 0; }
.zg-keymap__row kbd { font-weight: 700; font-size: var(--t-btn); letter-spacing: 0; white-space: nowrap; }
.zg-keymap__row .zg-ic { opacity: .8; }
.zg-keymap__row > span { min-width: 0; }
.zg-keymap__grp:last-child .zg-keymap__row { grid-template-columns: 1fr auto; }

/* ---- base folder bar (zg-folder.js mounts into .zg-base): one 44 px line, the label ellipsised, the one button that fixes it. A grid, not a flex row: the label
   sits in a minmax(0, 1fr) column and the button (and the ⓘ link) in auto columns, so the bar's min-content is the button alone and it never widens the
   Project section, where the foot's children live in the sheet modes and short ---- */
.zg-base { display: grid; grid-template-columns: minmax(0, 1fr); grid-auto-flow: column; grid-auto-columns: auto; align-items: center; gap: var(--sp-2); min-height: var(--tap); color: var(--ink-2); font-size: var(--t-lab); letter-spacing: .1em; text-transform: uppercase; }
.zg-base-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.zg-base-granted .zg-base-label { color: var(--ink); }
.zg-base-prompt .zg-base-label, .zg-base-moved .zg-base-label { color: var(--ink); }
.zg-base-prompt .zg-base-label::before, .zg-base-moved .zg-base-label::before { content: "!"; display: inline-grid; place-items: center; width: 16px; height: 16px; margin-right: var(--sp-1); background: var(--cut); color: var(--cut-ink); font-weight: 700; }
.zg-base button { min-height: var(--tap-fine); padding: 0 var(--sp-3); border: var(--rule) solid currentColor; background: var(--bg); color: var(--ink); cursor: pointer; font-size: var(--t-btn); letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }
.zg-base .zg-link { min-height: var(--tap); width: var(--tap); justify-content: center; text-decoration: none; }

/* bare view (porcelain ?ui=0): no chrome at all */
body.zg-bare .zg-brand, body.zg-bare .zg-rail, body.zg-bare .zg-panel, body.zg-bare .zg-status { display: none !important; }

/* ---- dock (wide): the panel's grip drags it across; let go and it snaps to the nearer side (html[data-zg-dock="left"]), the rail takes the other ---- */
.zg-panel__grip { display: none; }
html[data-zg-mode="wide"] .zg-panel__grip { display: block; position: absolute; z-index: 2; left: 0; top: 0; right: var(--tap); height: var(--tap); cursor: grab; touch-action: none; }
html[data-zg-mode="wide"] .zg-panel__grip > i { position: absolute; left: var(--sp-4); top: 50%; width: 28px; height: 8px; margin-top: -4px; opacity: .45;
  background: radial-gradient(circle, currentColor 1.4px, transparent 1.6px) 0 0 / 7px 4px; }
html[data-zg-mode="wide"] .zg-panel__grip:hover > i { opacity: 1; }
html[data-zg-mode="wide"] .zg-panel:has(> .zg-panel__head) > .zg-panel__grip { right: auto; width: var(--sp-4); }
html[data-zg-mode="wide"] .zg-panel:has(> .zg-panel__head) > .zg-panel__grip > i { left: 4px; width: 8px; height: 28px; top: 8px; margin: 0; background-size: 4px 7px; }
html[data-zg-mode="wide"] .zg-panel:has(> .zg-panel__head) > .zg-panel__head { cursor: grab; }
html.zg-docking, html.zg-docking * { cursor: grabbing !important; user-select: none; -webkit-user-select: none; }
html.zg-docking .zg-panel { z-index: 25; box-shadow: 0 12px 32px rgba(0, 0, 0, .18); }
.zg-dock-ghost { position: fixed; z-index: 24; top: calc(var(--gut) + var(--safe-t)); bottom: calc(var(--bar-h) + var(--safe-b) + var(--gut)); width: var(--panel-w); pointer-events: none;
  border: var(--rule) dashed var(--cut); background: color-mix(in srgb, var(--cut) 8%, transparent); }
.zg-dock-ghost[hidden] { display: none; }
.zg-dock-ghost[data-side="right"] { right: calc(var(--gut) + var(--safe-r)); }
.zg-dock-ghost[data-side="left"] { left: calc(var(--gut) + var(--safe-l)); }
html[data-zg-mode="wide"][data-zg-dock="left"] .zg-panel { right: auto; left: calc(var(--gut) + var(--safe-l)); }
html[data-zg-mode="wide"][data-zg-dock="left"] .zg-panel[data-folded] .zg-panel__fold { right: auto; left: var(--safe-l); border-right: var(--rule) solid currentColor; border-left: 0; }
html[data-zg-mode="wide"][data-zg-dock="left"] .zg-rail { left: auto; right: calc(var(--gut) + var(--safe-r)); align-items: flex-end; }
html[data-zg-mode="wide"][data-zg-dock="left"] .zg-brand { left: calc(var(--panel-w) + var(--gut)); max-width: calc(100% - var(--panel-w) - var(--rail-w) - 3 * var(--gut)); }
html[data-zg-mode="wide"][data-zg-dock="left"]:has(.zg-panel[data-folded]) .zg-brand { left: var(--tap); }
html[data-zg-mode="wide"][data-zg-dock="left"] .zg-toast:not(.zg-toast--centre) { left: calc(var(--panel-w) + 2 * var(--gut) + var(--safe-l)); }
html[data-zg-mode="wide"][data-zg-dock="left"]:has(.zg-panel[data-folded]) .zg-toast:not(.zg-toast--centre) { left: calc(var(--tap) + var(--gut) + var(--safe-l)); }
/* bottom: a wide strip above the status line, right of the rail; the sections stand side by side as columns, each scrolling on its own, the strip
   scrolling sideways when they do not fit */
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel { top: auto; left: calc(2 * var(--gut) + var(--rail-w) + var(--safe-l)); width: auto; height: var(--dock-h); }
html[data-zg-mode="wide"][data-zg-dock="bottom"]:has(.zg-rail[data-folded]) .zg-panel { left: calc(2 * var(--gut) + var(--tap) + var(--safe-l)); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll { display: flex; align-items: stretch; gap: var(--sp-5); overflow-x: auto; overflow-y: hidden; touch-action: pan-x pan-y; padding-bottom: var(--sp-2); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll > * { flex: 0 0 auto; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll > .zg-sec { flex: 0 0 min(340px, 80vw); min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; padding: 0 var(--sp-2); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll > .zg-sec:not([open]) { flex-basis: 200px; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll > .zg-sec[hidden] { display: none; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__head { display: none; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll > .zg-panel__head { flex: 0 0 min(300px, 70vw); align-self: start; border-bottom: 0; margin: 0; padding: 0 var(--sp-2); }   /* a page that moves its head into the strip: its first column */
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel[data-folded] .zg-panel__fold { top: auto; bottom: calc(var(--bar-h) + var(--safe-b) + var(--gut)); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-brand { max-width: calc(100% - 2 * var(--gut)); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-rail { max-height: calc(100vh - var(--brand-h) - var(--safe-t) - var(--sp-2) - var(--bar-h) - var(--safe-b) - var(--sp-2)); }
html[data-zg-mode="wide"][data-zg-dock="bottom"]:not(:has(.zg-panel[data-folded])) .zg-toast:not(.zg-toast--centre) { bottom: calc(var(--bar-h) + var(--safe-b) + var(--dock-h) + var(--gut) + var(--sp-3)); left: calc(2 * var(--gut) + var(--rail-w) + var(--safe-l)); }
.zg-dock-ghost[data-side="bottom"] { top: auto; height: var(--dock-h); width: auto; left: calc(2 * var(--gut) + var(--rail-w) + var(--safe-l)); right: calc(var(--gut) + var(--safe-r)); }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__grip { right: var(--tap); width: auto; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__grip > i { left: var(--sp-4); top: 50%; width: 28px; height: 8px; margin-top: -4px; background-size: 7px 4px; }
html[data-zg-mode="wide"][data-zg-dock="bottom"] .zg-panel > .zg-panel__scroll { margin-top: var(--tap); }
