/* =============================================================================
   IC component primitives — additive layer over ic-theme-base.css.
   Phoenix already styles .btn / .card / .badge / .alert / .form-control /
   .table / .modal / .offcanvas. This file only adds ic-* primitives the
   legacy views rely on: ic-chip, ic-dot, ic-stat-lines, ic-page-header,
   ic-gloss-card, ic-glow-ring, ic-card-hover-glow, ic-btn-glow, ic-mono.
   ============================================================================= */

/* ---------- button sizing token overrides -------------------------------- */
/* Phoenix's .btn / .btn-lg / .btn-sm redefine button tokens at their own
   scope, which beats our :root values.  Rebind at those scopes so the tokens
   flow through to font-size / font-weight. */
.btn {
  --ic-btn-font-weight: 500;
}
.btn-lg,
.btn-group-lg > .btn {
  --ic-btn-font-size: 0.85rem;
  --ic-btn-font-weight: 500;
}
.btn-sm,
.btn-group-sm > .btn {
  --ic-btn-font-size: 0.75rem;
  --ic-btn-font-weight: 500;
}

/* ---------- page header --------------------------------------------------- */
.ic-page-header {
  padding-bottom: 0.75rem;
}
.ic-page-header h1,
.ic-page-header .ic-title {
  margin-top: 1rem;
  margin-bottom: 0.25rem;
}
.ic-page-header p {
  font-size: 13px;
  margin-bottom: 1.5rem;
}
.ic-title {
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* ---------- chip + dot (used in headers) --------------------------------- */
.ic-chip {
  display: inline-flex;
  align-items: center;
  background: color-mix(in srgb, var(--ic-primary) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--ic-primary) 25%, transparent);
  color: var(--ic-body-color, var(--bs-body-color));
  border-radius: var(--bs-border-radius-pill, 999px);
  padding: 0.35rem 0.75rem;
}
.ic-dot {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ic-neon);
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--ic-neon) 22%, transparent),
    0 0 12px var(--ic-neon);
}

/* ---------- ic-tile (subtle purple-washed chip/tile) --------------------
   Used inside cards for metric pills, progress rows, rules summaries — any
   small inset surface that needs to read as grouped content without a heavy
   border. Replaces the legacy inline `background: rgba(var(--ic-
   primary-rgb), .04)` pattern that appears across vendor / catalog / image
   cards. */
.ic-tile {
  background: color-mix(in srgb, var(--ic-purple) 4%, transparent);
  border-radius: 0.5rem;
}

/* ---------- Tom Select theming -----------------------------------------
   Align the Tom Select bootstrap5 skin with our purple-on-dark palette so
   upgraded <select>s feel like native IC form elements. */
.ts-wrapper.form-select {
  padding: 0;
  height: auto;
  min-height: calc(3.5rem + 2px);
}
.ts-wrapper .ts-control {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 1rem 0.75rem !important;
  color: var(--ic-body-color, var(--bs-body-color)) !important;
  min-height: calc(3.5rem + 2px);
}
.ts-wrapper.multi .ts-control > div {
  background: color-mix(in srgb, var(--ic-purple) 22%, transparent) !important;
  color:      color-mix(in srgb, var(--ic-purple) 70%, #fff) !important;
  border: 1px solid color-mix(in srgb, var(--ic-purple) 32%, transparent) !important;
  border-radius: 0.4rem !important;
  font-weight: 500;
}
.ts-wrapper .ts-control > input {
  color: var(--ic-purple) !important;
  caret-color: var(--ic-purple);
}
.ts-wrapper .ts-control > input::placeholder {
  color: color-mix(in srgb, var(--ic-body-color, var(--bs-body-color)) 45%, transparent);
}
.ts-dropdown {
  background: var(--ic-body-bg, var(--bs-body-bg)) !important;
  border: 1px solid var(--ic-border-color, var(--bs-border-color)) !important;
  box-shadow: 0 12px 28px rgba(0,0,0,.35), 0 0 0 1px color-mix(in srgb, var(--ic-purple) 12%, transparent) !important;
  color: var(--ic-body-color, var(--bs-body-color)) !important;
}
.ts-dropdown .option {
  color: var(--ic-body-color, var(--bs-body-color)) !important;
}
.ts-dropdown [data-selectable].option {
  font-size: 13px;
}
.ts-dropdown .option.active,
.ts-dropdown .active {
  background: color-mix(in srgb, var(--ic-purple) 22%, transparent) !important;
  color:      var(--ic-purple) !important;
}
.ts-dropdown .option:hover {
  background: color-mix(in srgb, var(--ic-purple) 14%, transparent) !important;
}
.ts-dropdown .option.selected {
  background: color-mix(in srgb, var(--ic-purple) 18%, transparent) !important;
  color:      var(--ic-purple) !important;
}

/* ---------- ic-badge-pair (two-half pill: label + value) ----------------
   Rendered as one rounded pill split into a muted "label" half on the left
   and a colored "value" half on the right. Reusable for things like
   "Vendor · Foundry Lighting", "Catalog · Test 3", "Status · Draft".

   Variants: add a hue modifier (.ic-badge-pair--purple, --info, --success,
   --warning, --danger) to tint the value half. Default is purple.

   Usage:
     <span class="ic-badge-pair">
         <span class="ic-badge-pair__label">Vendor</span>
         <span class="ic-badge-pair__value">Foundry Lighting</span>
     </span>
-------------------------------------------------------------------------- */
.ic-badge-pair {
  --ic-pair-hue: var(--ic-purple);
  display: inline-flex;
  align-items: stretch;
  border-radius: 0.4rem;
  overflow: hidden;
  font-size: 0.72rem;
  line-height: 1;
  border: 1px solid color-mix(in srgb, var(--ic-pair-hue) 22%, transparent);
  max-width: 100%;
}
.ic-badge-pair__label,
.ic-badge-pair__value {
  padding: 0.35rem 0.6rem;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  min-width: 0;
}
.ic-badge-pair__label {
  background: color-mix(in srgb, var(--ic-body-color, var(--bs-body-color)) 6%, transparent);
  color: color-mix(in srgb, var(--ic-body-color, var(--bs-body-color)) 55%, transparent);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
  font-size: 0.62rem;
  border-right: 1px solid color-mix(in srgb, var(--ic-pair-hue) 18%, transparent);
}
.ic-badge-pair__value {
  background: color-mix(in srgb, var(--ic-pair-hue) 12%, transparent);
  color: color-mix(in srgb, var(--ic-pair-hue) 75%, #fff);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Allow long values to wrap onto multiple lines instead of being clipped
     with an ellipsis. Overrides the shared `white-space: nowrap` above so
     the value half breaks naturally on word boundaries (and on long tokens
     like filenames via overflow-wrap). */
  white-space: normal;
  overflow-wrap: anywhere;
}
/* Hue variants */
.ic-badge-pair--info    { --ic-pair-hue: var(--ic-info);    }
.ic-badge-pair--success { --ic-pair-hue: var(--ic-success); }
.ic-badge-pair--warning { --ic-pair-hue: var(--ic-warning); }
.ic-badge-pair--danger  { --ic-pair-hue: var(--ic-danger);  }
.ic-badge-pair--neon    { --ic-pair-hue: var(--ic-neon);    }

/* ---------- ic-avatar-initials -------------------------------------------
   Used everywhere Bootstrap's `.avatar` + `.avatar-name` renders initials
   (catalogs, vendors, resellers, users, ftp). The Bootstrap default
   (bg-primary-subtle + text-primary-emphasis) reads as flat purple-on-purple
   in dark mode — looks like a placeholder, not a brand surface.

   This treatment overrides the Bootstrap utility background/color on the
   same element (specificity wins via `.avatar .ic-avatar-initials`). The
   surface is a soft Phoenix-purple gradient with an inset highlight on the
   top edge for that "lit from above" depth, plus a subtle outer ring.
   `GetInitials` is now capped at 2 letters so the data-length sizing only
   needs to handle 1 and 2 — kept the larger fallback rules for safety in
   case any callsite still passes longer strings.
-------------------------------------------------------------------------- */
.avatar .ic-avatar-initials {
  /* Neutral dark surface with just a hint of purple in the upper-left
     highlight. Reads as a refined card, not a brand badge. */
  background:
    radial-gradient(130% 130% at 28% 18%,
      color-mix(in srgb, var(--ic-body-bg, #0b0b1a) 60%, var(--ic-purple) 18%) 0%,
      color-mix(in srgb, var(--ic-body-bg, #0b0b1a) 78%, #000000 12%) 60%,
      color-mix(in srgb, var(--ic-body-bg, #0b0b1a) 88%, #000000 20%) 100%);
  color: #ffffff;
  font-family: var(--ic-font-sans-serif, var(--bs-body-font-family));
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  border: 1px solid color-mix(in srgb, #ffffff 10%, transparent);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #ffffff 14%, transparent),
    inset 0 -10px 18px color-mix(in srgb, #000000 22%, transparent),
    0 4px 10px rgba(0, 0, 0, 0.25);
}
/* Length-aware sizing — capped at 2 letters by GetInitials, but the 3+
   rules stay as a safety net for any legacy callsite still passing more. */
.avatar .ic-avatar-initials[data-length="1"] { font-size: 1.25rem; }
.avatar .ic-avatar-initials[data-length="2"] { font-size: 1.05rem; }
.avatar .ic-avatar-initials[data-length="3"] { font-size: 0.85rem; letter-spacing: 0.02em; }
.avatar .ic-avatar-initials[data-length="4"] { font-size: 0.72rem; letter-spacing: 0.01em; }
.avatar .ic-avatar-initials[data-length="5"],
.avatar .ic-avatar-initials[data-length="6"],
.avatar .ic-avatar-initials[data-length="7"],
.avatar .ic-avatar-initials[data-length="8"] { font-size: 0.6rem; letter-spacing: 0; }

/* Truncate modifier — lets the pill shrink below its content's intrinsic
   width when space is tight (e.g. long filenames on mobile). Without this
   the default flex `min-width: auto` pins the pill at full content width
   and `__value`'s ellipsis never activates. Opt-in so other usages keep
   their natural sizing. */
.ic-badge-pair--truncate               { min-width: 0; }
.ic-badge-pair--truncate .ic-badge-pair__label,
.ic-badge-pair--truncate .ic-badge-pair__value { min-width: 0; }

/* ---------- ic-catalog-chip (icon badge for catalog list rows) ----------
   Small rounded-square badge holding a catalog icon, purple-tinted. Sits in
   list rows (assigned-catalogs list, recent-catalog cards, etc.) alongside
   the catalog name + vendor line. */
.ic-catalog-chip,
.ic-reseller-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 0.6rem;
  background: color-mix(in srgb, var(--ic-purple) 12%, transparent);
  color: color-mix(in srgb, var(--ic-purple) 70%, #fff);
  border: 1px solid color-mix(in srgb, var(--ic-purple) 22%, transparent);
  font-size: 1rem;
}
/* Reseller chip leans slightly cyan to visually differentiate from catalog. */
.ic-reseller-chip {
  background: color-mix(in srgb, var(--ic-neon) 10%, transparent);
  color: color-mix(in srgb, var(--ic-neon) 70%, #fff);
  border-color: color-mix(in srgb, var(--ic-neon) 22%, transparent);
}

/* ---------- ic-activity-log__action (oversized badge for log table) -----
   The activity-log table uses fs-9 which squashes .ic-badge below legibility.
   This variant bumps the action badge to a readable size while inheriting
   the color from its ic-badge-{variant} sibling class. */
.ic-activity-log__action {
  font-size: 0.7rem;
  padding: 0.3rem 0.65rem;
  letter-spacing: 0.02em;
  line-height: 1.1;
}

/* ---------- ic-mono (monospace inline) ------------------------------------ */
.ic-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
}

/* Override Phoenix's default .text-primary-emphasis tint */
.text-primary-emphasis {
  color: #46577e !important;
}
.bg-primary-subtle {
  background-color: #292e3c !important;
}

/* Search input left-padding fix: Phoenix reserves room for a search icon.
   When the icon is hidden, reclaim that padding so the placeholder aligns. */
.search-box .search-input,
input.search-input {
  /* padding-left: 0.75rem !important; */
}
.search-box .search-input + .search-box-icon:not(.d-none) ~ .search-input,
.search-box:has(.search-box-icon:not(.d-none)) .search-input {
  padding-left: 2rem !important;
}

/* Filter form alignment — keep the text inside every .form-floating input
   and select flush with its label (both at 0.75rem from the left). Webkit's
   default search appearance can shift the first character right, so zero it
   out explicitly. */
.js-ic-filters .form-floating > .form-control,
.js-ic-filters .form-floating > .form-select {
  /* padding-left: .75rem !important; */
}

.js-ic-filters .form-floating > input[type="search"]::-webkit-search-decoration,
.js-ic-filters
  .form-floating
  > input[type="search"]::-webkit-search-cancel-button,
.js-ic-filters
  .form-floating
  > input[type="search"]::-webkit-search-results-button,
.js-ic-filters
  .form-floating
  > input[type="search"]::-webkit-search-results-decoration {
  -webkit-appearance: none;
  appearance: none;
}

/* Data table headers — make every .table thead row read as a clear header
   band: body-color text, bold weight, a touch more padding, and a subtle
   bottom rule. The common .text-body-secondary small on each th muted the
   columns; we override those here so the header always feels prominent. */
.table > thead > tr > th {
  color: var(--ic-body-color, var(--bs-body-color)) !important;
  font-weight: 600;
  letter-spacing: 0.04em;
  background: color-mix(in srgb, var(--ic-purple) 5%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--ic-purple) 22%, transparent);
  padding-top: 0.65rem;
  padding-bottom: 0.65rem;
}

/* Vertical column separators — every th/td gets a right border so columns
   read as discrete cells. The last cell in each row drops the border. */
.table > thead > tr > th,
.table > tbody > tr > td {
  border-right: 1px solid color-mix(in srgb, var(--ic-purple) 12%, var(--ic-border-color, var(--bs-border-color)));
  padding-left:  0.9rem;
  padding-right: 0.9rem;
}
.table > thead > tr > th:last-child,
.table > tbody > tr > td:last-child {
  border-right: 0;
}

/* Table row hover — subtle purple wash for tables marked .table-hover so
   the interaction matches the .ic-stat-lines hover treatment. */
.table-hover > tbody > tr {
  transition: background 140ms var(--ic-easing, ease);
  cursor: default;
}
.table-hover > tbody > tr:hover > * {
  --bs-table-bg-state: transparent;
  background: color-mix(in srgb, var(--ic-purple) 8%, transparent) !important;
  box-shadow: inset 0 0 0 1px
    color-mix(in srgb, var(--ic-purple) 14%, transparent);
}

/* Selected row — set when a user clicks the row (JS handler in
   ic-forms.js). Stronger purple wash + ring + purple top/bottom rails so
   the selected row stays visible after the hover tint fades. Selection is
   single-row per table. */
.table-hover > tbody > tr.is-selected > * {
  --bs-table-bg-state: transparent;
  background: color-mix(in srgb, var(--ic-purple) 20%, transparent) !important;
  box-shadow: inset 0 0 0 1px
    color-mix(in srgb, var(--ic-purple) 36%, transparent);
  color: color-mix(in srgb, var(--ic-purple) 70%, #fff);
}
.table-hover > tbody > tr.is-selected:hover > * {
  background: color-mix(in srgb, var(--ic-purple) 26%, transparent) !important;
}

/* Mirror scrollbar rendered above a `.table-responsive.ic-scroll-top`, kept
   in sync with the table's own scroll by ic-forms.js. Lets the user drag
   the horizontal scrollbar without scrolling to the bottom of a tall
   table. */
.ic-table-top-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  /* Stick just below the topbar so it's always reachable while scrolling. */
  position: sticky;
  top: var(--ic-topbar-h, 4rem);
  z-index: 3;
  background: var(--ic-body-bg, var(--bs-body-bg));
}
.ic-table-top-scroll__inner {
  height: 1px;
  /* width set to table.scrollWidth by JS */
}


/* Column-label overlay — on hover, each cell reveals its column header in a
   tiny light-weight label at the top-left so the reader never loses column
   context. The label is driven by data-label attributes set in JS
   (ic-forms.js on DOM ready) from the table's thead th text. */
.table-hover > tbody > tr > td {
  position: relative;
  padding-top: 0.9rem;
}
.table-hover > tbody > tr > td[data-label]::before {
  content: attr(data-label);
  position: absolute;
  top: 2px;
  left: 0.5rem;
  font-size: 0.58rem;
  font-weight: 300;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ic-body-color, var(--bs-body-color)) 40%, transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 140ms var(--ic-easing, ease);
}
.table-hover > tbody > tr:hover > td[data-label]::before {
  opacity: 1;
}

/* ---------- stat lines ---------------------------------------------------- */
/* ---------- select options + dropdown menu --------------------------------
   Hover / active tint mirrors the sidebar link treatment (purple 14%
   hover, purple 22% active with the purple text color) so every menu-like
   surface reads as the same interaction. */
select.form-select option,
select.form-control option {
  background-color: var(--ic-body-bg, var(--bs-body-bg));
  color: var(--ic-body-color, var(--bs-body-color));
}
select.form-select option:hover,
select.form-control option:hover {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 22%,
    var(--ic-body-bg, var(--bs-body-bg))
  ) !important;
  color: var(--ic-purple) !important;
}
select.form-select option:checked,
select.form-control option:checked {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 22%,
    var(--ic-body-bg, var(--bs-body-bg))
  ) !important;
  color: var(--ic-purple) !important;
  font-weight: 600;
}

/* Bootstrap/Phoenix .dropdown-menu items — match the sidebar hover exactly. */
.dropdown-item:hover,
.dropdown-item:focus {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 22%,
    transparent
  ) !important;
  color: var(--ic-purple) !important;
}
.dropdown-item.active,
.dropdown-item:active {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 22%,
    transparent
  ) !important;
  color: var(--ic-purple) !important;
  font-weight: 600;
}

.ic-stat-lines {
  display: grid;
  gap: 0.25rem;
}
.ic-stat-lines > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4rem 0.5rem;
  border-radius: 0.5rem;
  border-bottom: 1px dashed var(--ic-border-color, rgba(255, 255, 255, 0.08));
  transition:
    background 140ms var(--ic-easing, ease),
    box-shadow 140ms var(--ic-easing, ease);
}
.ic-stat-lines > div:hover {
  background: color-mix(in srgb, var(--ic-purple) 8%, transparent);
  box-shadow: inset 0 0 0 1px
    color-mix(in srgb, var(--ic-purple) 18%, transparent);
  border-bottom-color: transparent;
}
.ic-stat-lines > div:last-child {
  border-bottom: 0;
}
.ic-stat-line-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(
    --ic-text-tertiary,
    var(--ic-secondary-color, var(--bs-secondary-color))
  );
  min-width: 5rem;
}

/* ---------- glossy / glow-ring cards -------------------------------------- */
.ic-glow-ring {
  box-shadow:
    var(--ic-glow-ring), var(--bs-box-shadow, 0 8px 24px rgba(0, 0, 0, 0.15));
}
/* Gloss card — soft pastel wash, very light sheen. No hard border or glow.
   The tinted variants shift the whole surface toward a pastel of the hue. */
.ic-gloss-card {
  position: relative;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.02) 0%,
    rgba(255, 255, 255, 0) 100%
  );
}
.ic-gloss-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 45%;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent);
  pointer-events: none;
  z-index: 0;
  opacity: 0.7;
}
.ic-gloss-card::after {
  content: none;
}
.ic-gloss-card > * {
  position: relative;
  z-index: 1;
}

/* Ultra-transparent glass variants — thin hue border, barely-there fill,
   no heavy shadow; the body bg shows through almost fully. */
.ic-gloss-card--info,
.ic-gloss-card--success,
.ic-gloss-card--warning,
.ic-gloss-card--danger {
  background: transparent;
  border-radius: inherit;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  box-shadow: none;
}
.ic-gloss-card--info {
  --ic-glow: var(--ic-info);
  background-color: color-mix(in srgb, var(--ic-info) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--ic-info) 32%, transparent);
}
.ic-gloss-card--success {
  --ic-glow: var(--ic-success);
  background-color: color-mix(in srgb, var(--ic-success) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--ic-success) 32%, transparent);
}
.ic-gloss-card--warning {
  --ic-glow: var(--ic-warning);
  background-color: color-mix(in srgb, var(--ic-warning) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--ic-warning) 32%, transparent);
}
.ic-gloss-card--danger {
  --ic-glow: var(--ic-danger);
  background-color: color-mix(in srgb, var(--ic-danger) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--ic-danger) 32%, transparent);
}

.ic-card-hover-glow {
  transition:
    transform var(--ic-motion) var(--ic-easing),
    box-shadow var(--ic-motion) var(--ic-easing),
    border-color var(--ic-motion) var(--ic-easing);
  border: 1px solid color-mix(in srgb, var(--ic-glow) 16%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ic-glow) 10%, transparent),
    0 6px 18px color-mix(in srgb, var(--ic-glow) 10%, transparent);
}
.ic-card-hover-glow:hover {
  border-color: color-mix(in srgb, var(--ic-glow) 38%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ic-glow) 22%, transparent),
    0 14px 34px color-mix(in srgb, var(--ic-glow) 18%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

/* When .ic-card-hover-glow wraps a hue variant (or is itself one), rebind
   --ic-glow at the glow element so its border/shadow layers tint correctly.
   Covers both same-element composition and parent-containing-child markup. */
.ic-card-hover-glow.ic-gloss-card--info,
.ic-card-hover-glow:has(.ic-gloss-card--info),
.ic-card-hover-glow:has(.alert-subtle-info),
.ic-card-hover-glow:has(.ic-alert-info) {
  --ic-glow: var(--ic-info);
}
.ic-card-hover-glow.ic-gloss-card--success,
.ic-card-hover-glow:has(.ic-gloss-card--success),
.ic-card-hover-glow:has(.alert-subtle-success),
.ic-card-hover-glow:has(.ic-alert-success) {
  --ic-glow: var(--ic-success);
}
.ic-card-hover-glow.ic-gloss-card--warning,
.ic-card-hover-glow:has(.ic-gloss-card--warning),
.ic-card-hover-glow:has(.alert-subtle-warning),
.ic-card-hover-glow:has(.ic-alert-warning) {
  --ic-glow: var(--ic-warning);
}
.ic-card-hover-glow.ic-gloss-card--danger,
.ic-card-hover-glow:has(.ic-gloss-card--danger),
.ic-card-hover-glow:has(.alert-subtle-danger),
.ic-card-hover-glow:has(.ic-alert-danger) {
  --ic-glow: var(--ic-danger);
}

/* ---------- button glow adornments (kept subtle) -------------------------- */
.ic-btn-glow {
  box-shadow: var(--ic-glow-ring);
}
.ic-btn-soft {
  background: color-mix(
    in srgb,
    var(--ic-body-color, var(--bs-body-color)) 5%,
    transparent
  ) !important;
  border-color: var(--ic-border-color, var(--bs-border-color)) !important;
  color: var(--ic-body-color, var(--bs-body-color)) !important;
}
.ic-btn-primary-glow {
  box-shadow: 0 4px 14px color-mix(in srgb, var(--ic-primary) 18%, transparent);
}

/* Tame the default Phoenix hover lift — same direction, less intensity */
.btn-subtle-primary:hover,
.btn-primary:hover {
  box-shadow: 0 3px 10px color-mix(in srgb, var(--ic-primary) 16%, transparent);
}
/* btn-subtle-secondary — faint purple tint to match the filter hero bg. */
.btn-subtle-secondary,
.btn-subtle-secondary:visited {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 10%,
    transparent
  ) !important;
  border-color: color-mix(
    in srgb,
    var(--ic-purple) 18%,
    transparent
  ) !important;
  color: color-mix(in srgb, var(--ic-purple) 75%, #000) !important;
}
.btn-subtle-secondary:hover,
.btn-subtle-secondary:focus {
  background-color: color-mix(
    in srgb,
    var(--ic-purple) 18%,
    transparent
  ) !important;
  border-color: color-mix(
    in srgb,
    var(--ic-purple) 32%,
    transparent
  ) !important;
  color: var(--ic-purple) !important;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--ic-purple) 16%, transparent);
}

/* btn-subtle-primary text override — the Phoenix default reads too washed.
   Tint the surface a bit stronger and use the solid primary color for the
   label so contrast is clear on both light and dark backgrounds. */
.btn-subtle-primary,
.btn-subtle-primary:visited {
  background-color: color-mix(
    in srgb,
    var(--ic-primary) 14%,
    transparent
  ) !important;
  border-color: color-mix(
    in srgb,
    var(--ic-primary) 26%,
    transparent
  ) !important;
  color: var(--ic-primary) !important;
}
.btn-subtle-primary:hover,
.btn-subtle-primary:focus {
  background-color: color-mix(
    in srgb,
    var(--ic-primary) 22%,
    transparent
  ) !important;
  border-color: color-mix(
    in srgb,
    var(--ic-primary) 45%,
    transparent
  ) !important;
  color: var(--ic-primary) !important;
}
[data-bs-theme="dark"] .btn-subtle-primary,
[data-bs-theme="dark"] .btn-subtle-primary:visited {
  color: color-mix(in srgb, var(--ic-primary) 60%, #ffffff 40%) !important;
}
[data-bs-theme="dark"] .btn-subtle-primary:hover,
[data-bs-theme="dark"] .btn-subtle-primary:focus {
  color: #ffffff !important;
}

/* btn-ic-primary — solid purple CTA aligned with the app's theme.
   Use on prominent actions (auth submits, key confirmations). */
.btn-ic-primary,
.btn-ic-primary:visited {
  position: relative;
  isolation: isolate;
  background: color-mix(in srgb, var(--ic-purple) 6%, transparent) !important;
  border: 1px solid color-mix(in srgb, var(--ic-purple) 45%, transparent) !important;
  color: var(--ic-purple) !important;
  letter-spacing: 0.01em;
  -webkit-backdrop-filter: blur(14px) saturate(180%);
  backdrop-filter: blur(14px) saturate(180%);
  box-shadow: none;
  transition:
    background 180ms var(--ic-easing, ease),
    border-color 180ms var(--ic-easing, ease),
    color 180ms var(--ic-easing, ease);
}

.btn-ic-primary:hover,
.btn-ic-primary:focus {
  background: color-mix(in srgb, var(--ic-purple) 12%, transparent) !important;
  border-color: color-mix(
    in srgb,
    var(--ic-purple) 65%,
    transparent
  ) !important;
  color: color-mix(in srgb, var(--ic-purple) 70%, #fff) !important;
  box-shadow: none;
}
.btn-ic-primary:active {
  background: color-mix(in srgb, var(--ic-purple) 18%, transparent) !important;
}
.btn-ic-primary:disabled,
.btn-ic-primary.disabled {
  opacity: 0.55;
  box-shadow: none;
}

/* ---------- ic-hero: pastel filter card (warm neutral, not blue) --------- */
.ic-hero {
  background: linear-gradient(
    180deg,
    color-mix(
        in srgb,
        var(--ic-purple) 7%,
        var(--ic-body-bg, var(--bs-body-bg))
      )
      0%,
    color-mix(
        in srgb,
        var(--ic-purple) 2%,
        var(--ic-body-bg, var(--bs-body-bg))
      )
      100%
  );
  border: 1px solid color-mix(in srgb, var(--ic-purple) 14%, transparent);
  border-radius: 1rem;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
.ic-hero::before,
.ic-hero::after {
  content: none;
}

/* ic-glow-ring on a filter/hero card is gentle and matches the purple tint */
.ic-hero.ic-glow-ring {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ic-purple) 18%, transparent),
    0 4px 14px color-mix(in srgb, var(--ic-purple) 10%, transparent);
}

/* ---------- filter card always margined from surrounding content --------- */
.js-ic-filters {
  margin-top: 1rem;
  margin-bottom: 1rem;
  display: block;
}
.js-ic-filters > .card {
  margin: 0 !important;
}
.js-ic-filters + * {
  margin-top: 1rem;
}
* + .js-ic-filters {
  margin-top: 1rem;
}

/* ---------- alert gets a gentle colored aura ----------------------------- */
.alert-subtle-info,
.ic-alert-info {
  --ic-glow: var(--ic-info);
  box-shadow: 0 0 8px color-mix(in srgb, var(--ic-info) 10%, transparent);
}
.alert-subtle-success,
.ic-alert-success {
  --ic-glow: var(--ic-success);
  box-shadow: 0 0 8px color-mix(in srgb, var(--ic-success) 10%, transparent);
}
.alert-subtle-warning,
.ic-alert-warning {
  --ic-glow: var(--ic-warning);
  box-shadow: 0 0 8px color-mix(in srgb, var(--ic-warning) 12%, transparent);
}
.alert-subtle-danger,
.ic-alert-danger {
  --ic-glow: var(--ic-danger);
  box-shadow: 0 0 8px color-mix(in srgb, var(--ic-danger) 12%, transparent);
}

/* ---------- alert titles get a darker cut of the variant color ----------- */
/* The bold first line of an alert renders in the same variant color as the
   body copy, so titles wash out on the subtle backgrounds. Darkening the
   variant color (currentColor) keeps the title unmistakably in the alert's
   hue family — deeper amber on warning, deeper rust in light mode — instead
   of drifting toward white/black like an emphasis-color blend would.
   Explicit color utilities inside alerts (.text-body etc.) still win —
   Bootstrap utilities are !important. */
.alert .fw-semibold,
.alert .alert-heading {
  color: color-mix(in srgb, currentColor 75%, #000 25%);
}

/* Hue-tinted subtle buttons — rebind --ic-glow so .ic-card-hover-glow or any
   composed glow utility picks up the button's own color. */
.btn-subtle-info,
.ic-btn-info {
  --ic-glow: var(--ic-info);
}
.btn-subtle-success,
.ic-btn-success {
  --ic-glow: var(--ic-success);
}
.btn-subtle-warning,
.ic-btn-warning {
  --ic-glow: var(--ic-warning);
}
.btn-subtle-danger,
.ic-btn-danger {
  --ic-glow: var(--ic-danger);
}

/* ---------- modal box-shadow border — subtle neon halo, not full bloom -----
   Applies to every Bootstrap modal in the app (alert popup, leave-confirm,
   any future themed modal). The 1px inset glow doubles as a border so we
   don't have to maintain a separate border rule per modal type. --ic-glow
   defaults to var(--ic-neon) but variant modifiers (e.g. text-warning on the
   header) can shift the hue without touching this rule. */
.modal-content {
  /* Phoenix's default --ic-modal-border-radius is 0.375rem (6px), which
     reads as square next to the app's 8-12px card/drawer radii. Bump to
     0.75rem so modals feel like they belong in the same family as the
     surrounding UI, and override the inner-border-radius the same way so
     the header/footer corners don't look clipped. */
  --ic-modal-border-radius: 0.75rem;
  --ic-modal-inner-border-radius: calc(0.75rem - var(--ic-border-width));
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ic-glow) 25%, transparent),
    0 0 18px color-mix(in srgb, var(--ic-glow) 18%, transparent),
    0 16px 40px rgba(0, 0, 0, 0.35);
}

/* =============================================================================
   Topbar activity feed — bell dropdown in nav-top, timeline-style list.
   ============================================================================= */
.ic-topbar-activity-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  color: var(--ic-body-color, var(--bs-body-color));
  transition: background-color var(--ic-motion) var(--ic-easing),
              box-shadow var(--ic-motion) var(--ic-easing);
}
.ic-topbar-activity-toggle:hover,
.ic-topbar-activity-toggle:focus-visible {
  background: color-mix(in srgb, var(--ic-purple) 12%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--ic-purple) 22%, transparent);
  color: var(--ic-purple);
}
.ic-topbar-activity-toggle__badge {
  position: absolute;
  top: 0.3rem;
  right: 0.35rem;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--ic-danger);
  box-shadow: 0 0 0 2px var(--ic-body-bg, var(--bs-body-bg));
}

.ic-topbar-activity-card {
  min-width: 26rem;
  max-width: 30rem;
}
.ic-topbar-activity-scroll {
  max-height: 24rem;
  overflow-y: auto;
}

.ic-topbar-activity-list {
  display: grid;
  gap: 0.5rem;
}
.ic-topbar-activity-item {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.75rem 0.85rem;
  border-radius: 0.75rem;
  border: 1px solid var(--ic-border-color-translucent);
  background: color-mix(in srgb, var(--ic-body-color) 8%, var(--ic-body-bg));
  color: inherit;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, transform 0.15s ease-in-out;
}
.ic-topbar-activity-item:hover,
.ic-topbar-activity-item:focus-within {
  background: color-mix(in srgb, var(--ic-body-color) 14%, var(--ic-body-bg));
  border-color: var(--ic-border-color);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
  transform: translateY(-1px);
}

.ic-topbar-activity-icon {
  flex: 0 0 auto;
  width: 2.1rem;
  height: 2.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  font-size: 0.85rem;
}
.ic-topbar-activity-chip--success  { background: color-mix(in srgb, var(--ic-success) 15%, transparent); color: var(--ic-success); }
.ic-topbar-activity-chip--info     { background: color-mix(in srgb, var(--ic-info) 15%, transparent);    color: var(--ic-info); }
.ic-topbar-activity-chip--warning  { background: color-mix(in srgb, var(--ic-warning) 18%, transparent); color: var(--ic-warning); }
.ic-topbar-activity-chip--primary  { background: color-mix(in srgb, var(--ic-purple) 15%, transparent);  color: var(--ic-purple); }
.ic-topbar-activity-chip--secondary{ background: color-mix(in srgb, var(--ic-body-color, var(--bs-body-color)) 10%, transparent); color: var(--ic-secondary-color, var(--bs-secondary-color)); }

/* Chip variant (small pill) reuses the same color tokens via the shared class */
.ic-topbar-activity-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
  flex: 0 0 auto;
}

.ic-topbar-activity-copy {
  min-width: 0;
  display: grid;
  gap: 0.35rem;
  flex: 1 1 auto;
}
.ic-topbar-activity-copy > .ic-badge-pair {
  display: inline-flex;
  width: fit-content;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
}
.ic-topbar-activity-copy > .ic-badge-pair > .ic-badge-pair__label {
  flex: 0 0 auto;
}
.ic-topbar-activity-copy > .ic-badge-pair > .ic-badge-pair__value {
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ic-topbar-activity-headline {
  font-weight: 600;
  font-size: 0.88rem;
  line-height: 1.3;
  color: var(--ic-emphasis-color, var(--ic-body-color));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 0.1rem;
}
.ic-topbar-activity-title-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
.ic-topbar-activity-title {
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.35;
  color: var(--ic-emphasis-color, var(--ic-body-color));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.ic-topbar-activity-meta {
  display: block;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--ic-secondary-color, var(--bs-secondary-color));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ic-topbar-activity-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.15rem;
  min-width: 0;
}
.ic-topbar-activity-time {
  flex: 0 0 auto;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--ic-secondary-color, var(--bs-secondary-color));
  padding-top: 0.2rem;
  text-align: right;
  min-width: 2.5rem;
}

.ic-topbar-activity-empty {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 0.85rem;
  border-radius: 0.75rem;
  background: color-mix(in srgb, var(--ic-body-bg, var(--bs-body-bg)) 94%, transparent);
  border: 1px dashed var(--ic-border-color-translucent);
}

/* ---------- ic-filter-pill (clickable badge-pair as toggle filter) -------
   Renders the existing .ic-badge-pair as a clickable button. Used for the
   Map Columns toolbar filters (Blank groups / Blank values / Unmapped) and
   anywhere else a count+label pill should toggle a list filter on/off.

   Off state: outlined pill, value-half lightly tinted (inherits from
   .ic-badge-pair--<hue>). On state (aria-pressed=true): both halves
   saturated, brighter border + soft glow so it reads as 'this filter is
   active right now'.

   Usage:
     <button type='button' class='ic-badge-pair ic-badge-pair--warning
                                  ic-filter-pill' aria-pressed='false'>
         <span class='ic-badge-pair__label'>Blank groups</span>
         <span class='ic-badge-pair__value'>12</span>
     </button>
-------------------------------------------------------------------------- */
.ic-filter-pill {
  cursor: pointer;
  background: transparent;
  padding: 0;
  font-family: inherit;
  font-size: 0.72rem;
  transition:
    border-color var(--ic-motion, 160ms) var(--ic-easing, ease),
    box-shadow var(--ic-motion, 160ms) var(--ic-easing, ease),
    transform var(--ic-motion, 160ms) var(--ic-easing, ease);
}
.ic-filter-pill:hover {
  border-color: color-mix(in srgb, var(--ic-pair-hue) 45%, transparent);
}
.ic-filter-pill:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ic-pair-hue) 25%, transparent);
}
.ic-filter-pill[aria-pressed='true'] {
  border-color: color-mix(in srgb, var(--ic-pair-hue) 70%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ic-pair-hue) 35%, transparent),
    0 4px 12px color-mix(in srgb, var(--ic-pair-hue) 18%, transparent);
}
.ic-filter-pill[aria-pressed='true'] .ic-badge-pair__label {
  background: color-mix(in srgb, var(--ic-pair-hue) 14%, transparent);
  color: color-mix(in srgb, var(--ic-pair-hue) 80%, #fff);
}
.ic-filter-pill[aria-pressed='true'] .ic-badge-pair__value {
  background: color-mix(in srgb, var(--ic-pair-hue) 28%, transparent);
  color: color-mix(in srgb, var(--ic-pair-hue) 92%, #fff);
}
/* Zero-count state: gently muted so a filter that would show nothing
   reads as inert but stays clearly interactive. Click still works in
   case the customer wants to confirm. */
.ic-filter-pill[data-count='0'] {
  opacity: 0.8;
}

