/* ==========================================================================
   AXING FTTR Configurator — Stylesheet
   ========================================================================== */

/* --- Variables ----------------------------------------------------------- */
:root {
  --ax: #009993;
  --ax-light: #e8f4f4;
  --ax-dark: #007a75;

  --bg: #ffffff;
  --bg-subtle: #f5f7f9;
  --bg-muted: #eaecf0;
  --bg-input: #f0f2f5;
  --border: #d0d5dc;
  --border-light: #e2e6eb;

  --text: #1c2028;
  --text-muted: #5c6370;
  --text-light: #8b919d;

  --success: #16a34a;
  --success-bg: #f0fdf4;
  --warning: #d97706;
  --warning-bg: #fffbeb;
  --warning-text: #92400e;
  --danger: #dc2626;
  --danger-bg: #fef2f2;

  --fs: 16px;
  --fs-sm: 15px;
  --fs-xs: 14px;
  --fs-lg: 1.125rem;
  --fs-xl: 1.25rem;

  --radius: 10px;
  --radius-sm: 6px;

  /* Spacing scale — used for padding, margin, gap. Pick the closest step.
     --space-3-5 is a half-step (10px) between --space-3 and --space-4, used
     by notice/warn blocks where the 8px/12px options both look off. */
  --space-1: 0.25rem;
  --space-2: 0.375rem;
  --space-3: 0.5rem;
  --space-3-5: 0.625rem;
  --space-4: 0.75rem;
  --space-5: 1rem;
  --space-6: 1.25rem;
  --space-7: 1.5rem;
  --space-8: 2rem;
  --space-9: 3rem;
  --space-10: 4rem;

  /* Effects */
  --ring-focus:  0 0 0 3px rgba(0, 153, 147, 0.2);
  --ring-danger: 0 0 0 3px rgba(220, 38, 38, 0.1);
  --overlay-dark: rgba(0, 0, 0, 0.4);
  --transition-fast: all 0.15s ease;

  /* Attention-pulse colors for empty primary inputs (#endpoints / #distance /
   * #bandwidth). Two stops — idle and peak — themed per mode. Light mode keeps
   * the brand teal at modest alpha; dark mode shifts to a lighter, more
   * luminous teal at higher alpha so the pulse stays visible against
   * --bg-input #181c28. */
  --pulse-low:  rgba(0, 153, 147, 0.28);
  --pulse-high: rgba(0, 153, 147, 0.6);

  /* Optical-budget segment palette (used both in segmented bar and legend dots) */
  --color-fiber: #60a5fa;
  --color-splitter: #f97316;
  --color-conn: #a78bfa;

  /* Step 3 topology signal palette. Three of four reuse segment palette
     so the color language stays coherent across budget / BOM / topology. */
  --sig-internet: #3b82f6;
  --sig-combined: var(--color-conn);   /* purple — GPON + RF overlay on one fiber (post-WDM) */
  --sig-pon: var(--ax);
  --sig-rf: var(--color-splitter);

  /* Step-nav arrows */
  --icon-arrow-left:  url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='19' y1='12' x2='5' y2='12'/><polyline points='12 19 5 12 12 5'/></svg>");
  --icon-arrow-right: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='5' y1='12' x2='19' y2='12'/><polyline points='12 5 19 12 12 19'/></svg>");

  /* Shell chrome — header toggle (mobile drawer) + sidebar misc actions */
  --icon-hamburger:    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><line x1='3' y1='6' x2='21' y2='6'/><line x1='3' y1='12' x2='21' y2='12'/><line x1='3' y1='18' x2='21' y2='18'/></svg>");
  --icon-close:        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><line x1='6' y1='6' x2='18' y2='18'/><line x1='6' y1='18' x2='18' y2='6'/></svg>");
  --icon-help:         url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><path d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'/><line x1='12' y1='17' x2='12.01' y2='17'/></svg>");
  --icon-theme-system: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='2' y='3' width='20' height='14' rx='2'/><line x1='8' y1='21' x2='16' y2='21'/><line x1='12' y1='17' x2='12' y2='21'/></svg>");
  --icon-theme-dark:   url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/></svg>");
  --icon-theme-light:  url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='5'/><line x1='12' y1='1' x2='12' y2='3'/><line x1='12' y1='21' x2='12' y2='23'/><line x1='4.22' y1='4.22' x2='5.64' y2='5.64'/><line x1='18.36' y1='18.36' x2='19.78' y2='19.78'/><line x1='1' y1='12' x2='3' y2='12'/><line x1='21' y1='12' x2='23' y2='12'/><line x1='4.22' y1='19.78' x2='5.64' y2='18.36'/><line x1='18.36' y1='5.64' x2='19.78' y2='4.22'/></svg>");

  /* Service-card icons (Step 1 "Additional Services") */
  --icon-wifi:          url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M5 13a10 10 0 0 1 14 0'/><path d='M8.5 16.5a5 5 0 0 1 7 0'/><path d='M2 8.82a15 15 0 0 1 20 0'/><line x1='12' y1='20' x2='12.01' y2='20'/></svg>");
  --icon-waves:         url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M 3 5 Q 6 1 9 5 T 15 5 T 21 5'/><path d='M 3 12 Q 6 8 9 12 T 15 12 T 21 12'/><path d='M 3 19 Q 6 15 9 19 T 15 19 T 21 19'/></svg>");
  --icon-zap:           url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polygon points='13 2 3 14 12 14 11 22 21 10 12 10 13 2'/></svg>");
  --icon-tv:            url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='2' y='7' width='20' height='15' rx='2' ry='2'/><polyline points='17 2 12 7 7 2'/></svg>");

  /* Topology icons (Step 3) — sources, core equipment, client devices */
  --icon-internet:      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><line x1='2' y1='12' x2='22' y2='12'/><path d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/></svg>");
  --icon-sat:           url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 10a7.3 7.3 0 0 0 10 10Z'/><path d='M9 15l3-3'/><path d='M17 13a6 6 0 0 0-6-6'/><path d='M21 13A10 10 0 0 0 11 3'/></svg>");
  --icon-server:        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='2' y='3' width='20' height='7' rx='1.5'/><rect x='2' y='14' width='20' height='7' rx='1.5'/><line x1='6' y1='6.5' x2='6.01' y2='6.5'/><line x1='6' y1='17.5' x2='6.01' y2='17.5'/></svg>");
  --icon-switch:        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='2' y='8' width='20' height='8' rx='1.5'/><line x1='6' y1='12' x2='6.01' y2='12'/><line x1='10' y1='12' x2='10.01' y2='12'/><line x1='14' y1='12' x2='14.01' y2='12'/><line x1='18' y1='12' x2='18.01' y2='12'/></svg>");
  --icon-amp:           url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polygon points='5 4 20 12 5 20 5 4'/><line x1='20' y1='12' x2='22' y2='12'/><line x1='5' y1='12' x2='2' y2='12'/></svg>");
  --icon-combiner:      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M3 5 L13 12'/><path d='M3 12 L13 12'/><path d='M3 19 L13 12'/><path d='M13 12 L21 12'/></svg>");
  --icon-splitter:      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M3 12 L11 12'/><path d='M11 12 L21 5'/><path d='M11 12 L21 12'/><path d='M11 12 L21 19'/></svg>");
  --icon-onu:           url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='2' y='8' width='20' height='8' rx='1.5'/><line x1='6' y1='12' x2='6.01' y2='12'/><line x1='13' y1='12' x2='15' y2='12'/><line x1='17' y1='12' x2='19' y2='12'/></svg>");
  --icon-phone:         url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='7' y='2' width='10' height='20' rx='2'/><line x1='12' y1='18' x2='12.01' y2='18'/></svg>");
  --icon-laptop:        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='12' rx='1.5'/><line x1='2' y1='20' x2='22' y2='20'/></svg>");
  --icon-ap:            url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M6 8 A 8 8 0 0 1 18 8'/><path d='M3 5 A 12 12 0 0 1 21 5'/><rect x='4' y='14' width='16' height='5' rx='2.5'/><line x1='12' y1='14' x2='12' y2='19'/></svg>");

  font-size: 16px;
}


/* --- Reset & Base -------------------------------------------------------- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: var(--fs);
  line-height: 1.5;
  color: var(--text);
  background: var(--bg-subtle);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

::selection {
  color: #fff!important;
  fill: #fff!important;
  background: var(--ax);
}

img, svg {
  display: block;
  max-width: 100%;
}

h1, h2, h3, h4 {
  line-height: 1.25;
}


/* --- Header (sticky full-width bar) --------------------------------------
   Persistent across all viewports: brand on the left, title + subtitle
   in the middle, hamburger toggle on the right (mobile only; hidden at
   >=768px where the sidebar is always visible). Sticky at top:0 with a
   high z-index so the mobile drawer and any content scrolls underneath.
   ----------------------------------------------------------------------- */
.header {
  position: sticky;
  top: 0;
  z-index: 30;
  height: 56px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: 0 var(--space-5);
}

.header-brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
  color: inherit;
}

.header-logo {
  width: auto;
}

.header-logo-full {
  display: none;
}

.header-logo-small {
  display: block;
  height: 20px;
}

.header-title-group {
  display: flex;
  align-items: center;
  gap: var(--space-3-5);
  min-width: 0;
  line-height: 1;
}

.header-title {
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--text);
  /* Override the global h1 line-height: 1.25 so the title sits flush
     with the header-subtitle / header-dot baseline inside the 56 px
     header (header-title-group is line-height: 1). */
  line-height: 1;
}

/* Dot separator + subtitle hidden on mobile (not enough room next to the
   hamburger); revealed at >=768px via the desktop media block. */
.header-dot,
.header-subtitle {
  display: none;
}

.header-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--text-light);
  flex-shrink: 0;
}

.header-subtitle {
  font-size: var(--fs-xl);
  color: var(--text-muted);
}

/* Hamburger toggle — mobile only. A single .header-toggle-icon span whose
   mask-image swaps between --icon-hamburger and --icon-close via the
   button's aria-expanded state, which JS keeps in sync with
   sidebar[data-open]. */
.header-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  margin-left: auto;
  border: none;
  background: none;
  color: var(--text);
  cursor: pointer;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  transition: var(--transition-fast);
}

.header-toggle:hover {
  background: var(--bg-subtle);
}

.header-toggle-icon {
  width: 24px;
  height: 24px;
  background-color: currentColor;
  mask-image: var(--icon-hamburger);
  -webkit-mask-image: var(--icon-hamburger);
  mask-position: center;
  -webkit-mask-position: center;
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
}

.header-toggle[aria-expanded="true"] .header-toggle-icon {
  mask-image: var(--icon-close);
  -webkit-mask-image: var(--icon-close);
}


/* --- Sidebar (mobile drawer / desktop rail) ------------------------------
   Holds nav + misc actions. Hidden on mobile until data-open="true"
   opens a full-viewport drawer below the sticky header. Desktop: sticky
   12rem rail in the first grid column — see the @media block at the
   bottom for the desktop layout.
   ----------------------------------------------------------------------- */
.sidebar {
  display: none;
  background: var(--bg);
  overflow-y: auto;
}

/* Mobile drawer open: pinned below the 56px header, fills the rest of
   the viewport. z-index sits below the header (30) so the × stays
   clickable, above normal content. */
.sidebar[data-open="true"] {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 56px 0 0 0;
  z-index: 25;
}

.sidebar-nav {
  flex: 1;
  padding: var(--space-6);
  min-width: 0;
}

.sidebar-misc {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-4);
  border-top: 1px solid var(--border-light);
  height: 7rem;
}

.sidebar-action {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: var(--fs);
  text-align: left;
  transition: var(--transition-fast);
}

.sidebar-action:hover {
  background: var(--bg-subtle);
  color: var(--text);
}

.sidebar-action-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  background-color: currentColor;
  mask-position: center;
  -webkit-mask-position: center;
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
}

.sidebar-action-icon-help {
  mask-image: var(--icon-help);
  -webkit-mask-image: var(--icon-help);
}

.sidebar-action-icon[data-theme-icon="system"] {
  mask-image: var(--icon-theme-system);
  -webkit-mask-image: var(--icon-theme-system);
}

.sidebar-action-icon[data-theme-icon="dark"] {
  mask-image: var(--icon-theme-dark);
  -webkit-mask-image: var(--icon-theme-dark);
}

.sidebar-action-icon[data-theme-icon="light"] {
  mask-image: var(--icon-theme-light);
  -webkit-mask-image: var(--icon-theme-light);
}

.sidebar-action-label {
  display: inline;
}

/* Body scroll lock while the mobile drawer is open. Reset to visible on
   desktop (see @media block) so a stale data-open flag after resize
   can't freeze the page. */
body.sidebar-open {
  overflow: hidden;
}


/* --- Step navigation (vertical stepper) ---------------------------------
   Only rendered inside the sidebar; always vertical. Dots + left-hand
   connector line; labels always visible. */
.nav-list {
  list-style: none;
  display: flex;
  flex-direction: column;
}

.nav-item {
  position: relative;
  display: flex;
  justify-content: flex-start;
  width: 100%;
}

/* Vertical connector line — each item paints the top half (::before) and
   bottom half (::after) on a left-hand rail at x = nav-btn padding-left
   + dot radius. The dot's opaque --bg fill masks the tiny bit of line
   passing behind the circle. First item hides ::before; last hides
   ::after. */
.nav-item::before,
.nav-item::after {
  content: "";
  position: absolute;
  left: calc(var(--space-4) + 16px);
  width: 1px;
  height: 50%;
  background: var(--border);
  z-index: 0;
}

.nav-item::before { top: 0; }
.nav-item::after  { top: 50%; }

.nav-item:first-child::before,
.nav-item:last-child::after {
  display: none;
}

.nav-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  width: 100%;
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--fs);
  color: var(--text-muted);
  cursor: pointer;
  text-align: left;
  justify-content: flex-start;
  white-space: nowrap;
  transition: var(--transition-fast);
}

.nav-btn:hover {
  color: var(--text);
}

.nav-item.active .nav-btn {
  color: var(--ax-dark);
  font-weight: 500;
}

.nav-dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: var(--bg);
  font-size: var(--fs);
  font-weight: 500;
  flex-shrink: 0;
  position: relative;
  z-index: 1;
  transition: var(--transition-fast);
}

.nav-item.active .nav-dot {
  background: var(--ax);
  border-color: var(--ax);
  color: #fff;
}

/* About nav-dot: a small solid bullet inside the 32 px circle instead
   of a numeral. Signals "not part of the numbered flow" without the
   lowercase-i vs. "1" ambiguity. Inherits currentColor so the bullet
   picks up the active-state white-on-teal automatically. */
.nav-item[data-step="about"] .nav-dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}

.nav-label {
  display: inline;
  white-space: nowrap;
}


/* --- Desktop layout (>=768px) -------------------------------------------
   Body switches from flex-column to a 2-row, 2-column grid:
     Row 1 (auto)  -> header spans both columns (full-width).
     Row 2 (1fr)   -> sidebar (12rem) + content (1fr).
   Sidebar becomes a sticky rail pinned under the header; hamburger is
   hidden; header reveals the dot + subtitle and swaps to the full logo.
   ----------------------------------------------------------------------- */
@media (min-width: 768px) {
  body {
    display: grid;
    grid-template-columns: 12rem 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "header  header"
      "sidebar content";
  }

  .header {
    grid-area: header;
    /* Drop the left padding so .header-brand can span the full sidebar
       width (12rem) and line its right border up with the sidebar's.
       Right padding stays at var(--space-5). The flex gap also drops to
       0 so .header-title-group can control its own inset and line up
       with .main's left padding. */
    padding-left: 0;
    gap: 0;
  }

  .sidebar {
    display: flex;
    flex-direction: column;
    grid-area: sidebar;
    position: sticky;
    top: 56px; /* header height */
    align-self: start;
    height: calc(100vh - 56px);
    border-right: 1px solid var(--border);
  }

  .sidebar-nav {
    padding: var(--space-5) 0;
  }

  .content { grid-area: content; }

  /* Brand occupies the same 12rem column as the sidebar below, with a
     matching right border so the two form a continuous vertical rule. */
  .header-brand {
    width: 12rem;
    align-self: stretch;
    padding: 0 var(--space-5);
    border-right: 1px solid var(--border);
  }

  /* Mirror .main's max-width + auto margins + clamp padding so the
     title-group sits inside the same 1400px-capped, centered column as
     the main content below. flex: 1 lets auto margins distribute any
     free space on wider viewports. */
  .header-title-group {
    flex: 1;
    min-width: 0;
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 clamp(var(--space-7), 3vw, 2.5rem);
  }

  .header-logo-full { display: block; height: 28px; }
  .header-logo-small { display: none; }

  .header-dot,
  .header-subtitle { display: block; }

  .header-toggle { display: none; }

  /* Body scroll-lock is a mobile-only concern; the drawer never opens on
     desktop (hamburger hidden), but a stale data-open from a
     resize-down-then-up sequence would otherwise leave the page frozen. */
  body.sidebar-open { overflow: visible; }
}


/* --- Content area (holds main + footer) ---------------------------------- */
.content {
  display: flex;
  flex-direction: column;
  flex: 1;
  /* Inline-size container so any future full-bleed child can use 100cqi
     to break past .main's max-width + horizontal padding without doing
     viewport / sidebar math. (No active caller right now.) */
  container-type: inline-size;
}

/* --- Main Content -------------------------------------------------------- */
.main {
  flex: 1;
  max-width: 1400px;
  width: 100%;
  margin: 0 auto;
  padding: var(--space-6) var(--space-5);
}

.step-panel {
  display: none;
}

.step-panel.active {
  display: block;
}

.step-title {
  font-size: var(--fs-xl);
  font-weight: 600;
  margin-bottom: var(--space-7);
  color: var(--text);
}


/* --- About page (landing / orientation) ---------------------------------
   Mixed layout: prose sections (How it works, Useful links) divided by
   bottom borders, plus collapsible cards for Methodology and Scope &
   assumptions (.card.card-collapsible.about-section). Reads top-down as
   a single scrollable overview. */
.about-lead {
  font-size: var(--fs-lg);
  color: var(--text);
  margin-bottom: var(--space-8);
  max-width: 56rem;
}

.about-lead strong {
  font-weight: 600;
}

.about-section {
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-7);
  border-bottom: 1px solid var(--border-light);
}

.about-section:not(.card):last-of-type {
  border-bottom: none;
  padding-bottom: 0;
}

.about-heading {
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--space-5);
}

/* Match the prose .about-heading scale on the About page's collapsible
   cards (Methodology, Scope & assumptions) so all four section headings
   read at the same level. Scoped to .about-section so the Optical Power
   Budget card on Step 2 keeps its smaller default --fs heading. The
   teal ::before bar is also dropped here so the About summaries match
   the plain prose <h3 class="about-heading"> visual. */
.about-section.card-collapsible > .card-heading {
  font-size: var(--fs-xl);
  font-weight: 600;
}

.about-section.card-collapsible > .card-heading::before {
  display: none;
}

.about-subheading {
  font-size: var(--fs);
  font-weight: 600;
  color: var(--text);
  margin: var(--space-6) 0 var(--space-3);
}

.about-section p {
  color: var(--text);
  margin-bottom: var(--space-4);
  max-width: 56rem;
}

.about-section p:last-child {
  margin-bottom: 0;
}

.about-cta-inline {
  margin-top: var(--space-7);
}

.about-cta-hint {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin: var(--space-3) 0 0;
}

.about-steps,
.about-list,
.about-links {
  margin-bottom: var(--space-4);
  padding-left: 1.5rem;
  color: var(--text);
  max-width: 56rem;
}

.about-steps li,
.about-list li,
.about-links li {
  margin-bottom: var(--space-2);
}

.about-links {
  list-style: none;
  padding-left: 0;
}

.about-links a {
  color: var(--ax);
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ax) 50%, transparent);
  font-weight: 500;
  transition: text-decoration-color 0.15s;
}

.about-links a:hover {
  text-decoration-color: var(--ax);
}

.about-scope {
  max-width: 56rem;
  margin-bottom: var(--space-5);
}

.about-scope dt {
  font-weight: 600;
  color: var(--text);
  margin-top: var(--space-4);
}

.about-scope dt:first-child {
  margin-top: 0;
}

.about-scope dd {
  color: var(--text-muted);
  margin-top: var(--space-1);
}

/* Reference tables on the About page (e.g. ITU-T G.984.2 GPON optical
   classes inside Methodology → Optical power budget). Same visual
   language as the budget metrics list — tinted header row, light
   bottom borders, teal-tinted highlight row for "this is what AXING
   uses by default". */
.about-table {
  width: 100%;
  max-width: 56rem;
  border-collapse: collapse;
  margin: var(--space-4) 0 var(--space-5);
  font-size: var(--fs-sm);
}

.about-table th,
.about-table td {
  padding: var(--space-2) var(--space-3-5);
  text-align: left;
  border-bottom: 1px solid var(--border-light);
}

.about-table th {
  font-weight: 500;
  color: var(--text);
  background: var(--bg-subtle);
}

.about-table .about-table-highlight {
  background: color-mix(in srgb, var(--ax) 8%, transparent);
}

.about-table .about-table-highlight td {
  color: var(--text);
  font-weight: 500;
}

.about-notice {
  margin-top: var(--space-5);
  padding: var(--space-4) var(--space-5);
  background: var(--bg-subtle);
  border-left: 3px solid var(--ax);
  border-radius: 0;
  font-size: var(--fs-sm);
  color: var(--text);
  max-width: 56rem;
}

.about-contact-link {
  color: var(--ax);
  font-weight: 500;
  text-decoration: underline dotted currentColor;
  text-underline-offset: 3px;
}


/* --- Cards --------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: var(--space-6);
}

.card-heading {
  font-size: var(--fs);
  line-height: 1.25;
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--space-6);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.card-heading::before {
  content: '';
  width: 3px;
  height: 14px;
  background: var(--ax);
  border-radius: 2px;
  flex-shrink: 0;
}

/* Collapsible card: <details class="card card-collapsible"> with a
   <summary class="card-heading"> replacing the usual <h3>. Native marker
   is hidden; a chevron after the heading rotates on [open]. When closed
   the heading's margin-bottom is suppressed so the card doesn't grow
   empty space below a collapsed summary. */
.card-collapsible > summary.card-heading {
  list-style: none;
  cursor: pointer;
  user-select: none;
}

.card-collapsible > summary.card-heading::-webkit-details-marker {
  display: none;
}

.card-collapsible > summary.card-heading::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  margin-left: auto;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  flex-shrink: 0;
}

.card-collapsible[open] > summary.card-heading::after {
  transform: rotate(45deg);
}

.card-collapsible:not([open]) > summary.card-heading {
  margin-bottom: 0;
}

/* Grouping block inside a card — separates adjacent sections with a soft
   top border + extra spacing so multiple .card-heading subsections can
   coexist in one card without reading as a wall of text. */
.form-section {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-7);
  padding-top: var(--space-7);
  border-top: 1px solid var(--border-light);
}

.form-section-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
}

.form-section-row > .form-section {
  position: relative;
  flex: 1 1 280px;
  margin-top: 0;
  padding: var(--space-6);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  background: var(--bg);
}

.form-section-row > .form-section-full {
  flex: 1 1 100%;
}


/* --- Form: Input fields -------------------------------------------------- */
.form-group {
  margin-bottom: var(--space-6);
}

.form-group:last-child {
  margin-bottom: 0;
}

.form-label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--space-2);
}

.form-input {
  display: block;
  width: 100%;
  padding: var(--space-3) var(--space-4);
  font-family: inherit;
  font-size: var(--fs);
  line-height: 1.375;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.form-input::placeholder {
  color: var(--text-light);
}

.form-input:focus {
  border-color: var(--ax);
  box-shadow: var(--ring-focus);
}

.form-input.invalid {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

/* The three primary project-parameter inputs use a 2 px state-driven border
 * instead of a permanent teal ring. validateInput() picks the state class:
 *   .state-success — value is inside the recommended range
 *   .state-warning — value is allowed but outside the recommended range
 *                    (data-rec-max attribute defines the threshold per field)
 *   .invalid       — value is outside the allowed range (existing global)
 * Empty inputs (placeholder visible) carry no state class and run the
 * attention pulse below; the pulse stops on focus or as soon as a state
 * class is applied (because :placeholder-shown stops matching). State rules
 * use ID specificity so the colored border persists through .form-input:focus
 * (focus still adds --ring-focus glow on top). */
#endpoints,
#distance,
#bandwidth {
  border-width: 2px;
}

#endpoints.state-success,
#distance.state-success,
#bandwidth.state-success {
  border-color: var(--success);
}

#endpoints.state-warning,
#distance.state-warning,
#bandwidth.state-warning {
  border-color: var(--warning);
}

@keyframes input-attention-pulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--pulse-low); }
  50%      { box-shadow: 0 0 0 3px var(--pulse-high); }
}

#endpoints:placeholder-shown:not(:focus),
#distance:placeholder-shown:not(:focus),
#bandwidth:placeholder-shown:not(:focus) {
  animation: input-attention-pulse 2.5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  #endpoints:placeholder-shown:not(:focus),
  #distance:placeholder-shown:not(:focus),
  #bandwidth:placeholder-shown:not(:focus) {
    animation: none;
  }
}

.form-input-unit {
  position: relative;
}

.form-input-unit .form-input {
  padding-right: 3.5rem;
}

.form-unit {
  position: absolute;
  right: 0.875rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  pointer-events: none;
}

.form-hint {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-sm);
  color: var(--text-light);
}

.form-hint.warning {
  color: var(--warning);
}

.form-error {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-sm);
  color: var(--danger);
}


/* --- Form: Radio button group -------------------------------------------- */
.radio-group {
  display: flex;
  gap: 0;
}

.radio-btn {
  cursor: pointer;
  display: block;
  position: relative;
}

/* Overlap shared borders so there's only one line between buttons */
.radio-btn:not(:first-child) {
  margin-left: -1px;
}

.radio-btn input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}

.radio-btn-label {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 3rem;
  padding: var(--space-3) var(--space-5);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-muted);
  background: var(--bg-input);
  border: 1px solid var(--border);
  transition: var(--transition-fast);
}

.radio-btn:first-child .radio-btn-label {
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}

.radio-btn:last-child .radio-btn-label {
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* Hover: teal border on all 4 sides, lift above neighbors */
.radio-btn:hover {
  z-index: 1;
}

.radio-btn:hover .radio-btn-label {
  border-color: var(--ax);
  color: var(--ax);
}

/* Checked: teal fill + border, lift above neighbors (even above hover) */
.radio-btn:has(input:checked) {
  z-index: 2;
}

.radio-btn input:checked + .radio-btn-label {
  background: var(--ax);
  border-color: var(--ax);
  color: #fff;
}

.radio-btn:hover input:checked + .radio-btn-label {
  background: var(--ax-dark);
  color: #fff;
}


/* --- Form: Service cards (Step 1 "Additional Services") ----------------- */
.service-grid {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-4);
}

.service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-1);
  padding: var(--space-5) 1.125rem;
  border: 1.5px solid var(--border-light);
  border-radius: var(--radius-sm);
  background: var(--bg);
  cursor: pointer;
  user-select: none;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.service-card input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}

.service-card:hover {
  border-color: var(--ax);
  background: color-mix(in srgb, var(--ax) 3%, var(--bg));
}

.service-card:has(input:checked) {
  border-color: var(--ax);
  background: color-mix(in srgb, var(--ax) 7%, var(--bg));
}

.service-card:has(input:focus-visible) {
  outline: 2px solid var(--ax);
  outline-offset: 2px;
}

.service-check {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: 20px;
  height: 20px;
  border: 1.5px solid var(--border);
  border-radius: 4px;
  background: var(--bg-input);
  transition: border-color 0.15s ease, background 0.15s ease;
}

.service-check::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 6px;
  width: 5px;
  height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
  opacity: 0;
  transition: opacity 0.15s ease;
}

.service-card:has(input:checked) .service-check {
  background: var(--ax);
  border-color: var(--ax);
}

.service-card:has(input:checked) .service-check::after {
  opacity: 1;
}

.service-icon {
  width: 26px;
  height: 26px;
  background-color: var(--text-muted);
  mask: var(--service-icon) center / contain no-repeat;
  -webkit-mask: var(--service-icon) center / contain no-repeat;
  transition: background-color 0.15s ease;
}

.service-card:has(input:checked) .service-icon {
  background-color: var(--ax);
}

.service-card[data-svc="wifi"]  { --service-icon: var(--icon-wifi); }
.service-card[data-svc="rf"]    { --service-icon: var(--icon-waves); }
.service-card[data-svc="poe"]   { --service-icon: var(--icon-zap); }
.service-card[data-svc="iptv"]  { --service-icon: var(--icon-tv); }

.service-title {
  font-size: var(--fs);
  font-weight: 500;
  color: var(--text);
  margin-top: var(--space-2);
}

.service-desc {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  line-height: 1.4;
}


/* --- Buttons ------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-5) 2rem;
  font-family: inherit;
  font-size: var(--fs);
  font-weight: 500;
  color: #fff;
  background: var(--ax);
  border: 1.5px solid var(--ax);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.btn:hover {
  background: var(--ax-dark);
  border-color: var(--ax-dark);
}

.btn-sm {
  padding: var(--space-3) var(--space-5);
  font-size: var(--fs-sm);
}

.btn-outline {
  color: var(--ax);
  background: transparent;
  border: 1.5px solid var(--border);
}

.btn-outline:hover {
  border-color: var(--ax);
  background: rgba(0, 153, 147, 0.04);
}

/* Step-nav arrow icons */
.btn-prev::before,
.btn-next::after {
  content: "";
  width: 1.1em;
  height: 1.1em;
  background-color: currentColor;
  mask-position: center;
  -webkit-mask-position: center;
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  flex-shrink: 0;
}

.btn-prev::before {
  mask-image: var(--icon-arrow-left);
  -webkit-mask-image: var(--icon-arrow-left);
}

.btn-next::after {
  mask-image: var(--icon-arrow-right);
  -webkit-mask-image: var(--icon-arrow-right);
}


/* --- Bandwidth estimation tiles (Step 2) --------------------------------- */
/* --- Bandwidth gauge (speedtest style) ----------------------------------- */
.bw-gauge {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-3) var(--space-5) 0;
}

.bw-gauge-svg {
  width: 100%;
  max-width: 400px;
}

.bw-gauge-track {
  fill: none;
  stroke: var(--bg-muted);
  stroke-width: 18;
  stroke-linecap: round;
}

.bw-gauge-peak {
  fill: none;
  stroke: var(--text-light);
  stroke-width: 18;
  stroke-linecap: round;
  opacity: 0.35;
  stroke-dashoffset: var(--arc-len);
  transition: stroke-dashoffset 0.8s ease-out;
}

.bw-gauge-peak.animate {
  stroke-dashoffset: 0;
}

.bw-gauge-fill {
  fill: none;
  stroke: var(--est-color);
  stroke-width: 18;
  stroke-linecap: round;
  stroke-dashoffset: var(--arc-len);
  transition: stroke-dashoffset 1s ease-out 0.6s;
}

.bw-gauge-fill.animate {
  stroke-dashoffset: var(--fill-offset);
}

.bw-gauge-marker {
  stroke: var(--text-muted);
  stroke-width: 2;
}

.bw-gauge-marker-label {
  font-size: var(--fs-sm);
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  fill: var(--text-muted);
}

.bw-gauge-center-value {
  font-size: 32px;
  font-weight: 700;
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  text-anchor: middle;
  fill: var(--est-color);
}

.bw-gauge-center-label {
  font-size: var(--fs-sm);
  fill: var(--text-muted);
  text-anchor: middle;
}

.bw-gauge-labels {
  font-size: var(--fs-sm);
  fill: var(--text-light);
  font-family: "Cascadia Mono", "Fira Mono", monospace;
}

.bw-gauge-legend {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-5);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.bw-gauge-legend-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: var(--space-2);
  vertical-align: middle;
}

.bw-gauge-legend-dot-peak { background: var(--text-light); opacity: 0.35; }
.bw-gauge-legend-dot-est { background: var(--est-color); }

.bw-est-summary {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* Details toggle */
.bw-est-details {
  padding: var(--space-4);
  background: var(--bg);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}

/* Same chevron-on-right pattern as .card-collapsible > .card-heading
   on #designBudget — hide the native marker, add a rotating square
   pseudo-element pushed to the right via margin-left: auto. */
.bw-est-details summary {
  list-style: none;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  user-select: none;
}

.bw-est-details summary::-webkit-details-marker {
  display: none;
}

.bw-est-details summary::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  margin-left: auto;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  flex-shrink: 0;
}

.bw-est-details[open] summary::after {
  transform: rotate(45deg);
}

.bw-est-details[open] summary {
  margin-bottom: var(--space-3-5);
}

/* Formula — vertical list */
.bw-est-formula {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  font-size: var(--fs-sm);
}

.bw-est-formula-line {
  display: flex;
  align-items: baseline;
  gap: var(--space-1);
  color: var(--text-muted);
}

.bw-est-formula-op {
  display: inline-block;
  width: var(--space-6);
  text-align: right;
  flex-shrink: 0;
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  color: var(--text-light);
}

.bw-est-formula-val {
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-weight: 600;
  color: var(--text);
}

.bw-est-formula-result {
  margin-top: 0.125rem;
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}

.bw-est-formula-result .bw-est-formula-val {
  color: var(--ax);
  font-weight: 700;
}

/* Endpoint capacity note */
.bw-est-note {
  margin: var(--space-3-5) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  line-height: 1.4;
}

.bw-est-note strong {
  color: var(--text);
}

/* Methodology note */
.bw-est-methodology {
  margin: var(--space-3-5) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-light);
  line-height: 1.4;
}

/* Soft ISP advisory — bandwidth gauge sits on a passive page, the user has not
   misconfigured anything; this is just a "heads up, check your uplink" note. */
.bw-est-warn {
  margin: 0 0 var(--space-3-5);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: center;
}

/* Design-level notice (oversubscription etc.) — actionable, stays prominent. */
.design-warn {
  margin: 0 0 var(--space-3-5);
  font-size: var(--fs-sm);
  color: var(--warning-text);
  background: var(--warning-bg);
  padding: var(--space-2) var(--space-3-5);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--warning);
}

.design-warn strong {
  color: inherit;
}


/* --- Step navigation (prev / next) --------------------------------------- */
.step-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 2rem;
  padding-top: var(--space-7);
  border-top: 1px solid var(--border-light);
}


/* --- Footer -------------------------------------------------------------- */
/* Height-matched to .sidebar-misc (both fixed at 7 rem) so the bottom-
   left misc actions and the bottom-right footer align horizontally.
   Flex-centering lets the single-line footer content sit midway within
   that block without extra vertical padding on .footer-inner. */
.footer {
  background: var(--bg-muted);
  border-top: 1px solid var(--border);
  margin-top: auto;
  height: 7rem;
  display: flex;
  align-items: center;
}

.footer-inner {
  max-width: 1400px;
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--space-7);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.footer-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.footer-brand-link {
  color: var(--text);
  font-weight: 500;
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--text-muted) 40%, transparent);
  transition: color 0.15s ease, text-decoration-color 0.15s ease;
}

.footer-brand-link:hover {
  color: var(--ax);
  text-decoration-color: var(--ax);
}

.footer-copyright {
  flex-shrink: 0;
}

/* Short footer notice pointing at the About page. Replaces the older
   expandable disclaimer block — full methodology + scope content now
   lives on /step-about. */
.footer-notice {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--text-muted);
}

.footer-about-link {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--ax);
  cursor: pointer;
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ax) 50%, transparent);
  transition: text-decoration-color 0.15s ease;
}

.footer-about-link:hover {
  text-decoration-color: var(--ax);
}


/* --- Design summary (Step 2) --------------------------------------------- */
.design-summary {
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: var(--space-6) var(--space-7);
  margin-bottom: var(--space-7);
}

.summary-stats {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  align-items: center;
}

.stat-inline {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  background: var(--bg-subtle);
  border-radius: 100px;
  border: 1px solid var(--border-light);
}

.stat-inline-value {
  font-weight: 700;
  color: var(--text);
  font-family: "Cascadia Mono", "Fira Mono", monospace;
}

.badge {
  display: inline-block;
  padding: var(--space-1) var(--space-4);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ax-dark);
  background: var(--ax-light);
  border-radius: 100px;
}

/* Wrapper around the variable feature badges (WiFi / RF / PoE / IPTV).
   Gives the badges their own gap since they're not direct flex children
   of .summary-stats. */
#designBadges,
#bomBadges {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}


/* --- Step 2 top row: Bandwidth gauge + System overview ------------------- *
 * Stacked on narrow viewports; side-by-side at ≥992 px with a 2:1 width
 * ratio (gauge : overview). flex gap handles both the vertical gap (stacked)
 * and the horizontal gap (side-by-side). min-width: 0 is required on the
 * flex children because the gauge SVG would otherwise widen the gauge column
 * past its 2/3 share when long peak-bandwidth labels (e.g. "10.2 Gbps") are
 * rendered. */
.design-top-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
}

@media (min-width: 992px) {
  .design-top-row {
    flex-direction: row;
    align-items: stretch;
  }
  .design-top-row > #designGauge    { flex: 2 1 0; min-width: 0; }
  .design-top-row > #designOverview { flex: 1 1 0; min-width: 0; }
}

/* --- System overview card (Step 2) --------------------------------------- */
.overview-section-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
}

.overview-detail {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-top: var(--space-2);
}

.product-link {
  color: var(--ax);
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ax) 50%, transparent);
  font-weight: 600;
  transition: text-decoration-color 0.15s;
}

.product-link:hover {
  text-decoration-color: var(--ax);
}


/* --- Key-value rows ------------------------------------------------------ */
.design-kv {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.kv-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: var(--fs-sm);
}

.kv-label {
  color: var(--text-muted);
}

.kv-value {
  font-weight: 600;
  color: var(--text);
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-size: var(--fs-sm);
}

.legend-fiber    { background: var(--color-fiber); }
.legend-splitter { background: var(--color-splitter); }
.legend-conn     { background: var(--color-conn); }
.legend-margin   { background: var(--success); opacity: 0.4; }

.budget-section-label {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.01em;
}

/* --- RF overlay budget subsection (1550 nm path) ------------------------- */
.budget-rf-section {
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-light);
}

/* --- Budget metrics: key-value list + status LED ------------------------- */
.budget-metrics {
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1px var(--space-6);
  align-items: baseline;
  font-size: var(--fs-xs);
}

.budget-metric {
  display: contents;
}

.budget-metric-label {
  margin: 0;
  color: var(--text-muted);
  font-weight: 500;
}

.budget-metric-value {
  margin: 0;
  color: var(--text);
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-feature-settings: "tnum";
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.budget-metric-sep {
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-light);
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
}

.budget-led {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--bg-muted);
  box-shadow: 0 0 0 1px var(--border-light);
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.budget-led-success {
  background: var(--success);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--success) 40%, transparent),
              0 0 8px color-mix(in srgb, var(--success) 55%, transparent);
}

.budget-led-warning {
  background: var(--warning);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--warning) 40%, transparent),
              0 0 8px color-mix(in srgb, var(--warning) 55%, transparent);
}

.budget-led-danger {
  background: var(--danger);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger) 40%, transparent),
              0 0 8px color-mix(in srgb, var(--danger) 55%, transparent);
}

/* Budget card header alert — shown next to "Optical Power Budget" heading when
   GPON or RF budget status is "fail" (not feasible). Red circle with "!" so
   the issue is visible even when the card is collapsed. */
.budget-alert {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--danger);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}
.budget-alert[hidden] { display: none; }

/* --- Warn / info blocks -------------------------------------------------- */
.budget-warn {
  font-size: var(--fs-xs);
  color: var(--danger);
  padding: var(--space-3-5) var(--space-4);
  background: var(--danger-bg);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--danger);
}
.budget-warn-caution {
  color: var(--warning-text);
  background: var(--warning-bg);
  border-left-color: currentColor;
}

/* "Your link configuration" inline block inside #designBudget. The static
   ITU-T G.984.2 class table that used to share these styles now lives on
   the About page (.about-table); these classes are scoped to the
   per-config bullets + Rx-range formula box. */
.budget-info-body {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  line-height: 1.6;
}

.budget-info-body p { margin: 0 0 var(--space-4); }

.budget-info-body code {
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-size: var(--fs-xs);
  background: var(--bg-muted);
  padding: 0.0625rem var(--space-2);
  border-radius: 3px;
  color: var(--text);
}

.budget-info-list {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-6);
}

.budget-info-list li { margin-bottom: var(--space-1); }

.budget-info-formula {
  padding: var(--space-3) var(--space-4);
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--ax);
}


/* --- BOM table (Step 4) -------------------------------------------------- */
.bom-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-6);
}

/* Heading inside the flex header: parent owns the bottom spacing. */
.bom-card-header .card-heading {
  margin-bottom: 0;
}

.bom-actions {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* Project ID + parameter pills between the card header and the BOM table. */
.bom-card-meta {
  margin-bottom: var(--space-5);
}

/* The last .project-id-row in the card-meta already supplies the gap to the
   pill strip below; no extra inner rules needed. */

.bom-table-wrap {
  overflow-x: auto;
  margin-top: var(--space-3);
}

.bom-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.bom-table th,
.bom-table td {
  padding: var(--space-3-5) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--border-light);
  vertical-align: top;
}

.bom-table th {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  border-bottom: 2px solid var(--text);
}

.bom-table tbody tr:last-child td {
  border-bottom: none;
}

.bom-table .bom-qty,
.bom-table th.bom-qty {
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  text-align: right;
  white-space: nowrap;
  width: 1%;
}

.bom-table .bom-model {
  white-space: nowrap;
  width: 1%;
}

.bom-table .bom-desc .bom-note {
  display: block;
  font-size: 14px;
  color: var(--text-muted);
  font-weight: 400;
  margin-top: 0.125rem;
}

.bom-table .bom-ordno {
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-size: 14px;
  color: var(--text);
  white-space: nowrap;
  width: 1%;
}

.bom-table .bom-desc {
  color: var(--text);
  font-size: 14px;
}


/* --- Attenuator recommendation ------------------------------------------- */
.attenuator-rec {
  font-size: var(--fs-sm);
  color: var(--warning-text);
  padding: var(--space-3-5) var(--space-4);
  background: var(--warning-bg);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--warning);
}

.fatal-error {
  margin: var(--space-5) 0;
  padding: var(--space-4) var(--space-5);
  background: var(--danger-bg);
  border: 1px solid var(--danger);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm);
  color: var(--danger);
  font-size: var(--fs-sm);
}


/* --- Project ID (Step 1 "General") --------------------------------------- */
.project-id-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  font-size: var(--fs-sm);
  line-height: 1.3;
  flex-wrap: wrap;
}

.project-id-label {
  color: var(--text-muted);
}

.project-id-value {
  font-family: "Cascadia Mono", "Fira Mono", monospace;
  font-weight: 600;
  color: var(--text);
  user-select: all;
  letter-spacing: 0.02em;
}

.project-id-reset {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
}


/* --- Request a Quote (Step 5) ------------------------------------------- */
textarea.form-input {
  min-height: 5.5rem;
  resize: vertical;
  line-height: 1.5;
}

.form-req {
  color: var(--danger);
  font-weight: 500;
}

.quote-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6) var(--space-5);
  margin-bottom: var(--space-6);
}

.quote-grid .form-group {
  margin-bottom: 0;
}

@media (min-width: 640px) {
  .quote-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.quote-actions {
  display: flex;
  gap: var(--space-3);
  justify-content: flex-end;
  margin-top: var(--space-5);
  flex-wrap: wrap;
}

/* Live URL-length counter under #qNotes. Empty until populateQuote runs and
 * a calc() result exists. Goes orange at ≥85 % of MAILTO_LIMIT and red once
 * the URL exceeds the cap (matches the warn / fail visual language used
 * elsewhere). */
.quote-counter {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.quote-counter.near-limit { color: var(--warning); }
.quote-counter.over-limit { color: var(--danger); font-weight: 500; }

.quote-notice {
  margin-top: var(--space-4);
  padding: var(--space-3-5) var(--space-4);
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--border);
}

.quote-notice-success {
  color: var(--success);
  background: var(--success-bg);
  border-left-color: var(--success);
}

.quote-notice-warn {
  color: var(--warning-text);
  background: var(--warning-bg);
  border-left-color: var(--warning);
}

.quote-notice-error {
  color: var(--danger);
  background: var(--danger-bg);
  border-left-color: var(--danger);
}

.quote-privacy {
  margin-top: var(--space-5);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  line-height: 1.6;
}

.quote-recipient-link {
  color: var(--text-muted);
  text-decoration: underline dotted currentColor;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.15s ease;
}

.quote-recipient-link:hover {
  color: var(--ax);
}

.step-placeholder {
  padding: var(--space-6) var(--space-7);
  margin-bottom: var(--space-7);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  background: var(--bg-subtle);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  text-align: center;
}


/* --- Step 3: Topology diagram ------------------------------------------- */
/* Full-SVG top-down schematic. Everything — boxes, icons, labels, lines —
   lives in one SVG. The viewBox is portrait-oriented and set dynamically
   per render (see populateTopology() / MIN_VIEWBOX_WIDTH in main.js).
   Rendered imperatively from composable drawDevice / drawLine /
   appendTopoIconDefs functions. No HTML grid, no click interactivity,
   no alignment math. */

.topo-svg {
  display: block;
  width: auto;
  /* Per-viewBox upscale cap: --topo-max-w/h are set inline by
     populateTopology to viewBox-px * 1.2, keeping rendered text + icon
     sizes visually similar across the 6 viewBox classes. Fallbacks
     match the largest cascade case so a render without JS still has
     sane bounds. */
  max-width: var(--topo-max-w, 797px);
  max-height: var(--topo-max-h, 926px);
  height: auto;                /* preserves aspect via viewBox */
  margin: var(--space-5) auto 0;
  color: var(--text-muted);    /* drives icon stroke="currentColor" for <use> */
}

/* Device boxes — fill follows theme, border is subtle. Client boxes drop
   the border: the row below ONU is icon-only, and the rect is kept only
   to mask the vertical connection line behind the icon. */
.topo-device-box {
  fill: var(--bg);
  stroke: var(--border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.topo-device-client .topo-device-box {
  stroke: none;
}

/* SVG text styling. Font-sizes are in SVG user units — they scale with the
   viewBox. At max-width 1000px the scale is 1:1, so these map directly to
   pixels. Label follows the 15 px app minimum; sublabel at 12 px is an
   exception (same relaxation as BOM table + print view), justified by the
   dense, schematic-style layout. */
.topo-device-label {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: 16px;
  font-weight: 500;
  fill: var(--text);
}

/* Ditto tile ("ONU" placeholder for non-representative splitter strands)
   — shrink label so it fits comfortably inside the 48×32 tile. */
.topo-device-ditto .topo-device-label {
  font-size: 14px;
}

.topo-device-sublabel {
  font-family: "Cascadia Mono", "Cascadia Code", Consolas, monospace;
  font-size: 14px;
  fill: var(--text-muted);
}

.topo-badge-bg {
  fill: var(--ax);
  stroke: var(--bg);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.topo-badge-text {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: 12px;
  font-weight: 600;
  fill: #fff;
}

/* Per-strand endpoint count marker on splitter → ONU / ditto lines:
   a short 45° slash across the line plus a "×N" label to the right.
   Replaces the per-tile badge — keeps the ONU and ditto boxes clean
   and makes the "each strand serves N endpoints" reading explicit on
   the connection line itself. */
.topo-tick {
  stroke: dimgray;
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.topo-tick-label {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: 14px;
  font-weight: 600;
  fill: dimgray;
}

/* Connection lines — colored by signal type. vector-effect keeps stroke
   weight constant even when the SVG is scaled up/down to fit the viewport. */
.topo-line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.topo-line.conn-internet { stroke: var(--sig-internet); }
.topo-line.conn-combined { stroke: var(--sig-combined); }  /* GPON + RF combined fiber (post-WDM) */
.topo-line.conn-pon      { stroke: var(--sig-pon); }
.topo-line.conn-rf       { stroke: var(--sig-rf); }
.topo-line.conn-antenna  { stroke: var(--text); }         /* electrical RF coax — SAT → MK and MK → OTX (pre-optical) */
.topo-line.conn-coax     { stroke: var(--text-muted); }   /* RF coax drop ONU → TV */
.topo-line.conn-client   { stroke: var(--text-light); }

/* Signal-color legend below the diagram (HTML, unchanged). */
.topo-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  justify-content: center;
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-light);
}

.topo-legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.topo-legend-item[hidden] { display: none; }

.topo-legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.topo-legend-item[data-sig="internet"] .topo-legend-dot { background: var(--sig-internet); }
.topo-legend-item[data-sig="combined"] .topo-legend-dot { background: var(--sig-combined); }
.topo-legend-item[data-sig="pon"]      .topo-legend-dot { background: var(--sig-pon); }
.topo-legend-item[data-sig="rf"]       .topo-legend-dot { background: var(--sig-rf); }


/* --- Help modal ---------------------------------------------------------- */
.help-overlay {
  position: fixed;
  inset: 0;
  background: var(--overlay-dark);
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}

.help-modal {
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  max-width: 480px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
}

.help-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border-light);
}

.help-header h3 {
  font-size: var(--fs);
  font-weight: 500;
  color: var(--text);
}

.help-close {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  font-size: var(--fs-xl);
  color: var(--text-light);
  cursor: pointer;
  border-radius: 4px;
  transition: background 0.1s, color 0.1s;
}

.help-close:hover {
  background: var(--bg-subtle);
  color: var(--text);
}

.help-body {
  padding: var(--space-6);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  line-height: 1.6;
}

.help-body h4 {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  margin: var(--space-5) 0 var(--space-2);
}

.help-body h4:first-child {
  margin-top: 0;
}

.help-body ol {
  padding-left: var(--space-6);
}

.help-body li {
  margin-bottom: var(--space-1);
}

.help-body p {
  margin: 0;
}


/* --- Confirm modal (reuses .help-overlay / .help-modal) ------------------ */
.confirm-modal {
  max-width: 420px;
}

.confirm-body {
  padding-bottom: var(--space-3);
  color: var(--text);
}

.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6) var(--space-6);
  flex-wrap: wrap;
}


/* --- Dark theme ---------------------------------------------------------- */
[data-theme="dark"] {
  --bg: #0d1017;
  --bg-subtle: #131720;
  --bg-muted: #1c2030;
  --bg-input: #181c28;
  --border: #2a2f3d;
  --border-light: #222736;

  --text: #d4d7de;
  --text-muted: #8b919d;
  --text-light: #5c6370;

  --ax-light: rgba(0, 153, 147, 0.12);

  --success-bg: rgba(22, 163, 74, 0.12);
  --warning-bg: rgba(217, 119, 6, 0.1);
  --warning-text: #fbbf24;
  --danger-bg: rgba(220, 38, 38, 0.12);

  /* Brighter, more luminous pulse for dark mode — translucent #009993 fades
   * into the dark surface, so we shift the hue lighter (teal-400 / teal-300
   * range) and bump alpha so the glow stays readable. */
  --pulse-low:  rgba(45, 212, 191, 0.28);
  --pulse-high: rgba(94, 234, 212, 0.6);
}

[data-theme="dark"] .sidebar,
[data-theme="dark"] .header {
  background: var(--bg);
}

[data-theme="dark"] .card {
  background: var(--bg-subtle);
}

[data-theme="dark"] .design-summary {
  background: var(--bg-subtle);
}

[data-theme="dark"] .help-modal {
  background: var(--bg-subtle);
}


/* --- Scrollbar ----------------------------------------------------------- */
/* One custom-scrollbar look shared by the document viewport and the
   sidebar: thin rail, transparent track, muted thumb that darkens on
   hover. html + body are both styled because the document scrollbar
   "propagates" from one or the other depending on browser/layout — in
   the grid layout in particular some browsers route it via <html>, so
   only styling <body> leaves the viewport scrollbar unthemed. WebKit
   (Chrome/Edge/Safari) uses the ::-webkit-scrollbar pseudos; Firefox
   uses scrollbar-width + scrollbar-color. */
html,
body,
.sidebar {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

html::-webkit-scrollbar,
body::-webkit-scrollbar,
.sidebar::-webkit-scrollbar {
  width: 6px;
}

html::-webkit-scrollbar-track,
body::-webkit-scrollbar-track,
.sidebar::-webkit-scrollbar-track {
  background: transparent;
}

html::-webkit-scrollbar-thumb,
body::-webkit-scrollbar-thumb,
.sidebar::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}

html::-webkit-scrollbar-thumb:hover,
body::-webkit-scrollbar-thumb:hover,
.sidebar::-webkit-scrollbar-thumb:hover {
  background: var(--text-light);
}


/* --- Utilities ----------------------------------------------------------- */
.mt-4  { margin-top: var(--space-1); }
.mt-8  { margin-top: var(--space-3); }
.mt-14 { margin-top: 0.875rem; }
.mt-16 { margin-top: var(--space-5); }
.mt-24 { margin-top: var(--space-7); }


/* --- Responsive ---------------------------------------------------------- */

/* Desktop: widen main padding, bump card padding. Header padding stays
   at the mobile value (0 var(--space-5)) so the brand sits a consistent
   distance from the viewport edge across breakpoints. */
@media (min-width: 768px) {
  .main {
    padding: 2rem clamp(var(--space-7), 3vw, 2.5rem);
  }

  .card {
    padding: var(--space-7);
  }
}
