/* style — upload chips, paste, tag filter, point picker.
   One section of the old style.css. The pieces load in filename order
   and that order is the cascade, so do not rearrange them. */
/* ---------- video upload status chip on slot cards ---------- */
.slot-card .upl {
  position: absolute; bottom: 14px; left: 3px; z-index: 2;
  display: flex; align-items: center; gap: 3px;
  font-size: 7.5px; font-weight: 700; letter-spacing: .4px;
  background: rgba(0, 0, 0, .72); color: #ddd;
  border-radius: 3px; padding: 2px 6px; pointer-events: none;
}
.slot-card .upl.ok { color: var(--green, #6fd08c); padding: 2px 5px; }
.slot-card .upl.warn { color: var(--warn); }
/* Amber means it still works, just not the fast way. RED means pressing
   Generate produces an error and nothing else — the upload failed and the
   clip is too big to travel with the request instead. Two different
   outcomes; for a long time they shared one badge that described neither. */
.slot-card .upl.bad { color: #fff; background: var(--red, #ff6b6b); border-color: var(--red, #ff6b6b); }
/* AND THE TOOLTIP HAS TO BE REACHABLE. The badge is `pointer-events: none`
   so it never blocks a drag off the card — which also meant the title
   attribute explaining what went wrong could not be hovered, and the whole
   explanation was one word on a chip. The two states that have something to
   say take the pointer back; the plain one does not. */
.slot-card .upl.warn, .slot-card .upl.bad { pointer-events: auto; cursor: help; }
.upl-ring {
  width: 7px; height: 7px; flex: none;
  border: 1.5px solid rgba(255, 255, 255, .25); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .8s linear infinite;
}

/* gallery accepts dropped media files */
#gallery-pane.gal-dragover {
  outline: 2px dashed var(--accent); outline-offset: -4px; border-radius: var(--radius-sm);
}

/* ---------- pasting into the gallery ----------
   Ctrl+V has to land somewhere, and the honest way to say where is to show it.
   Clicking the gallery arms it and draws this line; clicking anything else
   takes it away again, so the prompt box keeps its own paste and you can see
   which of the two is listening. Quiet on purpose — it is a hint about where
   the keystroke will go, not a selection. */
#gallery-pane.gal-active {
  outline: 1px solid var(--border-dash); outline-offset: -3px; border-radius: var(--radius-sm);
}
/* One pulse when something lands, because the import is asynchronous and the
   tile does not appear for a moment — without this the keypress reads as a
   keypress that did nothing. */
#gallery-pane.gal-pasted {
  outline: 2px solid var(--accent); outline-offset: -3px;
  animation: galPasted .42s ease-out;
}
@keyframes galPasted {
  from { background: rgba(var(--accent-rgb), .16); }
  to   { background: transparent; }
}
/* The editable the right-click Paste pastes into. It has to be focusable and
   contenteditable for execCommand('paste') to fire at all, so it cannot be
   display:none — it is 1px and out of the way instead. */
/* Clipped rather than parked off-screen: a -9999px child inside a sticky,
   scrolling pane is a way to give an ancestor a horizontal scrollbar. */
#gal-paste-sink {
  position: absolute; top: 0; left: 0;
  width: 1px; height: 1px; overflow: hidden; opacity: 0;
  clip-path: inset(50%); white-space: nowrap; pointer-events: none;
}
.gal-ctx {
  position: fixed; z-index: 420;
  background: #17171b; border: 1px solid var(--border); border-radius: 3px;
  padding: 4px; min-width: 132px;
  box-shadow: 0 12px 36px rgba(0, 0, 0, .65);
}
.gal-ctx button {
  display: block; width: 100%; text-align: left;
  background: none; border: none; border-radius: 3px;
  color: var(--text); font-family: inherit; font-size: 11.5px;
  padding: 6px 9px; cursor: pointer;
}
.gal-ctx button:hover { background: var(--accent); color: #fff; }
/* the tag menu: what this one already carries, then everything else */
.gal-ctx.tagm { max-height: 320px; overflow-y: auto; min-width: 156px; }
.gal-ctx.tagm button.on { color: var(--accent); font-weight: 700; }
.gal-ctx.tagm button.on:hover { color: #fff; }
.gal-ctx.tagm button.dim { opacity: .6; }
.gal-ctx.tagm button.new { border-top: 1px solid var(--border); border-radius: 0 0 3px 3px; margin-top: 3px; color: var(--text-dim); }

/* ---------- gallery tag filter ---------- */
/* A row of tags under the gallery head. Each one cycles: off → only these →
   all but these. Three states in one control because "everything except the
   batch" is asked as often as "only the batch", and a checkbox can only ever
   ask one of the two. */
#gal-tags {
  display: flex; flex-wrap: wrap; gap: 4px;
  padding: 5px 8px 2px; border-bottom: 1px solid var(--border);
}
#gal-tags.hidden { display: none; }
#gal-tags:empty { display: none; }
.gtag {
  background: none; border: 1px solid var(--border); border-radius: 3px;
  color: var(--text-faint); font-family: inherit; font-size: 9.5px; font-weight: 700;
  letter-spacing: .2px; padding: 2px 8px; cursor: pointer; white-space: nowrap;
}
.gtag:hover { color: var(--text); border-color: #4a4a55; }
.gtag.inc { background: var(--accent); border-color: var(--accent); color: #fff; }
.gtag.exc { border-color: #7a3b4b; color: #ff9bb0; text-decoration: line-through; }
.gtag.isbatch { border-style: dashed; }
.gtag.isbatch.inc, .gtag.isbatch.exc { border-style: solid; }
.gtag.clear { color: var(--text-dim); border-color: transparent; text-decoration: underline; }

/* ---------- the point picker ---------- */
/* subject-point button overlaying the clip thumbnail */
.slot-card .rm.pts {
  top: 3px; left: 3px; right: auto; width: 20px; height: 20px;
  background: rgba(0, 0, 0, .72); color: #fff;
}
.slot-card .rm.pts:hover { background: var(--accent); }
.slot-card .rm.pts.on { background: var(--accent); }
.slot-card .rm.pts svg { display: block; }
.slot-card .pts-count {
  position: absolute; top: 3px; left: 26px; z-index: 2;
  min-width: 15px; height: 15px; padding: 0 3px; border-radius: 3px;
  background: var(--accent); color: #fff; font-size: 9px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
#pointpick {
  position: fixed; inset: 0; z-index: var(--z-rail);
  background: var(--chrome-blur-bg);
  display: flex; flex-direction: column; padding: 12px;
}
/* The Luma keyframe room. Same shape as #pointpick above — it is the other
   room a node opens into the viewer — and it needs its own rule for the same
   reason: without one it is a plain static block, which inside an absolutely
   positioned tool host means "as tall as my content happens to be". Measured
   before this existed: a 377px room in a 295px host, its scrub bar sitting at
   y=426 under the panel seam's .nle-grip, so pressing the bar hit the grip and
   no keyframe was ever pinned. The host is the box; the timeline scrolls
   inside it. */
#lumatl {
  position: fixed; inset: 0; z-index: var(--z-rail);
  background: var(--chrome-blur-bg);
  display: flex; flex-direction: column; padding: 12px;
}
#lumatl .luma-kf-host {
  flex: 1; min-height: 0; overflow: auto;
  display: flex; flex-direction: column;
}
/* In the make panel this timeline sits in a column that scrolls, so its
   parts can be their natural height and the player can be 280px tall. Here
   the height is whatever the viewer panel has left, and the player is the
   only part that can give: the bar, the chip row and the hint ARE the
   controls, and a room that pushes its scrub bar below the fold is a room
   you cannot scrub. So the stage takes the slack and the picture is
   letterboxed into it. */
#lumatl .luma-stage { flex: 1 1 auto; min-height: 90px; }
/* Everything else keeps its own height. Without this the bar is a flex item
   like any other and gives up pixels too — measured at 23px against its
   designed 26 — and the chip row under it is worse, because a squashed
   thumbnail row is a keyframe you cannot read. */
#lumatl .luma-kf-host > .slot-label,
#lumatl .luma-kf-host > .luma-bar,
#lumatl .luma-kf-host > .kf-row,
#lumatl .luma-kf-host > .adh,
#lumatl .luma-kf-host > .hint { flex: none; }
#lumatl .luma-vid {
  position: absolute; left: 0; top: 0; right: 0; bottom: 0;
  width: 100%; height: 100%; max-height: none; object-fit: contain;
}
.pp-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.pp-mode { display: flex; gap: 4px; background: var(--card); border: 1px solid var(--border); border-radius: 3px; padding: 3px; }
.pp-modebtn {
  border: none; border-radius: 3px; cursor: pointer; background: none;
  color: var(--text-dim); font-size: 10.5px; font-weight: 600; padding: 4px 12px;
}
.pp-modebtn.active { background: #fff; color: #111; }
#pp-stage { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: auto; }
/* The wheel over the frame while the segmenter is thinking — see ppBusy.
   Absolute over the stage rather than drawn into the canvas, so it animates
   without a redraw and cannot be wiped by the next ppRedraw. */
#pp-stage { position: relative; }
#pp-spin {
  position: absolute; left: 50%; top: 50%; width: 26px; height: 26px;
  margin: -13px 0 0 -13px; border-radius: 50%; pointer-events: none; z-index: 3;
  border: 2px solid rgba(255,255,255,.26);
  border-top-color: var(--accent, #E50A4E);
  box-shadow: 0 0 0 1px rgba(0,0,0,.35), 0 2px 10px rgba(0,0,0,.5);
  animation: ppSpin .72s linear infinite;
}
@keyframes ppSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  #pp-spin { animation: ppPulse 1.1s ease-in-out infinite; }
  @keyframes ppPulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } }
}
#pp-canvas {
  max-width: 100%; max-height: 100%;
  border: 1px solid var(--border-dash); border-radius: 3px; background: #000; cursor: crosshair;
}
