/* ----------------------------------------------------------------
   Custom color picker — popover, magnifier, and the visible swatch
   buttons that replace the native <input type="color"> elements.

   Theme contract: floats over the canvas, so MUST use opaque-dark
   var(--panel-bg) + var(--panel-border) (not glass). See
   DOC/SO_Architecture.md → Floating panel background.
   ---------------------------------------------------------------- */

/* ---- visible swatch button (replaces the hidden native input) ---- */
.cp-swatch {
  appearance: none;
  -webkit-appearance: none;
  width: 28px;
  height: 28px;
  min-width: 28px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 6px;
  padding: 0;
  margin: 0;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
  transition: transform 80ms ease-out, border-color 120ms ease-out;
}
.cp-swatch:hover {
  border-color: rgba(255, 255, 255, 0.4);
  transform: scale(1.05);
}
/* Suppress browser-default :focus outline (which renders dashed/dotted
   on Safari and was leaking through after a click). Show a clean ring
   only on `:focus-visible` (keyboard navigation). */
.cp-swatch:focus { outline: none; }
.cp-swatch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* The Find/Fill swatches inside the Color floatbar are larger glyph-
   like targets — match the .color-swatch sizing they replaced. */
.floatbar .cp-swatch,
.color-slider-stack ~ * .cp-swatch {
  width: 30px;
  height: 24px;
  border-radius: 5px;
}
/* Settings modal swatches are inline form controls — match row height. */
.settings-row .cp-swatch {
  width: 36px;
  height: 24px;
  border-radius: 5px;
}

/* ---- the popover ---- */
.cp-popover {
  position: fixed;
  width: 340px;
  background: var(--panel-bg);
  border: var(--panel-border);
  border-radius: 14px;
  box-shadow: var(--shadow), var(--glass-highlight);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 9000;
  color: #e7e7ea;
  font-size: 12px;
  user-select: none;
  -webkit-user-select: none;
}
.cp-popover[hidden] { display: none; }

/* Window-style drag — no idle cursor change. The popover keeps
   its normal cursor on hover; the grabbing hand only appears
   while a drag is actively in flight (cp-popover--dragging is
   added in js/color-picker.js _wireDrag on pointerdown / removed
   on pointerup). User feedback (2026-04-29): a grab cursor on
   plain hover over a popover that's normally stationary read as
   a false affordance — the popover only needs to communicate
   draggability mid-gesture. */
.cp-popover.cp-popover--dragging,
.cp-popover.cp-popover--dragging * { cursor: grabbing !important; }

/* Current/Previous swatch stack — vertical pair of `[label] [swatch]`
   rows that lives inside the right-hand RGB column, beneath the B
   slider. The Previous row is a <button> so it can be clicked /
   keyboard-activated to revert; all button chrome (border, padding,
   hover bg) is stripped via CSS so it visually reads as plain text +
   swatch. */
.cp-compare-stack {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* CRITICAL: the global `button { … }` rule in index.html sets
   border-radius:10px, box-shadow, backdrop-filter:blur(12px), padding,
   border, background, transition, AND a button:hover background fill —
   ALL of which leak through unless explicitly nulled here. Same goes
   for button:active{transform:translateY(1px)}. Class selectors only
   override properties they actually declare; missing properties from
   the global rule still apply. PITFALL: removing any of these resets
   will reintroduce the "giant black bar" look. */
.cp-compare-row {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 0;
  margin: 0;
  outline: none;
  font: inherit;
  transition: color 120ms ease-out;

  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  color: rgba(255, 255, 255, 0.78);
  font-size: 11px;
  line-height: 1.1;
}
.cp-compare-row:hover {
  background: transparent;
  border-color: transparent;
}
.cp-compare-row:active {
  transform: none;
}
.cp-was-row {
  cursor: pointer;
}
.cp-was-row:hover .cp-compare-label {
  color: #fff;
}
.cp-was-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}
.cp-now-row {
  cursor: default;
}
.cp-compare-swatch {
  flex: 0 0 auto;
  display: inline-block;
  width: 24px;
  height: 24px;
  border-radius: 5px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4);
}
.cp-compare-label {
  white-space: nowrap;
}

/* main — wheel on left, RGB column on right */
.cp-main {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.cp-left {
  flex: 0 0 auto;
}
.cp-right {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  /* Pushes the whole RGB stack (including the Current/Previous compare
     stack) down so the middle (G) row's vertical center sits on the
     disc's vertical center. Tuned against a 140 px disc + 17 px row
     height + 8 px gap. Adjust if row sizing changes. */
  margin-top: 33px;
}
/* HSV disc — Apple-style solid color wheel. The canvas is sized at
   devicePixelRatio resolution by JS; CSS keeps it at 140 CSS px on
   screen. The disc handle is a positioned <div> overlay so dragging
   doesn't trigger canvas redraws (only V changes do). */
.cp-left {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
}
.cp-disc-wrap {
  position: relative;
  width: 140px;
  height: 140px;
}
.cp-disc {
  display: block;
  width: 140px;
  height: 140px;
  cursor: crosshair;
  /* The disc has its own anti-aliased rim drawn in pixel data; no
     CSS border. Adding one would clip the AA falloff. */
}
.cp-disc-handle {
  position: absolute;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  margin-top: -6px;
  border-radius: 50%;
  border: 2px solid #000;
  outline: 1px solid #fff;
  pointer-events: none;
  left: 0;
  top: 0;
  /* Filled with the picked color via JS so the handle reads as a
     mini-swatch on top of the disc. Dual-ring outline (inner black,
     outer white) keeps it visible on every hue. */
}

/* Brightness (V) slider — horizontal track directly under the disc.
   Track gradient is set inline by JS to "(picked color at V=1) → black"
   per Apple spec. V=1 is on the LEFT, V=0 on the RIGHT. */
.cp-v-row {
  width: 140px;
  display: flex;
  align-items: center;
}
.cp-v-track-wrap {
  position: relative;
  width: 100%;
  height: 14px;
  cursor: pointer;
}
.cp-v-track {
  position: absolute;
  inset: 4px 0;
  border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.cp-v-thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid rgba(0, 0, 0, 0.55);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}

/* RGB rows */
.cp-rgb-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cp-rgb-label {
  width: 14px;
  text-align: center;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.7);
  font-size: 11px;
}
.cp-rgb-track-wrap {
  position: relative;
  flex: 1 1 auto;
  height: 14px;
  cursor: pointer;
  min-width: 0;
}
.cp-rgb-track {
  position: absolute;
  inset: 4px 0;
  border-radius: 6px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.cp-rgb-thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  border-radius: 50%;
  background: #fff;
  border: 2px solid rgba(0, 0, 0, 0.55);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}
/* Compound selector (`.cp-rgb-row .cp-rgb-input`) is REQUIRED to bump
   specificity above the global `.value-readout` rule defined in the
   inline <style> block in index.html. Both color-picker.css (loaded
   via <link>) and the inline <style> sit at single-class specificity
   for these rules, but the inline block loads AFTER this file so its
   `min-width: 36px` would win on a tie. The compound selector
   (specificity 0,0,2,0) beats `.value-readout` (0,0,1,0) regardless
   of source order. Do NOT collapse back to bare `.cp-rgb-input` — the
   slider stretch will silently break again. */
.cp-rgb-row .cp-rgb-input {
  /* Lower → slider longer, numbers further right.
     Higher → slider shorter, numbers further left.
     Practical floor ~24 px so 3-digit values like "255" don't clip. */
  width: 24px;
  min-width: 0;
  text-align: right;
  padding-right: 0;
}

/* Hex row — Finder/macOS-style click-to-rename. The span reads as
   plain monospace text on the panel by default with NO box, NO border,
   NO background — exactly how a file name renders on the Finder /
   home-screen until you click into it. On click the JS sets
   contenteditable="true" and the [contenteditable="true"] selector
   below adds a subtle accent-blue tint + tiny padding so the user
   knows they're now in rename mode. Mirrors the proven
   `.tab-strip-title[contenteditable="true"]` pattern in index.html. */
.cp-hex-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
.cp-hex-input {
  display: inline-block;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;

  color: rgba(255, 255, 255, 0.85);
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 12px;
  letter-spacing: 0.4px;
  text-transform: uppercase;

  cursor: pointer;
  outline: none;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 120ms ease-out;
}
.cp-hex-input:hover {
  color: #fff;
}
.cp-hex-input[contenteditable="true"] {
  background: rgba(107, 154, 255, 0.18);
  border-radius: 3px;
  padding: 0 4px;
  margin: 0 -4px;
  cursor: text;
  user-select: text;
  -webkit-user-select: text;
}

/* Regular palette row */
.cp-palette-regular,
.cp-palette-irregular {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: nowrap;
}
.cp-palette-slot,
.cp-irreg-slot,
.cp-palette-add,
.cp-eyedropper-btn {
  appearance: none;
  -webkit-appearance: none;
  width: 24px;
  height: 24px;
  min-width: 24px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 5px;
  padding: 0;
  margin: 0;
  cursor: pointer;
  background: rgba(0, 0, 0, 0.2);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.85);
  transition: transform 80ms ease-out, border-color 120ms ease-out;
  outline: none;
}
.cp-palette-slot:focus,
.cp-irreg-slot:focus,
.cp-palette-add:focus,
.cp-eyedropper-btn:focus { outline: none; }
.cp-palette-slot:focus-visible,
.cp-irreg-slot:focus-visible,
.cp-palette-add:focus-visible,
.cp-eyedropper-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.cp-palette-slot:hover,
.cp-irreg-slot[role="button"]:hover,
.cp-palette-add:hover,
.cp-eyedropper-btn:hover {
  border-color: rgba(255, 255, 255, 0.4);
  transform: scale(1.06);
}
/* PITFALL: index.html line 383 declares a global `.empty { position:
   absolute; inset: 0; display: flex; flex-direction: column; padding:
   20px; pointer-events: none; z-index: 2; gap: 12px; }` rule for the
   start-screen drop zone. The bare `.empty` selector matches every
   element carrying the `empty` class anywhere in the DOM — including
   our reserved blank palette slots — and because it's loaded after
   color-picker.css (inline <style> after <link>), it wins on every
   property at equal specificity. Without these explicit nulls, the
   blank slots get position:absolute + inset:0 + flex column + 20px
   padding, get pulled out of the irregular palette row, and stack on
   top of each other at the popover's top-left corner — exactly the
   "extra little dashed window" we kept retrying to identify. Do NOT
   remove these resets without first renaming the `empty` class on the
   picker side (e.g. `cp-slot-empty`) so the bare `.empty` selector
   stops matching. */
.cp-palette-slot.empty,
.cp-irreg-slot.empty {
  position: static;
  inset: auto;
  display: inline-flex;
  flex-direction: row;
  padding: 0;
  gap: 0;
  pointer-events: auto;
  z-index: auto;
  text-align: initial;

  background: rgba(255, 255, 255, 0.04);
  border-style: dashed;
  cursor: default;
}
.cp-palette-slot.empty:hover,
.cp-irreg-slot.empty:hover {
  transform: none;
  border-color: rgba(255, 255, 255, 0.18);
}
.cp-palette-slot:disabled {
  cursor: default;
}
.cp-palette-add {
  font-size: 16px;
  margin-left: 4px;
  background: rgba(107, 154, 255, 0.14);
  color: var(--accent);
  border-color: rgba(107, 154, 255, 0.35);
}
.cp-palette-add:hover {
  background: rgba(107, 154, 255, 0.22);
  border-color: var(--accent);
}
.cp-grayscale-slot {
  background: linear-gradient(135deg, #2a2a2f 0%, #d4d4d4 100%);
  cursor: pointer;
}
.cp-grayscale-slot.is-on {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35),
              0 0 0 2px rgba(107, 154, 255, 0.35);
}
.cp-grayscale-slot-hidden {
  visibility: hidden;
  pointer-events: none;
}
.cp-eyedropper-btn {
  margin-left: 4px;
}

/* Footer with Confirm button. Visual treatment matches the rest of
   the panel chrome — neutral border, subtle background, no accent
   fill. Sits at the bottom-right of the popover. See
   SO_UIChromeAndKeybinds.md → "Confirm-button contract" for the
   panel-button styling rules every confirm button in the app should
   follow. */
.cp-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 2px;
}
.cp-confirm {
  appearance: none;
  -webkit-appearance: none;
  height: 28px;
  padding: 0 16px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.92);
  font-size: 12px;
  cursor: pointer;
  outline: none;
  transition: background-color 120ms ease-out, border-color 120ms ease-out;
}
.cp-confirm:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.32);
}
.cp-confirm:focus { outline: none; }
.cp-confirm:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- magnifier (parented to document.body) ---- */
/* Floats above all app chrome — sidebars, floatbars, modals, popovers —
   via position:fixed + a very high z-index. Position is driven by JS:
   _magnifierTick sets transform on every RAF using viewport-relative
   clientX/Y, so left/top stay at 0 and the transform is the sole source
   of truth. No edge clamping — the loupe can extend over any UI surface. */
.cp-magnifier {
  position: fixed;
  left: 0;
  top: 0;
  transform: translate3d(0, 0, 0);
  will-change: transform;
  width: 120px;
  height: auto;
  z-index: 99999;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cp-magnifier[hidden] { display: none; }
.cp-magnifier-canvas {
  width: 120px;
  height: 120px;
  display: block;
  border-radius: 50%;
  background: var(--panel-bg);
  /* Two-tone ring: outer white halo for visibility on dark images,
     inner dark trace for visibility on bright images. Outset shadow
     lifts the loupe off the canvas. */
  box-shadow:
    0 0 0 2px rgba(255, 255, 255, 0.85),
    0 0 0 3px rgba(0, 0, 0, 0.55),
    0 4px 14px rgba(0, 0, 0, 0.45);
}
.cp-magnifier-hex {
  align-self: center;
  font: 11px ui-monospace, 'SF Mono', Menlo, monospace;
  color: #fff;
  letter-spacing: 0.5px;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  padding: 2px 8px;
}

/* ---- eyedropper context box (mounted inside .canvas-wrap) ---- */
/* Pinned to the canvas's top-left corner. Shows the area around the cursor
   at the canvas's normal view zoom (no magnification) so the user retains
   spatial orientation while the lens covers the work area. Sits below the
   existing .canvas-corner-bar.left button (~46 px tall). Opaque dark per
   the "Floating panel background" rule — surfaces over the canvas image
   never use glassmorphism (bright imports defeat low-alpha white). */
.cp-loupe-context {
  position: absolute;
  top: 56px;
  left: 10px;
  width: 96px;
  height: 96px;
  z-index: 40;            /* matches .canvas-corner-bar */
  pointer-events: none;   /* never blocks canvas clicks */
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
.cp-loupe-context[hidden] { display: none; }
.cp-loupe-context-canvas {
  width: 96px;
  height: 96px;
  display: block;
}

/* Layer-rule for high-DPI ring crispness — explicit width/height match
   so the canvas doesn't auto-stretch on Retina. The picker JS draws
   from a DPR-aware offscreen cache via drawImage(canvas, 0,0, 200,200). */

/* Empty-slot tooltip cursor (don't claim hover state). */
.cp-irreg-slot.empty:not([role="button"]) { cursor: default; }
