/* ==========================================================================
   getalias.email — design system
   --------------------------------------------------------------------------
   Reusable static building blocks for the Login Flow handoff bundle.
   Class names are deliberately short and semantic so screens stay readable.
   Theme tokens live on .surface and flip via prefers-color-scheme.
   ==========================================================================
   Sections
     1. Theme tokens (light + dark)
     2. Reset & base
     3. Layout primitives  (.surface, .stage, .app)
     4. Brand              (.brand, .brand-mark)
     5. Pills              (.pill, .code-pill)
     6. Buttons            (.btn, .btn-primary, .btn-secondary, .btn-ghost)
     7. Form fields        (.field, .input, .divider)
     8. Auth card          (.auth-card, .auth-icon, .oauth-grid)
     9. Sidebar            (.sidebar, .sidebar-nav, .sidebar-user)
    10. Main column        (.main, .main-head, .empty)
    11. Filter chips       (.chip-bar, .chip)
    12. Alias rows         (.alias-list, .alias-row, .alias-status, …)
    13. Alias detail panel (.alias-detail, .detail-summary, .detail-actions)
    14. Not-found page     (.glyph-404, .path-pill)
    23. Responsive — mobile top-bar (sidebar -> horizontal nav < 768px)
   ========================================================================== */


/* 0. LOCAL FONT FACES ====================================================== */
/* JetBrains Mono — variable font from Google Fonts, kept as two unicode
   ranges (latin / latin-ext) so the woff2 stays small. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/jetbrains-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/jetbrains-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
                 U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
                 U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Switzer — variable font (upright + italic) from fontshare.com */
@font-face {
  font-family: 'Switzer';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/Switzer-Variable.woff2') format('woff2-variations'),
       url('fonts/Switzer-Variable.woff2') format('woff2');
}
@font-face {
  font-family: 'Switzer';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/Switzer-VariableItalic.woff2') format('woff2-variations'),
       url('fonts/Switzer-VariableItalic.woff2') format('woff2');
}


/* 1. THEME TOKENS ========================================================== */

.surface {
  --bg:            #ffffff;
  --bg-subtle:     #fafaf9;
  --bg-muted:      #f5f5f4;
  --bg-elevated:   #ffffff;
  --border:        #e7e5e4;
  --border-strong: #d6d3d1;
  --text:          #0c0a09;
  --text-muted:    #57534e;
  --text-subtle:   #78716c;
  --text-faint:    #78716c;  /* WCAG-AA: equal to --text-subtle in light mode (was #a8a29e = 2.7:1). Distinct tone preserved only in dark mode. */

  --accent:        #166534;
  --accent-hover:  #14532d;
  --accent-bg:     #f0fdf4;
  --accent-border: #bbf7d0;
  --accent-on:     #ffffff;

  --status-active:   #16a34a;
  --status-warn:     #d97706;
  --status-warn-bg:  #fef3c7;
  --status-warn-fg:  #92400e;
  --status-disabled: #a8a29e;

  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.04);
  --shadow-md: 0 1px 3px 0 rgb(0 0 0 / 0.06), 0 1px 2px -1px rgb(0 0 0 / 0.04);
  --shadow-lg: 0 8px 24px -4px rgb(0 0 0 / 0.08), 0 2px 6px -2px rgb(0 0 0 / 0.04);

  --font-sans: 'Switzer', -apple-system, BlinkMacSystemFont, 'Segoe UI',
               system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;

  /* Cap content in the main column on wide displays so tables and
     headings don't drift apart. Sidebar stays full-height; the area
     to the right of the cap shows the surface background. */
  --main-max-width: 1080px;
}

@media (prefers-color-scheme: dark) {
  .surface {
    --bg:            #0c0a09;
    --bg-subtle:     #131110;
    --bg-muted:      #1c1917;
    --bg-elevated:   #1c1917;
    --border:        #292524;
    --border-strong: #3f3a37;
    --text:          #fafaf9;
    --text-muted:    #d6d3d1;
    --text-subtle:   #a8a29e;
    --text-faint:    #78716c;

    --accent:        #4ade80;
    --accent-hover:  #86efac;
    --accent-bg:     #052e16;
    --accent-border: #166534;
    --accent-on:     #052e16;

    --status-active:   #4ade80;
    --status-warn-bg:  #451a03;
    --status-warn-fg:  #fcd34d;
    --status-disabled: #57534e;

    --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.4);
    --shadow-md: 0 1px 3px 0 rgb(0 0 0 / 0.5), 0 1px 2px -1px rgb(0 0 0 / 0.4);
    --shadow-lg: 0 8px 24px -4px rgb(0 0 0 / 0.6), 0 2px 6px -2px rgb(0 0 0 / 0.4);
  }
}


/* 2. RESET & BASE ========================================================== */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: #0c0a09;
  font-family: 'Switzer', -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}
.surface {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  min-height: 100vh;
  width: 100%;
}
.mono { font-family: var(--font-mono); }


/* 3. LAYOUT PRIMITIVES ===================================================== */

/* Centered single-column stage for auth screens / 404. */
.stage {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px;
}
.stage-column {
  width: 100%;
  max-width: 400px;
}
.stage-column.is-wide { max-width: 440px; }

/* Two-column app shell: sidebar + main. Capped and centred on wide
   displays (sidebar 232px + content cap) so the entire shell sits in
   the viewport centre instead of anchoring to the left edge. The
   surrounding empty area shows --bg, matching .main. */
.app {
  display: flex;
  height: 100vh;
  width: 100%;
  max-width: calc(232px + var(--main-max-width));
  margin: 0 auto;
  overflow: hidden;
}


/* 4. BRAND ================================================================= */

.brand {
  display: inline-flex;
  align-items: center;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
}
.brand-mark {
  width: 26px;
  height: 26px;
  background: var(--accent);
  color: var(--accent-on);
  border-radius: 6px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 14px;
  /* Tight line-box + a 2px bottom inset so a lowercase glyph (no
     descender, visual mass concentrated at the baseline) sits at the
     box's optical centre rather than hugging the bottom edge — what
     the old `g` covered with its descender. */
  line-height: 1;
  padding-bottom: 2px;
  flex-shrink: 0;
}
/* Wordmark — margin (not flex gap) so we can animate it to 0 in the
   collapsed sidebar without the gap leaving a visible gutter. */
.brand-wordmark {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  margin-left: 10px;
  max-width: 240px;
  opacity: 1;
  transition:
    max-width   320ms cubic-bezier(0.4, 0, 0.2, 1),
    margin-left 320ms cubic-bezier(0.4, 0, 0.2, 1),
    opacity     180ms ease;
}
.brand-line {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  margin-bottom: 28px;
}

.lang-switcher {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  letter-spacing: 0.05em;
}
.brand-line .lang-switcher {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
}
.lang-switcher a {
  color: var(--text-muted);
  text-decoration: none;
  padding: 4px 6px;
  border-radius: 4px;
  transition: background 150ms ease, color 150ms ease;
}
.lang-switcher a:hover { color: var(--text); background: var(--bg-muted); }
.lang-switcher .is-active {
  color: var(--text);
  font-weight: 500;
  padding: 4px 6px;
}
.lang-switcher .sep { color: var(--border-strong); }

/* In the dashboard sidebar the switcher sits as the first child of
   .sidebar-footer; the margin keeps DE · EN off the avatar below. */
.sidebar-footer .lang-switcher { margin-bottom: 10px; }

/* Landing footer: switcher sits between the legal-link strip and the
   tagline. The legal strip already carries margin-bottom: 10px, so
   only the bottom gap (lang → tagline) needs to be set here.
   text-align: center on .site-footer handles horizontal centring of
   the inline-flex element automatically — no justify-content needed. */
.site-footer .lang-switcher { margin-bottom: 10px; }


/* 5. PILLS ================================================================= */

/* Eyebrow pill above titles. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  color: var(--accent);
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}
.pill-dot {
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
  flex-shrink: 0;
}

/* Inline mono pill for an email address or short code value. */
.code-pill {
  display: inline-block;
  background: var(--bg-muted);
  border: 1px solid var(--border);
  padding: 2px 8px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
}


/* 6. BUTTONS =============================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 18px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  border: 1px solid transparent;
  background: transparent;
  color: inherit;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease,
              border-color 150ms ease, transform 80ms ease;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn:active:not(:disabled) { transform: translateY(1px); }

.btn-primary {
  background: var(--text);
  color: var(--bg);
}
.btn-primary:hover:not(:disabled) {
  background: var(--accent);
  color: var(--accent-on);
}
.btn-primary:active:not(:disabled) {
  background: var(--accent-hover);
  color: var(--accent-on);
}

.btn-secondary {
  background: var(--bg);
  color: var(--text);
  border-color: var(--border-strong);
}
.btn-secondary:hover:not(:disabled) { background: var(--bg-muted); }

.btn-ghost { color: var(--text-muted); }
.btn-ghost:hover:not(:disabled) {
  color: var(--text);
  background: var(--bg-muted);
}

.btn-block { width: 100%; }
.btn-sm    { padding: 7px 12px; font-size: 13px; }


/* 7. FORM FIELDS =========================================================== */

.field { margin-bottom: 14px; }
.field-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.input {
  width: 100%;
  padding: 11px 14px;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--text);
  outline: none;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}
.input::placeholder { color: var(--text-faint); }

/* Horizontal "or" separator with a label. */
.divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 14px 0;
  color: var(--text-faint);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.divider::before,
.divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}


/* 8. AUTH CARD ============================================================= */

.auth-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 32px;
  box-shadow: var(--shadow-md);
}
.auth-card.is-centered { text-align: center; }

.auth-foot {
  margin: 18px 0 0;
  text-align: center;
  font-size: 13px;
}
.auth-foot a {
  color: var(--text-muted);
  text-decoration: none;
}
.auth-foot a:hover { text-decoration: underline; }

.auth-head {
  text-align: center;
  margin-bottom: 22px;
}
.auth-head h1 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 14px 0 6px;
}
.auth-head h1:first-child { margin-top: 0; }
.auth-head p {
  color: var(--text-muted);
  font-size: 14px;
  margin: 0;
}

/* Pulsing mail icon used on the confirm card. */
.auth-icon {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  color: var(--accent);
  display: grid;
  place-items: center;
  margin: 0 auto 20px;
  position: relative;
}
.auth-icon::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid var(--accent-border);
  opacity: 0.5;
  animation: auth-pulse 2s ease-out infinite;
}
@keyframes auth-pulse {
  0%   { transform: scale(0.95); opacity: 0.6; }
  100% { transform: scale(1.15); opacity: 0;   }
}

/* OAuth row (Google / Apple) — two equal columns. */
.oauth-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-bottom: 14px;
}
.oauth-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border-strong);
  cursor: pointer;
  transition: background 150ms ease;
}
.oauth-btn:hover:not(:disabled) { background: var(--bg-muted); }
.oauth-btn svg { flex-shrink: 0; }

/* 9. SIDEBAR =============================================================== */

/* Shared easing for the collapse/expand motion. cubic-bezier(0.4, 0, 0.2, 1)
   is Material's "standard" curve — slight acceleration in, gentle out, feels
   crisp without being jumpy. */
.sidebar {
  width: 232px;
  flex-shrink: 0;
  background: var(--bg-subtle);
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  padding: 16px;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  transition:
    width   320ms cubic-bezier(0.4, 0, 0.2, 1),
    padding 320ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 16px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 14px;
  transition: padding 320ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-brand .brand {
  flex: 1;
  min-width: 0;
}
.sidebar-toggle {
  flex-shrink: 0;
  background: transparent;
  border: 0;
  padding: 4px;
  border-radius: 4px;
  color: var(--text-faint);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 120ms ease, color 120ms ease;
}
.sidebar-toggle:hover {
  color: var(--text);
  background: var(--bg-muted);
}
.sidebar-toggle svg { transition: transform 320ms cubic-bezier(0.4, 0, 0.2, 1); }

/* Collapsed sidebar — class lives on <html> so a tiny inline <head>
   script can apply it before paint, avoiding flash. Scoped to the
   desktop breakpoint so the cookie state can't fight the mobile
   top-bar layout in §23. */
@media (min-width: 768px) {
  .is-sidebar-collapsed .sidebar { width: 84px; padding: 16px 6px; }
  .is-sidebar-collapsed .sidebar-brand { padding: 6px 4px 16px; }
  .is-sidebar-collapsed .brand-wordmark { max-width: 0; margin-left: 0; opacity: 0; }
  /* Hide the heading copy but keep the box — `display: none` would let
     the items below jump up when the sidebar collapses; visibility
     keeps the row height so every menu entry stays at its expanded
     y-position. */
  .is-sidebar-collapsed .sidebar-section-label { visibility: hidden; }
  .is-sidebar-collapsed .sidebar-item > span:not(.sidebar-badge) { display: none; }
  .is-sidebar-collapsed .sidebar-badge { display: none; }
  .is-sidebar-collapsed .sidebar-user-info { display: none; }
  .is-sidebar-collapsed .sidebar-item { justify-content: center; padding: 7px 0; }
  .is-sidebar-collapsed .sidebar-user { justify-content: center; padding: 7px 0; }
  .is-sidebar-collapsed .sidebar-toggle svg { transform: rotate(180deg); }
}
.sidebar-section { margin-bottom: 18px; }
.sidebar-section-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
  padding: 0 10px;
  margin-bottom: 6px;
}
.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: 6px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  background: transparent;
  border: 0;
  text-align: left;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background 120ms ease,
    color      120ms ease,
    padding    320ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-item:hover {
  background: var(--bg-muted);
  color: var(--text);
}
.sidebar-item.is-active {
  background: var(--bg);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}
.sidebar-item.is-muted {
  color: var(--text-faint);
  cursor: not-allowed;
}
.sidebar-item.is-muted:hover {
  background: transparent;
  color: var(--text-faint);
}
.sidebar-item svg { flex-shrink: 0; color: var(--text-faint); }
.sidebar-item.is-active svg { color: var(--accent); }
.sidebar-badge {
  margin-left: auto;
  background: var(--bg-muted);
  color: var(--text-subtle);
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 4px;
  font-family: var(--font-mono);
}
.sidebar-item.is-active .sidebar-badge {
  background: var(--accent-bg);
  color: var(--accent);
}

.sidebar-footer {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* Accent-pill CTA in the footer; sits above .lang-switcher and the
   user row so it stands out from the regular muted nav items. Hover
   inverts the fill to solid accent for a clear affordance. */
.sidebar-feedback {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  color: var(--accent);
  text-decoration: none;
  transition: background 150ms ease, color 150ms ease;
}
.sidebar-feedback:hover {
  background: var(--accent);
  color: var(--accent-on);
}
.is-sidebar-collapsed .sidebar-feedback {
  justify-content: center;
  padding: 8px 0;
}
.is-sidebar-collapsed .sidebar-feedback span { display: none; }

/* Phase 3 — sidebar tier pill (DASH-PRO-02, DASH-PRO-05; CONTEXT D-22, D-23).
   Lives in app.css only — admin.css must not contain .tier-pill rules.
   All colours derive from existing custom properties so dark-mode at
   line 112-138 flips automatically without duplicate rules. */
.tier-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  border: 1px solid transparent;
  text-decoration: none;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.tier-pill > svg { flex-shrink: 0; }

/* Free state — interactive Upgrade-CTA. Hover lifts to accent so the
   pill telegraphs a click target. */
.tier-pill.is-free {
  background: var(--bg-muted);
  color: var(--text-muted);
  border-color: var(--border);
}
.tier-pill.is-free:hover,
.tier-pill.is-free:focus-visible {
  background: var(--accent-bg);
  color: var(--accent);
  border-color: var(--accent-border);
}

/* Collapsed sidebar — hide the inner label, keep the icon centred.
   Mirrors .is-sidebar-collapsed .sidebar-feedback (line 672-676). */
.is-sidebar-collapsed .tier-pill {
  justify-content: center;
  padding: 8px 0;
}
.is-sidebar-collapsed .tier-pill > span { display: none; }

/* Settings/Account "Plan" row link — neutral inline link styling so it
   does not over-emphasise within a row that also carries a label and
   a value. Distinct from .btn.btn-primary which would dominate the
   row visually. */
.setting-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
  font-size: 13px;
}
.setting-link:hover,
.setting-link:focus-visible {
  text-decoration: underline;
}

/* Pairs multiple controls inside a single .setting-row action cell
   without breaking the grid layout. Used today by the Pro-plan row
   to host the Paddle customer-portal link next to the cancel button
   or the pending-cancel note. */
.setting-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}


/* Informational text in the action column of a .setting-row — same
   size + muted colour as .setting-link, but without the link affordance.
   Used for "scheduled to cancel" and similar passive states. */
.setting-action-note {
  font-size: 13px;
  color: var(--text-muted);
}

/* Compact dropdown that lives in the action column of a .setting-row.
   Borrows the .input border + radius so the language picker matches
   the rest of the form chrome without inheriting the mono font. */
.setting-select {
  padding: 6px 28px 6px 10px;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  outline: none;
  transition: border-color 150ms ease, box-shadow 150ms ease;
  appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2 4l3 3 3-3' fill='none' stroke='%23888' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 8px center;
}
.setting-select:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}

/* Phase 3 — Settings/Capacity section (DASH-PRO-04, DASH-PRO-05; D-22, D-23).
   Lives in app.css only — admin.css must not contain .capacity-bar rules.
   All colours derive from existing custom properties so dark-mode at
   line 112-138 flips automatically; .is-blocked uses the literal #b04545
   matching the existing .setting-value.is-blocked / .main-count.is-blocked
   precedent (no --status-blocked-* token exists yet). */
.capacity-section .panel-head { margin-bottom: 4px; }
.capacity-section .is-muted   { color: var(--text-muted); font-size: 13px; }

.capacity-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 0;
  border-bottom: 1px dashed var(--border);
}
.capacity-row:last-of-type { border-bottom: none; }

.capacity-row-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.capacity-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.capacity-meter {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.capacity-value {
  font-family: var(--font-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  white-space: nowrap;
}

.capacity-bar-track {
  width: 240px;
  height: 8px;
  background: var(--bg-muted);
  border-radius: 999px;
  overflow: hidden;
}
.capacity-bar {
  height: 100%;
  background: var(--status-active);
  border-radius: inherit;
  transition: width 200ms ease;
}
.capacity-bar.is-warn    { background: var(--status-warn); }
.capacity-bar.is-blocked { background: #b04545; }

.capacity-row-foot {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-size: 12px;
}
.capacity-reset-hint {
  color: var(--text-muted);
}
.capacity-upgrade-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}
.capacity-upgrade-link:hover,
.capacity-upgrade-link:focus-visible {
  text-decoration: underline;
}

/* Mobile — stack the meter (bar + value) under the label so the row
   stays readable when the panel column narrows below ~640px. The bar
   spans the available width instead of clinging to its 240px desktop
   cap, otherwise it hugs the left edge with empty space to its right. */
@media (max-width: 640px) {
  .capacity-row-head {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .capacity-meter {
    justify-content: space-between;
  }
  .capacity-bar-track {
    flex: 1;
    width: auto;
  }
}

/* Phase 3 — Upgrade view (DASH-PRO-03, DASH-PRO-05; CONTEXT D-22, D-23).
   Lives in app.css only — admin.css must not contain these rules. The
   .checkout-container is the host element for Paddle's branded inline
   iframe (frameTarget=".checkout-container"); Paddle injects its own
   styles inside the iframe, so this rule is just the host-shape. All
   other classes derive their colours from existing custom properties so
   dark-mode at line 112-138 flips automatically. */
.upgrade-view .page-body {
  max-width: 920px;
}

/* Two-column layout for the upgrade view: feature list on the left,
   the existing checkout-summary + plan-toggle + Paddle iframe on the
   right. Stacks below 720px so the Paddle iframe (min-width 312px)
   keeps room to render. */
.upgrade-layout {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) minmax(360px, 1fr);
  gap: 32px;
  align-items: center;
  margin-top: 24px;
  /* Match the 32px horizontal inset that .panel uses elsewhere on the
     page so the features box doesn't sit flush against the sidebar. */
  padding: 0 32px;
}
.upgrade-checkout {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-width: 0;
}
.upgrade-checkout .checkout-summary { margin-top: 0; }

@media (max-width: 720px) {
  .upgrade-layout { grid-template-columns: 1fr; }
}

.pro-features {
  padding: 20px 22px;
  background: var(--bg-muted);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.pro-features-title {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.pro-features-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.pro-features-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
}
.pro-features-check {
  flex: 0 0 14px;
  margin-top: 3px;
  color: var(--accent);
}

/* Product-summary block above the plan-toggle and the Paddle iframe.
   Paddle's inline checkout deliberately omits item breakdowns, so this
   panel is the SPA-side surface for "what am I buying" — populated
   from the checkout.loaded / .updated event payloads. */
.checkout-summary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin: 24px auto 0;
  padding: 16px 20px;
  text-align: center;
}
.checkout-summary-skeleton {
  color: var(--text-muted);
  font-size: 13px;
}
.checkout-summary-product {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.checkout-summary-product-name {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
}
.checkout-summary-product-cycle {
  font-size: 13px;
  color: var(--text-muted);
}
.checkout-summary-price {
  font-variant-numeric: tabular-nums;
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
}
.checkout-summary-price-cycle {
  color: var(--text-muted);
}
.checkout-summary-trial {
  font-size: 12px;
  color: var(--accent);
}

.plan-toggle {
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--bg-muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px;
  width: fit-content;
  margin: 12px auto 16px;
}
.plan-toggle-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 13px;
  transition: background 150ms ease, color 150ms ease;
}
.plan-toggle-option.is-active {
  background: var(--bg);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}
/* Visually hide the radio input while keeping it accessible — the
   <label> wrapper is the click target, the input toggles state. */
.plan-toggle-option > input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.plan-toggle-label  { font-weight: 500; }
.plan-toggle-savings {
  font-size: 12px;
  color: var(--accent);
}

.checkout-container {
  width: 100%;
  min-width: 312px;
  background: transparent;
}

.upgrade-view-status {
  /* Confirmation/error banner replaces the full upgrade-layout when
     the checkout completes or errors out. Centered and narrowed so it
     reads as its own card, not an empty stretch of the page body. */
  max-width: 480px;
  margin: 40px auto 0;
  padding: 28px 24px;
  border-radius: 12px;
  text-align: center;
  font-size: 15px;
  line-height: 1.55;
}
.upgrade-view-status.is-completed {
  background: var(--accent-bg);
  color: var(--accent);
  border: 1px solid var(--accent-border);
}
.upgrade-view-status.is-error {
  background: var(--status-warn-bg);
  color: var(--status-warn-fg);
  border: 1px solid var(--status-warn-fg);
}

.upgrade-fallback {
  /* Same shape contract as .upgrade-view-status: a centered card, not
     a full-width banner that sits flush against the surrounding page
     chrome. Width is generous because the body can be a sentence or
     two of explanation, but it stops well short of the 920px
     page-body so it reads as its own element. */
  max-width: 560px;
  margin: 40px auto 0;
  padding: 32px 28px;
  background: var(--bg-muted);
  border: 1px dashed var(--border);
  border-radius: 12px;
  text-align: center;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1.55;
}

.sidebar-user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: 6px;
  transition: padding 320ms cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-on);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 600;
  /* Same optical-centring trick as .brand-mark: the lowercase initial
     would otherwise sit at the bottom of the circle. */
  line-height: 1;
  padding-bottom: 1px;
  flex-shrink: 0;
  text-transform: lowercase;
}
.sidebar-user-info { flex: 1; min-width: 0; }
.sidebar-user-name {
  font-size: 12px;
  font-weight: 500;
  color: var(--text);
}
.sidebar-user-email {
  font-size: 11px;
  color: var(--text-faint);
  font-family: var(--font-mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-logout {
  cursor: pointer;
  /* Match the height of .sidebar-user-info (name + email stack) by
     stretching against the flex line instead of inheriting
     align-items: center from .sidebar-user. The icon stays centred
     inside the now-taller button via the inner flex centring. */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
}


/* 10. MAIN COLUMN & EMPTY STATE =========================================== */

.main {
  flex: 1;
  background: var(--bg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
/* Full-width band: holds the bottom border that flows from sidebar to
   viewport edge. The flex row that hosts the title + action lives in
   .main-head-inner so it can be capped and centered on wide displays
   without breaking the border. The 64px min-height aligns this band's
   bottom border with the sidebar-brand's bottom border (sidebar pad-top
   16 + brand box 49 = 65px from viewport top; here 64 inner + 1 border
   = 65). Vertical centring instead of fixed padding keeps the title
   and action visually balanced even if their heights drift. */
.main-head {
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.main-head-inner {
  min-height: 64px;
  max-width: var(--main-max-width);
  margin: 0 auto;
  padding: 0 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}
.main-title {
  display: flex;
  align-items: center;
  gap: 12px;
}
.main-title h1 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.018em;
  margin: 0;
}
.main-count {
  font-size: 12px;
  color: var(--text-faint);
  font-family: var(--font-mono);
}
/* Quota state pills: warn at >= 80% of the alias quota, blocked at
   100%. Both reuse the existing status-warn / danger tokens so a
   theme switch carries through without a new palette. */
.main-count.is-warn {
  color: var(--status-warn-fg);
  background: var(--status-warn-bg);
  padding: 2px 8px;
  border-radius: 999px;
}
.main-count.is-blocked {
  color: #b04545;
  background: color-mix(in srgb, #b04545 10%, transparent);
  padding: 2px 8px;
  border-radius: 999px;
}

.main-error {
  margin: 14px 32px 0;
  /* Match the body cap on wide displays: subtract the 32px gutters so
     the banner aligns with the alias list / panels above it. */
  max-width: calc(var(--main-max-width) - 64px);
  padding: 10px 14px;
  font-size: 13px;
  line-height: 1.5;
  color: #b04545;
  background: color-mix(in srgb, #b04545 8%, transparent);
  border: 1px solid color-mix(in srgb, #b04545 35%, transparent);
  border-radius: 8px;
}

.empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  width: 100%;
  max-width: var(--main-max-width);
  align-self: center;
}
.empty-inner {
  max-width: 420px;
  text-align: center;
}
.empty-icon {
  width: 56px;
  height: 56px;
  border-radius: 12px;
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  color: var(--accent);
  display: grid;
  place-items: center;
  margin: 0 auto 18px;
}
.empty-title {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 6px;
}
.empty-sub {
  font-size: 14px;
  color: var(--text-muted);
  margin-bottom: 22px;
}
/* 11. FILTER CHIPS ========================================================= */

.chip-bar {
  padding: 12px 32px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  font-size: 12px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 12px;
  transition: border-color 120ms ease, color 120ms ease;
}
.chip:hover { border-color: var(--border-strong); color: var(--text); }
.chip.is-active {
  background: var(--text);
  color: var(--bg);
  border-color: var(--text);
}
.chip.is-warn {
  background: var(--status-warn-bg);
  color: var(--status-warn-fg);
  border-color: color-mix(in srgb, var(--status-warn-bg) 60%, var(--status-warn-fg));
}
.chip-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  display: inline-block;
}
.chip-dot.is-active   { background: var(--status-active); }
.chip-dot.is-warn     { background: var(--status-warn); }
.chip-dot.is-disabled { background: var(--status-disabled); }
.chip-count {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
}
.chip.is-active .chip-count { color: rgb(255 255 255 / 0.55); }


/* 12. ALIAS ROWS =========================================================== */

.alias-list {
  /* Fill the remaining height of .main (a flex column) so the list IS the
     scroll region. Without flex:1 the list is only content-tall: with one
     alias its bottom sits right under the action row, which fooled the
     ⋯-menu's open-direction check into flipping the menu upward over the
     row. Full height keeps the menu opening downward; the up-flip now only
     fires for a genuinely bottom-anchored last alias. min-height:0 lets the
     flex item shrink so overflow-y scrolling engages for long lists. */
  flex: 1;
  min-height: 0;
  padding: 0;
  overflow-y: auto;
  width: 100%;
  max-width: var(--main-max-width);
  align-self: center;
}

.alias-row {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr) minmax(180px, 1fr);
  align-items: center;
  gap: 14px;
  padding: 12px 32px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  background: transparent;
  border-left: 0;
  border-right: 0;
  border-top: 0;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
}
.alias-row:hover     { background: var(--bg-subtle); }
.alias-row.is-selected { background: var(--bg-subtle); }

.alias-row.is-disabled .alias-name { opacity: 0.5; }

.alias-status {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--status-active);
  box-shadow: 0 0 0 3px rgb(22 163 74 / 0.12);
}
.alias-status.is-warn {
  background: var(--status-warn);
  box-shadow: 0 0 0 3px rgb(217 119 6 / 0.15);
}
.alias-status.is-disabled {
  background: var(--status-disabled);
  box-shadow: none;
  opacity: 0.7;
}

.alias-name {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.at-domain {
  color: var(--text-faint);
  font-weight: 400;
}

.alias-context-cell {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
}
.alias-tag {
  background: var(--bg-muted);
  padding: 2px 7px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  display: inline-block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.alias-tag.is-warn {
  background: var(--status-warn-bg);
  color: var(--status-warn-fg);
}
.alias-tag.is-muted {
  opacity: 0.55;
  font-style: italic;
}

/* 13. ALIAS DETAIL PANEL ================================================== */

.alias-detail {
  padding: 22px 32px 24px;
  background: var(--bg-subtle);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin-top: -1px;
}
/* Summary line: `Erstellt 12. April · Letzte Mail vor 3 Tagen`.
   Replaces the previous three-card stat grid; volume counters drove
   no user decisions and read as broken UI on fresh aliases. Muted
   typography signals "metadata, not headline". */
.detail-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 18px;
}
.detail-summary-sep {
  color: var(--text-faint);
}
.detail-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* Alias action overflow menu (⋯): demotes note / disable / delete out of
   the primary action row so the everyday Copy never sits beside the
   destructive Delete. Mirrors the domain-picker dropdown's mechanics and
   look (capture-phase outside-click dismiss, soft-shadow popover). */
.actions-menu-wrap {
  position: relative;
  display: inline-flex;
}
.actions-menu-trigger {
  /* Tighter side padding + larger glyph so ⋯ reads as an icon button,
     not a word-width button. line-height is pinned to the .btn-sm text
     box (font-size 13px under .btn line-height:1) so the bigger glyph
     does not make this button taller than Copy/Send-from beside it. */
  padding-left: 11px;
  padding-right: 11px;
  font-size: 18px;
  line-height: 13px;
}
.actions-menu {
  position: absolute;
  top: calc(100% + 4px);
  /* Anchor to the trigger's right edge and open leftward: the ⋯ sits at
     the right end of the action row, so a left-anchored menu would spill
     past the panel edge and clip. */
  right: 0;
  min-width: 168px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  padding: 4px 0;
  z-index: 20;
  list-style: none;
  margin: 0;
}
/* Flipped variant: open upward from the trigger when it sits near the
   bottom of the scrolling alias list (set by detail-actions on open). */
.actions-menu.is-up {
  top: auto;
  bottom: calc(100% + 4px);
}
.actions-menu-item {
  display: block;
  width: 100%;
  padding: 7px 14px;
  border: 0;
  background: transparent;
  text-align: left;
  font-size: 14px;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.actions-menu-item:hover,
.actions-menu-item:focus {
  background: var(--bg-subtle);
  outline: none;
}
/* Delete sits below a divider and reads red; arming fills it via the
   shared .btn-danger.is-armed rule (which arm-confirm! also keys off). */
.actions-menu-danger {
  margin-top: 4px;
  border-top: 1px solid var(--border);
  padding-top: 9px;
  color: #b04545;
}

/* Inline form fades in on mount (alias-label editor, passkey/API-token
   create forms). Reagent unmounts the form on close, so each open
   creates a fresh node and the animation fires automatically — no JS
   state needed. Exit is intentionally instant: the user clicked
   Cancel/Save and already knows the form is gone, so a fade-out would
   only delay the next interaction. */
.inline-form-reveal {
  animation: inline-form-reveal 150ms ease-out;
}
@keyframes inline-form-reveal {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}


/* 14. NOT-FOUND PAGE ====================================================== */

.glyph-404 {
  font-family: var(--font-mono);
  font-size: 80px;
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1;
  margin: 4px 0;
  color: var(--text);
}
.glyph-404-accent { color: var(--accent); }

.path-pill {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 18px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-family: var(--font-mono);
}
.path-pill-label {
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 10px;
  font-weight: 600;
}
.path-pill-value {
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}

/* Two-button row under the path pill. Inline style="flex:1" alone
   wasn't enough to make short labels (Home / Dashboard) stretch and
   the gap then read as 0; force the basis with a class instead. */
.cta-row {
  display: flex;
  gap: 10px;
}
.cta-row > .btn {
  flex: 1 1 0;
  min-width: 0;
}

/* DE / EN language switcher (Addendum §20.5). Footer of the landing
   page and a centered row below each auth card. */
.lang-switch {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 11px;
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.lang-switch a {
  color: var(--text-muted);
  text-decoration: none;
}
.lang-switch a:hover { color: var(--text); }
.lang-switch .is-active {
  color: var(--text);
  font-weight: 600;
}
.lang-switch-sep { user-select: none; }

/* Footer-style meta line under cards (e.g. "report a problem"). */
.meta-line {
  font-size: 11px;
  color: var(--text-faint);
  text-align: center;
  margin-top: 16px;
}
.meta-line a {
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
}


/* 15. LANDING — TOP NAV ==================================================== */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.site-nav-row {
  max-width: 1080px;
  margin: 0 auto;
  height: 60px;
  padding: 0 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.site-nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
}
.site-nav-links a {
  padding: 7px 12px;
  border-radius: 6px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 13px;
  transition: background 150ms ease, color 150ms ease;
  /* Pin every nav anchor (incl. the lang-switcher children + .is-cta)
     to the same visual box so the row sits on one baseline. Without
     this the CTA's background-painted rectangle reads as taller than
     the bare-text links next to it even though the math says they
     should match. line-height: 1 + min-height: 30px + inline-flex
     gives an explicit box height with text centred vertically; the
     intrinsic line-height (~1.2) + transparent-vs-painted-bg combo
     was producing a visible vertical offset. Same recipe the mobile
     media query below already uses, lifted to the desktop default. */
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  line-height: 1;
}
.site-nav-links a:hover { color: var(--text); background: var(--bg-muted); }
.site-nav-links a.is-cta {
  margin-left: 16px;
  padding: 7px 14px;
  background: var(--text);
  color: var(--bg);
}
.site-nav-links a.is-cta:hover { background: var(--accent); color: var(--accent-on); }

/* Keyboard focus ring (WCAG 2.4.7). Applies to every .btn variant and
   nav-links; :focus-visible only fires for keyboard / programmatic
   focus, so mouse clicks don't grow an outline. */
.btn:focus-visible,
.site-nav-links a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* On phones the brand + Features + Pricing + DE·EN + CTA strip overflows
   the viewport. Hide the brand wordmark (the mark + "a" square still
   identifies the page) so the two in-page anchors stay discoverable —
   audit feedback was that mobile visitors lose all nav except Brand,
   Lang and CTA when the anchors disappear. Tightened chrome keeps
   everything on one row down to ~340px. */
@media (max-width: 640px) {
  .site-nav-row {
    height: 56px;
    padding: 0 14px;
  }
  .brand-wordmark { display: none; }
  .site-nav-links { gap: 8px; }
  .site-nav-links a {
    padding: 7px 8px;
    font-size: 12px;
    min-height: 30px;
    display: inline-flex;
    align-items: center;
  }
  .site-nav-links a.is-cta {
    margin-left: 0;
    padding: 7px 12px;
  }
}


/* 16. LANDING — HERO + DEMO ================================================ */

/* Generic landing-page section: max-width container with padding. */
.lp-section {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 28px;
}

.hero {
  padding: 80px 28px 56px;
  text-align: center;
}
.hero h1 {
  font-size: clamp(36px, 5vw, 54px);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-weight: 600;
  max-width: 760px;
  margin: 24px auto 18px;
}
.hero h1 em {
  font-style: normal;
  color: var(--accent);
}
.hero-sub {
  font-size: 17px;
  color: var(--text-muted);
  max-width: 540px;
  margin: 0 auto 32px;
  line-height: 1.55;
}
.hero-cta {
  display: inline-flex;
  gap: 10px;
  align-items: center;
}

.demo {
  margin-bottom: 72px;
}
.demo-card {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 26px 32px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
}
.demo-flow {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 1;
  min-width: 320px;
}
.demo-block {
  flex: 1;
  min-width: 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 16px;
}
.demo-label {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
  margin-bottom: 5px;
}
.demo-value {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.demo-arrow { color: var(--text-faint); flex-shrink: 0; }
.demo-note {
  max-width: 220px;
  font-size: 12px;
  color: var(--text-subtle);
}


/* 17. LANDING — FEATURE GRID + SECTION HEADINGS =========================== */

/* Small uppercase eyebrow above section title. */
.section-eyebrow {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent);
  margin-bottom: 10px;
}
.section-title {
  font-size: 28px;
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 600;
  max-width: 480px;
  margin: 0 0 44px;
}
.section-title.is-centered {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.feature {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 26px 22px;
  background: var(--bg);
}
.feature-icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--accent-bg);
  color: var(--accent);
  display: grid;
  place-items: center;
  margin-bottom: 4px;
}
.feature h3 {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.feature p {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.55;
  margin: 0;
}

/* Mobile: stack the demo flow vertically (drops the 320px min-width that
   pushed the card past the viewport) and collapse the feature grid to a
   single column. The card itself also switches to column so demo-flow
   gets full width and the inner blocks stretch instead of being squeezed
   by the demo-note sibling. */
@media (max-width: 640px) {
  .demo-card {
    flex-direction: column;
    align-items: stretch;
    padding: 20px;
    gap: 18px;
  }
  .demo-flow {
    flex-direction: column;
    align-items: stretch;
    min-width: 0;
    gap: 10px;
  }
  .demo-block { flex: 0 0 auto; }
  .demo-arrow {
    transform: rotate(90deg);
    align-self: center;
  }
  .demo-note {
    max-width: none;
    text-align: center;
  }

  .feature-grid {
    grid-template-columns: 1fr;
  }
}


/* 18. LANDING — PRICING + FOOTER =========================================== */

.pricing {
  padding: 72px 28px;
  text-align: center;
}
/* Phase 3 — Free/Pro/Business comparison table (PRICING-01, PRICING-02,
   DASH-PRO-05). Reuses the surface tokens defined at lines 75-141 so
   the dark-mode overrides flow through automatically. Lives here in
   app.css, not admin.css (D-22). */

.pricing-table {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  /* `separate` (not `collapse`) is what lets the Pro column read as a
     continuous floating card with rounded corners — collapsed borders
     would have nowhere to round to. border-spacing stays at 0 so the
     cells still meet flush. */
  border-collapse: separate;
  border-spacing: 0;
  font-family: var(--font-sans);
  text-align: left;
}

/* Headers. Free is a plain label; Pro starts the card — accent
   background, side+top borders, top-rounded. The PRO label is
   slightly bolder than FREE so the card asserts itself even before
   the eye reaches the prices below. */
.pricing-table thead th {
  padding: 14px 18px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text);
  font-weight: 600;
}
.pricing-table thead th:not(.col-pro) {
  border-bottom: 1px solid var(--border);
}
.pricing-table thead th.col-pro {
  background: var(--accent-bg);
  color: var(--accent);
  font-weight: 700;
  border-top: 1px solid var(--accent-border);
  border-left: 1px solid var(--accent-border);
  border-right: 1px solid var(--accent-border);
  border-top-left-radius: 12px;
  border-top-right-radius: 12px;
}

/* Row labels: muted, no row-by-row background — the Pro column carries
   the structure on the right, the typography contrast carries it on
   the left. */
.pricing-table tbody th.row-label {
  padding: 14px 18px;
  text-align: left;
  font-weight: 500;
  color: var(--text-muted);
}

/* Quota cells: tabular numerals so 10/100/1000 align in a column,
   bumped to 17px so the differentiator (the actual numbers) is the
   first thing the eye lands on. */
.pricing-table tbody td {
  padding: 14px 18px;
  text-align: center;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-size: 17px;
  font-weight: 500;
}
.pricing-table tbody td.col-pro {
  background: var(--accent-bg);
  color: var(--accent);
  font-weight: 600;
  border-left: 1px solid var(--accent-border);
  border-right: 1px solid var(--accent-border);
}

/* Section divider between the quota block and the prices row.
   The Pro side flows continuously through the accent background, so
   the divider only needs to live on the row-label and Free cells. */
.pricing-table tr.pricing-table-prices th.row-label,
.pricing-table tr.pricing-table-prices td.col-free {
  border-top: 1px solid var(--border);
  padding-top: 24px;
}
.pricing-table tr.pricing-table-prices td.col-pro {
  padding-top: 24px;
  padding-bottom: 16px;
}

/* Price typography. The price amount is the single biggest piece of
   text on the page — 30px, weight 700, tight letter-spacing so the
   digits feel anchored. The Pro amount picks up the brand accent;
   yearly secondary line is a smaller, muted echo. */
.pricing-table tr.pricing-table-prices .price-amount {
  display: inline-block;
  font-size: 30px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
}
.pricing-table tr.pricing-table-prices td.col-pro .price-amount {
  color: var(--accent);
}
.pricing-table tr.pricing-table-prices .price-amount-secondary {
  display: inline-block;
  margin-top: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-muted);
}
.pricing-table tr.pricing-table-prices .price-suffix {
  margin-left: 3px;
  font-size: 13px;
  font-weight: 400;
  color: var(--text-muted);
}

/* CTA row closes the Pro card with a bottom border + bottom-rounded
   corners. The button fills the Pro cell so the call-to-action reads
   as the card's primary action, not a small in-cell control. */
.pricing-table tr.pricing-table-cta th.row-label,
.pricing-table tr.pricing-table-cta td.col-free {
  padding-top: 14px;
  padding-bottom: 24px;
}
.pricing-table tr.pricing-table-cta td.col-pro {
  padding-top: 14px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--accent-border);
  border-bottom-left-radius: 12px;
  border-bottom-right-radius: 12px;
}
.pricing-table tr.pricing-table-cta td.col-pro .btn {
  width: 100%;
  padding: 12px 16px;
  font-weight: 600;
}

/* On narrow screens, fit the table to the viewport instead of letting
   the Pro card spill off the right edge. The cells take the available
   width, padding and font-sizes shrink so 17px tabular numerals and
   30px prices don't crowd a 375px viewport. */
@media (max-width: 640px) {
  /* Match the side gutter the rest of the landing uses (.lp-section,
     .hero, .cta-repeat all keep 28px on mobile) so the pricing column
     aligns with feature tiles and CTA-repeat block above and below.
     The table absorbs the tighter inner space via the cell-padding and
     font-size shrinks below — long labels may wrap to two lines on
     375px viewports, that's acceptable. */
  .pricing {
    padding: 48px 28px;
  }
  .pricing-table thead th,
  .pricing-table tbody th.row-label,
  .pricing-table tbody td {
    padding-left: 10px;
    padding-right: 10px;
  }
  .pricing-table thead th {
    font-size: 12px;
  }
  .pricing-table tbody th.row-label {
    font-size: 14px;
  }
  .pricing-table tbody td {
    font-size: 15px;
  }
  .pricing-table tr.pricing-table-prices .price-amount {
    font-size: 22px;
  }
  .pricing-table tr.pricing-table-prices .price-amount-secondary {
    font-size: 12px;
    margin-top: 6px;
  }
  .pricing-table tr.pricing-table-prices .price-suffix {
    font-size: 11px;
  }
  .pricing-table tr.pricing-table-cta td.col-pro .btn {
    padding: 10px 12px;
    font-size: 14px;
  }
}

.site-footer {
  padding: 28px;
  text-align: center;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-faint);
}
.site-footer-links {
  margin-bottom: 10px;
  display: flex;
  flex-wrap: wrap;
  /* Split the gap so wrapped rows (e.g. when "Política de reembolso"
     drops to its own line on narrow viewports) sit at the same 10px
     vertical rhythm as the margin to the lang-switcher below. The
     full 22px stays as the visual breathing room between siblings
     on a single line. */
  column-gap: 22px;
  row-gap: 10px;
  justify-content: center;
}
.site-footer-links a {
  color: var(--text-muted);
  text-decoration: none;
}
.site-footer-links a:hover { color: var(--text); }


/* 18b. LANDING — FAQ + CTA-REPEAT ========================================= */

/* FAQ stacks single-column with the border-trick as inter-item divider.
   Single column because answers run multi-sentence; a 2-column grid
   would crowd them and break reading flow. max-width keeps long lines
   readable; margin auto centres the list under the section title. */
.faq {
  padding-top: 72px;
}
.faq-list {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  max-width: 760px;
  margin: 0 auto;
}
.faq-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 22px 26px;
  background: var(--bg);
}
.faq-q {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--text);
}
.faq-a {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

/* Short clarification line under the Pricing comparison table. */
.pricing-blurb {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.55;
  max-width: 560px;
  margin: 24px auto 0;
  text-align: center;
}

/* CTA-repeat — centred conversion block between Pricing and Footer.
   No top-padding because Pricing already brings 72px of bottom-padding;
   doubling would over-space the break. */
.cta-repeat {
  padding: 0 28px 64px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.cta-repeat-lead {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--text);
}
.cta-repeat-note {
  font-size: 13px;
  color: var(--text-subtle);
  margin: 0;
}

@media (max-width: 640px) {
  .faq-item {
    padding: 20px;
  }
  .cta-repeat {
    padding: 0 24px 48px;
  }
  .cta-repeat-lead {
    font-size: 20px;
  }
}


/* 19. SUBPAGES — PAGE HEAD + PANELS ======================================== */

/* Header band that introduces a subpage (title + count + body sub).
   The 64px min-height matches the .main-head band so this band's
   bottom border lines up with the sidebar-brand border on the left,
   and the border itself sits on the outer band — full-width like
   .main-head — so the rule meets the sidebar divider without a gap. */
.page-head {
  flex-shrink: 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.page-head-inner {
  min-height: 64px;
  max-width: var(--main-max-width);
  margin: 0 auto;
  padding: 0 32px;
  display: flex;
  align-items: center;
}
.page-head-title {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin: 0 0 6px;
}
.page-head-title h1 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.018em;
  margin: 0;
}
.page-head-count {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.page-head-sub {
  margin: 0;
  max-width: 640px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* The scrollable column inside .main that hosts panels stacked vertically. */
.page-body {
  flex: 1;
  overflow: auto;
  width: 100%;
  max-width: var(--main-max-width);
  align-self: center;
}

/* A bordered horizontal section in the main column. */
.panel {
  padding: 24px 32px;
  border-bottom: 1px solid var(--border);
}
.panel:last-child { border-bottom: none; }

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}
.panel-title {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
  margin: 0;
}
.panel-title.is-danger { color: #b04545; }
.panel-action {
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
  cursor: pointer;
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 1px;
  background: transparent;
  border-left: 0;
  border-right: 0;
  border-top: 0;
  font-family: inherit;
}
.panel-action:hover:not(:disabled) { color: var(--text); }
.panel-action:disabled {
  color: var(--text-faint);
  border-bottom-color: var(--border);
  cursor: not-allowed;
}

.panel-sub {
  margin: 0 0 14px;
  max-width: 640px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
}


/* 20. SUBPAGES — KPI TILES + BAR CHART ==================================== */

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.kpi {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px 18px;
  background: var(--bg);
}
.kpi-label {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
}
.kpi-value {
  font-family: var(--font-mono);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.kpi-unit {
  margin-left: 4px;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-muted);
}
.kpi-trend {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-muted);
}
.kpi-trend.is-up   { color: var(--accent); }
.kpi-trend.is-down { color: #b04545; }

.bar-chart {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}
.bar-list {
  height: 140px;
  padding: 0 2px;
  display: flex;
  align-items: flex-end;
  gap: 6px;
}
.bar-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.bar {
  background: var(--text);
  border-radius: 2px;
  min-height: 2px;
  opacity: 0.85;
}
.bar.is-fwd   { background: var(--accent); opacity: 1; }
.bar.is-reply { background: var(--text);   opacity: 0.6; }
.bar.is-spam  { background: #c98a3b;       opacity: 1; }

.bar-axis {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-faint);
  text-align: center;
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  font-size: 12px;
  color: var(--text-muted);
}
.chart-legend > span {
  display: flex;
  align-items: center;
  gap: 6px;
}
.legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex-shrink: 0;
  display: inline-block;
}
.legend-swatch.is-fwd   { background: var(--accent); }
.legend-swatch.is-reply { background: var(--text); opacity: 0.6; }
.legend-swatch.is-spam  { background: #c98a3b; }


/* 21. SUBPAGES — DATA ROWS + BANNER + CODES =============================== */

/* Generic table-style row used inside a panel. The grid template is set
   per-context via inline style or a modifier so rows can match their
   columns without forcing a single shape on the component. */
.data-row {
  display: grid;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  border-radius: 8px;
  transition: background 120ms ease;
}
.data-row + .data-row { margin-top: 2px; }
.data-row:hover { background: var(--bg-subtle); }
.data-row-mono {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.data-row-meta {
  font-size: 12px;
  color: var(--text-muted);
}
.data-row-num {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.data-row-num-suffix {
  margin-left: 4px;
  font-size: 11px;
  color: var(--text-faint);
}
.data-row-action {
  color: var(--text-faint);
  text-align: center;
}

/* Volume bar embedded next to a number in a top-N list. */
.volume-bar {
  background: var(--bg-muted);
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
}
.volume-bar-fill {
  background: var(--accent);
  height: 100%;
}

/* Privacy / context banner with a coloured left border. Sits inside
   .main, which has no horizontal padding, so the banner provides its
   own inset (32px to match .main-head-inner). Without this the banner
   would render edge-to-edge — wrong severity signal for activation
   nudges and warnings alike. */
.banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 16px;
  margin: 18px 32px;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
}
.banner-icon { color: var(--accent); flex-shrink: 0; margin-top: 1px; }
.banner-text {
  flex: 1;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
}
.banner-text strong {
  color: var(--text);
  font-weight: 500;
}
.banner.is-warn {
  border-left-color: var(--status-warn);
  background: var(--status-warn-bg);
}
.banner.is-warn .banner-icon { color: var(--status-warn-fg); }
.banner.is-warn .banner-text,
.banner.is-warn .banner-text strong { color: var(--status-warn-fg); }
.banner.is-blocked {
  border-left-color: #b04545;
  background: color-mix(in srgb, #b04545 6%, transparent);
}
.banner.is-blocked .banner-icon { color: #b04545; }
.banner.is-blocked .banner-text,
.banner.is-blocked .banner-text strong { color: #b04545; }
.banner.is-nudge {
  border-left-color: var(--color-primary, #2563eb);
  background: var(--color-bg-info, #eff6ff);
  display: block;
}
.banner-actions { display: flex; gap: 8px; margin-top: 8px; }

/* Inline empty-state used inside a panel (e.g. no passkeys yet). */
.inline-empty {
  padding: 22px;
  text-align: center;
  font-size: 13px;
  color: var(--text-muted);
  background: var(--bg-subtle);
  border: 1px dashed var(--border);
  border-radius: 8px;
}

/* Recovery codes grid: 2 columns of mono strings, used ones struck-through. */
.codes-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  padding: 14px;
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: var(--font-mono);
  font-size: 13px;
}
.code              { color: var(--text); }
.code.is-used {
  color: var(--text-faint);
  text-decoration: line-through;
}


/* 22. SUBPAGES — SETTING ROWS + TOGGLE ==================================== */

/* Three-column row used in Security/Settings panels: label · value · action. */
.setting-row {
  display: grid;
  grid-template-columns: 220px 1fr auto;
  gap: 24px;
  align-items: center;
  padding: 16px 0;
  border-bottom: 1px dashed var(--border);
}
.setting-row:last-child { border-bottom: none; }
.setting-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.setting-label.is-danger { color: #b04545; }
.setting-hint {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text-muted);
}
.setting-value {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text);
}
.setting-value.is-muted {
  color: var(--text-muted);
  font-family: var(--font-sans);
}
.setting-value.is-warn    { color: var(--status-warn-fg); }
.setting-value.is-blocked { color: #b04545; }
.setting-value-soft {
  color: var(--text-faint);
}

/* Tabular row layout for the Security view — sessions, passkeys, API
   tokens, and the audit log all share the same shape (label + two
   timestamps + action), so a real <table> with shared header makes
   the panels scannable across rows without per-row label prefixes. */
.data-table {
  width: 100%;
  border-collapse: collapse;
}
.data-table thead th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  padding: 8px 12px 8px 0;
  border-bottom: 1px solid var(--border);
}
.data-table tbody td {
  padding: 14px 12px 14px 0;
  font-size: 13px;
  color: var(--text);
  vertical-align: top;
  border-bottom: 1px dashed var(--border);
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table .cell-sub {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--text-muted);
}
.data-table .col-action {
  text-align: right;
  width: 1%;
  white-space: nowrap;
  padding-right: 0;
}
.data-table tr.is-revoked td { opacity: 0.55; }

/* Fade in security tables on the loading→loaded swap. The
   .inline-empty loading row and the table are different DOM elements,
   so React unmounts/remounts the table when status flips. */
.data-table {
  animation: content-fade-in 150ms ease-out;
}
@keyframes content-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Disclosure for the inline API documentation. Suppress the browser's
   default ▶ marker (which sits awkwardly close to text and renders
   differently on Chrome/Safari/Firefox) and replace with a CSS-only
   chevron that flips on [open]. */
.api-docs > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  user-select: none;
}
.api-docs > summary::-webkit-details-marker { display: none; }
.api-docs > summary::before {
  content: "";
  width: 0;
  height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform 120ms ease;
}
.api-docs[open] > summary::before { transform: rotate(90deg); }
.api-docs > summary:hover { color: var(--accent); }

/* Functional toggle switch — wraps a hidden checkbox in a styled label.
   Markup: <label class="toggle"><input type="checkbox" [checked]>
            <span class="toggle-thumb"></span></label>
   Click anywhere on the track flips the state via the native checkbox. */
.toggle {
  position: relative;
  display: inline-block;
  width: 36px;
  height: 20px;
  background: var(--border-strong);
  border-radius: 10px;
  cursor: pointer;
  transition: background 150ms ease;
  flex-shrink: 0;
}
.toggle input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.15);
  transition: left 150ms ease;
  pointer-events: none;
}
.toggle:has(input:checked) { background: var(--accent); }
.toggle:has(input:checked) .toggle-thumb { left: 18px; }
.toggle:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Danger-tinted secondary button for destructive actions (delete account). */
.btn-danger {
  color: #b04545;
  border-color: #d9b3b3;
}
.btn-danger:hover:not(:disabled) {
  background: color-mix(in srgb, #b04545 8%, transparent);
}
/* Armed state: first click on a destructive button stages a confirm
   step, the second click within 3 s commits. The intense red bg makes
   "this is the irreversible click" obvious so the user can't mistake
   it for the same button they just hovered over. */
.btn-danger.is-armed,
.btn-danger.is-armed:hover:not(:disabled) {
  background: #b04545;
  color: #fff;
  border-color: #b04545;
}

/* Confirmation dialog (e.g. delete account). Fixed-position backdrop
   centred via flex; the dialog itself is plain bg with a soft shadow. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 18, 22, 0.55);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.modal-dialog {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25);
  max-width: 440px;
  width: 100%;
  padding: 22px 24px 20px;
}
.modal-title {
  margin: 0 0 10px;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}
.modal-body {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-muted);
}
.modal-body p { margin: 0 0 8px; }
.modal-body p:last-child { margin-bottom: 0; }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}
.modal-prompt {
  margin-top: 14px;
  font-size: 12px;
  color: var(--text);
  font-weight: 500;
}
.modal-input {
  width: 100%;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  margin-top: 4px;
  box-sizing: border-box;
}
.modal-input:focus {
  outline: 2px solid var(--accent, #4f6cff);
  outline-offset: 0;
  border-color: transparent;
}

/* Session row with a "current" tag inline next to the device name. */
.session-row-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.session-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
}
.session-tag-current {
  margin-left: 8px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent);
}
.session-ip {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}


/* 21b. STATIC LEGAL PAGES ================================================= */

/* Body class shared by /imprint, /terms, /privacy, /refund-policy. The
   inner <main> is capped at 720px so long-form legal prose doesn't
   stretch to the viewport edge on wide displays — matches the
   Addendum §12 "must stay readable through a DB outage" requirement
   by keeping styling self-contained (no SPA, no JS). */
.legal main {
  max-width: 720px;
  margin: 32px auto 16px;
  padding: 0 24px;
  color: var(--text);
  font-size: 16px;
  line-height: 1.6;
}
.legal h1 {
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 24px;
}
.legal h2 {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.012em;
  margin: 32px 0 12px;
}
.legal h3 {
  font-size: 16px;
  font-weight: 600;
  margin: 20px 0 8px;
}
.legal p,
.legal ul,
.legal ol {
  margin: 0 0 14px;
}
.legal ul,
.legal ol {
  padding-left: 20px;
}
.legal li + li {
  margin-top: 4px;
}
.legal a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal a:hover {
  text-decoration: none;
}
.legal code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  background: var(--bg-muted);
  padding: 1px 4px;
  border-radius: 3px;
}
/* Pflichtinhalte tables (DSGVO Art. 13/14 processing matrix in /privacy
   etc.). Borrows the .pricing-table cell rhythm so the two read-heavy
   tables on the site share the same visual language. */
.legal table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 18px;
  font-size: 14px;
}
.legal th,
.legal td {
  border-bottom: 1px solid var(--border);
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
}
.legal th {
  font-weight: 600;
  color: var(--text-muted);
}
/* Draft / pre-launch banner. The legal markdown drafts open with a
   blockquote that flags the content as unreviewed — style it loud
   enough that the operator can't miss it on a casual production check. */
.legal blockquote {
  margin: 0 0 24px;
  padding: 12px 16px;
  border-left: 3px solid var(--status-warn-fg);
  background: var(--status-warn-bg);
  color: var(--status-warn-fg);
  border-radius: 0 4px 4px 0;
}
.legal blockquote p { margin: 0; }
/* Version + last-changed-at line, rendered after the markdown body
   from the EDN frontmatter — gives the page a "frozen-at-deploy"
   feel matching the static legal content. */
.legal .legal-meta {
  margin: 32px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-faint);
}


/* 21c. /licenses ========================================================== */

/* Server-rendered open-source attribution page (spec §13.4). Public,
   no SPA. Capped at 56rem so the license-text cards stay readable
   on wide displays. */
.licenses main {
  max-width: 56rem;
  margin: 32px auto 16px;
  padding: 0 24px;
  color: var(--text);
  font-size: 15px;
  line-height: 1.55;
}
.licenses h1 {
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 16px;
}
.licenses h2 {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 8px;
}
.licenses p {
  margin: 0 0 14px;
  color: var(--text-muted);
}
.licenses-list {
  list-style: none;
  padding: 0;
  margin: 24px 0 0;
}
.licenses-component {
  margin: 16px 0;
  padding: 16px 18px 18px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-subtle);
}
.licenses-name {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 4px;
  color: var(--text);
}
.licenses-name .licenses-version {
  font-weight: 400;
  color: var(--text-subtle);
  font-size: 13px;
  margin-left: 4px;
}
.licenses-copyright {
  margin: 0 0 10px;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.45;
}
.licenses-fulltext {
  margin: 6px 0 0;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.licenses-fulltext + .licenses-fulltext { margin-top: 8px; }
.licenses-fulltext > summary {
  padding: 7px 12px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text-muted);
  user-select: none;
}
.licenses-fulltext > summary:hover { background: var(--bg-muted); }
.licenses-fulltext[open] > summary { border-bottom: 1px solid var(--border); }
/* Fixed character-width wrap, independent of viewport. 80ch is the
   conventional readable line for monospace; long SPDX-text lines fold
   so the page never horizontal-scrolls. */
.licenses-fulltext > pre {
  margin: 0;
  padding: 10px 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--text);
  max-width: 80ch;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}


/* 23. RESPONSIVE — MOBILE TOP-BAR ========================================= */
/* Below 768px the left sidebar flips to a horizontal top-bar without
   touching markup. The two .sidebar-section wrappers and their .sidebar-nav
   children are flattened with display: contents so the .sidebar-item
   nodes become direct flex children of .sidebar and distribute equally
   across the full width.

   Footer composition on production:
     .sidebar-footer
       .sidebar-feedback              (CTA pill — icon-only on mobile)
       .lang-switcher                 (DE | EN — kept compact)
       .sidebar-user
         .sidebar-avatar              (hidden on mobile)
         .sidebar-user-info           (hidden on mobile)
         .sidebar-logout              (always visible — primary action)

   The footer is lifted out of flex flow with position: absolute and
   pinned to the right edge of the brand row. That keeps logout
   reachable without burying it behind a hamburger and without
   stealing space from the nav strip below. */
@media (max-width: 767px) {
  .app {
    flex-direction: column;
    height: auto;
    min-height: 100vh;
    overflow: visible;
  }

  .sidebar {
    width: 100%;
    height: auto;
    padding: 0;
    flex-direction: row;
    flex-wrap: wrap;
    overflow: visible;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 10;
    transition: none;
  }

  /* Brand row consumes the full first flex line so the .sidebar-item
     children wrap onto a second line below. The right-side padding
     reserves space for the absolutely positioned footer cluster. */
  .sidebar-brand {
    flex: 1 1 100%;
    padding: 8px 152px 8px 16px;
    margin-bottom: 0;
    border-bottom: 1px solid var(--border);
    min-height: 48px;
  }
  .sidebar-toggle { display: none; }

  /* Flatten section + nav wrappers so every .sidebar-item becomes a
     direct flex child of .sidebar and spreads evenly across the row. */
  .sidebar-section { display: contents; }
  .sidebar-section-label { display: none; }
  .sidebar-nav { display: contents; }

  .sidebar-item {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 8px 4px;
    min-height: 56px;
    border-radius: 0;
    text-align: center;
    font-size: 11px;
    line-height: 1.2;
    white-space: normal;
    position: relative;
    transition: color 120ms ease, background 120ms ease;
  }
  .sidebar-item.is-active {
    background: transparent;
    box-shadow: none;
    color: var(--accent);
  }
  /* Underline reads cleaner than the desktop pill in a horizontal strip
     and keeps the existing .is-active hook. */
  .sidebar-item.is-active::after {
    content: '';
    position: absolute;
    left: 12px;
    right: 12px;
    bottom: 0;
    height: 2px;
    background: var(--accent);
    border-radius: 2px;
  }
  .sidebar-badge {
    position: absolute;
    top: 4px;
    right: 6px;
    margin: 0;
  }

  /* Pull the footer out of flex flow and pin it to the brand row's
     right edge, in the order: feedback · DE | EN · logout. */
  .sidebar-footer {
    position: absolute;
    top: 0;
    right: 8px;
    height: 48px;
    margin: 0;
    padding: 0;
    border-top: 0;
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .sidebar-footer .lang-switcher { margin-bottom: 0; }
  /* Drop the desktop bottom margin; in the centred flex row it offsets
     the pill's margin box and pushes it ~5px above the logout button. */
  .sidebar-footer .tier-pill { margin-bottom: 0; }
  .sidebar-feedback {
    padding: 6px 8px;
    margin-bottom: 0;
  }
  .sidebar-feedback span { display: none; }
  .sidebar-user {
    padding: 0;
    margin: 0;
    gap: 0;
    background: transparent;
  }
  .sidebar-user .sidebar-avatar,
  .sidebar-user .sidebar-user-info { display: none; }
  /* .sidebar-logout has no desktop styling today (browser default).
     Scope the icon-button rules to the mobile breakpoint so desktop
     stays untouched. */
  .sidebar-logout {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--text-faint);
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
  }
  .sidebar-logout:hover {
    background: var(--bg-muted);
    color: var(--text);
  }

  .main {
    overflow: visible;
    height: auto;
  }

  /* Subpage chrome — desktop's 32px horizontal padding leaves too
     little room for actual content on a 360px viewport. */
  .page-head-inner { padding: 0 16px; }
  .panel           { padding: 18px 16px; }

  /* Three-column grid (label · value · action) collapses to a vertical
     stack so wide values and right-aligned actions don't overflow. The
     empty placeholder span that setting-row renders for action-less
     rows would otherwise add a blank line, so suppress it. */
  .setting-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    padding: 14px 0;
  }
  .setting-row > span:empty { display: none; }

  /* Reflow the security-view table (sessions, passkeys, API tokens,
     audit log) into stacked card rows. The thead is dropped because
     each .cell-sub already carries inline context, so per-cell column
     labels would feel redundant. */
  .data-table,
  .data-table tbody,
  .data-table tr,
  .data-table td {
    display: block;
    width: auto;
  }
  .data-table thead { display: none; }
  .data-table tbody tr {
    padding: 12px 0;
    border-bottom: 1px dashed var(--border);
  }
  .data-table tbody tr:last-child { border-bottom: none; }
  .data-table tbody td {
    padding: 4px 0;
    border-bottom: 0;
  }
  .data-table .col-action {
    text-align: left;
    width: auto;
    padding-top: 8px;
    white-space: normal;
  }

  /* Alias rows reflow to two lines so the address (mono, can be 30+
     chars) gets the full row width on top, with the context tag on
     the line below. The desktop grid had a minmax(0, 1fr) name
     column that collapsed to zero whenever the fixed-width context
     column consumed all the space — that's what hid the address on
     a 360px viewport. */
  .alias-row {
    grid-template-columns: 14px minmax(0, 1fr);
    grid-template-rows: auto auto;
    grid-template-areas:
      "status name"
      "status context";
    gap: 4px 10px;
    padding: 12px 16px;
  }
  .alias-row > .alias-status       { grid-area: status; align-self: center; }
  .alias-row > .alias-name         { grid-area: name; }
  .alias-row > .alias-context-cell { grid-area: context; }
}

/* Phase 9 — Domain UI (DOMAIN-03, DOMAIN-12) */
.domain-wizard-step { padding: 16px 0 0; }
.wizard-subtitle { font-size: 0.85em; color: var(--color-muted, #666); margin-bottom: 6px; }
.wizard-lead {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0 0 16px;
  max-width: 640px;
}

.domain-records-table { width: 100%; border-collapse: collapse; font-size: 0.9em; margin: 12px 0; table-layout: fixed; }
.domain-records-table th,
.domain-records-table td { padding: 6px 10px; border-bottom: 1px solid var(--color-border, #e5e7eb); text-align: left; vertical-align: top; }
/* Type ~ 60px, Host ~ 24%, Priority ~ 70px, Value fills the rest.
   fixed table-layout + overflow-wrap:anywhere lets long names wrap on
   demand instead of collapsing one letter per line. Priority column
   carries the MX preference number; the other rows render an em dash. */
.domain-records-table th:nth-child(1),
.domain-records-table td:nth-child(1) { width: 60px; }
.domain-records-table th:nth-child(2),
.domain-records-table td:nth-child(2) { width: 24%; }
.domain-records-table th:nth-child(3),
.domain-records-table td:nth-child(3) { width: 70px; }
.domain-records-table th:nth-child(5),
.domain-records-table td:nth-child(5) { width: 80px; }
.domain-records-table .dns-type { font-family: monospace; color: var(--color-muted, #666); }
.domain-records-table .dns-host,
.domain-records-table .dns-value { font-family: monospace; overflow-wrap: anywhere; }
.domain-records-table .dns-priority { font-family: monospace; color: var(--color-muted, #666); }

/* Per-row Status column. Plain text labels — green for OK, red for
   Missing, muted em dash before the first verify run. Font is not
   monospace because the values are localised words, not DNS data. */
.domain-records-table .dns-status { font-size: 0.85em; font-weight: 600; white-space: nowrap; }
.domain-records-table .dns-status.is-ok      { color: var(--color-success, #16a34a); }
.domain-records-table .dns-status.is-missing { color: var(--color-danger,  #dc2626); }
.domain-records-table .dns-status.is-pending { color: var(--color-muted,   #666); font-weight: 400; }

.copy-cell { cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.copy-cell:hover .copy-icon { opacity: 1; }
.copy-icon { opacity: 0; font-size: 0.8em; color: var(--color-primary, #2563eb); transition: opacity 0.1s; }
.copy-icon.is-copied { opacity: 1; color: var(--color-success, #16a34a); }

.domain-spf-footnote { font-size: 0.8em; color: var(--color-muted, #666); margin: 8px 0; }
.domain-verify-panel { background: var(--color-bg-subtle, #f9fafb); border-radius: 6px; padding: 12px 16px; margin: 12px 0; }
.verify-status { font-size: 0.9em; margin-bottom: 4px; }
.verify-last-checked { font-size: 0.75em; color: var(--color-muted, #666); margin: 0 0 8px; }

/* Form-actions row: cancel + continue side-by-side with breathing
   room. Without a gap the buttons render flush against each other.
   align-items:center keeps the Cancel (btn-sm) vertically centred
   against the larger primary Continue. */
.domain-wizard-step .form-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 16px; }

/* Tiny CSS-only spinner for buttons in an in-flight state. The
   ::before pseudo-element is rendered before the button label so the
   label text remains readable; opacity:0.7 on the button conveys
   "disabled" without going so faint that the label disappears. */
.btn.is-loading { opacity: 0.7; pointer-events: none; }
.btn.is-loading::before {
  content: "";
  display: inline-block;
  width: 0.8em;
  height: 0.8em;
  margin-right: 0.5em;
  vertical-align: -2px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: btn-spinner 0.8s linear infinite;
}
@keyframes btn-spinner { to { transform: rotate(360deg); } }

.domain-card-head { display: flex; justify-content: space-between; align-items: center; }
.is-mono { font-family: monospace; }
.alias-count-chip { font-size: 0.85em; color: var(--color-primary, #2563eb); text-decoration: none; }
.alias-count-chip:hover { text-decoration: underline; }

/* Filter chip on /dashboard#aliases?domain=<id>: piggy-backs on the
   generic .chip pill (border, padding, hover) and just removes the
   anchor underline plus emphasises the × close marker so the click-
   to-clear affordance reads at a glance. */
.alias-filter-chip { text-decoration: none; }
.alias-filter-chip-x { margin-left: 4px; font-weight: 600; }

.domain-reverify-slot { padding: 12px 20px; border-bottom: 1px solid var(--color-border, #e5e7eb); }

/* Actual domain identifier in the detail card body. Mono is the
   visual cue; the explicit 14 px matches the .btn font-size below
   so the identifier and Remove Domain button read at the same
   weight. Body-default 15 px combined with mono letterforms made it
   visibly larger than surrounding text. */
.domain-card-name { font-family: monospace; font-size: 14px; margin: 0 0 12px; word-break: break-all; }

.domain-remove-alias-list { list-style: none; padding: 0; max-height: 200px; overflow-y: auto; margin: 8px 0; }
.domain-remove-alias-list li { padding: 4px 0; font-family: monospace; font-size: 0.9em; }
.domain-remove-alias-list .is-danger { color: var(--color-danger, #dc2626); }

/* -- Alias-create row + domain picker (Phase 9.1, DOMAIN-14) ---------- */

.alias-create-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.domain-picker-wrap {
  position: relative;
}

.domain-picker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 14px;
  color: inherit;
  cursor: pointer;
}

.domain-picker:hover {
  background: var(--bg-subtle);
}

.domain-picker[aria-expanded="true"] {
  background: var(--bg-subtle);
}

.domain-picker-caret {
  color: var(--text-faint);
  font-size: 10px;
  line-height: 1;
}

.domain-picker-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 100%;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  padding: 4px 0;
  z-index: 20;
  list-style: none;
  margin: 0;
}

.domain-picker-option {
  display: block;
  width: 100%;
  padding: 6px 12px;
  border: 0;
  background: transparent;
  text-align: left;
  font-family: var(--font-mono);
  font-size: 14px;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.domain-picker-option:hover,
.domain-picker-option:focus {
  background: var(--bg-subtle);
  outline: none;
}

.domain-picker-option.is-selected::before {
  content: "✓ ";
  color: var(--text-faint);
}

.domain-picker-option:not(.is-selected)::before {
  /* Reserve the same indent so selected and unselected align. */
  content: "  ";
  white-space: pre;
}

@media (max-width: 640px) {
  .domain-picker-menu {
    right: auto;
    left: 0;
    width: max-content;
  }
  /* Keep the title group and the create-row on a single line on phones
     too (operator request): the base rule's row + space-between is
     retained; we only tighten the gutters and gap so the compact btn-sm
     "New alias" fits beside the title. min-width:0 lets the title group
     shrink (its mono count is the first to give) rather than shoving the
     button off the row; the create-row never shrinks. */
  .main-head-inner {
    padding: 12px 16px;
    gap: 8px;
    min-height: 0;
  }
  .main-title {
    min-width: 0;
  }
  .alias-create-row {
    flex-shrink: 0;
  }
}

/* ---- Skip-Link (A11y) ----
   Off-screen until focused; keyboard users tab into this first and
   jump past the nav to <main id="main">. */
.skip-link {
  position: absolute;
  top: -100px;
  left: 8px;
  padding: 10px 14px;
  background: var(--text);
  color: var(--bg);
  border-radius: 6px;
  text-decoration: none;
  font-weight: 500;
  z-index: 100;
}
.skip-link:focus {
  top: 8px;
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
