/* Manual-entry page styles. Built entirely on tokens.css custom
   properties — no hardcoded colors/fonts here (see tokens.json for the
   source of truth). */

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--color-bg-base);
  color: var(--color-text-primary);
  font-family: var(--font-family-sans);
  font-size: var(--primitive-fontSize-base);
  line-height: 1.55;
}

[x-cloak] {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Consistent amber focus ring across every interactive control — applied
   once here rather than per-component, so nothing falls back to a
   mismatched browser default. */
.btn:focus-visible,
.os-option:focus-visible,
.link-button:focus-visible,
.field-input:focus-visible,
.checkbox-label input:focus-visible,
details summary:focus-visible {
  outline: 2px solid var(--color-accent-active);
  outline-offset: 2px;
}

a {
  color: var(--color-accent-info-bright);
}

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

.page {
  max-width: 760px;
  margin: 0 auto;
  padding: var(--primitive-spacing-8) var(--primitive-spacing-5) var(--primitive-spacing-20);
}

/* Widened only once results are showing, and only as much as the actual
   layout needs (see index.html's pageWidthClass getter) — one diagram
   column (either side) needs real room for a legibly-sized diagram
   alongside the sections column; two side by side (general path_trace
   on the right, scoped target_path_trace on the left) need more again.
   Every other view (landing, forms, review, or a result with no
   diagram at all) stays at the original, narrower 760px. */
.page--wide {
  max-width: 1040px;
}

.page--extra-wide {
  max-width: 1440px;
}

/* Embedded mode uses the full iframe width. Standalone mode keeps the
   deliberately narrower reading/workspace measure above. */
html.pathlens-embedded .page,
html.pathlens-embedded .page--wide,
html.pathlens-embedded .page--extra-wide {
  width: 100%;
  max-width: none;
}

/* ---------------------------------------------------------------- header */

.page-header {
  margin-bottom: var(--primitive-spacing-10);
}

.page-header__eyebrow {
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-active-bright);
  margin-bottom: var(--primitive-spacing-2);
}

.page-header h1 {
  font-size: var(--primitive-fontSize-2xl);
  font-weight: 600;
  margin: 0 0 var(--primitive-spacing-2);
  letter-spacing: -0.01em;
}

.page-header p {
  color: var(--color-text-secondary);
  margin: 0;
  max-width: 56ch;
}

/* ------------------------------------------------------------- landing */

.choice-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--primitive-spacing-4);
}

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

.choice-card {
  text-align: left;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-default);
  border-radius: var(--primitive-radius-lg);
  padding: var(--primitive-spacing-5);
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: border-color var(--primitive-duration-normal), transform var(--primitive-duration-normal);
}

.choice-card:hover {
  border-color: var(--color-accent-active-border);
  transform: translateY(-1px);
}

.choice-card:focus-visible {
  outline: 2px solid var(--color-accent-active);
  outline-offset: 2px;
}

.choice-card__title {
  font-weight: 600;
  font-size: var(--primitive-fontSize-lg);
  margin-bottom: var(--primitive-spacing-2);
}

.choice-card__desc {
  color: var(--color-text-secondary);
  font-size: var(--primitive-fontSize-sm);
}

/* -------------------------------------------------------------- os picker */

.os-picker {
  display: flex;
  gap: var(--primitive-spacing-3);
  margin-bottom: var(--primitive-spacing-8);
}

.os-option {
  flex: 1;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-default);
  border-radius: var(--primitive-radius-md);
  padding: var(--primitive-spacing-3) var(--primitive-spacing-4);
  min-height: 44px; /* WCAG 2.5.5 / mobile touch-target minimum */
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-sm);
  color: var(--color-text-secondary);
  cursor: pointer;
  text-align: center;
  transition: all var(--primitive-duration-fast);
}

.os-option:hover {
  border-color: var(--color-border-strong);
  color: var(--color-text-primary);
}

.os-option--selected {
  border-color: var(--color-accent-active-border);
  background: var(--color-accent-active-bg);
  color: var(--color-accent-active-bright);
}

/* --------------------------------------------------------------- step card */

.step-card {
  background: var(--step-card-bg);
  border-radius: var(--step-card-radius);
  padding: var(--step-card-padding);
  margin-bottom: var(--primitive-spacing-4);
  border: var(--step-card-border-width-pending) solid var(--step-card-border-color-pending);
  transition: border-color var(--primitive-duration-normal), box-shadow var(--primitive-duration-normal);
}

/* No opacity here (removed — see docs/security-upload-architecture-
   handoff.md's accessibility findings): opacity dims the WHOLE
   subtree as one flattened group composited over the page background,
   which multiplies every child's already-compliant text color by the
   same factor — at this card's old 0.55 opacity, --color-text-muted
   (already a deliberately-muted, already-compliant token on its own,
   used by .step-card__hop-label below) measured ~2.4:1 against the
   effective background, well under WCAG AA's 4.5:1 floor. Pending
   cards are visually distinguished from active/complete ones by
   border-color alone now (see --step-card-border-color-pending above
   vs. -active/-complete below) plus the title-specific override just
   below — both real, solid colors, individually contrast-checked
   against this card's actual background, not a blanket multiplier. */
.step-card--pending .step-card__title {
  /* text-secondary measures ~7.5:1 against --step-card-bg (#161a1e) —
     comfortably past AA's 4.5:1 floor, and visibly less prominent than
     text-primary's ~13:1, which active/complete titles keep by not
     overriding this. */
  color: var(--color-text-secondary);
}

.step-card--active {
  opacity: 1;
  border-width: var(--step-card-border-width-active);
  border-color: var(--step-card-border-color-active);
  box-shadow: var(--step-card-shadow-active);
}

.step-card--complete {
  opacity: 1;
  border-color: var(--step-card-border-color-complete);
}

.step-card__head {
  display: flex;
  align-items: center;
  gap: var(--primitive-spacing-3);
  margin-bottom: var(--primitive-spacing-4);
}

.step-badge {
  width: var(--step-card-badge-size);
  height: var(--step-card-badge-size);
  min-width: var(--step-card-badge-size);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-sm);
  font-weight: 600;
  background: var(--step-card-badge-bg-pending);
  color: var(--step-card-badge-fg-pending);
  transition: all var(--primitive-duration-normal);
}

.step-card--active .step-badge {
  background: var(--step-card-badge-bg-active);
  color: var(--step-card-badge-fg-active);
}

.step-card--complete .step-badge {
  background: var(--step-card-badge-bg-complete);
  color: var(--step-card-badge-fg-complete);
}

.step-card__title {
  font-weight: 600;
  font-size: var(--primitive-fontSize-md);
}

.step-card__hop-label {
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.step-card__label {
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--primitive-spacing-2);
}

/* ------------------------------------------------------------- code block */

.code-block {
  background: var(--code-block-bg);
  border: 1px solid var(--code-block-border);
  border-radius: var(--code-block-radius);
  padding: var(--code-block-padding-y) var(--code-block-padding-x);
  font-family: var(--code-block-font);
  font-size: var(--code-block-font-size);
  color: var(--code-block-fg);
  margin-bottom: var(--primitive-spacing-4);
  display: flex;
  align-items: center;
  gap: var(--primitive-spacing-2);
  overflow-x: auto;
  white-space: pre;
}

.code-block__prompt {
  color: var(--code-block-prompt-fg);
  user-select: none;
}

/* ---------------------------------------------------------------- textarea */

.paste-textarea {
  width: 100%;
  min-height: var(--textarea-min-height);
  background: var(--textarea-bg);
  color: var(--textarea-fg);
  font-family: var(--textarea-font);
  font-size: var(--textarea-font-size);
  border: 1px solid var(--textarea-border);
  border-radius: var(--textarea-radius);
  padding: var(--primitive-spacing-3);
  resize: vertical;
  margin-bottom: var(--primitive-spacing-3);
}

.paste-textarea::placeholder {
  color: var(--textarea-placeholder-fg);
}

.paste-textarea:focus-visible {
  outline: none;
  border-color: var(--textarea-border-focus);
  box-shadow: 0 0 0 3px var(--color-accent-active-bg);
}

/* ------------------------------------------------------------------ buttons */

.btn {
  font-family: var(--font-family-sans);
  font-size: var(--primitive-fontSize-sm);
  font-weight: 600;
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-2) var(--primitive-spacing-4);
  min-height: 44px; /* WCAG 2.5.5 / mobile touch-target minimum */
  border: 1px solid transparent;
  cursor: pointer;
  transition: all var(--primitive-duration-fast);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--color-accent-active);
  color: var(--primitive-color-graphite-950);
}

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

.btn-secondary {
  background: transparent;
  color: var(--color-text-secondary);
  border-color: var(--color-border-default);
}

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

.btn-full {
  width: 100%;
}

/* ------------------------------------------------------------------- badges */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--primitive-spacing-1);
  font-family: var(--badge-font);
  font-size: var(--badge-font-size);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--badge-padding-y) var(--badge-padding-x);
  border-radius: var(--badge-radius);
  border: 1px solid transparent;
  background: var(--badge-bg-neutral);
  color: var(--badge-fg-neutral);
}

.badge--info {
  background: var(--badge-bg-info);
  color: var(--badge-fg-info);
  border-color: var(--badge-border-info);
}

.badge--success {
  background: var(--badge-bg-success);
  color: var(--badge-fg-success);
  border-color: var(--badge-border-success);
}

.badge--warning {
  background: var(--badge-bg-warning);
  color: var(--badge-fg-warning);
  border-color: var(--badge-border-warning);
}

.badge--danger {
  background: var(--badge-bg-danger);
  color: var(--badge-fg-danger);
  border-color: var(--badge-border-danger);
}

/* ------------------------------------------------------------- summary line */

.summary-line {
  display: flex;
  align-items: flex-start;
  gap: var(--primitive-spacing-2);
  font-size: var(--summary-line-font-size);
  margin-top: var(--primitive-spacing-3);
}

.summary-line__icon {
  width: var(--summary-line-icon-size);
  height: var(--summary-line-icon-size);
  min-width: var(--summary-line-icon-size);
  margin-top: 2px;
}

.summary-line--success {
  color: var(--summary-line-fg-success);
}

.summary-line--error {
  color: var(--summary-line-fg-error);
}

/* ------------------------------------------------------------- disclosure */

.disclosure summary {
  cursor: pointer;
  color: var(--disclosure-trigger-fg);
  font-size: var(--primitive-fontSize-xs);
  font-family: var(--font-family-mono);
  margin-top: var(--primitive-spacing-2);
  list-style: none;
  user-select: none;
}

.disclosure summary:hover {
  color: var(--disclosure-trigger-fg-hover);
}

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

.disclosure summary::before {
  content: "▸ ";
}

.disclosure[open] summary::before {
  content: "▾ ";
}

.disclosure pre {
  background: var(--disclosure-content-bg);
  font-family: var(--disclosure-content-font);
  font-size: var(--disclosure-content-font-size);
  color: var(--color-text-secondary);
  padding: var(--primitive-spacing-3);
  border-radius: var(--primitive-radius-default);
  overflow-x: auto;
  margin-top: var(--primitive-spacing-2);
}

/* -------------------------------------------------------- section summary */

.section-summary-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--primitive-spacing-3);
}

.section-summary-row__text {
  font-size: var(--primitive-fontSize-sm);
  color: var(--color-text-secondary);
}

.link-button {
  background: none;
  border: none;
  padding: 0;
  color: var(--color-accent-info-bright);
  font-family: var(--font-family-sans);
  font-size: var(--primitive-fontSize-sm);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ----------------------------------------------------------- auto-fetch */

/* Same "active decision, real consequence" amber treatment as
   .watch-dns-callout below — this too is asking for an explicit yes
   before the browser talks to anything outside this page. */
.network-consent-callout {
  background: var(--color-accent-active-bg);
  border: 1px solid var(--color-accent-active-border);
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-4);
  margin-bottom: var(--primitive-spacing-4);
}

.network-consent-callout__text {
  color: var(--color-text-secondary);
  font-size: var(--primitive-fontSize-sm);
  margin-bottom: var(--primitive-spacing-3);
}

.network-consent-callout__text strong {
  color: var(--color-accent-active-bright);
}

.autofetch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--primitive-spacing-3);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--primitive-radius-md);
  padding: var(--primitive-spacing-3) var(--primitive-spacing-4);
  margin-bottom: var(--primitive-spacing-3);
}

@media (max-width: 480px) {
  .autofetch-row {
    flex-direction: column;
    align-items: flex-start;
  }
}

.autofetch-row__title {
  font-weight: 600;
  font-size: var(--primitive-fontSize-sm);
}

.autofetch-row__desc {
  color: var(--color-text-muted);
  font-size: var(--primitive-fontSize-xs);
}

/* -------------------------------------------------------------------- misc */

.optional-toggle {
  margin-top: var(--primitive-spacing-4);
  padding-top: var(--primitive-spacing-4);
  border-top: 1px dashed var(--color-border-default);
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: var(--primitive-spacing-2);
  font-size: var(--primitive-fontSize-sm);
  color: var(--color-text-secondary);
  cursor: pointer;
}

.review-panel {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--primitive-radius-lg);
  padding: var(--primitive-spacing-5);
  margin-top: var(--primitive-spacing-8);
}

.review-panel h2 {
  font-size: var(--primitive-fontSize-lg);
  margin: 0 0 var(--primitive-spacing-4);
}

.review-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--primitive-spacing-2) 0;
  border-bottom: 1px solid var(--color-border-subtle);
  font-size: var(--primitive-fontSize-sm);
}

.review-row:last-of-type {
  border-bottom: none;
}

.review-row__label {
  color: var(--color-text-secondary);
}

.field-input {
  width: 100%;
  background: var(--textarea-bg);
  color: var(--textarea-fg);
  font-family: var(--font-family-sans);
  font-size: var(--primitive-fontSize-sm);
  border: 1px solid var(--textarea-border);
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-2) var(--primitive-spacing-3);
}

/* Info, not danger — a missing optional tool isn't a failure state
   (same framing as collect.py's own "optional tool, not auto-installed"
   messages), just something worth knowing before pasting a command that
   would otherwise fail with no warning. */
.install-hint-box {
  background: var(--color-accent-info-bg);
  border: 1px solid var(--color-accent-info-border);
  color: var(--color-text-secondary);
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-3);
  font-size: var(--primitive-fontSize-sm);
  margin-bottom: var(--primitive-spacing-3);
}

.install-hint-box strong {
  color: var(--color-accent-info-bright);
}

.error-box {
  background: var(--color-accent-danger-bg);
  border: 1px solid var(--color-accent-danger-border);
  color: var(--color-accent-danger-bright);
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-3);
  font-size: var(--primitive-fontSize-sm);
  margin-top: var(--primitive-spacing-3);
}

/* Amber, not neutral — this is an active decision with a real ongoing
   consequence (indefinite daily monitoring), not passive information,
   so it gets the same "active/current scope" accent as everything else
   in this app that represents something the user is actively doing. */
.watch-dns-callout {
  background: var(--color-accent-active-bg);
  border: 1px solid var(--color-accent-active-border);
  border-radius: var(--primitive-radius-default);
  padding: var(--primitive-spacing-4);
  margin: var(--primitive-spacing-5) 0;
  text-align: left;
  max-width: 56ch;
  margin-left: auto;
  margin-right: auto;
}

.watch-dns-callout__text {
  color: var(--color-text-secondary);
  font-size: var(--primitive-fontSize-sm);
  margin-bottom: var(--primitive-spacing-3);
}

.watch-dns-callout__text strong {
  color: var(--color-accent-active-bright);
}

.watch-dns-callout--done {
  color: var(--color-accent-success-bright);
  font-size: var(--primitive-fontSize-sm);
  background: var(--color-accent-success-bg);
  border-color: var(--color-accent-success-border);
}

.done-panel {
  text-align: center;
  padding: var(--primitive-spacing-10) var(--primitive-spacing-4);
}

.done-panel__icon {
  color: var(--color-accent-success-bright);
  font-size: var(--primitive-fontSize-3xl);
  margin-bottom: var(--primitive-spacing-3);
}

.narrative-results {
  text-align: left;
  margin-top: var(--primitive-spacing-6);
  display: grid;
  /* No diagram at all: sections fill the full width. The two modifier
     classes below (combinable — see index.html's :class binding) add a
     column on whichever side has a diagram; DOM order controls left-vs-
     right placement directly (the target/left diagram renders first in
     the markup), so there's no need to juggle grid-column positions
     here, just how many tracks exist. */
  grid-template-columns: 1fr;
  gap: var(--primitive-spacing-6);
  align-items: start;
}

.narrative-results--with-diagram {
  grid-template-columns: 1fr minmax(320px, 420px);
}

.narrative-results--with-target {
  grid-template-columns: minmax(320px, 420px) 1fr;
}

.narrative-results--with-target.narrative-results--with-diagram {
  grid-template-columns: minmax(320px, 420px) 1fr minmax(320px, 420px);
}

.narrative-main {
  min-width: 0; /* grid blowout guard — lets long unbroken values in the
                   facts grid wrap/truncate instead of stretching this
                   column past its 1fr share */
}

@media (max-width: 768px) {
  /* side-by-side doesn't work at narrow widths — everything stacks into
     one column instead. DOM order alone would put the target/left
     diagram (rendered first, for desktop's left-column placement)
     ABOVE the status banner and sections on a phone screen, which reads
     badly — a diagram before you've even seen the summary. These three
     explicit `order` values put the sections first regardless of DOM
     position, then the target diagram, then the general one — desktop
     doesn't set `order` at all, so this only ever applies here.

     The three-selector list on grid-template-columns isn't redundant:
     .narrative-results--with-target.narrative-results--with-diagram
     (two classes combined, both diagrams present) has HIGHER
     specificity (0,2,0) than a single .narrative-results override
     (0,1,0) — a plain override here would silently lose to that
     combined selector's 3-column template and stay 3-wide even inside
     this media query, real behavior caught visually (not by any
     structural check) at a 700px viewport. Repeating the same modifier
     combinations at matching specificity is what actually wins. */
  .narrative-results,
  .narrative-results--with-diagram,
  .narrative-results--with-target,
  .narrative-results--with-target.narrative-results--with-diagram {
    grid-template-columns: 1fr;
  }

  .narrative-main {
    order: 1;
  }

  .narrative-diagram-col--target {
    order: 2;
  }

  .narrative-diagram-col:not(.narrative-diagram-col--target) {
    order: 3;
  }
}

/* ----------------------------------------------------------- status banner */

.status-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--primitive-spacing-3);
  padding: var(--status-banner-padding);
  border-radius: var(--status-banner-radius);
  border: var(--status-banner-border-width) solid;
  margin-bottom: var(--primitive-spacing-6);
}

.status-banner--healthy {
  background: var(--status-banner-bg-healthy);
  border-color: var(--status-banner-border-healthy);
}

.status-banner--attention {
  background: var(--status-banner-bg-attention);
  border-color: var(--status-banner-border-attention);
}

.status-banner--issue {
  background: var(--status-banner-bg-issue);
  border-color: var(--status-banner-border-issue);
}

.status-banner__icon {
  font-size: var(--primitive-fontSize-xl);
  line-height: 1;
  margin-top: 2px;
}

.status-banner--healthy .status-banner__icon,
.status-banner--healthy .status-banner__label { color: var(--status-banner-fg-healthy); }
.status-banner--attention .status-banner__icon,
.status-banner--attention .status-banner__label { color: var(--status-banner-fg-attention); }
.status-banner--issue .status-banner__icon,
.status-banner--issue .status-banner__label { color: var(--status-banner-fg-issue); }

.status-banner__label {
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--primitive-spacing-1);
}

.status-banner__summary {
  color: var(--status-banner-summary-fg);
  font-size: var(--primitive-fontSize-md);
  font-weight: 500;
  line-height: 1.5;
}

/* ------------------------------------------------------------ narrative section cards */

.narrative-section {
  background: var(--step-card-bg);
  border-radius: var(--step-card-radius);
  padding: var(--step-card-padding);
  margin-bottom: var(--primitive-spacing-4);
  border: 1px solid var(--color-border-subtle);
}

.narrative-section__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--primitive-spacing-3);
  margin-bottom: var(--primitive-spacing-4);
}

.narrative-section__title {
  font-weight: 600;
  font-size: var(--primitive-fontSize-md);
  margin: 0;
}

.facts-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--facts-grid-row-gap) var(--facts-grid-column-gap);
  margin-bottom: var(--primitive-spacing-4);
  padding-bottom: var(--primitive-spacing-4);
  border-bottom: 1px solid var(--facts-grid-divider);
}

.facts-grid__label {
  color: var(--facts-grid-label-fg);
  font-family: var(--facts-grid-label-font);
  font-size: var(--facts-grid-label-font-size);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.facts-grid__value {
  color: var(--facts-grid-value-fg);
  font-family: var(--facts-grid-value-font);
  font-size: var(--facts-grid-value-font-size);
  word-break: break-word;
}

.narrative-section__text {
  color: var(--narrative-text-fg);
  font-family: var(--narrative-text-font);
  font-size: var(--narrative-text-font-size);
  line-height: var(--narrative-text-line-height);
  margin: 0;
}

@media (max-width: 480px) {
  .facts-grid {
    grid-template-columns: 1fr;
    gap: 0 var(--facts-grid-row-gap);
  }

  .facts-grid__value {
    margin-bottom: var(--primitive-spacing-2);
  }
}

/* --------------------------------------------------------- path diagram */

.narrative-diagram-col {
  min-width: 0; /* grid blowout guard, same reasoning as .narrative-main */
}

.path-diagram__label {
  color: var(--path-diagram-label-fg);
  font-family: var(--path-diagram-label-font);
  font-size: var(--path-diagram-label-font-size);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--primitive-spacing-2);
}

.path-diagram {
  background: var(--path-diagram-bg);
  border: 1px solid var(--path-diagram-border);
  border-radius: var(--path-diagram-radius);
  padding: var(--path-diagram-padding);
  /* No overflow-x/scrolling here on purpose: that was for the old
     horizontal (flowchart LR) layout, where a 15-30 hop traceroute
     rendered wider than its card. The vertical (flowchart TD) layout
     grows tall instead of wide — this container just lets that height
     happen naturally, and the page itself scrolling to see the whole
     diagram is the intended behavior, not a scrollbar on a small box. */
}

.path-diagram svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* ------------------------------------------------------------------ print */

@media print {
  /* Only reached from the done panel (the export buttons only render
     once finalResult.narrative exists), but hidden explicitly rather
     than relying on that: none of this — the intro copy, every button,
     the mode/OS-picker/step-card flow, the review panel — is the report
     itself, and none of it belongs on paper or in a saved PDF. */
  .page-header p,
  .btn,
  .link-button,
  .choice-grid,
  .os-picker,
  .step-card,
  .autofetch-row,
  .review-panel,
  .done-panel__icon,
  .done-panel > h2,
  .done-panel > p {
    display: none !important;
  }

  /* Status-banner tints and section badges carry real meaning (the
     status IS the information), not decoration — browsers drop
     background colors from print/PDF output by default unless told
     not to. */
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .page,
  .page--wide,
  .page--extra-wide {
    max-width: 100%;
    padding: 0;
  }

  /* A physical page (or PDF page) is never wide enough for the desktop
     2-3 column grid, so print always collapses to one column, same
     stacking order as the narrow-viewport case above — same specificity
     reasoning applies here too: see that block's comment for why all
     four selectors are needed instead of just .narrative-results. */
  .narrative-results,
  .narrative-results--with-diagram,
  .narrative-results--with-target,
  .narrative-results--with-target.narrative-results--with-diagram {
    grid-template-columns: 1fr;
  }

  .narrative-main {
    order: 1;
  }

  .narrative-diagram-col--target {
    order: 2;
  }

  .narrative-diagram-col:not(.narrative-diagram-col--target) {
    order: 3;
  }

  /* Keeps a section card or a diagram panel from splitting mid-content
     across a page boundary where the content is short enough to fit on
     one page to begin with — break-inside:avoid can't do anything for
     a diagram/card genuinely taller than one physical page, only stop
     the awkward splits on ones that would otherwise fit. */
  .narrative-section,
  .path-diagram,
  .narrative-diagram-col {
    break-inside: avoid;
  }
}

/* ------------------------------------------------ landing explanation */
/* This screen's job is a single decision between two paths. An earlier
   version put ~390 words above those two buttons; the choice is now first
   and the detail sits behind disclosures.

   Every value below is a token. An earlier pass used literal fallbacks
   like rgba(255,255,255,0.03), which silently ignored the theme -- the
   real names are in tokens.css and they already handle light and dark. */

.landing {
  display: flex;
  flex-direction: column;
  gap: var(--primitive-spacing-6);
}

.landing__lede {
  /* ch, not px: the measure should follow the font, and this keeps body
     copy inside the ~45-75 character range where it stays readable. */
  max-width: 62ch;
}

.landing__title {
  margin: 0 0 var(--primitive-spacing-3);
  text-wrap: balance;
}

.landing__sub {
  margin: 0;
  color: var(--color-text-secondary);
  line-height: 1.6;
}

.choice-card__badge {
  display: inline-block;
  align-self: flex-start;
  margin-bottom: var(--primitive-spacing-2);
  padding: 0.15rem 0.5rem;
  border-radius: var(--badge-radius);
  border: 1px solid var(--color-accent-info-border);
  color: var(--color-accent-info);
  font-size: var(--primitive-fontSize-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* The card is a <button>; its children were <div>s, which is invalid
   inside one and made the browser's own layout unpredictable. They are
   spans now, so the card needs to establish the column itself. */
.choice-card {
  display: flex;
  flex-direction: column;
}

.choice-card__title {
  font-weight: 600;
  margin-bottom: var(--primitive-spacing-2);
}

.choice-card__desc {
  color: var(--color-text-secondary);
  line-height: 1.55;
}

.choice-card__meta {
  margin-top: var(--primitive-spacing-3);
  font-family: var(--font-family-mono);
  font-size: var(--primitive-fontSize-xs);
  color: var(--color-text-muted);
}

.landing__more {
  display: flex;
  flex-direction: column;
  gap: var(--primitive-spacing-3);
  max-width: 72ch;
}

.disclosure {
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--primitive-radius-lg);
  background: var(--color-bg-surface);
}

.disclosure > summary {
  cursor: pointer;
  padding: var(--primitive-spacing-4);
  font-weight: 600;
  /* The default marker is inconsistent across browsers and cannot be
     styled reliably; list-style:none plus an explicit marker is the
     portable route. Keyboard behaviour is unaffected -- <summary> stays
     focusable and Enter/Space still toggle it. */
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--primitive-spacing-2);
}

.disclosure > summary::-webkit-details-marker { display: none; }

.disclosure > summary::before {
  content: "›";
  display: inline-block;
  transition: transform var(--primitive-duration-normal);
  color: var(--color-text-muted);
}

.disclosure[open] > summary::before { transform: rotate(90deg); }

/* Focus must stay visible: the summary is the only way to open this by
   keyboard. */
.disclosure > summary:focus-visible {
  outline: 2px solid var(--color-accent-active-border);
  outline-offset: 2px;
}

.disclosure__body {
  padding: 0 var(--primitive-spacing-4) var(--primitive-spacing-4);
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.disclosure__body p { margin: 0 0 var(--primitive-spacing-3); }
.disclosure__body p:last-child { margin-bottom: 0; }
.disclosure__body ul { padding-left: 1.25rem; margin: 0 0 var(--primitive-spacing-3); }
.disclosure__body li { margin-bottom: 0.35rem; }

.disclosure__actions {
  display: flex;
  gap: var(--primitive-spacing-3);
  flex-wrap: wrap;
  margin: var(--primitive-spacing-4) 0 var(--primitive-spacing-3);
}

.muted-note {
  font-size: var(--primitive-fontSize-sm);
  color: var(--color-text-muted);
}

/* A multi-line variant of the existing .code-block, which is display:flex
   and white-space:pre -- correct for the one-line commands it was built
   for, wrong for a multi-line block, where it would collapse the lines
   onto one row. Only the properties that differ are overridden. */
.code-block--multiline {
  display: block;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.55;
}
