
.visualai-select__label[data-v-06abe16b] {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.visualai-select[data-v-0fee8713] {
  width: 100%;
}

/* .visualai-select__label lives in VisualAiFieldLabel, which owns both the
   markup and the styling. A scoped copy here would not apply to it anyway —
   scoped styles do not cross a component boundary. */
.visualai-select__wrapper[data-v-0fee8713] {
  position: relative;
  width: 100%;
}
.visualai-select__field[data-v-0fee8713] {
  width: 100%;
  /* Geometry comes from `controlMetrics` in the theme so anything that has to
     line up beside this — the multi-select trigger, the Reports business-hours
     toggle — reads the SAME numbers instead of restating them and drifting
     (AB#15501). The fallbacks only apply when the theme was never applied,
     e.g. a component mounted in a unit test. */
  padding:
    var(--va-control-py, 10px)
    32px
    var(--va-control-py, 10px)
    var(--va-control-px, 14px);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  color: var(--text-primary);
  font-size: var(--va-control-font, 14px);
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  cursor: pointer;
  -webkit-appearance: none;
  -moz-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 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  text-align: start;
}
.visualai-select__value[data-v-0fee8713] {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.visualai-select__field--placeholder .visualai-select__value[data-v-0fee8713] {
  color: var(--text-secondary);
}
.visualai-select__field[data-v-0fee8713]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-select__field[data-v-0fee8713]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Error state */
.visualai-select--error .visualai-select__field[data-v-0fee8713] {
  border-color: var(--danger);
}
.visualai-select--error .visualai-select__field[data-v-0fee8713]:focus {
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
}
.visualai-select__error[data-v-0fee8713] {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}

/* UNSCOPED on purpose: the panel is teleported to #va-overlay-root, outside
   this component's subtree, so Vue's scoped data attribute never reaches it.
   Colors still resolve because theme variables live on documentElement.
   Logical properties (padding-inline, text-align: start) keep RTL correct. */
.visualai-select__panel {
  background: var(--bg-base);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  overflow-y: auto;
  padding-block: 4px;
  font-family: var(--font, 'Inter', sans-serif);
}
.visualai-select__search {
  box-sizing: border-box;
  width: calc(100% - 16px);
  margin: 4px 8px 6px;
  padding: var(--va-control-py, 10px) var(--va-control-px, 14px);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  color: var(--text-primary);
  font-size: var(--va-control-font, 14px);
  font-family: inherit;
  outline: none;
}
.visualai-select__search:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-select__option {
  padding-block: 8px;
  padding-inline: var(--va-control-px, 14px);
  color: var(--text-primary);
  font-size: var(--va-control-font, 14px);
  cursor: pointer;
  text-align: start;
}
.visualai-select__option:hover,
.visualai-select__option.is-active {
  background: var(--accent-light);
}

/* AB#16231: rendered, never hidden — an operator must be able to see WHY a
   combination is greyed out, not just that it's missing. Higher specificity
   than the hover/active rule above so a disabled option never highlights on
   mouseover, even while it is also the current (grandfathered) value. */
.visualai-select__option.is-disabled {
  cursor: not-allowed;
  opacity: 0.5;
}
.visualai-select__option.is-disabled:hover {
  background: transparent;
}
.visualai-select__option-reason {
  display: block;
  font-size: 11px;
  color: var(--text-secondary);
  margin-top: 2px;
}
.visualai-select__group-label {
  padding-block: 6px;
  padding-inline: var(--va-control-px, 14px);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}
.visualai-select__empty,
.visualai-select__truncation {
  padding-block: 8px;
  padding-inline: var(--va-control-px, 14px);
  font-size: 12px;
  color: var(--text-secondary);
  margin: 0;
  text-align: start;
}
.visualai-select__truncation {
  border-top: 1px solid var(--border-color);
}

.visualai-confirm-overlay[data-v-024dc426] {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  /* Above modal overlays (1000) and the loitering detail overlay (1200): a
     confirmation raised FROM inside a modal must sit on top of it, or the
     operator clicks Delete, sees nothing, and the app looks frozen. Still
     below the notifiers (3999/4000) so toasts remain visible. */
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.visualai-confirm[data-v-024dc426] {
  /* OPAQUE BY CONSTRUCTION (AB#15856), for the reasons spelled out on
     .visualai-modal. This component does NOT render through VisualAiModal —
     it draws its own overlay and box — so it carried its own copy of the same
     defect and needs its own copy of the fix. Of the two it was the worse
     case: an alertdialog you can see the page through is one an operator can
     misread while approving something consequential. */
  background: linear-gradient(var(--bg-glass), var(--bg-glass)), var(--bg-base);
  border: 1px solid var(--border-glass);
  border-radius: 16px;
  box-shadow: var(--shadow-dropdown);
  padding: 32px;
  max-width: 420px;
  width: 100%;
  text-align: center;
}
.visualai-confirm__icon[data-v-024dc426] {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 16px;
  font-size: 24px;
}
.visualai-confirm__icon--danger[data-v-024dc426] {
  background: rgba(239, 68, 68, 0.15);
  color: var(--danger);
}
.visualai-confirm__icon--warning[data-v-024dc426] {
  background: rgba(245, 158, 11, 0.15);
  color: var(--warning);
}
.visualai-confirm__title[data-v-024dc426] {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 8px;
}
.visualai-confirm__message[data-v-024dc426] {
  font-size: 14px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 24px;
}
.visualai-confirm__actions[data-v-024dc426] {
  display: flex;
  gap: 8px;
  justify-content: center;
}
.visualai-confirm__btn[data-v-024dc426] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 24px;
  border: none;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  font-family: var(--font, 'Inter', sans-serif);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-confirm__btn--cancel[data-v-024dc426] {
  background: var(--bg-glass);
  color: var(--text-primary);
  border: 1px solid var(--border-glass);
}
.visualai-confirm__btn--cancel[data-v-024dc426]:hover {
  background: var(--bg-glass-hover);
}
.visualai-confirm__btn--danger[data-v-024dc426] {
  background: var(--danger);
  color: #fff;
}
.visualai-confirm__btn--danger[data-v-024dc426]:hover {
  filter: brightness(1.1);
  box-shadow: 0 4px 16px rgba(239, 68, 68, 0.3);
}
.visualai-confirm__btn--warning[data-v-024dc426] {
  background: var(--warning);
  color: #000;
}
.visualai-confirm__btn--warning[data-v-024dc426]:hover {
  filter: brightness(1.1);
  box-shadow: 0 4px 16px rgba(245, 158, 11, 0.3);
}

/* Transition */
.visualai-confirm-enter-active[data-v-024dc426] {
  transition: opacity 0.2s ease;
}
.visualai-confirm-enter-active .visualai-confirm[data-v-024dc426] {
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
}
.visualai-confirm-leave-active[data-v-024dc426] {
  transition: opacity 0.15s ease;
}
.visualai-confirm-leave-active .visualai-confirm[data-v-024dc426] {
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.visualai-confirm-enter-from[data-v-024dc426] {
  opacity: 0;
}
.visualai-confirm-enter-from .visualai-confirm[data-v-024dc426] {
  transform: scale(0.95);
  opacity: 0;
}
.visualai-confirm-leave-to[data-v-024dc426] {
  opacity: 0;
}
.visualai-confirm-leave-to .visualai-confirm[data-v-024dc426] {
  transform: scale(0.97);
  opacity: 0;
}

.placeholder-widget[data-v-94c502f5] {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 16px;
  background: var(--bg-glass);
  border: 1px dashed var(--border-color);
  border-radius: 10px;
  transition: border-color 0.15s;
}
.placeholder-widget[data-v-94c502f5]:hover {
  border-color: var(--accent);
}
.placeholder-header[data-v-94c502f5] {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}
.placeholder-icon[data-v-94c502f5] {
  color: var(--accent);
  font-size: 18px;
}
.placeholder-label[data-v-94c502f5] {
  font-weight: 600;
  font-size: 14px;
  color: var(--text-primary);
}
.placeholder-desc[data-v-94c502f5] {
  margin: 0;
  flex: 1;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.5;
}
.placeholder-filters[data-v-94c502f5] {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}
.filter-badge[data-v-94c502f5] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 500;
  border-radius: 10px;
  white-space: nowrap;
}
.filter-badge i[data-v-94c502f5] {
  font-size: 9px;
}
.placeholder-footer[data-v-94c502f5] {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border-color);
}
.placeholder-meta[data-v-94c502f5] {
  font-size: 10px;
  color: var(--text-muted);
  font-style: italic;
}

.widget-grid[data-v-86149e6b] {
  display: grid;
  /* Must match GRID_COLS in <script> — see the lockstep comment there. */
  grid-template-columns: repeat(72, 1fr);
  /* Must match GRID_ROW_H in <script>. */
  grid-auto-rows: 20px;
  grid-auto-flow: dense; /* fills holes — no empty spaces */
  gap: 8px;
  position: relative;
}

/* Visible grid lines while editing — overlay shows the snap targets.
   Two layers: thin lines every column / row, thicker lines every 18 cols
   and every 8 rows (forming a "major grid" feel for easier visual reference,
   still 4 major vertical dividers at the 72-col resolution; row pitch (28px)
   × 8 keeps roughly the same physical major-line spacing as the pre-bump
   40px-row grid had every 4 rows).
   Hidden on /dashboard (read-only view). */
.widget-grid.editable[data-v-86149e6b] {
  background-image:
    /* Major vertical lines every 18 cols (4 visible) */
    repeating-linear-gradient(
      to right,
      rgba(76, 194, 255, 0.45) 0,
      rgba(76, 194, 255, 0.45) 1px,
      transparent 1px,
      transparent calc(((100% + 8px) / 72) * 18)
    ),
    /* Minor vertical lines every col */
    repeating-linear-gradient(
      to right,
      rgba(76, 194, 255, 0.18) 0,
      rgba(76, 194, 255, 0.18) 1px,
      transparent 1px,
      transparent calc((100% + 8px) / 72)
    ),
    /* Major horizontal lines every 8 rows */
    repeating-linear-gradient(
      to bottom,
      rgba(76, 194, 255, 0.45) 0,
      rgba(76, 194, 255, 0.45) 1px,
      transparent 1px,
      transparent calc(28px * 8)
    ),
    /* Minor horizontal lines every row */
    repeating-linear-gradient(
      to bottom,
      rgba(76, 194, 255, 0.18) 0,
      rgba(76, 194, 255, 0.18) 1px,
      transparent 1px,
      transparent 28px
    );
  background-size: 100% 100%;
  background-position: 0 0;
  /* Pad the container slightly so the grid lines extend past the last cell */
  padding-bottom: 8px;
}
.grid-cell[data-v-86149e6b] {
  position: relative;
  /* Matches VisualAiCard's 16px. With `overflow: hidden` below, a smaller
     radius here silently shaves the corners off every widget card it
     contains — the card rounds at 16px and is then clipped at 12px. */
  border-radius: 16px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 0.15s;
  min-width: 0;
  min-height: 0;
}

/* Border only in edit mode — view mode (dashboard) renders cells borderless. */
.grid-cell.editable[data-v-86149e6b] {
  border: 1px solid var(--border-glass);
}

/* Custom resize handle (replaces CSS resize:both). The handle is a small
   accent-tinted square anchored to the bottom-right corner of editable
   cells, with a clear icon. mousedown drives the resize via JS — the
   layout snaps to grid units on mouseup. */
.resize-handle[data-v-86149e6b] {
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: var(--accent);
  background: var(--bg-glass-hover);
  border: 1px solid var(--accent);
  border-radius: 4px;
  cursor: nwse-resize;
  user-select: none;
  z-index: 10;
  opacity: 0.65;
  transition: opacity 0.15s, transform 0.15s;
}
.resize-handle[data-v-86149e6b]:hover,
.resize-handle.resizing[data-v-86149e6b] {
  opacity: 1;
  transform: scale(1.1);
}
.grid-cell.editable[data-v-86149e6b]:hover {
  border-color: var(--accent);
}
.cell-header[data-v-86149e6b] {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 10px;
  background: var(--bg-glass-hover);
  border-bottom: 1px solid var(--border-color);
}
.drag-handle[data-v-86149e6b],
.filter-toggle[data-v-86149e6b],
.delete-btn[data-v-86149e6b] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--text-muted);
  font-size: 11px;
  cursor: pointer;
  transition: all 0.15s;
}
.filter-toggle.active[data-v-86149e6b] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.filter-panel[data-v-86149e6b] {
  padding: 10px 12px;
  background: var(--bg-glass-hover);
  border-bottom: 1px solid var(--border-color);
}

/* Deliberately NOT the error vocabulary: no red, no triangle, no Retry.
   "Doesn't apply here" and "failed to load" must be distinguishable at a
   glance, and this grid already has four separate failure treatments. */
.cell-scope-strip[data-v-86149e6b] {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 22px;
  padding: 2px 10px;
  font-size: 11px;
  color: var(--text-secondary);
  background: var(--bg-glass-hover);
  border-bottom: 1px solid var(--border-color);
}
.filter-row[data-v-86149e6b] {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--text-primary);
}
.filter-label[data-v-86149e6b] {
  color: var(--text-muted);
  font-weight: 500;
  min-width: 70px;
}
.filter-row select[data-v-86149e6b] {
  flex: 1;
  padding: 5px 8px;
  background: var(--bg-input, var(--bg-glass));
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
}
.filter-row select[data-v-86149e6b]:focus {
  outline: none;
  border-color: var(--accent);
}
.filter-row select[data-v-86149e6b]:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.drag-handle[data-v-86149e6b] {
  cursor: grab;
}
.drag-handle[data-v-86149e6b]:active:not(:disabled) {
  cursor: grabbing;
}
.drag-handle[data-v-86149e6b]:hover:not(:disabled),
.filter-toggle[data-v-86149e6b]:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}
.delete-btn[data-v-86149e6b] {
  margin-left: auto;
}
.delete-btn[data-v-86149e6b]:hover:not(:disabled) {
  border-color: var(--danger);
  color: var(--danger);
}
.filter-toggle.active[data-v-86149e6b]:hover:not(:disabled) {
  border-color: var(--accent);
  color: #fff;
  opacity: 0.85;
}
.drag-handle[data-v-86149e6b]:disabled,
.filter-toggle[data-v-86149e6b]:disabled,
.delete-btn[data-v-86149e6b]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.dragging-ghost[data-v-86149e6b] {
  opacity: 0.4;
}
.unknown-widget[data-v-86149e6b] {
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-muted);
  font-size: 12px;
  font-style: italic;
}
.grid-state[data-v-86149e6b] {
  padding: 24px;
  text-align: center;
  color: var(--text-muted);
  background: var(--bg-glass);
  border: 1px solid var(--border-glass);
  border-radius: 12px;
}
.grid-state.error[data-v-86149e6b] {
  color: var(--danger);
  border-color: var(--danger);
}
.grid-state.inline-error[data-v-86149e6b] {
  margin-bottom: 12px;
  padding: 10px 14px;
  text-align: left;
  font-size: 13px;
}
.inline-link[data-v-86149e6b] {
  color: var(--accent);
  text-decoration: none;
}
.inline-link[data-v-86149e6b]:hover {
  text-decoration: underline;
}
@media (max-width: 768px) {
.widget-grid[data-v-86149e6b] {
    grid-template-columns: 1fr;
}
.grid-cell.wide[data-v-86149e6b] {
    grid-column: span 1;
}
}

.customize-page[data-v-6b789ad7] {
  padding: 0;
}
.back-btn[data-v-6b789ad7],
.reset-btn[data-v-6b789ad7],
.admin-default-btn[data-v-6b789ad7] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: transparent;
  color: var(--text-primary);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s;
  white-space: nowrap;
}
.back-btn[data-v-6b789ad7]:hover,
.reset-btn[data-v-6b789ad7]:hover:not(:disabled),
.admin-default-btn[data-v-6b789ad7]:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
}
.admin-default-btn[data-v-6b789ad7] {
  border-color: var(--accent);
  color: var(--accent);
}
.reset-btn[data-v-6b789ad7]:disabled,
.admin-default-btn[data-v-6b789ad7]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.action-error[data-v-6b789ad7] {
  margin: 0 0 16px;
  font-size: 12px;
  color: var(--danger);
}
.filter-bar[data-v-6b789ad7] {
  margin-bottom: 20px;
}
.section[data-v-6b789ad7] {
  margin-bottom: 32px;
}
.section-title[data-v-6b789ad7] {
  font-size: 12px;
  margin: 0 0 12px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: 600;
}
.palette-section + .palette-section[data-v-6b789ad7] {
  margin-top: 24px;
}
.palette-subheader[data-v-6b789ad7] {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.palette-subheader-icon[data-v-6b789ad7] {
  color: var(--text-muted);
  font-size: 12px;
}
.palette-subheader-count[data-v-6b789ad7] {
  font-weight: 400;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: normal;
}
.palette-grid[data-v-6b789ad7] {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
.palette-card[data-v-6b789ad7] {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 16px;
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-glass);
  border-radius: 10px;
  transition: border-color 0.15s, transform 0.15s;
}
.palette-card[data-v-6b789ad7]:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}
.palette-icon-wrap[data-v-6b789ad7] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: var(--bg-glass-hover);
  border-radius: 8px;
  flex-shrink: 0;
}
.palette-icon[data-v-6b789ad7] {
  color: var(--accent);
  font-size: 18px;
}
.palette-meta[data-v-6b789ad7] {
  flex: 1;
  min-width: 0;
}
.palette-label[data-v-6b789ad7] {
  font-weight: 600;
  font-size: 14px;
  color: var(--text-primary);
}
.palette-desc[data-v-6b789ad7] {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
}
.add-btn[data-v-6b789ad7] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: transparent;
  color: var(--accent);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
  flex-shrink: 0;
}
.add-btn[data-v-6b789ad7]:hover:not(:disabled) {
  background: var(--accent);
  color: #fff;
}
.add-btn[data-v-6b789ad7]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.state-message[data-v-6b789ad7] {
  padding: 32px;
  text-align: center;
  color: var(--text-muted);
  background: var(--bg-glass);
  border: 1px solid var(--border-glass);
  border-radius: 12px;
}
.state-message.error[data-v-6b789ad7] {
  color: var(--danger);
  border-color: var(--danger);
}

.visualai-empty[data-v-63f59ea5] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
}
.visualai-empty__icon[data-v-63f59ea5] {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--bg-glass);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
}
.visualai-empty__icon i[data-v-63f59ea5] {
  font-size: 28px;
  color: var(--text-muted);
  opacity: 0.6;
}
.visualai-empty__title[data-v-63f59ea5] {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 4px;
}
.visualai-empty__description[data-v-63f59ea5] {
  font-size: 14px;
  color: var(--text-secondary);
  max-width: 320px;
  line-height: 1.5;
}
.visualai-empty__actions[data-v-63f59ea5] {
  margin-top: 20px;
  display: flex;
  gap: 8px;
}

.visualai-modal-overlay[data-v-a32cce86] {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.visualai-modal[data-v-a32cce86] {
  /* OPAQUE BY CONSTRUCTION (AB#15856) — same construction as .settings-overlay
     and .dropdown-menu in the shell's main.css.
     --bg-glass alone is a tint, not a surface: rgba(255,255,255,0.06) in dark
     and rgba(255,255,255,0.65) in light. Over the overlay's rgba(0,0,0,0.5)
     scrim and the page beneath it, that composited to grey and stayed opaque
     only while backdrop-filter held. That filter is dropped under
     reduced-transparency OS settings, with hardware acceleration off, and in
     browsers without support — and there was no fallback behind it, so page
     content read straight through the open dialog.
     Painting the same tint OVER the theme's own base colour keeps the look in
     both themes while making the surface opaque on its own. The blur went with
     it: over an opaque background it renders nothing and only costs a
     compositing layer. The scrim above keeps its own blur — that element is
     genuinely translucent by design. */
  background: linear-gradient(var(--bg-glass), var(--bg-glass)), var(--bg-base);
  border: 1px solid var(--border-glass);
  border-radius: 16px;
  box-shadow: var(--shadow-dropdown);
  max-height: 85vh;
  overflow-y: auto;
  width: 100%;
  padding: 24px;
}

/* Sizes */
.visualai-modal--sm[data-v-a32cce86] {
  max-width: 400px;
}
.visualai-modal--md[data-v-a32cce86] {
  max-width: 600px;
}
.visualai-modal--lg[data-v-a32cce86] {
  max-width: 800px;
}
.visualai-modal--xl[data-v-a32cce86] {
  max-width: 1080px;
}
.visualai-modal__header[data-v-a32cce86] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}
.visualai-modal__title[data-v-a32cce86] {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
}
.visualai-modal__close[data-v-a32cce86] {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: var(--bg-glass);
  border-radius: 6px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  flex-shrink: 0;
}
.visualai-modal__close[data-v-a32cce86]:hover {
  background: var(--bg-glass-hover);
  color: var(--text-primary);
}
.visualai-modal__body[data-v-a32cce86] {
  color: var(--text-primary);
}

/* Same construction as SettingsPage's .error-banner, so a refused save reads
   the same whether it is answered in a dialog or on a page. */
.visualai-modal__error[data-v-a32cce86] {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 20px;
  padding: 10px 14px;
  border-radius: 10px;
  background: rgba(248, 113, 113, 0.08);
  border: 1px solid rgba(248, 113, 113, 0.32);
  color: var(--danger);
  font-size: 13px;
}
.visualai-modal__error-msg[data-v-a32cce86] {
  flex: 1 1 auto;
  /* Server messages enumerate the offending values and can be long; wrap them
     rather than widen the dialog or clip the name that makes the message
     useful. */
  overflow-wrap: anywhere;
}

/* The banner is a fully bordered box, so the footer's own separator rule would
   read as a second line 12px under it. Drop the rule while an error is up; the
   footer keeps it in every other case, which is all 25 existing callers. */
.visualai-modal__error + .visualai-modal__footer[data-v-a32cce86] {
  margin-top: 12px;
  padding-top: 0;
  border-top: none;
}
.visualai-modal__footer[data-v-a32cce86] {
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* Transition */
.visualai-modal-enter-active[data-v-a32cce86] {
  transition: opacity 0.3s ease;
}
.visualai-modal-enter-active .visualai-modal[data-v-a32cce86] {
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}
.visualai-modal-leave-active[data-v-a32cce86] {
  transition: opacity 0.2s ease;
}
.visualai-modal-leave-active .visualai-modal[data-v-a32cce86] {
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.visualai-modal-enter-from[data-v-a32cce86] {
  opacity: 0;
}
.visualai-modal-enter-from .visualai-modal[data-v-a32cce86] {
  transform: translateY(12px) scale(0.97);
  opacity: 0;
}
.visualai-modal-leave-to[data-v-a32cce86] {
  opacity: 0;
}
.visualai-modal-leave-to .visualai-modal[data-v-a32cce86] {
  transform: translateY(8px) scale(0.98);
  opacity: 0;
}

.visualai-btn[data-v-9f72db46] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 6px;
  font-family: var(--font, 'Inter', sans-serif);
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  white-space: nowrap;
  outline: none;
  position: relative;
}
.visualai-btn[data-v-9f72db46]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Sizes */
.visualai-btn--sm[data-v-9f72db46] {
  padding: 6px 12px;
  font-size: 12px;
}
.visualai-btn--md[data-v-9f72db46] {
  padding: 9px 18px;
  font-size: 13px;
}
.visualai-btn--lg[data-v-9f72db46] {
  padding: 12px 24px;
  font-size: 14px;
}

/* Icon-only */
.visualai-btn--icon-only.visualai-btn--sm[data-v-9f72db46] {
  width: 28px;
  height: 28px;
  padding: 0;
}
.visualai-btn--icon-only.visualai-btn--md[data-v-9f72db46] {
  width: 32px;
  height: 32px;
  padding: 0;
}
.visualai-btn--icon-only.visualai-btn--lg[data-v-9f72db46] {
  width: 40px;
  height: 40px;
  padding: 0;
}

/* Variants */
.visualai-btn--primary[data-v-9f72db46] {
  background: var(--accent);
  color: #fff;
}
.visualai-btn--primary[data-v-9f72db46]:hover:not(:disabled) {
  filter: brightness(1.1);
  box-shadow: 0 4px 16px var(--accent-glow);
}
.visualai-btn--secondary[data-v-9f72db46] {
  background: var(--bg-glass);
  color: var(--text-primary);
  border: 1px solid var(--border-glass);
}
.visualai-btn--secondary[data-v-9f72db46]:hover:not(:disabled) {
  background: var(--bg-glass-hover);
}
.visualai-btn--danger[data-v-9f72db46] {
  background: rgba(239, 68, 68, 0.15);
  color: var(--danger);
}
.visualai-btn--danger[data-v-9f72db46]:hover:not(:disabled) {
  background: rgba(239, 68, 68, 0.25);
}
.visualai-btn--success[data-v-9f72db46] {
  background: rgba(16, 185, 129, 0.15);
  color: var(--success);
}
.visualai-btn--success[data-v-9f72db46]:hover:not(:disabled) {
  background: rgba(16, 185, 129, 0.25);
}
.visualai-btn--warning[data-v-9f72db46] {
  background: rgba(245, 158, 11, 0.15);
  color: var(--warning);
}
.visualai-btn--warning[data-v-9f72db46]:hover:not(:disabled) {
  background: rgba(245, 158, 11, 0.25);
}
.visualai-btn--ghost[data-v-9f72db46] {
  background: transparent;
  color: var(--text-secondary);
}
.visualai-btn--ghost[data-v-9f72db46]:hover:not(:disabled) {
  background: var(--bg-glass-hover);
  color: var(--text-primary);
}

/* Spinner */
.visualai-btn__spinner[data-v-9f72db46] {
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: visualai-btn-spin-9f72db46 0.6s linear infinite;
}
.visualai-btn--loading[data-v-9f72db46] {
  pointer-events: none;
}
.visualai-btn__icon[data-v-9f72db46] {
  font-size: 14px;
  line-height: 1;
}
.visualai-btn--sm .visualai-btn__icon[data-v-9f72db46] {
  font-size: 12px;
}
@keyframes visualai-btn-spin-9f72db46 {
to {
    transform: rotate(360deg);
}
}

.visualai-table-root[data-v-748668d9] {
  width: 100%;
}

/* Toolbar */
.visualai-table__toolbar[data-v-748668d9] {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.visualai-table__search[data-v-748668d9] {
  position: relative;
  flex: 1;
  max-width: 320px;
}
.visualai-table__search-icon[data-v-748668d9] {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  font-size: 14px;
  pointer-events: none;
}
.visualai-table__search-input[data-v-748668d9] {
  width: 100%;
  padding: 9px 14px 9px 38px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 13px;
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-table__search-input[data-v-748668d9]::placeholder {
  color: var(--text-muted);
}
.visualai-table__search-input[data-v-748668d9]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

/* Table */
.visualai-table__container[data-v-748668d9] {
  overflow-x: auto;
  transition: opacity 0.2s ease;
}
.visualai-table__container--refreshing[data-v-748668d9] {
  opacity: 0.6;
  /* Rows stay in the DOM during a refetch (see the template) — block
     pointer events so a click can't land on a row, sort header, or
     per-row action while its data is being replaced underneath it. */
  pointer-events: none;
}
.visualai-table[data-v-748668d9] {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.visualai-table__th[data-v-748668d9] {
  text-align: left;
  padding: 12px 16px;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  border-bottom: 1px solid var(--border-color);
  white-space: nowrap;
  user-select: none;
}
.visualai-table__th--sortable[data-v-748668d9] {
  cursor: pointer;
  transition: color 0.2s;
}
.visualai-table__th--sortable[data-v-748668d9]:hover {
  color: var(--text-primary);
}

/* AB#17056 — was 100px, which is why Members overflowed in the first place
   (AB#16907): up to five 28px icon buttons in a row need roughly 156px once
   their gaps and the cell's own inline padding are counted, and 100px was
   clipping them well before the row-actions rule capped a row at two inline
   controls plus one overflow trigger. Widened once, here, rather than per
   caller. This is `auto` table layout inside an `overflow-x: auto` container
   (`.visualai-table__container`), not `table-layout: fixed` — the extra
   width grows the table itself and, on a narrow viewport, the scroll
   container takes it; it does not shrink any other column's own
   content-driven minimum width. Recounted rather than trusting the
   ticket's "21": 22 current `<VisualAiTable>` call sites (grepped
   `packages/`, excluding `__tests__` and this file's own template; 15 of
   the 22 render an `#actions` slot at all). None sets
   `table-layout: fixed` and none overrides `.visualai-table__th--actions`
   locally, so this is the only place the width is declared. MembersPage is
   one of the 22 — its import of `RowActionsMenu` moved to `shared` in this
   same ticket, but it still renders every permitted action through the
   menu with no inline split; Members only adopts the two-inline-actions
   rule when it migrates (ticket 3 of 3). */
.visualai-table__th--actions[data-v-748668d9] {
  text-align: center;
  width: 156px;
}
.visualai-table__th--select[data-v-748668d9] {
  width: 40px;
  text-align: center;
}
.visualai-table__th-content[data-v-748668d9] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.visualai-table__sort-icon[data-v-748668d9] {
  font-size: 10px;
  line-height: 1;
}
.visualai-table__td[data-v-748668d9] {
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-primary);
  vertical-align: middle;
}
.visualai-table__td--actions[data-v-748668d9] {
  text-align: center;
}
.visualai-table__td--select[data-v-748668d9] {
  text-align: center;
  width: 40px;
}

/* Column alignment (AB#16313) — the `align` descriptor on TableColumn.
   Header and body TOGETHER, from one declaration, because they are one
   statement about a column: a right-aligned figure under a left-aligned
   heading is what this pair exists to stop. Declared AFTER the base
   `__th` / `__td` rules so the single-class specificity resolves in favour
   of the explicit alignment. There is no `--left` rule: left IS the base. */
.visualai-table__th--center[data-v-748668d9],
.visualai-table__td--center[data-v-748668d9] {
  text-align: center;
}
.visualai-table__th--right[data-v-748668d9],
.visualai-table__td--right[data-v-748668d9] {
  text-align: right;
}
.visualai-table__row[data-v-748668d9] {
  transition: background 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-table__row[data-v-748668d9]:hover {
  background: var(--bg-glass-hover);
}

/* Scoped via the [tabindex] attribute rather than a new class — tabindex is
   only ever rendered when rowInteractive is true (see template), so this
   rule can't affect the other seven consumers. Mirrors the accent/ring pair
   this component already uses for its own search-input :focus above. */
.visualai-table__row[tabindex][data-v-748668d9]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.visualai-table__row:last-child .visualai-table__td[data-v-748668d9] {
  border-bottom: none;
}

/* Empty state */
/* VisualAiEmpty already brings its own 48px 24px padding — this only needs
   to keep a little horizontal breathing room around the <td> itself. */
.visualai-table__empty[data-v-748668d9] {
  padding: 8px 16px;
  text-align: center;
}

/* Skeleton */
.visualai-table__skeleton[data-v-748668d9] {
  height: 16px;
  background: var(--bg-glass-hover);
  border-radius: 4px;
  animation: visualai-skeleton-pulse-748668d9 1.5s ease-in-out infinite;
  width: 80%;
}
.visualai-table__skeleton--sm[data-v-748668d9] {
  width: 40px;
  margin: 0 auto;
}
@keyframes visualai-skeleton-pulse-748668d9 {
0%, 100% {
    opacity: 1;
}
50% {
    opacity: 0.4;
}
}

/* Pagination */
/* The bar itself. Carries what .visualai-table__pagination used to, since the
   gear now shares this row and the bar can outlive the pager. */
.visualai-table__footer[data-v-748668d9] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  padding: 16px;
  border-top: 1px solid var(--border-color);
  font-size: 13px;
  color: var(--text-secondary);
  flex-wrap: wrap;
  gap: 12px;
}

/* margin-left:auto rather than space-between alone: with no total there is no
   "Showing …" on the left, and the controls would otherwise jump to it. */
.visualai-table__footer-controls[data-v-748668d9] {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}
.visualai-table__pagination[data-v-748668d9] {
  display: flex;
  align-items: center;
  gap: 12px;
}
.visualai-table__page-size[data-v-748668d9] {
  padding: 6px 28px 6px 10px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 12px;
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  cursor: pointer;
  -webkit-appearance: none;
  -moz-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 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

/* AB#16907. The OPEN option list is painted by the OS, not by the rules above.
   `appearance: none` styles the CLOSED control only, and an <option> does not
   reliably inherit its select's `color`/`background` — so the popup has to be
   coloured explicitly or it falls back to the UA's own canvas.

   That is what broke in dark mode. `--bg-input` is a TRANSLUCENT overlay
   (`rgba(255,255,255,0.06)`), which reads as ~#191d28 composited over the
   page's `--bg-base: #0a0e1a`, but composites to near-white over the UA's
   default popup canvas. The inherited `--text-primary: #f0f2f5` then landed
   near-white on near-white — roughly 1.1:1 — and only the row under the cursor
   was legible, because the UA paints its own solid highlight there. Opaque
   values, so nothing depends on what the popup is drawn over: #f0f2f5 on
   #1a1f2e is ~14.5:1.

   The lift off `--bg-base` and the pair of literals are deliberate and match
   DynamicForm.vue, which fixed the same defect on its own <select>: the token
   itself is too near-black for a popup, and a translucent token cannot be used
   here at all for the reason above.

   NOT replaced with a custom dropdown under this ticket — that is a much
   larger change with keyboard and a11y consequences (see VisualAiSelect). This
   fixes the contrast and leaves the native control, and its keyboard, alone. */
.visualai-table__page-size option[data-v-748668d9] {
  background-color: var(--bg-base);
  color: var(--text-primary);
}
[data-theme='dark'] .visualai-table__page-size option[data-v-748668d9] {
  background-color: #1a1f2e;
  color: #f0f2f5;
}
[data-theme='light'] .visualai-table__page-size option[data-v-748668d9] {
  background-color: #ffffff;
  color: #1a1d2e;
}
.visualai-table__pagination-btns[data-v-748668d9] {
  display: flex;
  gap: 4px;
}
.visualai-table__page-btn[data-v-748668d9] {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
  border-radius: 6px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  font-size: 13px;
  font-family: var(--font, 'Inter', sans-serif);
}
.visualai-table__page-btn[data-v-748668d9]:hover:not(:disabled),
.visualai-table__page-btn--active[data-v-748668d9] {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.visualai-table__page-btn[data-v-748668d9]:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ---- Column settings (OBS-05) ---- */
.visualai-table__cols-btn[data-v-748668d9] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: var(--bg-glass);
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s ease;
}
.visualai-table__cols-btn[data-v-748668d9]:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.visualai-table__cols-count[data-v-748668d9] {
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 10px;
  min-width: 18px;
  text-align: center;
}
.visualai-table__cols-hint[data-v-748668d9] {
  font-size: 13px;
  color: var(--text-secondary);
  margin-bottom: 12px;
}

/* Scrolls vertically: a table with many columns must not push the modal's
   actions off-screen. */
.visualai-table__cols-list[data-v-748668d9] {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--border-color);
  border-radius: 8px;
}
.visualai-table__cols-item + .visualai-table__cols-item[data-v-748668d9] {
  border-top: 1px solid var(--border-color);
}
.visualai-table__cols-label[data-v-748668d9] {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  font-size: 13px;
  color: var(--text-primary);
  cursor: pointer;
}
.visualai-table__cols-label[data-v-748668d9]:hover {
  background: var(--bg-glass-hover);
}
.visualai-table__cols-label.is-locked[data-v-748668d9] {
  cursor: default;
  color: var(--text-secondary);
}
.visualai-table__cols-required[data-v-748668d9] {
  margin-left: auto;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.visualai-badge[data-v-4d221ff0] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 20px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
.visualai-badge--md[data-v-4d221ff0] {
  padding: 4px 10px;
  font-size: 11px;
}
.visualai-badge--sm[data-v-4d221ff0] {
  padding: 2px 8px;
  font-size: 10px;
}
.visualai-badge__dot[data-v-4d221ff0] {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}
.visualai-badge--sm .visualai-badge__dot[data-v-4d221ff0] {
  width: 5px;
  height: 5px;
}

/* Variants */
.visualai-badge--success[data-v-4d221ff0] {
  background: rgba(52, 211, 153, 0.12);
  color: var(--success);
}
.visualai-badge--success .visualai-badge__dot[data-v-4d221ff0] {
  background: var(--success);
}
.visualai-badge--warning[data-v-4d221ff0] {
  background: rgba(251, 191, 36, 0.12);
  color: var(--warning);
}
.visualai-badge--warning .visualai-badge__dot[data-v-4d221ff0] {
  background: var(--warning);
}
.visualai-badge--danger[data-v-4d221ff0] {
  background: rgba(248, 113, 113, 0.12);
  color: var(--danger);
}
.visualai-badge--danger .visualai-badge__dot[data-v-4d221ff0] {
  background: var(--danger);
}
.visualai-badge--info[data-v-4d221ff0] {
  background: rgba(96, 165, 250, 0.12);
  color: var(--info);
}
.visualai-badge--info .visualai-badge__dot[data-v-4d221ff0] {
  background: var(--info);
}
.visualai-badge--neutral[data-v-4d221ff0] {
  background: var(--bg-glass);
  color: var(--text-muted);
}
.visualai-badge--neutral .visualai-badge__dot[data-v-4d221ff0] {
  background: var(--text-muted);
}

.visualai-input[data-v-5fb0b1f3] {
  width: 100%;
}
.visualai-input__label[data-v-5fb0b1f3] {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.visualai-input__wrapper[data-v-5fb0b1f3] {
  position: relative;
  width: 100%;
}
.visualai-input__icon[data-v-5fb0b1f3] {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  font-size: 14px;
  pointer-events: none;
  z-index: 1;
}
.visualai-input__field[data-v-5fb0b1f3] {
  width: 100%;
  padding: 10px 14px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 14px;
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-input--has-icon .visualai-input__field[data-v-5fb0b1f3] {
  padding-left: 38px;
}
.visualai-input__field[data-v-5fb0b1f3]::placeholder {
  color: var(--text-muted);
}
.visualai-input__field[data-v-5fb0b1f3]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-input__field[data-v-5fb0b1f3]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Error state */
.visualai-input--error .visualai-input__field[data-v-5fb0b1f3] {
  border-color: var(--danger);
}
.visualai-input--error .visualai-input__field[data-v-5fb0b1f3]:focus {
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
}
.visualai-input__error[data-v-5fb0b1f3] {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}

.visualai-multiselect[data-v-caaee57c] {
  width: 100%;
}
.visualai-multiselect__wrapper[data-v-caaee57c] {
  position: relative;
  width: 100%;
}

/* Deliberately the same geometry as .visualai-select__field, read from the same
   custom properties, so the two line up without either restating the other's
   numbers. The caret is drawn the same way for the same reason. */
.visualai-multiselect__field[data-v-caaee57c] {
  width: 100%;
  text-align: left;
  padding:
    var(--va-control-py, 10px)
    32px
    var(--va-control-py, 10px)
    var(--va-control-px, 14px);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  color: var(--text-primary);
  font-size: var(--va-control-font, 14px);
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
.visualai-multiselect__field[data-v-caaee57c]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-multiselect__field[data-v-caaee57c]:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* One line, clipped rather than wrapped: a wrapping summary would grow the
   trigger and reintroduce the row-height problem this control exists to fix. */
.visualai-multiselect__summary[data-v-caaee57c] {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The panel's own rules are UNSCOPED, below — see the note there. */

/* UNSCOPED ON PURPOSE — AB#15895.
   The panel is teleported to #va-overlay-root, outside this component's
   subtree, so Vue's scoped data attribute never reaches it and a scoped rule
   here would not apply at all. Same construction, and the same reason, as
   VisualAiSelect's second style block. Colours still resolve because the
   theme's custom properties live on documentElement.

   ⚠️ POSITION, WIDTH, MAX-HEIGHT AND Z-INDEX ARE NOT SET HERE. They arrive as
   an inline style from `usePanelPosition`, measured from the trigger's
   bounding rect on open and on every scroll or resize. Restating any of them
   in CSS would either be overridden silently or fight the composable:
   `min-width: 100%` in particular resolved against the containing block, which
   for a fixed-position node is the VIEWPORT — a full-width panel. */
.visualai-multiselect__panel {
  /* So the supplied `width` is the trigger's width including this padding and
     border, rather than 14px wider than the control it hangs off. */
  box-sizing: border-box;
  overflow-y: auto;
  padding: 6px;
  background: var(--bg-base);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  box-shadow: var(--shadow-dropdown);
  font-family: var(--font, 'Inter', sans-serif);
}

/* Focus moves here on open when there is no search box; it is a scroll and
   announcement target, not a control, so it draws no ring of its own. */
.visualai-multiselect__panel:focus {
  outline: none;
}
.visualai-multiselect__search {
  box-sizing: border-box;
  width: 100%;
  margin-bottom: 6px;
  padding: var(--va-control-py, 10px) var(--va-control-px, 14px);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--va-control-radius, 6px);
  color: var(--text-primary);
  font-size: var(--va-control-font, 14px);
  font-family: inherit;
  outline: none;
}
.visualai-multiselect__search:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-multiselect__empty {
  margin: 0;
  padding-block: 8px;
  /* Logical, so the panel reads correctly under dir="rtl". */
  padding-inline: var(--va-control-px, 14px);
  font-size: 12px;
  color: var(--text-secondary);
  text-align: start;
}
.visualai-multiselect__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 4px;
  font-size: var(--va-control-font, 14px);
  color: var(--text-primary);
  cursor: pointer;
  /* Deliberately NOT `white-space: nowrap`. That was right while the panel
     could shrink-to-fit past its trigger (`min-width: 100%`, width auto); the
     panel is now exactly the trigger's width, so nowrap would turn a long
     option name into a horizontal scrollbar instead of a second line. */
  text-align: start;
}

/* A wrapped label must not squeeze the box it belongs to. */
.visualai-multiselect__row > input[type='checkbox'] {
  flex-shrink: 0;
}
.visualai-multiselect__row:hover {
  background: var(--bg-glass-hover);
}
.visualai-multiselect__row--locked {
  opacity: 0.6;
  cursor: not-allowed;
}

/* One line (OBS-09): search, chips, the Filters toggle and the host's page
   actions all share this row — it replaced the page-header/subtitle block and
   the toggle's own row below the panel. `nowrap` is the point of the change;
   the narrow-screen override at the bottom of this file lets it wrap again
   rather than overflow. */
/* FLEX-END with an explicit control height — NOT stretch, and not center.
   The controls in this row were each sized independently. Measured in Chromium
   against the built CSS, Detections ran 38 / 29 / 30 / 31 / 31 px — four
   heights and a 4.5px spread in their tops. Only the search input is driven by
   --va-control-py; the toggle, the chips and each host page`s action buttons
   were hand-tuned separately. One explicit control height fixes that.

   STRETCH WAS TRIED AND SHIPPED BRIEFLY, AND IT REGRESSED REPORTS. Taking the
   height from the tallest item in the row reads as self-maintaining, right up
   until a sibling is tall for a reason that has nothing to do with control
   height. Reports sets `searchable: false` and puts a LABELLED select in the
   `leading` slot — a label stacked above a control, 60px — so every button
   stretched to 60px in production. The literal below is not the fragile
   choice; it is what makes this row immune to a tall sibling.

   FLEX-END, not center. Center was measured too: it fixes the height but
   leaves the buttons floating ABOVE the control line on Reports (bottom 183
   against the select`s 194). Bottom-aligning puts every control on the same
   baseline whether or not a neighbour carries a label above it.

   Measured across all three toolbar shapes in the codebase: Detections
   (search + buttons), Reports (labelled leading slot, no search), and
   search + chips + actions. All 38px, bottom spread 0, and on Reports the
   buttons share the select`s bottom edge exactly.

   The groups below need the same alignment: each is its own flex container,
   so setting it only here leaves their children aligned inside a box that is
   itself aligned, which is not the same thing. */
.toolbar[data-v-81c06bf7] {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 12px;
  flex-wrap: nowrap;
}

/* Sized like .toolbar__search, and for the same reason: it occupies the same
   head-of-row position, so a page using `leading` instead of a search box gets
   the same row proportions rather than a control that either stretches to fill
   the band or sits marooned at its natural width. */
.toolbar__leading[data-v-81c06bf7] {
  flex: 0 1 320px;
  min-width: 160px;
}

/* Shrinkable, not fixed: with actions now sharing the row, a rigid 320px is
   what would force the wrap this layout exists to avoid. It keeps 320px when
   there is room and gives way first when there isn't. */
.toolbar__search[data-v-81c06bf7] {
  flex: 0 1 320px;
  min-width: 160px;
}
.toolbar__chips[data-v-81c06bf7] {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  flex-shrink: 0;
}
.filter-chip[data-v-81c06bf7] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 20px;
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
  color: var(--text-secondary);
  font-size: 12px;
  font-weight: 500;
  font-family: var(--font, 'Inter', sans-serif);
  cursor: pointer;
  transition: all 0.2s ease;
}
.filter-chip[data-v-81c06bf7]:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.filter-chip--active[data-v-81c06bf7] {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* Right-aligned per OBS-01: filters sit on the right on every list screen.
   `margin-left:auto` is what does that now — this used to be a full-width
   block below the panel with `justify-content:flex-end`, and since OBS-09 it
   is an item in the toolbar row. The auto margin eats the free space, so this
   and the actions after it sit right while search and chips stay left. */
.toolbar__filter-toggle[data-v-81c06bf7] {
  display: flex;
  margin-left: auto;
  flex-shrink: 0;
}
.toolbar__actions[data-v-81c06bf7] {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  flex-shrink: 0;
}

/* `v-if="$slots.actions"` only asks whether the host PASSED a slot, not
   whether it rendered anything. Several pages wrap their actions in
   <PermissionGuard>, which renders nothing when the permission is denied — so
   an operator without `visitors.add` (or `gates.add`, or `users.add`) would
   otherwise get an empty flex item and, through .toolbar's 12px gap, a
   phantom gap to the right of the Filters button. :empty collapses it. */
.toolbar__actions[data-v-81c06bf7]:empty {
  display: none;
}

/* One control height for everything in the row. THREE kinds of thing live
   here and each needs naming separately, which is the trap:

     - this component`s own `.filter-toggle-btn`;
     - this component`s own `.filter-chip`, rendered from the `chips` prop,
       which 11 pages pass. Easy to miss because it is NOT `.chip` — a host
       page`s chip and the bar`s own chip are different classes, and the
       first version of this rule covered only the former (AB#15516);
     - host slot content, `.chip` and `.btn`. That compiles in the HOST`s
       scope, so this component`s scoped rules cannot reach it directly — but
       the wrappers belong to this template and carry the scope attribute, so
       a descendant selector through them does.

   38px is what --va-control-py 10px + a 14px control font + a 1px border
   produces for an input. The spec asserts every one of these selectors is
   covered, not merely that the rule exists. */
.toolbar[data-v-81c06bf7] .chip,
.toolbar[data-v-81c06bf7] .btn,
.toolbar__actions[data-v-81c06bf7] button,
.toolbar__chips .filter-chip[data-v-81c06bf7],
.toolbar .filter-toggle-btn[data-v-81c06bf7] {
  min-height: 38px;
}
.filter-toggle-btn[data-v-81c06bf7] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: var(--bg-glass);
  color: var(--text-secondary);
  font-size: 13px;
  font-family: var(--font, 'Inter', sans-serif);
  cursor: pointer;
  transition: all 0.2s ease;
}
.filter-toggle-btn[data-v-81c06bf7]:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.filter-count[data-v-81c06bf7] {
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 10px;
  min-width: 18px;
  text-align: center;
}
.filter-panel[data-v-81c06bf7] {
  background: var(--bg-glass);
  border: 1px solid var(--border-glass);
  border-radius: 12px;
  padding: 20px;
  margin-bottom: 16px;
}
.filter-panel__header[data-v-81c06bf7] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}
.filter-panel__header h3[data-v-81c06bf7] {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
}
.filter-panel__header h3 i[data-v-81c06bf7] {
  color: var(--accent);
  margin-right: 8px;
}
.filter-panel__actions[data-v-81c06bf7] {
  display: flex;
  gap: 8px;
}
.filter-grid[data-v-81c06bf7] {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 900px) {
.filter-grid[data-v-81c06bf7] {
    grid-template-columns: repeat(2, 1fr);
}

  /* One line is a desktop goal, not a promise to overflow on a phone. Below
     900px the row wraps again; `margin-left:auto` on the toggle is dropped so
     that once wrapped the controls read left-to-right instead of leaving a
     ragged gap mid-row. */
.toolbar[data-v-81c06bf7] {
    flex-wrap: wrap;
}
.toolbar__filter-toggle[data-v-81c06bf7] {
    margin-left: 0;
}
.toolbar__search[data-v-81c06bf7] {
    flex-basis: 100%;
}
}
.slide-enter-active[data-v-81c06bf7],
.slide-leave-active[data-v-81c06bf7] {
  transition: all 0.3s ease;
  overflow: hidden;
}
.slide-enter-from[data-v-81c06bf7],
.slide-leave-to[data-v-81c06bf7] {
  max-height: 0;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
  margin-bottom: 0;
}

.visualai-stepper[data-v-000e12f7] {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 24px;
}
.visualai-stepper__step[data-v-000e12f7] {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  /* Reset the button chrome — this is a step indicator, not a push button. */
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  text-align: left;
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 600;
}
.visualai-stepper__step[data-v-000e12f7]:disabled {
  /* Not dimmed: the CURRENT step is disabled too, and it must stay legible. */
  cursor: default;
  opacity: 1;
}
.visualai-stepper__step.is-clickable[data-v-000e12f7] {
  cursor: pointer;
}
.visualai-stepper__marker[data-v-000e12f7] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border-color);
  background: var(--bg-secondary);
  font-size: 12px;
}
.visualai-stepper__label[data-v-000e12f7] {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.visualai-stepper__step.is-current[data-v-000e12f7] {
  color: var(--primary);
}
.visualai-stepper__step.is-current .visualai-stepper__marker[data-v-000e12f7] {
  border-color: var(--primary);
  color: var(--primary);
}
.visualai-stepper__step.is-complete .visualai-stepper__marker[data-v-000e12f7] {
  border-color: var(--success);
  background: var(--success);
  color: #fff;
}
.visualai-stepper__bar[data-v-000e12f7] {
  flex: 1;
  height: 2px;
  min-width: 12px;
  background: var(--border-color);
}
.visualai-stepper__step.is-complete .visualai-stepper__bar[data-v-000e12f7] {
  background: var(--success);
}

.mih[data-v-20d6b1c3] {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--border-color);
  border-radius: 10px;
  background: var(--bg-surface);
}

/* A member with nothing enrolled is the case this flow exists to repair, so it
   is marked rather than left to read as ordinary. */
.mih--empty[data-v-20d6b1c3] {
  border-color: var(--warning);
}
.mih__avatar[data-v-20d6b1c3] {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--bg-glass);
  color: var(--text-secondary);
}
.mih__avatar img[data-v-20d6b1c3] {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.mih__who[data-v-20d6b1c3] {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.mih__name[data-v-20d6b1c3] {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mih__id[data-v-20d6b1c3] {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
}
.mih__id-label[data-v-20d6b1c3] {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10px;
  color: var(--text-muted);
}
.mih__id-value[data-v-20d6b1c3] {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text-secondary);
}
.mih__photos[data-v-20d6b1c3] {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  font-size: 12px;
  color: var(--text-secondary);
}
.mih--empty .mih__photos[data-v-20d6b1c3] {
  color: var(--warning);
}

.snapshot-preview[data-v-a6b3e934] {
  display: inline-flex;
}

/*
 * A real button, not a div with a click handler. It is in the tab order, Enter
 * and Space activate it for free, it can be labelled, and it works on touch.
 * The previous Detections thumbnail had a handler on a bare <div> with no role,
 * no tabindex and no key handler, so there was no keyboard route to any
 * snapshot at all.
 */
.snapshot-preview__opener[data-v-a6b3e934] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  line-height: 0;
  border-radius: 4px;
  /* The affordance. Nothing in the old markup said the thumbnail was live. */
  cursor: zoom-in;
}
.snapshot-preview__opener[data-v-a6b3e934]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*
 * Fixed HEIGHT, natural width, no border, no background: the row stays a
 * uniform height whatever the aspect, and a narrow crop is simply narrow
 * instead of being a sliver marooned in an outlined box.
 */
.snapshot-preview__thumb[data-v-a6b3e934] {
  display: block;
  height: 44px;
  width: auto;
  max-width: 120px;
  object-fit: contain;
  border-radius: 4px;
  transition: transform 0.12s ease;
}
.snapshot-preview__opener:hover .snapshot-preview__thumb[data-v-a6b3e934] {
  transform: scale(1.06);
}
.snapshot-preview__thumb-missing[data-v-a6b3e934] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 4px;
  color: var(--text-muted);
  font-size: 13px;
}

/* ── the peek ─────────────────────────────────────────────────────────── */
.snapshot-preview__peek[data-v-a6b3e934] {
  position: fixed;
  z-index: 1100;
  pointer-events: none;
  padding: 6px;
  border-radius: 10px;
  border: 1px solid var(--border-glass);
  background: var(--bg-card, var(--bg-glass));
  box-shadow: var(--shadow-dropdown);
}
.snapshot-preview__peek img[data-v-a6b3e934] {
  display: block;
  width: auto;
  height: auto;
  min-width: 120px;
  max-width: 340px;
  max-height: 300px;
  object-fit: contain;
  border-radius: 6px;
}
.snapshot-preview__peek-hint[data-v-a6b3e934] {
  display: block;
  padding: 5px 4px 1px;
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
}

/* ── the panel ────────────────────────────────────────────────────────── */
.snapshot-preview__overlay[data-v-a6b3e934] {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/*
 * `max-content`, not a fixed 1200px. The old modal was 1200px wide whatever it
 * held, so a 300x100 plate sat in a 1200px frame. The dialog is now as wide as
 * the images plus the details column, and no wider.
 */
.snapshot-preview__dialog[data-v-a6b3e934] {
  width: max-content;
  max-width: min(96vw, 1100px);
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--border-glass);
  box-shadow: var(--shadow-dropdown);
  background: var(--bg-card, var(--bg-glass));
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
[data-theme="dark"] .snapshot-preview__dialog[data-v-a6b3e934] { background: rgba(15, 20, 35, 0.97);
}
[data-theme="light"] .snapshot-preview__dialog[data-v-a6b3e934] { background: rgba(255, 255, 255, 0.97);
}

/*
 * `width: 0; min-width: 100%` — a title plus a track number plus three chips is
 * easily wider than a 154px person crop, and laid out normally it would set the
 * dialog width and strand dead space beside that crop. Zero width contributes
 * nothing to the intrinsic size; the body decides, and this wraps within it.
 */
.snapshot-preview__header[data-v-a6b3e934] {
  width: 0;
  min-width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-color);
}
.snapshot-preview__title[data-v-a6b3e934] {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
}
.snapshot-preview__title > i[data-v-a6b3e934] { color: var(--accent);
}
.snapshot-preview__chip[data-v-a6b3e934] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 12px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.snapshot-preview__chip i[data-v-a6b3e934] { font-size: 10px;
}
.snapshot-preview__chip--neutral[data-v-a6b3e934] { background: var(--bg-glass-hover); color: var(--text-secondary);
}
.snapshot-preview__chip--success[data-v-a6b3e934] { background: rgba(52, 211, 153, 0.14); color: var(--success);
}
.snapshot-preview__chip--danger[data-v-a6b3e934]  { background: rgba(248, 113, 113, 0.14); color: var(--danger);
}
.snapshot-preview__chip--warning[data-v-a6b3e934] { background: rgba(251, 191, 36, 0.14); color: var(--warning);
}

/* Track #1234 is an identifier, not a status — it gets no pill. */
.snapshot-preview__chip--plain[data-v-a6b3e934] {
  padding: 0;
  background: none;
  font-family: 'SF Mono', 'Fira Code', monospace;
  font-size: 12px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}

/*
 * The back control (AB#15612). Sits at the head of the title row so the panel
 * reads left-to-right as "where you can go" then "what you are looking at",
 * and inherits the header's zero-width trick — it must not be what decides how
 * wide the dialog is any more than the title is.
 */
.snapshot-preview__back[data-v-a6b3e934] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}
.snapshot-preview__back[data-v-a6b3e934]:hover { background: var(--bg-glass-hover); color: var(--text-primary);
}
.snapshot-preview__back[data-v-a6b3e934]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px;
}

/*
 * The pane takes the details column's slot in the flex row, and is allowed to
 * be wider: a details list is label/value pairs, whereas this holds a search
 * field and rows carrying a name, a code, a property and a pill. It stays
 * capped so the crops beside it keep their width.
 */
.snapshot-preview__pane[data-v-a6b3e934] {
  flex: 1 1 340px;
  min-width: 300px;
  max-width: 420px;
  display: flex;
  flex-direction: column;
}
.snapshot-preview__close[data-v-a6b3e934] {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.2s;
}
.snapshot-preview__close[data-v-a6b3e934]:hover { background: var(--bg-glass-hover); color: var(--text-primary);
}

/*
 * Flex, not a fixed grid. The waste this replaces was per-COLUMN, not per
 * modal: `grid-template-columns: 2fr 1fr 1fr` gave each image a share of the
 * width regardless of its shape, so a 0.44 person crop floated in about half an
 * empty panel while the 1.00 face crop nearly filled its own.
 */
.snapshot-preview__body[data-v-a6b3e934] {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 20px;
  padding: 16px 18px 20px;
  max-height: calc(90vh - 62px);
  overflow-y: auto;
}

/* Each panel is sized by its own image, and by nothing else. */
.snapshot-preview__figure[data-v-a6b3e934] {
  margin: 0;
  width: max-content;
  max-width: 100%;
}

/*
 * THE SIZING RULE. One rule, every type, no branches.
 *
 * FLOOR   `min-width` lifts the small crops to legibility — the 112px face
 *         crop, the smallest image in the system, comes up to 160px.
 * CEILING `max-width` / `max-height` cap the full frames — the 2560px smoke
 *         frame lands at 340px wide.
 *
 * `object-fit: contain` is what makes the pair safe together. A floor on one
 * axis and a ceiling on the other can collide (a 490x1080 person crop is capped
 * to 340 tall, which puts it at 154 wide, under the 160 floor), and CSS
 * resolves such a collision by STRETCHING the image. `contain` keeps the
 * picture at its true aspect inside the resolved box; because there is no
 * border and no background, the few pixels of slack are invisible rather than
 * being the outlined emptiness this component exists to remove.
 */
.snapshot-preview__image[data-v-a6b3e934] {
  display: block;
  width: auto;
  height: auto;
  min-width: 160px;
  max-width: min(38vw, 340px);
  max-height: 340px;
  object-fit: contain;
  border-radius: 8px;
}

/*
 * Same zero-width trick as the header, one level down: 'Person Crop' must not
 * decide how wide the person crop's panel is.
 */
.snapshot-preview__figcaption[data-v-a6b3e934] {
  width: 0;
  min-width: 100%;
  margin-bottom: 9px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.snapshot-preview__missing[data-v-a6b3e934] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 160px;
  padding: 24px 16px;
  border-radius: 8px;
  border: 1px dashed var(--border-color);
  color: var(--text-muted);
  font-size: 12px;
}
.snapshot-preview__details[data-v-a6b3e934] {
  flex: 1 1 210px;
  min-width: 210px;
  max-width: 340px;
  text-align: left;
}
.snapshot-preview__meta[data-v-a6b3e934] {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 10px 14px;
  margin: 0;
  font-size: 13px;
}
.snapshot-preview__meta dt[data-v-a6b3e934] {
  align-self: start;
  padding-top: 2px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted);
}
.snapshot-preview__meta dd[data-v-a6b3e934] {
  margin: 0;
  min-width: 0;
  color: var(--text-primary);
}
.snapshot-preview__meta-sub[data-v-a6b3e934] {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-muted);
}
.snapshot-preview-fade-enter-active[data-v-a6b3e934],
.snapshot-preview-fade-leave-active[data-v-a6b3e934] { transition: opacity 0.2s ease;
}
.snapshot-preview-fade-enter-from[data-v-a6b3e934],
.snapshot-preview-fade-leave-to[data-v-a6b3e934] { opacity: 0;
}

.member-search[data-v-8837fa9b] {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  text-align: left;
}
.member-search__label[data-v-8837fa9b] {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.member-search__input[data-v-8837fa9b] {
  width: 100%;
  padding: 8px 11px;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
  color: var(--text-primary);
  font-size: 13px;
}
.member-search__input[data-v-8837fa9b]:focus {
  outline: none;
  border-color: var(--accent);
}
.member-search__hint[data-v-8837fa9b],
.member-search__count[data-v-8837fa9b] {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}
.member-search__list[data-v-8837fa9b] {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Capped and scrolled rather than growing: the crops beside this set the
     dialog's height, and a twelve-row list must not stretch past them. */
  max-height: 300px;
  overflow-y: auto;
}
.member-row[data-v-8837fa9b] {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border-color);
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: all 0.15s;
}
.member-row[data-v-8837fa9b]:hover { background: var(--bg-glass-hover);
}
.member-row[data-v-8837fa9b]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px;
}

/* The chosen row is marked by more than colour: the border thickens and the
   background fills, so the selection survives a monochrome display. */
.member-row--selected[data-v-8837fa9b] {
  border-color: var(--accent);
  background: var(--bg-glass-hover);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.member-row__avatar[data-v-8837fa9b] {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--bg-glass-hover);
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
}
.member-row__main[data-v-8837fa9b] {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.member-row__name[data-v-8837fa9b] {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.member-row__sub[data-v-8837fa9b] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-muted);
  overflow: hidden;
}
.member-row__code[data-v-8837fa9b] {
  font-family: 'SF Mono', 'Fira Code', monospace;
  font-size: 11px;
}
.member-row__property[data-v-8837fa9b] {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.member-row__pills[data-v-8837fa9b] {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}
.member-pill[data-v-8837fa9b] {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  white-space: nowrap;
}
.member-pill--ok[data-v-8837fa9b]       { background: rgba(52, 211, 153, 0.14); color: var(--success);
}
.member-pill--none[data-v-8837fa9b]     { background: rgba(251, 191, 36, 0.14); color: var(--warning);
}
.member-pill--inactive[data-v-8837fa9b] { background: rgba(248, 113, 113, 0.14); color: var(--danger);
}
.member-search__none[data-v-8837fa9b] {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 12px;
  border: 1px dashed var(--border-color);
  border-radius: 10px;
  font-size: 12px;
  color: var(--text-muted);
}
.member-search__none p[data-v-8837fa9b] { margin: 0;
}
.member-search__error[data-v-8837fa9b] {
  margin: 0;
  font-size: 12px;
  color: var(--danger);
}
.member-search__done[data-v-8837fa9b] {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  border-radius: 10px;
  background: rgba(52, 211, 153, 0.12);
  font-size: 13px;
  color: var(--text-primary);
}
.member-search__done > i[data-v-8837fa9b] { color: var(--success); margin-top: 2px;
}
.member-search__done-sub[data-v-8837fa9b] {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--text-muted);
}
.member-search__footer[data-v-8837fa9b] {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: auto;
  padding-top: 4px;
}

.row-actions[data-v-1e7bef8b] {
  display: inline-flex;
}
.row-actions__trigger[data-v-1e7bef8b] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}
.row-actions__trigger[data-v-1e7bef8b]:hover {
  background: var(--bg-glass-active);
  color: var(--text-primary);
}
.row-actions__trigger[data-v-1e7bef8b]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* UNSCOPED on purpose: the menu is teleported to #va-overlay-root, outside
   this component's subtree, so Vue's scoped attribute never reaches it. The
   theme variables still resolve because they live on documentElement — the
   same arrangement VisualAiSelect's panel styles use. */
.row-actions__menu {
  min-width: 180px;
  padding-block: 4px;
  background: var(--bg-base);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  box-shadow: var(--shadow-dropdown, 0 12px 40px rgba(0, 0, 0, 0.3));
  overflow-y: auto;
  font-family: var(--font, 'Inter', sans-serif);
}
.row-actions__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding-block: 9px;
  padding-inline: 14px;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 13px;
  text-align: start;
  cursor: pointer;
}
.row-actions__item i {
  width: 14px;
  flex-shrink: 0;
  text-align: center;
  color: var(--text-secondary);
}
.row-actions__item:hover,
.row-actions__item:focus-visible {
  background: var(--accent-light);
  outline: none;
}
.row-actions__item--danger,
.row-actions__item--danger i {
  color: var(--danger);
}

.visualai-dynamic-form[data-v-73c2a765] {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}
.visualai-dynamic-form__label[data-v-73c2a765] {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.visualai-dynamic-form__required[data-v-73c2a765] {
  color: var(--danger);
  margin-left: 2px;
}
.visualai-dynamic-form__input[data-v-73c2a765],
.visualai-dynamic-form__select[data-v-73c2a765] {
  width: 100%;
  padding: 10px 14px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 14px;
  font-family: var(--font, 'Inter', sans-serif);
  outline: none;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-dynamic-form__input[data-v-73c2a765]::placeholder {
  color: var(--text-muted);
}
.visualai-dynamic-form__input[data-v-73c2a765]:focus,
.visualai-dynamic-form__select[data-v-73c2a765]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}
.visualai-dynamic-form__select[data-v-73c2a765] {
  cursor: pointer;
  -webkit-appearance: none;
  -moz-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 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}
.visualai-dynamic-form__select option[data-v-73c2a765] {
  background: var(--bg-base);
  color: var(--text-primary);
}
[data-theme="dark"] .visualai-dynamic-form__select option[data-v-73c2a765] {
  background: #1a1f2e;
  color: #f0f2f5;
}
[data-theme="light"] .visualai-dynamic-form__select option[data-v-73c2a765] {
  background: #ffffff;
  color: #1a1d2e;
}
.visualai-dynamic-form__field--bool[data-v-73c2a765] {
  display: flex;
  align-items: center;
  padding-top: 24px;
}
.visualai-dynamic-form__checkbox-label[data-v-73c2a765] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
}
.visualai-dynamic-form__checkbox[data-v-73c2a765] {
  width: 16px;
  height: 16px;
  accent-color: hsl(var(--accent-h), var(--accent-s), var(--accent-l));
  cursor: pointer;
}

.image-upload[data-v-85513cd8] {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}
.image-upload__preview[data-v-85513cd8] {
  flex: none;
  width: 96px;
  height: 96px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 28px;
}
.image-upload__preview img[data-v-85513cd8] {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.image-upload__preview--empty[data-v-85513cd8] {
  border-style: dashed;
}
.image-upload__controls[data-v-85513cd8] {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.image-upload__btn[data-v-85513cd8] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  background: var(--bg-glass);
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 500;
  font-family: var(--font, 'Inter', sans-serif);
  cursor: pointer;
  transition: all 0.2s;
  align-self: flex-start;
}
.image-upload__btn[data-v-85513cd8]:hover:not(:disabled) {
  background: var(--bg-glass-hover);
  border-color: var(--accent, #3b82f6);
}
.image-upload__btn[data-v-85513cd8]:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.image-upload__btn--ghost[data-v-85513cd8] {
  background: transparent;
  color: var(--danger);
  border-color: transparent;
}
.image-upload__btn--ghost[data-v-85513cd8]:hover:not(:disabled) {
  background: rgba(248, 113, 113, 0.12);
  border-color: rgba(248, 113, 113, 0.2);
}
.image-upload__hint[data-v-85513cd8] {
  margin: 0;
  font-size: 11px;
  color: var(--text-muted);
}
.image-upload__error[data-v-85513cd8] {
  margin: 0;
  font-size: 12px;
  color: var(--danger);
}
.image-upload__spinner[data-v-85513cd8] {
  width: 12px;
  height: 12px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: image-upload-spin-85513cd8 0.6s linear infinite;
}
@keyframes image-upload-spin-85513cd8 {
to { transform: rotate(360deg);
}
}

.detection-notifier[data-v-cbafde74] {
  position: fixed;
  top: 80px;
  right: 24px;
  z-index: 4000;
  display: flex;
  flex-direction: column;
  gap: 12px;
  pointer-events: none;
  max-width: calc(100vw - 48px);
}
.toast[data-v-cbafde74] {
  pointer-events: auto;
  display: grid;
  grid-template-columns: 56px 1fr 28px;
  gap: 12px;
  align-items: center;
  width: 360px;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--bg-glass, rgba(15, 23, 42, 0.92));
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-glass, rgba(255, 255, 255, 0.1));
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  user-select: none;
}
.toast--open[data-v-cbafde74] {
  border-left: 4px solid var(--success, #34d399);
}
.toast--block[data-v-cbafde74] {
  border-left: 4px solid var(--danger, #f87171);
}
.toast--severity-critical[data-v-cbafde74] {
  border-left-width: 6px;
  border-color: rgba(248, 113, 113, 0.45);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(248, 113, 113, 0.25),
    0 0 24px rgba(248, 113, 113, 0.18);
  animation: toast-block-pulse-cbafde74 1.6s ease-in-out 2;
}
.toast--severity-high[data-v-cbafde74] {
  border-left-width: 5px;
}
@keyframes toast-block-pulse-cbafde74 {
0%,
  100% {
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4),
      0 0 0 1px rgba(248, 113, 113, 0.25),
      0 0 24px rgba(248, 113, 113, 0.18);
}
50% {
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4),
      0 0 0 1px rgba(248, 113, 113, 0.55),
      0 0 32px rgba(248, 113, 113, 0.4);
}
}
.toast__photo--block[data-v-cbafde74] {
  background: rgba(248, 113, 113, 0.18);
  color: var(--danger, #f87171);
}
.toast__resident--block[data-v-cbafde74] {
  color: var(--danger, #f87171);
  font-weight: 600;
}
.toast--log[data-v-cbafde74] {
  border-left: 4px solid var(--info, #60a5fa);
}
.toast__photo[data-v-cbafde74] {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-glass-active, rgba(255, 255, 255, 0.08));
  color: var(--text-muted, #94a3b8);
  font-size: 24px;
}
.toast__photo img[data-v-cbafde74] {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.toast__body[data-v-cbafde74] {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.toast__head[data-v-cbafde74] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.toast__plate[data-v-cbafde74] {
  font-family: 'SF Mono', 'Fira Code', monospace;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text-primary, #e2e8f0);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.toast__action[data-v-cbafde74] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.toast__action--open[data-v-cbafde74] {
  background: rgba(52, 211, 153, 0.16);
  color: var(--success, #34d399);
}
.toast__action--block[data-v-cbafde74] {
  background: rgba(248, 113, 113, 0.16);
  color: var(--danger, #f87171);
}
.toast__action--log[data-v-cbafde74] {
  background: rgba(96, 165, 250, 0.16);
  color: var(--info, #60a5fa);
}
.toast__resident[data-v-cbafde74] {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary, #e2e8f0);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.toast__location[data-v-cbafde74],
.toast__gate[data-v-cbafde74] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-secondary, #94a3b8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.toast__close[data-v-cbafde74] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted, #94a3b8);
  cursor: pointer;
  font-size: 11px;
}
.toast__close[data-v-cbafde74]:hover {
  background: var(--bg-glass-hover, rgba(255, 255, 255, 0.05));
  color: var(--text-primary, #e2e8f0);
}
.toast-enter-active[data-v-cbafde74],
.toast-leave-active[data-v-cbafde74] {
  transition: transform 0.25s ease, opacity 0.2s ease;
}
.toast-enter-from[data-v-cbafde74] {
  transform: translateX(40px);
  opacity: 0;
}
.toast-leave-to[data-v-cbafde74] {
  transform: translateX(40px);
  opacity: 0;
}
@media (max-width: 480px) {
.detection-notifier[data-v-cbafde74] {
    top: 64px;
    right: 12px;
    left: 12px;
}
.toast[data-v-cbafde74] {
    width: auto;
}
}

.system-notifier[data-v-3137c569] {
  position: fixed;
  top: 80px;
  right: 24px;
  z-index: 3999;  /* one below DetectionNotifier so person-related toasts win the overlap */
  display: flex;
  flex-direction: column;
  gap: 12px;
  pointer-events: none;
  max-width: calc(100vw - 48px);
  /* Stack below the access-decision toasts so we don't fight for the same
     visual real estate when both fire in the same second. */
  margin-top: 480px;
}
.toast[data-v-3137c569] {
  pointer-events: auto;
  display: grid;
  grid-template-columns: 44px 1fr 28px;
  gap: 12px;
  align-items: center;
  width: 360px;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--bg-glass, rgba(15, 23, 42, 0.92));
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-glass, rgba(255, 255, 255, 0.1));
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  user-select: none;
}
.toast--low[data-v-3137c569]      { border-left: 4px solid var(--info, #60a5fa);
}
.toast--medium[data-v-3137c569]   { border-left: 4px solid var(--warning, #fbbf24);
}
.toast--high[data-v-3137c569]     { border-left: 4px solid #fb923c;
}
.toast--critical[data-v-3137c569] { border-left: 4px solid var(--danger, #f87171);
}
.toast__icon[data-v-3137c569] {
  width: 44px; height: 44px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
}
.toast__icon--low[data-v-3137c569]      { background: rgba(96, 165, 250, 0.16); color: var(--info, #60a5fa);
}
.toast__icon--medium[data-v-3137c569]   { background: rgba(251, 191, 36, 0.16); color: var(--warning, #fbbf24);
}
.toast__icon--high[data-v-3137c569]     { background: rgba(251, 146, 60, 0.16); color: #fb923c;
}
.toast__icon--critical[data-v-3137c569] { background: rgba(248, 113, 113, 0.16); color: var(--danger, #f87171);
}
.toast__body[data-v-3137c569] { min-width: 0; display: flex; flex-direction: column; gap: 2px;
}
.toast__head[data-v-3137c569] { display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.toast__title[data-v-3137c569] {
  font-size: 13px; font-weight: 600;
  color: var(--text-primary, #e2e8f0);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.toast__sev[data-v-3137c569] {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.5px;
}
.toast__sev--low[data-v-3137c569]      { background: rgba(96, 165, 250, 0.16); color: var(--info, #60a5fa);
}
.toast__sev--medium[data-v-3137c569]   { background: rgba(251, 191, 36, 0.16); color: var(--warning, #fbbf24);
}
.toast__sev--high[data-v-3137c569]     { background: rgba(251, 146, 60, 0.16); color: #fb923c;
}
.toast__sev--critical[data-v-3137c569] { background: rgba(248, 113, 113, 0.16); color: var(--danger, #f87171);
}
.toast__detail[data-v-3137c569], .toast__context[data-v-3137c569] {
  font-size: 11px;
  color: var(--text-secondary, #94a3b8);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.toast__close[data-v-3137c569] {
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border: none; border-radius: 6px;
  background: transparent;
  color: var(--text-muted, #94a3b8);
  cursor: pointer; font-size: 11px;
}
.toast__close[data-v-3137c569]:hover {
  background: var(--bg-glass-hover, rgba(255, 255, 255, 0.05));
  color: var(--text-primary, #e2e8f0);
}
.toast-enter-active[data-v-3137c569], .toast-leave-active[data-v-3137c569] { transition: transform 0.25s ease, opacity 0.2s ease;
}
.toast-enter-from[data-v-3137c569] { transform: translateX(40px); opacity: 0;
}
.toast-leave-to[data-v-3137c569]   { transform: translateX(40px); opacity: 0;
}
@media (max-width: 480px) {
.system-notifier[data-v-3137c569] { top: 64px; right: 12px; left: 12px; margin-top: 360px;
}
.toast[data-v-3137c569] { width: auto;
}
}

.visualai-card[data-v-96c72d32] {
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-glass);
  border-radius: 16px;
  /* No box-shadow. `--shadow-glass` is a 32px blur, so on a dashboard whose
     grid gap is 8px the shadows of neighbouring cards overlapped in the
     gutters and rendered as a murky band rather than clean whitespace. The
     border already separates the card from the page. The token is left in the
     theme for any consumer that still wants it. */
  padding: 24px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.visualai-card[data-v-96c72d32]:hover {
  border-color: rgba(255, 255, 255, 0.15);
}
[data-theme="light"] .visualai-card[data-v-96c72d32]:hover {
  border-color: rgba(0, 0, 0, 0.12);
}
.visualai-card--no-padding[data-v-96c72d32] {
  padding: 0;
}
.visualai-card--no-padding .visualai-card__header[data-v-96c72d32] {
  padding: 24px 24px 0;
}
.visualai-card--no-padding .visualai-card__body[data-v-96c72d32] {
  padding: 0;
}
.visualai-card--no-padding .visualai-card__footer[data-v-96c72d32] {
  padding: 0 24px 24px;
}
.visualai-card__header[data-v-96c72d32] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}
.visualai-card__title[data-v-96c72d32] {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.4;
}
.visualai-card__subtitle[data-v-96c72d32] {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 2px;
}
.visualai-card__header-actions[data-v-96c72d32] {
  display: flex;
  align-items: center;
  gap: 8px;
}
.visualai-card__footer[data-v-96c72d32] {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border-color);
}

.visualai-loader[data-v-5ad263a3] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.visualai-loader__spinner[data-v-5ad263a3] {
  color: var(--accent);
}
.visualai-loader--sm .visualai-loader__spinner[data-v-5ad263a3] {
  width: 20px;
  height: 20px;
}
.visualai-loader--md .visualai-loader__spinner[data-v-5ad263a3] {
  width: 36px;
  height: 36px;
}
.visualai-loader--lg .visualai-loader__spinner[data-v-5ad263a3] {
  width: 52px;
  height: 52px;
}
.visualai-loader__svg[data-v-5ad263a3] {
  width: 100%;
  height: 100%;
  animation: visualai-loader-rotate-5ad263a3 1.4s linear infinite;
}
.visualai-loader__circle[data-v-5ad263a3] {
  stroke-dasharray: 90, 150;
  stroke-dashoffset: 0;
  animation: visualai-loader-dash-5ad263a3 1.4s ease-in-out infinite;
}
.visualai-loader__text[data-v-5ad263a3] {
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 500;
}
.visualai-loader--sm .visualai-loader__text[data-v-5ad263a3] {
  font-size: 11px;
}
.visualai-loader--lg .visualai-loader__text[data-v-5ad263a3] {
  font-size: 14px;
}
@keyframes visualai-loader-rotate-5ad263a3 {
100% {
    transform: rotate(360deg);
}
}
@keyframes visualai-loader-dash-5ad263a3 {
0% {
    stroke-dasharray: 1, 150;
    stroke-dashoffset: 0;
}
50% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -35;
}
100% {
    stroke-dasharray: 90, 150;
    stroke-dashoffset: -124;
}
}

.uv[data-v-3427d6a9] {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 4px 2px;
}
.uv__headline[data-v-3427d6a9] {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.uv__value[data-v-3427d6a9] {
  font-size: 34px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text-primary);
}
.uv__caption[data-v-3427d6a9] {
  font-size: 12px;
  color: var(--text-secondary);
}
.uv__qualifier[data-v-3427d6a9] {
  color: var(--text-muted);
}
.uv__stats[data-v-3427d6a9] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 10px;
}
.uv__stat[data-v-3427d6a9] {
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 10px;
  background: var(--bg-glass);
  min-width: 0;
}
.uv__stat-label[data-v-3427d6a9] {
  font-size: 11px;
  color: var(--text-muted);
  margin-bottom: 3px;
}
.uv__stat-value[data-v-3427d6a9] {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
}
.uv__stat-hint[data-v-3427d6a9] {
  font-size: 10px;
  color: var(--text-muted);
  line-height: 1.4;
  margin-top: 2px;
}
.uv__caveat[data-v-3427d6a9] {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
}
.uv__caveat i[data-v-3427d6a9] {
  margin-top: 2px;
  color: var(--warning, var(--text-muted));
}
.uv__footnote[data-v-3427d6a9] {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 0;
}
.uv__withheld[data-v-3427d6a9] {
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 14px;
  background: var(--bg-glass);
}
.uv__withheld-head[data-v-3427d6a9] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 8px;
}
.uv__withheld-head i[data-v-3427d6a9] {
  color: var(--warning, var(--text-muted));
}
.uv__withheld-body[data-v-3427d6a9] {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.6;
  margin: 0 0 8px 0;
}
.uv__withheld-hint[data-v-3427d6a9] {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 0;
}

.widget-frame__body[data-v-f2a660b9] {
  height: 100%;
  /* Anchors the copy notice below. Deliberately not a layout change: the
     notice is absolutely positioned precisely so it cannot resize a chart
     that resolves its bar heights against this box. */
  position: relative;
}

/*
 * ── Copy button (AB#15957) ──────────────────────────────────────────────────
 *
 * WHERE THIS SITS, AND WHY, because it was a real choice.
 *
 * It sits in the CARD HEADER, beside the period and axis toggles a widget
 * already puts there, rather than in a new per-widget menu. There is no
 * per-widget menu today — the header actions slot IS the established
 * affordance, and inventing a kebab menu to hold one item would put the
 * feature two clicks away and add a second, competing control vocabulary to a
 * header that already has one.
 *
 * It is REVEALED ON HOVER, not always visible. A dashboard is scanned, not
 * operated: a dozen chart widgets each showing a permanent button turns a
 * reading surface into a control panel, and the buttons compete with the
 * numbers they sit above. Hover-reveal keeps the resting state clean and
 * costs nothing at the moment of use, because the operator's pointer is
 * already on the card they want.
 *
 * The three ways hover-reveal is usually got wrong, and what is done here:
 *
 *  - KEYBOARD. The button is always in the DOM and `:focus-visible` shows it,
 *    so tabbing reaches it and it becomes visible when it does. It is never
 *    `v-if`-ed on hover.
 *  - TOUCH. There is no hover on a tablet, so `@media (hover: hover)` scopes
 *    the hiding: a device that cannot hover gets the button permanently
 *    visible, which is the only usable answer there.
 *  - REDUCED MOTION / low vision. The transition is opacity only and short,
 *    and the resting state is `opacity: 0` with the box still laid out, so
 *    nothing moves when it appears.
 */
.widget-frame__copy[data-v-f2a660b9] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 11px;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border-color);
  border-radius: 4px;
  cursor: pointer;
  transition: opacity 0.15s, color 0.15s, border-color 0.15s;
}
.widget-frame__copy[data-v-f2a660b9]:hover:not(:disabled) {
  color: var(--text-primary);
  border-color: var(--accent);
}
.widget-frame__copy[data-v-f2a660b9]:disabled {
  opacity: 0.4;
  cursor: default;
}
@media (hover: hover) {
.widget-frame__copy[data-v-f2a660b9] {
    opacity: 0;
}

  /* `:focus-within` on the CARD, so the button shows while it — or any other
     header control — holds focus. `:focus-visible` on the button itself covers
     the keyboard user who tabs straight to it. */
.visualai-card:hover .widget-frame__copy[data-v-f2a660b9],
  .visualai-card:focus-within .widget-frame__copy[data-v-f2a660b9],
  .widget-frame__copy[data-v-f2a660b9]:focus-visible,
  .widget-frame__copy.is-busy[data-v-f2a660b9] {
    opacity: 1;
}
}
.widget-frame__copy-notice[data-v-f2a660b9] {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  margin: 0;
  padding: 5px 8px;
  border-radius: 6px;
  font-size: 0.7rem;
  line-height: 1.35;
  /* Opaque, not translucent: it sits on top of a chart, and a see-through
     strip over bars is unreadable. */
  background: var(--bg-elevated, var(--bg-card, #1f2430));
  border: 1px solid var(--border-color);
}
.widget-frame__copy-notice--info[data-v-f2a660b9] {
  color: var(--success, #34d399);
}
.widget-frame__copy-notice--warn[data-v-f2a660b9] {
  color: var(--warning, #fbbf24);
}
.widget-frame__copy-notice--error[data-v-f2a660b9] {
  color: var(--danger, #f87171);
}
.widget-frame__state[data-v-f2a660b9] {
  min-height: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13px;
}
.widget-frame__empty-icon[data-v-f2a660b9] {
  font-size: 22px;
  opacity: 0.5;
}
.widget-frame__empty-text[data-v-f2a660b9],
.widget-frame__error-text[data-v-f2a660b9] {
  margin: 0;
}
.widget-frame__state--error[data-v-f2a660b9] {
  color: var(--danger);
}
.widget-frame__state--error i[data-v-f2a660b9] {
  font-size: 22px;
}
.widget-frame__retry[data-v-f2a660b9] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  font-size: 12px;
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid var(--border-glass);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.widget-frame__retry[data-v-f2a660b9]:hover {
  color: var(--text-primary);
  border-color: var(--accent);
}

.loitering-widget[data-v-2777f631] {
  height: 100%;
  min-height: 0;
  overflow: auto;
  padding: 14px;
  color: var(--text-primary);
}
.widget-header[data-v-2777f631] { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px;
}
.widget-header h3[data-v-2777f631] { display: flex; align-items: center; gap: 7px; margin: 0; font-size: 13px;
}
.widget-header h3 i[data-v-2777f631] { color: #a855f7;
}
.widget-header > div > span[data-v-2777f631] { color: var(--text-muted); font-size: 9px;
}
.header-actions[data-v-2777f631] { display: flex; gap: 5px;
}
.header-actions select[data-v-2777f631] { height: 27px; padding: 3px 24px 3px 7px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-input); color: var(--text-primary); font-size: 9px;
}
.header-actions button[data-v-2777f631] { width: 27px; height: 27px; border: 1px solid var(--border-color); border-radius: 5px; background: var(--bg-glass-hover); color: var(--text-secondary); cursor: pointer;
}
.widget-error[data-v-2777f631] { margin-bottom: 8px; padding: 6px 8px; border-radius: 5px; background: rgba(239, 68, 68, 0.1); color: var(--danger); font-size: 10px;
}
.kpi-row[data-v-2777f631] { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; transition: opacity 0.2s;
}
.kpi-row article[data-v-2777f631] { display: flex; align-items: center; gap: 9px; padding: 9px; border: 1px solid var(--border-color); border-radius: 8px; background: var(--bg-glass-hover);
}
.kpi-icon[data-v-2777f631] { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 7px;
}
.kpi-icon--events[data-v-2777f631] { background: rgba(168, 85, 247, 0.14); color: #a855f7;
}
.kpi-icon--alerts[data-v-2777f631] { background: rgba(239, 68, 68, 0.14); color: var(--danger);
}
.kpi-row article div[data-v-2777f631] { display: flex; flex-direction: column;
}
.kpi-row strong[data-v-2777f631] { font-size: 17px; line-height: 1;
}
.kpi-row span[data-v-2777f631] { margin-top: 3px; color: var(--text-muted); font-size: 9px;
}
.insight-grid[data-v-2777f631] { display: grid; grid-template-columns: repeat(3, minmax(150px, 1fr)); gap: 8px; transition: opacity 0.2s;
}
.loading[data-v-2777f631] { opacity: 0.55;
}
.insight-panel[data-v-2777f631] { min-height: 125px; padding: 9px; border: 1px solid var(--border-color); border-radius: 8px;
}
.insight-panel h4[data-v-2777f631] { margin: 0 0 7px; font-size: 10px;
}
.breakdown-columns[data-v-2777f631] { display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}
.column-label[data-v-2777f631] { display: block; margin-bottom: 4px; color: var(--text-muted); font-size: 8px; font-weight: 700; text-transform: uppercase;
}
.rank-row[data-v-2777f631] { display: flex; justify-content: space-between; gap: 5px; padding: 3px 0; border-bottom: 1px solid var(--border-subtle); font-size: 8px;
}
.rank-row span[data-v-2777f631] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rank-row strong[data-v-2777f631] { color: #a855f7;
}
.empty[data-v-2777f631] { color: var(--text-muted); font-size: 8px;
}
.empty--large[data-v-2777f631] { display: flex; min-height: 85px; align-items: center; justify-content: center;
}
.mini-trend[data-v-2777f631] { display: flex; align-items: flex-end; gap: 3px; height: 92px; overflow-x: auto;
}
.trend-column[data-v-2777f631] { display: grid; grid-template-rows: 1fr 15px; flex: 1 0 18px; align-items: end; height: 100%; text-align: center;
}
.trend-column > span[data-v-2777f631] { width: 70%; min-height: 3px; margin: 0 auto; border-radius: 3px 3px 0 0; background: linear-gradient(#a855f7, #6366f1);
}
.trend-column small[data-v-2777f631] { padding-top: 3px; color: var(--text-muted); font-size: 6px; white-space: nowrap;
}
.hotspot-stage[data-v-2777f631] { position: relative; width: 100%; aspect-ratio: 16 / 8; overflow: hidden; border-radius: 5px; background: #080b12;
}
.hotspot-stage img[data-v-2777f631],
.hotspot-stage svg[data-v-2777f631],
.preview-placeholder[data-v-2777f631] { position: absolute; inset: 0; width: 100%; height: 100%;
}
.hotspot-stage img[data-v-2777f631] { z-index: 1; object-fit: cover;
}
.hotspot-stage svg[data-v-2777f631] { z-index: 2;
}
.hotspot-stage polygon[data-v-2777f631] { vector-effect: non-scaling-stroke; stroke-width: 0.8;
}
.preview-placeholder[data-v-2777f631] { display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.25);
}
.hotspot-legend[data-v-2777f631] { display: flex; flex-wrap: wrap; gap: 3px 7px; margin-top: 5px; color: var(--text-muted); font-size: 7px;
}
.hotspot-legend strong[data-v-2777f631] { color: var(--text-primary);
}
@media (max-width: 900px) {
.insight-grid[data-v-2777f631] { grid-template-columns: 1fr;
}
}
@media (max-width: 520px) {
.kpi-row[data-v-2777f631] { grid-template-columns: 1fr;
}
.widget-header[data-v-2777f631] { flex-direction: column;
}
}

.axis-toggle[data-v-c11c3957] {
  display: flex;
  gap: 2px;
}
.axis-toggle__btn[data-v-c11c3957] {
  border: 1px solid var(--border-color);
  background: transparent;
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
}
.axis-toggle__btn[data-v-c11c3957]:first-child {
  border-radius: 4px 0 0 4px;
}
.axis-toggle__btn[data-v-c11c3957]:last-child {
  border-radius: 0 4px 4px 0;
}
.axis-toggle__btn[data-v-c11c3957]:not(:first-child) {
  border-left: none;
}
.axis-toggle__btn--active[data-v-c11c3957] {
  /* `--accent`, NOT `--primary`: the latter is not defined anywhere in this
     app, which makes the declaration invalid at computed-value time. The fill
     then never painted and `color: #fff` left the SELECTED button as white
     text on a white card — an invisible active state. */
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.axis-toggle__btn[data-v-c11c3957]:hover:not(.axis-toggle__btn--active) {
  color: var(--text-primary);
}

.period-toggle[data-v-bea8a1c3] {
  display: flex;
  gap: 2px;
}
.period-toggle__btn[data-v-bea8a1c3] {
  border: 1px solid var(--border-color);
  background: transparent;
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
}
.period-toggle__btn[data-v-bea8a1c3]:first-child {
  border-radius: 4px 0 0 4px;
}
.period-toggle__btn[data-v-bea8a1c3]:last-child {
  border-radius: 0 4px 4px 0;
}
.period-toggle__btn[data-v-bea8a1c3]:not(:first-child) {
  border-left: none;
}
.period-toggle__btn--active[data-v-bea8a1c3] {
  /* `--accent`, NOT `--primary`: the latter is not defined anywhere in this
     app, which makes the declaration invalid at computed-value time. The fill
     then never painted and `color: #fff` left the SELECTED button as white
     text on a white card — an invisible active state. */
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.period-toggle__btn[data-v-bea8a1c3]:hover:not(.period-toggle__btn--active) {
  color: var(--text-primary);
}

/* Local mono stack: the "camera OSD" voice for HUD text.
   Hue + saturation always follow the tenant accent (white-labeling);
   lightness is pinned per-layer for legibility on the dark hero. */
.login-page[data-v-1ac841aa] {
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --hero-glow: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.5);
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  background: var(--bg-base);
  overflow: hidden;
}

/* ===================== HERO ===================== */
/* Deliberately dark in both themes: it reads as a night camera feed. */
.hero[data-v-1ac841aa] {
  position: relative;
  flex: 1 1 60%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  background: #060a13;
  color: #e8ecf5;
}
.hero-nebula[data-v-1ac841aa] {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 55% at 25% 25%, hsla(var(--accent-h), var(--accent-s), 45%, 0.16), transparent 65%),
    radial-gradient(ellipse 55% 45% at 80% 75%, hsla(calc(var(--accent-h) + 40), var(--accent-s), 45%, 0.1), transparent 65%);
  animation: nebulaDrift-1ac841aa 24s ease-in-out infinite alternate;
}
@keyframes nebulaDrift-1ac841aa {
from { transform: translate3d(-2%, -2%, 0) scale(1);
}
to { transform: translate3d(2%, 3%, 0) scale(1.08);
}
}

/* Perspective grid floor scrolling toward the viewer. */
.hero-floor[data-v-1ac841aa] {
  position: absolute;
  left: -30%;
  right: -30%;
  bottom: -12%;
  height: 55%;
  overflow: hidden;
  transform: perspective(480px) rotateX(58deg);
  transform-origin: top center;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 30%, transparent 95%);
  mask-image: linear-gradient(to bottom, transparent, #000 30%, transparent 95%);
}
/* The grid scrolls via transform (compositor-only) — one extra tile row
   above the box makes the 56px loop seamless. */
.hero-floor[data-v-1ac841aa]::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: -56px;
  bottom: 0;
  background-image:
    linear-gradient(hsla(var(--accent-h), var(--accent-s), 55%, 0.18) 1px, transparent 1px),
    linear-gradient(90deg, hsla(var(--accent-h), var(--accent-s), 55%, 0.18) 1px, transparent 1px);
  background-size: 56px 56px;
  animation: floorScroll-1ac841aa 3.2s linear infinite;
}
@keyframes floorScroll-1ac841aa {
from { transform: translate3d(0, 0, 0);
}
to { transform: translate3d(0, 56px, 0);
}
}

/* One slow radar ring behind the scan stage. */
.hero-ring[data-v-1ac841aa] {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 620px;
  height: 620px;
  margin: -310px 0 0 -310px;
  border-radius: 50%;
  border: 1px solid hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.12);
  animation: ringSpin-1ac841aa 26s linear infinite;
}
.hero-ring[data-v-1ac841aa]::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.22),
    transparent 18%
  );
  -webkit-mask-image: radial-gradient(closest-side, transparent 96%, #000 97%);
  mask-image: radial-gradient(closest-side, transparent 96%, #000 97%);
}
.hero-ring[data-v-1ac841aa]::after {
  content: '';
  position: absolute;
  inset: 60px;
  border-radius: 50%;
  border: 1px dashed hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.1);
}
@keyframes ringSpin-1ac841aa {
to { transform: rotate(360deg);
}
}
.hero-inner[data-v-1ac841aa] {
  position: relative;
  z-index: 2;
  padding: 48px clamp(32px, 6vw, 96px);
  max-width: 720px;
}
.hero-live[data-v-1ac841aa] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  color: hsla(var(--accent-h), var(--accent-s), 75%, 0.9);
  border: 1px solid hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.25);
  border-radius: 999px;
  padding: 6px 14px;
  margin-bottom: 28px;
  animation: riseIn-1ac841aa 0.7s 0.05s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.live-dot[data-v-1ac841aa] {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--success, #34d399);
  box-shadow: 0 0 8px var(--success, #34d399);
  animation: dotPulse-1ac841aa 2s ease-in-out infinite;
}
@keyframes dotPulse-1ac841aa {
0%, 100% { opacity: 1;
}
50% { opacity: 0.35;
}
}
.hero-title[data-v-1ac841aa] {
  font-size: clamp(34px, 4.4vw, 56px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 12px;
  background: linear-gradient(120deg, #f4f7ff 55%, hsla(var(--accent-h), var(--accent-s), 72%, 1));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: riseIn-1ac841aa 0.7s 0.15s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.hero-tagline[data-v-1ac841aa] {
  font-size: clamp(14px, 1.4vw, 17px);
  color: #9aa4bd;
  margin-bottom: 44px;
  animation: riseIn-1ac841aa 0.7s 0.25s cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* ---- Signature element: the feature slideshow ---- */
.slide-stage[data-v-1ac841aa] {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  margin-bottom: 36px;
  min-width: min(380px, 100%);
  animation: riseIn-1ac841aa 0.7s 0.35s cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* Frame + readout + caption travel together in one keyed transition. */
.slide-body[data-v-1ac841aa] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.scan-frame[data-v-1ac841aa] {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 320px;
  min-height: 150px;
  padding: 26px 34px;
  overflow: hidden;
}

/* Icon vignette for non-ANPR slides. */
.slide-icon[data-v-1ac841aa] {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 98px;
  height: 98px;
  font-size: 46px;
  color: hsla(var(--accent-h), var(--accent-s), 72%, 1);
}
.slide-icon-fire[data-v-1ac841aa] {
  color: var(--warning, #fbbf24);
}
.slide-icon-ring[data-v-1ac841aa] {
  position: absolute;
  inset: 0;
  border: 1px solid currentColor;
  border-radius: 50%;
  opacity: 0.5;
  animation: iconPing-1ac841aa 2.4s ease-out infinite;
}
@keyframes iconPing-1ac841aa {
0% { transform: scale(0.7); opacity: 0.6;
}
70% { transform: scale(1.15); opacity: 0;
}
100% { transform: scale(1.15); opacity: 0;
}
}

/* Crossfade + drift between slides. */
.slide-swap-enter-active[data-v-1ac841aa],
.slide-swap-leave-active[data-v-1ac841aa] {
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.slide-swap-enter-from[data-v-1ac841aa] {
  opacity: 0;
  transform: translateX(28px);
}
.slide-swap-leave-to[data-v-1ac841aa] {
  opacity: 0;
  transform: translateX(-28px);
}
.slide-caption[data-v-1ac841aa] {
  min-height: 62px;
  max-width: 360px;
  text-align: center;
}
.slide-caption h3[data-v-1ac841aa] {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: #e8ecf5;
  margin-bottom: 4px;
}
.slide-caption p[data-v-1ac841aa] {
  font-size: 13px;
  line-height: 1.5;
  color: #9aa4bd;
}
.corner[data-v-1ac841aa] {
  position: absolute;
  width: 18px;
  height: 18px;
  border: 2px solid var(--hero-glow);
}
.corner.tl[data-v-1ac841aa] { top: 0; left: 0; border-right: 0; border-bottom: 0;
}
.corner.tr[data-v-1ac841aa] { top: 0; right: 0; border-left: 0; border-bottom: 0;
}
.corner.bl[data-v-1ac841aa] { bottom: 0; left: 0; border-right: 0; border-top: 0;
}
.corner.br[data-v-1ac841aa] { bottom: 0; right: 0; border-left: 0; border-top: 0;
}
.plate[data-v-1ac841aa] {
  display: flex;
  align-items: stretch;
  border-radius: 6px;
  overflow: hidden;
  border: 2px solid #cfd6e6;
  box-shadow:
    0 0 0 1px #0a0f1c,
    0 10px 40px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.25);
  font-family: var(--mono);
}
.plate-region[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  padding: 12px 12px;
  background: hsl(var(--accent-h), var(--accent-s), 38%);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
}
.plate-number[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  padding: 12px 20px;
  background: #eef1f7;
  color: #10141f;
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 700;
  letter-spacing: 0.14em;
}
.scan-beam[data-v-1ac841aa] {
  position: absolute;
  left: 6px;
  right: 6px;
  height: 3px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--hero-glow), transparent);
  box-shadow: 0 0 18px 4px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.35);
  animation: beamSweep-1ac841aa 3s ease-in-out infinite;
}
@keyframes beamSweep-1ac841aa {
0% { top: 8%; opacity: 0;
}
12% { opacity: 1;
}
46% { top: 88%;
}
54% { top: 88%;
}
88% { opacity: 1;
}
100% { top: 8%; opacity: 0;
}
}

/* Cycling OSD readout — three stacked lines, 4.8s loop (fits one full
   pass inside the 6s slide window). */
.scan-readout[data-v-1ac841aa] {
  position: relative;
  height: 18px;
  min-width: 220px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-align: center;
}
.readout[data-v-1ac841aa] {
  position: absolute;
  inset: 0;
  opacity: 0;
  color: hsla(var(--accent-h), var(--accent-s), 78%, 0.95);
}
.readout-1[data-v-1ac841aa] { animation: readoutCycle-1ac841aa 4.8s infinite;
}
.readout-2[data-v-1ac841aa] { animation: readoutCycle-1ac841aa 4.8s 1.6s infinite;
}
.readout-3[data-v-1ac841aa] {
  color: var(--success, #34d399);
  animation: readoutCycle-1ac841aa 4.8s 3.2s infinite;
}
.readout-static[data-v-1ac841aa] {
  position: static;
  display: block;
  opacity: 1;
  animation: none;
}
@keyframes readoutCycle-1ac841aa {
0% { opacity: 0; transform: translateY(4px);
}
4%, 30% { opacity: 1; transform: translateY(0);
}
34%, 100% { opacity: 0; transform: translateY(-4px);
}
}
.hero-features[data-v-1ac841aa] {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  animation: riseIn-1ac841aa 0.7s 0.45s cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Chips double as the slide navigation. */
.feature-chip[data-v-1ac841aa] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #b7c0d8;
  padding: 7px 14px;
  border: 1px solid hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.22);
  border-radius: 999px;
  background: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.06);
  cursor: pointer;
  transition: border-color 0.25s ease, background 0.25s ease, color 0.25s ease;
}
.feature-chip[data-v-1ac841aa]:hover {
  border-color: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.5);
  color: #e8ecf5;
}
.feature-chip.active[data-v-1ac841aa] {
  border-color: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.75);
  background: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.16);
  color: #f4f7ff;
}
.feature-chip[data-v-1ac841aa]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.chip-pause[data-v-1ac841aa] {
  padding: 7px 12px;
  font-size: 10px;
}
.feature-dot[data-v-1ac841aa] {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--hero-glow);
  animation: dotPulse-1ac841aa 2.6s ease-in-out infinite;
}
.feature-chip:nth-child(2) .feature-dot[data-v-1ac841aa] { animation-delay: 0.4s;
}
.feature-chip:nth-child(3) .feature-dot[data-v-1ac841aa] { animation-delay: 0.8s;
}
.feature-chip:nth-child(4) .feature-dot[data-v-1ac841aa] { animation-delay: 1.2s;
}
.feature-chip:nth-child(5) .feature-dot[data-v-1ac841aa] { animation-delay: 1.6s;
}
.hero-foot[data-v-1ac841aa] {
  position: absolute;
  bottom: 22px;
  left: clamp(32px, 6vw, 96px);
  z-index: 2;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.24em;
  color: #7d88a6;
  animation: riseIn-1ac841aa 0.7s 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes riseIn-1ac841aa {
from { opacity: 0; transform: translateY(18px);
}
to { opacity: 1; transform: translateY(0);
}
}

/* ===================== AUTH PANEL ===================== */
.auth[data-v-1ac841aa] {
  position: relative;
  flex: 0 0 clamp(400px, 38vw, 540px);
  display: flex;
  overflow-y: auto;
  padding: 40px;
  background: var(--bg-base);
  border-left: 1px solid var(--border-color);
}
.login-card[data-v-1ac841aa] {
  position: relative;
  width: 100%;
  max-width: 420px;
  /* auto margins center the card but still allow scrolling on short
     viewports (mobile keyboard, landscape, high zoom). */
  margin: auto;
  padding: 44px;
  overflow: hidden;
  animation: cardEnter-1ac841aa 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Accent glow line across the top of the card. */
.login-card[data-v-1ac841aa]::before {
  content: '';
  position: absolute;
  top: 0;
  left: 10%;
  right: 10%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0.8;
}
@keyframes cardEnter-1ac841aa {
from { opacity: 0; transform: translateY(30px) scale(0.96);
}
to { opacity: 1; transform: translateY(0) scale(1);
}
}
.login-logo[data-v-1ac841aa] {
  display: block;
  width: 84px;
  height: 84px;
  margin: 0 auto 20px;
  border-radius: 16px;
  object-fit: cover;
  box-shadow: 0 8px 32px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.25);
  animation: logoPulse-1ac841aa 3s ease-in-out infinite;
}
@keyframes logoPulse-1ac841aa {
0%, 100% { box-shadow: 0 8px 32px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.3);
}
50% { box-shadow: 0 8px 48px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.5);
}
}
.login-card h2[data-v-1ac841aa] {
  text-align: center;
  font-size: 24px;
  margin-bottom: 4px;
  font-weight: 700;
  letter-spacing: -0.5px;
}
.login-subtitle[data-v-1ac841aa] {
  text-align: center;
  color: var(--text-secondary);
  font-size: 14px;
  margin-bottom: 28px;
}
.login-error[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(248, 113, 113, 0.1);
  border: 1px solid rgba(248, 113, 113, 0.2);
  border-radius: var(--radius-xs);
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--danger);
}
.login-success[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(52, 211, 153, 0.1);
  border: 1px solid rgba(52, 211, 153, 0.2);
  border-radius: var(--radius-xs);
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--success, #34d399);
}
.login-card .form-control[data-v-1ac841aa]:focus {
  border-color: hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.6);
  box-shadow: 0 0 0 3px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.15);
}
.password-toggle[data-v-1ac841aa] {
  position: absolute;
  right: 12px;
  bottom: 0;
  height: 42px;
  width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 14px;
}
.password-toggle[data-v-1ac841aa]:hover { color: var(--text-primary);
}
.form-group.password[data-v-1ac841aa] { position: relative;
}
.form-group.password .form-control[data-v-1ac841aa] { padding-right: 40px;
}
.remember-row[data-v-1ac841aa] { margin: 8px 0 4px;
}
.remember-row label[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
}
.remember-row input[type='checkbox'][data-v-1ac841aa] { accent-color: var(--accent);
}
.login-submit[data-v-1ac841aa] {
  width: 100%;
  margin-top: 12px;
  padding: 13px;
  justify-content: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.login-submit[data-v-1ac841aa]:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 6px 24px hsla(var(--accent-h), var(--accent-s), var(--accent-l), 0.35);
}
.login-footer[data-v-1ac841aa] {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  margin-top: 20px;
  font-size: 11px;
  color: var(--text-muted);
  animation: footFade-1ac841aa 1s 0.6s ease both;
}
@keyframes footFade-1ac841aa {
from { opacity: 0;
}
to { opacity: 1;
}
}

/* ===================== RESPONSIVE ===================== */
@media (max-width: 900px) {
.hero[data-v-1ac841aa] { display: none;
}
.auth[data-v-1ac841aa] {
    flex: 1;
    border-left: none;
}
  /* Slimmed sci-fi background behind the centered card. */
.auth[data-v-1ac841aa]::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image:
      linear-gradient(hsla(var(--accent-h), 50%, 50%, 0.05) 1px, transparent 1px),
      linear-gradient(90deg, hsla(var(--accent-h), 50%, 50%, 0.05) 1px, transparent 1px);
    background-size: 56px 56px;
}
.auth[data-v-1ac841aa]::after {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse 80% 55% at 50% 0%, hsla(var(--accent-h), 80%, 45%, 0.14), transparent 70%);
}
.login-card[data-v-1ac841aa] { z-index: 1;
}
}
@media (max-width: 480px) {
.auth[data-v-1ac841aa] { padding: 20px;
}
.login-card[data-v-1ac841aa] { padding: 28px 24px;
}
}

/* ===================== REDUCED MOTION ===================== */
@media (prefers-reduced-motion: reduce) {
.login-page[data-v-1ac841aa] *,
  .login-page[data-v-1ac841aa] *::before,
  .login-page[data-v-1ac841aa] *::after {
    animation: none !important;
    transition: none !important;
}
.scan-beam[data-v-1ac841aa] { opacity: 0;
}
.readout-1[data-v-1ac841aa], .readout-3[data-v-1ac841aa] { display: none;
}
.readout-2[data-v-1ac841aa] { opacity: 1;
}
}
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties {
  @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) {
    *, :before, :after, ::backdrop {
      --tw-rotate-x: initial;
      --tw-rotate-y: initial;
      --tw-rotate-z: initial;
      --tw-skew-x: initial;
      --tw-skew-y: initial;
      --tw-border-style: solid;
      --tw-shadow: 0 0 #0000;
      --tw-shadow-color: initial;
      --tw-shadow-alpha: 100%;
      --tw-inset-shadow: 0 0 #0000;
      --tw-inset-shadow-color: initial;
      --tw-inset-shadow-alpha: 100%;
      --tw-ring-color: initial;
      --tw-ring-shadow: 0 0 #0000;
      --tw-inset-ring-color: initial;
      --tw-inset-ring-shadow: 0 0 #0000;
      --tw-ring-inset: initial;
      --tw-ring-offset-width: 0px;
      --tw-ring-offset-color: #fff;
      --tw-ring-offset-shadow: 0 0 #0000;
      --tw-outline-style: solid;
      --tw-ease: initial;
    }
  }
}

@layer theme {
  :root, :host {
    --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
      "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
      "Segoe UI Symbol", "Noto Color Emoji";
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
      "Courier New", monospace;
    --radius-xs: .125rem;
    --radius-sm: .25rem;
    --ease-out: cubic-bezier(0, 0, .2, 1);
    --ease-in-out: cubic-bezier(.4, 0, .2, 1);
    --default-transition-duration: .15s;
    --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
    --default-font-family: var(--font-sans);
    --default-mono-font-family: var(--font-mono);
  }
}

@layer base {
  *, :after, :before, ::backdrop {
    box-sizing: border-box;
    border: 0 solid;
    margin: 0;
    padding: 0;
  }

  ::file-selector-button {
    box-sizing: border-box;
    border: 0 solid;
    margin: 0;
    padding: 0;
  }

  html, :host {
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
    line-height: 1.5;
    font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
    font-feature-settings: var(--default-font-feature-settings, normal);
    font-variation-settings: var(--default-font-variation-settings, normal);
    -webkit-tap-highlight-color: transparent;
  }

  hr {
    height: 0;
    color: inherit;
    border-top-width: 1px;
  }

  abbr:where([title]) {
    -webkit-text-decoration: underline dotted;
    text-decoration: underline dotted;
  }

  h1, h2, h3, h4, h5, h6 {
    font-size: inherit;
    font-weight: inherit;
  }

  a {
    color: inherit;
    -webkit-text-decoration: inherit;
    -webkit-text-decoration: inherit;
    -webkit-text-decoration: inherit;
    text-decoration: inherit;
  }

  b, strong {
    font-weight: bolder;
  }

  code, kbd, samp, pre {
    font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
    font-feature-settings: var(--default-mono-font-feature-settings, normal);
    font-variation-settings: var(--default-mono-font-variation-settings, normal);
    font-size: 1em;
  }

  small {
    font-size: 80%;
  }

  sub, sup {
    vertical-align: baseline;
    font-size: 75%;
    line-height: 0;
    position: relative;
  }

  sub {
    bottom: -.25em;
  }

  sup {
    top: -.5em;
  }

  table {
    text-indent: 0;
    border-color: inherit;
    border-collapse: collapse;
  }

  :-moz-focusring:where(:not(iframe)) {
    outline: auto;
  }

  progress {
    vertical-align: baseline;
  }

  summary {
    display: list-item;
  }

  ol, ul, menu {
    list-style: none;
  }

  img, svg, video, canvas, audio, iframe, embed, object {
    vertical-align: middle;
    display: block;
  }

  img, video {
    max-width: 100%;
    height: auto;
  }

  button, input, select, optgroup, textarea {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    opacity: 1;
    background-color: #0000;
    border-radius: 0;
  }

  ::file-selector-button {
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    opacity: 1;
    background-color: #0000;
    border-radius: 0;
  }

  :where(select:is([multiple], [size])) optgroup {
    font-weight: bolder;
  }

  :where(select:is([multiple], [size])) optgroup option {
    padding-inline-start: 20px;
  }

  ::file-selector-button {
    margin-inline-end: 4px;
  }

  ::placeholder {
    opacity: 1;
  }

  @supports (not ((-webkit-appearance: -apple-pay-button))) or (contain-intrinsic-size: 1px) {
    ::placeholder {
      color: currentColor;
    }

    @supports (color: color-mix(in lab, red, red)) {
      ::placeholder {
        color: color-mix(in oklab, currentcolor 50%, transparent);
      }
    }
  }

  textarea {
    resize: vertical;
  }

  ::-webkit-search-decoration {
    -webkit-appearance: none;
  }

  ::-webkit-date-and-time-value {
    min-height: 1lh;
    text-align: inherit;
  }

  ::-webkit-datetime-edit {
    display: inline-flex;
  }

  ::-webkit-datetime-edit-fields-wrapper {
    padding: 0;
  }

  ::-webkit-datetime-edit {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-year-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-month-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-day-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-hour-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-minute-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-second-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-millisecond-field {
    padding-block: 0;
  }

  ::-webkit-datetime-edit-meridiem-field {
    padding-block: 0;
  }

  ::-webkit-calendar-picker-indicator {
    line-height: 1;
  }

  :-moz-ui-invalid {
    box-shadow: none;
  }

  button, input:where([type="button"], [type="reset"], [type="submit"]) {
    appearance: button;
  }

  ::file-selector-button {
    appearance: button;
  }

  ::-webkit-inner-spin-button {
    height: auto;
  }

  ::-webkit-outer-spin-button {
    height: auto;
  }

  [hidden]:where(:not([hidden="until-found"])) {
    display: none !important;
  }
}

@layer components;

@layer utilities {
  .collapse {
    visibility: collapse;
  }

  .invisible {
    visibility: hidden;
  }

  .visible {
    visibility: visible;
  }

  .absolute {
    position: absolute;
  }

  .fixed {
    position: fixed;
  }

  .relative {
    position: relative;
  }

  .static {
    position: static;
  }

  .block {
    display: block;
  }

  .flex {
    display: flex;
  }

  .grid {
    display: grid;
  }

  .hidden {
    display: none;
  }

  .table {
    display: table;
  }

  .shrink {
    flex-shrink: 1;
  }

  .grow {
    flex-grow: 1;
  }

  .transform {
    transform: var(--tw-rotate-x, ) var(--tw-rotate-y, ) var(--tw-rotate-z, ) var(--tw-skew-x, ) var(--tw-skew-y, );
  }

  .flex-wrap {
    flex-wrap: wrap;
  }

  .truncate {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
  }

  .border {
    border-style: var(--tw-border-style);
    border-width: 1px;
  }

  .ring {
    --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }

  .outline {
    outline-style: var(--tw-outline-style);
    outline-width: 1px;
  }

  .transition {
    transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }

  .ease-in-out {
    --tw-ease: var(--ease-in-out);
    transition-timing-function: var(--ease-in-out);
  }

  .ease-out {
    --tw-ease: var(--ease-out);
    transition-timing-function: var(--ease-out);
  }
}

:root {
  --font: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --radius: 16px;
  --radius-sm: 10px;
  --radius-xs: 6px;
  --transition: .3s cubic-bezier(.4, 0, .2, 1);
  --sidebar-w: 260px;
  --sidebar-collapsed: 72px;
  --header-h: 64px;
  --accent-h: 210;
  --accent-s: 100%;
  --accent-l: 56%;
  --accent: hsl(var(--accent-h), var(--accent-s), var(--accent-l));
  --accent-light: hsla(var(--accent-h), var(--accent-s), var(--accent-l), .15);
  --accent-glow: hsla(var(--accent-h), var(--accent-s), var(--accent-l), .25);
}

[data-theme="dark"] {
  --bg-base: #0a0e1a;
  --bg-surface: #ffffff0a;
  --bg-glass: #ffffff0f;
  --bg-glass-hover: #ffffff1a;
  --bg-glass-active: #ffffff1f;
  --bg-card: #ffffff0d;
  --bg-input: #ffffff0f;
  --border-color: #ffffff14;
  --border-glass: #ffffff1f;
  --text-primary: #f0f2f5;
  --text-secondary: #8b92a5;
  --text-muted: #5a6178;
  --shadow-glass: 0 8px 32px #0000004d;
  --shadow-card: 0 4px 24px #0003;
  --shadow-dropdown: 0 12px 40px #00000080;
  --backdrop-blur: blur(20px);
  --scrollbar-track: #ffffff05;
  --scrollbar-thumb: #ffffff1a;
  --success: #34d399;
  --warning: #fbbf24;
  --danger: #f87171;
  --info: #60a5fa;
}

[data-theme="light"] {
  --bg-base: #f0f2f5;
  --bg-surface: #ffffffb3;
  --bg-glass: #ffffffa6;
  --bg-glass-hover: #fffc;
  --bg-glass-active: #ffffffe6;
  --bg-card: #ffffffb3;
  --bg-input: #0000000a;
  --border-color: #00000014;
  --border-glass: #0000001a;
  --text-primary: #1a1d2e;
  --text-secondary: #5a6178;
  --text-muted: #8b92a5;
  --shadow-glass: 0 8px 32px #00000014;
  --shadow-card: 0 4px 24px #0000000f;
  --shadow-dropdown: 0 12px 40px #0000001f;
  --backdrop-blur: blur(20px);
  --scrollbar-track: #00000005;
  --scrollbar-thumb: #0000001f;
  --success: #10b981;
  --warning: #f59e0b;
  --danger: #ef4444;
  --info: #3b82f6;
}

*, :before, :after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font);
  background: var(--bg-base);
  color: var(--text-primary);
  min-height: 100vh;
  line-height: 1.6;
  overflow: hidden;
}

::-webkit-scrollbar {
  width: 6px;
}

::-webkit-scrollbar-track {
  background: var(--scrollbar-track);
}

::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb);
  border-radius: 3px;
}

.app-layout {
  height: 100vh;
  display: flex;
  overflow: hidden;
}

.sidebar {
  width: var(--sidebar-w);
  background: var(--bg-glass);
  height: 100vh;
  -webkit-backdrop-filter: var(--backdrop-blur);
  border-right: 1px solid var(--border-glass);
  transition: width var(--transition);
  z-index: 100;
  flex-direction: column;
  display: flex;
  position: fixed;
  top: 0;
  left: 0;
  overflow: hidden;
}

.sidebar.collapsed {
  width: var(--sidebar-collapsed);
}

.sidebar.collapsed .nav-label, .sidebar.collapsed .sidebar-logo span, .sidebar.collapsed .sidebar-section-title, .sidebar.collapsed .nav-badge {
  display: none;
}

.sidebar.collapsed .nav-item {
  justify-content: center;
  padding: 12px;
  position: relative;
}

.sidebar.collapsed .nav-item i {
  margin-right: 0;
  font-size: 18px;
}

.sidebar.collapsed .sidebar-logo {
  justify-content: center;
  padding: 16px;
}

.sidebar.collapsed .nav-item:after {
  content: attr(data-tooltip);
  background: var(--bg-base);
  color: var(--text-primary);
  border-radius: var(--radius-xs);
  white-space: nowrap;
  border: 1px solid var(--border-glass);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  z-index: 999;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  transition: opacity .2s, visibility .2s;
  position: absolute;
  top: 50%;
  left: calc(100% + 8px);
  transform: translateY(-50%);
  box-shadow: 0 4px 16px #00000026;
}

.sidebar.collapsed .nav-item:hover:after {
  opacity: 1;
  visibility: visible;
}

.sidebar-logo {
  border-bottom: 1px solid var(--border-glass);
  flex-shrink: 0;
  align-items: center;
  gap: 12px;
  padding: 20px 20px 16px;
  display: flex;
}

.sidebar-logo .logo-icon {
  background: linear-gradient(135deg, var(--accent), hsl(calc(var(--accent-h) + 30), var(--accent-s), var(--accent-l)));
  border-radius: var(--radius-xs);
  color: #fff;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
  width: 38px;
  height: 38px;
  font-size: 16px;
  font-weight: 700;
  display: flex;
}

.sidebar-logo .logo-icon--image {
  object-fit: cover;
  background: none;
  padding: 0;
}

.sidebar-logo span {
  color: var(--text-primary);
  white-space: nowrap;
  font-size: 16px;
  font-weight: 700;
}

.sidebar-logo .logo-nameimage {
  object-fit: contain;
  object-position: left center;
  flex-shrink: 1;
  width: auto;
  min-width: 0;
  max-width: 100%;
  height: 38px;
}

.sidebar-nav {
  scrollbar-width: thin;
  flex: 1;
  padding: 12px 8px;
  overflow-y: auto;
}

.sidebar-section-title {
  text-transform: uppercase;
  letter-spacing: 1.2px;
  color: var(--text-muted);
  white-space: nowrap;
  padding: 16px 14px 8px;
  font-size: 10px;
  font-weight: 600;
}

.nav-item {
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-secondary);
  transition: all var(--transition);
  white-space: nowrap;
  align-items: center;
  gap: 0;
  margin: 2px 0;
  padding: 10px 14px;
  text-decoration: none;
  display: flex;
  position: relative;
}

.nav-item:hover {
  background: var(--bg-glass-hover);
  color: var(--text-primary);
}

.nav-item.active {
  background: var(--accent-light);
  color: var(--accent);
}

.nav-item.active:before {
  content: "";
  background: var(--accent);
  border-radius: 0 3px 3px 0;
  width: 3px;
  height: 20px;
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
}

.nav-item i {
  text-align: center;
  flex-shrink: 0;
  width: 20px;
  margin-right: 12px;
  font-size: 15px;
}

.nav-label {
  font-size: 13px;
  font-weight: 500;
}

.nav-badge {
  background: var(--danger);
  color: #fff;
  border-radius: 10px;
  margin-left: auto;
  padding: 2px 7px;
  font-size: 10px;
  font-weight: 600;
}

.sidebar-collapse-btn {
  border-top: 1px solid var(--border-glass);
  cursor: pointer;
  color: var(--text-muted);
  transition: all var(--transition);
  font-family: var(--font);
  background: none;
  border-bottom: none;
  border-left: none;
  border-right: none;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 14px;
  font-size: 12px;
  display: flex;
}

.sidebar-collapse-btn:hover {
  color: var(--text-primary);
  background: var(--bg-glass-hover);
}

.sidebar-collapse-btn i {
  transition: transform var(--transition);
  font-size: 14px;
}

.sidebar.collapsed .sidebar-collapse-btn span {
  display: none;
}

.sidebar.collapsed .sidebar-collapse-btn i {
  transform: rotate(180deg);
}

.main-content {
  margin-left: var(--sidebar-w);
  height: 100vh;
  transition: margin-left var(--transition);
  flex-direction: column;
  flex: 1;
  display: flex;
  overflow: hidden;
}

.main-content.sidebar-collapsed {
  margin-left: var(--sidebar-collapsed);
}

.header {
  height: var(--header-h);
  background: var(--bg-glass);
  -webkit-backdrop-filter: var(--backdrop-blur);
  border-bottom: 1px solid var(--border-glass);
  z-index: 50;
  flex-shrink: 0;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
  display: flex;
}

.header-left {
  align-items: center;
  gap: 16px;
  display: flex;
}

.header-left .toggle-sidebar {
  background: var(--bg-glass);
  border-radius: var(--radius-xs);
  width: 36px;
  height: 36px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all var(--transition);
  border: none;
  justify-content: center;
  align-items: center;
  font-size: 16px;
  display: flex;
}

.header-left .toggle-sidebar:hover {
  background: var(--bg-glass-hover);
  color: var(--text-primary);
}

.page-breadcrumb {
  color: var(--text-muted);
  font-size: 12px;
}

.sr-only {
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  position: absolute;
  overflow: hidden;
}

.page-actions {
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  display: flex;
}

.header-right {
  align-items: center;
  gap: 12px;
  display: flex;
}

.header-btn {
  background: var(--bg-glass);
  border-radius: var(--radius-xs);
  width: 36px;
  height: 36px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all var(--transition);
  border: none;
  justify-content: center;
  align-items: center;
  font-size: 15px;
  display: flex;
  position: relative;
}

.header-btn:hover {
  background: var(--bg-glass-hover);
  color: var(--text-primary);
}

.header-btn .badge-dot {
  background: var(--danger);
  border: 2px solid var(--bg-base);
  border-radius: 50%;
  width: 8px;
  height: 8px;
  position: absolute;
  top: 6px;
  right: 6px;
}

.header-btn .badge-count {
  background: var(--danger);
  color: #fff;
  border: 2px solid var(--bg-base);
  border-radius: 8px;
  justify-content: center;
  align-items: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  font-size: 9px;
  font-weight: 700;
  display: flex;
  position: absolute;
  top: 2px;
  right: 2px;
}

.user-avatar {
  background: linear-gradient(135deg, var(--accent), hsl(calc(var(--accent-h) + 40), 80%, 60%));
  color: #fff;
  cursor: pointer;
  width: 36px;
  height: 36px;
  transition: all var(--transition);
  border-radius: 50%;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  display: flex;
}

.user-avatar:hover {
  box-shadow: 0 0 0 3px var(--accent-light);
}

.page-container {
  flex: 1;
  padding: 24px;
  overflow-y: auto;
}

.denial-banner {
  border: 1px solid var(--warning);
  background: var(--bg-card);
  color: var(--text-primary);
  border-radius: 8px;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  padding: 10px 14px;
  font-size: 14px;
  display: flex;
}

.denial-banner__text {
  flex: 1;
}

.denial-banner__dismiss {
  cursor: pointer;
  color: var(--text-muted);
  background: none;
  border: 0;
  flex: none;
  padding: 4px;
  line-height: 1;
}

.denial-banner__dismiss:hover {
  color: var(--text-primary);
}

.page-fade-enter-active {
  animation: .3s fadeIn;
}

.page-fade-leave-active {
  animation: .15s reverse fadeIn;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.glass-card {
  background: var(--bg-glass);
  -webkit-backdrop-filter: var(--backdrop-blur);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius);
  transition: all var(--transition);
  padding: 24px;
}

.glass-card:hover {
  border-color: #ffffff26;
}

[data-theme="light"] .glass-card:hover {
  border-color: #0000001f;
}

.form-group {
  margin-bottom: 16px;
}

.form-label {
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .5px;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 600;
  display: block;
}

.form-control {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xs);
  width: 100%;
  color: var(--text-primary);
  font-size: 14px;
  font-family: var(--font);
  transition: all var(--transition);
  outline: none;
  padding: 10px 14px;
}

.form-control:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

.form-control::placeholder {
  color: var(--text-muted);
}

.btn {
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: all var(--transition);
  font-size: 13px;
  font-weight: 500;
  font-family: var(--font);
  border: none;
  align-items: center;
  gap: 8px;
  padding: 9px 18px;
  display: inline-flex;
}

.btn-primary {
  background: var(--accent);
  color: #fff;
}

.btn-primary:hover {
  filter: brightness(1.1);
  box-shadow: 0 4px 16px var(--accent-glow);
}

.theme-toggle {
  gap: 8px;
  display: flex;
}

.theme-toggle button {
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
  border-radius: var(--radius-xs);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 13px;
  font-family: var(--font);
  transition: all var(--transition);
  flex: 1;
  justify-content: center;
  align-items: center;
  gap: 8px;
  padding: 10px;
  font-weight: 500;
  display: flex;
}

.theme-toggle button.active {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-light);
}

.color-presets {
  grid-template-columns: repeat(6, 1fr);
  gap: 8px;
  display: grid;
}

.color-preset {
  aspect-ratio: 1;
  cursor: pointer;
  width: 100%;
  transition: all var(--transition);
  border: 2px solid #0000;
  border-radius: 50%;
  position: relative;
}

.color-preset:hover {
  transform: scale(1.15);
}

.color-preset.active {
  border-color: var(--text-primary);
}

.color-preset.active:after {
  content: "";
  color: #fff;
  font-family: "Font Awesome 6 Free";
  font-size: 10px;
  font-weight: 900;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.settings-overlay {
  z-index: 200;
  background: linear-gradient(var(--bg-glass), var(--bg-glass)), var(--bg-base);
  border-left: 1px solid var(--border-glass);
  width: 340px;
  box-shadow: var(--shadow-dropdown);
  padding: 24px;
  animation: .3s slideIn;
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  overflow-y: auto;
}

@keyframes slideIn {
  from {
    transform: translateX(100%);
  }

  to {
    transform: translateX(0);
  }
}

.settings-overlay h3 {
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  font-size: 16px;
  font-weight: 600;
  display: flex;
}

.settings-overlay .close-settings {
  background: var(--bg-glass);
  border-radius: var(--radius-xs);
  width: 32px;
  height: 32px;
  color: var(--text-secondary);
  cursor: pointer;
  border: none;
  justify-content: center;
  align-items: center;
  display: flex;
}

.setting-section {
  margin-bottom: 24px;
}

.setting-section label {
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: .5px;
  margin-bottom: 10px;
  font-size: 12px;
  font-weight: 600;
  display: block;
}

.dropdown-menu {
  background: linear-gradient(var(--bg-glass), var(--bg-glass)), var(--bg-base);
  border: 1px solid var(--border-glass);
  border-radius: var(--radius);
  min-width: 200px;
  box-shadow: var(--shadow-dropdown);
  z-index: 1000;
  animation: .2s dropdownFade;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  overflow: hidden;
}

@keyframes dropdownFade {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.dropdown-header {
  border-bottom: 1px solid var(--border-glass);
  padding: 14px 16px;
}

.dropdown-item {
  color: var(--text-primary);
  cursor: pointer;
  width: 100%;
  font-size: 13px;
  font-family: var(--font);
  text-align: left;
  background: none;
  border: none;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  text-decoration: none;
  transition: background .2s;
  display: flex;
}

.dropdown-item:hover {
  background: var(--bg-glass-hover);
}

.dropdown-item i {
  color: var(--text-muted);
  width: 16px;
}

.dropdown-item.danger, .dropdown-item.danger i {
  color: var(--danger);
}

.dropdown-divider {
  border-top: 1px solid var(--border-glass);
}

@media (max-width: 768px) {
  .sidebar {
    width: var(--sidebar-w);
    z-index: 200;
    transform: translateX(-100%);
  }

  .sidebar.mobile-open {
    transform: translateX(0);
  }

  .main-content {
    margin-left: 0 !important;
  }

  .page-container {
    padding: 16px;
  }
}

@media (max-width: 480px) {
  .header {
    padding: 0 12px;
  }

  .glass-card {
    padding: 16px;
  }
}

.mobile-overlay {
  z-index: 150;
  background: #00000080;
  display: none;
  position: fixed;
  inset: 0;
}

.mobile-overlay.show {
  display: block;
}

.loading-spinner {
  color: var(--text-muted);
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 16px;
  padding: 80px 24px;
  display: flex;
}

.loading-spinner .spinner {
  border: 3px solid var(--border-glass);
  border-top-color: var(--accent);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: .8s linear infinite spin;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.error-state {
  color: var(--text-muted);
  text-align: center;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 12px;
  padding: 80px 24px;
  display: flex;
}

.error-state i {
  color: var(--danger);
  font-size: 48px;
}

.error-state h3 {
  color: var(--text-secondary);
  font-size: 16px;
  font-weight: 600;
}

.error-state p {
  max-width: 400px;
  font-size: 13px;
}

@property --tw-rotate-x {
  syntax: "*";
  inherits: false
}

@property --tw-rotate-y {
  syntax: "*";
  inherits: false
}

@property --tw-rotate-z {
  syntax: "*";
  inherits: false
}

@property --tw-skew-x {
  syntax: "*";
  inherits: false
}

@property --tw-skew-y {
  syntax: "*";
  inherits: false
}

@property --tw-border-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}

@property --tw-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-shadow-color {
  syntax: "*";
  inherits: false
}

@property --tw-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@property --tw-inset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-inset-shadow-color {
  syntax: "*";
  inherits: false
}

@property --tw-inset-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}

@property --tw-ring-color {
  syntax: "*";
  inherits: false
}

@property --tw-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-inset-ring-color {
  syntax: "*";
  inherits: false
}

@property --tw-inset-ring-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-ring-inset {
  syntax: "*";
  inherits: false
}

@property --tw-ring-offset-width {
  syntax: "<length>";
  inherits: false;
  initial-value: 0;
}

@property --tw-ring-offset-color {
  syntax: "*";
  inherits: false;
  initial-value: #fff;
}

@property --tw-ring-offset-shadow {
  syntax: "*";
  inherits: false;
  initial-value: 0 0 #0000;
}

@property --tw-outline-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}

@property --tw-ease {
  syntax: "*";
  inherits: false
}

.kpi-card[data-v-488e829a] {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-glass);
  border-radius: 16px;
  /* No box-shadow — see VisualAiCard. This is the standalone (non-flat) case;
     the flat case draws no chrome at all. */
  padding: 20px 24px;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.kpi-card[data-v-488e829a]:hover {
  border-color: rgba(255, 255, 255, 0.15);
  transform: translateY(-2px);
}
[data-theme="light"] .kpi-card[data-v-488e829a]:hover {
  border-color: rgba(0, 0, 0, 0.12);
}

/* Already inside someone else's card — see the `flat` prop. The lift on hover
   goes too: a nested block that rises off a card it is painted flush against
   reads as a rendering glitch rather than an affordance. */
.kpi-card--flat[data-v-488e829a],
.kpi-card--flat[data-v-488e829a]:hover {
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  transform: none;
}
.kpi-icon[data-v-488e829a] {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
}
.kpi-icon--blue[data-v-488e829a] {
  background: rgba(59, 130, 246, 0.15);
  color: var(--info);
}
.kpi-icon--green[data-v-488e829a] {
  background: rgba(52, 211, 153, 0.15);
  color: var(--success);
}
.kpi-icon--orange[data-v-488e829a] {
  background: rgba(251, 191, 36, 0.15);
  color: var(--warning);
}
.kpi-icon--red[data-v-488e829a] {
  background: rgba(248, 113, 113, 0.15);
  color: var(--danger);
}
.kpi-icon--purple[data-v-488e829a] {
  background: rgba(167, 139, 250, 0.15);
  color: #a78bfa;
}
.kpi-icon--teal[data-v-488e829a] {
  background: rgba(45, 212, 191, 0.15);
  color: #2dd4bf;
}
.kpi-info[data-v-488e829a] {
  flex: 1;
  min-width: 0;
}
.kpi-value[data-v-488e829a] {
  font-size: 26px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.2;
  margin: 0;
}
.kpi-label[data-v-488e829a] {
  font-size: 13px;
  color: var(--text-secondary);
  margin: 4px 0 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * The note WRAPS where the label ellipsises. It exists to explain a missing or
 * partial figure, so truncating it to one line would defeat the point — an
 * operator seeing "—" needs the whole reason, not the first few words of it.
 */
/* Visually hidden, NOT display:none — the latter drops it from the
   accessibility tree, which would defeat the purpose. */
.sr-only[data-v-488e829a] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/*
 * Bounded to two lines. The tile is allotted a FIXED 7 grid rows (188px) and
 * `.grid-cell` sets `overflow: hidden`, so an unbounded note would simply be
 * cut off mid-sentence — and how many lines it takes depends on the card's
 * width and on tenant-localized labels, which can be far longer than the
 * English ones this was measured against. Two lines keeps the worst case at
 * ~132px, comfortably inside the cell, and the full string stays reachable as
 * the element's own tooltip.
 */
.kpi-note[data-v-488e829a] {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-secondary);
  margin: 4px 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kpi-trend[data-v-488e829a] {
  font-size: 12px;
  font-weight: 500;
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.kpi-trend.up[data-v-488e829a] {
  color: var(--success);
}
.kpi-trend.down[data-v-488e829a] {
  color: var(--danger);
}
.kpi-trend i[data-v-488e829a] {
  font-size: 10px;
}

.gate-grid[data-v-4b78a5aa] {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-bottom: 16px;
}
@media (max-width: 480px) {
.gate-grid[data-v-4b78a5aa] { grid-template-columns: 1fr;
}
}
.gate-card[data-v-4b78a5aa] {
  background: var(--bg-glass);
  border: 1px solid var(--border-glass);
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  transition: all 0.3s;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.gate-card[data-v-4b78a5aa]:hover {
  border-color: rgba(255, 255, 255, 0.15);
  background: var(--bg-glass-hover);
}
.gate-card--offline[data-v-4b78a5aa] {
  opacity: 0.65;
}
.gate-indicator[data-v-4b78a5aa] {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  transition: all 0.3s;
}
.gate-indicator--online[data-v-4b78a5aa] {
  background: rgba(52, 211, 153, 0.15);
  color: var(--success);
  box-shadow: 0 0 20px rgba(52, 211, 153, 0.2);
}
.gate-indicator--offline[data-v-4b78a5aa] {
  background: rgba(248, 113, 113, 0.15);
  color: var(--danger);
}
.gate-name[data-v-4b78a5aa] {
  font-weight: 600;
  font-size: 14px;
  color: var(--text-primary);
}
.gate-type-badge[data-v-4b78a5aa] {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  padding: 2px 8px;
  background: var(--bg-glass-active);
  border-radius: 4px;
}
.gate-status-badge[data-v-4b78a5aa] {
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 20px;
}
.gate-status-badge--online[data-v-4b78a5aa] {
  background: rgba(52, 211, 153, 0.12);
  color: var(--success);
  border: 1px solid rgba(52, 211, 153, 0.2);
}
.gate-status-badge--offline[data-v-4b78a5aa] {
  background: rgba(248, 113, 113, 0.12);
  color: var(--danger);
  border: 1px solid rgba(248, 113, 113, 0.2);
}
.gate-actions[data-v-4b78a5aa] {
  display: flex;
  gap: 6px;
  margin-top: 4px;
  width: 100%;
}
.gate-action-btn[data-v-4b78a5aa] {
  flex: 1;
  padding: 6px 8px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--bg-glass);
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-family: inherit;
}
.gate-action-btn--open[data-v-4b78a5aa]:hover {
  color: var(--success);
  border-color: var(--success);
  background: rgba(52, 211, 153, 0.08);
}
.gate-action-btn--close[data-v-4b78a5aa]:hover {
  color: var(--text-secondary);
  border-color: var(--border-glass);
  background: var(--bg-glass-hover);
}
.emergency-btn[data-v-4b78a5aa] {
  width: 100%;
  padding: 12px;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #ef4444, #dc2626);
  border: none;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.emergency-btn[data-v-4b78a5aa]:hover {
  background: linear-gradient(135deg, #dc2626, #b91c1c);
  box-shadow: 0 4px 20px rgba(239, 68, 68, 0.4);
  transform: translateY(-1px);
}

.summary-grid[data-v-23fbce5f] {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 16px;
}
.summary-stat[data-v-23fbce5f] {
  background: var(--bg-glass);
  border: 1px solid var(--border-glass);
  border-radius: 10px;
  padding: 14px;
  text-align: center;
  transition: all 0.2s;
}
.summary-stat[data-v-23fbce5f]:hover {
  background: var(--bg-glass-hover);
}
.summary-value[data-v-23fbce5f] {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
}
.summary-value--info[data-v-23fbce5f] { color: var(--info);
}
.summary-value--success[data-v-23fbce5f] { color: var(--success);
}
.summary-value--warning[data-v-23fbce5f] { color: var(--warning);
}
.summary-value--danger[data-v-23fbce5f] { color: var(--danger);
}
.summary-label[data-v-23fbce5f] {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
}
.camera-table-wrap[data-v-23fbce5f] {
  overflow-x: auto;
}
.camera-table[data-v-23fbce5f] {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.camera-table thead th[data-v-23fbce5f] {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-color);
}
.camera-table tbody td[data-v-23fbce5f] {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-primary);
}

/* Was .cam-id, monospace at 11px — serial-number styling for a serial number.
   The cell now carries a name, so it takes the table's own type. */
.cam-name[data-v-23fbce5f] {
  font-weight: 600;
}
.cam-status[data-v-23fbce5f] {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 20px;
}
.cam-status--online[data-v-23fbce5f] {
  background: rgba(52, 211, 153, 0.12);
  color: var(--success);
}
.cam-status--offline[data-v-23fbce5f] {
  background: rgba(248, 113, 113, 0.12);
  color: var(--danger);
}
.cam-heartbeat[data-v-23fbce5f] {
  font-size: 11px;
  color: var(--text-muted);
}
.no-cameras[data-v-23fbce5f] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.feed-controls[data-v-40dc8c83] {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Metrics only. Two of the four `.feed-select` elements are VisualAiSelect
   COMPONENTS, so this class lands on their root <div> through attribute
   fall-through — a background/border/padding here paints a second box around
   the trigger button, which already paints itself. The compact size reaches the
   button through the shared --va-control-* metrics; the two native date inputs
   keep the paint under `.feed-date`. */
.feed-select[data-v-40dc8c83] {
  --va-control-py: 5px;
  --va-control-px: 10px;
  --va-control-font: 12px;
  --va-control-radius: 8px;
}
.feed-date[data-v-40dc8c83] {
  padding: 5px 10px;
  font-size: 12px;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  color: var(--text-primary);
  outline: none;
  cursor: pointer;
  transition: border-color 0.2s;
  font-family: inherit;
  min-width: 130px;
  /* No `color-scheme: dark` here: it pinned the picker icon to white, which
     was right in dark mode and invisible against a light input in light mode.
     applyTheme() now sets color-scheme on :root, so this input inherits the
     ACTIVE theme instead of assuming one (OBS-02). */
}
.feed-live-indicator[data-v-40dc8c83] {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  padding: 4px 10px;
  border-radius: 20px;
  background: var(--bg-glass);
  border: 1px solid var(--border-color);
}
.feed-live-indicator.connected[data-v-40dc8c83] {
  color: var(--success);
  border-color: rgba(52, 211, 153, 0.3);
  background: rgba(52, 211, 153, 0.08);
}
.feed-live-indicator.connected .feed-sync-icon[data-v-40dc8c83] {
  animation: spin-sync-40dc8c83 3s linear infinite;
}
@keyframes spin-sync-40dc8c83 {
from { transform: rotate(0deg);
}
to { transform: rotate(360deg);
}
}
.feed-table-wrap[data-v-40dc8c83] {
  overflow-x: auto;
  margin: 0 -24px;
  padding: 0 24px;
}
.feed-table[data-v-40dc8c83] {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.feed-table thead th[data-v-40dc8c83] {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  font-weight: 600;
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-color);
  white-space: nowrap;
}
.feed-table tbody td[data-v-40dc8c83] {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-primary);
  vertical-align: middle;
}
.feed-row[data-v-40dc8c83] {
  transition: background 0.2s;
}
.feed-row[data-v-40dc8c83]:hover {
  background: var(--bg-glass-hover);
}
.feed-row--blacklisted[data-v-40dc8c83] {
  background: rgba(248, 113, 113, 0.06);
}
.feed-row--blacklisted[data-v-40dc8c83]:hover {
  background: rgba(248, 113, 113, 0.12);
}
.feed-time[data-v-40dc8c83] {
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
  font-size: 12px;
}
.feed-date[data-v-40dc8c83]:focus {
  border-color: hsl(var(--accent-h) var(--accent-s) var(--accent-l));
}
.feed-date-sep[data-v-40dc8c83] {
  font-size: 11px;
  color: var(--text-muted);
  align-self: center;
}
.feed-image-col[data-v-40dc8c83] { text-align: center; width: 88px;
}
.feed-image-link[data-v-40dc8c83] {
  display: inline-block;
  line-height: 0;
  border-radius: 4px;
  overflow: hidden;
  text-decoration: none;
}
.feed-thumb[data-v-40dc8c83] {
  width: 80px;
  height: 56px;
  object-fit: cover;
  display: block;
  border: 1px solid var(--border-glass);
  border-radius: 4px;
  background: var(--bg-glass);
  transition: transform 0.15s, border-color 0.15s;
}
.feed-image-link:hover .feed-thumb[data-v-40dc8c83] {
  transform: scale(1.04);
  border-color: var(--accent);
}
.feed-image-link--broken[data-v-40dc8c83]::after {
  content: '\f071';
  font-family: 'Font Awesome 6 Free';
  font-weight: 900;
  display: inline-block;
  width: 80px;
  height: 56px;
  line-height: 56px;
  text-align: center;
  color: var(--text-secondary);
  font-size: 18px;
  border: 1px dashed var(--border-glass);
  border-radius: 4px;
}
.feed-image-none[data-v-40dc8c83] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 80px;
  height: 56px;
  color: var(--text-muted);
  font-size: 14px;
  border: 1px dashed var(--border-glass);
  border-radius: 4px;
}
.feed-gate[data-v-40dc8c83] {
  font-size: 12px;
  color: var(--text-secondary);
}
.type-badge[data-v-40dc8c83] {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  text-transform: capitalize;
  white-space: nowrap;
}
.type-badge--entry[data-v-40dc8c83] {
  background: rgba(52, 211, 153, 0.12);
  color: var(--success);
  border: 1px solid rgba(52, 211, 153, 0.2);
}
.type-badge--exit[data-v-40dc8c83] {
  background: rgba(96, 165, 250, 0.12);
  color: var(--info);
  border: 1px solid rgba(96, 165, 250, 0.2);
}
.type-badge--pending[data-v-40dc8c83] {
  background: rgba(251, 191, 36, 0.12);
  color: var(--warning);
  border: 1px solid rgba(251, 191, 36, 0.2);
}
.feed-plate[data-v-40dc8c83] {
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.5px;
  font-family: 'JetBrains Mono', 'Fira Code', monospace;
}
.feed-resident[data-v-40dc8c83] {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
  display: inline-block;
}
.feed-resident-empty[data-v-40dc8c83] {
  color: var(--text-muted);
  font-size: 13px;
}
.confidence-bar[data-v-40dc8c83] {
  display: inline-block;
  width: 48px;
  height: 4px;
  background: var(--bg-glass-active);
  border-radius: 2px;
  overflow: hidden;
  vertical-align: middle;
  margin-right: 6px;
}
.confidence-fill[data-v-40dc8c83] {
  display: block;
  height: 100%;
  border-radius: 2px;
  transition: width 0.3s;
}
.confidence-fill--high[data-v-40dc8c83] { background: var(--success);
}
.confidence-fill--medium[data-v-40dc8c83] { background: var(--warning);
}
.confidence-fill--low[data-v-40dc8c83] { background: var(--danger);
}
.confidence-text[data-v-40dc8c83] {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
.status-badge[data-v-40dc8c83] {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
.status-badge i[data-v-40dc8c83] { font-size: 10px;
}
.status-badge--success[data-v-40dc8c83] {
  background: rgba(52, 211, 153, 0.12);
  color: var(--success);
  border: 1px solid rgba(52, 211, 153, 0.2);
}
.status-badge--danger[data-v-40dc8c83] {
  background: rgba(248, 113, 113, 0.12);
  color: var(--danger);
  border: 1px solid rgba(248, 113, 113, 0.2);
}
.status-badge--warning[data-v-40dc8c83] {
  background: rgba(251, 191, 36, 0.12);
  color: var(--warning);
  border: 1px solid rgba(251, 191, 36, 0.2);
}
.feed-empty[data-v-40dc8c83] {
  text-align: center;
  padding: 40px 24px !important;
  color: var(--text-muted);
  font-size: 14px;
}
.feed-empty i[data-v-40dc8c83] {
  display: block;
  font-size: 32px;
  margin-bottom: 10px;
  opacity: 0.5;
}
.feed-footer[data-v-40dc8c83] {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.feed-count[data-v-40dc8c83] {
  font-size: 12px;
  color: var(--text-muted);
}
.feed-sync-icon[data-v-40dc8c83] {
  font-size: 10px;
  margin-right: 4px;
}

.people-today-grid[data-v-41603391] {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
@media (max-width: 640px) {
.people-today-grid[data-v-41603391] {
    grid-template-columns: 1fr;
}
}

.attendance-today-grid[data-v-00222303] {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
@media (max-width: 900px) {
.attendance-today-grid[data-v-00222303] {
    grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.attendance-today-grid[data-v-00222303] {
    grid-template-columns: 1fr;
}
}

.feed[data-v-113848c3] {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  height: 100%;
  overflow-y: auto;
}
.feed__row[data-v-113848c3] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.feed__chip[data-v-113848c3] {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  white-space: nowrap;
  flex-shrink: 0;
  border: 1px solid currentColor;
  /* An unrecognised kind is named by the RAW backend string, whose length this
     build cannot know. Capped so a long one ellipsises inside the chip instead
     of pushing the description and the timestamp out of the row. */
  max-width: 45%;
}
.feed__chip-text[data-v-113848c3] {
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.feed__chip--plate[data-v-113848c3] {
  color: var(--info);
}
.feed__chip--person[data-v-113848c3] {
  color: var(--success);
}
.feed__chip--fire[data-v-113848c3] {
  color: var(--danger);
}
.feed__chip--smoke[data-v-113848c3] {
  color: var(--warning);
}

/* Muted, matching `type-badge--unknown` on the Detections page. A kind this
   build cannot name must not borrow the colour of one it can — an unrecognised
   type wearing --info would read as a vehicle at a glance, which is the whole
   defect in a different medium. */
.feed__chip--unknown[data-v-113848c3] {
  color: var(--text-muted);
}
.feed__label[data-v-113848c3] {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.feed__time[data-v-113848c3] {
  margin-inline-start: auto;
  color: var(--text-muted);
  flex-shrink: 0;
}

.health[data-v-dc0b6f7d] {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
}
.health__counts[data-v-dc0b6f7d] {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.health__count[data-v-dc0b6f7d] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 4px;
  border: 1px solid var(--border-glass);
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.health__count[data-v-dc0b6f7d]:hover,
.health__count.is-active[data-v-dc0b6f7d] {
  border-color: currentColor;
}
.health__count--online[data-v-dc0b6f7d] {
  color: var(--success);
}
.health__count--degraded[data-v-dc0b6f7d] {
  color: var(--warning);
}
.health__count--offline[data-v-dc0b6f7d] {
  color: var(--danger);
}
.health__number[data-v-dc0b6f7d] {
  font-size: 20px;
  font-weight: 600;
  line-height: 1;
}
.health__label[data-v-dc0b6f7d] {
  font-size: 11px;
  color: var(--text-muted);
}
.health__list[data-v-dc0b6f7d] {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.health__row[data-v-dc0b6f7d] {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.health__dot[data-v-dc0b6f7d] {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.health__dot--online[data-v-dc0b6f7d],
.health__dot--connecting[data-v-dc0b6f7d] {
  background: var(--success);
}
.health__dot--degraded[data-v-dc0b6f7d] {
  background: var(--warning);
}
.health__dot--offline[data-v-dc0b6f7d] {
  background: var(--danger);
}
.health__name[data-v-dc0b6f7d] {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.health__meta[data-v-dc0b6f7d] {
  margin-inline-start: auto;
  color: var(--text-muted);
  flex-shrink: 0;
}
.health__all-well[data-v-dc0b6f7d] {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 12px;
  color: var(--success);
  flex: 1;
}

.plates[data-v-b26ce838] {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  height: 100%;
  overflow-y: auto;
  counter-reset: rank;
}
.plates__row[data-v-b26ce838] {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
}
.plates__rank[data-v-b26ce838] {
  width: 18px;
  flex-shrink: 0;
  text-align: end;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.plates__plate[data-v-b26ce838] {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.04em;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plates__meta[data-v-b26ce838] {
  margin-inline-start: auto;
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-shrink: 0;
}
.plates__passes[data-v-b26ce838] {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.plates__seen[data-v-b26ce838] {
  color: var(--text-muted);
}

.chart-canvas[data-v-80fb02e9] {
  position: relative;
  width: 100%;
}
.chart-canvas__empty[data-v-80fb02e9] {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-muted);
  font-size: 13px;
}
.chart-canvas__empty i[data-v-80fb02e9] {
  font-size: 22px;
  opacity: 0.5;
}
.chart-canvas__legend[data-v-80fb02e9] {
  display: flex;
  gap: 16px;
  justify-content: center;
  margin-top: 12px;
  font-size: 12px;
}

.coverage[data-v-94f9c2a3] {
  margin: 10px 0 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-muted);
}

.overstay[data-v-0095e364] {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  overflow-y: auto;
}
.overstay__row[data-v-0095e364] {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
}
.overstay__who[data-v-0095e364] {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.overstay__name[data-v-0095e364] {
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.overstay__sub[data-v-0095e364] {
  color: var(--text-muted);
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.overstay__over[data-v-0095e364] {
  margin-inline-start: auto;
  flex-shrink: 0;
  color: var(--warning);
  font-variant-numeric: tabular-nums;
}
.overstay__over.is-severe[data-v-0095e364] {
  color: var(--danger);
}

.gender[data-v-25d324c5] {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Lets the chart grow in a tall card. NOT depended on: .gender__pie carries
     its own definite size — see peopleHourlyProfileStyles.spec.ts for the bug
     that rule exists to prevent. */
  height: 100%;
}
.gender__chart[data-v-25d324c5] {
  display: flex;
  align-items: center;
  /* Centre the donut + legend pair rather than hugging the left edge — but
     only when it FITS.

     The donut is `flex: 0 0 108px` and cannot shrink, so in a card narrower
     than donut+legend a plain `center` overflows BOTH sides, and `.grid-cell`
     clips with `overflow: hidden` — the donut itself gets cut off. `safe
     center` falls back to start-alignment exactly then.

     The first declaration is `flex-start`, NOT `center`: it is what a browser
     that cannot parse the `safe` keyword is left with, so it must be the SAFE
     alignment. Writing `center` there would hand those browsers the very bug
     this rule exists to avoid. Centring is the progressive enhancement.

     Deliberately no `flex-wrap`. Wrapping would not help — nothing can make a
     108px donut fit a narrower card — and it would make this row taller, which
     in a short card pushes the coverage caption into the clipped region. It
     trades a sideways clip for a vertical one. */
  justify-content: flex-start;
  justify-content: safe center;
  gap: 14px;
  flex: 1 0 auto;
  /* The box .gender__pie sizes itself against.

     `inline-size`, NOT `size`: the size variant needs a DEFINITE HEIGHT, which
     is exactly what a WidgetFrame body does not have — asking for it would
     re-open the collapse this widget's px sizing exists to avoid. Inline-size
     containment needs only a definite WIDTH, which a flex row always has. */
  container-type: inline-size;
}

/*
 * THE DONUT OWNS ITS SIZE, in px, on both axes.
 *
 * Unchanged in shape by the move to ChartCanvas (AB#15979), and still
 * load-bearing for the same reason. Chart.js runs `maintainAspectRatio: false`,
 * so the canvas fills THIS box; `ChartCanvas` is handed `height="100%"`, and a
 * percentage height only resolves against a definite one. A percentage here
 * would inherit the same collapse that blanked the hourly-profile and
 * people-flow sparklines in an auto-height WidgetFrame body — a canvas of zero
 * height rather than an unpainted gradient, but just as blank. `flex-shrink: 0`
 * keeps the box square in a narrow cell, so the arc stays a circle rather than
 * being centred in a squashed rectangle.
 */
.gender__pie[data-v-25d324c5] {
  /* `auto` basis, so the width declarations below are what decide the size.
     Still 0 0 — shrinking would squash the circle into an ellipse. */
  flex: 0 0 auto;
  width: 108px;
  height: 108px;
  /* Grow with the CARD'S WIDTH, in px on both axes.

     Sized off the container's inline size rather than a percentage: a
     percentage of an auto-height parent collapses to 0 (the bug that blanked
     the hourly-profile and people-flow sparklines), while clamp() in px always
     resolves.

     THIS DOES NOT MAKE OVERFLOW IMPOSSIBLE. 42cqi is a fraction of the whole
     row, not of the space left after the 14px gap and the legend, and at the
     108px floor the donut is as wide as it always was. A narrow card with a
     long tenant member label can still exceed the row and be clipped by
     .grid-cell — exactly as it could before this change. What the fraction buys
     is that growth is proportional, so a WIDER card never gets closer to
     overflowing than a narrow one. The legend carries `min-width: 0` so it
     absorbs the squeeze first.

     The 108px pair above stays as the fallback for engines that cannot parse
     container units — same progressive-enhancement shape as `safe center`
     above, where the SAFE value must come first.

     Floor 108px: never smaller than it shipped. Cap 200px: stops a wide but
     short tile from growing the donut past the card's height. Both numbers are
     reasoned, not measured — check in a browser before trusting them. */
  width: clamp(108px, 42cqi, 200px);
  height: clamp(108px, 42cqi, 200px);
  /* No border-radius and no mask any more: this element is now a plain box that
     a <canvas> fills, and the ring — including the 54% hole this used to cut
     with `radial-gradient(circle, transparent 54%, #000 55%)` — is drawn by
     Chart.js from the `cutout` prop. The two numbers are deliberately the same,
     so the ring keeps the weight it shipped with. */
}
.gender__legend[data-v-25d324c5] {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.gender__key[data-v-25d324c5] {
  display: grid;
  grid-template-columns: 10px 1fr auto auto;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
}
.gender__dot[data-v-25d324c5] {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  display: inline-block;
}
.gender__label[data-v-25d324c5] {
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gender__value[data-v-25d324c5] {
  color: var(--text-primary, var(--text-secondary));
  font-variant-numeric: tabular-nums;
}
.gender__pct[data-v-25d324c5] {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.gender__warn[data-v-25d324c5] {
  margin: 0;
  font-size: 0.72rem;
  color: var(--warning, #fbbf24);
}
.gender__note[data-v-25d324c5] {
  margin: 0;
  font-size: 0.72rem;
  color: var(--text-muted);
}

/* The donut is aria-hidden, so this table is the only way the numbers reach a
   screen reader. Visually hidden, NOT display:none — the latter removes it
   from the accessibility tree too, which would defeat the point. */
.sr-only[data-v-25d324c5] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.flow[data-v-c70c1093] {
  display: flex;
  flex-direction: column;
  gap: 14px;
  /* Harmless, and not depended on: the chart takes its height from
     ChartCanvas's `:height` prop, not from this chain. It was the chain being
     DEPENDED on that blanked the sparkline — see .flow__spark below. */
  height: 100%;
}
.flow__totals[data-v-c70c1093] {
  display: flex;
  gap: 18px;
}
.flow__stat[data-v-c70c1093] {
  display: flex;
  align-items: baseline;
  gap: 5px;
}
.flow__value[data-v-c70c1093] {
  font-size: 22px;
  font-weight: 600;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.flow__stat--in .flow__value[data-v-c70c1093] {
  color: var(--success);
}
.flow__stat--out .flow__value[data-v-c70c1093] {
  color: var(--info);
}
.flow__label[data-v-c70c1093] {
  font-size: 11px;
  color: var(--text-muted);
}

/*
 * THE CHART OWNS ITS HEIGHT. Still true, for a changed reason.
 *
 * Each bar used to be a PERCENTAGE of this element, and a percentage height
 * only resolves against a parent whose height is DEFINITE. This previously
 * inherited its height through `.flow { height: 100% }` up to the WidgetFrame
 * body, which is auto-height unless the card is stretched — so every bar
 * computed to 0px and the sparkline rendered blank. Measured in Chrome on that
 * CSS: 0px in an auto-height card, 180px in a definite-height one. Same defect
 * and same fix as PeopleHourlyProfileWidget; found while fixing that one.
 *
 * Chart.js runs `maintainAspectRatio: false`, so the canvas fills the box
 * ChartCanvas gives it — and ChartCanvas is handed a definite `:height` in px,
 * which is what keeps that collapse unreachable. The px lives on the PROP now;
 * this element only has to not fight it, hence `flex: 0 0 auto` rather than a
 * grow rule that would stretch the box past the canvas inside it.
 */
.flow__spark[data-v-c70c1093] {
  flex: 0 0 auto;
}

.profile[data-v-8b2fcf82] {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-height: 0;
  height: 100%;
}

/*
 * THE CHART OWNS ITS HEIGHT. Still true, for a changed reason, and still the
 * thing not to "simplify" away.
 *
 * The bars used to be percentages of this element, and a percentage height only
 * resolves against a parent whose height is DEFINITE — a WidgetFrame body is
 * auto-height, so a chain of `height: 100%` up to the card collapsed the series
 * to 0px and the widget rendered blank against a response carrying 227 entries.
 * Measured in Chrome: 0px through the inherited chain, 45px with an explicit
 * height.
 *
 * Chart.js runs `maintainAspectRatio: false`, so the canvas fills the box
 * `ChartCanvas` gives it — and `ChartCanvas` is handed a definite `:height`
 * in px, which is what keeps that same collapse unreachable. The px lives on
 * the PROP now rather than in this rule; this element only has to not fight it.
 *
 * ⚠ ONE BEHAVIOUR WAS GIVEN UP HERE, deliberately: `flex: 0 0 auto`, so the
 * chart no longer GROWS in a tall card the way `flex: 1 0 110px` let the CSS
 * bars grow. Growing it again means handing ChartCanvas a percentage height and
 * proving the percentage resolves through the flex item — which is exactly the
 * measurement no test in this repo can make (jsdom performs no layout), and
 * getting it wrong reproduces the blank card. A slightly short chart in a tall
 * tile is the cheaper mistake. Verify in a browser before changing it.
 */
.profile__chart[data-v-8b2fcf82] {
  flex: 0 0 auto;
}
.profile__note[data-v-8b2fcf82] {
  margin: 0;
  font-size: 0.7rem;
  color: var(--text-muted);
}

.cp-page[data-v-d2bb7703] {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: var(--color-bg, #0f1115);
}
.cp-card[data-v-d2bb7703] {
  width: 100%;
  max-width: 26rem;
  padding: 2rem;
  border-radius: 0.75rem;
  background: var(--color-surface, #181b22);
  border: 1px solid var(--color-border, #262a33);
}
.cp-logo[data-v-d2bb7703] { height: 2.5rem; margin-bottom: 1.25rem;
}
.cp-title[data-v-d2bb7703] { margin: 0 0 0.5rem; font-size: 1.375rem; font-weight: 600;
}
.cp-lead[data-v-d2bb7703] { margin: 0 0 1.5rem; font-size: 0.875rem; opacity: 0.75;
}
.cp-form[data-v-d2bb7703] { display: flex; flex-direction: column; gap: 1rem;
}
.cp-field[data-v-d2bb7703] { display: flex; flex-direction: column; gap: 0.375rem; font-size: 0.875rem;
}
.cp-field input[data-v-d2bb7703] {
  padding: 0.625rem 0.75rem;
  border-radius: 0.5rem;
  border: 1px solid var(--color-border, #262a33);
  background: var(--color-bg, #0f1115);
  color: inherit;
}
.cp-hint[data-v-d2bb7703] { opacity: 0.6; font-size: 0.75rem;
}
.cp-err-inline[data-v-d2bb7703], .cp-error[data-v-d2bb7703] { color: var(--color-danger, #f87171); font-size: 0.8125rem;
}
.cp-submit[data-v-d2bb7703] {
  margin-top: 0.5rem;
  padding: 0.6875rem 1rem;
  border: 0;
  border-radius: 0.5rem;
  font-weight: 600;
  cursor: pointer;
  background: var(--color-primary, #3b82f6);
  color: #fff;
}
.cp-submit[data-v-d2bb7703]:disabled { opacity: 0.5; cursor: not-allowed;
}
.cp-signout[data-v-d2bb7703] {
  margin-top: 1.25rem;
  background: none;
  border: 0;
  padding: 0;
  font-size: 0.8125rem;
  cursor: pointer;
  opacity: 0.7;
  color: inherit;
  text-decoration: underline;
}

.na-page[data-v-1700ef41] {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: var(--color-bg, #0f1115);
}
.na-card[data-v-1700ef41] {
  max-width: 30rem;
  padding: 2rem;
  text-align: center;
  border-radius: 0.75rem;
  background: var(--color-surface, #181b22);
  border: 1px solid var(--color-border, #262a33);
}
.na-title[data-v-1700ef41] { margin: 0 0 0.75rem; font-size: 1.375rem; font-weight: 600;
}
.na-body[data-v-1700ef41] { margin: 0 0 1.5rem; font-size: 0.9375rem; opacity: 0.75;
}
.na-signout[data-v-1700ef41] {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-size: 0.875rem; color: inherit; text-decoration: underline; opacity: 0.8;
}

.nf[data-v-ffb13a85] {
  padding: 3rem 1.5rem;
  text-align: center;
}
.nf-title[data-v-ffb13a85] {
  margin: 0 0 0.5rem;
  font-size: 1.25rem;
  font-weight: 600;
}
.nf-path[data-v-ffb13a85] {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.875rem;
  opacity: 0.7;
  overflow-wrap: anywhere;
}
