feat(web-ui): style the asset right-click menu (.ctx-menu)

The AssetContextMenu in screens-library.jsx has shipped without
matching styles, so the menu rendered as raw HTML on the page. Adds
.ctx-menu / .ctx-header / .ctx-divider / .ctx-section-label / .ctx-empty
plus button + danger styles matching the existing .row-menu look.

/* ========== Projects ========== */
.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 14px;
}
.project-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  cursor: pointer;
  transition: transform 120ms, border 80ms;
}
.project-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-stronger);
}
.project-thumb-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 2px;
  aspect-ratio: 16 / 9;
  background: var(--bg-2);
}
.project-thumb-grid .project-thumb-cell:first-child { grid-row: span 2; }
.project-thumb-cell { position: relative; overflow: hidden; background: var(--bg-2); }
.project-thumb-cell .thumb-svg { width: 100%; height: 100%; }
.project-card-body { padding: 12px 14px; }
.project-meta {
  display: flex; gap: 6px;
  font-size: 11.5px; color: var(--text-3);
  margin-top: 4px;
}
.project-bar {
  margin-top: 10px;
  display: flex;
  height: 4px;
  border-radius: 99px;
  overflow: hidden;
  background: var(--bg-3);
  gap: 1px;
}

/* ========== Upload ========== */
.field-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-4);
  display: block;
  margin-bottom: 6px;
}
.select-faux, .field-input {
  height: 34px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0 10px;
  display: flex; align-items: center; gap: 8px;
  color: var(--text-1);
  font-size: 12.5px;
  width: 100%;
  cursor: pointer;
}
.field-input { font-size: 12.5px; outline: 0; }
.field-input:focus { border-color: var(--accent); background: var(--bg-2); }
.field-input.select { justify-content: space-between; }

.dropzone {
  background: var(--bg-1);
  border: 1.5px dashed var(--border-stronger);
  border-radius: var(--r-lg);
  padding: 40px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: background 120ms, border 120ms;
}
.dropzone:hover { background: var(--bg-2); border-color: var(--accent); }
.dropzone-formats { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; justify-content: center; }
.upload-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.upload-row:last-child { border-bottom: 0; }

/* ========== Recorders ========== */
.recorders-list { display: flex; flex-direction: column; gap: 10px; }
.recorder-row {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 12px;
  display: grid;
  grid-template-columns: 220px 1fr 380px auto;
  align-items: center;
  gap: 16px;
  transition: border 80ms;
}
.recorder-row:hover { border-color: var(--border-stronger); }
.recorder-row.recording { border-color: rgba(255,59,48,0.25); }
.recorder-row.error { border-color: rgba(255,91,91,0.25); }
.recorder-preview {
  height: 56px;
  border-radius: var(--r-sm);
  background: var(--bg-2);
  overflow: hidden;
  position: relative;
}
.recorder-empty {
  height: 100%;
  display: grid; place-items: center;
  color: var(--text-3);
}
.recorder-audio-prev {
  height: 100%;
  display: flex; align-items: center; gap: 10px;
  padding: 0 12px;
}
.recorder-audio-prev .waveform { flex: 1; height: 80%; }
.recorder-info { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.recorder-sub {
  font-size: 11.5px;
  color: var(--text-3);
  display: flex; gap: 6px;
}
.recorder-sub.mono { font-family: var(--font-mono); font-size: 11px; }
.recorder-stats {
  display: grid;
  grid-template-columns: 90px 90px 1fr;
  gap: 12px;
}
.recorder-stat .stat-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--text-4);
  margin-bottom: 3px;
}
.recorder-stat .stat-val { font-size: 12.5px; }
.recorder-actions { display: flex; align-items: center; gap: 4px; }
.rec-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
}

/* ========== Capture / DeckLink ========== */
.decklink-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.decklink-head {
  padding: 14px 16px;
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px solid var(--border);
}
.decklink-body {
  padding: 24px;
  display: grid;
  grid-template-columns: 60px 1fr;
  gap: 20px;
  align-items: stretch;
  background:
    radial-gradient(ellipse at top, rgba(91,124,250,0.05), transparent 60%),
    var(--bg-0);
}
.decklink-card-face {
  background: linear-gradient(180deg, #1c1f28, #0d0e13);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  display: flex; flex-direction: column;
  justify-content: space-between;
  padding: 12px 6px;
  position: relative;
}
.decklink-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.12em;
  color: var(--text-3);
  text-align: center;
  margin: 0 auto;
}
.decklink-leds {
  display: flex; gap: 6px;
  justify-content: center;
}
.decklink-led {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(255,255,255,0.1);
}
.decklink-led.on {
  background: var(--success);
  box-shadow: 0 0 6px var(--success);
}
.bnc-ports { display: flex; flex-direction: column; gap: 10px; }
.bnc-port {
  display: grid;
  grid-template-columns: 32px 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: background 80ms, border 80ms;
}
.bnc-port:hover { border-color: var(--border-stronger); }
.bnc-port.active { background: var(--bg-3); }
.bnc-port.active.live::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--success);
}
.bnc-port.recording::before { background: var(--live); }
.bnc-port.active { box-shadow: inset 0 0 0 1px var(--accent); border-color: var(--accent); }
.bnc-connector {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: radial-gradient(circle, #1a1d24, #0a0c11);
  display: grid; place-items: center;
  border: 1.5px solid var(--border-stronger);
  position: relative;
}
.bnc-pin {
  width: 6px; height: 6px;
  background: linear-gradient(135deg, #6b7280, #2a2f3a);
  border-radius: 50%;
}
.bnc-ring {
  position: absolute;
  inset: 4px;
  border: 1px dashed rgba(255,255,255,0.08);
  border-radius: 50%;
}
.bnc-port.live .bnc-pin { background: linear-gradient(135deg, #FFC857, #C8862D); box-shadow: 0 0 8px rgba(255,200,87,0.4); }
.bnc-port.recording .bnc-pin { background: linear-gradient(135deg, #FF5C5C, #C8362D); box-shadow: 0 0 8px rgba(255,92,92,0.5); }
.bnc-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.bnc-num { font-size: 12.5px; font-weight: 600; }
.bnc-label { font-size: 11px; color: var(--text-2); }
.bnc-sig { font-size: 10.5px; color: var(--text-3); }
.bnc-port.live .bnc-sig { color: var(--success); }
.bnc-rec {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--live);
  animation: pulse 1.2s ease-in-out infinite;
}
.bnc-signal-bar {
  grid-column: 2 / 4;
  height: 3px;
  background: var(--bg-3);
  border-radius: 99px;
  overflow: hidden;
  margin-top: 4px;
}
.bnc-signal-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--success), var(--warning), var(--danger));
  background-size: 200% 100%;
  background-position: 0% 0;
  transition: width 200ms;
}
.decklink-foot {
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  display: flex; gap: 20px;
  font-size: 11.5px;
  color: var(--text-3);
}
.decklink-foot strong { color: var(--text-1); font-weight: 600; }

.capture-detail {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px;
}
.capture-detail.empty {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 80px 24px;
  color: var(--text-3);
}
.capture-preview {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-md);
  overflow: hidden;
  background: #000;
}
.capture-overlay-meters {
  position: absolute;
  right: 8px; top: 8px;
  display: flex; gap: 4px;
}
.capture-tc {
  position: absolute;
  bottom: 8px; right: 8px;
  background: rgba(0,0,0,0.7);
  padding: 3px 8px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: white;
}
.capture-stats {
  margin-top: 16px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.capture-stat {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 8px 10px;
}
.capture-stat-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  color: var(--text-4);
}
.capture-stat-value { font-size: 13px; margin-top: 2px; }

/* ========== Monitors ========== */
.monitors-grid {
  display: grid;
  gap: 10px;
  background: var(--bg-2);
  border-radius: var(--r-lg);
  padding: 10px;
}
.monitor-tile {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  display: flex; flex-direction: column;
  cursor: pointer;
}
.monitor-tile.audio { background: linear-gradient(135deg, hsl(180 30% 12%), hsl(200 25% 6%)); }
.monitor-tile-label {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  padding: 8px 10px;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,0.8));
  display: flex; align-items: center; gap: 6px;
}
.monitor-tile-label .name {
  color: white;
  font-size: 11.5px;
  font-weight: 500;
}
.monitor-tile-label .time {
  margin-left: auto;
  color: white;
  font-family: var(--font-mono);
  font-size: 10.5px;
}

/* ========== Jobs ========== */
.jobs-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.job-row {
  display: grid;
  grid-template-columns: 20px 110px 1fr 90px 200px 70px 80px 90px;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}
.job-row:last-child { border-bottom: 0; }
.job-row.head {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-4);
}
.job-progress-wrap {
  display: flex; align-items: center; gap: 8px;
}
.job-progress-bar {
  flex: 1;
  height: 5px;
  background: var(--bg-3);
  border-radius: 99px;
  overflow: hidden;
  position: relative;
}
.job-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), #7C9EFF);
  background-size: 200% 100%;
  animation: shimmer 2s linear infinite;
  transition: width 300ms;
}

/* ========== Editor ========== */
.editor-shell {
  display: flex; flex-direction: column;
  height: 100%;
  background: var(--bg-0);
}
.editor-topbar {
  height: 44px;
  border-bottom: 1px solid var(--border);
  padding: 0 14px;
  display: flex; align-items: center; gap: 10px;
}
.editor-body {
  flex: 1;
  display: grid;
  grid-template-columns: 240px 1fr 240px;
  min-height: 0;
}
.editor-bins, .editor-insp { background: var(--bg-1); border-right: 1px solid var(--border); overflow-y: auto; }
.editor-insp { border-right: 0; border-left: 1px solid var(--border); }
.editor-bin-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px;
  border-radius: var(--r-sm);
  cursor: pointer;
}
.editor-bin-item:hover { background: var(--hover); }
.editor-bin-thumb { width: 48px; aspect-ratio: 16/9; border-radius: 3px; overflow: hidden; background: var(--bg-2); flex-shrink: 0; }
.editor-viewer { background: #000; display: flex; flex-direction: column; }
.editor-canvas {
  flex: 1;
  position: relative;
  background: #050608;
  display: grid; place-items: center;
  overflow: hidden;
  max-height: 50vh;
}
.editor-canvas .thumb-svg { width: 100%; height: 100%; }
.editor-transport {
  height: 44px;
  display: flex; align-items: center; gap: 8px;
  padding: 0 14px;
  background: var(--bg-1);
  border-top: 1px solid var(--border);
}
.editor-timeline {
  background: var(--bg-0);
  border-top: 1px solid var(--border);
  height: 240px;
  display: flex; flex-direction: column;
  position: relative;
  overflow: hidden;
}
.editor-timeline-head {
  height: 32px;
  display: flex; align-items: center;
  padding: 0 12px;
  gap: 8px;
  border-bottom: 1px solid var(--border);
}
.timeline-ruler {
  height: 22px;
  display: flex;
  padding-left: 40px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-1);
}
.ruler-tick {
  flex: 1;
  border-left: 1px solid var(--border);
  font-size: 9.5px;
  color: var(--text-4);
  padding: 4px 4px 0;
}
.timeline-track {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: stretch;
  height: 42px;
  border-bottom: 1px solid var(--border);
}
.timeline-track-label {
  background: var(--bg-1);
  display: grid; place-items: center;
  font-size: 10.5px;
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text-3);
  border-right: 1px solid var(--border);
}
.timeline-track-lane {
  position: relative;
  background:
    repeating-linear-gradient(90deg, transparent 0 49px, rgba(255,255,255,0.02) 49px 50px);
}
.clip {
  position: absolute;
  top: 4px; bottom: 4px;
  border-radius: 3px;
  overflow: hidden;
  display: flex; align-items: center;
  cursor: pointer;
  border: 1px solid rgba(0,0,0,0.3);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.15);
}
.clip-label {
  position: absolute;
  left: 6px; top: 3px;
  font-size: 10px;
  font-weight: 600;
  color: white;
  z-index: 2;
  text-shadow: 0 1px 1px rgba(0,0,0,0.4);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.clip-film { display: flex; flex: 1; height: 100%; }
.clip-film-cell { flex: 1; overflow: hidden; }
.clip-film-cell .thumb-svg { width: 100%; height: 100%; }
.clip.audio { background: var(--success) !important; }
.clip-wave { width: 100%; height: 100%; padding: 4px; opacity: 0.6; }
.clip-wave .waveform { width: 100%; height: 100%; }
.timeline-playhead {
  position: absolute;
  top: 32px; bottom: 0;
  width: 1.5px;
  background: var(--live);
  pointer-events: none;
  z-index: 5;
}
.timeline-playhead::before {
  content: "";
  position: absolute;
  top: -4px; left: 50%;
  width: 10px; height: 10px;
  background: var(--live);
  transform: translateX(-50%) rotate(45deg);
}

/* ========== Admin tables ========== */
/* ── Row popover menu (Users, etc.) ────────────────────────────────── */
.row-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  min-width: 180px;
  background: var(--bg-1);
  border: 1px solid var(--border-stronger);
  border-radius: 6px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  padding: 4px;
  display: flex;
  flex-direction: column;
}
.row-menu button {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: 0;
  color: var(--text-1);
  font-size: 12.5px;
  padding: 7px 10px;
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
}
.row-menu button:hover { background: var(--bg-3); }
.row-menu button.danger:hover { background: var(--danger-soft); color: var(--danger); }

.user-row, .token-row, .container-row, .schedule-row {
  display: grid;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}
.user-row { grid-template-columns: 1.5fr 100px 1.5fr 120px 40px; }
.token-row { grid-template-columns: 1.4fr 1.4fr 110px 110px 100px 40px; }
.container-row { grid-template-columns: 1.4fr 1.4fr 140px 140px 100px 1.4fr 110px; }
.schedule-row { grid-template-columns: 1.6fr 1.2fr 1.2fr 90px 110px 110px 150px; }
.user-row.head, .token-row.head, .container-row.head, .schedule-row.head {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-4);
}
.user-row:last-child, .token-row:last-child, .container-row:last-child, .schedule-row:last-child { border-bottom: 0; }
.token-row.revoked { opacity: 0.5; }

/* ========== Cluster ========== */
.cluster-canvas {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}

/* ========== Settings ========== */
.settings-nav {
  display: flex; flex-direction: column; gap: 2px;
  position: sticky; top: 0;
}
.settings-nav-item {
  display: flex; align-items: center; gap: 8px;
  padding: 0 10px;
  height: 32px;
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: 12.5px;
  cursor: pointer;
}
.settings-nav-item:hover { background: var(--hover); color: var(--text-1); }
.settings-nav-item.active { background: var(--accent-soft); color: var(--accent-text); }
.settings-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.settings-card-head {
  padding: 16px;
  display: flex; align-items: flex-start; gap: 12px;
  border-bottom: 1px solid var(--border);
}
.settings-card-icon {
  width: 36px; height: 36px;
  border-radius: var(--r-sm);
  background: var(--accent-soft);
  color: var(--accent);
  display: grid; place-items: center;
  flex-shrink: 0;
}
.settings-card-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field-input-wrap { display: flex; gap: 6px; align-items: center; }
.checkbox-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--text-1);
  cursor: pointer;
}
.checkbox-row input { accent-color: var(--accent); }

/* ========== Tokens parody ========== */
.token-hero {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 14px;
  margin-bottom: 16px;
}
.token-burn-card, .token-actual-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 18px 20px;
  position: relative;
  overflow: hidden;
}
.token-burn-card {
  background:
    radial-gradient(ellipse at top right, rgba(255,91,91,0.12), transparent 60%),
    var(--bg-1);
  border-color: rgba(255,91,91,0.18);
}
.token-actual-card {
  background:
    radial-gradient(ellipse at bottom left, rgba(45,212,168,0.10), transparent 60%),
    var(--bg-1);
  border-color: rgba(45,212,168,0.18);
}
.token-card-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--text-4);
  margin-bottom: 8px;
}
.token-counter {
  display: flex; align-items: baseline; gap: 12px;
}
.token-flame { font-size: 32px; line-height: 1; }
.token-big {
  font-size: 48px;
  font-weight: 700;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, #FF9D6B, #FF5B5B);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  line-height: 1.05;
}
.token-rate {
  font-size: 12px;
  display: flex; align-items: baseline;
  font-family: var(--font-mono);
}
.token-actual-amount {
  display: flex; align-items: baseline; gap: 0;
  color: var(--success);
  margin-bottom: 8px;
}

.token-comparison {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 0 0 12px;
  margin-bottom: 16px;
  overflow: hidden;
}
.token-compare-chart { padding: 0 16px; }
.token-compare-legend {
  display: flex; gap: 24px;
  padding: 8px 0 0;
  font-size: 12px;
  color: var(--text-2);
}
.token-compare-legend .dot {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
}

.token-grid {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 14px;
}
.token-event {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.token-event:last-child { border-bottom: 0; }
.token-event.fresh { animation: tokenFresh 800ms ease; }
@keyframes tokenFresh {
  0% { background: rgba(255,91,91,0.15); transform: translateX(-4px); }
  100% { background: transparent; transform: none; }
}
.token-tiers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.token-tier {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px 14px;
  display: flex; flex-direction: column;
  gap: 6px;
  position: relative;
}
.token-tier.popular {
  border-color: var(--accent);
  background: linear-gradient(180deg, var(--accent-soft) 0%, var(--bg-1) 40%);
  box-shadow: 0 0 24px rgba(91,124,250,0.10);
}
.token-tier-badge {
  position: absolute;
  top: -8px; right: 12px;
  background: var(--accent);
  color: white;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  border-radius: 99px;
}
.token-tier-name { font-size: 13px; font-weight: 700; letter-spacing: -0.01em; }
.token-tier-desc { font-size: 11px; color: var(--text-3); min-height: 32px; line-height: 1.4; }
.token-tier-price { margin-top: 6px; display: flex; align-items: baseline; }
.token-tier-tokens { font-size: 11px; color: var(--text-3); padding-top: 4px; border-top: 1px solid var(--border); }

.token-footnote {
  margin-top: 20px;
  padding: 14px 16px;
  background: var(--warning-soft);
  border: 1px solid rgba(245,166,35,0.2);
  border-radius: var(--r-md);
  display: flex; gap: 12px;
  font-size: 12.5px;
  color: var(--text-2);
  line-height: 1.55;
}
.token-footnote svg { color: var(--warning); flex-shrink: 0; margin-top: 2px; }
.token-footnote strong { color: var(--warning); }

/* ========== Global Search ========== */
.search-wrap {
  position: relative;
  flex-shrink: 0;
}
.search-wrap .search {
  width: 280px;
}
.search-wrap .search.is-open {
  border-color: var(--accent);
  background: var(--bg-2);
}
.search-results {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: 440px;
  max-width: 90vw;
  max-height: 460px;
  overflow-y: auto;
  background: var(--bg-1);
  border: 1px solid var(--border-stronger);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  padding: 4px;
  z-index: 60;
}
.search-empty {
  padding: 18px 12px;
  text-align: center;
  font-size: 12px;
  color: var(--text-3);
}
.search-result {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  color: var(--text-1);
}
.search-result.active {
  background: var(--accent-soft);
}
.search-result-icon {
  width: 24px; height: 24px;
  border-radius: 5px;
  background: var(--bg-3);
  color: var(--text-2);
  display: grid; place-items: center;
  flex-shrink: 0;
}
.search-result.active .search-result-icon {
  background: var(--accent-soft-2);
  color: var(--accent-text);
}
.search-result-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.search-result-label {
  font-size: 12.5px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-result-sub {
  font-size: 11px;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.search-result-kind {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-4);
  background: var(--bg-2);
  border: 1px solid var(--border);
  padding: 2px 6px;
  border-radius: 99px;
  flex-shrink: 0;
}
.search-result-kind.kind-asset { color: #B4C3FF; border-color: rgba(91,124,250,0.25); }
.search-result-kind.kind-project { color: #FFD89B; border-color: rgba(245,166,35,0.25); }
.search-result-kind.kind-recorder { color: #FFAFAF; border-color: rgba(255,91,91,0.25); }
.search-result-kind.kind-job { color: #9EE7D2; border-color: rgba(45,212,168,0.25); }
.search-result-kind.kind-user { color: #D5B8FF; border-color: rgba(181,124,250,0.25); }
.search-result-kind.kind-nav { color: var(--text-2); }

/* ========== Asset right-click menu ========== */
.ctx-menu {
  position: fixed;
  z-index: 80;
  min-width: 220px;
  max-width: 280px;
  background: var(--bg-1);
  border: 1px solid var(--border-stronger);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  padding: 4px;
  display: flex;
  flex-direction: column;
  font-size: 12.5px;
}
.ctx-menu .ctx-header {
  padding: 8px 10px 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ctx-menu .ctx-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 2px;
}
.ctx-menu .ctx-section-label {
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-4);
  padding: 6px 10px 4px;
}
.ctx-menu .ctx-empty {
  padding: 6px 10px 10px;
  font-size: 11.5px;
  color: var(--text-3);
  font-style: italic;
}
.ctx-menu button {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: 0;
  color: var(--text-1);
  font-size: 12.5px;
  padding: 7px 10px;
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.ctx-menu button svg { color: var(--text-3); flex-shrink: 0; }
.ctx-menu button:hover:not(:disabled) { background: var(--bg-3); }
.ctx-menu button:hover:not(:disabled) svg { color: var(--text-1); }
.ctx-menu button:disabled {
  opacity: 0.5;
  cursor: default;
}
.ctx-menu button.danger { color: var(--danger); }
.ctx-menu button.danger svg { color: var(--danger); }
.ctx-menu button.danger:hover:not(:disabled) {
  background: var(--danger-soft);
}


OK | commit:f474a77 | Updated services/web-ui/public/styles-rest.css


right click menu looks awful , aslo the search bar at the top of the screen still appears to be broken.


Wire up search bar and add right-click context menu


Now I need to rebuild the web-ui container. Finding the docker-compose project directory:


docker inspect wild-dragon-web-ui-1 --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'


$ docker inspect wild-dragon-web-ui-1 --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'

/mnt/NVME/MAM/wild-dragon


cd /mnt/NVME/MAM/wild-dragon && git remote -v && git status -s && git log -1 --oneline


$ cd /mnt/NVME/MAM/wild-dragon && git remote -v && git status -s && git log -1 --oneline

origin	ssh://git@forgejo-local/zgaetano/dragonflight.git (fetch)
origin	ssh://git@forgejo-local/zgaetano/dragonflight.git (push)
f186cde polish(ui): wire dead buttons across asset detail, shell, containers, cluster


cd /mnt/NVME/MAM/wild-dragon && git fetch && git log HEAD..origin/main --oneline


$ cd /mnt/NVME/MAM/wild-dragon && git fetch && git log HEAD..origin/main --oneline

f474a77 feat(web-ui): style the asset right-click menu (.ctx-menu)
[stderr]
From ssh://forgejo-local/zgaetano/dragonflight
   f186cde..f474a77  main       -> origin/main


Find the running web-ui container & verify what shell.jsx it serves

Finding the running web-ui container & verifying what shell.jsx it serves

Diagnose why search bar still appears broken

Diagnosing why search bar still appears broken

Add CSS for existing .ctx-menu (right-click menu)

Adding CSS for existing .ctx-menu (right-click menu)

Push fixes to forgejo


cd /mnt/NVME/MAM/wild-dragon && git log origin/main --oneline -10


$ cd /mnt/NVME/MAM/wild-dragon && git log origin/main --oneline -10

f474a77 feat(web-ui): style the asset right-click menu (.ctx-menu)
f186cde polish(ui): wire dead buttons across asset detail, shell, containers, cluster
630dc75 fix(web-ui): hide search wrapper (with dropdown) on narrow screens
899876c feat(web-ui): style global search dropdown
61d02d5 feat(web-ui): pass search-select handlers from App to Topbar
45c0e0f feat(web-ui): wire global search in topbar with results dropdown
992fbdf fix(recorders,library): empty-capture handling + right-click context menu
9877ed3 fix(recorders): queue proxy on finalize + custom clip names
b128c9f fix(metrics): use real job_status enum values (queued/processing/complete)
ef4c301 feat(home,users): real metrics, working Users row actions + Groups CRUD


All my prior search commits ARE in origin/main — they're just not in the container yet. Pull and rebuild:


cd /mnt/NVME/MAM/wild-dragon && git pull --ff-only


$ cd /mnt/NVME/MAM/wild-dragon && git pull --ff-only

Updating f186cde..f474a77
Fast-forward
 services/web-ui/public/styles-rest.css | 72 ++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)


cd /mnt/NVME/MAM/wild-dragon && grep -c 'GlobalSearch' services/web-ui/public/shell.jsx; grep -c 'ctx-menu' services/web-ui/public/styles-rest.css; grep -c 'search-wrap' services/web-ui/public/styles-rest.css


$ cd /mnt/NVME/MAM/wild-dragon && grep -c 'GlobalSearch' services/web-ui/public/shell.jsx; grep -c 'ctx-menu' services/web-ui/public/styles-rest.css; grep -c 'search-wrap' services/web-ui/public/styles-rest.css

3
13
3


Files are good. Rebuilding the web-ui container now:


cd /mnt/NVME/MAM/wild-dragon && docker compose build web-ui 2>&1 | tail -40


$ cd /mnt/NVME/MAM/wild-dragon && docker compose build web-ui 2>&1 | tail -40

#12 [css-build 4/8] RUN npm install --no-audit --no-fund
#12 CACHED

#13 [css-build 6/8] COPY src/ ./src/
#13 CACHED

#14 [css-build 7/8] COPY public/ ./public/
#14 DONE 0.2s

#15 [css-build 8/8] RUN npx postcss ./src/css/app.css -o ./public/dist/app.css --env production
#15 1.078
#15 1.078 🚀   flyonui 1.3.1
#15 1.208 ├─ ✔ 2 themes added		https://flyonui.com/docs/customization/themes/
#15 1.208 ╰─ ★ Star FlyonUI on GitHub		https://github.com/themeselection/flyonui
#15 1.208
#15 1.270
#15 1.270 warn - The safelist pattern `/^wd-/` doesn't match any Tailwind CSS classes.
#15 1.270 warn - Fix this pattern or remove it from your `safelist` configuration.
#15 1.270 warn - https://tailwindcss.com/docs/content-configuration#safelisting-classes
#15 DONE 1.8s

#7 [stage-1 1/3] FROM docker.io/library/nginx:alpine
#7 CACHED

#16 [stage-1 2/3] COPY --from=css-build /build/public/ /usr/share/nginx/html/
#16 DONE 0.2s

#17 [stage-1 3/3] COPY nginx.conf /etc/nginx/conf.d/default.conf
#17 DONE 0.2s

#18 exporting to image
#18 exporting layers
#18 exporting layers 0.2s done
#18 writing image sha256:79cb23d78a56528b187a4ed847193a55914b7090e531e06e4b8671615f17e962 done
#18 naming to docker.io/library/wild-dragon-web-ui 0.0s done
#18 DONE 0.2s

#19 resolving provenance for metadata file
#19 DONE 0.0s
 web-ui  Built


cd /mnt/NVME/MAM/wild-dragon && docker compose up -d web-ui 2>&1 | tail -10 && sleep 2 && docker exec wild-dragon-web-ui-1 grep -c 'GlobalSearch' /usr/share/nginx/html/shell.jsx && docker exec wild-dragon-web-ui-1 grep -c 'ctx-menu' /usr/share/nginx/html/styles-rest.css


$ cd /mnt/NVME/MAM/wild-dragon && docker compose up -d web-ui 2>&1 | tail -10 && sleep 2 && docker exec wild-dragon-web-ui-1 grep -c 'GlobalSearch' /usr/share/nginx/html/shell.jsx && docker exec wild-dragon-web-ui-1 grep -c 'ctx-menu' /usr/share/nginx/html/styles-rest.css

 Container wild-dragon-web-ui-1  Recreate
 Container wild-dragon-web-ui-1  Recreated
 Container wild-dragon-web-ui-1  Starting
 Container wild-dragon-web-ui-1  Started
3
13


Container redeployed. Let me verify with a screenshot against the actual host.


ip -4 -o addr show scope global | awk '{print $4}' | head -3; curl -sI http://localhost:47434/ | head -3


Error: Streamable HTTP error: Error POSTing to endpoint: <!DOCTYPE html>

<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />

Please enable cookies.

Sorry, you have been blocked

You are unable to access anthropic.com

Why have I been blocked?

This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.

What can I do to resolve this?

You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.

      Cloudflare Ray ID: a0012f0ddc11564e
      •

        Your IP:
        <button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
        71.178.142.110
        •

      Performance & security by Cloudflare


curl -s -o /dev/null -w '%{http_code}' http://localhost:47434/shell.jsx


$ curl -s -o /dev/null -w '%{http_code}' http://localhost:47434/shell.jsx

200


Push fixes to forgejo


TodoWrite

Find the running web-ui container & verify what shell.jsx it serves

Finding the running web-ui container & verifying what shell.jsx it serves

Diagnose why search bar still appears broken (container not rebuilt)

Diagnosing why search bar still appears broken (container not rebuilt)

Add CSS for existing .ctx-menu (right-click menu)

Adding CSS for existing .ctx-menu (right-click menu)

Push fixes to forgejo and rebuild web-ui container

Pushing fixes to forgejo and rebuilding web-ui container


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Push fixes to forgejo

Diagnose why search bar still appears broken (container not rebuilt)

Diagnosing why search bar still appears broken (container not rebuilt)

Push fixes to forgejo and rebuild web-ui container

Pushing fixes to forgejo and rebuilding web-ui container


Root cause: the web-ui container was still serving the pre-change files — `docker exec wild-dragon-web-ui-1 grep -c 'GlobalSearch' shell.jsx` returned **0**. The Dockerfile bakes `public/` into the image at build time, so my push to `main` did nothing until the image was rebuilt.

What I did:

1. **Found the live deploy** — `wild-dragon-web-ui-1` on TrueNAS at `/mnt/NVME/MAM/wild-dragon`, port 47434.
2. **Shipped ctx-menu CSS** (commit `f474a77`) — the right-click `AssetContextMenu` in `screens-library.jsx` was already shipped (commit `992fbdf`, before my session), but its `.ctx-menu` / `.ctx-header` / `.ctx-divider` / `.ctx-section-label` / `.ctx-empty` classes had no CSS — so it rendered as raw HTML. Now styled to match `.row-menu` (dark popover, hover states, danger variant in red).
3. **Pulled and rebuilt** — `git pull --ff-only` (fast-forwarded from `f186cde` → `f474a77`), then `docker compose build web-ui && up -d`. Verified the new container actually has the code: `grep -c GlobalSearch shell.jsx` → 3, `grep -c ctx-menu styles-rest.css` → 13.

Hard refresh (Cmd-Shift-R) the page — the new shell.jsx + CSS are live now. Search bar and right-click menu should both work properly.