/* ==========================================================================
   Design System Components — Clarity (Yozu)
   Token layer lives in app/assets/tailwind/tokens.css, driven by the
   [data-theme] attribute on <html>. This file defines component classes
   that consume those tokens via var(--token-name).

   Do NOT add new :root / :host token declarations here — extend tokens.css.
   ========================================================================== */


/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  transition: box-shadow var(--transition-normal),
              border-color var(--transition-normal),
              transform var(--transition-normal);
}

.card--elevated {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.card--interactive {
  cursor: pointer;
}
.card--interactive:hover {
  border-color: #d0d0d0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}
.card--interactive:active {
  transform: translateY(0);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}


/* --------------------------------------------------------------------------
   Stat Card
   -------------------------------------------------------------------------- */
.stat-card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  padding: 1.25rem 1.5rem;
  transition: box-shadow var(--transition-normal),
              border-color var(--transition-normal),
              transform var(--transition-normal);
  position: relative;
  overflow: hidden;
}
.stat-card:hover {
  border-color: #d0d0d0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}
.stat-card__label {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-tertiary);
  margin-bottom: 0.5rem;
}
.stat-card__value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-primary);
  letter-spacing: -0.02em;
}
.stat-card__delta {
  margin-top: 0.625rem;
}


/* --------------------------------------------------------------------------
   Delta Badge
   -------------------------------------------------------------------------- */
.delta-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: 100px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.5;
}
.delta-badge--positive {
  background: rgba(22, 163, 74, 0.08);
  color: #16a34a;
}
.delta-badge--negative {
  background: rgba(220, 38, 38, 0.08);
  color: #dc2626;
}
.delta-badge--neutral {
  background: rgba(0, 0, 0, 0.04);
  color: var(--text-tertiary);
}


/* --------------------------------------------------------------------------
   Data Tables
   -------------------------------------------------------------------------- */
.data-table-wrap {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  overflow: hidden;
}
/* Horizontal-scroll container INSIDE the chrome. Scrolling lives on its
   own element so toolbar rows (quick filter / title) can sit inside the
   card without scrolling with the table. */
.data-table-scroll {
  overflow-x: auto;
}
.data-table-wrap__header {
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--border-subtle);
}
.data-table-wrap__title {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
}

.data-table {
  width: 100%;
  border-collapse: collapse;
}
.data-table thead th {
  padding: 0.75rem 1.5rem;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
  position: sticky;
  top: 0;
  background: var(--surface-table-header);
  z-index: 1;
}
.data-table thead th.text-right {
  text-align: right;
}
.data-table tbody tr {
  border-bottom: 1px solid var(--border-subtle);
  transition: background var(--transition-fast);
}
.data-table tbody tr:last-child {
  border-bottom: none;
}
.data-table tbody tr:hover {
  background: var(--surface-hover);
}
.data-table tbody td {
  padding: 0.75rem 1.5rem;
  font-size: 0.875rem;
  color: var(--text-secondary);
}
.data-table tbody td.text-right {
  text-align: right;
}
.data-table tbody td .font-mono,
.data-table tbody td.font-mono {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8125rem;
  color: var(--text-primary);
}
.data-table .link {
  color: var(--text-primary);
  font-weight: 500;
  text-decoration: none;
  transition: color var(--transition-fast);
}
.data-table .link:hover {
  color: var(--accent-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Responsive table — card mode below md, sticky first column above md.
   (E10 td-9eaeb8)
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  /* Sticky first column on horizontal scroll for tabular layout. */
  .data-table tbody td:first-child,
  .data-table thead th:first-child {
    position: sticky;
    left: 0;
    background: var(--surface-card);
    z-index: 2;
  }
  .data-table thead th:first-child {
    background: var(--surface-table-header);
    z-index: 3;
  }
  /* Scroll-shadow on the right edge when the table overflows its
     wrapper. Without this, narrow viewports (~1024) clip the last
     column with no visual cue that more is scrollable. The gradient
     is local-attached on the surface and scroll-attached on the
     shadow — when the user reaches the right edge, the shadow rolls
     off-screen, indicating "no more content this way". */
  .data-table-scroll {
    background:
      linear-gradient(to right, var(--surface-card) 30%, transparent),
      linear-gradient(to left, var(--surface-card) 30%, transparent),
      linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent 30%),
      linear-gradient(to left, rgba(0, 0, 0, 0.08), transparent 30%);
    background-attachment: local, local, scroll, scroll;
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 24px 100%, 24px 100%, 12px 100%, 12px 100%;
  }
}

@media (max-width: 767px) {
  /* Stack each row as a card; visually hide the thead. */
  .data-table-scroll {
    overflow-x: visible;
  }
  .data-table,
  .data-table thead,
  .data-table tbody,
  .data-table tr,
  .data-table th,
  .data-table td {
    display: block;
    width: 100%;
  }
  .data-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }
  .data-table tbody tr {
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    margin: 0.5rem 0;
    padding: 0.5rem 0.75rem;
    background: var(--surface-card);
  }
  .data-table tbody td {
    border: none;
    padding: 0.375rem 0;
    text-align: left !important;
  }
  /* `data-label="Column"` rendered as a small caption before the cell
     content so users can identify the field without the header row. */
  .data-table tbody td[data-label]::before {
    content: attr(data-label) ":\00a0";
    display: inline;
    color: var(--text-secondary);
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-right: 0.25rem;
  }
}


/* --------------------------------------------------------------------------
   Data table shell — one unified card: toolbar + table + pagination.
   The shell carries the card chrome; the inner .data-table-wrap renders
   flush (no border/radius/shadow) so the pieces read as a single surface.
   -------------------------------------------------------------------------- */
.data-table-shell {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  overflow: hidden;
}
.data-table-wrap--flush {
  border: none;
  border-radius: 0;
  box-shadow: none;
}

/* Server-sorted column headers: the whole header cell is the link.
   The th drops its own padding so the link's hit area fills the cell. */
.data-table thead th.data-table__th--sort {
  padding: 0;
}
.data-table__sort-link {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  width: 100%;
  padding: 0.75rem 1.5rem;
  color: inherit;
  text-decoration: none;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.data-table__sort-link--numeric {
  justify-content: flex-end;
}
.data-table__sort-link:hover,
.data-table__sort-link:focus-visible {
  background: var(--surface-hover);
  color: var(--text-primary);
}
/* Sortable-but-inactive affordance: chevron-up-down fades in on hover/focus. */
.data-table__sort-hint {
  opacity: 0;
  transition: opacity var(--transition-fast);
}
.data-table__sort-link:hover .data-table__sort-hint,
.data-table__sort-link:focus-visible .data-table__sort-hint {
  opacity: 1;
}

/* Toolbar filter controls: native selects styled as compact dropdown
   buttons with an embedded funnel icon (left) and the form-select
   chevron (right). Scoped under .data-table-filter so this beats the
   .form-select base rule regardless of source order — .form-select's
   `padding` shorthand otherwise clobbers the left inset and the text
   renders underneath the funnel icon. padding-right must clear the
   chevron background-image (12px at right 0.625rem). */
.data-table-filter .data-table-filter__select {
  height: 36px;
  max-width: 13rem;
  padding: 0 2rem 0 1.9rem;
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.data-table-filter--active .data-table-filter__icon {
  color: var(--accent);
}
.data-table-filter--active .data-table-filter__select {
  border-color: var(--accent);
  color: var(--text-primary);
}

/* --------------------------------------------------------------------------
   Date range picker — popover above md, full-screen modal below md.
   (E10 td-669d1e)
   -------------------------------------------------------------------------- */
.date-picker-popover {
  min-width: 540px;
}

@media (max-width: 767px) {
  .date-picker-popover {
    /* Switch from popover to full-screen modal at the bottom of the
       viewport — the calendar gets the full available width. */
    position: fixed;
    inset: auto 0 0 0;
    top: auto;
    margin: 0;
    min-width: 0;
    width: 100vw;
    max-height: 90vh;
    overflow-y: auto;
    border-radius: 12px 12px 0 0;
    flex-direction: column;
    gap: 0.75rem;
    z-index: 50;
  }
  .date-picker-popover > ul {
    border-right: none;
    border-bottom: 1px solid var(--border-default);
    padding-right: 0;
    padding-bottom: 0.75rem;
    flex-direction: row;
    flex-wrap: wrap;
  }
  .date-picker-popover > ul li {
    flex: 1 1 calc(50% - 0.5rem);
  }
}


/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: 36px;
  padding: 0 1rem;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: all var(--transition-fast);
  text-decoration: none;
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}
.btn:active {
  transform: scale(0.98);
}
.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.btn--primary {
  background: var(--accent);
  color: #1a1a1a;
  font-weight: 600;
  border-color: var(--accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}

.btn--secondary {
  background: var(--surface-card);
  color: var(--text-secondary);
  border-color: var(--border-default);
}
.btn--secondary:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
  border-color: #d0d0d0;
}

.btn--ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}
.btn--ghost:hover {
  background: rgba(0, 0, 0, 0.04);
  color: var(--text-primary);
}

.btn--danger {
  background: transparent;
  color: #dc2626;
  border-color: rgba(220, 38, 38, 0.3);
}
.btn--danger:hover {
  background: rgba(220, 38, 38, 0.06);
  border-color: rgba(220, 38, 38, 0.5);
}

.btn--sm {
  height: 30px;
  padding: 0 0.625rem;
  font-size: 0.75rem;
  border-radius: 6px;
}

.btn--lg {
  height: 44px;
  padding: 0 1.5rem;
  font-size: 0.875rem;
}


/* --------------------------------------------------------------------------
   Form Controls
   -------------------------------------------------------------------------- */
.form-label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  margin-bottom: 0.375rem;
}

.form-input {
  width: 100%;
  height: 40px;
  padding: 0 0.75rem;
  font-size: 0.875rem;
  color: var(--text-primary);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  transition: border-color var(--transition-fast),
              box-shadow var(--transition-fast);
  outline: none;
}
.form-input::placeholder {
  color: var(--text-muted);
}
.form-input:hover {
  border-color: var(--border-strong);
}
.form-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
/* The accent border + soft glow above IS the focus indicator; the
   global *:focus-visible outline on top reads as a double box. */
.form-input:focus-visible,
.form-select:focus-visible {
  outline: none;
}
.form-input--mono {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8125rem;
}

.form-select {
  height: 36px;
  padding: 0 2rem 0 0.75rem;
  font-size: 0.8125rem;
  color: var(--text-primary);
  background-color: var(--surface-card);
  /* SVG arrow uses currentColor so it tracks --text-secondary in light
     and dark themes. Without this the arrow was hardcoded #8c8c8c which
     read fine on white but disappeared into the navy of dark cards. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5l3 3 3-3' stroke='currentColor' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.625rem center;
  border: 1px solid var(--border-default);
  border-radius: 8px;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: border-color var(--transition-fast),
              box-shadow var(--transition-fast);
  outline: none;
}
.form-select:hover {
  border-color: var(--border-strong);
}
.form-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}

.form-hint {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 0.25rem;
}


/* --------------------------------------------------------------------------
   Badges
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.625rem;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.5;
  border-radius: 100px;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.badge--success {
  background: rgba(22, 163, 74, 0.1);
  color: #16a34a;
}
.badge--warning {
  background: rgba(217, 119, 6, 0.1);
  color: #d97706;
}
.badge--danger {
  background: rgba(220, 38, 38, 0.1);
  color: #dc2626;
}
.badge--info {
  background: rgba(37, 99, 235, 0.1);
  color: #2563eb;
}
.badge--neutral {
  background: rgba(0, 0, 0, 0.05);
  color: var(--text-secondary);
}


/* --------------------------------------------------------------------------
   Page Header — layout is owned by Tailwind utilities on the
   _page_header component. The legacy .page-header / .page-header__title /
   .page-header__actions classes were dropped on 2026-05-15 because their
   `align-items: center; justify-content: space-between` on a flex column
   pushed the H1 to the horizontal centre of the page, breaking alignment
   with the content grid below.
   -------------------------------------------------------------------------- */

.section-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-tertiary);
  margin-bottom: 0.75rem;
}


/* --------------------------------------------------------------------------
   Sidebar
   -------------------------------------------------------------------------- */
.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: 16rem;
  display: flex;
  flex-direction: column;
  background: var(--surface-card);
  border-right: 1px solid var(--border-default);
  z-index: 40;
}

.sidebar__logo {
  /* Match the topbar's height (4rem) and divider (--border-default) so
     the sidebar-header and topbar bottom borders form one continuous
     line across the top of the app (UAT v2: misaligned top row). */
  min-height: 4rem;
  padding: 0.75rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  border-bottom: 1px solid var(--border-default);
}
.sidebar__logo-mark {
  width: 1.5rem;
  height: 1.5rem;
  flex: none;
}
.sidebar__logo-text {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: -0.02em;
}
.sidebar__logo-suffix {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--text-tertiary);
  margin-left: 0.125rem;
}

.sidebar__nav {
  flex: 1;
  padding: 0.5rem 0.75rem;
  overflow-y: auto;
}

.sidebar__section-label {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  padding: 1.25rem 0.75rem 0.375rem;
}

.sidebar__link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4375rem 0.75rem;
  margin-bottom: 1px;
  font-size: 0.8125rem;
  font-weight: 450;
  color: var(--text-sidebar);
  border-radius: 8px;
  text-decoration: none;
  transition: color var(--transition-fast),
              background var(--transition-fast);
}
.sidebar__link svg {
  flex-shrink: 0;
  opacity: 0.6;
}
.sidebar__link:hover svg,
.sidebar__link--active svg {
  opacity: 1;
}
.sidebar__link:hover {
  color: var(--text-sidebar-hover);
  background: var(--surface-hover);
}
.sidebar__link--active {
  color: var(--text-primary);
  background: var(--surface-bg);
  font-weight: 600;
}

.sidebar__user {
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border-subtle);
}
.sidebar__user-info {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-bottom: 0.375rem;
}
.sidebar__avatar {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--surface-bg);
  border: 1px solid var(--border-default);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.625rem;
  font-weight: 600;
  color: var(--text-secondary);
  flex-shrink: 0;
}
.sidebar__user-name {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-primary);
  line-height: 1.2;
}
.sidebar__user-account {
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  line-height: 1.2;
}
.sidebar__signout {
  display: block;
  padding: 0.25rem 0.75rem;
  margin-top: 0.25rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
  text-decoration: none;
  border-radius: 6px;
  transition: color var(--transition-fast),
              background var(--transition-fast);
}
.sidebar__signout:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}

/* Collapsible-section trigger (Insights / Performance views).
   Re-uses the .sidebar__section-label styling but adds a clickable
   trigger row with caret. */
.sidebar__group-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
}
.sidebar__group-trigger:hover .sidebar__section-label--clickable {
  color: var(--text-secondary);
}
.sidebar__section-label--clickable {
  cursor: pointer;
}
.sidebar__group-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem 0.75rem 0.375rem;
  color: var(--text-tertiary);
}
/* Rotate the (symmetric) glyph, NOT the padded span: the span's
   asymmetric vertical padding rotates with it and lifts the caret off
   the label's text line. The expanded state used to be the Tailwind
   class name `rotate-90` — once Tailwind 4 started emitting its own
   `.rotate-90 { rotate: 90deg }` utility, the two rotations composed
   to 180° (chevron pointed LEFT) and sat 14px high. Custom modifier
   class avoids the utility collision for good. */
.sidebar__group-caret svg {
  transition: transform var(--transition-fast);
}
.sidebar__group-caret--expanded svg {
  transform: rotate(90deg);
}

/* Accordion trigger caret: point down when the panel is open. Scoped to the
   `accordion-caret` marker class so other accordion icons are unaffected. */
[data-accordion-target="trigger"][aria-expanded="true"] .accordion-caret {
  transform: rotate(90deg);
}

/* User menu in the sidebar footer — replaces tiny "Settings"/"Sign out"
   text links with discoverable icon-and-label rows (audit §2.12). */
.sidebar__user-menu {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border-subtle);
}
.sidebar__user-action {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4375rem 0.75rem;
  width: 100%;
  font-size: 0.8125rem;
  font-weight: 450;
  color: var(--text-sidebar);
  border: 0;
  border-radius: 8px;
  background: transparent;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.sidebar__user-action svg {
  flex-shrink: 0;
  opacity: 0.6;
}
.sidebar__user-action:hover svg,
.sidebar__user-action--active svg {
  opacity: 1;
}
.sidebar__user-action:hover {
  color: var(--text-sidebar-hover);
  background: var(--surface-hover);
}
.sidebar__user-action--active {
  color: var(--text-primary);
  background: var(--surface-bg);
  font-weight: 600;
}
/* button_to wraps in a <form>; reset its margins so it lines up. */
.sidebar__user-menu form {
  margin: 0;
}

/* Account switcher (sidebar header). */
.sidebar__account-switcher {
  padding: 0.75rem 0.75rem 0.5rem;
  border-bottom: 1px solid var(--border-subtle);
}
.account-switcher {
  width: 100%;
}
.account-switcher--static {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.625rem;
  border-radius: 8px;
  background: var(--surface-bg);
  border: 1px solid var(--border-subtle);
}
.account-switcher__trigger {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.5rem 0.625rem;
  background: var(--surface-bg);
  border: 1px solid var(--border-subtle);
  border-radius: 8px;
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.account-switcher__trigger:hover {
  background: var(--surface-hover);
  border-color: var(--border-default);
}
.account-switcher__trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.account-switcher__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 6px;
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
}
.account-switcher__label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.2;
}
.account-switcher__hint {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  line-height: 1.2;
}
.account-switcher__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 0.3125rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-on);
  font-size: 0.625rem;
  font-weight: 600;
}
.account-switcher__menu {
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  z-index: 50;
  max-height: 18rem;
  overflow: hidden;
  flex-direction: column;
}
/* Same gotcha as .topbar__overflow-sheet — display:flex on the base
   wins over Tailwind's .hidden, so the menu would render permanently
   open. Scope the flex layout to the visible state. */
.account-switcher__menu:not(.hidden) {
  display: flex;
}
.account-switcher__search {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border-subtle);
}
.account-switcher__search-input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: 0;
  font-size: 0.8125rem;
  color: var(--text-primary);
}
.account-switcher__search-input::placeholder {
  color: var(--text-tertiary);
}
.account-switcher__list {
  list-style: none;
  margin: 0;
  padding: 0.25rem 0;
  overflow-y: auto;
  max-height: 14rem;
}
.account-switcher__item form {
  margin: 0;
}
.account-switcher__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  padding: 0.4375rem 0.75rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.account-switcher__row:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}
.account-switcher__row--current {
  background: var(--surface-bg);
  color: var(--text-primary);
  font-weight: 600;
  cursor: default;
}
.account-switcher__empty {
  padding: 0.625rem 0.75rem;
  font-size: 0.75rem;
  color: var(--text-tertiary);
}


/* --------------------------------------------------------------------------
   Topbar
   -------------------------------------------------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4rem;
  padding: 0.75rem 1.5rem;
  border-bottom: 1px solid var(--border-default);
  background: var(--surface-card);
}
.topbar__left { flex: 1; }
.topbar__right { position: relative; flex-shrink: 0; }
.topbar__title {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}

.topbar__hamburger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  margin-left: -0.5rem;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.topbar__hamburger:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
/* Mobile-only control. This sheet loads after the Tailwind build, so the
   display above would out-cascade the markup's `lg:hidden` at equal
   specificity — guard the breakpoint here too. */
@media (min-width: 1024px) {
  .topbar__hamburger {
    display: none;
  }
}

.topbar__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 2.25rem;
  padding: 0 0.5rem;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.8125rem;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.topbar__action:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
.topbar__action--stacked {
  width: 100%;
  justify-content: flex-start;
  padding: 0.5rem 0.75rem;
  height: auto;
}
.topbar__action-label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
/* Sized against the 1rem (w-4) bell glyph: at 18px the old badge
   swallowed the icon it was annotating. 14px + a surface-coloured ring
   reads as a count on the bell rather than a dot covering it. */
.topbar__action-badge {
  position: absolute;
  top: -0.3125rem;
  right: -0.4375rem;
  min-width: 0.875rem;
  height: 0.875rem;
  padding: 0 0.1875rem;
  border-radius: 999px;
  background: var(--status-danger);
  box-shadow: 0 0 0 2px var(--surface-card);
  color: #fff;
  font-size: 0.5625rem;
  font-weight: 700;
  line-height: 0.875rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.topbar__overflow-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 8px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.topbar__overflow-trigger:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
/* Mobile-only control — same cascade guard as .topbar__hamburger. */
@media (min-width: 768px) {
  .topbar__overflow-trigger {
    display: none;
  }
}
.topbar__overflow-sheet {
  position: absolute;
  top: 100%;
  right: 1rem;
  min-width: 14rem;
  margin-top: 0.25rem;
  padding: 0.5rem;
  flex-direction: column;
  gap: 0.125rem;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
  z-index: 40;
}
/* Layout switches to flex only when the controller removes `hidden`;
   leaving `display: flex` on the base would beat the .hidden utility
   (same specificity, base rule loaded later) and the sheet would be
   visible by default on every mobile page. */
.topbar__overflow-sheet:not(.hidden) {
  display: flex;
}
/* Hard-hide the overflow sheet at md+: mobile-only affordance.
   Without this, the absolutely-positioned sheet sits behind the inline
   actions and intercepts pointer events even when the trigger is
   md:hidden. A media-query rule beats the inline `display: flex` above. */
@media (min-width: 768px) {
  .topbar__overflow-sheet {
    display: none !important;
    pointer-events: none;
  }
}

.topbar__kbd-hint {
  display: inline-flex;
  align-items: center;
  gap: 0.125rem;
}
.topbar__kbd {
  display: inline-flex;
  align-items: center;
  padding: 0 0.25rem;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.625rem;
  color: var(--text-tertiary);
  background: var(--surface-bg);
  border: 1px solid var(--border-subtle);
  border-radius: 4px;
  line-height: 1.4;
}


/* --------------------------------------------------------------------------
   Chart Card
   -------------------------------------------------------------------------- */
.chart-card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  padding: 1.5rem;
}
.chart-card__title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}
/* Cap chart canvas height inside chart-card so Chart.js (with
   maintainAspectRatio: false) gets a finite container box at every
   breakpoint. (E10 td-58d95a) */
.chart-card > [id^="chart-"] {
  position: relative;
  height: 18rem;
  max-height: 18rem;
  width: 100%;
}
.chart-card > [id^="chart-"] > canvas {
  max-height: 100% !important;
}


/* --------------------------------------------------------------------------
   Quick Link Card
   -------------------------------------------------------------------------- */
.quick-link {
  display: block;
  padding: 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  text-decoration: none;
  transition: all var(--transition-normal);
  position: relative;
  overflow: hidden;
}
.quick-link::after {
  content: '';
  position: absolute;
  right: 1.5rem;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  opacity: 0;
  transition: opacity var(--transition-normal), transform var(--transition-normal);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M7 4l6 6-6 6' stroke='%231a1a1a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.quick-link:hover {
  border-color: #d0d0d0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
}
.quick-link:hover::after {
  opacity: 0.4;
  transform: translateY(-50%) translateX(2px);
}
.quick-link__title {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 0.5rem;
  transition: color var(--transition-fast);
}
.quick-link:hover .quick-link__title {
  color: var(--text-primary);
}
.quick-link__value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.2;
  letter-spacing: -0.02em;
}
.quick-link__desc {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 0.375rem;
}


/* --------------------------------------------------------------------------
   Flash Messages
   -------------------------------------------------------------------------- */
.flash {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border-radius: 10px;
  font-size: 0.8125rem;
  line-height: 1.5;
  margin-bottom: 1.5rem;
  border: 1px solid transparent;
  animation: flash-enter 0.3s var(--ease-out-expo);
}
@keyframes flash-enter {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}
.flash--notice {
  background: rgba(22, 163, 74, 0.06);
  border-color: rgba(22, 163, 74, 0.15);
  color: #16a34a;
}
.flash--alert {
  background: rgba(220, 38, 38, 0.06);
  border-color: rgba(220, 38, 38, 0.15);
  color: #dc2626;
}
.flash__icon {
  flex-shrink: 0;
  margin-top: 0.0625rem;
}
.flash__message {
  flex: 1;
}
.flash__dismiss {
  flex-shrink: 0;
  padding: 0.25rem;
  color: inherit;
  opacity: 0.5;
  cursor: pointer;
  background: none;
  border: none;
  border-radius: 4px;
  transition: opacity var(--transition-fast);
  line-height: 1;
}
.flash__dismiss:hover {
  opacity: 0.9;
}


/* --------------------------------------------------------------------------
   Login
   -------------------------------------------------------------------------- */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-bg);
}
.login-card {
  width: 100%;
  max-width: 400px;
  padding: 2.5rem;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 16px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  position: relative;
  z-index: 1;
}
.login-card__brand {
  text-align: center;
  margin-bottom: 2rem;
}
.login-card__logo {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: -0.02em;
}
.login-card__logo-suffix {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-left: 0.25rem;
}
.login-card__title {
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-top: 0.5rem;
}


/* --------------------------------------------------------------------------
   Pagination
   -------------------------------------------------------------------------- */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.5rem;
}
.pagination__btn {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  text-decoration: none;
  transition: all var(--transition-fast);
}
.pagination__btn:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
  border-color: #d0d0d0;
}
.pagination__info {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
  padding: 0 0.5rem;
}


/* --------------------------------------------------------------------------
   Alert Card
   -------------------------------------------------------------------------- */
.alert-card {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.25rem 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-left: 4px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  transition: box-shadow var(--transition-normal),
              border-color var(--transition-normal);
}
.alert-card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.alert-card--acknowledged {
  opacity: 0.45;
}
.alert-card__indicator {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-top: 0.375rem;
}
.alert-card__indicator--critical {
  background: #dc2626;
}
.alert-card:has(.alert-card__indicator--critical) {
  border-left-color: #dc2626;
}
.alert-card__indicator--warning {
  background: #d97706;
  animation: pulse-glow 2s ease-in-out infinite;
}
.alert-card:has(.alert-card__indicator--warning) {
  border-left-color: #d97706;
}
.alert-card__indicator--info {
  background: #2563eb;
}
.alert-card:has(.alert-card__indicator--info) {
  border-left-color: #2563eb;
}
@keyframes pulse-glow {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
.alert-card__body {
  flex: 1;
  min-width: 0;
}
.alert-card__header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}
.alert-card__title {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text-primary);
}
.alert-card__time {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  white-space: nowrap;
}
.alert-card__message {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  margin-top: 0.375rem;
  line-height: 1.5;
}


/* --------------------------------------------------------------------------
   Conversion Funnel
   -------------------------------------------------------------------------- */
.funnel-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.funnel-bar__label {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  width: 7rem;
  flex-shrink: 0;
}
.funnel-bar__track {
  flex: 1;
  height: 1.75rem;
  background: var(--surface-bg);
  border-radius: 6px;
  overflow: hidden;
}
.funnel-bar__fill {
  height: 100%;
  background: linear-gradient(90deg, rgba(45, 212, 191, 0.15) 0%, rgba(45, 212, 191, 0.3) 100%);
  border-radius: 6px;
  transition: width 0.6s var(--ease-out-expo);
}
.funnel-bar__value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8125rem;
  color: var(--text-primary);
  width: 5rem;
  text-align: right;
  flex-shrink: 0;
}


/* --------------------------------------------------------------------------
   Detail Section (Lead/Campaign Show)
   -------------------------------------------------------------------------- */
.detail-card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  padding: 1.5rem;
}
.detail-card__heading {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
  margin-bottom: 1.25rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--border-subtle);
}
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.25rem;
}
.detail-grid dt {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-bottom: 0.25rem;
}
.detail-grid dd {
  font-size: 0.875rem;
  color: var(--text-primary);
}
.detail-grid dd.font-mono {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8125rem;
}


/* --------------------------------------------------------------------------
   Timeline
   -------------------------------------------------------------------------- */
.timeline {
  position: relative;
}
.timeline__item {
  display: flex;
  gap: 0.875rem;
  padding-bottom: 1.25rem;
  position: relative;
}
.timeline__item:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 4.5px;
  top: 1.25rem;
  bottom: 0;
  width: 1px;
  background: var(--border-subtle);
}
.timeline__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
  margin-top: 0.375rem;
}
.timeline__content {
  flex: 1;
}
.timeline__event {
  font-size: 0.875rem;
  color: var(--text-primary);
  font-weight: 500;
}
.timeline__date {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.6875rem;
  color: var(--text-tertiary);
  margin-top: 0.125rem;
}


/* --------------------------------------------------------------------------
   Metric Row (Reports sidebar)
   -------------------------------------------------------------------------- */
.metric-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.375rem 0;
}
.metric-row__label {
  font-size: 0.8125rem;
  color: var(--text-tertiary);
}
.metric-row__value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8125rem;
  color: var(--text-primary);
  font-weight: 500;
}


/* --------------------------------------------------------------------------
   Empty State
   -------------------------------------------------------------------------- */
.empty-state {
  text-align: center;
  padding: 4rem 2rem;
  color: var(--text-tertiary);
}
.empty-state__icon {
  margin-bottom: 1rem;
  opacity: 0.4;
}
.empty-state__text {
  font-size: 0.875rem;
}


/* --------------------------------------------------------------------------
   Prose overrides (Markdown rendering in light theme)
   -------------------------------------------------------------------------- */
.prose {
  color: var(--text-primary);
}
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
  color: var(--text-primary);
  font-family: "Space Grotesk", ui-sans-serif, system-ui, sans-serif;
}
.prose p, .prose li {
  color: var(--text-secondary);
}
.prose a {
  color: var(--accent-dim);
}
.prose code {
  color: var(--text-primary);
  background: rgba(0, 0, 0, 0.05);
  padding: 0.125rem 0.375rem;
  border-radius: 4px;
  font-size: 0.875em;
}
.prose pre {
  background: #1a1a1a;
  color: #e0e0e0;
  border-radius: 8px;
}
.prose blockquote {
  border-left-color: var(--accent);
  color: var(--text-secondary);
}
.prose strong {
  color: var(--text-primary);
}
.prose table th {
  color: var(--text-secondary);
}
.prose hr {
  border-color: var(--border-subtle);
}


/* --------------------------------------------------------------------------
   Global / Misc
   -------------------------------------------------------------------------- */

/* Scrollbar — theme-aware. Mixing from --text-primary keeps the thumb
   visible on both themes (the old black rgba vanished on dark pages). */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text-primary) 16%, transparent);
  border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--text-primary) 28%, transparent);
}

/* Focus visible global — keyboard-only focus indicator using the
   tokenised --ring-focus colour (45% opacity accent in light theme,
   55% in dark per tokens.css). 2px outline + offset reads on every
   surface; border-radius: inherit means rounded controls keep their
   shape. focus-visible (not :focus) ensures mouse users don't see
   the ring on click. (E9 td-23edf1) */
*:focus-visible {
  outline: 2px solid var(--ring-focus);
  outline-offset: 2px;
  border-radius: inherit;
}

/* Dashboard staggered reveal (E11 td-ad6956). One orchestrated
   moment of motion on first paint: stat cards fade-in-and-up
   sequentially, 60ms between each via --motion-stagger. nth-child
   carries the per-card delay (no inline styles). Subsequent
   navigations also play this — keeping it once-per-page-load
   would need JS, and the cost isn't worth it for a 60ms x 6 hop. */
@media (prefers-reduced-motion: no-preference) {
  .stat-card-stagger > * {
    animation: stat-card-reveal var(--duration-normal) var(--ease-out-expo) both;
  }
  .stat-card-stagger > *:nth-child(1) { animation-delay: calc(var(--motion-stagger) * 0); }
  .stat-card-stagger > *:nth-child(2) { animation-delay: calc(var(--motion-stagger) * 1); }
  .stat-card-stagger > *:nth-child(3) { animation-delay: calc(var(--motion-stagger) * 2); }
  .stat-card-stagger > *:nth-child(4) { animation-delay: calc(var(--motion-stagger) * 3); }
  .stat-card-stagger > *:nth-child(5) { animation-delay: calc(var(--motion-stagger) * 4); }
  .stat-card-stagger > *:nth-child(6) { animation-delay: calc(var(--motion-stagger) * 5); }
  .stat-card-stagger > *:nth-child(7) { animation-delay: calc(var(--motion-stagger) * 6); }
  .stat-card-stagger > *:nth-child(8) { animation-delay: calc(var(--motion-stagger) * 7); }
  @keyframes stat-card-reveal {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: none; }
  }
}

/* --------------------------------------------------------------------------
   Dashboard hero — the headline ROAS moment. A faint accent wash rising
   from the top-left corner separates it from the supporting stat grid
   without breaking the "accent sparingly" rule: it is pure token mix,
   <6% accent, and disappears gracefully on either theme.
   -------------------------------------------------------------------------- */
.dashboard-hero {
  background:
    radial-gradient(
      120% 140% at 0% 0%,
      color-mix(in srgb, var(--accent) 6%, transparent),
      transparent 55%
    ),
    var(--surface-card);
}

/* --------------------------------------------------------------------------
   Auth screens (sign in / two-factor) — first thing a client sees.
   Two soft radial accent glows on the page background give the brand
   moment some atmosphere; everything is token-mixed so both themes and
   forced-colors degrade to a plain page background.
   -------------------------------------------------------------------------- */
.auth-screen {
  background:
    radial-gradient(
      55rem 36rem at 18% -10%,
      color-mix(in srgb, var(--accent) 7%, transparent),
      transparent 60%
    ),
    radial-gradient(
      48rem 32rem at 105% 110%,
      color-mix(in srgb, var(--accent) 5%, transparent),
      transparent 55%
    ),
    var(--surface-bg);
}

/* Submit button loading state (E11 td-645ee5). When the
   submit_button Stimulus controller flips data-loading=true on a
   button, dim the label and tee up an inline spinner glyph via a
   pseudo-element so authors don't have to add markup per call site. */
button[data-loading="true"],
[data-loading="true"][role="button"] {
  pointer-events: none;
  opacity: 0.7;
  position: relative;
}
@media (prefers-reduced-motion: no-preference) {
  button[data-loading="true"]::after,
  [data-loading="true"][role="button"]::after {
    content: "";
    display: inline-block;
    width: 0.875em;
    height: 0.875em;
    margin-left: 0.5em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 600ms linear infinite;
    vertical-align: -2px;
  }
  @keyframes spin {
    to { transform: rotate(360deg); }
  }
}

/* Turbo view transitions for primary nav (E11 td-41dae2). Wrapped in
   motion-safe so reduced-motion users get instant page swaps. The
   @view-transition rule is no-op on Firefox / Safari today. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 200ms;
    animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
  }
}

/* Selection color — token-driven. The old rule forced near-black text
   (#1a1a1a), which made selected text unreadable in the dark theme.
   Tinting the background only and inheriting the text colour works on
   every surface in both themes. */
::selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}

/* ==========================================================================
   Funnel Pyramid
   ========================================================================== */

.funnel-pyramid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.funnel-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.funnel-stage__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.25rem;
  min-height: 3rem;
  color: #ffffff;
  font-size: 0.875rem;
  transition: width 0.4s ease;
  position: relative;
}

.funnel-stage:first-child .funnel-stage__bar {
  border-radius: 0.5rem 0.5rem 0 0;
}

.funnel-stage:last-child .funnel-stage__bar {
  border-radius: 0 0 0.5rem 0.5rem;
}

.funnel-stage__label {
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.01em;
}

.funnel-stage__value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 500;
  font-size: 0.875rem;
}

.funnel-stage__drop {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.25rem 0;
  font-size: 0.6875rem;
  color: #8c8c8c;
  font-family: "JetBrains Mono", ui-monospace, monospace;
}

/* ==========================================================================
   App shell + responsive sidebar / nav drawer
   ========================================================================== */

/* Default desktop layout: sidebar pinned to the left, content fills
   the remainder. The sidebar partial uses position: fixed already, so
   we reserve its 16rem with a left margin on the content column. */
.app-shell {
  min-height: 100vh;
}
.app-shell__content {
  margin-left: 16rem;
  min-height: 100vh;
}

/* Below the lg breakpoint the sidebar slides off-canvas. */
.nav-drawer__panel {
  position: fixed;
  inset: 0 auto 0 0;
  width: 16rem;
  z-index: 60;
  transition: transform 0.2s ease;
}
.nav-drawer__panel .sidebar {
  position: relative;
  width: 100%;
  height: 100%;
  border-right: 1px solid var(--border-default);
}
.nav-drawer__scrim {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(2px);
  z-index: 50;
  transition: opacity var(--transition-normal);
}

@media (max-width: 1023px) {
  .app-shell__content {
    margin-left: 0;
  }
  .nav-drawer__panel--closed {
    transform: translateX(-100%);
  }
  .nav-drawer__panel--open {
    transform: translateX(0);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.32);
  }
  .topbar__title {
    font-size: 1rem;
  }
}

@media (min-width: 1024px) {
  /* On desktop the panel is always visible; ignore --closed/--open. */
  .nav-drawer__panel {
    transform: none !important;
    z-index: 40;
  }
  .nav-drawer__scrim {
    display: none !important;
  }
}

/* Body scroll lock for mobile drawer (audit §1.5). */
.body-scroll-locked {
  overflow: hidden;
  touch-action: none;
}

/* ==========================================================================
   Budget scenario slider (Budget Planner what-if planner)
   --------------------------------------------------------------------------
   Token-styled <input type="range">: accent fill up to the thumb via the
   --scenario-fill custom property (set by budget_scenario_controller.js —
   no inline style in ERB), neutral remainder, accent thumb that lifts on
   hover. The midpoint marker is static CSS: the slider range is fixed at
   50%–150% of the current budget, so "current" is always the centre.
   ========================================================================== */
.scenario-slider {
  position: relative;
  padding-block: 2px;
}

.scenario-range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 6px;
  border-radius: 9999px;
  background: linear-gradient(
    to right,
    var(--accent) var(--scenario-fill, 50%),
    var(--border-default) var(--scenario-fill, 50%)
  );
  outline: none;
  cursor: pointer;
}

.scenario-range:focus-visible {
  box-shadow: 0 0 0 3px var(--ring-focus);
}

.scenario-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 9999px;
  background: var(--accent);
  border: 3px solid var(--surface-card);
  box-shadow: var(--shadow-card-hover);
  transition: transform var(--transition-fast);
}

.scenario-range::-webkit-slider-thumb:hover,
.scenario-range::-webkit-slider-thumb:active {
  transform: scale(1.15);
}

.scenario-range::-moz-range-track {
  background: transparent;
}

.scenario-range::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 9999px;
  background: var(--accent);
  border: 3px solid var(--surface-card);
  box-shadow: var(--shadow-card-hover);
  transition: transform var(--transition-fast);
}

.scenario-range::-moz-range-thumb:hover {
  transform: scale(1.15);
}

/* Tick marking the current budget — always the track midpoint (see above). */
.scenario-slider__marker {
  position: absolute;
  left: 50%;
  top: -2px;
  bottom: -2px;
  width: 2px;
  border-radius: 1px;
  transform: translateX(-50%);
  background: var(--text-tertiary);
  opacity: 0.6;
  pointer-events: none;
}

/* Stat readout pulse on slider release (change event). Motion-gated so
   reduced-motion users get an instant value swap with no scaling. */
@keyframes scenario-stat-pulse {
  0% { transform: scale(1); }
  35% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

.scenario-stat__value {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  transform-origin: left center;
}

@media (prefers-reduced-motion: no-preference) {
  .scenario-stat__value--pulse {
    animation: scenario-stat-pulse 240ms var(--ease-out-expo);
  }
}

/* Reduced-motion safety net (E11 td-ef0ef3). Existing rules (skeleton
   shimmer, view-transitions, stat-card stagger, submit-button spinner)
   are already wrapped in motion-safe queries. This blanket rule
   neutralises any remaining unguarded transitions / animations so a
   reduced-motion user never sees easing or keyframe motion — state
   changes happen instantly without breaking functionality. WCAG 2.1
   SC 2.3.3 Animation from Interactions. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  /* Essential progress indicators are the WCAG 2.3.3 exception: a
     frozen spinner reads as "nothing is happening" (the AI first-draft
     spinner appeared broken to reduced-motion users). Slow the spin
     right down instead of freezing it. `spin` keyframes come from the
     Tailwind build. */
  .progress-spinner {
    animation: spin 2s linear infinite !important;
  }
}

/* Floating "Quote" chip (comment_quote_controller): appears above a
   text selection in the report body; inserts the selection into the
   discussion composer as a blockquote. Position (top/left) is set at
   runtime from the selection rect. */
.comment-quote-chip {
  position: absolute;
  transform: translateX(-50%);
  z-index: 30;
  padding: 0.25rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--accent-on);
  background: var(--accent);
  border-radius: 9999px;
  box-shadow: var(--shadow-dropdown);
  cursor: pointer;
}

.comment-quote-chip:hover {
  background: var(--accent-hover);
}

/* App-wide confirmation dialog (shared/_confirm_dialog +
   confirm_dialog.js) — replaces browser-native confirm(). Native
   <dialog> centred by UA styles; skinned with tokens. */
.confirm-dialog {
  /* Tailwind preflight zeroes margins, which breaks the UA's native
     dialog centring (margin: auto against inset: 0) — restore it. */
  margin: auto;
  background: var(--surface-card);
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-elevated);
  padding: 1.25rem 1.5rem;
  width: min(26rem, calc(100vw - 2rem));
}

.confirm-dialog::backdrop {
  background: rgb(0 0 0 / 0.5);
  backdrop-filter: blur(2px);
}

/* Comment author avatar — initials circle, same idiom as the sidebar
   avatar but sized for the thread. */
.comment-avatar {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--surface-elevated);
  border: 1px solid var(--border-default);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.comment-avatar--muted {
  color: var(--text-tertiary);
  border-style: dashed;
}

/* Comment bodies (Action Text .trix-content) — prose rhythm at chat
   scale; blockquote/list/code styling lives in trix_overrides.css. */
.comment-body > * + *,
.comment-body .trix-content > * + * {
  margin-top: 0.5rem;
}

/* Report editor height modes (editor_height_controller). Capped pins
   the shell to the viewport so the toolbar and AI chat input stay on
   screen and each pane scrolls internally; without it the shell grows
   with content (min-h only) and the page scrolls. Desktop-only — the
   stacked mobile layout always flows with the page. */
@media (min-width: 1024px) {
  .report-editor--capped {
    height: calc(100vh - 220px);
  }
}
