/* =====================================================================
   VOIP.SO — base, layout primitives and component vocabulary.
   Loaded after tokens.css. Written by hand so the page renders correctly
   before the Tailwind CDN script evaluates; Tailwind utilities layer on
   top for one-off spacing rather than carrying the design.
   ===================================================================== */

/* ---- Reset ---------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Sticky headers must not cover an anchored heading or a focused field. */
  scroll-padding-top: 6rem;
}

body {
  background: var(--bg);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Nothing may push the page sideways; wide content scrolls internally. */
  overflow-x: hidden;
}

img, svg, video, canvas { display: block; max-width: 100%; height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }

/* Buttons default to the UA's `buttonface` grey. Any button styled to look
   like something else — a nav item, a sortable table header, a rail link —
   inherits that grey unless it is reset, which reads as a light box behind
   light text. Components that want a background set one explicitly. */
button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: inherit;
}

p, li, figcaption { overflow-wrap: break-word; }

h1, h2, h3, h4, h5, h6 {
  color: var(--text);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
}

a { color: var(--accent-text); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }

ul, ol { padding: 0; list-style: none; }

hr { border: 0; border-top: 1px solid var(--border); }

table { border-collapse: collapse; width: 100%; }

/* ---- Focus ----------------------------------------------------------
   One treatment everywhere. Never removed — :focus-visible means it only
   appears for keyboard users, so there is no reason to suppress it. */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.on-dark :focus-visible,
.site-header :focus-visible,
.hero :focus-visible,
.band--dark :focus-visible,
.band--panel :focus-visible,
.site-footer :focus-visible { outline-color: var(--brand-400); }

/* Skip link: present for keyboard users, out of the way for everyone else. */
.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -100%;
  z-index: var(--z-tooltip);
  padding: var(--sp-3) var(--sp-4);
  background: var(--brand-600);
  color: #fff;
  border-radius: var(--r-md);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--dur-fast) var(--ease-out-quart);
}
.skip-link:focus { top: var(--sp-4); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Layout ---------------------------------------------------------- */

.wrap { width: 100%; max-width: var(--w-page); margin-inline: auto; padding-inline: var(--sp-4); }

@media (min-width: 768px) {
  .wrap { padding-inline: var(--sp-5); }
}

.section    { padding-block: var(--section-y); }
.section--tight { padding-block: var(--section-y-tight); }

.prose { max-width: var(--measure); text-wrap: pretty; }
.prose p + p { margin-top: var(--sp-4); }
.prose h2 { margin-top: var(--sp-7); margin-bottom: var(--sp-3); font-size: var(--fs-h2); }
.prose h3 { margin-top: var(--sp-6); margin-bottom: var(--sp-2); font-size: var(--fs-h3); }
.prose ul { margin-top: var(--sp-4); display: grid; gap: var(--sp-2); }
.prose ul li { padding-left: 1.25rem; position: relative; }
.prose ul li::before {
  content: '';
  position: absolute; left: 0; top: 0.62em;
  width: 5px; height: 5px; border-radius: var(--r-full);
  background: var(--accent-text);
}
.prose ol { margin-top: var(--sp-4); display: grid; gap: var(--sp-2); counter-reset: prose-list; }
.prose ol li { padding-left: 1.75rem; position: relative; counter-increment: prose-list; }
.prose ol li::before {
  content: counter(prose-list) '.';
  position: absolute; left: 0; top: 0;
  font-family: var(--font-mono); font-size: 0.85em; color: var(--text-muted);
}
.prose a { color: var(--accent-text); }
.prose code {
  font-family: var(--font-mono); font-size: 0.86em;
  background: var(--bg-sunken); border: 1px solid var(--border);
  padding: 0.1em 0.35em; border-radius: var(--r-sm);
}

.stack   { display: grid; gap: var(--sp-4); }
.stack-2 { display: grid; gap: var(--sp-2); }
.stack-6 { display: grid; gap: var(--sp-6); }
.row     { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }

/* Breakpoint-free responsive grid. */
.grid-auto {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}

/* ---- Typography helpers --------------------------------------------- */

.display {
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: var(--ls-display);
  font-stretch: 112%;              /* Archivo's width axis — signage, not brochure */
  color: var(--text);
}
.h1 { font-size: var(--fs-h1); }
.h3 { font-size: var(--fs-h3); }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--text-body);
  max-width: 58ch;
  text-wrap: pretty;
}
.on-dark .lead { line-height: var(--lh-dark); }

.small  { font-size: var(--fs-sm); }
.tiny   { font-size: var(--fs-xs); }
.muted  { color: var(--text-muted); }
.strong { color: var(--text); font-weight: 600; }

/* Mono is used for real data — dial codes, rates, SIP URIs, durations —
   never as decoration. Tabular figures keep columns aligned. */
.mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.num { font-variant-numeric: tabular-nums; }

.caps {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ---- Buttons --------------------------------------------------------- */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-border: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 2.5rem;
  padding: 0.5rem 1.05rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-border);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out-quart),
              border-color var(--dur-fast) var(--ease-out-quart),
              color var(--dur-fast) var(--ease-out-quart),
              transform var(--dur-fast) var(--ease-out-quart);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn[disabled], .btn[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.btn--primary { --btn-bg: var(--brand-600); --btn-fg: #fff; --btn-border: var(--brand-600); }
.btn--primary:hover { --btn-bg: var(--brand-700); --btn-border: var(--brand-700); }

.btn--secondary { --btn-fg: var(--text); --btn-border: var(--border-strong); }
.btn--secondary:hover { --btn-bg: var(--bg-sunken); --btn-border: var(--text-muted); }
.on-dark .btn--secondary { --btn-fg: var(--paper); --btn-border: var(--ink-700); }
.on-dark .btn--secondary:hover { --btn-bg: var(--ink-800); --btn-border: var(--ink-600); }

.btn--ghost { --btn-fg: var(--text-body); }
.btn--ghost:hover { --btn-bg: var(--bg-sunken); --btn-fg: var(--text); }
.on-dark .btn--ghost:hover { --btn-bg: color-mix(in oklch, var(--ink-800) 70%, transparent); }

.btn--danger { --btn-bg: var(--danger-fill); --btn-fg: #fff; --btn-border: var(--danger-fill); }
.btn--danger:hover { filter: brightness(0.92); }

.btn--lg { min-height: 3rem; padding: 0.75rem 1.5rem; font-size: var(--fs-body); }
.btn--sm { min-height: 2rem; padding: 0.3rem 0.7rem; font-size: var(--fs-xs); }
.btn--block { width: 100%; }

/* Touch targets get the 44px treatment; WCAG 2.2 requires 24px minimum
   and comfortable pointers deserve better. */
@media (pointer: coarse) {
  .btn { min-height: 2.75rem; }
  .btn--sm { min-height: 2.25rem; }
}

.btn .spinner { display: none; }
.btn.is-loading { pointer-events: none; }
.btn.is-loading .btn__label { opacity: 0.6; }
.btn.is-loading .spinner { display: inline-block; }

.spinner {
  width: 0.9em; height: 0.9em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--r-full);
  animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Forms ----------------------------------------------------------- */

.field { display: grid; gap: var(--sp-2); }

.label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
}
.label .req { color: var(--danger-text); font-weight: 400; }
.label__hint { display: block; font-weight: 400; color: var(--text-muted); font-size: var(--fs-xs); margin-top: 2px; }

.input, .select, .textarea {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.6rem 0.8rem;
  background: var(--bg-raised);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  transition: border-color var(--dur-fast) var(--ease-out-quart),
              box-shadow var(--dur-fast) var(--ease-out-quart);
}
.textarea { min-height: 7rem; resize: vertical; line-height: 1.5; }

.input:hover, .select:hover, .textarea:hover { border-color: var(--text-muted); }

.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--brand-600);
  box-shadow: var(--shadow-focus);
}

/* Placeholder must clear 4.5:1 like any other text. ink-500 does; the
   browser default grey does not. */
.input::placeholder, .textarea::placeholder { color: var(--text-muted); opacity: 1; }

.input[aria-invalid='true'], .select[aria-invalid='true'], .textarea[aria-invalid='true'] {
  border-color: var(--danger-text);
}
.input[aria-invalid='true']:focus { box-shadow: 0 0 0 3px rgb(220 38 38 / 0.18); }

.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--bg-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}

.input--mono { font-family: var(--font-mono); font-size: 0.9em; letter-spacing: 0; }

.select {
  appearance: none;
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
}

.field__error {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  font-size: var(--fs-xs);
  color: var(--danger-text);
  font-weight: 500;
}

.checkbox, .radio {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  cursor: pointer;
  font-size: var(--fs-sm);
  /* 24px minimum target height, per WCAG 2.2 target size. */
  min-height: 1.5rem;
}
.checkbox input, .radio input {
  flex: 0 0 auto;
  width: 1.125rem; height: 1.125rem;
  margin-top: 0.18rem;
  accent-color: var(--brand-600);
  cursor: pointer;
}
.checkbox span, .radio span { color: var(--text-body); }

fieldset { border: 0; padding: 0; }
legend { font-weight: 600; color: var(--text); font-size: var(--fs-sm); padding: 0; }

/* ---- Panels ---------------------------------------------------------
   Deliberately restrained: on the public site, full-bleed bands and
   tables carry the design instead of an endless card grid. */

.panel {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-5);
}
.panel--flush { padding: 0; overflow: hidden; }
.panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
}
.panel__title { font-size: var(--ui-h3); font-weight: 650; color: var(--text); }
.panel__body { padding: var(--sp-5); }
.panel__foot {
  padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--bg-sunken);
}

/* ---- Status pills: colour + dot + word, never colour alone ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--r-full);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  border: 1px solid transparent;
}
.pill::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: var(--r-full);
  background: currentColor;
  flex: 0 0 auto;
}
.pill--success { color: var(--success-text); background: var(--success-wash); border-color: color-mix(in oklch, var(--success-fill) 25%, transparent); }
.pill--warning { color: var(--warning-text); background: var(--warning-wash); border-color: color-mix(in oklch, var(--warning-fill) 25%, transparent); }
.pill--danger  { color: var(--danger-text);  background: var(--danger-wash);  border-color: color-mix(in oklch, var(--danger-fill) 25%, transparent); }
.pill--info    { color: var(--info-text);    background: var(--info-wash);    border-color: color-mix(in oklch, var(--info-fill) 25%, transparent); }
.pill--muted   { color: var(--text-muted);   background: var(--bg-sunken);    border-color: var(--border); }

.on-dark .pill--success,
.on-dark .pill--warning,
.on-dark .pill--danger,
.on-dark .pill--info,
.on-dark .pill--muted { background: color-mix(in oklch, var(--ink-800) 80%, transparent); border-color: var(--ink-700); }

/* A live indicator that actually pulses — used only where the value is
   genuinely real-time. */
.pill--live { color: var(--signal); background: color-mix(in oklch, var(--signal) 12%, transparent); border-color: color-mix(in oklch, var(--signal) 35%, transparent); }
.pill--live::before { animation: pulse 2s var(--ease-in-out) infinite; }
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.8); }
}

/* ---- Tables: the primary product affordance ------------------------- */

.table-scroll {
  /* Wide tables scroll inside their own box; the page body never does. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.table { width: 100%; font-size: var(--ui-body); }

.table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-sunken);
  padding: 0.6rem var(--sp-4);
  text-align: left;
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
}

.table td {
  padding: 0.7rem var(--sp-4);
  border-bottom: 1px solid var(--border);
  color: var(--text-body);
  vertical-align: middle;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: var(--bg-sunken); }

.table .num, .table .mono { text-align: right; font-variant-numeric: tabular-nums; }
.table th.num { text-align: right; }

.table__sort {
  display: inline-flex; align-items: center; gap: 0.3rem;
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
}
.table__sort:hover { color: var(--text); }

/* Below 768px a wide data table becomes stacked rows: side scrolling on a
   phone loses the row context that makes the data readable. */
@media (max-width: 767px) {
  .table--stack thead { display: none; }
  .table--stack tbody tr {
    display: grid;
    gap: 0.35rem;
    padding: var(--sp-4);
    border-bottom: 1px solid var(--border);
  }
  .table--stack tbody tr:hover td { background: transparent; }
  .table--stack td {
    display: grid;
    grid-template-columns: minmax(7rem, 40%) 1fr;
    gap: var(--sp-3);
    padding: 0;
    border: 0;
    text-align: left !important;
  }
  .table--stack td::before {
    content: attr(data-label);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: var(--ls-caps);
    text-transform: uppercase;
    color: var(--text-muted);
  }
}

/* ---- Empty states teach; they do not just say "nothing here" -------- */

.empty {
  display: grid;
  justify-items: center;
  gap: var(--sp-3);
  padding: var(--sp-8) var(--sp-5);
  text-align: center;
}
.empty__icon {
  display: grid; place-items: center;
  width: 3rem; height: 3rem;
  border-radius: var(--r-lg);
  background: var(--bg-sunken);
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.empty__title { font-size: var(--ui-h3); font-weight: 650; color: var(--text); }
.empty__body { max-width: 46ch; color: var(--text-muted); font-size: var(--fs-sm); }

/* ---- Toasts ---------------------------------------------------------- */

.toasts {
  position: fixed;
  inset-block-end: var(--sp-4);
  inset-inline-end: var(--sp-4);
  z-index: var(--z-toast);
  display: grid;
  gap: var(--sp-2);
  width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--ink-900);
  color: var(--paper);
  border: 1px solid var(--ink-700);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm);
  animation: toast-in var(--dur-base) var(--ease-out-quart);
}
.toast--success { border-color: color-mix(in oklch, var(--success-fill) 55%, transparent); }
.toast--danger  { border-color: color-mix(in oklch, var(--danger-fill) 55%, transparent); }
.toast--warning { border-color: color-mix(in oklch, var(--warning-fill) 55%, transparent); }
.toast__close {
  margin-left: auto; background: none; border: 0; color: var(--ink-300);
  cursor: pointer; padding: 0.15rem; border-radius: var(--r-sm);
  min-width: 24px; min-height: 24px; display: grid; place-items: center;
}
.toast__close:hover { color: var(--paper); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}

/* ---- Dialog ---------------------------------------------------------
   Native <dialog>, so it escapes any overflow:hidden ancestor and gets
   focus trapping and Esc handling from the platform. */

dialog.modal {
  width: min(34rem, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-raised);
  color: var(--text-body);
  box-shadow: var(--shadow-lg);
}
dialog.modal::backdrop { background: rgb(2 6 23 / 0.55); backdrop-filter: blur(2px); }
.modal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border); }
.modal__title { font-size: var(--ui-h2); font-weight: 650; color: var(--text); }
.modal__body { padding: var(--sp-5); }
.modal__foot { display: flex; justify-content: flex-end; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--border); background: var(--bg-sunken); }

/* ---- Credential block ----------------------------------------------- */

.creds {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}
.creds__row {
  display: grid;
  grid-template-columns: minmax(8rem, 12rem) 1fr auto;
  align-items: center;
  gap: var(--sp-3);
  padding: 0.65rem var(--sp-4);
  background: var(--bg-raised);
}
.creds__key { font-size: var(--fs-xs); font-weight: 600; letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--text-muted); }
.creds__val {
  font-family: var(--font-mono); font-size: 0.9em; color: var(--text);
  /* anywhere, not break-all: a hostname breaks at a sensible point rather
     than splitting a label in half, which reads as corruption. */
  overflow-wrap: anywhere;
  word-break: normal;
  min-width: 0;
}
@media (max-width: 560px) {
  .creds__row { grid-template-columns: 1fr auto; }
  .creds__key { grid-column: 1 / -1; }
}

.copy-btn {
  display: inline-grid; place-items: center;
  width: 1.9rem; height: 1.9rem;
  min-width: 24px; min-height: 24px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--bg-raised);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart);
}
.copy-btn:hover { color: var(--text); border-color: var(--text-muted); }
.copy-btn.is-copied { color: var(--success-text); border-color: var(--success-text); }

/* ---- Pagination ------------------------------------------------------ */

.pager { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.pager__link {
  display: grid; place-items: center;
  min-width: 2.25rem; height: 2.25rem;
  padding-inline: 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text-body);
  font-size: var(--fs-sm);
  text-decoration: none;
}
.pager__link:hover { background: var(--bg-sunken); color: var(--text); }
.pager__link[aria-current='page'] { background: var(--brand-600); border-color: var(--brand-600); color: #fff; font-weight: 600; }
.pager__gap { color: var(--text-muted); padding-inline: 0.25rem; }

/* ---- Motion preference ----------------------------------------------
   Not optional. Every animation above has an alternative here. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: var(--dur-instant) !important;
    scroll-behavior: auto !important;
  }

  .skeleton { animation: none; background: var(--bg-sunken); }
  .pill--live::before { animation: none; }
  .spinner { animation: none; border-right-color: currentColor; opacity: 0.5; }
}

/* ---- Print ------------------------------------------------------------ */

@media print {
  .site-header, .site-footer, .portal-rail, .btn, .toasts, .skip-link { display: none !important; }
  body { background: #fff; color: #000; }
  .panel { border: 1px solid #ccc; box-shadow: none; }
  a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 0.8em; }
}

/* ---- Notice strip -----------------------------------------------------
   One inline-message component for both registers. It replaced a separate
   `.alert` block that did the same job for two call sites — same shape,
   same tones, twice the CSS. */

.notice-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid;
  font-size: var(--ui-sm);
}
.notice-strip--warning { background: var(--warning-wash); border-color: color-mix(in oklch, var(--warning-fill) 32%, transparent); color: var(--warning-text); }
.notice-strip--danger  { background: var(--danger-wash);  border-color: color-mix(in oklch, var(--danger-fill) 32%, transparent);  color: var(--danger-text); }
.notice-strip--info    { background: var(--info-wash);    border-color: color-mix(in oklch, var(--info-fill) 32%, transparent);    color: var(--info-text); }
.notice-strip .btn { margin-left: auto; }

/* ---- Spec list --------------------------------------------------------
   Key/value rows with a monospace, right-aligned value — the datasheet
   shape. Shared: the public service pages use it for specifications and
   the portal uses it for IVR options and SIP endpoints. It lived in
   site.css, which the portal never loads, so those rows rendered as
   unstyled blocks. */

.spec {
  display: grid;
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  font-size: var(--fs-sm);
}
.spec__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-4);
  padding: 0.55rem var(--sp-4);
  background: var(--bg-raised);
  align-items: baseline;
}
.spec__key { color: var(--text-muted); font-size: var(--fs-xs); }
.spec__val { font-family: var(--font-mono); font-size: 0.86em; color: var(--text); text-align: right; font-variant-numeric: tabular-nums; }
