/* The painting gallery (js/gallery.js): the Paintings lens grid, the Adjust sheet, the lite painting page and the
   "In paintings" row on color pages. Same "Museum editorial" language as app.css: hairlines, mono small caps,
   serif titles, color as the only decoration. */

/* a sideways row of pins (Featured, Similar palettes, In paintings) */
.gl-rail{display:flex;gap:14px;align-items:flex-start;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;margin:0 calc(-1 * var(--g));padding:2px var(--g) 8px;scroll-padding:0 var(--g);scroll-snap-type:x proximity;scrollbar-width:none}
.gl-rail::-webkit-scrollbar{display:none}
/* a filmstrip: every picture the same height, each pin as wide as its picture; the text never widens it */
.gl-rail>.pin,.gl-rail>.gl-pin{flex:none;width:auto;scroll-snap-align:start}
.gl-rail>.pin-art img,.gl-rail>.gl-pin .gl-im{height:150px;width:auto}
.gl-rail>.pin-art>:not(img),.gl-rail>.gl-pin>:not(.gl-im){width:0;min-width:100%}
.gl-rail>.pin-art b{font-size:18px}

/* the bar above the grid: Adjust, what the search is, clear */
.gl-bar{display:flex;align-items:center;gap:14px;min-height:46px;border-top:1px solid var(--rule-2);border-bottom:1px solid var(--rule);margin:4px 0 18px}
.gl-adj{display:inline-flex;align-items:center;gap:8px;height:46px;font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--ink);flex:none}
.gl-adj svg{width:16px;height:16px}
.gl-sum{flex:1;min-width:0;display:flex;align-items:center;gap:7px;font:500 13px/1.2 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gl-sum i{width:10px;height:10px;background:var(--c);flex:none}
.gl-x{width:40px;height:40px;display:grid;place-items:center;color:var(--soft);margin-right:-10px;flex:none}
.gl-x svg{width:16px;height:16px}
.gl-x[hidden],.gl-float[hidden],.gl-picker[hidden]{display:none}

/* the virtualized grid: pins are absolutely placed; their heights come from the index */
.gl-grid{position:relative;min-height:80px}
.gl-grid>.fine{margin-top:0}
.gl-pin{display:flex;flex-direction:column;text-align:left;min-width:0;contain:layout paint}
.gl-grid>.gl-pin{position:absolute}
.gl-im{position:relative;display:block;width:100%;flex:none;background:var(--c,var(--lift));border-radius:2px;overflow:hidden}
.gl-im img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .45s var(--ease)}
.gl-im img.ld{opacity:1}
.gl-pin .mini-pal{margin:6px 0 8px;flex:none}
.gl-pin b{display:block;height:21px;font:400 19px/21px var(--serif);letter-spacing:-.005em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gl-pin small{display:flex;height:14px;margin-top:5px;font:500 13px/14px var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);white-space:nowrap;overflow:hidden}
.gl-pin small span{min-width:0;overflow:hidden;text-overflow:ellipsis}
.gl-pin small em{flex:none;font-style:normal;white-space:pre}
.gl-pin:active .gl-im{opacity:.8}
.gl-badge{position:absolute;left:6px;bottom:6px;z-index:1;max-width:calc(100% - 12px);padding:5px 7px 4px;border-radius:2px;background:rgba(14,13,11,.7);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:var(--ink);font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Adjust floats once the bar has scrolled away */
.gl-float{position:fixed;left:50%;bottom:calc(var(--tabh) + 14px);transform:translateX(-50%);z-index:14;max-width:min(78vw,420px);box-shadow:0 10px 30px -10px rgba(0,0,0,.8);animation:fade .25s both}
.gl-float span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* the Adjust sheet: light scrim so the results stay visible above it */
.gl-scrim{background:rgba(0,0,0,.22)}
.gl-sheet{padding-top:10px;padding-bottom:calc(var(--bottom) + 16px)}
.gl-sheet .grab{margin-bottom:12px}
.gl-picker .cp-wheel{touch-action:none}
.gl-sh-top{display:flex;align-items:baseline;gap:12px;padding-bottom:8px}
.gl-sh-top b{font:400 30px/1 var(--serif);letter-spacing:-.02em}
.gl-sh-top span{flex:1;font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft)}
.gl-reset{font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);padding:10px 0 10px 10px}
.gl-row{display:grid;grid-template-columns:58px minmax(0,1fr);align-items:center;min-height:48px;border-top:1px solid var(--rule)}
.gl-lab{font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--faint)}
.gl-sw,.gl-chips{display:flex;gap:7px;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none;padding:9px var(--g) 9px 3px;margin-right:calc(-1 * var(--g))}
.gl-sw::-webkit-scrollbar,.gl-chips::-webkit-scrollbar{display:none}
.gl-sw button{flex:none;width:30px;height:30px;background:var(--c);border-radius:2px;position:relative}
.gl-sw button.on{outline:2px solid var(--ink);outline-offset:2px}
.gl-sw .today::after{content:"";position:absolute;left:50%;bottom:-7px;width:4px;height:4px;margin-left:-2px;border-radius:50%;background:var(--ink)}
.gl-sw .gl-any{border-radius:50%;background:conic-gradient(#E34234,#FFBF00,#50C878,#00A6C8,#4B5BD8,#B04BC8,#E34234)}
.gl-cap{display:flex;align-items:center;gap:8px;min-height:30px;margin:-4px 0 6px 58px;font-size:13px;line-height:1.3;color:var(--soft)}
.gl-cap i{width:12px;height:12px;background:var(--c);flex:none}
.gl-cap b{font:400 18px/1 var(--serif);color:var(--ink);white-space:nowrap}
.gl-cap span{min-width:0}
.gl-picker{padding:6px 0 14px}
.gl-picker .cp-wheel{width:min(100%,190px)}
/* the wheel and the hex field are enough here; the HSB/RGB/LCh sliders live in Studio */
.gl-picker .cp-modes,.gl-picker .cp-sliders{display:none}
.gl-chips button{flex:none;height:30px;padding:0 11px;border:1px solid var(--rule);border-radius:2px;font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);white-space:nowrap;transition:background .2s,color .2s}
.gl-chips button.on{background:var(--paper);border-color:var(--paper);color:var(--paper-ink)}
.gl-range{display:flex;align-items:center;gap:0;font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--faint)}
.gl-range>span{width:34px;flex:none}
.gl-range>span:last-child{text-align:right}
.gl-tr{position:relative;flex:1;height:8px;margin:14px 12px;border-radius:4px;touch-action:none;cursor:pointer}
.gl-tr::before{content:"";position:absolute;left:-12px;right:-12px;top:-16px;bottom:-16px}
.gl-dim{position:absolute;top:0;bottom:0;background:rgba(23,22,15,.74);pointer-events:none}
.gl-dim.l{left:0;border-radius:4px 0 0 4px}.gl-dim.r{right:0;border-radius:0 4px 4px 0}
.gl-kn{position:absolute;top:50%;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;background:var(--ink);box-shadow:0 0 0 3px #17160F,0 2px 8px rgba(0,0,0,.6);pointer-events:none}
.gl-go{margin-top:14px}

/* the lite painting page */
.gl-hero{display:flex;justify-content:center}
.gl-hero>span{display:block;position:relative;max-width:100%;background:var(--c);border-radius:2px;overflow:hidden}
.gl-hero img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;opacity:0;transition:opacity .5s var(--ease)}
.gl-hero img.ld{opacity:1}
.gl-pal-h{margin-top:30px}
.gl-page .sec-head{gap:12px}
/* the bar sits over the full-bleed hero and the page's running text once scrolled; a fading gradient let text
   show through behind the buttons, so give it a solid, blurred backdrop like the color page's bar (David screenshot,
   2026-10-09). PLAN §3.5: the bar is ‹ · the heart · ⋯ · the place pill -- the museum link moved into ⋯ › Go,
   but the heart stays here (David, relayed 2026-10-10: "visible without scrolling", js/trail.js tlDecorate
   treats it as one of the bar's allowed slots). css/favs.css's .art-top .fva-heart styles it. */
.gl-page .art-top{background:var(--ground);background:color-mix(in srgb,var(--ground) 92%,transparent);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--rule)}
.gl-page .palette{margin-top:12px}
.gl-sim-h{margin-bottom:16px}

/* "In paintings" on a color page */
.gl-in{margin-top:40px}
.gl-in:empty{display:none}
.gl-in h3{font:500 13px/1 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);padding-bottom:10px;border-bottom:1px solid var(--rule);margin-bottom:14px}
.gl-in-sub{color:var(--soft);font-size:13.5px;line-height:1.45;margin:0 0 14px;max-width:46ch}
.gl-in .gl-all{margin-top:4px;padding:0}

/* painting page: our 200px copies stay crisp at a smaller size; a link offers the full image at the museum */
.gl-hero.small span{margin:0 auto}
.gl-full{display:block;text-align:center;margin-top:10px;font:500 13px/1.4 var(--mono);letter-spacing:0;text-transform:none;color:var(--soft);text-decoration:underline;text-underline-offset:3px}
.gl-hero img.hi{animation:fade .4s both}

/* the dynamic palette's 3/6/12/20 control (ROADMAP §13) */
.gl-sizes{margin-top:14px}

/* "arrive from a color and see it": the line above the palette, and the nearest swatch's highlight (the .on
   styling itself — outline on .pal, underline on .pal-name — already exists in app.css) */
.gl-arrive{display:flex;align-items:center;gap:8px;margin:14px 0 0}
.gl-arrive-sw{width:14px;height:14px;border-radius:50%;flex:none;box-shadow:inset 0 0 0 1px rgba(236,232,223,.22)}

/* tap the painting to name a spot: a quiet crosshair cursor only once a canvas read is confirmed possible, and
   a small marker where the visitor tapped (removed on the next tap) */
.gl-hero>span.gl-tap{cursor:crosshair}
.gl-tap-dot{position:absolute;width:18px;height:18px;margin:-9px 0 0 -9px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.5),0 2px 6px rgba(0,0,0,.4);pointer-events:none;animation:fade .2s both}

/* the painting page leads with its best colors (IMPROVE-2026-10-08, Wave 1a Lane A): the picture full width, one
   quiet "Name its colors" button under it, then Look for (accent, easy to miss, focal) above the bars */
.gl-hero.gl-full-w{flex-direction:column;align-items:center}
.gl-under{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;min-height:58px}
.gl-under .gl-full{margin:0;text-align:right;margin-left:auto}
.gl-quiz{min-height:44px}
.gl-quiz .tq-open{margin:8px 0 0}
.gl-roles{margin-top:22px}
.gl-roles:empty{display:none}
.gl-roles-h{margin:0 0 10px;font:italic 400 17px/1 var(--serif);color:var(--soft)}
.gl-roles-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.gl-role{display:flex;flex-direction:column;gap:8px;min-width:0;padding:0;text-align:left;color:var(--ink);background:none}
.gl-role i{display:block;width:100%;height:56px;border-radius:var(--r-1);background:var(--c) no-repeat;box-shadow:inset 0 0 0 1px rgba(236,232,223,.14)}
/* the "Findings" wrapper (js/gallery.js glPage, David's rebuild brief, 2026-10-09): one header over the
   crops/roles row and the painter/decade/movement comparison; quiet when both are still empty */
.gl-finds .sec-head{margin-bottom:4px}
.gl-finds .aw-cx{margin-top:18px}
/* Findings and Analysis used to read as two data sections back to back; the strongest lines (roles/crops, then
   In context) lead, the rest of the Analysis deep-dive folds behind one "More" (David's polish pass, 2026-10-09) */
.gl-finds-more{margin-top:18px;border-top:1px solid var(--rule)}
.gl-finds-more>summary{font:400 17px/1.2 var(--serif);color:var(--ink);padding:16px 0;cursor:pointer;min-height:44px;box-sizing:border-box;list-style:none}
.gl-finds-more>summary::-webkit-details-marker{display:none}
.gl-finds-more[open]>summary{padding-bottom:10px}
.gl-role span{display:flex;flex-direction:column;gap:2px;min-width:0}
.gl-role em{font:italic 400 17px/1.2 var(--serif);color:var(--soft)}
.gl-role b{font:400 18px/1.15 var(--serif);overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.gl-role small{font:400 13px/1.3 var(--sans);color:var(--soft)}
.gl-ctl{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-top:14px}
.gl-ctl .gl-sizes{margin-top:0}
.gl-ctl .seg button{padding:0 12px}
.gl-cov{display:flex;align-items:center;gap:12px;margin:16px 0 4px}
.gl-cov:empty{display:none}
.gl-cov>span{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.gl-cov b{font:400 19px/1.2 var(--serif)}
.gl-cov em{font:400 14px/1.35 var(--sans);font-style:normal;color:var(--soft)}
.gl-cov-go{flex:none;min-height:44px;padding:0 16px;border-radius:var(--r-pill,22px);border:1px solid var(--ink);background:transparent;color:var(--ink);font:italic 400 17px/1 var(--serif)}
/* "Similar paintings, on the map" (js/paintmap.js): one quiet row under "More like this" */
.gl-pmap{display:flex;align-items:center;gap:12px;width:100%;min-height:56px;margin:18px 0 4px;padding:0 4px;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);text-align:left;color:var(--ink)}
.gl-pmap span{flex:1;font:400 18px/1.2 var(--serif)}
.gl-pmap svg:first-child{color:var(--soft)}
.gl-pmap svg:last-child{color:var(--faint)}
/* the same action, a second time, right by the palette (David, 2026-10-09: "it should be more prominent" --
   the one below "More like this" was the only way to it, easy to miss on a long page). An opaque pill instead
   of the bordered full-width row, so it reads as a clear control inside the palette card, not another section. */
.gl-pmap-top{min-height:48px;margin:14px 0 0;padding:0 16px;border:0;border-radius:var(--r-pill,24px);background:var(--surface-2)}
.gl-pmap-top span{font-size:16px}
/* the first-run hint above it (David, 2026-10-09), once ever -- inline, not position:fixed, since the page
   scrolls and the button it points at isn't pinned to one spot on screen (js/gallery.js glPage) */
.gl-pmap-hint{display:flex;align-items:center;gap:9px;margin:14px 0 0;padding:0 2px;font:400 15px/1.3 var(--sans);color:var(--soft);animation:glPmHintIn .5s var(--spring) .3s both}
.gl-pmap-hint i{width:7px;height:7px;flex:none;border-radius:50%;background:var(--sel-ink,var(--ink));animation:glPmHintPulse 1.6s ease-in-out .8s infinite}
.gl-pmap-hint.out{animation:glPmHintOut .3s var(--ease) both}
@keyframes glPmHintIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@keyframes glPmHintOut{to{opacity:0;transform:translateY(-4px)}}
@keyframes glPmHintPulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.6);opacity:.35}}
@media (prefers-reduced-motion:reduce){.gl-pmap-hint,.gl-pmap-hint i,.gl-pmap-hint.out{animation:none}}

/* David's rebuild brief, 2026-10-09: the picture is now much bigger (css/paintzoom.css), so it no longer stays
   pinned while you change palette types below it -- at this size that would eat the whole screen. "Look closer"
   (the full-screen view) is the way to keep studying it while the palette controls stay reachable. */
.gl-pal-wrap .gl-hero{margin:0 calc(-1 * var(--g));padding:0 var(--g) 10px}
/* Palette view, split mode (coordinator, 2026-10-12): the default page is unchanged from main -- classic modes
   only, the hero sized exactly as before (var(--hero-vh, 62dvh), unset here so it falls through to 62dvh).
   One more tile, "Browse palettes", opens a dedicated full-screen split (js/gallery.js enterSplitMode): a
   plain `position:fixed` overlay, same pattern as css/paintzoom.css's Look closer, so nothing here is sticky
   and nothing can ever land on top of anything else -- the hero and the controls above the feed are flex:none
   siblings that never move; only .gl-split-feed scrolls. */
.gl-hero-dots{position:absolute;inset:0;pointer-events:none}
.gl-hero-dots i{position:absolute;width:12px;height:12px;border-radius:50%;box-shadow:0 0 0 2px #fff,0 1px 6px rgba(0,0,0,.5);transform:translate(-50%,-50%);background:var(--c)}
@media (prefers-reduced-motion:no-preference){.gl-hero-dots i{transition:left .3s var(--ease),top .3s var(--ease),opacity .3s var(--ease)}}
.gl-tile-browse{background:var(--sel-fill,#2B2823)}
.gl-tile-browse.on{box-shadow:var(--sel-ring,inset 0 0 0 1.5px rgba(236,232,223,.22))}
.gl-split{position:fixed;inset:0;z-index:55;display:flex;flex-direction:column;background:var(--ground)}
.gl-split-top{flex:none;height:45vh;min-height:260px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;padding-top:var(--top)}
.gl-split-top .gl-hero{margin:0;padding:0;width:100%;--hero-vh:40vh}
/* a tall/narrow panel (a hanging scroll, say) can compute a span narrower than the "Pick a color"/"Look closer"
   pair needs at this box's smaller height -- a floor keeps them apart; .gl-split-top's own overflow:hidden
   above crops anything past 45vh that this then adds, never spilling into the chips below. Below that floor
   (a container query on the span itself, since its width is what the two buttons actually compete for) each
   button drops its label and becomes a plain icon circle with a real gap between them -- both buttons already
   carry their own aria-label, so the accessible name survives the text disappearing. */
.gl-split-top .gl-hero>span{min-width:230px;container-type:inline-size}
@container (max-width:300px){
  .gl-split-top .gl-closer{width:40px;padding:0;justify-content:center;gap:0}
  .gl-split-top .gl-closer span{display:none}
  .gl-split-top .gl-closer{right:8px}
  .gl-split-top .gl-pick-btn{right:auto;left:8px}
}
.gl-split-done{position:absolute;top:calc(var(--top) + 10px);right:14px;z-index:3;display:flex;align-items:center;gap:6px;min-height:40px;padding:0 14px 0 10px;border-radius:999px;background:rgba(14,13,11,.55);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);color:#fff;font:500 15px/1 var(--sans)}
.gl-split-done svg{width:18px;height:18px}
.gl-split-chips-row{flex:none;padding:12px var(--g) 0}
.gl-split-chips-row .gl-modes{margin:0;padding:0}
/* the draggable track's own thumb (app.css .cnt-wrap/input[type=range]) rendered tall enough to peek out under
   the first feed row at this box's tighter spacing -- split mode keeps only the -/+ stepper (same control,
   same curK, no separate state), never the track, so nothing can ever show through from above. */
.gl-split .gl-slide.cnt-wrap{flex:none;display:flex;justify-content:flex-end;margin:6px var(--g) 0;height:44px}
.gl-split .gl-slide input[type=range]{display:none}
.gl-split-feed{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:10px var(--g) calc(var(--bottom) + 20px);display:flex;flex-direction:column;gap:8px}
.gl-split-feed .plv-sentinel{height:1px;flex:none}
/* .gl-feed-row also carries .plv-row (js/paletteview.js's plvSwatchRow markup, reused as-is) -- paletteview.css
   loads after this file and its .plv-row{flex:1;height:64px} would otherwise win on source order alone (equal
   specificity), shrinking every row to near-nothing in .gl-split-feed's flex column. The extra .gl-split-feed
   ancestor in this selector is what wins the tie-break, not load order. */
.gl-split-feed .gl-feed-row{flex:none;height:56px;border-radius:var(--r-2,10px);overflow:hidden;transition:transform .15s var(--ease),box-shadow .15s var(--ease)}
.gl-split-feed .gl-feed-row:active{transform:scale(.985)}
.gl-split-feed .gl-feed-row.on{box-shadow:0 0 0 2px var(--ink)}
/* David, 2026-10-09 ("weird that you need to scroll far down just to get who and why"): title, painter, date and
   museum sit right under the pinned image, above the palette strip, so who/when/where/why never needs a scroll.
   Kept short on purpose -- the eyebrow/title/dek are the same elements the painting used to show lower on the
   page (gl-roles still follows, further down); this block just moves them above the palette. */
.gl-id{margin-top:14px}
.gl-id .p-title{margin-top:6px}
.gl-id .p-dek{margin-top:6px}
.gl-id-src{margin-top:4px;font:400 13px/1.3 var(--mono);color:var(--faint)}
.gl-id-src a{color:inherit;text-decoration:underline;text-underline-offset:2px}
/* "Why it matters": one or two lines from this painting's own Analysis findings (js/artwiki.js awPaintingWhy),
   the only per-painting prose the corpus currently has. Quiet until there's something to say. */
.gl-why{margin-top:10px}
.gl-why[hidden]{display:none}
.gl-why-t{font:400 15px/1.45 var(--sans);color:var(--soft);text-wrap:pretty}
.gl-why-ex{margin:6px 0 0;padding-left:18px;font:400 15px/1.45 var(--sans);color:var(--soft)}
.gl-why-ex[hidden]{display:none}
.gl-why-ex li+li{margin-top:4px}
.gl-why-more{margin-top:4px;font:500 14px/1 var(--sans);color:var(--ink);text-decoration:underline;text-underline-offset:2px}
/* David, 2026-10-08 ("weird spacing; palettes don't fit"): the strip first, right under the picture, then three
   slim rows (type, how many, on the painting) and a one-line caption. Selection lifts a step, never turns white. */
.gl-pal-ui{padding-top:0}
.gl-page .gl-pal-ui .palette.gl-strip{height:52px;margin-top:2px;border-radius:var(--r-tile,6px);overflow:hidden}
/* legibility pass (2026-10-09): 12px is under the 13px reading-text floor -- these percentage labels (a photo
   palette's share-of-area, js/studio.js's palPhotoView) are real reading text, not decoration. */
/* David, 2026-10-09: "the color palette slider doesn't show more than 11 colors." A flex item's default
   min-width is auto (its content's own min size -- here, the padding plus the percentage label's text), not 0,
   so chips stopped shrinking once each one needed ~35-40px and the rest silently overflowed this row's own
   overflow:hidden. min-width:14px (David's own floor -- any narrower and a swatch stops reading as a color at
   all) replaces that content-based floor with a real one: 20 chips at 14px is 280px, comfortably inside even a
   320px phone, so every count up to the slider's own max (20) now actually fits and shows. Each chip becomes
   its own container (container-type) so its OWN rendered width -- not the row's -- decides whether its percent
   label still fits; squeezed down near the floor, the label quietly drops rather than wrapping into mush. */
.gl-strip .pal{position:relative;padding:6px 7px;font:500 13px/1 var(--sans);letter-spacing:0;font-variant-numeric:tabular-nums;min-width:14px;container-type:inline-size}
.gl-strip .pal>span{display:none;white-space:nowrap;overflow:hidden}
@container (min-width:28px){.gl-strip .pal>span{display:block}}
.gl-strip .pal[data-ink="dark"],.pal-name i[data-ink="dark"]{color:rgba(14,13,11,.78)}
.gl-strip .pal[data-ink="light"],.pal-name i[data-ink="light"]{color:rgba(255,255,255,.88)}
.gl-strip .pal,.gl-pal-ui .pal-name{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
/* "Where" glyph (David, 2026-10-09: "the palette strip looks weird now because there's a symbol on the
   colors... it looked better when the swatches had no symbols on top"): moved off the strip entirely -- a tap
   on a strip chip opens the color's page, a long-press locates it (js/gallery.js's wireLocate). This row
   version is the explicit, always-visible way to do the same thing from the expanded list below the strip.
   28px box + padding keeps the tap target close to this app's other controls (countify's 32px .cnt-b) without
   the circle itself dominating the row. */
.gl-pal-ui .pal-name{position:relative;padding-right:34px}
/* sits on the plain page background now, not a colored chip, so a fixed neutral color (not the old per-swatch
   contrast-aware ink) is the right call here */
.pal-where{position:absolute;top:6px;right:0;width:28px;height:28px;padding:3px;box-sizing:content-box;display:grid;place-items:center;opacity:.6;border-radius:50%;color:var(--faint)}
.pal-where:active{opacity:1;background:var(--lift);color:var(--soft)}
.pal-where svg{width:14px;height:14px}
.gl-pal-ui .pal-name.loc .pal-where{opacity:1;color:var(--ink)}
.gl-modes-f{position:relative;margin:8px calc(-1 * var(--g)) 0}
.gl-modes-f::before,.gl-modes-f::after{content:"";position:absolute;top:0;bottom:0;width:36px;z-index:1;pointer-events:none;opacity:0;transition:opacity .2s}
.gl-modes-f::before{left:0;background:linear-gradient(90deg,var(--ground) 20%,transparent)}
.gl-modes-f::after{right:0;background:linear-gradient(270deg,var(--ground) 20%,transparent)}
.gl-modes-f.fl::before,.gl-modes-f.fr::after{opacity:1}
.gl-modes{display:flex;gap:6px;overflow-x:auto;margin:0;padding:2px var(--g);scrollbar-width:none;-webkit-overflow-scrolling:touch;scroll-padding:0 var(--g)}
.gl-modes::-webkit-scrollbar{display:none}
.gl-modes button{flex:none;height:40px;padding:0 14px;border-radius:999px;font:500 14px/1 var(--sans);color:var(--soft);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10));transition:background .12s,color .12s,transform .12s}
.gl-modes button:active{transform:scale(.96);background:var(--s3,#2B2823)}
.gl-modes button.on{background:var(--sel-fill,#2B2823);color:var(--sel-ink,var(--ink));box-shadow:var(--sel-ring,inset 0 0 0 1.5px rgba(236,232,223,.22))}
/* the mode switcher as a compact 2-row grid of tiles, each with its own tiny live preview strip (David,
   2026-10-10: "the palette extractions/selectors... scrolling through that top row isn't convenient"). Only
   `.gl-modes.gl-tiles` (the painting page's own container) gets this -- js/studio.js's photo page keeps the
   plain scrolling `.gl-modes` pill row above untouched. */
.gl-modes.gl-tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:62px;gap:8px;overflow:visible;padding:2px var(--g) 0}
.gl-tile{flex:none;height:auto;min-height:0;min-width:0;padding:0 12px;border-radius:var(--r-tile,10px);display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:6px;text-align:left}
.gl-modes.gl-tiles .gl-tile{height:100%;border-radius:12px;padding:0 12px}
.gl-tile-prev{display:flex;width:100%;height:9px;border-radius:3px;overflow:hidden}
.gl-tile-prev i{flex:1;background:var(--c)}
.gl-tile-prev:empty{display:none}
.gl-tile b{font:500 14px/1.15 var(--sans);color:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.gl-tile-more .gl-tile-prev{gap:3px}
.gl-tile-dots i{flex:none;width:calc((100% - 6px)/3);background:var(--faint,#8C877C);opacity:.55}
.gl-tile b em{font-style:normal;color:var(--faint);font-weight:400}
.gl-modes.gl-tiles .gl-tile.on{box-shadow:var(--sel-ring,inset 0 0 0 2px rgba(236,232,223,.5))}
.gl-seg-row{display:flex;align-items:center;gap:12px;margin:12px 0 0}
.gl-seg-l{flex:none;font:500 13px/1 var(--sans);color:var(--soft)}
.gl-seg{flex:1;min-width:0;display:grid;grid-template-columns:1fr 1fr;gap:2px;padding:2px;border-radius:999px;background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10))}
.gl-seg button{height:36px;border-radius:999px;font:500 14px/1 var(--sans);color:var(--soft);padding:0 8px;white-space:nowrap;transition:background .12s,color .12s}
.gl-seg button.on{background:var(--sel-fill,#2B2823);color:var(--sel-ink,var(--ink));box-shadow:var(--sel-ring,inset 0 0 0 1.5px rgba(236,232,223,.22))}
.gl-pal-ui .gl-slide{display:flex;align-items:center;gap:10px;margin:2px 0 0;height:44px}
.gl-pal-ui .gl-slide[hidden]{display:none}
/* Shuffle / Edit / Save for the current single palette, and its short re-roll history (every mode but
   Harmonies, which gives each of its own cards the same three -- David, 2026-10-10 + coordinator follow-up) */
.gl-pal-acts{display:flex;gap:8px;margin:12px 0 0;flex-wrap:wrap}
.gl-pal-acts[hidden],.gl-shufhist[hidden]{display:none}
.gl-pa-btn{flex:none;height:40px;padding:0 14px;display:inline-flex;align-items:center;gap:7px;border-radius:999px;font:500 14px/1 var(--sans);color:var(--soft);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10));transition:background .12s,transform .12s}
.gl-pa-btn:active{transform:scale(.96);background:var(--s3,#2B2823)}
.gl-pa-btn.solid{background:var(--ink);color:var(--ground)}
.gl-pa-btn svg{width:16px;height:16px}
.gl-pa-btn:disabled{opacity:.35}
.gl-shufhist{display:flex;gap:7px;margin:10px 0 0;overflow-x:auto;scrollbar-width:none}
.gl-shufhist::-webkit-scrollbar{display:none}
.gl-shuf-thumb{flex:none;display:flex;width:52px;height:30px;border-radius:5px;overflow:hidden;box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.14))}
.gl-shuf-thumb.on{box-shadow:inset 0 0 0 2px var(--ink)}
.gl-shuf-thumb i{flex:1;background:var(--c)}

/* Harmonies: several real-color relation cards at once, not one (David, 2026-10-10) */
.gl-harm[hidden]{display:none}
.gl-harm-top{display:flex;align-items:center;gap:10px;margin-top:4px}
.gl-harm-chips{flex:1;min-width:0;display:flex;gap:7px;overflow-x:auto;scrollbar-width:none;padding:2px 0}
.gl-harm-chips::-webkit-scrollbar{display:none}
.gl-harm-chips button{flex:none;height:34px;padding:0 12px;border-radius:999px;font:500 13px/1 var(--sans);color:var(--soft);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10))}
.gl-harm-chips button.on{background:var(--sel-fill,#2B2823);color:var(--sel-ink,var(--ink));box-shadow:var(--sel-ring,inset 0 0 0 1.5px rgba(236,232,223,.22))}
.gl-harm-list{display:flex;flex-direction:column;gap:12px;margin-top:12px}
.gl-hcard{padding:12px;border-radius:var(--r-tile,10px);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10))}
.gl-hcard-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}
.gl-hcard-top b{font:400 17px/1.2 var(--serif);color:var(--ink)}
.gl-hcard-top span{font:500 13px/1 var(--mono);color:var(--soft);flex:none}
.gl-hcard-strip{height:40px;border-radius:6px;overflow:hidden}
.gl-hcard-names{margin:8px 0 0;font:400 13px/1.4 var(--sans);color:var(--soft)}
.gl-hcard-acts{display:flex;gap:8px;margin-top:10px}
.gl-harm-more{width:100%;height:44px;margin-top:4px;border-radius:999px;font:500 14px/1 var(--sans);color:var(--soft);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10))}
.gl-harm-more[hidden]{display:none}
.gl-pal-ui .gl-slide input{flex:1;height:44px}
.gl-pal-ui .gl-slide input::-webkit-slider-thumb{width:24px;height:24px;margin-top:-10px}
.gl-pal-ui .gl-slide input::-moz-range-thumb{width:24px;height:24px}
.gl-kn-t{flex:none;min-width:58px;text-align:center;font:500 14px/1 var(--sans);color:var(--soft);font-variant-numeric:tabular-nums}
/* countify()'s own +/- stepper (js/core.js), reused here for the How-many-colors slider (2026-10-09: every
   palette mode gets this slider now, not just By area) -- no shared base style exists yet for .cnt-step/.cnt-b
   anywhere in the app, so this page styles its own instance of it, to match the mode chips beside it. */
.gl-pal-ui .cnt-step{flex:none;display:flex;align-items:center;gap:4px}
.gl-pal-ui .cnt-b{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;color:var(--ink);background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10));transition:background .12s,transform .12s}
.gl-pal-ui .cnt-b:active{transform:scale(.9);background:var(--s3,#2B2823)}
.gl-pal-ui .cnt-b:disabled{opacity:.32}
.gl-where{display:flex;align-items:center;justify-content:space-between;gap:10px;height:44px;margin-top:2px}
.gl-where[hidden]{display:none}
.gl-where>span{font:400 14px/1.2 var(--sans);color:var(--soft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.gl-where-seg{flex:none;display:flex;padding:2px;border-radius:999px;background:var(--s1,#171512);box-shadow:inset 0 0 0 1px var(--line,rgba(236,232,223,.10))}
.gl-where-seg button{height:36px;padding:0 12px;border-radius:999px;font:500 14px/1 var(--sans);color:var(--soft);transition:background .12s,color .12s}
.gl-where-seg button.on{background:var(--sel-fill,#2B2823);color:var(--sel-ink,var(--ink));box-shadow:var(--sel-ring,inset 0 0 0 1.5px rgba(236,232,223,.22))}
.gl-pal-ui .gl-cap{display:flex;align-items:baseline;gap:10px;min-height:0;margin:4px 0 2px;max-width:none}
/* David (screenshot, Madrazo's "La Marquise d'Hervey Saint-Denys en Diane"): the short caption ("Vivid and rare
   for this painter") was cut by a single-line nowrap+ellipsis once the row got tight. Two lines, never cut
   mid-word, still compact -- collapsed captions are one short sentence, so this rarely even reaches line 2. */
.gl-cap-t{flex:1;min-width:0;min-height:32px;padding:0;text-align:left;font:400 14px/1.4 var(--sans);color:var(--soft);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;white-space:normal}
.gl-cap.open .gl-cap-t{-webkit-line-clamp:unset;overflow:visible}
.gl-cap-t[disabled]{cursor:default;opacity:1}
.gl-cap .aw-link{flex:none}
/* a located swatch (tapped on the strip, not its name): an outline plus a quiet ring so it reads as "active"
   distinctly from the "arrived from" .on state (David's rebuild brief, 2026-10-09) */
.gl-strip .pal.loc{outline:2px solid var(--ink);outline-offset:-2px;box-shadow:inset 0 0 0 4px rgba(14,13,11,.35)}
.gl-locate{display:flex;align-items:center;gap:8px;min-height:0;margin:4px 0 2px;font:400 14px/1.4 var(--sans);color:var(--soft)}
.gl-locate[hidden]{display:none}
.gl-locate i{width:12px;height:12px;border-radius:50%;background:var(--c);flex:none;box-shadow:inset 0 0 0 1px rgba(236,232,223,.22)}
.gl-pal-ui .pal-names{margin-top:6px}
.gl-pal-ui .pal-name i{display:grid;place-items:center;font:500 12px/1 var(--sans);font-style:normal}
/* markers: each palette color's main places on the painting, numbered like its chip */
.gl-mks{position:absolute;inset:0;pointer-events:none;z-index:2}
.gl-mk{position:absolute;width:26px;height:26px;margin:-13px 0 0 -13px;padding:0;border-radius:50%;display:grid;place-items:center;background:var(--c);
  font:600 13px/1 var(--sans);font-variant-numeric:tabular-nums;pointer-events:auto;
  box-shadow:0 0 0 2px var(--ground,#0E0D0B),0 0 0 3px rgba(236,232,223,.85),0 3px 10px rgba(0,0,0,.45)}
.gl-mk[data-ink="dark"]{color:rgba(14,13,11,.85)}
.gl-mk[data-ink="light"]{color:#fff}
.gl-mk.sm{width:14px;height:14px;margin:-7px 0 0 -7px;box-shadow:0 0 0 2px var(--ground,#0E0D0B),0 0 0 3px rgba(236,232,223,.7)}
.gl-mk::after{content:"";position:absolute;inset:-9px}
.gl-mk.sm::after{inset:-15px}
.gl-mk.in{animation:glMkIn .32s cubic-bezier(.2,.8,.2,1) var(--d,0ms) both}
.gl-mk.pulse{animation:glMkPulse .7s cubic-bezier(.2,.8,.2,1) 2}
@keyframes glMkIn{from{opacity:0;transform:translateY(6px) scale(.6)}to{opacity:1;transform:none}}
@keyframes glMkPulse{0%{transform:scale(1)}35%{transform:scale(1.55);box-shadow:0 0 0 2px var(--ground,#0E0D0B),0 0 0 3px #fff,0 0 0 10px rgba(236,232,223,.18)}100%{transform:scale(1)}}
@media (prefers-reduced-motion:reduce){.gl-mk.in,.gl-mk.pulse{animation:none}.gl-modes-f::before,.gl-modes-f::after{transition:none}}
.gl-lit-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)}
.gl-lit-cv.on{opacity:1}
.gl-pick-dot{pointer-events:none}
/* "Test yourself" (David's rebuild brief, 2026-10-09: quiz collapsed, closed by default, like the color page's
   other <details> sections) and "More by this painter" just above "More like this" */
.gl-quiz-fold{margin:18px 0 0;border-top:1px solid var(--rule)}
.gl-quiz-fold>summary{font:400 17px/1.2 var(--serif);color:var(--ink);padding:16px 0;cursor:pointer;min-height:44px;box-sizing:border-box;list-style:none}
.gl-quiz-fold>summary::-webkit-details-marker{display:none}
.gl-quiz-fold[open]>summary{padding-bottom:10px}
.gl-quiz-fold .gl-quiz{padding-bottom:16px}
.gl-morepainter{margin-top:22px}
.gl-morepainter:empty{display:none}
.gl-morepainter .sec-head{margin-bottom:4px}
.gl-morepainter .gl-mp-sub{color:var(--soft);font-size:13.5px;line-height:1.4;margin:0 0 12px}
.gl-page .gl-pal-ui .palette.gl-strip:empty{display:none}

/* the palette editor sheet (David, 2026-10-10: "how do we edit the palette?") -- remove/reorder/lock+shuffle
   mirror js/setpage.js's own edit mode (a drag handle, an ×, a lock before a re-derive), as a modal for a
   palette that hasn't been saved yet. */
.gl-edit-sheet .gl-pe-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.gl-pe-name{width:100%;height:46px;margin-top:4px;padding:0 2px;border:0;border-bottom:1px solid var(--rule);background:none;color:var(--ink);font:400 19px/1 var(--serif)}
.gl-pe-list{display:flex;flex-direction:column;margin-top:14px}
.gl-pe-row{display:flex;align-items:center;gap:10px;height:52px;border-bottom:1px solid var(--rule);background:var(--ground);touch-action:none}
.gl-pe-row.dragging{position:relative;z-index:2;box-shadow:0 6px 16px rgba(0,0,0,.4)}
.gl-pe-row.locked{opacity:.85}
.gl-pe-handle{flex:none;width:28px;height:44px;display:grid;place-items:center;color:var(--faint);cursor:grab}
.gl-pe-sw{flex:none;width:34px;height:34px;border-radius:7px;background:var(--c);box-shadow:inset 0 0 0 1px rgba(236,232,223,.18)}
.gl-pe-nm{flex:1;min-width:0;font:400 16px/1.2 var(--serif);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gl-pe-lock,.gl-pe-x{flex:none;width:36px;height:36px;display:grid;place-items:center;color:var(--soft)}
.gl-pe-lock[aria-pressed="true"]{color:var(--ink)}
.gl-pe-x:disabled{opacity:.3}
.gl-pe-x svg{width:16px;height:16px}
.gl-pe-swappanel{padding:10px 0 14px 38px}
.gl-pe-swopts{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.gl-pe-swopt{width:32px;height:32px;border-radius:7px;background:var(--c);box-shadow:inset 0 0 0 1px rgba(236,232,223,.18)}
.gl-pe-addrow{display:flex;align-items:center;gap:12px;height:52px;width:100%;text-align:left;color:var(--soft);font:400 16px/1 var(--serif)}
.gl-pe-addsw{flex:none;width:34px;height:34px;border-radius:7px;display:grid;place-items:center;background:var(--s1,#171512);color:var(--faint)}
.gl-pe-acts{display:flex;gap:10px;margin-top:16px}
.gl-pe-acts .gl-pa-btn{flex:1;justify-content:center}
.gl-pe-save{flex:2}

/* pictures-only pins (painter page: Palettes off, or 4 and 5 across) */
.gl-pin.plain{contain:layout paint}
.gl-pin.plain .gl-im{height:100%}
