/*
 * Lens visual system: controls (owner: lane V1c).
 *
 * Buttons, links, fields, the tom-select theme, the segmented control, tabs, the filter bar,
 * pagination, the modal and the toast, on the tokens of system/tokens.css only.
 * Contract: docs/web/visual-system-contract.md §4 items 1–10; every state is drawn in /design
 * (templates/design/controls.html).
 *
 * It styles the system's compounds (.btn.btn-primary, .lens-field .form-control, .lens-pager
 * .pagination, .lens-modal .modal-content), never a bare Bootstrap selector that base.css's remap
 * also styles (VisualSystemNetsTest (d)).
 */

/* ------------------------------------------------------------------ 1. buttons */

/* One filled primary per working area; secondary is outlined and neutral; quiet is text-like;
   danger is outlined, and solid only for a modal's confirm. A button with a shortcut declares it in
   aria-keyshortcuts, and lens-keys.js draws it as a key cap (below). */
.btn:is(.btn-primary, .btn-secondary, .btn-quiet, .btn-danger, .btn-danger-solid) {
  --bs-btn-font-family: var(--lens-font-ui);
  --bs-btn-font-size: var(--lens-fs-body);
  --bs-btn-font-weight: var(--lens-fw-medium);
  --bs-btn-line-height: 1.4;
  --bs-btn-padding-x: var(--lens-sp-3);
  --bs-btn-padding-y: 7px;
  --bs-btn-border-width: 1px;
  --bs-btn-border-radius: var(--lens-r-m);
  --bs-btn-box-shadow: none;
  --bs-btn-disabled-opacity: 0.5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--lens-sp-2);
  white-space: nowrap;
  transition: background-color var(--lens-duration) var(--lens-ease),
    border-color var(--lens-duration) var(--lens-ease), color var(--lens-duration) var(--lens-ease);
}

.btn.btn-sm:is(.btn-primary, .btn-secondary, .btn-quiet, .btn-danger, .btn-danger-solid) {
  --bs-btn-font-size: var(--lens-fs-meta);
  --bs-btn-padding-x: var(--lens-sp-2);
  --bs-btn-padding-y: 3px;
  --bs-btn-border-radius: var(--lens-r-s);
  gap: var(--lens-sp-1);
}

.btn:is(.btn-primary, .btn-secondary, .btn-quiet, .btn-danger, .btn-danger-solid):focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 2px;
  box-shadow: none;
}

.btn.btn-primary {
  --bs-btn-color: var(--lens-text-inverse);
  --bs-btn-bg: var(--lens-primary);
  --bs-btn-border-color: var(--lens-primary);
  --bs-btn-hover-color: var(--lens-text-inverse);
  --bs-btn-hover-bg: var(--lens-primary-hover);
  --bs-btn-hover-border-color: var(--lens-primary-hover);
  --bs-btn-active-color: var(--lens-text-inverse);
  --bs-btn-active-bg: var(--lens-primary-hover);
  --bs-btn-active-border-color: var(--lens-primary-hover);
  --bs-btn-disabled-color: var(--lens-text-inverse);
  --bs-btn-disabled-bg: var(--lens-primary);
  --bs-btn-disabled-border-color: var(--lens-primary);
}

.btn.btn-secondary {
  --bs-btn-color: var(--lens-text);
  --bs-btn-bg: var(--lens-surface);
  --bs-btn-border-color: var(--lens-border-strong);
  --bs-btn-hover-color: var(--lens-heading);
  --bs-btn-hover-bg: var(--lens-hover);
  --bs-btn-hover-border-color: var(--lens-border-strong);
  --bs-btn-active-color: var(--lens-heading);
  --bs-btn-active-bg: var(--lens-selected);
  --bs-btn-active-border-color: var(--lens-border-strong);
  --bs-btn-disabled-color: var(--lens-text-muted);
  --bs-btn-disabled-bg: var(--lens-surface);
  --bs-btn-disabled-border-color: var(--lens-border);
}

.btn.btn-quiet {
  --bs-btn-color: var(--lens-text);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-color: var(--lens-heading);
  --bs-btn-hover-bg: var(--lens-hover);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-color: var(--lens-heading);
  --bs-btn-active-bg: var(--lens-selected);
  --bs-btn-active-border-color: transparent;
  --bs-btn-disabled-color: var(--lens-text-muted);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: transparent;
}

.btn.btn-danger {
  --bs-btn-color: var(--lens-action-ink);
  --bs-btn-bg: var(--lens-surface);
  --bs-btn-border-color: var(--lens-action);
  --bs-btn-hover-color: var(--lens-action-ink);
  --bs-btn-hover-bg: var(--lens-action-bg);
  --bs-btn-hover-border-color: var(--lens-action);
  --bs-btn-active-color: var(--lens-action-ink);
  --bs-btn-active-bg: var(--lens-action-bg);
  --bs-btn-active-border-color: var(--lens-action);
  --bs-btn-disabled-color: var(--lens-action-ink);
  --bs-btn-disabled-bg: var(--lens-surface);
  --bs-btn-disabled-border-color: var(--lens-action);
}

.btn.btn-danger-solid {
  --bs-btn-color: var(--lens-text-inverse);
  --bs-btn-bg: var(--lens-action-ink);
  --bs-btn-border-color: var(--lens-action-ink);
  --bs-btn-hover-color: var(--lens-text-inverse);
  --bs-btn-hover-bg: var(--lens-action);
  --bs-btn-hover-border-color: var(--lens-action);
  --bs-btn-active-color: var(--lens-text-inverse);
  --bs-btn-active-bg: var(--lens-action);
  --bs-btn-active-border-color: var(--lens-action);
  --bs-btn-disabled-color: var(--lens-text-inverse);
  --bs-btn-disabled-bg: var(--lens-action-ink);
  --bs-btn-disabled-border-color: var(--lens-action-ink);
}

/* A row of actions: the primary last, wrapping on a phone rather than pushing the page. */
.lens-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--lens-sp-2);
}

/* The shortcut's key cap (owner decision K2, 8 October 2026), drawn by lens-keys.js from the
   button's own aria-keyshortcuts: a soft fill of the button's own colour, so it reads on a filled
   primary and an outlined secondary alike, in both themes. In a menu it sits on the right. Hidden
   where there is no keyboard. */
.lens-key {
  display: inline-block;
  margin-left: var(--lens-sp-1);
  padding: 2px 6px;
  border-radius: var(--lens-r-s);
  background: color-mix(in srgb, currentColor 16%, transparent);
  box-shadow: none;
  color: inherit;
  font-family: var(--lens-font-mono);
  font-size: var(--lens-fs-key);
  font-weight: var(--lens-fw-medium);
  line-height: 1.2;
  letter-spacing: 0;
}
.btn .lens-key { margin-left: 0; }
.dropdown-item:has(.lens-key) {
  display: flex;
  align-items: center;
  gap: var(--lens-sp-2);
}
.dropdown-item .lens-key {
  margin-left: auto;
  color: var(--lens-text-muted);
}
@media (hover: none) and (pointer: coarse) {
  .lens-key { display: none; }
}

/* ------------------------------------------------------------------ 2. links */

/* One link colour everywhere. Bootstrap's `a` reads --bs-link-color; these rules only set the
   properties, so they never compete with a component's own link colour. */
:root {
  --bs-link-color: var(--lens-link);
  --bs-link-hover-color: var(--lens-link-hover);
}

a:hover {
  --bs-link-color: var(--lens-link-hover);
}

/* The contextual link beside a problem (D4): verb first, a trailing arrow drawn here. */
a.lens-go {
  color: var(--lens-link);
  font-weight: var(--lens-fw-medium);
  text-decoration: none;
  white-space: nowrap;
}

a.lens-go::after {
  content: "\2192" / "";
  display: inline-block;
  margin-left: var(--lens-sp-1);
  transition: transform var(--lens-duration) var(--lens-ease);
}

a.lens-go:hover {
  color: var(--lens-link-hover);
  text-decoration: underline;
}

a.lens-go:hover::after {
  transform: translateX(2px);
}

a.lens-go:focus-visible,
.lens-toast__action:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 2px;
  border-radius: var(--lens-r-s);
}

/* ------------------------------------------------------------------ 3. field and fieldset */

/* Label above, always; help and error below. */
.lens-field {
  display: flex;
  flex-direction: column;
  gap: var(--lens-sp-1);
  min-width: 0;
  margin: 0;
}

.lens-field__label {
  margin: 0;
  color: var(--lens-text);
  font-size: var(--lens-fs-meta);
  font-weight: var(--lens-fw-medium);
  line-height: 1.4;
}

/* The required mark: decoration only (alt text ""); the control's `required` is what is said. */
.lens-field--required .lens-field__label::after {
  content: "*" / "";
  margin-left: 2px;
  color: var(--lens-action-ink);
}

.lens-field__help,
.lens-field__error {
  margin: 0;
  font-size: var(--lens-fs-meta);
  line-height: 1.4;
}

.lens-field__help {
  color: var(--lens-text-muted);
}

.lens-field__error {
  display: flex;
  gap: var(--lens-sp-1);
  color: var(--lens-action-ink);
}

.lens-field__error::before {
  content: "\f333" / "";
  font-family: bootstrap-icons;
  line-height: 1.4;
}

.lens-field__error:empty {
  display: none;
}

.lens-field :is(.form-control, .form-select, select.lens-select:not(.tomselected)) {
  min-height: 36px;
  border: 1px solid var(--lens-border-strong);
  border-radius: var(--lens-r-m);
  background-color: var(--lens-surface);
  color: var(--lens-text);
  font-family: var(--lens-font-ui);
  font-size: var(--lens-fs-body);
}

.lens-field :is(.form-control, .form-select)::placeholder {
  color: var(--lens-text-muted);
  opacity: 1;
}

.lens-field :is(.form-control, .form-select):focus {
  border-color: var(--lens-focus);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lens-focus) 35%, transparent);
  outline: 0;
}

.lens-field :is(.form-control, .form-select):disabled {
  border-color: var(--lens-border);
  background-color: var(--lens-surface-subtle);
  color: var(--lens-text-muted);
  cursor: not-allowed;
}

/* As specific as the field's own rule above (its :is() counts select.lens-select:not(.tomselected)),
   and later, so the error border wins. */
.lens-field--error :is(.form-control, .form-select, select.lens-select:not(.tomselected)),
.lens-field--error .ts-wrapper.lens-select .ts-control,
.lens-field :is(.form-control, .form-select, select.lens-select:not(.tomselected))[aria-invalid="true"] {
  border-color: var(--lens-action-ink);
}

/* A group of fields, with its legend as a quiet object title. */
fieldset.lens-fieldset {
  display: grid;
  gap: var(--lens-sp-4);
  min-width: 0;
  margin: 0 0 var(--lens-sp-5);
  padding: 0;
  border: 0;
}

fieldset.lens-fieldset > legend {
  float: none;
  width: auto;
  margin: 0 0 var(--lens-sp-1);
  padding: 0;
  color: var(--lens-heading);
  font-size: var(--lens-fs-object);
  font-weight: var(--lens-fw-strong);
  line-height: 1.4;
}

fieldset.lens-fieldset:disabled .lens-field__label {
  color: var(--lens-text-muted);
}

/* ------------------------------------------------------------------ 4. select (tom-select) */

/* Home and Analyze share the location field, including its width while focused/searching. */
.lens-location-select { width: 220px; max-width: 100%; }
.lens-location-select .lens-select { width: 100%; min-width: 0; }
@media (max-width: 640px) {
  .lens-location-select { width: 100%; }
}

/* Every select is select.lens-select (S4); js/lens-select.js turns it into tom-select. Before it
   does (or without script) the native select already looks like a field. */
select.lens-select:not(.tomselected) {
  width: 100%;
  padding: 6px var(--lens-sp-3);
  border: 1px solid var(--lens-border-strong);
  border-radius: var(--lens-r-m);
  background-color: var(--lens-surface);
  color: var(--lens-text);
  font-size: var(--lens-fs-body);
}

.ts-wrapper.lens-select {
  min-height: 36px;
  font-family: var(--lens-font-ui);
  font-size: var(--lens-fs-body);
}

.ts-wrapper.lens-select .ts-control {
  min-height: 36px;
  padding: 5px var(--lens-sp-3);
  border: 1px solid var(--lens-border-strong);
  border-radius: var(--lens-r-m);
  background: var(--lens-surface);
  color: var(--lens-text);
  font-size: var(--lens-fs-body);
  line-height: 1.5;
  box-shadow: none;
}

.ts-wrapper.lens-select .ts-control > input {
  color: var(--lens-text);
  font-size: var(--lens-fs-body);
}

.ts-wrapper.lens-select .ts-control > input::placeholder {
  color: var(--lens-text-muted);
  opacity: 1;
}

.ts-wrapper.lens-select:not(.disabled) .ts-control:hover {
  border-color: var(--lens-text-muted);
}

.ts-wrapper.lens-select.focus .ts-control {
  border-color: var(--lens-focus);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--lens-focus) 35%, transparent);
  outline: 0;
}

.ts-wrapper.lens-select.disabled .ts-control {
  border-color: var(--lens-border);
  background: var(--lens-surface-subtle);
  color: var(--lens-text-muted);
  opacity: 1;
}

/* A single value stays on one line in every scope, including Analyze and Home. Reserve the
   caret's space; the vendor's search input must not push a long value onto another line. */
.ts-wrapper.lens-select.single .ts-control {
  height: 36px;
  flex-wrap: nowrap;
  padding-right: var(--lens-sp-6);
}

.ts-wrapper.lens-select.single .ts-control > .item {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ts-wrapper.lens-select.single .ts-control > input {
  min-width: 0;
}

/* The single select's caret, drawn in the text's colour rather than the vendor's dark image. */
.ts-wrapper.lens-select.single .ts-control {
  background-image: none;
}

.ts-wrapper.lens-select.single::after {
  content: "";
  position: absolute;
  top: 50%;
  right: var(--lens-sp-3);
  z-index: 2;
  width: 7px;
  height: 7px;
  margin-top: -6px;
  border-right: 1.5px solid var(--lens-text-muted);
  border-bottom: 1.5px solid var(--lens-text-muted);
  transform: rotate(45deg);
  pointer-events: none;
}

.ts-wrapper.lens-select.single.dropdown-active::after {
  margin-top: -2px;
  transform: rotate(225deg);
}

/* Multiple: each value a removable chip. */
.ts-wrapper.lens-select.multi.has-items .ts-control {
  padding: 4px var(--lens-sp-2);
  gap: var(--lens-sp-1);
}

.ts-wrapper.lens-select.multi .ts-control > .item {
  margin: 0;
  padding: 1px var(--lens-sp-2);
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-pill);
  background: var(--lens-surface-subtle);
  color: var(--lens-text);
  font-size: var(--lens-fs-meta);
  line-height: 1.5;
}

.ts-wrapper.lens-select.multi .ts-control > .item.active {
  border-color: var(--lens-focus);
  background: var(--lens-selected);
  color: var(--lens-heading);
}

.ts-wrapper.lens-select.multi.disabled .ts-control > .item {
  border-color: var(--lens-border);
  background: var(--lens-surface);
  color: var(--lens-text-muted);
}

.ts-wrapper.lens-select.plugin-remove_button .item .remove {
  margin-left: var(--lens-sp-1);
  padding: 0 var(--lens-sp-1);
  border-left: 1px solid var(--lens-border);
  border-radius: 0 var(--lens-r-pill) var(--lens-r-pill) 0;
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-body);
  line-height: 1;
}

.ts-wrapper.lens-select.plugin-remove_button .item .remove:hover {
  background: var(--lens-hover);
  color: var(--lens-action-ink);
}

.ts-wrapper.lens-select.plugin-remove_button .item.active .remove {
  border-left-color: var(--lens-focus);
}

.ts-wrapper.lens-select.plugin-remove_button.disabled .item .remove {
  border-left-color: var(--lens-border);
  color: var(--lens-text-muted);
}

/* The dropdown (its own class from lens-select.js: tom-select does not copy the select's). */
.ts-dropdown.lens-select-dropdown {
  z-index: var(--lens-z-dropdown);
  margin-top: var(--lens-sp-1);
  padding: 0;
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-m);
  background: var(--lens-surface-raised);
  box-shadow: var(--lens-shadow-overlay);
  color: var(--lens-text);
  font-size: var(--lens-fs-body);
}

.ts-dropdown.lens-select-dropdown .ts-dropdown-content {
  max-height: 280px;
  padding: var(--lens-sp-1) 0;
}

.ts-dropdown.lens-select-dropdown :is(.option, .create, .no-results, .optgroup-header) {
  padding: 6px var(--lens-sp-3);
  line-height: 1.4;
}

.ts-dropdown.lens-select-dropdown .option {
  color: var(--lens-text);
}

.ts-dropdown.lens-select-dropdown .option.selected {
  background: var(--lens-selected);
  color: var(--lens-heading);
  font-weight: var(--lens-fw-medium);
}

.ts-dropdown.lens-select-dropdown :is(.option, .create).active {
  background: var(--lens-hover);
  color: var(--lens-heading);
}

.ts-dropdown.lens-select-dropdown .option[data-disabled] {
  color: var(--lens-text-muted);
  opacity: 1;
}

.ts-dropdown.lens-select-dropdown .create {
  color: var(--lens-link);
}

.ts-dropdown.lens-select-dropdown .no-results {
  color: var(--lens-text-muted);
}

.ts-dropdown.lens-select-dropdown .optgroup-header {
  background: transparent;
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-meta);
  font-weight: var(--lens-fw-strong);
}

.ts-dropdown.lens-select-dropdown .optgroup::before {
  border-top-color: var(--lens-divider);
}

/* The typed text inside an option: stronger ink, no marker colour (colour is not decoration). */
.ts-dropdown.lens-select-dropdown [data-selectable] .highlight {
  background: none;
  color: var(--lens-heading);
  font-weight: var(--lens-fw-strong);
}

/* ------------------------------------------------------------------ 5. segmented control */

/* One choice of a few: buttons with aria-pressed. It wraps on a phone rather than pushing. */
.lens-segmented {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  max-width: 100%;
  padding: 2px;
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-m);
  background: var(--lens-surface-subtle);
}

.lens-segmented__option {
  min-height: 30px;
  padding: 4px var(--lens-sp-3);
  border: 0;
  border-radius: var(--lens-r-pill);
  background: transparent;
  color: var(--lens-text-muted);
  font-family: var(--lens-font-ui);
  font-size: var(--lens-fs-meta);
  font-weight: var(--lens-fw-medium);
  line-height: 1.5;
  white-space: nowrap;
  cursor: pointer;
}

.lens-segmented__option:hover:not(:disabled) {
  background: var(--lens-hover);
  color: var(--lens-text);
}

.lens-segmented__option[aria-pressed="true"] {
  background: var(--lens-surface);
  color: var(--lens-heading);
  box-shadow: inset 0 0 0 1px var(--lens-border-strong);
}

.lens-segmented__option:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 1px;
}

.lens-segmented__option:disabled {
  color: var(--lens-text-muted);
  opacity: 0.55;
  cursor: not-allowed;
}

/* ------------------------------------------------------------------ 6. tabs */

/* One look for route tabs (a[aria-current="page"]) and in-page tabs (role="tab", aria-selected).
   On a phone the row scrolls inside itself and never cuts. */
.lens-tabs {
  display: flex;
  gap: var(--lens-sp-1);
  max-width: 100%;
  margin: 0 0 var(--lens-sp-4);
  overflow-x: auto;
  overflow-y: hidden;
  /* The row's rule is a shadow, not a border: a scroller clips at its padding edge, and a tab's
     underline drawn over a border would be cut. */
  box-shadow: inset 0 -1px 0 var(--lens-divider);
  scrollbar-width: thin;
}

.lens-tabs__tab {
  flex: none;
  padding: var(--lens-sp-2) var(--lens-sp-3);
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--lens-text-muted);
  font-family: var(--lens-font-ui);
  font-size: var(--lens-fs-body);
  font-weight: var(--lens-fw-medium);
  line-height: 1.4;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.lens-tabs__tab:hover {
  border-bottom-color: var(--lens-border-strong);
  color: var(--lens-text);
}

.lens-tabs__tab:is([aria-current="page"], [aria-selected="true"]) {
  border-bottom-color: var(--lens-primary);
  color: var(--lens-heading);
}

.lens-tabs__tab:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: -2px;
  border-radius: var(--lens-r-s) var(--lens-r-s) 0 0;
}

.lens-tabs__count {
  margin-left: var(--lens-sp-1);
  color: var(--lens-text-muted);
  font-weight: var(--lens-fw-regular);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ 7. filter bar and chips */

/* Local filters, right above the result set they filter. */
.lens-filterbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--lens-sp-3);
  margin: 0 0 var(--lens-sp-3);
}

.lens-filterbar > .lens-field {
  flex: 1 1 180px;
  max-width: 280px;
}

.lens-filterbar > .lens-field--grow {
  flex: 2 1 260px;
  max-width: none;
}

/* The active filters: each a removable chip. */
.lens-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--lens-sp-2);
  margin: 0 0 var(--lens-sp-3);
}

.lens-chips[hidden] {
  display: none;
}

.lens-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--lens-sp-1);
  min-height: 28px;
  max-width: 100%;
  padding: 2px var(--lens-sp-2) 2px var(--lens-sp-3);
  border: 1px solid var(--lens-border-strong);
  border-radius: var(--lens-r-pill);
  background: var(--lens-surface);
  color: var(--lens-text);
  font-family: var(--lens-font-ui);
  font-size: var(--lens-fs-meta);
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
}

.lens-chip::after {
  content: "\f62a" / "";
  font-family: bootstrap-icons;
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-body);
  line-height: 1;
}

.lens-chip:hover {
  border-color: var(--lens-text-muted);
  background: var(--lens-hover);
}

.lens-chip:hover::after {
  color: var(--lens-action-ink);
}

.lens-chip:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 2px;
}

.lens-chip__name {
  color: var(--lens-text-muted);
}

/* ------------------------------------------------------------------ 7b. choices and picker */

/* One choice among a few, each with a line that explains it (a role, an account type): real
   radios (or checkboxes) inside their labels, so the keyboard and the form work as usual. */
.lens-choices {
  display: grid;
  gap: var(--lens-sp-2);
}

.lens-choices--two {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.lens-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--lens-sp-3);
  margin: 0;
  padding: var(--lens-sp-3);
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-m);
  background: var(--lens-surface);
  cursor: pointer;
}

.lens-choice:hover {
  background: var(--lens-hover);
}

.lens-choice:has(.lens-choice__input:checked) {
  border-color: var(--lens-primary);
  background: var(--lens-selected);
}

.lens-choice:has(.lens-choice__input:focus-visible) {
  outline: 2px solid var(--lens-focus);
  outline-offset: 2px;
}

.lens-choice__input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 3px 0 0;
  accent-color: var(--lens-primary);
}

.lens-choice__input:focus-visible {
  outline: none;
}

.lens-choice__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.lens-choice__title {
  color: var(--lens-heading);
  font-weight: var(--lens-fw-medium);
}

.lens-choice__text {
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-meta);
}

/* Many choices to tick (a user's locations): search and filters, the count and its bulk actions,
   then the list in its own frame, scrolling inside itself. */
.lens-picker {
  display: grid;
  gap: var(--lens-sp-3);
  min-width: 0;
}

.lens-picker[hidden] {
  display: none;
}

.lens-picker > .lens-chips,
.lens-picker > .lens-notices {
  margin: 0;
}

.lens-picker__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--lens-sp-3);
}

.lens-picker__tools > .lens-field {
  flex: 1 1 180px;
  min-width: 0;
}

.lens-picker__tools > .lens-field--grow {
  flex: 2 1 260px;
}

.lens-picker__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--lens-sp-2);
}

.lens-picker__summary {
  margin: 0;
  color: var(--lens-text-muted);
  font-variant-numeric: tabular-nums;
}

.lens-picker__list {
  max-height: 360px;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-m);
}

.lens-picker__item {
  display: flex;
  align-items: flex-start;
  gap: var(--lens-sp-3);
  padding: var(--lens-sp-2) var(--lens-sp-3);
  border-bottom: 1px solid var(--lens-divider);
}

.lens-picker__item:last-child {
  border-bottom: 0;
}

.lens-picker__item[hidden] {
  display: none;
}

.lens-picker__item:hover {
  background: var(--lens-hover);
}

.lens-picker__item:has(input:checked) {
  background: var(--lens-selected);
}

.lens-picker__item > .form-check-input {
  flex: none;
  margin-top: 3px;
}

.lens-picker__label {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--lens-sp-2);
  flex: 1;
  min-width: 0;
  cursor: pointer;
}

.lens-picker__name {
  color: var(--lens-text);
  overflow-wrap: anywhere;
}

.lens-picker__meta {
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-meta);
}

.lens-picker__empty {
  margin: 0;
  color: var(--lens-text-muted);
}

/* ------------------------------------------------------------------ 8. pagination */

.lens-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--lens-sp-2) var(--lens-sp-4);
  margin: var(--lens-sp-3) 0;
}

.lens-pager__summary {
  margin: 0;
  color: var(--lens-text-muted);
  font-size: var(--lens-fs-meta);
  font-variant-numeric: tabular-nums;
}

.lens-pager .pagination {
  --bs-pagination-padding-x: 10px;
  --bs-pagination-padding-y: 4px;
  --bs-pagination-font-size: var(--lens-fs-meta);
  --bs-pagination-color: var(--lens-text);
  --bs-pagination-bg: var(--lens-surface);
  --bs-pagination-border-width: 1px;
  --bs-pagination-border-color: var(--lens-border);
  --bs-pagination-border-radius: var(--lens-r-m);
  --bs-pagination-hover-color: var(--lens-heading);
  --bs-pagination-hover-bg: var(--lens-hover);
  --bs-pagination-hover-border-color: var(--lens-border);
  --bs-pagination-focus-color: var(--lens-heading);
  --bs-pagination-focus-bg: var(--lens-hover);
  --bs-pagination-focus-box-shadow: 0 0 0 2px var(--lens-focus);
  --bs-pagination-active-color: var(--lens-text-inverse);
  --bs-pagination-active-bg: var(--lens-primary);
  --bs-pagination-active-border-color: var(--lens-primary);
  --bs-pagination-disabled-color: var(--lens-text-muted);
  --bs-pagination-disabled-bg: var(--lens-surface-subtle);
  --bs-pagination-disabled-border-color: var(--lens-border);
  flex-wrap: wrap;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ 9. modal */

/* Bootstrap's modal with .lens-modal on .modal: a raised surface, the consequence in one
   sentence, the footer Cancel then the action. */
.lens-modal {
  --bs-modal-zindex: var(--lens-z-modal);
  --bs-modal-width: 520px;
  --bs-modal-margin: var(--lens-sp-4);
  --bs-modal-bg: var(--lens-surface-raised);
  --bs-modal-color: var(--lens-text);
  --bs-modal-border-color: var(--lens-border);
  --bs-modal-border-radius: var(--lens-r-l);
  --bs-modal-inner-border-radius: var(--lens-r-l);
  --bs-modal-box-shadow: var(--lens-shadow-overlay);
  --bs-modal-header-border-color: var(--lens-divider);
  --bs-modal-footer-border-color: var(--lens-divider);
  --bs-modal-padding: var(--lens-sp-5);
  --bs-modal-header-padding: var(--lens-sp-4) var(--lens-sp-5);
  --bs-modal-footer-gap: var(--lens-sp-2);
}

.lens-modal .modal-content {
  border: 1px solid var(--lens-border);
  border-radius: var(--lens-r-l);
  background: var(--lens-surface-raised);
  box-shadow: var(--lens-shadow-overlay);
  color: var(--lens-text);
}

.lens-modal .modal-header {
  padding: var(--lens-sp-4) var(--lens-sp-5);
  border-bottom: 1px solid var(--lens-divider);
}

.lens-modal .modal-title {
  color: var(--lens-heading);
  font-size: var(--lens-fs-section);
  font-weight: var(--lens-fw-strong);
  line-height: 1.3;
}

.lens-modal .modal-body {
  display: grid;
  gap: var(--lens-sp-4);
  padding: var(--lens-sp-5);
}

.lens-modal .modal-footer {
  gap: var(--lens-sp-2);
  padding: var(--lens-sp-3) var(--lens-sp-5);
  border-top: 1px solid var(--lens-divider);
}

.lens-modal .modal-footer > * {
  margin: 0;
}

.lens-modal .btn-close:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 2px;
  box-shadow: none;
}

/* What will happen, in one sentence, before the action that does it. */
.lens-modal__consequence {
  display: flex;
  gap: var(--lens-sp-2);
  align-items: flex-start;
  margin: 0;
  padding: var(--lens-sp-3);
  border-radius: var(--lens-r-m);
  background: var(--lens-surface-subtle);
  color: var(--lens-text);
  font-size: var(--lens-fs-body);
}
/* The icon says what kind of sentence it is; no bar on the edge. */
.lens-modal__consequence::before {
  content: "\f431" / "";
  flex: none;
  font-family: bootstrap-icons;
  line-height: 1.45;
  color: var(--lens-info-ink);
}
.lens-modal__consequence.d-none { display: none; }

/* Only when it describes a real risk (deleting, rotating a token) does it take the action tint. */
.lens-modal__consequence--risk {
  background: var(--lens-action-bg);
  color: var(--lens-action-ink);
}
.lens-modal__consequence--risk::before {
  content: "\f33a" / "";
  color: var(--lens-action-ink);
}

/* ------------------------------------------------------------------ 9b. notice */
/* A message that belongs to the page, not a transient toast: what happened on the sign-in, reset
   and password pages, a note on a form. The same soft rounded box with an icon as a modal's
   consequence (owner decision B1, 8 October 2026), in the state's colour; never an edge bar. */
.lens-notices {
  display: flex;
  flex-direction: column;
  gap: var(--lens-sp-2);
}
.lens-notice {
  display: flex;
  gap: var(--lens-sp-2);
  align-items: flex-start;
  margin: 0;
  padding: var(--lens-sp-3);
  border-radius: var(--lens-r-m);
  background: var(--lens-info-bg);
  color: var(--lens-info-ink);
  font-size: var(--lens-fs-body);
  line-height: 1.45;
}
.lens-notice::before {
  content: "\f431" / "";
  flex: none;
  font-family: bootstrap-icons;
  line-height: 1.45;
}
.lens-notice--error { background: var(--lens-action-bg); color: var(--lens-action-ink); }
.lens-notice--error::before { content: "\f333" / ""; }
.lens-notice--warning { background: var(--lens-watch-bg); color: var(--lens-watch-ink); }
.lens-notice--warning::before { content: "\f33a" / ""; }
.lens-notice--success { background: var(--lens-good-bg); color: var(--lens-good-ink); }
.lens-notice--success::before { content: "\f26b" / ""; }

/* ------------------------------------------------------------------ 10. toast */

/* LensToast.show() and the server's messages (fragments/lens-toasts.html) share this markup. */
.lens-toasts {
  position: fixed;
  right: var(--lens-sp-4);
  bottom: var(--lens-sp-4);
  z-index: var(--lens-z-toast);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--lens-sp-2);
  width: min(400px, calc(100vw - 2 * var(--lens-sp-4)));
  pointer-events: none;
}

.lens-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--lens-sp-2);
  width: 100%;
  padding: var(--lens-sp-3) var(--lens-sp-2) var(--lens-sp-3) var(--lens-sp-3);
  border: 0;
  border-radius: var(--lens-r-m);
  background: var(--lens-toast-bg);
  box-shadow: var(--lens-shadow-overlay);
  color: var(--lens-toast-text);
  font-size: var(--lens-fs-body);
  line-height: 1.45;
  pointer-events: auto;
  animation: lens-toast-in var(--lens-duration) var(--lens-ease);
}

.lens-toast[hidden] {
  display: none;
}

.lens-toast::before {
  flex: none;
  font-family: bootstrap-icons;
  font-size: var(--lens-fs-lead);
  line-height: 1.3;
}

.lens-toast--success::before {
  content: "\f26b" / "";
  color: var(--lens-toast-good);
}

.lens-toast--error::before {
  content: "\f333" / "";
  color: var(--lens-toast-action);
}

.lens-toast--warning::before {
  content: "\f33b" / "";
  color: var(--lens-toast-watch);
}

.lens-toast--info::before {
  content: "\f431" / "";
  color: var(--lens-toast-info);
}

.lens-toast__text {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
}

.lens-toast__action {
  flex: none;
  color: inherit;
  text-decoration: underline;
  font-weight: var(--lens-fw-medium);
  white-space: nowrap;
}

.lens-toast__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin: -4px 0 -4px 0;
  padding: 0;
  border: 0;
  border-radius: var(--lens-r-s);
  background: transparent;
  color: var(--lens-toast-muted);
  cursor: pointer;
}

.lens-toast__close::before {
  content: "\f659" / "";
  font-family: bootstrap-icons;
  font-size: var(--lens-fs-meta);
}

.lens-toast__close:hover {
  background: transparent;
  color: var(--lens-toast-text);
}

.lens-toast__close:focus-visible {
  outline: 2px solid var(--lens-focus);
  outline-offset: 1px;
}

/* In the gallery a toast is shown in place, not floating. */
.lens-toasts--inline {
  position: static;
  width: 100%;
  max-width: 400px;
  align-items: stretch;
}

@keyframes lens-toast-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------------ phone and motion */

@media (max-width: 640px) {
  .lens-filterbar > .lens-field,
  .lens-filterbar > .lens-field--grow {
    flex: 1 1 100%;
    max-width: none;
  }

  .lens-pager {
    justify-content: flex-start;
  }

  .lens-toasts {
    right: var(--lens-sp-3);
    bottom: var(--lens-sp-3);
    left: var(--lens-sp-3);
    width: auto;
  }

  .lens-modal .modal-footer {
    flex-wrap: wrap;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lens-toast {
    animation: none;
  }

  a.lens-go::after,
  .btn:is(.btn-primary, .btn-secondary, .btn-quiet, .btn-danger, .btn-danger-solid) {
    transition: none;
  }
}
