/* Shared design tokens + component vocabulary for both the admin console
   and tenant portal. One stylesheet, reused by every page (same pattern
   the reference project uses for its own two portals) -- a page's own
   <style> block should only ever hold page-specific layout, never redefine
   these tokens. */

:root {
  --bg: #0b1220;
  --surface: #131b2e;
  --surface-raised: #182338;
  --border: #25314a;
  --text: #e8edf5;
  --text-muted: #8b96ab;
  --accent: #f5b942;
  --accent-text: #1a1406;
  --success: #3ecf8e;
  --danger: #f2545b;
  --danger-text: #ffffff;
  --warning: #f5b942;
  --info: #5aa9e6;
  --radius: 8px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* Space Grotesk, per the logo kit -- only loaded (Google Fonts) on pages
     that actually use it for display text; falls back to the system stack
     everywhere else without needing a second @font-face. */
  --font-display: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* The real sailDNS brand palette (design/saildns-logo/README.md) -- distinct
     from the tokens above, which are this app's general dark-UI chrome.
     Use these only where something needs to visually match the logo/mark
     itself (illustrations, brand-colored accents), not as a substitute for
     --accent/--info/etc. in ordinary UI. */
  --brand-ink: #0A3543;
  --brand-teal: #1C8FA8;
  --brand-spray: #57C8C2;
  --brand-amber: #F2A63C;
  --brand-cloth: #F4F8F7;
  --brand-deep: #06222C;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
}

a {
  color: var(--info);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

h1, h2, h3 {
  margin: 0 0 0.5em;
  font-weight: 600;
}
h1 { font-size: 20px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

code, .mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

/* --- App shell (sidebar + content) --- */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 20px 0;
  /* Pinned to the viewport, not just stretched to .app-shell's flex height
     -- without this, a page tall enough to need real scrolling (the wiki's
     architecture.md render, the first page in this app long enough to
     expose it) scrolls the sidebar's own nav links out of view along with
     the rest of the page, since nothing was otherwise holding them in
     place. Its own scroll for the pathological case where the nav list
     itself someday grows taller than the viewport. */
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 20px 20px;
  font-weight: 700;
  font-size: 16px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}
.brand-mark { height: 22px; width: 22px; flex-shrink: 0; }

/* Collapsible nav groups (shared/app.js's renderNavGroups/wireNavGroups) --
   only the group holding the active page starts open, so the sidebar shows
   a handful of section headers instead of every link in the app at once. */
.nav-group:first-child .nav-section-toggle {
  padding-top: 0;
}

.nav-section-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 18px 20px 6px;
  background: none;
  border: none;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
}
.nav-section-toggle:hover {
  color: var(--text);
}

.nav-toggle-chevron {
  width: 6px;
  height: 6px;
  margin-top: -2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); /* pointing right -- collapsed */
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.nav-group.open .nav-toggle-chevron {
  transform: rotate(45deg); /* pointing down -- open */
}

.nav-group-links {
  display: none;
}
.nav-group.open .nav-group-links {
  display: block;
}

.nav-link {
  display: block;
  padding: 10px 20px;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
  border-left: 3px solid transparent;
}
.nav-link:hover {
  color: var(--text);
  text-decoration: none;
  background: var(--surface-raised);
}
.nav-link.active {
  color: var(--accent);
  border-left-color: var(--accent);
  background: var(--surface-raised);
}


.main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 28px;
  border-bottom: 1px solid var(--border);
}

/* Injected by shared/app.js's renderTopbarMenu -- wraps whatever a page's
   own topbar already had (e.g. a "+ New X" button) alongside the account
   menu, so both end up grouped at the far right instead of the topbar's
   own space-between spreading three top-level children evenly. */
.topbar-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

.topbar-account {
  position: relative;
}

.topbar-account-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.topbar-account-trigger:hover {
  color: var(--text);
  border-color: var(--text-muted);
}
.topbar-account-trigger .nav-toggle-chevron {
  transform: rotate(45deg); /* pointing down, matches the sidebar's own "open" chevron */
}

.topbar-account-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 180px;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  z-index: 20;
}

.topbar-account-item {
  display: block;
  width: 100%;
  padding: 8px 10px;
  background: none;
  border: none;
  border-radius: calc(var(--radius) - 2px);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.topbar-account-item:hover {
  background: var(--surface);
  text-decoration: none;
}

.topbar-account-divider {
  height: 1px;
  margin: 6px 4px;
  background: var(--border);
}

.content {
  padding: 28px;
  max-width: 1100px;
}

/* --- Centered auth layout (login) --- */

.auth-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.auth-card {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px;
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 20px;
  font-weight: 700;
  margin-bottom: 24px;
}
.auth-brand .brand-mark { height: 28px; width: 28px; }

/* --- Components --- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  margin-bottom: 20px;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

/* --- Tabs: one visible section at a time (shared/app.js's initTabs) --- */

.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;
  overflow-x: auto;
}

.tab-btn {
  flex-shrink: 0;
  padding: 10px 18px;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.tab-btn:hover {
  color: var(--text);
}
.tab-btn.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab-panel {
  display: none;
}
.tab-panel.active {
  display: block;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
}
.btn:hover { background: var(--border); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-text);
}
.btn-primary:hover { filter: brightness(1.08); }

.btn-danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
}
.btn-danger:hover { background: var(--danger); color: var(--danger-text); }

.btn-sm { padding: 5px 10px; font-size: 12px; }

.form-field {
  margin-bottom: 16px;
}
.form-field label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.input, select.input, textarea.input {
  width: 100%;
  padding: 9px 12px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
}
.input:focus {
  outline: none;
  border-color: var(--accent);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.table th {
  text-align: left;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
}
.table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.table tr:last-child td { border-bottom: none; }
.table tr:hover td { background: var(--surface-raised); }

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.badge-success { background: rgba(62, 207, 142, 0.15); color: var(--success); }
.badge-danger { background: rgba(242, 84, 91, 0.15); color: var(--danger); }
.badge-warning { background: rgba(245, 185, 66, 0.15); color: var(--warning); }
.badge-info { background: rgba(90, 169, 230, 0.15); color: var(--info); }
.badge-muted { background: rgba(139, 150, 171, 0.15); color: var(--text-muted); }

.stat-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.stat-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 20px;
  min-width: 140px;
}
.stat-tile .value {
  font-size: 24px;
  font-weight: 700;
}
.stat-tile .label {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-muted);
}

.error-banner {
  background: rgba(242, 84, 91, 0.12);
  border: 1px solid var(--danger);
  color: var(--danger);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}

.success-banner {
  background: rgba(62, 207, 142, 0.12);
  border: 1px solid var(--success);
  color: var(--success);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 13px;
  margin-bottom: 16px;
}

.hint {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 4px;
}

/* --- Modal (used for confirm dialogs) --- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  width: 100%;
  max-width: 380px;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 20px;
}

/* --- Toasts --- */

.toast-stack {
  position: fixed;
  bottom: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 200;
}
.toast {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 16px;
  font-size: 13px;
  min-width: 220px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.toast-success { border-color: var(--success); }
.toast-error { border-color: var(--danger); }

.code-block {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 14px 16px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text);
  margin: 0;
}

.text-muted { color: var(--text-muted); }
.flex-between { display: flex; align-items: center; justify-content: space-between; }

/* --- Public marketing site (root domain: site-home/site-whitepaper/site-request) --- */

.site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 32px;
  border-bottom: 1px solid var(--border);
  /* Pinned to the viewport while the page scrolls, not just stretched to
     the top of the document -- without an explicit background here, a
     sticky element lets page content scroll up visibly underneath it. */
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
}
.site-nav .site-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 18px;
  font-weight: 700;
}
.site-nav .site-brand .brand-mark { height: 24px; width: 24px; }
.site-nav .site-links {
  display: flex;
  align-items: center;
  gap: 24px;
  font-size: 13px;
  font-weight: 500;
}
.site-nav .site-links a { color: var(--text-muted); }
.site-nav .site-links a:hover { color: var(--text); text-decoration: none; }

.site-main {
  max-width: 960px;
  margin: 0 auto;
  padding: 0 32px 80px;
}

.site-hero {
  text-align: center;
  padding: 72px 0 48px;
}
.site-hero h1 {
  font-size: 36px;
  margin-bottom: 12px;
}
.site-hero p {
  font-size: 16px;
  color: var(--text-muted);
  max-width: 640px;
  margin: 0 auto 28px;
}

.site-section {
  padding: 40px 0;
  border-top: 1px solid var(--border);
}
.site-section h2 {
  font-size: 22px;
  margin-bottom: 8px;
}
.site-section > p.section-lead {
  color: var(--text-muted);
  margin-bottom: 28px;
  max-width: 640px;
}

.site-feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
.site-feature {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
}
.site-feature h3 {
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
  font-size: 15px;
  margin-bottom: 6px;
}
.site-feature p {
  color: var(--text-muted);
  font-size: 13px;
  margin: 0;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 20px;
}
.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 20px;
  text-align: center;
}
.stat-number {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 32px;
  color: var(--brand-amber);
  line-height: 1;
  margin-bottom: 8px;
}
.stat-label { font-size: 13px; color: var(--text); line-height: 1.5; }
.stat-sources { font-size: 11px; color: var(--text-muted); text-align: center; margin-top: 4px; }

.site-footer {
  text-align: center;
  padding: 32px;
  color: var(--text-muted);
  font-size: 12px;
  border-top: 1px solid var(--border);
}

/* Long-form prose (whitepaper) laid over the same dark surface as .card */
.prose {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 40px;
  max-width: 760px;
  margin: 0 auto;
}
.prose h2 { font-size: 20px; margin-top: 32px; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { color: var(--text); text-transform: none; letter-spacing: normal; font-size: 15px; margin-top: 20px; }
.prose p { margin: 0 0 14px; }
.prose ul { margin: 0 0 14px; padding-left: 20px; }
.prose li { margin-bottom: 6px; }

/* Mobile layout -- every admin/tenant page shares this one .app-shell
   skeleton and pulls from this one file, so this single breakpoint covers
   all of them at once rather than needing 27 individual page fixes. The
   sidebar becomes an off-canvas drawer (shared/app.js's initMobileNav()
   injects the toggle button + backdrop and wires the open/close logic --
   called once, automatically, from guardedInit, so no page's own markup
   needed to change). 768px is the standard phone/small-tablet boundary --
   a reasonable default, not a value with any special significance here. */

/* Hidden outside the mobile breakpoint by default -- both are plain
   elements injected by initMobileNav() with no other styling of their own,
   so without this a real (if usually invisible) button/div sits in the
   topbar/body at desktop widths too, using the browser's default styling
   rather than actually being absent. The media query below is what shows
   them again below 768px. */
.mobile-nav-toggle,
.mobile-nav-backdrop {
  display: none;
}

@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 40;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: 0 0 24px rgba(0, 0, 0, 0.35);
  }
  .sidebar.open {
    transform: translateX(0);
  }

  /* Backdrop behind the open drawer -- injected by initMobileNav(), not
     present in any page's own markup. Clicking it closes the drawer,
     same as tapping outside the topbar account menu already does. */
  .mobile-nav-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 30;
  }
  .mobile-nav-backdrop.open {
    display: block;
  }

  .mobile-nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    margin-right: 12px;
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    cursor: pointer;
    flex-shrink: 0;
  }

  .topbar {
    padding: 12px 16px;
    flex-wrap: nowrap;
  }
  .topbar h1 {
    font-size: 16px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .content {
    padding: 16px;
  }

  /* Tables become stacked "label: value" cards instead of scrolling
     sideways -- every row's data stays readable without needing to pan the
     screen. The data-label values themselves are injected automatically by
     shared/app.js's initResponsiveTables(), reading each table's own static
     <thead> once and applying it to every cell regardless of how each
     page's own JS renders its rows -- no per-page markup changes needed. */
  .table thead {
    display: none;
  }
  .table,
  .table tbody,
  .table tr,
  .table td {
    display: block;
    width: 100%;
  }
  .table tr {
    margin-bottom: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .table tr:last-child {
    margin-bottom: 0;
  }
  .table td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
  }
  .table tr td:last-child {
    border-bottom: none;
  }
  .table td::before {
    content: attr(data-label);
    font-weight: 600;
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    flex-shrink: 0;
  }
  /* A column with no header text (the common trailing "actions" column,
     whose <th> is deliberately empty in the static markup) shouldn't show
     a bold blank label ahead of its button -- just right-align it instead. */
  .table td:not([data-label]),
  .table td[data-label=""] {
    justify-content: flex-end;
  }
  .table td:not([data-label])::before,
  .table td[data-label=""]::before {
    content: none;
  }

  /* Side-by-side fields (host/port pairs, etc.) stack instead of squishing
     into an unreadable width -- one rule fixes every such layout at once,
     since .flex-gap is the one shared class used for this everywhere. */
  /* Only when a .flex-gap's direct children are form fields (the
     side-by-side host/port-pair pattern) -- deliberately not every
     .flex-gap, since the same class is also used for button rows and
     badge rows elsewhere, which should stay side-by-side/wrap rather than
     stack full-width. */
  .flex-gap:has(> .form-field) {
    flex-direction: column;
    align-items: stretch;
  }
}

/* "Download PDF" buttons (admin-wiki.html) just call window.print() rather
   than generating a file server-side -- a deliberate choice over pulling in
   a headless-browser dependency (docs/decisions.md). This hides the chrome
   every page shares (sidebar, topbar, buttons) so what actually prints/
   saves-as-PDF is just the content. */
@media print {
  .sidebar, .topbar, .wiki-toc, #download-pdf, .tabs, .tab-btn { display: none !important; }
  .app-shell, .main, .content { display: block !important; margin: 0 !important; padding: 0 !important; }
  .tab-panel { display: block !important; }
  body { background: #fff; color: #000; }
}
.flex-gap { display: flex; align-items: center; gap: 8px; }
