/* js/paintzoom.js: the full-screen "Look closer" view for a painting page. */
.glz-scrim{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;background:rgba(6,6,5,.97);opacity:0;transition:opacity .22s var(--ease)}
.glz-scrim.in{opacity:1}
.glz-top{display:flex;align-items:center;gap:12px;padding:calc(var(--top) + 10px) var(--g) 6px;flex:none}
.glz-title{flex:1;min-width:0;font:400 15px/1.3 var(--serif);color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.glz-stage{position:relative;flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;touch-action:none}
/* the frame's box is the image's natural pixel size, untouched by CSS -- js/paintzoom.js's gesture model does
   ALL the sizing with transform:scale(), starting at the "fit" scale (min(stageW/naturalW,stageH/naturalH))
   computed once the image loads, so a transform-origin:center scale() and a max-width/height clamp are never
   both trying to size the same box at once. transform has no transition by default: glZoomOpen() turns one on
   only for the specific moments that want an eased snap (a pinch/drag settling back in bounds, a double-tap),
   and removes it again before the next live-dragged frame so panning never fights a CSS transition. */
.glz-frame{position:relative;will-change:transform}
.glz-img{display:block;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;transition:filter .2s var(--ease)}
.glz-cv{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;opacity:0;transition:opacity .25s var(--ease);filter:blur(1px)}
.glz-cv.on{opacity:1}
.glz-tools{flex:none;display:flex;flex-direction:column;align-items:center;gap:10px;padding:10px var(--g) calc(var(--bottom) + 14px)}
.glz-seg button[data-glzv]{padding:0 16px}
.glz-seg button[data-glzv="pick"]{display:flex;align-items:center;gap:6px;padding:0 14px 0 12px}
.glz-seg button[data-glzv="pick"] svg{width:15px;height:15px}
.glz-pal{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.glz-pal[hidden]{display:none}
.glz-pal button{width:34px;height:34px;border-radius:50%;background:var(--c);box-shadow:inset 0 0 0 1px rgba(236,232,223,.22)}
.glz-pal button.on{outline:2px solid var(--ink);outline-offset:2px}
/* Select tool: hidden until segProbe resolves whether this painting's host even lets the encoder read its
   pixels (glZoomOpen) -- revealed either as a normal button or, honestly, a disabled one with a title tooltip
   explaining why, never silently missing. .glz-tool-hint is shared with Where's original one-line instruction. */
[data-glzv="select"][hidden]{display:none}
[data-glzv="select"]:disabled{opacity:.4}
.glz-tool-hint{margin:2px 0 0;font:400 13px/1.3 var(--sans);color:var(--soft);text-align:center}
.glz-tool-hint[hidden]{display:none}
@media (prefers-reduced-motion:reduce){.glz-scrim,.glz-frame,.glz-img{transition:none}}

/* Select's own controls block (js/paintzoom.js, js/segment.js): the first-run model-download progress bar,
   the "getting ready"/"tap the thing you want" hint (.glz-tool-hint, shared with Where), and once an image is
   encoded, the +/- tap-mode toggle plus Undo/Clear -- all hidden together outside Select (data-glzsel) */
.glz-sel[hidden]{display:none}
.glz-sel-prog[hidden]{display:none}
.glz-sel-prog-label{margin:0 0 6px;font:400 13px/1.3 var(--sans);color:var(--soft);text-align:center}
.glz-sel-bar{height:5px;border-radius:999px;background:rgba(236,232,223,.14);overflow:hidden}
.glz-sel-bar i{display:block;height:100%;width:0;background:var(--ink);border-radius:inherit;transition:width .15s linear}
.glz-sel-wifi{margin:6px 0 0;text-align:center}
.glz-sel-wifi[hidden]{display:none}
.glz-sel-ctl{display:flex;align-items:center;justify-content:center;gap:10px}
.glz-sel-ctl[hidden]{display:none}
.glz-sel-pm button{min-width:44px;font:500 17px/1 var(--sans)}
.glz-sel-btn{height:36px;padding:0 14px;border-radius:999px;background:var(--s1,#171512);color:var(--ink);font:500 13px/1 var(--sans);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10));transition:background .12s,opacity .12s}
.glz-sel-btn:active{background:var(--s3,#2B2823)}
.glz-sel-btn:disabled{opacity:.32}
/* Select's own error disclosure: the honest one-line hint above (.glz-tool-hint) always says what happened in
   plain words; this is the real error text, one tap away, never shouted -- see js/paintzoom.js's selSetError */
.glz-sel-errdetail{margin:4px 0 0;text-align:center}
.glz-sel-errdetail[hidden]{display:none}
.glz-sel-errdetail summary{font:400 12px/1.3 var(--sans);color:var(--soft);opacity:.6;cursor:pointer;list-style:none;text-decoration:underline;text-underline-offset:2px}
.glz-sel-errdetail summary::-webkit-details-marker{display:none}
.glz-sel-errdetail p{margin:4px auto 0;max-width:280px;font:400 11px/1.4 var(--mono,monospace);color:var(--soft);opacity:.6;word-break:break-word}

/* the selection's own palette sheet (js/segment.js segSheet) -- a compact version of the painting page's own
   strip + mode switcher + slider, reusing its CSS (.gl-pal-ui, .gl-strip, .gl-slide, .cnt-step/.cnt-b); the
   same classes the old region sheet used (.rgs-*), now fed a live AI-selected pool instead of a precomputed one.
   David, 2026-10-10: "adding more colors (raising the count) pushes the menu up so it's hard to scroll normally;
   it should extend downwards without panning" -- the base .sheet (app.css) is bottom-anchored with no fixed
   height, so it grows upward as the swatch strip and name rows grow with the count. Same fix as js/settray.js's
   .sx-pick-sheet: a fixed height with its own internal scroller ([data-sheet-scroll], js/core.js sheet()'s
   supported shape for this) around just the part that grows, so the sheet's top edge never moves when the count
   changes -- new colors extend downward inside that scroller instead. */
.sheet.rgs-sheet{display:flex;flex-direction:column;overflow:hidden;padding-bottom:0;height:66dvh}
.rgs-sheet>.grab,.rgs-sheet>.rgs-head,.rgs-sheet>.rgs-modes,.rgs-sheet>.pr-slide{flex:none}
.rgs-scroll{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-bottom:calc(var(--bottom) + 16px)}
.rgs-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin:2px 0 12px}
.rgs-head b{font:400 19px/1 var(--serif);color:var(--ink)}
.rgs-head span{font:400 13px/1 var(--sans);color:var(--soft)}
.rgs-modes{margin-bottom:10px}
.rgs-modes button{flex:1}
.rgs-sheet .gl-strip{height:46px;margin-bottom:10px;border-radius:var(--r-tile,6px);overflow:hidden}
.rgs-sheet .pal-names{margin-top:4px}

/* the hero on the painting page itself: much bigger than the old 30dvh box, tinted with the painting's own
   average color instead of black when it doesn't fill the full width, and a quiet "Look closer" button on it
   (David's rebuild brief, 2026-10-09) */
.gl-hero.gl-full-w{background:var(--c);border-radius:2px;margin:0 calc(-1 * var(--g));padding:0 var(--g)}
/* the button sits inside the picture's own box (.gl-hero>span, already position:relative + overflow:hidden in
   css/gallery.css), not the full-bleed tinted surround — so it always lands on the image itself, at any aspect
   ratio, instead of risking the surrounding padding math (David's rebuild brief, 2026-10-09) */
.gl-closer{position:absolute;right:10px;bottom:10px;z-index:2;display:flex;align-items:center;gap:7px;height:38px;padding:0 14px 0 11px;border-radius:999px;background:rgba(14,13,11,.62);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);box-shadow:inset 0 0 0 1px rgba(236,232,223,.18);color:#fff;font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;white-space:nowrap}
.gl-closer svg{width:16px;height:16px}
/* "Pick a color" (David, relayed 2026-10-09): the explicit eyedropper entry, beside Look closer rather than on
   top of it -- left corner of the same picture, same pill treatment, lit up while armed */
.gl-pick-btn{right:auto;left:10px}
.gl-pick-btn[hidden]{display:none}
.gl-pick-btn.on{background:rgba(236,232,223,.92);color:#0E0D0B;box-shadow:inset 0 0 0 1px rgba(14,13,11,.14)}

/* ============================================================ landscape lane (2026-10-09, CSS only -- js/paintzoom.js
   untouched): "the painting page -- image fits the height, info beside it". The column stack (top bar / image /
   tools+palette) becomes a grid: the top bar spans the full width, the image keeps the left/center and now fits
   by HEIGHT instead of width (the usual portrait constraint), and the segmented view switch + palette move into
   a right-hand rail next to it instead of stacking underneath, so nothing competes with the image for height. */
@media (orientation:landscape){
  .glz-scrim{display:grid;grid-template-columns:1fr minmax(200px,248px);grid-template-rows:auto 1fr;grid-template-areas:"top top" "stage tools"}
  .glz-top{grid-area:top;padding-left:calc(var(--g) + var(--left));padding-right:calc(var(--g) + var(--right))}
  .glz-stage{grid-area:stage}
  .glz-tools{grid-area:tools;flex-direction:column;justify-content:center;align-items:stretch;gap:14px;
    padding:14px calc(14px + var(--right)) calc(var(--bottom) + 14px) 14px;overflow-y:auto}
  .glz-pal{justify-content:flex-start}
}

/* ---- Pick: the palette editor (js/paintzoom.js "Pick: the palette editor") ---- */
/* the loupes live inside .glz-frame (so they ride pinch and pan exactly) and counter-scale by --iz, which keeps
   them one size on screen. A solid circle of the sampled color (David, 2026-10-20: a circle, not a donut) with a white
   and a dark hairline edge, so it reads on pale and on black paint alike; the drag lens shows the exact spot. */
.glz-pk-layer{position:absolute;inset:0;pointer-events:none}
.glz-pk-layer[hidden]{display:none}
.glz-lp{position:absolute;width:40px;height:40px;border-radius:50%;pointer-events:auto;touch-action:none;cursor:grab;
  transform:translate(-50%,-50%) scale(var(--iz,1));
  background:radial-gradient(circle,var(--c) 0 13px,#fff 13px 14.6px,rgba(0,0,0,.75) 14.6px 15.8px,transparent 16px);
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.45));-webkit-tap-highlight-color:transparent}
.glz-lp::before{content:"";position:absolute;inset:-6px;border-radius:50%}
.glz-lp.on{width:50px;height:50px;z-index:2;
  background:radial-gradient(circle,var(--c) 0 17px,#fff 17px 19.2px,rgba(0,0,0,.8) 19.2px 20.6px,transparent 20.8px)}
.glz-lp.drag{cursor:grabbing;z-index:3}
.glz-lp.drop{animation:glzlp-in .24s var(--spring)}
.glz-lp.out{opacity:0;scale:.6;transition:opacity .15s var(--ease),scale .15s var(--ease)}
@keyframes glzlp-in{from{scale:1.7;opacity:0}to{scale:1;opacity:1}}
.glz-spring .glz-lp{transition:transform .32s var(--spring)}
/* the lens that floats above a loupe while it's dragged, so the finger never covers the spot */
.glz-lens{position:absolute;z-index:5;width:108px;height:108px;margin:-54px 0 0 -54px;border-radius:50%;pointer-events:none;
  background:#000;box-shadow:0 0 0 4px var(--c,#fff),0 0 0 6px #fff,0 6px 18px rgba(0,0,0,.55);overflow:hidden}
.glz-lens[hidden]{display:none}
.glz-lens canvas{display:block;width:100%;height:100%}
.glz-lens i{position:absolute;left:50%;top:50%;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;box-shadow:0 0 0 1.5px #fff,0 0 0 3px rgba(0,0,0,.65)}
.glz-pk{width:100%;max-width:560px;display:flex;flex-direction:column;gap:6px}
.glz-pk[hidden]{display:none}
.glz-pk-info{min-height:50px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}
.glz-pk-hint{margin:0;font:400 16px/1.35 var(--sans);color:var(--soft)}
.glz-pk-name{display:inline-flex;align-items:center;gap:8px;max-width:100%;min-height:30px;padding:0 4px;color:var(--ink);font:400 21px/1.2 var(--serif)}
.glz-pk-name span{min-width:0;overflow-wrap:anywhere}
.glz-pk-name svg{flex:none;width:16px;height:16px;opacity:.8}
.glz-pk-sub{margin:0;font:400 15px/1.3 var(--sans);color:var(--soft);font-variant-numeric:tabular-nums}
.glz-pk-hex{letter-spacing:.02em}
.glz-pk-strip{display:flex;gap:10px;align-items:center;overflow-x:auto;overflow-y:hidden;padding:12px 6px 10px;touch-action:pan-x;scrollbar-width:none;-webkit-overflow-scrolling:touch;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.glz-pk-strip::-webkit-scrollbar{display:none}
.glz-pk-strip>:first-child{margin-left:auto}.glz-pk-strip>:last-child{margin-right:auto}   /* centered while it fits, scrolls from the left once it doesn't */
.glz-pk-strip.lifting{touch-action:none;overflow-x:hidden}
.glz-sw-w{position:relative;flex:none;width:44px;height:44px;transition:transform .18s var(--ease)}
.glz-sw{flex:none;width:44px;height:44px;border-radius:10px;background:var(--c);box-shadow:inset 0 0 0 1px rgba(128,128,128,.55);-webkit-tap-highlight-color:transparent}
.glz-sw.on{outline:2px solid var(--ink);outline-offset:3px}
.glz-sw-w.lift{z-index:4;transition:none;filter:drop-shadow(0 6px 10px rgba(0,0,0,.55))}
.glz-sw-add{display:flex;align-items:center;justify-content:center;background:transparent;box-shadow:none;border:1.5px dashed rgba(236,232,223,.45);color:var(--ink);font:300 26px/1 var(--sans)}
.glz-sw-add:active{background:rgba(236,232,223,.1)}
.glz-sw-x{position:absolute;top:-9px;right:-9px;width:22px;height:22px;border-radius:50%;background:var(--ink);color:#141311;display:flex;align-items:center;justify-content:center;box-shadow:0 0 0 2px rgba(6,6,5,.9);z-index:2}
.glz-sw-x::after{content:"";position:absolute;inset:-11px}
.glz-pk-act{display:flex;align-items:center;justify-content:center;gap:14px;min-height:46px}
.glz-pk-save{height:46px;padding:0 26px;border-radius:var(--r-pill,999px);background:var(--paper,#ECE8DF);color:var(--paper-ink,#141311);font:400 18px/1 var(--serif)}
.glz-pk-save:disabled{opacity:.4}
.glz-pk-note{font:400 15px/1.3 var(--sans);color:var(--soft)}
@media (prefers-reduced-motion:reduce){.glz-lp.drop{animation:none}.glz-sw-w,.glz-spring .glz-lp{transition:none}}
@media (orientation:landscape){.glz-pk-act{justify-content:flex-start}.glz-pk-info{align-items:flex-start;text-align:left}}
@media (max-width:359px){.glz-seg button[data-glzv]{padding:0 10px}.glz-seg button[data-glzv="pick"]{padding:0 10px 0 9px}}
