/* MeshTender app-specific styles layered on top of Tabler.
   Everything generic (cards, forms, buttons, tables, badges, dropdowns) comes
   from Tabler; this file only covers things Tabler has no component for: the
   live console/event log, the Leaflet map, and the public-key code block. */

/* ---------- Text selection ----------
   The dark theme's default selection highlight is nearly invisible inside form
   controls; force a high-contrast highlight everywhere, inputs included. */
::selection {
  background-color: var(--tblr-primary);
  color: #fff;
}
input::selection,
textarea::selection {
  background-color: var(--tblr-primary);
  color: #fff;
}

/* ---------- Back links (icon + text, plain link — not a button) ----------
   These are navigational "← All organizations" links. Styling them as a plain
   link (rather than .btn .btn-link) avoids the button's inline-flex box being
   icon-height tall but text-width wide, which made the focus/hover state show
   asymmetric padding (flush left/right, padded top/bottom). */
.back-link {
  display: inline-flex;
  align-items: center;
  color: var(--tblr-link-color);
  text-decoration: none;
}
/* a.back-link beats Tabler's `a:hover:has(.icon){text-decoration:none}`. */
a.back-link:hover {
  color: var(--tblr-link-hover-color);
  text-decoration: underline;
}
.back-link .icon {
  width: 1.25rem;
  height: 1.25rem;
}

/* ---------- Public-key / monospace code blocks ---------- */
code.pk,
code.pubkey {
  display: block;
  word-break: break-all;
  background: var(--tblr-bg-surface-secondary);
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius);
  padding: 0.5rem 0.625rem;
  font-size: 0.8125rem;
  /* gray-400, not --tblr-secondary (#6b7280): the latter is only 3.67:1 on the
     near-black panel bg and fails WCAG AA for this key/data text. */
  color: var(--tblr-gray-400);
}

/* ---------- Collapse toggle label (Show/Hide) ---------- */
.collapse-hide {
  display: none;
}
[aria-expanded="true"] .collapse-show {
  display: none;
}
[aria-expanded="true"] .collapse-hide {
  display: inline;
}

/* A row's expanded panel (account page credential rows) lines up with the row's
   heading rather than with the icon gutter to its left: one .icon (1.25rem) plus
   one g-3 grid gutter (1rem). Hardcoded rather than read from --tblr-icon-size,
   which Tabler redefines per component context. */
.row-panel {
  padding-left: 2.25rem;
}

/* A chevron on a collapse toggle: points down when the panel is closed, up when
   it's open. Bootstrap maintains aria-expanded on the toggle itself, so the same
   attribute the Show/Hide labels key off drives this too — no JS of our own. */
.collapse-chevron {
  transition: transform 0.2s ease;
}
[aria-expanded="true"] .collapse-chevron {
  transform: rotate(180deg);
}

/* Card headers: Tabler leaves them transparent, divided from the body by a faint
   line, so a header read as more of the card. Give every header the tint of
   Tabler's own .card-header-light (and of the strip behind .card-header-tabs, so
   tabbed and plain headers match), as one rule rather than a class on each
   header. Unlike .card-header-light it keeps the divider: a table's column
   labels right under a header carry the same tint, and without the line the two
   would merge into one band. */
.card-header {
  --tblr-card-header-bg: var(--tblr-bg-surface-tertiary);
}

/* Segmented controls (a .btn-group of .btn-check radios, or of links where the
   current page carries aria-current): Tabler marks the chosen segment with a
   background barely lighter than the rest, which is hard to pick out,
   especially in the dark theme. Tint it with the primary color. */
.btn-group > .btn-check:checked + .btn,
.btn-group > .btn[aria-current="page"] {
  background-color: var(--tblr-primary-lt);
  border-color: var(--tblr-primary);
  color: var(--tblr-primary);
  z-index: 1;
}

/* ---------- Live event / console log ---------- */
.evlog {
  list-style: none;
  margin: 0;
  padding: 0.75rem;
  background: var(--tblr-bg-surface-secondary);
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius);
  max-height: 240px;
  overflow-y: auto;
  font-family: var(--tblr-font-monospace);
  font-size: 0.8125rem;
}
.evlog:empty { display: none; }
.evlog.console { max-height: 320px; }
/* The console log stays visible before connecting, with a hint in place of entries. */
.evlog.console[data-empty]:empty { display: block; }
.evlog.console[data-empty]:empty::before {
  content: attr(data-empty);
  color: var(--tblr-secondary);
  font-family: var(--tblr-font-sans-serif);
}
/* Console completion: opens upward over the log, so it never runs off the page. */
.console-suggest {
  position: absolute;
  bottom: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  z-index: 10;
  max-height: 14rem;
  overflow-y: auto;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--tblr-bg-surface);
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius);
  box-shadow: var(--tblr-box-shadow-dropdown);
}
.console-suggest-item {
  padding: 0.25rem 0.5rem;
  border-radius: var(--tblr-border-radius-sm);
  cursor: pointer;
}
.console-suggest-item:hover,
.console-suggest-item.active { background: var(--tblr-active-bg); }
.ev { padding: 0.15rem 0; border-bottom: 1px solid var(--tblr-border-color-translucent); }
.ev:last-child { border-bottom: none; }
/* Colors chosen for WCAG AA (≥4.5:1) on the near-black log background:
   --tblr-secondary (#6b7280) and --tblr-danger (#d63939) only reach ~3.7:1,
   so info uses the lighter gray-400 and errors the lighter danger emphasis. */
.ev-info, .ev-ready, .ev-queued { color: var(--tblr-gray-400); }
.ev-confirmed { color: var(--tblr-success); font-weight: 600; }
.ev-heard { color: var(--tblr-success); }
.ev-error, .ev-timeout { color: var(--tblr-danger-text-emphasis); }
.ev-warning, .ev-denied, .ev-noreply { color: var(--tblr-warning); }
.ev-debug { color: var(--tblr-info); word-break: break-all; }
.ev-sent { color: var(--tblr-azure); }
.ev-reply, .ev-message { color: var(--tblr-body-color); white-space: pre-wrap; }

/* ---------- Badge contrast (dark) ----------
   Tabler's light "-lt" badges set their text to the full-strength brand color
   over a 10%-opacity tint, which is too dark for this small status text on the dark
   theme. The list below is maintained by TestContrastMeetsWCAGAA rather than by eye,
   and re-checked on Tabler 1.7.1: without these, purple measures 2.88:1 and azure,
   teal and orange about 4.25:1. (1.7's palette fixed links and inactive tabs, whose overrides
   are gone.)

   Where Tabler defines a dark-theme *-text-emphasis value, use it; the rest are mixed
   toward white against their own palette variable, so they stay tied to the palette
   instead of becoming hand-picked hexes. */
.badge.bg-purple-lt { color: #d98fe6 !important; }
.badge.bg-secondary-lt { color: var(--tblr-secondary-text-emphasis) !important; }
.badge.bg-blue-lt { color: var(--tblr-primary-text-emphasis) !important; }
.badge.bg-azure-lt { color: color-mix(in srgb, var(--tblr-azure) 80%, #fff) !important; }
.badge.bg-teal-lt { color: color-mix(in srgb, var(--tblr-teal) 80%, #fff) !important; }
.badge.bg-orange-lt { color: color-mix(in srgb, var(--tblr-orange) 80%, #fff) !important; }

/* Tabler's danger button pairs its off-white foreground (#f9fafb) with the danger red,
   which measures 4.46:1 — just under the 4.5:1 floor. Pure white reaches 4.66:1 without
   touching the button's color. */
.btn-danger {
  color: #fff;
}

/* ---------- MapLibre map (dark) ---------- */
#map {
  height: 360px;
  border-radius: var(--tblr-border-radius);
  border: 1px solid var(--tblr-border-color);
}
/* Painted behind the WebGL canvas, so it shows while tiles are still in flight
   rather than a white flash on a dark page. */
.maplibregl-map { background: #14171c; }
/* Scoped under .maplibregl-popup so these beat MapLibre's own defaults, which load
   after app.css (maplibre-gl.css is pulled in per-page in the map card body). */
.maplibregl-popup .maplibregl-popup-content {
  background: var(--tblr-bg-surface);
  color: var(--tblr-body-color);
  box-shadow: var(--tblr-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.4));
}
.maplibregl-popup-anchor-top .maplibregl-popup-tip { border-bottom-color: var(--tblr-bg-surface); }
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip { border-top-color: var(--tblr-bg-surface); }
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--tblr-bg-surface); }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--tblr-bg-surface); }
.maplibregl-popup-close-button { color: var(--tblr-body-color); }

/* Controls: the zoom buttons, plus our own two button groups (the Dark/Light
   basemap switch and the region-editor draw tools, both built in JS — see
   basemap.js and regionmap.js). MapLibre's default control is a white box, which
   is wrong on every page we render.

   Everything here is scoped under .maplibregl-map purely to win the cascade:
   maplibre-gl.css is pulled in per-page in the map card body, so it loads *after*
   app.css and an equally specific rule of ours loses to it. The tell when this is
   missing is subtle — the buttons we style by state still look right, and only the
   unpressed ones stay white. */
.maplibregl-map .maplibregl-ctrl-group {
  background: var(--tblr-bg-surface);
  box-shadow: var(--tblr-box-shadow, 0 1px 2px rgba(0, 0, 0, 0.4));
}
.maplibregl-map .maplibregl-ctrl-group button { color: var(--tblr-body-color); }
/* The zoom glyphs are background-image SVGs with a hard-coded #333 fill — fine on
   MapLibre's white control, invisible on our dark one, and not restyleable because
   the color lives inside the data: URI. Inverting the icon is the way to reach it. */
.maplibregl-map .maplibregl-ctrl-group button .maplibregl-ctrl-icon { filter: invert(1); }
.maplibregl-map .maplibregl-ctrl-group button + button { border-top-color: var(--tblr-border-color); }
.maplibregl-map .maplibregl-ctrl-group button:not(:disabled):hover { background: var(--tblr-bg-surface-secondary); }
/* MapLibre's icon buttons are square and unlabeled; ours carry text, so they need
   width and horizontal padding or the label is clipped to a 29px box. */
.maplibregl-map .mesh-basemap-ctrl button,
.maplibregl-map .mesh-draw-ctrl button {
  width: auto;
  min-width: 4.5rem;
  padding: 0 0.5rem;
  font-size: 0.75rem;
  line-height: 1.75rem;
}
/* aria-pressed is the state, so it is also what styles the active button — there
   is no second class to keep in sync. */
.maplibregl-map .mesh-basemap-ctrl button[aria-pressed="true"],
.maplibregl-map .mesh-draw-ctrl button[aria-pressed="true"] {
  background: var(--tblr-primary);
  color: #fff;
}
.maplibregl-map .mesh-draw-ctrl button:disabled { opacity: 0.45; }
/* The attribution CARTO require stays visible; only its chrome is themed. It sits
   over the map, not the page, so it is deliberately NOT painted in theme tokens:
   the same strip has to stay legible over both the near-black Dark Matter basemap
   and the near-white Voyager one, which a token that only knows the page theme
   cannot do. A dark scrim with near-white text reads on both. */
.maplibregl-map .maplibregl-ctrl.maplibregl-ctrl-attrib {
  /* Both class names, because upstream's own rule is .maplibregl-ctrl.maplibregl-
     ctrl-attrib — matching only one of them ties on specificity and loses, which
     shows up as white-on-white text rather than as nothing happening. */
  background: rgba(0, 0, 0, 0.7);
  color: #f4f6fa;
}
.maplibregl-map .maplibregl-ctrl-attrib a,
.maplibregl-map .maplibregl-ctrl-attrib a:hover { color: #f4f6fa; }

/* Profile list on the org config page: a long list scrolls inside its card
   instead of pushing the location-preview map off the page. Rows are compact —
   Tabler's default list-group padding plus a full-size icon button makes a ~4.5rem
   row, so only a couple fit before scrolling. Both are driven by CSS variables, so
   turn those down here rather than overriding the padding itself. */
.profile-list {
  max-height: 22rem;
  overflow-y: auto;
}
.profile-list .list-group-item {
  --tblr-list-group-item-padding-y: 0.375rem;
}
.profile-list .btn-icon {
  --tblr-btn-padding-y: 0.25rem;
  --tblr-btn-icon-size: 1.25rem;
}

/* Active region block in the config editor: highlight the block currently being
   drawn on the shared region map. */
.region-block.region-active {
  border-color: var(--tblr-primary) !important;
  box-shadow: 0 0 0 1px var(--tblr-primary);
}

/* Footer on the centered auth layout (authbase). footerbody right-packs its two
   columns, which suits a full-width page but reads as misaligned under a narrow
   centered card, so center them here instead. */
.footer-centered .row {
  justify-content: center;
}

/* Reserve the scrollbar's space so pages don't shift sideways when one appears.
   Tabler before 1.7 did this with `:root { margin-left: calc(100vw - 100%) }`
   (@media min-width:992px), which put the gutter on the LEFT: every scrollable page
   sat a scrollbar's width right of the window with an unpainted strip down the left
   edge. 1.7 dropped that rule; scrollbar-gutter keeps the no-shift behavior on the
   correct side. Where it isn't supported the declaration is ignored, and overlay
   scrollbars (macOS, mobile) take no space at all, so it's a no-op there.
   TestE2ENoLeftGutterWhenScrollbarAppears guards it. */
:root {
  scrollbar-gutter: stable;
}

/* A copy button (ui.js data-copy*) that just copied: green for a moment. */
[data-copied] {
  color: var(--tblr-success) !important;
}

/* ---------- Landing page ---------- */
/* A section label over a group of content ("For repeater owners"), on the
   landing page and in the docs. */
.section-kicker {
  font-size: 0.8125rem;
  font-weight: var(--tblr-font-weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--tblr-primary-text-emphasis);
  margin: 1rem 0 1.5rem;
}
/* The product previews: a touch of depth so they read as screenshots, and no
   interaction (they're illustrations). */
.landing-preview {
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
/* Step numbers: the -lt tint behind emphasis blue (bg-primary-lt forces the
   full-strength blue, which is 2.75:1 on the tint). */
.landing-step-n {
  background: var(--tblr-primary-lt);
  color: var(--tblr-primary-text-emphasis);
}
/* What a feature needs ("Just your companion app", "Needs a KISS modem"), on the
   landing page and the add-repeater wizard. */
.need-tag {
  display: inline-flex;
  align-items: center;
  font-size: 0.875rem;
  color: var(--tblr-secondary-text-emphasis);
}
