/* charliehub-ui-kit — shared components (Deep Harbour).
   Depends on tokens.css + base.css being loaded first.
   Ticket: sdwan-v4.5 / WS-E / E1. Origin: vpn-spa-v2/app/static/css/theme.css.

   Scope note: this file holds structural/reusable primitives only — the
   header/nav shell, page wrapper, card, forms, buttons, tables, pills,
   language toggle, help-button, and small utility classes. App-specific
   page composition (FAQ layout, onboarding wizard, check-exit result cards,
   users-admin table, QR/confirm dialogs, etc.) stays in each app's own
   stylesheet and is built ON TOP of these primitives + the tokens above,
   per the two-layer architecture documented in tokens.css.
*/

/* ── Header / nav (Noz dark canvas) ────────────────────────────────────── */
.site-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 24px;
  background: var(--nz-900);
  color: var(--pearl);
  border-bottom: 1px solid var(--nz-700);
}
.site-header .brand { display: flex; align-items: center; gap: 10px; font-weight: 600; font-family: var(--font-display); font-size: 16px; color: var(--pearl); }
/* The Charliehub mark — transparent box; SVG colours via currentColor.
   Markup source: charliehub-ui-kit/jinja/macros.html `charliehub_mark()`. */
.site-header .brand .mark { width: 28px; height: 28px; display: inline-flex; color: var(--mg-300); flex: none; }
.site-header .brand .mark svg { width: 100%; height: 100%; display: block; }

.site-header nav > a {
  position: relative;
  color: var(--pearl);
  margin-left: 20px;
  opacity: 0.78;
  font-size: 14px;
  padding-bottom: 6px;
}
.site-header nav > a:hover { opacity: 1; text-decoration: none; }
.site-header nav > a.active { opacity: 1; }
/* Maen Roz accent — the "small indicator bar" per Deep Harbour. */
.site-header nav > a.active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--rz-300);
  border-radius: 1px;
}

/* Nav layout — single row, no wrap. */
.site-header nav {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 0;
}
.site-header nav > * { flex: 0 0 auto; }
.site-header nav .lang-toggle { margin-top: 0; }

/* Brand block becomes a link when wrapped in <a> (anonymous visitors click
   back to the app's public landing page) — keep the visual identical to the
   non-link form: no underline, no opacity drop. */
.site-header a.brand,
.site-header a.brand:hover,
.site-header a.brand:visited {
  color: var(--pearl);
  text-decoration: none;
}

/* Nav "help" affordance — text link promoted to a button-styled badge with
   an icon, so it reads as a distinct affordance rather than a plain link.
   App supplies its own icon/label/href; this only styles the shell. */
.site-header nav a.nav-help-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 20px;
  padding: 5px 11px 5px 9px;
  border-radius: var(--radius-input);
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.04);
  color: var(--pearl);
  font-size: 13px;
  opacity: 0.92;
  text-decoration: none;
}
.site-header nav a.nav-help-btn:hover {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.30);
  opacity: 1;
  text-decoration: none;
}
.site-header nav a.nav-help-btn.active {
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.35);
}
.site-header nav a.nav-help-btn.active::after { display: none; }   /* override the underline rule */
.site-header nav a.nav-help-btn svg { flex: none; display: block; }

/* Nav primary action (e.g. "Sign in") — Mor Gwer fill reads as the page's
   "next step" affordance against the Noz header. */
.site-header nav a.nav-login-btn {
  display: inline-flex;
  align-items: center;
  margin-left: 20px;
  padding: 5px 14px;
  border-radius: var(--radius-input);
  background: var(--mg-500);
  border: 1px solid var(--mg-500);
  color: var(--white);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .01em;
  opacity: 1;
}
.site-header nav a.nav-login-btn:hover {
  background: var(--mg-300);
  border-color: var(--mg-300);
  color: var(--white);
  text-decoration: none;
}
.site-header nav a.nav-login-btn::after { display: none; }   /* no active underline on primary buttons */

/* ── Page wrapper ──────────────────────────────────────────────────────── */
.page { max-width: 920px; margin: 24px auto; padding: 0 20px; }
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 24px;
}
.card + .card { margin-top: 16px; }

/* ── Forms ─────────────────────────────────────────────────────────────── */
label { display: block; font-size: 13px; font-weight: 600; color: var(--text); margin: 14px 0 6px; letter-spacing: .02em; }

input[type=text], input[type=email], input[type=password], select {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-strong);
  background: var(--bg-surface);
  transition: border-color .15s, box-shadow .15s;
  outline: none;
}
input:hover, select:hover { border-color: var(--border-hover); }
input:focus, select:focus { border-color: var(--focus-border); box-shadow: 0 0 0 3px var(--focus-ring); }
input[aria-invalid="true"], select[aria-invalid="true"] {
  border-color: var(--state-exposed);
  box-shadow: 0 0 0 3px rgba(214, 61, 46, 0.24);
}

/* ── Buttons ───────────────────────────────────────────────────────────── */
button, .btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 10px 18px; border: 1px solid transparent;
  border-radius: var(--radius-input);
  background: var(--action); color: var(--on-action);
  font-family: var(--font-sans); font-size: 14px; font-weight: 600;
  cursor: pointer;
  transition: background .18s, color .18s, border-color .18s;
}
button:hover, .btn:hover { background: var(--action-hover); color: var(--on-action); text-decoration: none; }
button:focus-visible, .btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* Secondary: transparent, action border + text, hover gets mg-50 wash. */
.btn-secondary {
  background: transparent;
  color: var(--action);
  border: 1px solid var(--action);
}
.btn-secondary:hover {
  background: var(--mg-50);
  color: var(--action-hover);
  border-color: var(--action-hover);
}

/* Tertiary / ghost: text-only link. */
.btn-tertiary, .btn-ghost {
  background: transparent;
  color: var(--link);
  border: 1px solid transparent;
}
.btn-tertiary:hover, .btn-ghost:hover {
  background: transparent;
  color: var(--action-hover);
  text-decoration: underline;
}

/* Danger reuses the exposed state-chip pair for clear "removes data" semantics. */
.btn-danger {
  background: transparent;
  color: var(--exposed-fg);
  border: 1px solid var(--exposed-bg);
}
.btn-danger:hover {
  background: var(--exposed-bg);
  color: var(--exposed-fg);
  border-color: var(--exposed-fg);
}

/* Icon + label variant — small gap so an inline SVG icon sits before the text. */
.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.btn-icon svg { flex: none; display: block; }

/* ── Tables ────────────────────────────────────────────────────────────── */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); }
th { color: var(--text-faint); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; }
tr:last-child td { border-bottom: none; }

/* ── Status chips ──────────────────────────────────────────────────────── */
.pill { display: inline-block; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 12px; font-weight: 500; line-height: 1.6; }
.pill-success { background: var(--protected-bg); color: var(--protected-fg); }
.pill-warn    { background: var(--connecting-bg); color: var(--connecting-fg); }
.pill-danger  { background: var(--exposed-bg); color: var(--exposed-fg); }
.pill-muted   { background: var(--bg-sunken); color: var(--text-muted); }

/* ── Language toggle (CT2151-style FR/EN pill) ──────────────────────────
   Light context by default; dark variant overrides for the .site-header
   navigation. Uses semantic tokens elsewhere so it auto-themes in any
   surface-noz context. Pairs with the `lang_toggle()` Jinja macro in
   charliehub-ui-kit/jinja/macros.html for consumers that render server-side;
   non-Jinja consumers can reuse just this CSS against equivalent markup. */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  background: var(--bg-sunken);
  border-radius: var(--radius-input);
  padding: 2px;
  gap: 1px;
  margin-top: 12px;
}
.lang-btn {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  padding: 4px 9px;
  border-radius: 4px;
  cursor: pointer;
  transition: color .15s, background .15s;
  line-height: 1;
}
.lang-btn:hover:not(.active) { color: var(--text-strong); background: transparent; }
.lang-btn.active {
  background: var(--bg-surface);
  color: var(--text-strong);
}
.lang-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}

/* Dark variant in the Noz nav — alpha-white pattern mirroring CT2151. */
.site-header .lang-toggle {
  background: rgba(255, 255, 255, 0.08);
  margin-top: 0;
  margin-left: 16px;
}
.site-header .lang-btn { color: rgba(255, 255, 255, 0.55); }
.site-header .lang-btn:hover:not(.active) { color: rgba(255, 255, 255, 0.85); background: transparent; }
.site-header .lang-btn.active {
  background: rgba(255, 255, 255, 0.18);
  color: var(--pearl);
}

/* ── Help icon button (round ghost) ─────────────────────────────────────
   Compact secondary entry point (e.g. to a help/FAQ page). Sits next to a
   primary action in card headers; visually subordinate to it. */
.help-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px; height: 36px;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--action);
  transition: background .15s, border-color .15s, color .15s;
  text-decoration: none;
  flex: none;
}
.help-btn:hover {
  background: var(--mg-50);
  border-color: var(--action);
  color: var(--action-hover);
  text-decoration: none;
}
.help-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.help-btn svg { display: block; }

/* Labeled variant — reuses .help-btn (round circular ghost) but expands at
   >=768px to show an inline text label, improving legibility without
   breaking the 36x36 mobile target. */
.help-btn-labeled {
  width: auto;
  height: 36px;
  padding: 0 12px 0 10px;
  gap: 6px;
  border-radius: 18px;
  border: 1px solid var(--mg-200);
  color: var(--action);
  background: var(--mg-50);
}
.help-btn-labeled:hover {
  background: var(--mg-50);
  border-color: var(--action);
  color: var(--action-hover);
}
.help-btn-labeled .help-btn-label {
  display: none;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}
@media (min-width: 768px) {
  .help-btn-labeled .help-btn-label { display: inline; }
}

/* ── Small utilities ─────────────────────────────────────────────────────── */
.muted { color: var(--text-muted); }
.kbd   { font-family: var(--font-mono); font-size: 12px; padding: 2px 6px; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: 4px; }
.row   { display: flex; gap: 12px; align-items: center; }
.row > .flex { flex: 1; }
.empty-state    { text-align: center; padding: 40px 20px; color: var(--text-muted); }
.empty-state h2 { color: var(--text-muted); margin-bottom: 6px; }
.fullscreen { min-height: 100vh; }

/* Visually hidden — accessible-only label. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ── E1.1 (sdwan-v4.5) — components promoted from the CharlieHub Control console
   so every kit consumer (vpn-spa-v2 included) inherits them. Generic only;
   nothing here is network-specific. Pair the sortable table with the
   `data_table_js()` macro in jinja/macros.html. ──────────────────────────── */

/* KPI / stat tiles */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.kpi { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; }
.kpi .v { font-family: var(--font-display); font-size: 26px; font-weight: 600; color: var(--text); line-height: 1.1; }
.kpi .k { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.kpi.good .v { color: var(--protected-fg); }
.kpi.warn .v { color: var(--connecting-fg); }
.kpi.bad  .v { color: var(--exposed-fg); }

/* Country flag chip — always render the flag next to a country. */
.flag { font-size: 15px; line-height: 1; }

/* Filter chips (a segmented in/out filter row) */
.filterbar { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.filter-chip { padding: 4px 11px; border-radius: var(--radius-pill); border: 1px solid var(--border); background: var(--bg-surface); color: var(--text); font: inherit; font-size: 13px; cursor: pointer; }
.filter-chip:hover { border-color: var(--mg-300); }
.filter-chip.active { border-color: var(--mg-500); color: var(--mg-500); font-weight: 500; }

/* Sortable + filterable table affordance. Add class="data-table" and
   <th data-sort="text|num">; behaviour comes from data_table_js(). */
.table-tools { display: flex; gap: 10px; align-items: center; margin-bottom: 8px; }
.table-tools input[type="search"] { flex: 0 0 220px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-input); background: var(--bg-surface); color: var(--text); font-size: 13px; }
.data-table th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
.data-table th[data-sort]::after { content: "↕"; opacity: .35; margin-left: 6px; font-size: 11px; }
.data-table th[data-sort][aria-sort="ascending"]::after  { content: "↑"; opacity: 1; }
.data-table th[data-sort][aria-sort="descending"]::after { content: "↓"; opacity: 1; }

/* ── E2.2 (sdwan-v4.5) — responsive behaviour for the kit's own primitives.
   app-shell.css already carries breakpoints for the .ch-* family; this section
   does the same for the header/page/card/table primitives above, which every
   consumer (vpn-spa-v2, transit-manager console, docs dashboard) inherits.
   Same 760px/460px breakpoints as app-shell.css — do not invent new ones. ── */
@media (max-width: 760px) {
  /* The header previously kept nav on one non-wrapping line and simply clipped
     whatever didn't fit (the console's "drift" link was invisible on phones).
     Wrap instead: brand row first, nav drops to its own row when needed. */
  .site-header { flex-wrap: wrap; row-gap: 8px; padding: 10px 14px; }
  .site-header .brand { min-width: 0; font-size: 15px; }
  .site-header nav { flex-wrap: wrap; row-gap: 6px; }
  .site-header nav > a, .site-header nav a.nav-help-btn, .site-header nav a.nav-login-btn { margin-left: 12px; }

  .page { margin: 16px auto; padding: 0 14px; }
  .card { padding: 16px; }
  .card + .card { margin-top: 12px; }

  th, td { padding: 8px 10px; }

  .table-tools { flex-wrap: wrap; }
  .table-tools input[type="search"] { flex: 1 1 160px; }

  .kpi .v { font-size: 22px; }
}
@media (max-width: 460px) {
  /* Phones: two stat tiles per row beats auto-fit's occasional 1-per-row
     stack (minmax(150px,1fr) yields a single huge column below ~330px). */
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
