/* av-components.css — sitewide COMPONENT language (the reusable chrome).
   Phase 1.5: nav, buttons, theme toggle, footer, section primitives, base body
   typography + a11y utilities + the av-rise entrance keyframe. Built entirely on
   tokens (av-tokens.css) + skin vars (av-skin-*.css); shared across every living
   page. Page-specific composition stays in the page CSS (e.g. av-living-landing.css). */

/* ── BASE BODY + A11Y ─────────────────────────────────────────────────────── */

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--av-bg);
  color: var(--av-text);
  font-family: var(--av-font-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transition: background 0.25s var(--av-ease-out), color 0.25s var(--av-ease-out);
}

/* Sticky footer: body is a flex column (every page's nav/main/footer are direct
   children via the shared `living` layout's block content), footer floats to the
   bottom on short pages instead of sitting right under a half-empty main. */
.av-footer {
  margin-top: auto;
}

/* Screen-reader only utility */
.av-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Focus visible — WCAG AA */
:focus-visible {
  outline: 2px solid var(--av-orange);
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) { outline: none; }


/* ── BUTTONS ──────────────────────────────────────────────────────────────── */

.av-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--av-space-2);
  padding: 11px 24px;
  border-radius: var(--av-radius);
  font-family: var(--av-font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  border: 2px solid transparent;
  transition: background 0.18s var(--av-ease-out),
              color 0.18s var(--av-ease-out),
              border-color 0.18s var(--av-ease-out),
              transform 0.12s var(--av-ease-out),
              box-shadow 0.18s var(--av-ease-out);
  min-height: 44px;
  white-space: nowrap;
}
.av-btn:active { transform: scale(0.97); }

.av-btn--primary {
  background: var(--av-orange);
  color: #ffffff;
  border-color: var(--av-orange);
}
.av-btn--primary:hover {
  background: var(--av-orange-soft);
  border-color: var(--av-orange-soft);
}

.av-btn--outline {
  background: transparent;
  color: var(--av-orange);
  border-color: var(--av-orange);
}
.av-btn--outline:hover {
  background: rgba(252, 114, 19, 0.08);
}

.av-btn--danger {
  background: var(--av-danger);
  color: #ffffff;
  border-color: var(--av-danger);
}
.av-btn--danger:hover {
  background: #cf3a3f;
  border-color: #cf3a3f;
}

.av-btn--lg {
  padding: 15px 36px;
  font-size: 1.0625rem;
}

/* /account/tokens/ — one-time token display + checkbox rows */
.av-token-value {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	width: 100%;
	margin: 0.5rem 0;
}
.av-token-check {
	display: block;
	margin: 0.35rem 0;
}
/* Token list rows are term+value pairs, not marker+content — widen the label
   track (the base .av-card__list-item grid is 20px 1fr, sized for a check icon). */
.av-token-list .av-card__list-item {
	grid-template-columns: 7rem 1fr;
	align-items: baseline;
}
.av-token-list .av-card__list-term { margin-bottom: 0; }
/* Scope note sits tight under its checkbox, indented to the checkbox text. */
.av-token-note {
	margin: 0.1rem 0 0 1.4rem;
	font-size: 0.875rem;
	color: var(--av-text-muted);
	max-width: 560px;
}
/* Keep the exchange allowlist visually apart from the live-orders choice. */
.av-token-exchanges { margin-top: var(--av-space-5); }

/* Compact button — secondary/per-record actions. Reusable modifier, and applied
   automatically to any button inside a .av-card__actions row (no markup change). */
.av-btn--sm,
.av-card__actions .av-btn {
  padding: 8px 16px;
  gap: var(--av-space-1);
  font-size: 0.8125rem;
  min-height: 36px;
}


/* ── SECTION PRIMITIVES ───────────────────────────────────────────────────── */

.av-section-heading {
  font-family: var(--av-font-display);
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  font-weight: 700;
  color: var(--av-text);
  margin: 0 0 var(--av-space-4);
  line-height: 1.15;
}

.av-section-sub {
  font-size: 1.0625rem;
  color: var(--av-text-muted);
  max-width: 560px;
  margin: 0 0 var(--av-space-7);
  line-height: 1.65;
}
/* When the sub is centre-aligned, centre the block too — otherwise the 560px box stays
   left-anchored and the centred text reads as off-centre under a centred heading. */
.av-section-sub.text-center {
  margin-left: auto;
  margin-right: auto;
}

/* Alphabetical divider — the section heading scaled down to a labelled rule (the
   exchange picker groups A, B, C…). The letter sits left; a hairline fills the row. */
.av-section-heading--letter {
  display: flex;
  align-items: center;
  gap: var(--av-space-4);
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--av-text-muted);
  margin: var(--av-space-7) 0 var(--av-space-5);
}
.av-section-heading--letter::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--av-border);
}


/* ── NAV ──────────────────────────────────────────────────────────────────── */

.av-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  background: var(--av-bg);
  border-bottom: 1px solid var(--av-border);
  transition: background 0.25s, border-color 0.25s;
}

.av-nav__inner {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: 0 var(--av-space-5);
  height: 64px;
  display: flex;
  align-items: center;
  gap: var(--av-space-5);
}

.av-nav__logo {
  text-decoration: none;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}

.av-nav__logo-img {
  height: 24px;
  width: auto;
  display: block;
}

/* Theme swap: dark variant (orange/white) default, light variant (orange/coal)
   under [data-theme="light"]. Brand book p.14 pairing — never a non-compliant mix. */
.av-nav__logo--light { display: none; }
[data-theme="light"] .av-nav__logo--dark { display: none; }
[data-theme="light"] .av-nav__logo--light { display: block; }

.av-nav__links {
  display: flex;
  align-items: center;
  gap: var(--av-space-5);
  margin-left: var(--av-space-4);
}

.av-nav__link {
  font-family: var(--av-font-display);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--av-text-muted);
  text-decoration: none;
  transition: color 0.15s;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.av-nav__link:hover { color: var(--av-text); }

.av-nav__actions {
  display: flex;
  align-items: center;
  gap: var(--av-space-3);
  margin-left: auto;
}

.av-nav__theme-toggle {
  background: none;
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius);
  color: var(--av-text-muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-size: 1rem;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
  min-height: 44px;
  min-width: 44px;
}
.av-nav__theme-toggle:hover {
  border-color: var(--av-orange);
  color: var(--av-orange);
  background: rgba(252, 114, 19, 0.06);
}

/* Show/hide theme icons based on current theme */
.av-nav__theme-icon--moon { display: none; }
[data-theme="light"] .av-nav__theme-icon--sun { display: none; }
[data-theme="light"] .av-nav__theme-icon--moon { display: inline; }

.av-nav__mobile-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--av-space-2);
  margin-left: auto;
  min-height: 44px;
  min-width: 44px;
  border-radius: var(--av-radius);
}
.av-nav__mobile-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--av-text);
  border-radius: 1px;
  transition: transform 0.2s, opacity 0.2s;
}

/* Mobile nav — the bar collapses to logo + hamburger. The nav links AND the
   actions (Log in / Sign up free / theme) drop into a single in-flow panel
   below the bar when the toggle is open, so nothing wraps out of the
   fixed-height bar onto the page. (Fixes the Sign-up-free button overflowing
   the bar and obscuring the hero on mobile.) */
@media (max-width: 768px) {
  .av-nav__inner {
    flex-wrap: wrap;
    row-gap: 0;
    min-height: 64px;
    height: auto;
    align-items: center;
  }
  .av-nav__mobile-toggle { display: flex; margin-left: auto; }

  /* Both menu panels: out of the bar, hidden until the toggle opens, then each
     takes a full-width row below the bar. */
  .av-nav__links,
  .av-nav__actions {
    display: none;
    order: 1;
    flex-basis: 100%;
    width: 100%;
    margin-left: 0;
  }
  .av-nav__links {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--av-space-4);
    padding: var(--av-space-4) 0 0;
    margin-top: var(--av-space-2);
    border-top: 1px solid var(--av-border);
  }
  .av-nav__links.is-open,
  .av-nav__links[aria-hidden="false"] { display: flex; }

  /* The actions block follows the toggle in source order, so the same open
     state reveals it via a sibling selector — no JS change needed. */
  .av-nav__mobile-toggle[aria-expanded="true"] ~ .av-nav__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--av-space-3);
    padding: var(--av-space-3) 0 var(--av-space-4);
  }
  .av-nav__actions .av-btn--primary { flex: 1 1 100%; justify-content: center; }
  /* Keep Log in reachable inside the open menu at every mobile width. */
  .av-nav__actions .av-nav__login { display: inline-flex; }
}


/* ── Unified header: sub-nav dropdown groups (Option A, 2026-06-28) ─────────────
   ONE login-state-aware nav. Each top-level item is a dropdown group. Desktop:
   opens on :hover / :focus-within (zero-JS) with a click toggle layered on by
   av-theme.js (touch / no-hover). Mobile: groups render inline inside the open
   hamburger panel. Spec: docs/redesign/unified-header-spec.md. */
.av-nav__group {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.av-nav__group-trigger {
  font-family: var(--av-font-display);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--av-text-muted);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: var(--av-space-2);
  transition: color 0.15s;
}
.av-nav__group:hover .av-nav__group-trigger,
.av-nav__group:focus-within .av-nav__group-trigger,
.av-nav__group-trigger[aria-expanded="true"] { color: var(--av-text); }
.av-nav__group-caret { font-size: 0.62em; line-height: 1; transition: transform 0.15s; }
.av-nav__group:hover .av-nav__group-caret,
.av-nav__group:focus-within .av-nav__group-caret,
.av-nav__group-trigger[aria-expanded="true"] .av-nav__group-caret { transform: rotate(180deg); }

.av-nav__menu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 184px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--av-bg);
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius);
  padding: var(--av-space-2);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.15s, transform 0.15s, visibility 0.15s;
  z-index: 110;
}
/* Invisible hover bridge so the cursor can cross from trigger to menu. */
.av-nav__menu::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 0;
  right: 0;
  height: 8px;
}
.av-nav__group:hover .av-nav__menu,
.av-nav__group:focus-within .av-nav__menu,
.av-nav__menu[data-open="true"] {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.av-nav__menu-link {
  font-family: var(--av-font-display);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--av-text-muted);
  text-decoration: none;
  padding: var(--av-space-2) var(--av-space-3);
  border-radius: var(--av-radius);
  white-space: nowrap;
  transition: color 0.15s, background 0.15s;
}
.av-nav__menu-link:hover { color: var(--av-text); background: rgba(252, 114, 19, 0.06); }
.av-nav__menu-link.is-active { color: var(--av-orange); }
.av-nav__menu-divider { height: 1px; background: var(--av-border); margin: var(--av-space-2) 0; }

@media (max-width: 768px) {
  /* Groups render inline (accordion-style) inside the open hamburger panel —
     no floating menus on touch. */
  .av-nav__group { width: 100%; flex-direction: column; align-items: flex-start; }
  .av-nav__group-trigger { width: 100%; justify-content: space-between; }
  .av-nav__menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    border: none;
    background: none;
    padding: var(--av-space-2) 0 var(--av-space-2) var(--av-space-4);
    min-width: 0;
    width: 100%;
  }
  .av-nav__menu::before { display: none; }
}


/* ── ENTRANCE KEYFRAME (shared) ───────────────────────────────────────────── */

@keyframes av-rise {
  to { opacity: 1; transform: translateY(0); }
}


/* ── LAYOUT PRIMITIVES (shared by every interior page) ────────────────────── */

/* Centered max-width inner wrapper. Replaces the per-page `__inner` repetition. */
.av-container {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: 0 var(--av-space-5);
}

/* Vertical rhythm section. --alt paints the raised surface band with hairlines,
   matching the landing's exchanges/frontier strips. */
.av-section {
  padding: var(--av-space-10) 0;
}
.av-section--tight { padding: var(--av-space-8) 0; }
.av-section--alt {
  background: var(--av-surface);
  border-top: 1px solid var(--av-border);
  border-bottom: 1px solid var(--av-border);
}


/* ── INTERIOR PAGE HERO (compact, not the 100svh landing hero) ─────────────── */

.av-page-hero {
  position: relative;
  overflow: hidden;
  padding: calc(64px + var(--av-space-10)) 0 var(--av-space-9);
  text-align: center;
}

/* Subtle orange glow, echoing the frontier strip — atmosphere over flat fill. */
.av-page-hero::before {
  content: '';
  position: absolute;
  top: -40%;
  left: 50%;
  transform: translateX(-50%);
  width: 760px;
  height: 520px;
  max-width: 120vw;
  background: radial-gradient(ellipse at center, rgba(252, 114, 19, 0.10) 0%, transparent 70%);
  pointer-events: none;
}

.av-page-hero__inner {
  position: relative;
  z-index: 1;
  max-width: 760px;
  margin: 0 auto;
  padding: 0 var(--av-space-5);
}

.av-page-hero__eyebrow {
  display: inline-block;
  background: rgba(252, 114, 19, 0.12);
  color: var(--av-orange);
  border: 1px solid rgba(252, 114, 19, 0.3);
  border-radius: 100px;
  padding: var(--av-space-1) var(--av-space-4);
  font-family: var(--av-font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: var(--av-space-5);

  opacity: 0;
  animation: av-rise 0.6s var(--av-ease-out) 0.05s forwards;
}

.av-page-hero__title {
  font-family: var(--av-font-display);
  font-size: clamp(2.25rem, 6vw, 3.75rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.025em;
  color: var(--av-text);
  margin: 0 0 var(--av-space-5);

  opacity: 0;
  transform: translateY(24px);
  animation: av-rise 0.75s var(--av-ease-out) 0.12s forwards;
}
.av-page-hero__title-accent { color: var(--av-orange); }

.av-page-hero__sub {
  font-size: clamp(1rem, 2.2vw, 1.2rem);
  color: var(--av-text-muted);
  line-height: 1.65;
  max-width: 560px;
  margin: 0 auto var(--av-space-6);

  opacity: 0;
  transform: translateY(18px);
  animation: av-rise 0.7s var(--av-ease-out) 0.26s forwards;
}

.av-page-hero__actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--av-space-3);
  flex-wrap: wrap;

  opacity: 0;
  transform: translateY(14px);
  animation: av-rise 0.65s var(--av-ease-out) 0.4s forwards;
}

@media (prefers-reduced-motion: reduce) {
  .av-page-hero__eyebrow,
  .av-page-hero__title,
  .av-page-hero__sub,
  .av-page-hero__actions {
    opacity: 1;
    transform: none;
    animation: none;
  }
}


/* ── RESPONSIVE GRID ──────────────────────────────────────────────────────── */

.av-grid {
  display: grid;
  gap: var(--av-space-5);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.av-grid--2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
/* A-Z letter dividers inside a card grid (the subscription catalog) must break the row,
   not sit in a column as a grid item. */
.av-grid > .av-section-heading--letter { grid-column: 1 / -1; }


/* ── CARD (generic surface card, the shared base for feature/compare cards) ── */

.av-card {
  background: var(--av-surface);
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius-lg);
  padding: var(--av-space-6);
  transition: border-color 0.2s var(--av-ease-out), transform 0.2s var(--av-ease-out);
  text-decoration: none;   /* whole-card anchors (a.av-card, e.g. Home v1) must not underline */
  color: inherit;          /* …and must not take the link colour either */
}
.av-card--hover:hover {
  border-color: var(--av-orange);
  transform: translateY(-3px);
}
.av-card--feature { border-top: 2px solid var(--av-orange); }

.av-card__icon {
  width: 40px;
  height: 40px;
  color: var(--av-orange);
  margin-bottom: var(--av-space-4);
  overflow: hidden;
}
.av-card__icon svg { width: 100%; height: 100%; }
.av-card__icon img { width: 100%; height: 100%; object-fit: contain; }
/* Exchange wordmark logos injected into a card icon slot (Home/Connections connected-exchange
   cards) are sized as a LOGO, not clamped into the 40px glyph box (which made them illegible). */
/* Exchange logos sit on a white tile so dark/monochrome marks stay visible on the dark theme
   (matches the marketing comparable-wall treatment), sized up from the tiny clamped version. */
.av-card__icon:has(.av-card__icon-img) {
  width: 44px; height: 44px; padding: 7px; box-sizing: border-box;
  background: var(--av-tile-bg, var(--av-tile-bg-default, #fff)); border-radius: 10px; overflow: hidden; margin-bottom: var(--av-space-3);
  display: flex; align-items: center; justify-content: center;
}
.av-card__icon img.av-card__icon-img { width: 100%; height: 100%; object-fit: contain; display: block; }

.av-card__eyebrow {
  font-family: var(--av-font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--av-orange);
  margin-bottom: var(--av-space-3);
  display: block;
}

.av-card__title {
  font-family: var(--av-font-display);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--av-text);
  margin: 0 0 var(--av-space-3);
}

.av-card__body {
  font-size: 0.9375rem;
  color: var(--av-text-muted);
  margin: 0;
  line-height: 1.65;
}

/* Token-driven feature list — replaces ad-hoc <p><strong> stacks. */
.av-card__list {
  list-style: none;
  padding: 0;
  margin: var(--av-space-5) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--av-space-4);
}
.av-card__list-item {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: var(--av-space-3);
  align-items: start;
}
.av-card__list-marker {
  color: var(--av-orange);
  flex-shrink: 0;
  margin-top: 2px;
}
.av-card__list-marker svg { width: 18px; height: 18px; display: block; }
.av-card__list-term {
  font-family: var(--av-font-display);
  font-weight: 600;
  color: var(--av-text);
  font-size: 0.9375rem;
  display: block;
  margin-bottom: 2px;
}
.av-card__list-desc {
  font-size: 0.875rem;
  color: var(--av-text-muted);
  line-height: 1.55;
  display: block;
}

/* Recent-activity rows reuse .av-card__list but have NO marker, so the 20px marker
   column squeezed the message into one-word-per-line. Give the message the full width
   (1fr) and pin the timestamp to the right (auto). */
.av-activity .av-card__list-item {
  grid-template-columns: 1fr auto; align-items: baseline; gap: var(--av-space-4);
  padding: 4px 8px; border-radius: var(--av-radius);
}
.av-activity .av-card__list-term { font-family: var(--av-font-body); font-weight: 400; font-size: 0.875rem; color: var(--av-text); min-width: 0; overflow-wrap: anywhere; margin-bottom: 0; }
.av-activity .av-card__list-desc { white-space: nowrap; }
/* Same ok/dry/danger states as the Event Log ledger, same row-wash tokens — a
   consistent color language across both surfaces (operator, 2026-07-08:
   "mimic Event Log for Recent Activity... probably easier to just mimic and
   correct the current" rather than a different treatment). info stays
   untinted, same convention as the ledger. */
.av-activity__item--ok     { background: var(--av-row-ok-bg); }
.av-activity__item--dry    { background: var(--av-row-dry-bg); }
.av-activity__item--danger { background: var(--av-row-danger-bg); }

/* Card footer note — a muted "best if…" line set off by a hairline. */
.av-card__foot {
  margin: var(--av-space-5) 0 0;
  padding-top: var(--av-space-4);
  border-top: 1px solid var(--av-border);
  font-size: 0.8125rem;
  color: var(--av-text-muted);
  line-height: 1.55;
}
.av-card__foot strong {
  font-family: var(--av-font-display);
  color: var(--av-text);
  font-weight: 600;
}

/* Per-record action row (edit / remove / copy / manage). Wraps on narrow cards;
   spacing-separated from the content above (no extra hairline — the optional
   .av-card__foot already supplies one). Buttons inside are auto-compacted via the
   .av-card__actions .av-btn rule in the BUTTONS section. */
.av-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--av-space-2);
  margin-top: var(--av-space-5);
}

/* Status chip — small inline marker (Extension-managed, Secure, …). Full-round is
   intentional here: it reads as a state pill, distinct from the 6px control radius.
   Base is neutral; --live / --managed opt into meaning where the surface wants it. */
.av-card__tag {
  display: inline-flex;
  align-items: center;
  margin-top: var(--av-space-3);
  padding: 2px 10px;
  border: 1px solid var(--av-border);
  border-radius: 999px;
  background: transparent;
  font-family: var(--av-font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--av-text-muted);
}
.av-card__tag--live {
  border-color: transparent;
  background: var(--av-live-green-bg);
  color: var(--av-live-green);
}
.av-card__tag--managed {
  border-color: transparent;
  background: var(--av-orange-bg);
  color: var(--av-orange-soft);
}
/* Robust spacing for adjacent chips (whitespace-independent for Mustache markup). */
.av-card__tag + .av-card__tag { margin-left: var(--av-space-2); }

/* Media band — a full-bleed image-on-colour header inside a card (the exchange
   picker; background-color is set inline per-exchange). Negative margins cancel the
   card's padding so the band meets the card edge; top corners follow the card radius. */
.av-card__media {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 168px;
  margin: calc(-1 * var(--av-space-6)) calc(-1 * var(--av-space-6)) var(--av-space-5);
  padding: var(--av-space-5);
  overflow: hidden;
  border-radius: var(--av-radius-lg) var(--av-radius-lg) 0 0;
}
.av-card__media img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}


/* ── FORM FIELDS ──────────────────────────────────────────────────────────── */
/* av treatment of the Bootstrap form classes the migrated living-app forms still
   carry (.form-control / .form-select / .form-floating / .form-text / label) — no
   markup change. Only reaches pages that load av-components.css (living-app), so
   the un-migrated dashboard-shell create/setup pages keep their own Bootstrap
   styling untouched. Design: top-set eyebrow label over a surface-raise input. */

.form-control,
.form-select,
select.form-control,
textarea.form-control {
  display: block;
  width: 100%;
  padding: 11px 14px;
  background: var(--av-surface-raise);
  color: var(--av-text);
  font-family: var(--av-font-body);
  font-size: 0.9375rem;
  line-height: 1.4;
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius);
  transition: border-color 0.18s var(--av-ease-out), box-shadow 0.18s var(--av-ease-out);
  -webkit-appearance: none;
  appearance: none;
}
.form-control::placeholder { color: var(--av-text-muted); opacity: 0.55; }

.form-control:focus,
.form-select:focus,
select.form-control:focus,
textarea.form-control:focus {
  outline: none;
  border-color: var(--av-orange);
  box-shadow: 0 0 0 2px var(--av-orange-bg);
}

.form-control:disabled,
.form-select:disabled,
select.form-control:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Custom chevron (appearance:none removed the native one). Neutral gray reads on
   both themes; selects get extra right padding to clear it. */
.form-select,
select.form-control {
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23999999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

/* Top-set label: Bootstrap markup is [input, label]; column-reverse stacks the
   label on top. Resets Bootstrap's floating-label absolute positioning. */
.form-floating {
  display: flex;
  flex-direction: column-reverse;
  margin-bottom: var(--av-space-5);
}
.form-floating:has(+ .form-text) { margin-bottom: var(--av-space-2); }
.form-floating > label {
  position: static;
  transform: none;
  height: auto;
  padding: 0;
  margin: 0 0 var(--av-space-2);
  pointer-events: auto;
  font-family: var(--av-font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--av-text-muted);
}

/* Helper / hint line under a field. */
.form-text {
  display: block;
  margin-top: var(--av-space-2);
  margin-bottom: var(--av-space-5);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--av-text-muted);
}
.form-text a { color: var(--av-orange); text-decoration: none; }
.form-text a:hover { text-decoration: underline; }

/* Checkboxes & radios. Living-app markup is [label, input] (label first in the DOM,
   like .form-floating), so the control is pulled left with order:-1 rather than
   relying on source order. Custom control matches the input vocabulary: surface-raise
   fill, hairline border, orange when checked, orange focus ring. */
.form-check {
  display: flex;
  align-items: center;
  gap: var(--av-space-2);
  margin-bottom: var(--av-space-2);
}
.form-check-inline {
  display: inline-flex;
  margin-right: var(--av-space-5);
}
.form-check-input {
  order: -1;            /* control sits left of the DOM-after label */
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 0;
  background-color: var(--av-surface-raise);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 64%;
  border: 1px solid var(--av-border);
  border-radius: 4px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.18s var(--av-ease-out), background-color 0.18s var(--av-ease-out), box-shadow 0.18s var(--av-ease-out);
}
.form-check-input[type="radio"] { border-radius: 50%; }
.form-check-input:focus {
  outline: none;
  border-color: var(--av-orange);
  box-shadow: 0 0 0 2px var(--av-orange-bg);
}
.form-check-input:checked {
  background-color: var(--av-orange);
  border-color: var(--av-orange);
}
.form-check-input:checked[type="checkbox"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3.5 8.5 6.5 11.5 12.5 4.5'/%3E%3C/svg%3E");
}
.form-check-input:checked[type="radio"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3.4' fill='%23ffffff'/%3E%3C/svg%3E");
  background-size: 100%;
}
.form-check-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.form-check-label {
  font-family: var(--av-font-body);
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--av-text);
  cursor: pointer;
}

/* In-card sub-group: fieldset wraps a labelled group, legend is the group label.
   Styled as an eyebrow (matches .form-floating > label) with a hairline rule so it
   reads as a divider inside a card. (hooks/create "Advanced configuration" — drop the
   .av-section-sub stopgap from the legend to pick this up.) */
fieldset {
  min-width: 0;
  margin: 0 0 var(--av-space-5);
  padding: 0;
  border: 0;
}
legend {
  width: 100%;
  float: none;          /* reset the browser-default legend layout */
  margin: 0 0 var(--av-space-4);
  padding: 0 0 var(--av-space-2);
  font-family: var(--av-font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--av-text-muted);
  border-bottom: 1px solid var(--av-border);
}


/* ── ALERTS ───────────────────────────────────────────────────────────────── */
/* av treatment of the Bootstrap alert classes the `alerts` mixin + the migrated
   wizard carry. The functional `.d-none` initial-hide is server/JS-driven and is
   defined here too — without it, adding .alert styling would surface the three
   empty pre-rendered alert containers on every page. Keep `.d-none` verbatim. */
.d-none { display: none !important; }

.alert {
  margin: var(--av-space-2) 0;
  padding: var(--av-space-3) var(--av-space-4);
  border: 1px solid var(--av-border);
  border-left-width: 3px;
  border-radius: var(--av-radius);
  background: var(--av-surface-raise);
  color: var(--av-text);
  font-size: 0.9375rem;
  line-height: 1.55;
}
.alert strong { font-family: var(--av-font-display); font-weight: 600; }
.alert a { color: var(--av-orange); text-decoration: none; }
.alert a:hover { text-decoration: underline; }

.alert-success { border-left-color: var(--av-live-green); background: var(--av-live-green-bg); }
.alert-warning { border-left-color: var(--av-orange);     background: var(--av-orange-bg); }
.alert-danger  { border-left-color: var(--av-danger);     background: var(--av-danger-bg); }
.alert-info    { border-left-color: var(--av-elephant); } /* no blue token — neutral accent on base surface */


/* ── FOOTER CTA ───────────────────────────────────────────────────────────── */

.av-footer-cta {
  padding: var(--av-space-10) 0;
  text-align: center;
}

.av-footer-cta__inner {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: 0 var(--av-space-5);
}

.av-footer-cta__heading {
  font-family: var(--av-font-display);
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  font-weight: 700;
  color: var(--av-text);
  margin: 0 0 var(--av-space-4);
  line-height: 1.2;
}

.av-footer-cta__sub {
  font-size: 1.0625rem;
  color: var(--av-text-muted);
  max-width: 480px;
  margin: 0 auto var(--av-space-7);
  line-height: 1.65;
}


/* ── FOOTER BAR ───────────────────────────────────────────────────────────── */

.av-footer__bar {
  border-top: 1px solid var(--av-border);
  padding: var(--av-space-5) 0;
  background: var(--av-surface);
}

.av-footer__bar-inner {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: 0 var(--av-space-5);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--av-space-4);
}

.av-footer__brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  flex-shrink: 0;
}
.av-footer__brand-logo {
  height: 26px;
  width: auto;
  display: block;
}
/* Theme-swap: keep the orange readable on either surface (dark default / light). */
.av-footer__brand-logo--light { display: none; }
[data-theme="light"] .av-footer__brand-logo--dark { display: none; }
[data-theme="light"] .av-footer__brand-logo--light { display: block; }

.av-footer__legal {
  display: flex;
  align-items: center;
  gap: var(--av-space-4);
  flex-wrap: wrap;
}

.av-footer__legal-link {
  font-size: 0.8125rem;
  color: var(--av-text-muted);
  text-decoration: none;
  transition: color 0.15s;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.av-footer__legal-link:hover { color: var(--av-text); }

.av-footer__copy {
  font-size: 0.8rem;
  color: var(--av-text-muted);
  margin: 0 0 0 auto;
}

@media (max-width: 600px) {
  .av-footer__bar-inner { flex-direction: column; align-items: flex-start; }
  .av-footer__copy { margin-left: 0; }
}

/* Risk Disclosure — its own quiet, faded compliance footnote below the footer
   bar, not bare text competing for attention. */
.av-footer__disclosure {
  background: var(--av-bg);
  border-top: 1px solid var(--av-border);
}
.av-footer__disclosure-inner {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: var(--av-space-4) var(--av-space-5);
  opacity: 0.7;
}
.av-footer__disclosure-title {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--av-text-muted);
  margin: 0 0 var(--av-space-2);
}
.av-footer__disclosure-inner p {
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--av-text-muted);
  margin: 0;
}


/* ── NAV LOGIN (secondary action) ─────────────────────────────────────────── */

.av-nav__login {
  font-family: var(--av-font-display);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--av-text-muted);
  text-decoration: none;
  transition: color 0.15s;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.av-nav__login:hover { color: var(--av-text); }

/* Drop the login text link on very small screens to keep the action row uncluttered. */
@media (max-width: 480px) {
  .av-nav__login { display: none; }
}


/* ── LEGAL DISCLOSURES (compliance small-print) ───────────────────────────── */

.av-legal {
  border-top: 1px solid var(--av-border);
  background: var(--av-bg);
  padding: var(--av-space-7) 0;
}

.av-legal__inner {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: 0 var(--av-space-5);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--av-space-5);
}

.av-legal__title {
  font-family: var(--av-font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--av-text-muted);
  margin: 0 0 var(--av-space-2);
}

.av-legal__body {
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--av-text-muted);
  opacity: 0.85;
  margin: 0;
}
.av-legal__body p { margin: 0; }


/* ── FRONTIER STRIP (promoted from av-living-landing.css — shared by landing
   AND logged-in app pages; landing retains its copy for zero regression risk) ── */

.av-frontier {
  padding: var(--av-space-10) 0;
  background: var(--av-surface);
  border-top: 1px solid var(--av-border);
  border-bottom: 1px solid var(--av-border);
  position: relative;
  overflow: hidden;
}

/* Subtle angular glow in the background */
.av-frontier::before {
  content: '';
  position: absolute;
  top: -60%;
  right: -10%;
  width: 500px;
  height: 500px;
  background: radial-gradient(circle, rgba(252, 114, 19, 0.08) 0%, transparent 70%);
  pointer-events: none;
}

.av-frontier__inner {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--av-space-5);
  text-align: center;
  position: relative;
  z-index: 1;
}

.av-frontier__badge {
  display: inline-block;
  background: rgba(252, 114, 19, 0.12);
  color: var(--av-orange);
  border: 1px solid rgba(252, 114, 19, 0.3);
  border-radius: 100px;
  padding: var(--av-space-1) var(--av-space-4);
  font-family: var(--av-font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: var(--av-space-5);
}


/* ── AV MODAL (native <dialog>) ───────────────────────────────────────────── */

/* Resets browser default <dialog> positioning; av-modal.js calls showModal()
   which centres it via top-layer. Backdrop via ::backdrop. */
dialog.av-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  padding: 0;
  background: var(--av-surface);
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius-lg);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
  width: min(560px, calc(100vw - var(--av-space-6)));
  max-height: calc(100vh - var(--av-space-6));
  overflow-y: auto;
  color: var(--av-text);
  font-family: var(--av-font-body);
  /* Open animation — tasteful fade-up */
  opacity: 0;
  translate: 0 8px;
  transition: opacity 0.2s var(--av-ease-out),
              translate 0.2s var(--av-ease-out);
}

/* Entry state: dialog is open */
dialog.av-modal[open] {
  opacity: 1;
  translate: 0 0;
}

/* @starting-style — from-invisible for browsers that support it (Chrome 117+, Firefox 129+) */
@starting-style {
  dialog.av-modal[open] {
    opacity: 0;
    translate: 0 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  dialog.av-modal,
  dialog.av-modal[open] {
    transition: none;
    translate: 0 0;
    opacity: 1;
  }
}

/* Backdrop — dim + subtle blur matching av dark-first aesthetic */
dialog.av-modal::backdrop {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* Header */
.av-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--av-space-5) var(--av-space-6);
  border-bottom: 1px solid var(--av-border);
}

.av-modal__title {
  margin: 0;
  font-family: var(--av-font-display);
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--av-text);
}

.av-modal__close {
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--av-text-muted);
  padding: var(--av-space-1) var(--av-space-2);
  border-radius: var(--av-radius);
  transition: color 0.15s, background 0.15s;
  min-height: 36px;
  min-width: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.av-modal__close:hover {
  color: var(--av-text);
  background: var(--av-surface-raise);
}

/* Body */
.av-modal__body {
  padding: var(--av-space-5) var(--av-space-6);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--av-text);
}

.av-modal__body .list-group {
  padding-left: 0;
  margin: var(--av-space-4) 0;
  list-style: none;
}

.av-modal__body .list-group-item {
  padding: var(--av-space-3) 0;
  border: none;
  border-bottom: 1px solid var(--av-border);
  background: transparent;
  font-size: 0.9rem;
  color: var(--av-text-muted);
  line-height: 1.55;
}
.av-modal__body .list-group-item:last-child {
  border-bottom: none;
}
.av-modal__body .list-group-item strong {
  color: var(--av-text);
}

.av-modal__body .text-muted {
  color: var(--av-text-muted);
  font-size: 0.8125rem;
}

.av-modal__body a {
  color: var(--av-orange);
  text-decoration: none;
}
.av-modal__body a:hover {
  text-decoration: underline;
}

/* Footer */
.av-modal__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--av-space-3);
  padding: var(--av-space-4) var(--av-space-6);
  border-top: 1px solid var(--av-border);
}

/* Light theme overrides — surface tokens auto-switch; box-shadow lightens */
[data-theme="light"] dialog.av-modal {
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
}

[data-theme="light"] dialog.av-modal::backdrop {
  background: rgba(0, 0, 0, 0.35);
}

.av-frontier__heading {
  font-family: var(--av-font-display);
  font-size: clamp(1.75rem, 4.5vw, 2.75rem);
  font-weight: 700;
  line-height: 1.15;
  color: var(--av-text);
  margin: 0 0 var(--av-space-5);
}

.av-frontier__heading-accent {
  color: var(--av-orange);
}

.av-frontier__body {
  font-size: 1.0625rem;
  color: var(--av-text-muted);
  line-height: 1.65;
  margin: 0 0 var(--av-space-7);
  max-width: 560px;
  margin-left: auto;
  margin-right: auto;
}

.av-frontier__cta-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--av-space-4);
  flex-wrap: wrap;
}


/* ── PULSE STATUS (promoted from av-living-landing.css — shared component) ── */

.av-pulse__status {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--av-space-2);
  font-size: 0.8125rem;
  color: var(--av-text-muted);
}

.av-pulse__status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--av-elephant);
  flex-shrink: 0;
  transition: background 0.3s;
}
/* live/offline states — JS toggles these classes (events.pug + any other page using
   this shared component) but no rule existed for either, so the dot silently never
   changed color anywhere in the app (operator-found, 2026-07-08). */
.is-live .av-pulse__status-dot {
  background: var(--av-live-green);
  box-shadow: 0 0 0 4px var(--av-live-green-bg);
  animation: av-pulse-live 2s ease-in-out infinite;
}
.is-live span:last-child { color: var(--av-live-green); }
.is-offline .av-pulse__status-dot {
  background: var(--av-danger);
  box-shadow: 0 0 0 4px var(--av-danger-bg);
}
.is-offline span:last-child { color: var(--av-danger); }
@keyframes av-pulse-live {
  0%, 100% { box-shadow: 0 0 0 4px var(--av-live-green-bg); }
  50% { box-shadow: 0 0 0 8px rgba(62, 201, 122, 0); }
}


/* ── APP SHELL + APP-SPECIFIC COMPONENTS ──────────────────────────────────── */

/* Logged-in page content wrapper. Mirrors .av-container (max-width, centred,
   horizontal padding) with top padding to clear the fixed nav. */
.av-app-shell {
  max-width: var(--av-max-w);
  margin: 0 auto;
  padding: calc(64px + var(--av-space-8)) var(--av-space-5) var(--av-space-9);
}

/* Softer card surface for secondary/supporting content blocks. Lower contrast
   than .av-card base; uses bg token instead of surface + a subtler border. */
.av-card--soft {
  background: var(--av-bg);
  border-color: var(--av-border);
  opacity: 0.85;
}

/* App nav modifier — logged-in context. Adds a subtle surface background to
   visually distinguish the app chrome from the public nav. */
.av-nav--app {
  background: var(--av-surface);
}

/* Primary action button in the nav — composes .av-btn--primary appearance.
   Sized to sit inside the nav bar without overflow. */
.av-nav__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--av-space-2);
  padding: 8px 18px;
  border-radius: var(--av-radius);
  font-family: var(--av-font-display);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  border: 2px solid var(--av-orange);
  background: var(--av-orange);
  color: #ffffff;
  transition: background 0.18s var(--av-ease-out),
              border-color 0.18s var(--av-ease-out);
  min-height: 36px;
  white-space: nowrap;
}
.av-nav__cta:hover {
  background: var(--av-orange-soft);
  border-color: var(--av-orange-soft);
}

/* Muted text-link in the app nav — mirrors .av-nav__link, de-emphasised via
   muted text color for secondary actions like Log out. */
.av-nav__logout {
  font-family: var(--av-font-display);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--av-text-muted);
  text-decoration: none;
  transition: color 0.15s;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  opacity: 0.75;
}
.av-nav__logout:hover {
  color: var(--av-text);
  opacity: 1;
}


/* ── WIZARD STEPS ─────────────────────────────────────────────────────────── */
/* Setup-wizard step indicator. Replaces the per-step Bootstrap circles + the inline
   `background:var(--av-orange,#hex)` stopgap with a tokenised component. States:
   .av-step--done (filled + check), .av-step--active (filled + ring), .av-step--upcoming
   (hollow). The connector rail fills orange through the active step; stacks to rows on
   narrow widths. Markup contract handed to autoview (markup = their lane). */
.av-steps {
  display: flex;
  align-items: flex-start;
  margin: var(--av-space-5) 0;
}
.av-step {
  flex: 1;
  min-width: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
/* Connector rail behind the markers; orange through the active step. Scoped to .av-steps
   (the wizard) so it does NOT leak onto the exchange page's .av-steps-grid > .av-step,
   which reuses the .av-step class for a different icon-card layout and was picking up a
   stray, mis-centred 18px rail across its 56px icons. */
.av-steps .av-step:not(:first-child)::before {
  content: "";
  position: absolute;
  top: 18px;
  right: 50%;
  width: 100%;
  height: 2px;
  background: var(--av-border);
}
.av-step--done::before,
.av-step--active::before { background: var(--av-orange); }

.av-step__marker {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--av-surface-raise);
  border: 1px solid var(--av-border);
  color: var(--av-text-muted);
  font-family: var(--av-font-display);
  font-weight: 700;
  font-size: 0.9rem;
}
.av-step--done .av-step__marker,
.av-step--active .av-step__marker {
  background: var(--av-orange);
  border-color: var(--av-orange);
  color: #ffffff;
}
.av-step--active .av-step__marker { box-shadow: 0 0 0 4px var(--av-orange-bg); }
.av-step__marker .material-icons { font-size: 1.15rem; }

.av-step__title {
  margin-top: var(--av-space-2);
  padding: 0 var(--av-space-1);
  font-family: var(--av-font-display);
  font-weight: 600;
  font-size: 0.8125rem;
  line-height: 1.3;
  color: var(--av-text);
}
.av-step--upcoming .av-step__title { color: var(--av-text-muted); }
.av-step__desc {
  margin-top: 2px;
  padding: 0 var(--av-space-1);
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--av-text-muted);
}

/* Narrow: stack to marker + (title over desc) rows; drop the rail (marker states
   carry done/active/upcoming). Grid so the marker spans both text rows on its left. */
@media (max-width: 600px) {
  .av-steps {
    flex-direction: column;
    align-items: stretch;
    gap: var(--av-space-4);
  }
  .av-step {
    flex: none;
    display: grid;
    grid-template-columns: 38px 1fr;
    column-gap: var(--av-space-3);
    align-items: center;
    text-align: left;
  }
  .av-steps .av-step:not(:first-child)::before { display: none; }
  .av-step__marker { grid-row: 1 / 3; align-self: center; }
  .av-step__title { grid-column: 2; grid-row: 1; align-self: end; margin-top: 0; padding: 0; }
  .av-step__desc { grid-column: 2; grid-row: 2; align-self: start; padding: 0; }
}


/* ── CONTENT LINKS ────────────────────────────────────────────────────────── */
/* Inline/content links anywhere on the site. Scoped to BARE <a> (no class) so
   component anchors (.av-btn, .av-nav__*, .av-card__* links) keep their own treatment.
   Fixes browser-default blue/purple links leaking into prose, on the logged-in app
   AND the public marketing/legal pages alike (was app-shell-only; a bare link in
   /platforms/ body copy had no rule covering it at all). */
a:not([class]) {
  color: var(--av-link);
  text-decoration: none;
}
a:not([class]):hover { text-decoration: underline; }
a:not([class]):visited { color: var(--av-link-visited); }

/* Back-link / breadcrumb — secondary nav (e.g. the setup-wizard "back to setup").
   Muted by default so it doesn't compete with the page title; brand-link colour on
   hover. Replaces the legacy Bootstrap .text-decoration-none + raw .material-icons. */
.av-back {
  display: inline-flex;
  align-items: center;
  gap: var(--av-space-1);
  margin-bottom: var(--av-space-4);
  font-family: var(--av-font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--av-text-muted);
  text-decoration: none;
  transition: color 0.15s var(--av-ease-out);
}
.av-back:hover { color: var(--av-link); }
.av-back__icon { font-size: 1rem; }


/* ── APP PAGE HEAD ────────────────────────────────────────────────────────── */
/* Dashboard-grade page header for the logged-in management views (replaces the
   marketing .av-section-heading + .av-section-sub hero). Compact title, one terse
   helper line, primary action inline-right, hairline divider. Stacks on narrow. */
.av-app-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--av-space-4);
  margin-bottom: var(--av-space-5);
  padding-bottom: var(--av-space-3);
  border-bottom: 1px solid var(--av-border);
}
.av-app-head__main { min-width: 0; }
.av-app-head__title {
  font-family: var(--av-font-display);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.2;
  margin: 0;
  color: var(--av-text);
}
.av-app-head__sub {
  margin: var(--av-space-1) 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--av-text-muted);
}
.av-app-head__actions {
  flex-shrink: 0;
  display: flex;
  gap: var(--av-space-2);
  align-items: center;
}
/* A status pulse used as the head action (events page) carries margin-left:auto for
   inline rows — neutralise it here so it doesn't push right / clip when stacked. */
.av-app-head__actions .av-pulse__status { margin-left: 0; }
@media (max-width: 600px) {
  .av-app-head { flex-direction: column; align-items: stretch; gap: var(--av-space-3); }
  .av-app-head__actions { flex-wrap: wrap; justify-content: flex-start; }
}
/* Safety net: any in-app section heading that isn't a page head (e.g. profile's
   in-page "Change passphrase" / "Delete account" sub-sections) reads at dashboard
   scale, not the marketing clamp — keeps sub-sections from out-sizing the page title. */
.av-app-shell .av-section-heading {
  font-size: 1.25rem;
  line-height: 1.25;
}


/* ── APP LOG / EVENT TABLE ────────────────────────────────────────────────── */
/* Dense, scannable event stream (replaces one-card-per-event in a grid). The
   #events sink becomes a <tbody>; displayEvents() still renders rows + insertAdjacentHTML
   into it. Columns: time / detail / actions. Rows hairline-separated, hover-raised. */
/* The ledger scrolls inside its own wrapper so a phone never scrolls the page
   sideways — the dense columns keep their widths and the wrapper takes the overflow. */
.av-log-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.av-log {
  width: 100%;
  border-collapse: collapse;
  /* ~10% up from the previous 0.875rem/14px (operator feedback, 2026-07-08:
     letter-spacing read uncomfortably tight at the old size) — 15px/16px is a
     whole pixel at the site's fixed 16px root, not a fractional one. */
  font-size: 0.9375rem;
}
.av-log--ledger { min-width: 720px; }
.av-log__head th {
  padding: 0 var(--av-space-3) var(--av-space-2);
  text-align: left;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--av-text-muted);
  border-bottom: 1px solid var(--av-border);
  white-space: nowrap;
}
.av-log td {
  padding: 10px var(--av-space-3);
  border-bottom: 1px solid var(--av-border);
  vertical-align: top;
}
/* Outcome lives on the row as a full-tint wash, not an edge accent — so it
   reaches wherever you're actually reading, not just a strip on the far left
   (operator feedback, 2026-07-08). Neutral/info rows (commands, comments) get
   no wash. "dry" (a successful non-live trade/cancel/close) is its own blue
   tier, distinct from "ok" (a real live fire) — a live order's dry preview and
   its live fire are two different rows and used to read as two different
   colors on the pre-migration dashboard (table-info vs table-success). One
   shared, deliberately bold alpha for both themes now (operator feedback,
   2026-07-08: light read too pastel/faded too, not just dark — an earlier
   pass only strengthened dark; see av-skin-default.css for the token). No row
   hover — didn't read as useful on a passive, colored log (operator call).*/
.av-log__row--ok     { background: var(--av-row-ok-bg); }
.av-log__row--dry    { background: var(--av-row-dry-bg); }
.av-log__row--danger { background: var(--av-row-danger-bg); }
.av-log__time {
  width: 1%;
  white-space: nowrap;
  color: var(--av-text-muted);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}
.av-log__type, .av-log__mode { width: 1%; white-space: nowrap; }
/* Type chip — identity, not outcome, so it doesn't compete with the row tint above.
   command gets an inverted fill (the old dashboard's table-dark made command rows
   visually distinct from every other type; this restores that distinctiveness
   without recoloring the whole row). Everything else is a plain outlined chip. */
.av-log-type-chip {
  display: inline-block;
  font-family: var(--av-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.8125rem;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--av-surface-raise);
  color: var(--av-text-muted);
  border: 1px solid var(--av-border);
}
.av-log-type-chip[data-type="command"] {
  background: var(--av-text);
  color: var(--av-bg);
  border-color: var(--av-text);
  font-weight: 600;
}
/* Mode — Live moved real money (green dot), Dry run is the preview, — is neither. */
.av-log-mode { font-size: 0.8125rem; font-weight: 600; }
.av-log-mode--live {
  display: inline-flex; align-items: center; gap: 6px; color: var(--av-live-green);
}
.av-log-mode--live::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--av-live-green); box-shadow: 0 0 0 3px var(--av-live-green-bg);
}
.av-log-mode--dry { color: var(--av-text-muted); font-weight: 500; }
/* "no mode" placeholder — a visual affordance, kept out of the HTML text so the
   dense ledger cell reads as a data table (empty cells look like missing data). */
.av-log-mode--na { color: var(--av-border); }
.av-log-mode--na::before { content: "\2013"; }
.av-log__detail {
  color: var(--av-text); line-height: 1.5; word-break: break-word;
}
.av-log__actions { width: 1%; white-space: nowrap; text-align: right; }
.av-log__empty { color: var(--av-text-muted); text-align: center; padding: var(--av-space-6); }

/* ── Connections page — exchange drawers + sections ───────────────────── */
.av-connection { padding: 0; overflow: hidden; }
.av-connection > .av-connection__face {
  list-style: none; cursor: pointer; display: block; padding: 1.25rem; position: relative;
}
.av-connection > .av-connection__face::-webkit-details-marker { display: none; }
/* Logo beside the title, not stacked above it (operator feedback, 2026-07-08 —
   supersedes the vertical layout below). A PLAIN horizontal row wrapped/collided
   with long exchange names ("Tradovate Simulation") at the 280px narrow end of
   the grid — the fix is align-items:flex-start (not center) so a wrapped title's
   second line has room under the fixed-size logo instead of fighting it, plus
   zeroing the icon's own bottom margin (sized for the old vertical stack) so its
   top edge lines up with the title's top edge instead of floating high. */
.av-connection__face-head { display: flex; align-items: flex-start; gap: var(--av-space-3); }
.av-connection__face-head .av-card__icon { margin-bottom: 0; flex-shrink: 0; }
.av-connection__face-title { min-width: 0; }
.av-connection__face-title .av-card__title { margin: 0; }
/* The eyebrow IS the credential's own name (shadow.name) — easy to forget you
   set it, or that more than one credential on the same exchange means more than
   one card. The label makes that legible without having to already know it.
   Its own full-width row below the logo+title, not nested inside the title
   column — left-aligned the same way Status is, not indented to the title's
   text start (operator feedback, 2026-07-08: "ignoring the logo left
   spacing" — the first pass kept it inside the title column, which visually
   tucked it in next to the logo instead of reading as its own line). */
.av-connection__eyebrow-row { margin: var(--av-space-2) 0 0; }
.av-connection__eyebrow-label { color: var(--av-text-muted); font-weight: 600; text-transform: none; letter-spacing: normal; }
.av-connection__face-foot { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: var(--av-space-4); }
/* av-pulse__status carries margin-left:auto for its other context (pushed to the
   far right of a wider header row); inside this narrower space-between footer
   that auto-margin ate all the free space and shoved BOTH the status AND Manage
   to the right edge together, collapsing the intended left/right split (operator
   caught this live against the actual page, 2026-07-08 — a bug my own "check the
   CSS" pass missed, since space-between alone was the wrong thing to check).
   Same zeroing already exists for .av-app-head__actions below, same fix here. */
.av-connection__face-foot .av-pulse__status { margin-left: 0; }
.av-connection__status-label { color: var(--av-text-muted); margin-right: 4px; }
/* "Needs a link" reuses is-offline (red) rather than the old neutral grey — an
   exchange with no webhook linked cannot fire, that is worth flagging the same
   way an actually-dropped connection is (operator: "why have it if it is not
   connected"). */
.av-connection__hooks { margin: var(--av-space-3) 0 0; font-size: 0.875rem; }
.av-connection__hooks-label { color: var(--av-text-muted); margin-right: 6px; }
.av-connection__hook-chip {
  display: inline-block; background: var(--av-surface-raise); border: 1px solid var(--av-border);
  border-radius: 4px; padding: 1px 8px; font-size: 0.8125rem; margin: 0 6px 4px 0;
}
.av-connection__toggle { font-weight: 600; opacity: .85; }
.av-connection__toggle::after { content: " \25be"; }
.av-connection[open] .av-connection__toggle::after { content: " \25b4"; }
.av-connection__drawer {
  /* more top space than the old 0 — was tightest exactly when there was the
     least else in the drawer (operator: "worse when there are no webhooks
     connected already... no top padding") */
  padding: 1rem 1.25rem 1.25rem; display: flex; flex-direction: column; gap: 1rem;
  border-top: 1px solid var(--av-border, rgba(255,255,255,.08));
}
.av-connection__subhead { margin: 0 0 .25rem; font-size: .95rem; opacity: .9; }
/* Credential actions (Edit/Remove key) get their own labeled block, ordered
   first — always-present/static identity info ahead of the more variable
   webhook-linking section below it (operator call). Previously these two
   concerns had no visual break between them at all. */
.av-connection__key-section { padding-bottom: .75rem; border-bottom: 1px solid var(--av-border); }
.av-connection__key-label { font-size: .8rem; color: var(--av-text-muted); margin: 0 0 .5rem; }
.av-connection__row-actions { display: inline-flex; gap: .4rem; margin-left: auto; }
.av-connection__link-form { display: flex; flex-direction: column; gap: .4rem; }
.av-connection__link-row { display: flex; gap: .5rem; align-items: center; }
.av-connection__link-row .av-input { flex: 1; }
.av-connection__actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* Unlinked-webhook activation callout */
.av-card--alert { border-color: var(--av-orange, #e0a030); }
.av-card__foot--alert { color: var(--av-orange, #e0a030); font-weight: 600; }

/* Small button + section-heading-with-action row */
.av-btn--xs { padding: .2rem .5rem; font-size: .8rem; }
.av-section-heading--row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.av-section-heading__label { flex: 1; }

/* Connections input field (av-input) — mirrors .form-control token set */
.av-input {
  display: block;
  width: 100%;
  padding: 11px 14px;
  background: var(--av-surface-raise);
  color: var(--av-text);
  font-family: var(--av-font-body);
  font-size: 0.9375rem;
  line-height: 1.4;
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius);
  transition: border-color 0.18s var(--av-ease-out), box-shadow 0.18s var(--av-ease-out);
  -webkit-appearance: none;
  appearance: none;
}
.av-input::placeholder { color: var(--av-text-muted); opacity: 0.55; }
.av-input:focus {
  outline: none;
  border-color: var(--av-orange);
  box-shadow: 0 0 0 2px var(--av-orange-bg);
}
.av-input:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Pagination wrapper (Activity Log events page) ─────────────────────────
   nav.av-pager wraps the Previous/Next .av-btn controls rendered by the
   pagination mustache template. The buttons style themselves; this centers
   and spaces the pair below the table. */
.av-pager {
  display: flex;
  justify-content: center;
  gap: var(--av-space-3);
  margin-top: var(--av-space-5);
}

/* ── Inline code sample (setup-wizard "send a test alert" block) ───────────
   Copy-paste alert template shown in wizard step 5. Mirrors the guide
   fenced-code treatment (av-guide.css .av-doc-prose pre) so command samples
   read the same across the wizard and the docs. Replaces the legacy
   .bg-dark.text-white.rounded.p-3.my-2.font-monospace.fs-6 chain. */
.av-code-sample {
  background: var(--av-surface-raise);
  border: 1px solid var(--av-border);
  border-radius: var(--av-radius);
  padding: var(--av-space-4) var(--av-space-5);
  margin: var(--av-space-2) 0;
  overflow-x: auto;
  color: var(--av-text);
  font-family: 'Courier New', Courier, monospace;
  font-size: 0.875rem;
  line-height: 1.6;
}
