/* Reviso for Bricks — Client review mode (front end)
   -------------------------------------------------------------------------
   The shared sidebar / comment-card / form / pin / lightbox styling is loaded
   from builder.css so the reviewer UI matches the in-builder experience. This
   file only adds the front-end-specific pieces: the FAB, comment-mode cursor,
   the identity gate, the sticky footer (identity strip + approval) and a few
   layout helpers. It depends on the design tokens defined in builder.css. */

/* ---------------------------------------------------------------------------
   Stacking order — the builder pin layer sits at z 2147483000 so pins float
   above arbitrary page content. Lift our own UI above the pins so panels are
   never obscured by a pin.
--------------------------------------------------------------------------- */
#reviso-sidebar      { z-index: 2147483610 !important; }

/* ---------------------------------------------------------------------------
   Reviewer footer actions — "I'm done reviewing" + Approve, side by side.
   They wrap to a stack on a very narrow sidebar.
--------------------------------------------------------------------------- */
#reviso-sidebar .reviso-footer-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: stretch;
}
#reviso-sidebar .reviso-footer-actions > .reviso-btn,
#reviso-sidebar .reviso-footer-actions > .reviso-approved-state,
#reviso-sidebar .reviso-footer-actions > .reviso-done-state {
  flex: 1 1 140px;
  min-width: 0;
}
#reviso-sidebar .reviso-footer-actions:empty { display: none; }
/* The done button is the primary reviewer action — solid accent fill, white
   text (uses the accent var so white-label theming still applies). */
#reviso-sidebar .reviso-done-btn {
  background: var(--rv-accent, #6366f1) !important;
  border-color: var(--rv-accent, #6366f1) !important;
  color: #fff !important;
}
#reviso-sidebar .reviso-done-btn:hover {
  filter: brightness(0.93);
}
#reviso-sidebar .reviso-done-state {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--rv-accent, #6366f1);
}
#reviso-sidebar .reviso-done-state svg { width: 15px; height: 15px; }

/* "Reviewed — undo" toggle (multi-page, after a page is marked reviewed). */
#reviso-sidebar .reviso-reviewed-toggle.is-reviewed {
  border-color: var(--rv-teal, #10b981) !important;
  color: var(--rv-teal, #10b981) !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
#reviso-sidebar .reviso-reviewed-toggle.is-reviewed svg { width: 14px; height: 14px; }

/* Single-page "Finish & notify developer" → inline optional-note composer. */
#reviso-sidebar .reviso-finish-note {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#reviso-sidebar .reviso-finish-note textarea {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  min-height: 54px;
  border-radius: 8px;
  border: 1px solid var(--rv-border, rgba(255,255,255,.12));
  padding: 8px 10px;
  font: inherit;
  background: var(--rv-surface-hi, rgba(255,255,255,.04));
  color: var(--rv-text, #e3e6ea);
}
#reviso-sidebar .reviso-finish-note textarea:focus {
  outline: none;
  border-color: var(--rv-accent, #6366f1);
}
#reviso-sidebar .reviso-finish-note-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
#reviso-comment-form { z-index: 2147483620 !important; }
#reviso-lightbox     { z-index: 2147483640 !important; }

/* ---------------------------------------------------------------------------
   Comment-mode cursor — only on Bricks elements (the commentable targets)
   Mirrors the custom SVG cursor injected into the builder canvas by
   builder.js commentCursor() so the reviewer-facing UX matches what the
   agency sees inside Bricks. Data-URL cursors can't reference CSS vars,
   so the accent colour is hardcoded to the brand blue — it's a small
   cursor glyph, not a primary brand surface. Falls back to crosshair on
   browsers that don't support SVG cursors.

   The crosshair covers the whole page in comment mode: the generic adapter
   can anchor any element, so feedback works on Bricks, Elementor, Gutenberg
   and plain-theme markup alike. Reviso's own overlay UI is excluded below
   (it gets the normal pointer affordances).
--------------------------------------------------------------------------- */
body.reviso-comment-mode,
body.reviso-comment-mode * {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='30'%20height='30'%20viewBox='0%200%2030%2030'%3E%3Cpath%20d='M5%203%20h20%20a2%202%200%200%201%202%202%20v12%20a2%202%200%200%201%20-2%202%20h-13%20l-5%205%20v-5%20h-2%20a2%202%200%200%201%20-2%20-2%20v-12%20a2%202%200%200%201%202%20-2%20z'%20fill='%232563eb'%20stroke='%23ffffff'%20stroke-width='2'%20stroke-linejoin='round'/%3E%3Cline%20x1='11'%20y1='11'%20x2='19'%20y2='11'%20stroke='%23ffffff'%20stroke-width='2'%20stroke-linecap='round'/%3E%3Cline%20x1='15'%20y1='7'%20x2='15'%20y2='15'%20stroke='%23ffffff'%20stroke-width='2'%20stroke-linecap='round'/%3E%3C/svg%3E") 7 24, crosshair !important;
}

/* Never let the reviewer UI inherit the crosshair. The lightbox is also
   excluded — when an existing comment's screenshot is open the reviewer
   isn't placing a new pin, they're looking at the image. */
body.reviso-comment-mode #reviso-sidebar,
body.reviso-comment-mode #reviso-sidebar *,
body.reviso-comment-mode #reviso-comment-form,
body.reviso-comment-mode #reviso-comment-form *,
body.reviso-comment-mode #reviso-fab,
body.reviso-comment-mode #reviso-fab *,
body.reviso-comment-mode #reviso-mode-pill,
body.reviso-comment-mode #reviso-mode-pill *,
body.reviso-comment-mode #reviso-pages-nav,
body.reviso-comment-mode #reviso-pages-nav *,
body.reviso-comment-mode #reviso-off-scope,
body.reviso-comment-mode #reviso-off-scope *,
body.reviso-comment-mode #reviso-annotator,
body.reviso-comment-mode #reviso-annotator *,
body.reviso-comment-mode #reviso-lightbox,
body.reviso-comment-mode #reviso-lightbox *,
body.reviso-comment-mode #wpadminbar,
body.reviso-comment-mode #wpadminbar * {
  cursor: auto !important;
}
/* Inside the lightbox the image itself zooms-out on click, so use the
   zoom-out affordance there specifically. */
body.reviso-comment-mode #reviso-lightbox img { cursor: zoom-out !important; }
/* Annotator opens while comment-mode is still active — the universal
   comment-cursor rule above would otherwise overpower the pen cursor on
   the draw canvas. Re-assert the pen cursor with the higher specificity
   needed to beat that universal rule. */
body.reviso-comment-mode #reviso-annotator button,
#reviso-annotator button { cursor: pointer !important; }
/* Defensive: even outside comment-mode, page-level CSS sometimes leaks
   a cursor onto our overlays via universal selectors. Lock the nav-panel
   + off-scope banner to standard pointer affordances. */
#reviso-pages-nav, #reviso-pages-nav *,
#reviso-off-scope, #reviso-off-scope * { cursor: default; }
#reviso-pages-nav a, #reviso-pages-nav button,
#reviso-off-scope a { cursor: pointer; }
body.reviso-comment-mode #reviso-sidebar .reviso-sidebar-header { cursor: grab !important; }
body.reviso-comment-mode #reviso-sidebar button,
body.reviso-comment-mode #reviso-comment-form button,
body.reviso-comment-mode #reviso-fab { cursor: pointer !important; }
body.reviso-comment-mode #reviso-sidebar textarea,
body.reviso-comment-mode #reviso-sidebar input { cursor: text !important; }

/* ---------------------------------------------------------------------------
   FAB — feedback launcher (bottom-right)
--------------------------------------------------------------------------- */
#reviso-fab {
  position: fixed;
  bottom: 24px;
  right: 24px;
  display: inline-flex;
  /* Default corner is bottom-right (above). The admin-chosen corner is applied
     via a reviso-fab--* modifier class set in review.js. */
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  background: var(--rv-accent, #2563eb);
  color: var(--rv-accent-text, #fff);
  border: none;
  border-radius: 50px;
  box-shadow: 0 4px 16px var(--rv-accent-glow, rgba(37, 99, 235, .4));
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  line-height: 1;
  white-space: nowrap;
  z-index: 2147483600;
  transition: transform .15s, box-shadow .15s, filter .15s;
}
#reviso-fab:hover  { filter: brightness(1.08); transform: translateY(-2px); box-shadow: 0 6px 20px var(--rv-accent-glow, rgba(37, 99, 235, .45)); }
#reviso-fab:active { transform: translateY(0); }
#reviso-fab svg    { width: 18px; height: 18px; }

/* Admin-chosen Feedback-button corner. bottom-right is the base above. */
#reviso-fab.reviso-fab--bottom-left { right: auto; left: 24px; }
#reviso-fab.reviso-fab--top-right   { bottom: auto; top: 24px; }
#reviso-fab.reviso-fab--top-left    { bottom: auto; top: 24px; right: auto; left: 24px; }
/* Keep a top-anchored button clear of the WP admin bar for logged-in users. */
body.admin-bar #reviso-fab.reviso-fab--top-right,
body.admin-bar #reviso-fab.reviso-fab--top-left { top: 56px; }

/* ---------------------------------------------------------------------------
   First-visit FAB tooltip — points new reviewers at the Feedback button
   instead of force-opening the sidebar. Corner variant classes mirror the
   FAB's admin-chosen position (set in review.js showFabTip).
--------------------------------------------------------------------------- */
#reviso-fab-tip {
  position: fixed;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  max-width: 280px;
  padding: 12px 14px;
  background: #1a1d24;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .35);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 13px;
  line-height: 1.45;
  z-index: 2147483599;
  animation: reviso-fab-tip-in .25s ease-out;
}
/* Arrow: a rotated square matching the bubble's background + border. */
#reviso-fab-tip::after {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  background: #1a1d24;
  border: 1px solid rgba(255, 255, 255, .12);
  border-top: none;
  border-left: none;
  transform: rotate(45deg);
}
.reviso-fab-tip-close {
  flex: none;
  margin: -4px -6px 0 0;
  padding: 0 4px;
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, .55);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.reviso-fab-tip-close:hover { color: #fff; }
/* Corner variants — sit beside the FAB (24px inset, ~42px-tall button). */
#reviso-fab-tip.reviso-fab-tip--bottom-right { right: 24px; bottom: 84px; }
#reviso-fab-tip.reviso-fab-tip--bottom-right::after { bottom: -7px; right: 28px; }
#reviso-fab-tip.reviso-fab-tip--bottom-left  { left: 24px; bottom: 84px; }
#reviso-fab-tip.reviso-fab-tip--bottom-left::after  { bottom: -7px; left: 28px; }
#reviso-fab-tip.reviso-fab-tip--top-right { right: 24px; top: 84px; }
#reviso-fab-tip.reviso-fab-tip--top-right::after { top: -7px; right: 28px; transform: rotate(225deg); }
#reviso-fab-tip.reviso-fab-tip--top-left  { left: 24px; top: 84px; }
#reviso-fab-tip.reviso-fab-tip--top-left::after  { top: -7px; left: 28px; transform: rotate(225deg); }
body.admin-bar #reviso-fab-tip.reviso-fab-tip--top-right,
body.admin-bar #reviso-fab-tip.reviso-fab-tip--top-left { top: 116px; }
#reviso-fab-tip.reviso-fab-tip--hide { opacity: 0; transition: opacity .4s; }
@keyframes reviso-fab-tip-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------------------------------------------------------------------------
   Screenshot annotator
--------------------------------------------------------------------------- */
.reviso-annot-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  background: transparent;
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.15));
  border-radius: var(--rv-radius, 6px);
  color: var(--rv-text-muted, #6e7f91);
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  align-self: flex-start;
  transition: all .12s;
}
.reviso-annot-btn:hover { border-color: var(--rv-accent, #2563eb); color: var(--rv-accent, #2563eb); }

#reviso-annotator {
  position: fixed;
  inset: 0;
  z-index: 2147483645;
  background: rgba(0,0,0,.82);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3vh 3vw;
}
.reviso-annot-inner {
  display: flex;
  flex-direction: column;
  max-width: 100%;
  max-height: 100%;
  gap: 10px;
}
.reviso-annot-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  color: #fff;
  font-size: 14px;
}
.reviso-annot-tools { display: flex; gap: 6px; }
.reviso-annot-stage {
  overflow: auto;
  background: #111;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.reviso-annot-canvas,
body.reviso-comment-mode .reviso-annot-canvas {
  max-width: 100%;
  max-height: calc(94vh - 60px);
  /* Pen-tip cursor — the annotate stage is a freehand draw surface, not a
     click-to-pin canvas. Hotspot at the pen nib (bottom-left, 2 24).
     `!important` is required to beat the universal `body.reviso-comment-mode *`
     comment-cursor rule that's still active while the annotator overlay is open. */
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='28'%20height='28'%20viewBox='0%200%2028%2028'%3E%3Cpath%20d='M19%202%20l7%207%20-13%2013%20-7%200%200%20-7%20z'%20fill='%23ff3b30'%20stroke='%23ffffff'%20stroke-width='1.5'%20stroke-linejoin='round'/%3E%3Cpath%20d='M16%205%20l7%207'%20stroke='%23ffffff'%20stroke-width='1.5'%20stroke-linecap='round'/%3E%3Cpath%20d='M6%2022%20l3%203'%20stroke='%23ffffff'%20stroke-width='1.5'%20stroke-linecap='round'/%3E%3C/svg%3E") 2 24, crosshair !important;
  display: block;
  touch-action: none;
}

/* ---------------------------------------------------------------------------
   White-label brand logo in the sidebar header (Pro)

   Both variants render side-by-side; CSS hides whichever doesn't match the
   active data-rv-theme. This means the swap is instant on theme toggle
   without any JS coupling. When only one variant is uploaded, the host
   still passes the same URL for both — visually identical but no double-
   render flicker because only one is ever visible.
--------------------------------------------------------------------------- */
.reviso-brand-logo {
  display: block;
  max-height: 30px;
  max-width: 160px;
  width: auto;
  object-fit: contain;
}
[data-rv-theme="dark"]  .reviso-brand-logo--light,
[data-rv-theme="light"] .reviso-brand-logo--dark { display: none; }
/* OS-prefers-light with no explicit override → hide the dark-bg variant. */
@media (prefers-color-scheme: light) {
  :root:not([data-rv-theme="dark"]) .reviso-brand-logo--dark { display: none; }
}
/* OS-prefers-dark or unset → hide the light-bg variant. */
@media (prefers-color-scheme: dark), (prefers-color-scheme: no-preference) {
  :root:not([data-rv-theme="light"]) .reviso-brand-logo--light { display: none; }
}

/* ---------------------------------------------------------------------------
   Static Review-name label for reviewers (caps.canPickReview === false).
   Matches the visual rhythm of the dropdown pills next to it (device filter)
   without the chevron / clickable affordance.
--------------------------------------------------------------------------- */
.reviso-review-label {
  display: inline-block;
  box-sizing: border-box;
  vertical-align: middle;
  height: 28px;
  /* 28px box − 2×1px border = 26px content height → centres the text */
  line-height: 26px;
  padding: 0 10px;
  /* Cap the width so a long Review name can't stretch the bar; adapts on
     narrow viewports. Full name stays available via the title tooltip. */
  max-width: clamp(120px, 30vw, 240px);
  border-radius: 999px;
  background: var(--rv-surface-hi, rgba(255,255,255,.06));
  border: 1px solid var(--rv-border, rgba(255,255,255,.08));
  color: var(--rv-text-sub, #aab2bc);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Review switcher — same pill look, but a real <select> for viewers who can
   reach more than one review (logged-in admins, or email reviewers on several). */
/* Match the built-in .reviso-dropdown pill next to it (the device filter):
   rounded rect (not a full pill), same surface/border/typography, custom
   chevron so the native select arrow doesn't double up. */
.reviso-review-switch {
  box-sizing: border-box;
  vertical-align: middle;
  max-width: clamp(140px, 32vw, 240px);
  padding: 5px 26px 5px 10px;
  border-radius: 7px;
  background: var(--rv-surface, rgba(255,255,255,.04));
  border: 1px solid var(--rv-border, rgba(255,255,255,.08));
  color: var(--rv-text-sub, #aab2bc);
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23aab2bc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  transition: border-color .12s, color .12s;
}
.reviso-review-switch:hover { color: var(--rv-text, #e3e6ea); border-color: var(--rv-border-hi, rgba(255,255,255,.16)); }
.reviso-review-switch:focus { outline: none; border-color: var(--rv-border-hi, rgba(255,255,255,.16)); }
.reviso-review-switch option { color: initial; }

/* ---------------------------------------------------------------------------
   Sidebar header icon buttons (theme toggle + close)
   The SVG glyphs in engine.js ICONS.{sun,moon,close} ship without intrinsic
   width/height — they need CSS sizing. builder.css has this rule for the
   in-builder context; the front-end was missing it, so the SVGs rendered at
   the browser default size (huge → clipped by the 28px button) and the user
   saw "no icon" until first paint. Mirror the builder styling here.
--------------------------------------------------------------------------- */
#reviso-sidebar .reviso-theme-toggle,
#reviso-sidebar .reviso-resolved-headbtn,
#reviso-sidebar .reviso-sidebar-min,
#reviso-sidebar .reviso-sidebar-close {
  width: 28px;
  height: 28px;
  border-radius: 7px;
  border: none;
  background: var(--rv-surface, transparent);
  color: var(--rv-text-muted, #888);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .12s, color .12s;
  padding: 0;
}
#reviso-sidebar .reviso-theme-toggle svg,
#reviso-sidebar .reviso-resolved-headbtn svg,
#reviso-sidebar .reviso-sidebar-min svg,
#reviso-sidebar .reviso-sidebar-close svg { width: 14px; height: 14px; display: block; }
#reviso-sidebar .reviso-theme-toggle:hover,
#reviso-sidebar .reviso-resolved-headbtn:hover,
#reviso-sidebar .reviso-sidebar-min:hover,
#reviso-sidebar .reviso-sidebar-close:hover {
  background: var(--rv-surface-hi, rgba(255,255,255,0.08));
  color: var(--rv-text, #fff);
}
#reviso-sidebar .reviso-resolved-headbtn.is-active {
  background: var(--rv-accent, #6366f1);
  color: var(--rv-accent-text, #fff);
}

/* ---------------------------------------------------------------------------
   Sidebar body — flex scroll container holding the list OR the identity gate
--------------------------------------------------------------------------- */
.reviso-sidebar-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* The shared .reviso-comment-list (flex:1 + scroll, from builder.css) fills it. */

/* ---------------------------------------------------------------------------
   Identity gate
--------------------------------------------------------------------------- */
.reviso-identity {
  padding: 16px 16px 20px;
  overflow-y: auto;
}

.reviso-identity-intro {
  font-size: 13px;
  line-height: 1.5;
  color: var(--rv-text, #dde1e5);
  margin: 0 0 14px;
}
.reviso-identity-intro strong { color: var(--rv-text, #fff); }

.reviso-identity-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--rv-text-muted, #6e7f91);
  margin: 0 0 4px;
}
.reviso-identity-optional {
  font-weight: 400;
  opacity: 0.7;
  margin-left: 4px;
}

.reviso-identity-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 0 0 12px;
  padding: 8px 10px;
  background: var(--rv-surface, #1e252e);
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.15));
  border-radius: var(--rv-radius, 6px);
  font-size: 13px;
  line-height: 1.5;
  font-family: inherit;
  color: var(--rv-text, #dde1e5);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.reviso-identity-input::placeholder { color: var(--rv-text-muted, #6e7f91); }
.reviso-identity-input:focus {
  border-color: var(--rv-accent, #2563eb);
  box-shadow: 0 0 0 2px var(--rv-accent-bg, rgba(37, 99, 235, .18));
}

.reviso-identity-error {
  min-height: 16px;
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--rv-danger, #e05252);
}

/* Back + Save row used by the change-name flow. */
.reviso-identity-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 4px;
}

/* ---------------------------------------------------------------------------
   Footer — identity strip + "Mark page as approved"
--------------------------------------------------------------------------- */
.reviso-sidebar-footer {
  flex-shrink: 0;
  padding: 10px 14px 12px;
  border-top: 1px solid var(--rv-border, rgba(255,255,255,.08));
  background: var(--rv-surface, #1e252e);
  border-radius: 0 0 10px 10px;
}
.reviso-sidebar-footer:empty { display: none; }

.reviso-identity-strip {
  font-size: 11px;
  color: var(--rv-text-muted, #6e7f91);
  margin-bottom: 8px;
}
.reviso-identity-strip strong { color: var(--rv-text, #dde1e5); }

.reviso-link-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 11px;
  font-family: inherit;
  color: var(--rv-accent, #2563eb);
  text-decoration: underline;
  cursor: pointer;
}

.reviso-btn-full {
  width: 100%;
  justify-content: center;
}

.reviso-approved-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 14px;
  border-radius: var(--rv-radius, 6px);
  background: rgba(63, 191, 110, .12);
  border: 1px solid rgba(63, 191, 110, .35);
  color: var(--rv-success, #3fbf6e);
  font-size: 13px;
  font-weight: 600;
}
.reviso-approved-state svg { width: 15px; height: 15px; }

/* Empty-state shown in the comment list when the page is approved — replaces
   the comment cards so reviewers can't accidentally try to add new feedback. */
.reviso-approved-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 32px 22px;
  gap: 6px;
  color: var(--rv-text, #dde1e5);
}
.reviso-approved-empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(63, 191, 110, .14);
  color: var(--rv-success, #3fbf6e);
  margin-bottom: 6px;
}
.reviso-approved-empty-icon svg { width: 22px; height: 22px; }
.reviso-approved-empty-title {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}
.reviso-approved-empty-body {
  margin: 0;
  max-width: 280px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--rv-text-muted, #6e7f91);
}

/* Hint shown above a disabled "Mark page as approved" button when there are
   still open comments — explains why the button is locked. The .is-flash
   modifier (added by engine.js on click of the soft-disabled button) briefly
   highlights the message so the reviewer connects the dots. */
.reviso-approve-blocked {
  margin: 0 0 8px;
  padding: 6px 10px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--rv-text-muted, #6e7f91);
  text-align: center;
  border-radius: 6px;
  background: transparent;
  transition: background .2s ease, color .2s ease;
}
.reviso-approve-blocked.is-flash {
  animation: revisoApproveBlockedFlash 1.4s ease;
}
@keyframes revisoApproveBlockedFlash {
  0%   { background: rgba(248, 113, 113, 0.28); color: #fecaca; }
  40%  { background: rgba(248, 113, 113, 0.18); color: #fecaca; }
  100% { background: transparent;                color: var(--rv-text-muted, #6e7f91); }
}

/* ---------------------------------------------------------------------------
   Delete-own-comment button (sits beside the resolve button)
--------------------------------------------------------------------------- */
.reviso-delete-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: 4px;
  background: none;
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.15));
  border-radius: 4px;
  color: var(--rv-text-muted, #6e7f91);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  transition: all .12s;
}
.reviso-delete-btn svg { width: 14px; height: 14px; }
.reviso-delete-btn:hover {
  background: var(--rv-danger, #e05252);
  border-color: var(--rv-danger, #e05252);
  color: #fff;
}

/* Edit-own-comment button (sits beside resolve/delete) + inline editor */
.reviso-edit-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: 4px;
  background: none;
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.15));
  border-radius: 4px;
  color: var(--rv-text-muted, #6e7f91);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
  transition: all .12s;
}
.reviso-edit-btn svg { width: 14px; height: 14px; }
.reviso-edit-btn:hover {
  background: var(--rv-accent, #2563eb);
  border-color: var(--rv-accent, #2563eb);
  color: var(--rv-accent-text, #fff);
}
.reviso-edit-form { margin: 6px 0 2px; }
.reviso-edit-text {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  min-height: 60px;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  line-height: 1.5;
  color: var(--rv-text, #e7eef6);
  background: var(--rv-surface-hi, rgba(255,255,255,.04));
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.18));
  border-radius: 6px;
}
.reviso-edit-text:focus { outline: none; border-color: var(--rv-accent, #2563eb); }
.reviso-edit-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 6px; }

/* ---------------------------------------------------------------------------
   Approval confirmation (authority check + recording notice)
--------------------------------------------------------------------------- */
.reviso-approve-confirm {
  border: 1px solid var(--rv-border-hi, rgba(255,255,255,.15));
  border-radius: var(--rv-radius, 6px);
  padding: 10px 12px;
  background: var(--rv-surface, #20262e);
}
.reviso-approve-auth {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  color: var(--rv-text, #e8eef4);
  cursor: pointer;
  line-height: 1.4;
}
.reviso-approve-auth input { margin-top: 2px; flex-shrink: 0; }
.reviso-approve-note {
  margin: 8px 0 10px;
  font-size: 11px;
  color: var(--rv-text-muted, #6e7f91);
  line-height: 1.4;
}
.reviso-approve-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

/* ---------------------------------------------------------------------------
   Identity-gate "note" line — explains the email is from the invite
--------------------------------------------------------------------------- */
.reviso-identity-note {
  margin: -8px 0 12px;
  font-size: 12px;
  color: var(--rv-text-muted, #94a3b8);
  line-height: 1.4;
}

/* ---------------------------------------------------------------------------
   Pages-nav panel (bottom-left)

   Always-on floating panel rendered by review.js renderPagesNav() whenever
   cfg.review.pages is populated. Works in both full-overlay mode and the
   chrome-only off-scope mode (engine deliberately not booted there).

   - Z-index sits below #reviso-comment-form (2147483620) so the in-page
     comment form floats above it when both are open.
   - Collapsed state collapses to a header pill; localStorage-persisted so
     the reviewer's preference survives navigation.
   - Palette follows `data-rv-theme` on the document element so the panel
     stays consistent with the comment modal when the reviewer toggles
     dark / light. Tokens default to dark; the light overrides live in the
     [data-rv-theme="light"] / OS-prefers-light blocks below.
--------------------------------------------------------------------------- */
.rv-nav {
  position: fixed;
  bottom: 16px;
  left: 16px;
  width: 280px;
  max-height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  background: var(--rv-modal, #1e252e);
  border: 1px solid var(--rv-border, rgba(255,255,255,0.08));
  border-radius: 12px;
  box-shadow: var(--rv-shadow-modal, 0 8px 32px rgba(0,0,0,0.45), 0 2px 6px rgba(0,0,0,0.25));
  font-family: var(--rv-font-stack, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif);
  font-size: 13px;
  color: var(--rv-text, #e8eaf5);
  z-index: 2147483615;
  overflow: hidden;
  transition: max-height .18s ease;
}
.rv-nav.is-collapsed { max-height: 44px; }

.rv-nav-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 12px 14px;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
}
.rv-nav-header:hover { background: var(--rv-surface-hi, rgba(255,255,255,0.06)); }
.rv-nav-header-title {
  display: flex; align-items: center; gap: 8px;
  font-weight: 600;
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rv-nav-count {
  background: var(--rv-surface-hi, rgba(255,255,255,0.10));
  color: var(--rv-text-sub, #aab2bc);
  font-size: 11px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 999px;
  flex-shrink: 0;
}
.rv-nav-chev {
  color: var(--rv-text-muted, #6e7f91);
  transition: transform .18s ease;
  display: inline-flex;
  flex-shrink: 0;
}
.rv-nav.is-collapsed .rv-nav-chev { transform: rotate(-90deg); }

.rv-nav-body {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--rv-border, rgba(255,255,255,0.06));
  overflow: hidden;
}
.rv-nav-list {
  overflow-y: auto;
  max-height: 320px;
  padding: 4px 0;
  /* Slim custom scrollbar to match the comment modal, not the OS one. */
  scrollbar-width: thin;
  scrollbar-color: rgba(128, 128, 128, 0.25) transparent;
}
#reviso-pages-nav .rv-nav-list::-webkit-scrollbar { width: 5px; }
#reviso-pages-nav .rv-nav-list::-webkit-scrollbar-thumb { background: rgba(128, 128, 128, 0.25); border-radius: 99px; }
#reviso-pages-nav .rv-nav-list::-webkit-scrollbar-track { background: transparent; }
.rv-nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 14px;
  text-decoration: none !important;
  color: var(--rv-text, #e8eaf5) !important;
  transition: background .12s ease;
}
.rv-nav-row:hover { background: var(--rv-surface-hi, rgba(255,255,255,0.06)); }
.rv-nav-row.is-current {
  background: var(--rv-accent-bg, rgba(37,99,235,0.18));
  color: var(--rv-accent, #2563eb) !important;
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--rv-accent, #2563eb); /* "you are here" bar */
}
.rv-nav-title {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px;
}
.rv-nav-badge {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--rv-surface-hi, rgba(255,255,255,0.08));
  color: var(--rv-text-muted, #6e7f91);
}
.rv-nav-badge.is-active {
  background: var(--rv-accent-bg, rgba(37,99,235,0.18));
  color: var(--rv-accent, #2563eb);
}
.rv-nav-badge.is-done {
  background: var(--rv-teal-bg, rgba(63,191,110,0.15));
  color: var(--rv-teal, #3fbf6e);
}
/* Reviewer finished their pass but the client hasn't approved yet — green like
   the other "done" signals, but softened so final approval still reads stronger. */
.rv-nav-badge.is-reviewed {
  background: var(--rv-status-done-bg, rgba(63,191,110,0.15));
  color: var(--rv-status-done, #3fbf6e);
  opacity: 0.8;
}

/* ── Grouped nav (Entire-Website reviews) ────────────────────────────────
   One collapsible row per post type. Without this an Entire-Website review
   dumps every resolved item (662 in one real case) into a flat list. Group
   bodies are filled lazily on first expand — see buildNavRows in review.js. */
.rv-nav-group + .rv-nav-group { border-top: 1px solid var(--rv-border, rgba(255,255,255,0.06)); }
.rv-nav-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 9px 14px;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--rv-text, #e8eaf5);
  font: inherit;
  text-align: left;
}
.rv-nav-group-head:hover { background: var(--rv-surface-hi, rgba(255,255,255,0.06)); }
.rv-nav-group-chev {
  display: flex;
  flex-shrink: 0;
  color: var(--rv-text-muted, #6e7f91);
  transition: transform .15s ease;
  transform: rotate(90deg);
}
.rv-nav-group.is-collapsed .rv-nav-group-chev { transform: rotate(0deg); }
.rv-nav-group-label {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px;
  font-weight: 650;
}
.rv-nav-group-count,
.rv-nav-group-tpl {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--rv-surface-hi, rgba(255,255,255,0.08));
  color: var(--rv-text-muted, #6e7f91);
}
.rv-nav-group-tpl {
  text-transform: uppercase;
  background: var(--rv-accent-bg, rgba(37,99,235,0.18));
  color: var(--rv-accent, #2563eb);
}
.rv-nav-group.is-collapsed .rv-nav-group-body { display: none; }
.rv-nav-group-body .rv-nav-row { padding-left: 30px; }

.rv-nav-dashboard {
  display: block;
  padding: 10px 14px;
  border-top: 1px solid var(--rv-border, rgba(255,255,255,0.06));
  text-align: center;
  font-weight: 600;
  font-size: 12.5px;
  color: var(--rv-accent, #2563eb) !important;
  text-decoration: none !important;
  background: var(--rv-accent-bg, rgba(37,99,235,0.10));
}
.rv-nav-dashboard:hover {
  background: var(--rv-surface-hi, rgba(37,99,235,0.18));
}

/* ---------------------------------------------------------------------------
   Phone layout: keep pages-nav from overlapping the Feedback FAB.
   The FAB lives bottom-right (24/24); the pages-nav defaults to bottom-left
   with a fixed 280px width. On phones ~360px wide that puts the panel's
   right edge right under the FAB and the two cover each other. Lift the
   nav above the FAB and shrink to fit small screens; review.js also
   default-collapses on this breakpoint so it doesn't fill the screen.
--------------------------------------------------------------------------- */
@media (max-width: 600px) {
  .rv-nav {
    bottom: 88px; /* clear the FAB (24 + button height + breathing room) */
    left: 12px;
    right: 12px;
    width: auto;
    max-height: calc(100vh - 120px);
  }
  .rv-nav-list { max-height: 240px; }
  /* Comment form: full-width-ish on phones so the action buttons stay
     reachable and the form can't drift past the right edge. */
  #reviso-comment-form {
    left: 12px !important;
    right: 12px;
    width: auto !important;
    max-width: calc(100vw - 24px);
    max-height: calc(100vh - 24px);
  }
}

/* ---------------------------------------------------------------------------
   Off-scope banner (top of page when reviewer wanders off-scope)
--------------------------------------------------------------------------- */
.rv-off-scope {
  position: sticky;
  top: 0;
  z-index: 2147483614;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  background: #fef3c7;
  color: #78350f;
  border-bottom: 1px solid #fbbf24;
  padding: 10px 16px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  font-size: 13.5px;
  font-weight: 500;
  text-align: center;
}
.rv-off-scope-actions {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}
.rv-off-scope-back {
  color: #78350f !important;
  text-decoration: underline !important;
  font-weight: 700;
  white-space: nowrap;
}
.rv-off-scope-back:hover { color: #451a03 !important; }
.rv-off-scope-exit {
  background: transparent;
  border: 1px solid #b45309;
  color: #78350f;
  font: inherit;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.12s, color 0.12s;
}
.rv-off-scope-exit:hover {
  background: #b45309;
  color: #fffbeb;
}
.rv-off-scope-exit:disabled {
  opacity: 0.6;
  cursor: wait;
}

/* ---------------------------------------------------------------------------
   Viewport emulation (iframe-based)

   When the reviewer picks tablet/mobile in the sidebar viewport switcher,
   review.js mounts a same-origin <iframe> sized to the simulated width.
   The iframe loads the same URL with ?reviso_no_chrome=1 so PHP skips the
   overlay enqueue — the page renders bare inside it.

   The parent html/body get a "stage" treatment: locked to viewport, dark
   surface behind the iframe, original page content hidden so it doesn't
   bleed through. Our overlay UI (FAB, sidebar, pages-nav, comment form,
   lightbox, annotator) stays on the parent body and floats above the
   iframe via the high z-indexes already set further up this file.
--------------------------------------------------------------------------- */
html.reviso-vp-emulating,
html.reviso-vp-emulating body {
  height: 100vh !important;
  max-height: 100vh !important;
  overflow: hidden !important;
  margin: 0 !important;
  padding: 0 !important;
}
/* Hide the original page content while the iframe is the canvas. Whitelist
   the engine's body-level overlay elements (pin-layer lives inside the
   iframe, so it's not in this list — its parent-doc copy is removed in JS
   when emulation starts). The popover is engine-managed and only exists
   while a dropdown is open; without it whitelisted the device/round/round
   pills appear to do nothing because the menu is hidden under the iframe.
   `display: none` collapses them out of layout entirely. */
html.reviso-vp-emulating body > *:not(#reviso-vp-wrapper):not(#reviso-fab):not(#reviso-sidebar):not(#reviso-comment-form):not(#reviso-pages-nav):not(#reviso-off-scope):not(#reviso-annotator):not(#reviso-lightbox):not(#reviso-popover):not(#reviso-summary):not(#wpadminbar) {
  display: none !important;
}

#reviso-vp-wrapper {
  position: fixed;
  inset: 0;
  z-index: 1;
  background: #2b2f36;
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 32px 32px 24px;
  box-sizing: border-box;
}
#reviso-vp-iframe {
  display: block;
  height: 100%;
  background: #fff;
  border: 0;
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .35), 0 2px 6px rgba(0, 0, 0, .2);
  transition: width .25s ease;
}

/* WP admin bar (shown to logged-in editors who happen to be reviewing) is
   position:fixed on the parent — push our wrapper down so the iframe doesn't
   sit underneath it. */
html.reviso-vp-emulating body.admin-bar #reviso-vp-wrapper {
  padding-top: calc(32px + var(--wp-admin--admin-bar--height, 32px));
}

/* ───────────────────────── First-open welcome overlay ─────────────────────
   Shown once per review on first open (review.js → showWelcomeOverlay). Sits
   above every other Reviso layer. Fully #reviso-scoped, self-contained values,
   responsive + dismissible (Esc, ✕, scrim, or "Start reviewing"). */
#reviso-welcome.reviso-welcome-scrim {
  position: fixed; inset: 0; z-index: 2147483646;
  display: flex; align-items: center; justify-content: center;
  padding: 20px; box-sizing: border-box;
  background: rgba(15, 23, 42, .55);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: reviso-welcome-fade .18s ease;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
}
#reviso-welcome.reviso-welcome--hide { opacity: 0; transition: opacity .2s ease; }
#reviso-welcome .reviso-welcome-card {
  position: relative; box-sizing: border-box;
  width: 100%; max-width: 440px; max-height: calc(100vh - 40px); overflow-y: auto;
  background: #fff; color: #1e293b;
  border-radius: 14px; padding: 26px 26px 24px;
  box-shadow: 0 18px 50px rgba(15, 23, 42, .35);
  text-align: left; line-height: 1.5;
  animation: reviso-welcome-pop .2s ease;
}
#reviso-welcome .reviso-welcome-x {
  position: absolute; top: 10px; right: 12px;
  width: 30px; height: 30px; padding: 0;
  background: transparent; border: 0; cursor: pointer;
  font-size: 22px; line-height: 1; color: #94a3b8;
  border-radius: 6px;
}
#reviso-welcome .reviso-welcome-x:hover { background: #f1f5f9; color: #475569; }
#reviso-welcome .reviso-welcome-title {
  font-size: 18px; font-weight: 700; margin: 0 28px 8px 0; color: #0f172a;
}
#reviso-welcome .reviso-welcome-body { font-size: 14px; color: #475569; margin: 0 0 16px; }
#reviso-welcome .reviso-welcome-steps {
  list-style: none; counter-reset: rvw; margin: 0 0 20px; padding: 0;
}
#reviso-welcome .reviso-welcome-steps li {
  counter-increment: rvw; position: relative;
  padding: 0 0 0 36px; margin: 0 0 12px; font-size: 14px; color: #334155;
}
#reviso-welcome .reviso-welcome-steps li:last-child { margin-bottom: 0; }
#reviso-welcome .reviso-welcome-steps li::before {
  content: counter(rvw); position: absolute; left: 0; top: -1px;
  width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--rv-accent, #2563eb); color: var(--rv-accent-text, #fff);
  font-size: 13px; font-weight: 700;
}
#reviso-welcome .reviso-welcome-go {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; box-sizing: border-box; padding: 11px 18px;
  background: var(--rv-accent, #2563eb); color: var(--rv-accent-text, #fff);
  border: 0; border-radius: 9px; cursor: pointer;
  font-size: 15px; font-weight: 600;
}
#reviso-welcome .reviso-welcome-go:hover { filter: brightness(1.08); }
@keyframes reviso-welcome-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes reviso-welcome-pop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
@media (max-width: 600px) {
  #reviso-welcome.reviso-welcome-scrim { padding: 0; align-items: flex-end; }
  #reviso-welcome .reviso-welcome-card {
    max-width: 100%; border-radius: 16px 16px 0 0; padding: 22px 20px 20px;
    max-height: 88vh;
  }
}

/* ───────────────────────── Template-item banner ──────────────────────────
   Sticky top bar shown when the client is on a "type template" representative
   (review.js → renderTemplateBanner). #reviso-scoped, self-contained values. */
#reviso-tpl-banner.reviso-tpl-banner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 2147483614;
  display: flex; align-items: center; gap: 12px;
  padding: 9px 16px; box-sizing: border-box;
  background: var(--rv-accent, #2563eb); color: var(--rv-accent-text, #fff);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  font-size: 13px; line-height: 1.4;
  box-shadow: 0 2px 8px rgba(15, 23, 42, .18);
}
#reviso-tpl-banner .reviso-tpl-banner-msg { flex: 1; min-width: 0; }
#reviso-tpl-banner .reviso-tpl-banner-x {
  flex: none; width: 26px; height: 26px; padding: 0;
  background: rgba(255,255,255,.18); border: 0; border-radius: 6px;
  color: inherit; font-size: 18px; line-height: 1; cursor: pointer;
}
#reviso-tpl-banner .reviso-tpl-banner-x:hover { background: rgba(255,255,255,.3); }
html.admin-bar #reviso-tpl-banner.reviso-tpl-banner { top: 32px; }
@media screen and (max-width: 782px) {
  html.admin-bar #reviso-tpl-banner.reviso-tpl-banner { top: 46px; }
}

/* Internal/team mode: badge the Feedback FAB so private team notes are visually
   distinct from a client review, and hint the "Done commenting" exit. */
#reviso-fab .reviso-fab-badge {
  margin-left: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
  line-height: 1.4;
}

/* Visible reason under a disabled "Mark page as approved" (not hover-only). */
.reviso-approve-hint {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--rv-text-mut, #8a8a9a);
  text-align: center;
}

/* Blank-email nudge: an amber "you won't get replies" prompt, not an error. */
.reviso-identity-error.reviso-identity-warn {
  color: #b45309;
}
@media (prefers-color-scheme: dark) {
  .reviso-identity-error.reviso-identity-warn { color: #fbbf24; }
}

/* Global "working…" indicator — slim top bar shown while a mutating server
   action is in flight (150ms threshold, so instant actions don't flash it). */
#reviso-busy { position: fixed; top: 0; left: 0; width: 100%; height: 3px; z-index: 2147483646; opacity: 0; pointer-events: none; transition: opacity .15s ease; overflow: hidden; }
#reviso-busy.is-on { opacity: 1; }
#reviso-busy.is-on::before { content: ''; position: absolute; top: 0; left: -40%; width: 40%; height: 100%; background: var(--rv-accent, #2563eb); border-radius: 0 3px 3px 0; animation: reviso-busy-slide 1.05s ease-in-out infinite; }
@keyframes reviso-busy-slide { 0% { left: -40%; } 100% { left: 100%; } }
