/*
 * NDG Design System — Component Styles
 */

/* ---------------------------------------------------------------------
   Base — only rules Tailwind preflight doesn't cover
   --------------------------------------------------------------------- */
html {
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--text-primary);
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
  scroll-behavior: smooth;
  scroll-padding-top: 80px;
}
body {
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  font-weight: var(--fw-regular);
}
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.tabular { font-variant-numeric: tabular-nums; }

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sharp);
}
.skip {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}
.skip:focus {
  left: 1rem; top: 1rem; width: auto; height: auto;
  background: var(--action-primary); color: #fff;
  padding: 10px 16px; border-radius: var(--radius-sharp); z-index: 1000;
}

/* ---------------------------------------------------------------------
   Prose link fallback

   input.css resets `a` to `color: inherit; text-decoration: none` so that
   nav/card/button links aren't painted browser-blue. The cost is that a
   plain link in running copy renders as body text — invisible as a link.
   This restores it for unclassed links only: anything carrying a class was
   styled deliberately, and :where() keeps the container part at zero
   specificity so every component rule still wins.

   Navigation components are excluded below: the footer columns and the
   NETLAB+ content sidebar are unclassed <li><a> too, and underlining them
   turns tidy link lists into a wall of rules.
   --------------------------------------------------------------------- */
:where(p, li, dd, dt, td, th, blockquote, figcaption) a:not([class]) {
  color: var(--color-link);
  text-decoration: underline;
  text-underline-offset: 2px;
}
:where(p, li, dd, dt, td, th, blockquote, figcaption) a:not([class]):hover {
  color: var(--action-primary-hover);
}
:where(.site-footer, .content-sidebar, .site-nav, .breadcrumb, .dropdown,
       .pagination, .mobile-nav-group) :where(p, li, dd, dt, td, th) a:not([class]) {
  color: inherit;
  text-decoration: none;
}

/* ---------------------------------------------------------------------
   Quote form: collapsible vendor groups + sticky running total
   --------------------------------------------------------------------- */
/* Inline only — see .form-section. Clearing the UA fieldset margin with m-0
   also cleared the block margin from the wrapper's space-y-4, so the five
   vendor groups rendered as one flush stack. */
/* No border reset here: these groups draw a card border through Tailwind
   utilities, and an unlayered `border: 0` would outrank them. */
.quote-group { margin-inline: 0; }
.quote-group-details > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  font-size: var(--fs-base); font-weight: var(--fw-bold);
  color: var(--text-primary);
}
.quote-group-details > summary::-webkit-details-marker { display: none; }
.quote-group-details > summary::after {
  content: "+"; margin-left: auto;
  font-family: var(--font-mono); font-weight: var(--fw-regular);
  color: var(--text-subtle);
}
.quote-group-details[open] > summary::after { content: "\2212"; }
.quote-group-details[open] > summary { border-bottom: 1px solid var(--border-subtle); }
.quote-group-count {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-link-on-light);
  background: var(--surface-callout);
  padding: 2px 8px; border-radius: var(--radius-full);
}
.quote-group-count:empty { display: none; }
.quote-group-details.has-selection > summary { color: var(--text-link-on-light); }

/* Sticky so the total stays visible while you work down the course lists —
   it previously sat several screens below the inputs that change it. */
.quote-total-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-5);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
  box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(4px);
  transition: opacity var(--dur-normal) var(--ease-out),
              transform var(--dur-normal) var(--ease-out);
  pointer-events: none;
}
.quote-total-bar.is-active { opacity: 1; transform: none; }
.quote-total-label {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  text-transform: uppercase; letter-spacing: var(--tracking-wider);
  color: var(--text-on-inverse-muted);
}
.quote-total-value { font-size: var(--fs-xl); font-weight: var(--fw-bold); }

/* Collapsible lab-detail sections (Supported Labs, Using/Enabling the Labs).
   These carry long tables and were the bulk of a lab page's height. */
.content-body .lab-section {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  margin: 0 0 var(--space-4);
}
.content-body .lab-section > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  font-weight: var(--fw-bold); color: var(--text-primary);
  background: var(--surface-raised);
  border-radius: var(--radius-sharp);
}
.content-body .lab-section > summary::-webkit-details-marker { display: none; }
.content-body .lab-section > summary::after {
  content: "+"; font-family: var(--font-mono);
  color: var(--text-subtle); font-weight: var(--fw-regular);
}
.content-body .lab-section[open] > summary {
  border-bottom: 1px solid var(--border-default);
  border-radius: var(--radius-sharp) var(--radius-sharp) 0 0;
}
.content-body .lab-section[open] > summary::after { content: "\2212"; }
.content-body .lab-section-body { padding: var(--space-4); }
.content-body .lab-section-body > :last-child { margin-bottom: 0; }

/* Collapsible documentation groups. The item count on the summary means you
   can judge a section's size before opening it. */
.doc-accordion > details { border-bottom: 1px solid var(--border-default); }
.doc-accordion > details:last-child { border-bottom: 0; }
.doc-accordion > details > summary { padding: var(--space-3) 0; }
.doc-accordion .ndg-list { padding-bottom: var(--space-3); }
.doc-count {
  margin-left: auto; margin-right: var(--space-3);
  font-family: var(--font-mono); font-size: var(--fs-xs);
  font-weight: var(--fw-regular);
  color: var(--text-subtle);
}

/* ---------------------------------------------------------------------
   Legacy document lists (.ndg-list)

   1,500+ uses across the NETLAB+ documentation pages, and no rule anywhere —
   so they fell through to the generic .content-body ul (disc bullets, base
   size) while hand-ported pages on the same screen render the same content as
   a compact icon list. That mismatch is the inconsistent link sizing on the
   docs pages.

   Legacy markup puts the file-type icon *after* the link; ported markup puts
   it first. `order: -1` reconciles the two without touching the templates.

   Scoped carefully: the class is also on 40 <ol> procedures and 155 lists
   containing nested lists. Stripping markers from an ordered list, or setting
   every <li> to flex, destroys those — so the marker reset is <ul>-only and
   the flex/icon-reordering applies only to rows that actually carry an icon.
   --------------------------------------------------------------------- */
ul.ndg-list {
  list-style: none;
  padding-left: 0;
}
.ndg-list {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-sm);
}
.ndg-list li { margin: 0 0 var(--space-2); }

/* Icon-bearing file links only. Legacy markup puts the file-type icon after
   the link; ported pages put it first. order:-1 reconciles the two. */
ul.ndg-list > li:has(> i, > .fa, > .fas, > .far) {
  display: flex; align-items: baseline; gap: 6px;
}
ul.ndg-list > li > i,
ul.ndg-list > li > .fa,
ul.ndg-list > li > .fas,
ul.ndg-list > li > .far {
  order: -1;
  flex-shrink: 0;
  width: 1rem; text-align: center;
  color: var(--text-subtle);
}
ul.ndg-list > li > i.fa-file-pdf { color: var(--status-error-fg); }

/* ---------------------------------------------------------------------
   Small-text floor

   Legacy NETLAB+ pages nest <small> inside copy that is already reduced, so
   the sizes compound down to roughly 10px of "legal type". max() pins a 13px
   floor while still stepping down from normal-size parents.
   --------------------------------------------------------------------- */
:where(.content-body, .legal-doc) small { font-size: max(0.8125rem, 0.9em); }

/* ---------------------------------------------------------------------
   Table baseline

   .content-body and .legal-doc style their tables, but legacy support pages
   emit a bare <table> inside neither wrapper and rendered with no borders at
   all. Scoped to unclassed tables so .compare-table, .table-mono and the
   pricing tables keep their own treatment; :where() zeroes specificity.
   --------------------------------------------------------------------- */
:where(table:not([class])) {
  width: 100%; border-collapse: collapse;
  margin: 0 0 var(--space-4);
  font-size: var(--fs-sm);
}
:where(table:not([class])) th,
:where(table:not([class])) td {
  border: 1px solid var(--border-default);
  padding: 8px 12px; text-align: left; vertical-align: top;
}
:where(table:not([class])) th {
  background: var(--surface-raised);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}

/* ---------------------------------------------------------------------
   Layout primitives
   --------------------------------------------------------------------- */
/* One page width. 6xl is the shell for every page; the wider 7xl is opt-in via
   `container max-w-7xl` and reserved for the two-column sidebar layouts, which
   spend ~360px of it on the sidebar. This default used to be 7xl, so any page
   mixing a bare `.container` with an explicit `max-w-6xl` section — including
   / and /products/ — stepped 128px narrower partway down. */
.container { width: 100%; max-width: var(--max-w-6xl); margin: 0 auto; }
@layer components { .container { padding: 0 var(--space-8); } }
.container-wide { width: 100%; max-width: var(--max-w-7xl); margin: 0 auto; }
@layer components { .container-wide { padding: 0 var(--space-6); } }

/* ---------------------------------------------------------------------
   Theme toggle
   --------------------------------------------------------------------- */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  background: transparent;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-std),
              color var(--dur-fast) var(--ease-std),
              border-color var(--dur-fast) var(--ease-std);
}
.theme-toggle:hover {
  background: var(--surface-callout);
  color: var(--text-link-on-light);
  border-color: var(--action-primary);
}
.theme-toggle .fa-sun { display: none; }
[data-theme="dark"] .theme-toggle .fa-sun { display: inline-block; }
[data-theme="dark"] .theme-toggle .fa-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .fa-sun { display: inline-block; }
  :root:not([data-theme="light"]) .theme-toggle .fa-moon { display: none; }
}

/* ---------------------------------------------------------------------
   Logo / wordmark
   --------------------------------------------------------------------- */
.wordmark {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-display);
  font-weight: var(--fw-extrabold);
  font-size: var(--fs-xl);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  line-height: 1;
}
.wordmark-logo { height: 2em; width: auto; flex-shrink: 0; display: block; }
.wordmark-logo .logo-text { fill: currentColor; }
.wordmark-logo .logo-bar  { fill: var(--action-primary); transform-box: fill-box; transform-origin: bottom; }
.wordmark.on-dark { color: #fff; }
.wordmark.on-dark .logo-bar { fill: var(--color-brand-shimmer); }

/* TEMP logo comparison — footer mark fully in the primary/accent color
   (letters + bars; bars already use the accent by default, so only the letters
   are overridden here). The navbar keeps the split treatment (dark letters,
   accent bars) in the more visible position. Delete this block to restore the
   split-treatment logo in the footer. */
.site-footer .wordmark-logo .logo-text { fill: var(--action-primary); }

/* Bars primitive — used by the logo, loaders, and level indicators.
   Logo SVG order: bar 1 = tallest (x=32.6), bar 4 = shortest (x=0).
   Hover stagger runs shortest→tallest so the bars "build up" left-to-right. */
@keyframes bars-stair-grow {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes bars-stair-loop {
  0%, 100% { transform: scaleY(0.12); }
  40%, 60% { transform: scaleY(1); }
}
/* Hover triggers on the logo itself only — not on a wrapper. Anywhere
   the wordmark appears, hovering it animates the bars. */
.wordmark:hover .logo-bar {
  animation: bars-stair-grow var(--dur-slow) var(--ease-out) both;
}
.wordmark:hover .logo-bar:nth-of-type(4) { animation-delay: 0ms; }
.wordmark:hover .logo-bar:nth-of-type(3) { animation-delay: 70ms; }
.wordmark:hover .logo-bar:nth-of-type(2) { animation-delay: 140ms; }
.wordmark:hover .logo-bar:nth-of-type(1) { animation-delay: 210ms; }
@media (prefers-reduced-motion: reduce) {
  .wordmark:hover .logo-bar { animation: none; }
  html { scroll-behavior: auto; }
}

/* Bars loader — looped variant of the same primitive. Uses explicit
   pixel widths per size so the bars render even outside a sized parent. */
.bars-loader {
  display: inline-flex; align-items: end; gap: 3px;
  width: 27px; height: 24px;
  vertical-align: middle;
  color: var(--text-link-on-light);
}
.bars-loader.is-sm { width: 18px; height: 16px; gap: 2px; }
.bars-loader.is-lg { width: 40px; height: 36px; gap: 5px; }
.bars-loader span {
  display: block; flex: 1;
  background: currentColor; border-radius: 1px;
  transform-origin: bottom;
  animation: bars-stair-loop 1.5s var(--ease-out) infinite both;
}
.bars-loader span:nth-child(1) { height: 25%; animation-delay: 0ms; }
.bars-loader span:nth-child(2) { height: 50%; animation-delay: 100ms; }
.bars-loader span:nth-child(3) { height: 75%; animation-delay: 200ms; }
.bars-loader span:nth-child(4) { height: 100%; animation-delay: 300ms; }
@media (prefers-reduced-motion: reduce) {
  .bars-loader span { animation: none; transform: scaleY(1); }
}

/* Level indicator — static 4-bar primitive mirroring the logo geometry.
   Use .is-active on the first N bars to indicate level. */
.level-bars {
  display: inline-flex; align-items: end; gap: 2px;
  height: 12px; vertical-align: middle;
}
.level-bars span {
  display: block; width: 3px;
  background: var(--border-strong); border-radius: 1px;
}
.level-bars span.is-active { background: var(--action-primary); }
.level-bars span:nth-child(1) { height: 25%; }
.level-bars span:nth-child(2) { height: 50%; }
.level-bars span:nth-child(3) { height: 75%; }
.level-bars span:nth-child(4) { height: 100%; }
.level-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  color: var(--text-secondary);
}
.logo-card {
  padding: var(--space-8);
  border-radius: var(--radius-sharp);
  border: 1px solid var(--border-default);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.logo-card.is-dark { background: var(--surface-inverse); border-color: var(--surface-inverse); color: var(--text-on-inverse); }
.logo-card.is-tint { background: var(--surface-callout); border-color: transparent; }
.logo-card .caption {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  color: var(--text-muted); letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.logo-card.is-dark .caption { color: var(--text-on-inverse-muted); }

/* ---------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 22px;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  line-height: 1;
  letter-spacing: var(--tracking-snug);
  border-radius: var(--radius-full);
  border: 1.5px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-std),
              color var(--dur-fast) var(--ease-std),
              border-color var(--dur-fast) var(--ease-std);
}
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: 0.5; cursor: not-allowed;
}
.btn-primary    { background: var(--action-primary); color: var(--action-primary-text); }
.btn-primary:hover:not(:disabled) { background: var(--action-primary-hover); }
.btn-outline    { background: transparent; color: var(--text-primary); border-color: var(--border-default); }
.btn-outline:hover:not(:disabled) { border-color: var(--action-primary); color: var(--text-link-on-light); }
.btn-ghost      { background: transparent; color: var(--text-link-on-light); padding: 8px 12px; }
.btn-ghost:hover:not(:disabled) { color: var(--action-primary-hover); }
.btn-destructive { background: var(--action-destructive); color: #fff; }
.btn-destructive:hover:not(:disabled) { background: var(--action-destructive-hover); }
.btn-sm  { padding: 10px 18px; font-size: var(--fs-sm); }
.btn-md  { padding: 12px 22px; }
.btn-lg  { padding: 18px 36px; font-size: var(--fs-lg); }
.btn-icon {
  width: 36px; height: 36px; padding: 0; border-radius: 50%;
}
.btn-group {
  display: inline-flex; align-items: center;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full); overflow: hidden;
  background: var(--surface-page);
}
.btn-group > button {
  padding: 8px 14px; font-size: var(--fs-sm);
  background: transparent; color: var(--text-secondary);
  border: 0; cursor: pointer; font-family: inherit;
  transition: background var(--dur-fast) var(--ease-std);
  border-right: 1px solid var(--border-subtle);
}
.btn-group > button:last-child { border-right: 0; }
.btn-group > button.is-active {
  background: var(--surface-raised);
  color: var(--text-primary);
  font-weight: var(--fw-semibold);
}
/* Button loading state — inline bars-loader sized to fit inside a button label. */
.btn-loader {
  display: inline-flex; align-items: end; gap: 2px;
  width: 14px; height: 12px;
  vertical-align: middle;
  color: currentColor;
}
.btn-loader span {
  display: block; flex: 1;
  background: currentColor; border-radius: 1px;
  transform-origin: bottom;
  animation: bars-stair-loop 1.5s var(--ease-out) infinite both;
}
.btn-loader span:nth-child(1) { height: 25%; animation-delay: 0ms; }
.btn-loader span:nth-child(2) { height: 50%; animation-delay: 100ms; }
.btn-loader span:nth-child(3) { height: 75%; animation-delay: 200ms; }
.btn-loader span:nth-child(4) { height: 100%; animation-delay: 300ms; }
@media (prefers-reduced-motion: reduce) {
  .btn-loader span { animation: none; transform: scaleY(1); }
}

/* ---------------------------------------------------------------------
   Form inputs
   --------------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field-label {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-primary); letter-spacing: var(--tracking-snug);
}
.field-hint  { font-size: var(--fs-xs); color: var(--text-muted); }
.field-error { font-size: var(--fs-xs); color: var(--status-error-fg); font-weight: var(--fw-medium); }

/* A grouped block (a fieldset of checkboxes, say) is a section, not another
   field, so the form's base rhythm reads too tight around it.
   margin-inline only: these fieldsets carried Tailwind's m-0 to clear the UA
   2px inline margin, and that also zeroed the block margin the form's
   space-y-* had set — the two groups ended up touching. Extra separation is
   padding for the same reason, so space-y-* keeps owning the block margins. */
.form-section { border: 0; margin-inline: 0; padding: var(--space-3) 0; }

.input, .textarea, .select {
  width: 100%;
  padding: 12px 14px;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--text-primary);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  transition: border-color var(--dur-fast) var(--ease-std),
              box-shadow var(--dur-fast) var(--ease-std);
}
.input::placeholder, .textarea::placeholder { color: var(--text-subtle); }
.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--action-primary);
  box-shadow: 0 0 0 4px var(--surface-tint);
}
.input[aria-invalid="true"] { border-color: var(--status-error-fg); }
.input:disabled { background: var(--surface-raised); color: var(--text-muted); cursor: not-allowed; }
.textarea { min-height: 96px; resize: vertical; line-height: var(--lh-normal); }
.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%236B7689' stroke-width='1.5'%3E%3Cpath d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  padding-right: 36px;
}
.input-search-wrap { position: relative; display: flex; align-items: center; }
.input-search-wrap .icon {
  position: absolute; left: 14px; font-size: 14px;
  color: var(--text-muted); pointer-events: none;
}
.input-search { padding-left: 42px; }

.checkbox, .radio, .switch {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); color: var(--text-primary);
  cursor: pointer;
}
.checkbox input, .radio input { width: 16px; height: 16px; accent-color: var(--action-primary); cursor: pointer; }
.switch {
  --w: 34px; --h: 20px;
}
.switch input {
  appearance: none; width: var(--w); height: var(--h);
  background: var(--border-default); border-radius: var(--radius-full);
  position: relative; cursor: pointer; outline: none; flex-shrink: 0;
  transition: background var(--dur-fast) var(--ease-std);
}
.switch input::before {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; background: #fff; border-radius: 50%;
  transition: transform var(--dur-fast) var(--ease-std);
  box-shadow: var(--shadow-sm);
}
.switch input:checked { background: var(--action-primary); }
.switch input:checked::before { transform: translateX(14px); }

.slider { width: 100%; accent-color: var(--action-primary); }

.file-upload {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 14px 16px;
  border: 1px dashed var(--border-default);
  border-radius: var(--radius-sharp);
  background: var(--surface-raised);
  cursor: pointer;
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.file-upload:hover { border-color: var(--action-primary); color: var(--text-primary); }
.file-upload .icon { font-size: 18px; color: var(--text-link-on-light); flex-shrink: 0; }

/* ---------------------------------------------------------------------
   Badges, pills, chips
   --------------------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 12px;
  background: var(--surface-callout);
  color: var(--text-link-on-light);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  border-radius: var(--radius-full);
}
.badge-vendor { background: var(--surface-inverse); color: #fff; }
.badge-success { background: var(--status-success-bg); color: var(--status-success-text); }
.badge-warning { background: var(--status-warning-bg); color: var(--status-warning-text); }
.badge-error   { background: var(--status-error-bg);   color: var(--status-error-text); }
.badge-neutral { background: var(--surface-sunken); color: var(--text-secondary); }

.pill {
  display: inline-flex; align-items: center;
  padding: 4px 12px;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-snug);
  color: var(--text-link-on-light);
  background: var(--surface-callout);
  border-radius: var(--radius-full);
}

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--text-secondary);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-std),
              color var(--dur-fast) var(--ease-std),
              background var(--dur-fast) var(--ease-std);
}
.chip:hover { border-color: var(--action-primary); color: var(--text-primary); }
.chip.is-active {
  background: var(--action-primary); color: #fff;
  border-color: var(--action-primary); font-weight: var(--fw-bold);
}

/* ---------------------------------------------------------------------
   Cards
   --------------------------------------------------------------------- */
@layer components { .card { padding: var(--space-6); } }
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sharp);
  transition: border-color var(--dur-fast) var(--ease-std),
              background var(--dur-fast) var(--ease-std);
}
.card.is-interactive { cursor: pointer; }
.card.is-interactive:hover { border-color: var(--action-primary); background: var(--surface-tint); }
.card.is-raised { box-shadow: var(--shadow-lg); }
.card.is-tinted { background: var(--surface-tint); border-color: transparent; }

/* Course card — 16:9 header image, body with topic pill / title / desc / meta strip,
   state-dependent footer slot, overlay badges (top-left "New", top-right cert),
   4-bar level indicator. Whole card click via stretched link. */
/* Grid for course and lab cards. The tracks are held near a fixed width
   instead of dividing the container, because the header images are 350x150
   sources: a card that stretches with the viewport upscales them. 349px is
   the largest three-up track in a max-w-6xl container (the image inside the
   1px card borders renders at 347px, within 1% of the source); 352px — the
   exact 1:1 width — drops the grid to two columns. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 349px));
  justify-content: start;
  gap: var(--space-5);
}

.course-card {
  display: flex; flex-direction: column;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  overflow: hidden;
  position: relative;
  transition: border-color var(--dur-fast) var(--ease-std),
              box-shadow var(--dur-fast) var(--ease-std),
              transform var(--dur-fast) var(--ease-std);
}
.course-card:hover {
  border-color: var(--action-primary);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.course-card .card-image {
  position: relative;
  /* Matches the 350x150 header images; 16/7 cropped every card slightly. */
  aspect-ratio: 7 / 3;
  background: var(--surface-callout);
  overflow: hidden;
}
.course-card .card-image img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.course-card .card-image .placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-link-on-light); opacity: 0.55;
}
.course-card .card-image .placeholder i { font-size: 64px; }
.course-card .badge-overlay {
  position: absolute; top: var(--space-3);
  display: inline-flex; align-items: center;
  padding: 4px 10px;
  background: color-mix(in oklab, var(--surface-page) 90%, transparent);
  border-radius: var(--radius-sharp);
  font-size: 11px; font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--text-primary);
  box-shadow: var(--shadow-xs);
  backdrop-filter: blur(4px);
}
.course-card .badge-overlay.is-cert { right: var(--space-3); }
.course-card .card-body {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-4) var(--space-5) var(--space-5);
  flex: 1;
}
.course-card h2, .course-card h3, .course-card h4 {
  font-size: var(--fs-base); font-weight: var(--fw-bold);
  line-height: 1.3; letter-spacing: var(--tracking-snug);
}
.course-card .desc {
  font-size: var(--fs-sm); color: var(--text-secondary);
  line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
}
.course-card .meta-strip {
  display: flex; flex-wrap: wrap; gap: var(--space-3);
  font-size: var(--fs-xs); color: var(--text-muted);
  font-variant-numeric: tabular-nums; font-weight: var(--fw-medium);
}
.course-card .meta-strip span {
  display: inline-flex; align-items: center; gap: 4px;
}
.course-card .meta-strip i {
  font-size: 11px; opacity: 0.85;
}
.course-card .card-footer {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--space-3); margin-top: auto;
  padding-top: var(--space-3);
  font-size: var(--fs-sm);
}
.course-card .price {
  font-weight: var(--fw-bold); color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.course-card .progress-mini {
  display: flex; align-items: center; gap: var(--space-2);
  flex: 1; font-size: var(--fs-xs); color: var(--text-muted);
}
.course-card .progress-mini .bar {
  flex: 1; height: 4px; background: var(--border-subtle);
  border-radius: var(--radius-full); overflow: hidden;
}
.course-card .progress-mini .bar .fill {
  display: block; height: 100%;
  background: var(--action-primary);
}
.course-card a.stretched {
  position: absolute; inset: 0; z-index: 1;
  border-radius: inherit;
}
/* The card clips overflow, so the stretched link's focus shadow is invisible —
   surface keyboard focus on the card itself instead. */
.course-card:focus-within {
  box-shadow: var(--focus-ring);
  border-color: transparent;
}
.course-card a.stretched:focus-visible { outline: none; }

/* Compact card variant — for dense catalogs.
   No image, single-row body, same border/radius/hover treatment. */
.course-card.is-compact { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--space-4); padding: var(--space-3) var(--space-4); }
.course-card.is-compact .card-image { display: none; }
.course-card.is-compact .card-body { padding: 0; gap: 4px; }
.course-card.is-compact .card-body h4 { font-size: var(--fs-sm); }
.course-card.is-compact .meta-strip { font-size: 11px; gap: var(--space-2); }
.course-card.is-compact .card-footer { margin: 0; padding: 0; }


.article-card {
  padding: var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  transition: border-color var(--dur-fast) var(--ease-std), box-shadow var(--dur-fast) var(--ease-std);
}
.article-card:hover { border-color: var(--action-primary); box-shadow: var(--shadow-md); }
.article-card .article-kicker {
  font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold);
  color: var(--text-link-on-light); letter-spacing: var(--tracking-wider);
  text-transform: uppercase; margin-bottom: var(--space-2);
}
.article-card h4 { font-size: var(--fs-xl); font-weight: var(--fw-extrabold); margin-bottom: var(--space-3); }
.article-card p { font-size: var(--fs-base); color: var(--text-secondary); line-height: var(--lh-normal); }
.article-card .byline {
  margin-top: var(--space-4);
  font-size: var(--fs-sm); color: var(--text-muted);
}

.testimonial-card {
  padding: var(--space-8);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
}
.testimonial-card blockquote {
  margin: 0;
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
  color: var(--text-primary);
  letter-spacing: var(--tracking-snug);
  font-weight: var(--fw-semibold);
}
.testimonial-card .cite {
  margin-top: var(--space-5);
  font-size: var(--fs-sm); color: var(--text-muted);
}
.testimonial-card .cite strong { color: var(--text-primary); }

.pricing-card {
  padding: var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.pricing-card.is-recommended {
  background: var(--surface-callout); border-color: var(--action-primary);
}
.pricing-card .tier {
  font-family: var(--font-mono); font-size: 11px; font-weight: var(--fw-bold);
  color: var(--text-link-on-light); letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}
.pricing-card .price {
  font-size: var(--fs-5xl); font-weight: 900; letter-spacing: var(--tracking-tightest);
  color: var(--text-primary); font-variant-numeric: tabular-nums; line-height: 1;
}
.pricing-card .price .unit { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-muted); }
.pricing-card ul {
  list-style: none; padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2);
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.pricing-card ul li {
  display: grid; grid-template-columns: 18px 1fr; gap: 8px;
}
.pricing-card ul li .check { color: var(--text-link-on-light); font-size: 14px; }

/* ---------------------------------------------------------------------
   Tables
   --------------------------------------------------------------------- */
.table {
  width: 100%; border-collapse: collapse;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  overflow: hidden;
  font-size: var(--fs-sm);
}
.table th, .table td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: top;
}
.table tr:last-child th, .table tr:last-child td { border-bottom: 0; }
.table th {
  font-weight: var(--fw-bold);
  color: var(--text-secondary);
  background: var(--surface-raised);
}
.table-striped tbody tr:nth-child(even) { background: var(--surface-raised); }
.table-mono td { font-family: var(--font-mono); color: var(--text-primary); font-variant-numeric: tabular-nums; }

.compare-table {
  width: 100%; border-collapse: collapse;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  overflow: hidden;
  font-size: var(--fs-sm);
}
.compare-table th, .compare-table td {
  padding: 14px 16px; text-align: center;
  border-bottom: 1px solid var(--border-subtle);
}
.compare-table th:first-child, .compare-table td:first-child {
  text-align: left; font-weight: var(--fw-semibold); color: var(--text-primary);
}
.compare-table thead th {
  font-weight: var(--fw-extrabold); color: var(--text-primary);
  background: var(--surface-raised);
}
.compare-table thead .col-recommended {
  background: var(--surface-callout); color: var(--text-link-on-light);
  position: relative;
}
.compare-table tbody .col-recommended { background: var(--surface-tint); }
.compare-table .check { color: var(--text-link-on-light); font-size: 14px; }
.compare-table .dash { color: var(--text-subtle); }

.kv-list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column;
}
.kv-list li {
  display: grid; grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm);
}
.kv-list li:first-child { padding-top: 0; }
.kv-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.kv-list .key { color: var(--text-muted); font-weight: var(--fw-medium); }
.kv-list .val { color: var(--text-primary); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }

dl.defs {
  display: grid; grid-template-columns: minmax(120px, max-content) 1fr;
  font-size: var(--fs-sm); margin: 0;
}
dl.defs dt {
  color: var(--text-muted); font-weight: var(--fw-semibold);
  padding: var(--space-3) var(--space-5) var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
}
dl.defs dd {
  margin: 0; color: var(--text-primary);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
  line-height: var(--lh-normal);
}
dl.defs dt:first-of-type, dl.defs dd:first-of-type { padding-top: 0; }
dl.defs dt:last-of-type, dl.defs dd:last-of-type { border-bottom: 0; padding-bottom: 0; }

.tree { list-style: none; padding-left: 0; font-size: var(--fs-sm); color: var(--text-secondary); }
.tree ul { list-style: none; padding-left: var(--space-6); border-left: 1px dashed var(--border-default); margin-left: 8px; }
.tree li { padding: 4px 0; }
.tree .tree-folder { font-weight: var(--fw-semibold); color: var(--text-primary); }

/* ---------------------------------------------------------------------
   Status / feedback
   --------------------------------------------------------------------- */
.banner {
  display: grid; grid-template-columns: auto 1fr auto;
  gap: var(--space-3); align-items: start;
  padding: 14px 18px;
  border-radius: var(--radius-sharp);
  border: 1px solid transparent;
  font-size: var(--fs-sm);
}
.banner .b-icon { font-size: 18px; margin-top: 1px; flex-shrink: 0; }
.banner .b-title { font-weight: var(--fw-bold); color: var(--text-primary); margin-bottom: 2px; }
.banner .b-text { color: var(--text-secondary); }
.banner-info    { background: var(--surface-callout); border-color: color-mix(in oklab, var(--action-primary) 25%, transparent); }
.banner-info .b-icon    { color: var(--text-link-on-light); }
.banner-success { background: var(--status-success-bg); border-color: var(--status-success-border); }
.banner-success .b-icon { color: var(--status-success-fg); }
.banner-warning { background: var(--status-warning-bg); border-color: var(--status-warning-border); }
.banner-warning .b-icon { color: var(--status-warning-fg); }
.banner-error   { background: var(--status-error-bg);   border-color: var(--status-error-border); }
.banner-error   .b-icon { color: var(--status-error-fg); }

.toast {
  display: grid; grid-template-columns: auto 1fr auto;
  gap: var(--space-3); align-items: center;
  padding: 12px 16px;
  background: var(--surface-inverse); color: var(--text-on-inverse);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm);
  max-width: 380px;
}
.toast .t-icon { font-size: 18px; color: var(--color-brand-shimmer); }
.toast .t-close { color: var(--text-on-inverse-muted); background: transparent; border: 0; cursor: pointer; padding: 4px; }

.progress-linear {
  height: 8px; width: 100%;
  background: var(--surface-sunken);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.progress-linear .fill {
  height: 100%;
  background: var(--action-primary);
  border-radius: var(--radius-full);
  transition: width var(--dur-normal) var(--ease-std);
}
.skeleton {
  background: linear-gradient(90deg, var(--surface-raised) 0%, var(--surface-sunken) 50%, var(--surface-raised) 100%);
  background-size: 200% 100%;
  animation: skel 1.4s ease-in-out infinite;
  border-radius: var(--radius-sharp);
}
@keyframes skel { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.skeleton-line { height: 12px; }
.skeleton-block { height: 96px; }

.empty-state {
  padding: var(--space-12);
  text-align: center;
  border: 1px dashed var(--border-default);
  border-radius: var(--radius-sharp);
  background: var(--surface-raised);
}
.empty-state h2, .empty-state h3, .empty-state h4 { font-size: var(--fs-lg); font-weight: var(--fw-extrabold); margin-bottom: var(--space-2); }
.empty-state p { color: var(--text-muted); font-size: var(--fs-sm); margin-bottom: var(--space-5); }

/* ---------------------------------------------------------------------
   Overlays
   --------------------------------------------------------------------- */
.modal {
  width: 100%; max-width: 480px;
  background: var(--surface-page);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-2xl);
  overflow: hidden;
}
.modal-head {
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: space-between;
}
.modal-head h3 { font-size: var(--fs-lg); }
.modal-body { padding: var(--space-6); font-size: var(--fs-sm); color: var(--text-secondary); }
.modal-foot {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--border-subtle);
  display: flex; justify-content: flex-end; gap: var(--space-3);
  background: var(--surface-raised);
}

.drawer {
  width: 100%; max-width: 380px;
  background: var(--surface-page);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-2xl);
  overflow: hidden;
  margin-left: auto;
}
.drawer-head { padding: var(--space-5) var(--space-6); border-bottom: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: space-between; }
.drawer-body { padding: var(--space-6); font-size: var(--fs-sm); color: var(--text-secondary); }

.tooltip {
  display: inline-block;
  padding: 6px 10px;
  background: var(--surface-inverse); color: var(--text-on-inverse);
  border-radius: 6px;
  font-size: var(--fs-xs); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-snug);
}
.popover {
  max-width: 280px;
  padding: var(--space-4);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.popover .pop-title { font-weight: var(--fw-bold); color: var(--text-primary); margin-bottom: 4px; }
.dropdown {
  min-width: 200px;
  padding: 6px;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-lg);
}
.dropdown a {
  display: block;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: var(--fs-sm); color: var(--text-secondary);
  /* Panel sizes to its longest label; wrapped nav items read as two rows. */
  white-space: nowrap;
}
.dropdown a:hover { background: var(--surface-callout); color: var(--text-primary); }
.dropdown hr { border: 0; border-top: 1px solid var(--border-subtle); margin: 6px 0; }
/* Product grouping inside a panel that spans both products. */
.dropdown-heading {
  padding: 6px 12px 2px;
  font-family: var(--font-mono);
  font-size: 10px; font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-widest); text-transform: uppercase;
  color: var(--text-subtle);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------
   Navigation patterns
   --------------------------------------------------------------------- */
.site-header {
  background: color-mix(in oklab, var(--surface-page) 92%, transparent);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--border-default);
}
.site-header-inner {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: var(--space-8);
  padding: var(--space-4) var(--space-8);
}
.site-nav { display: flex; align-items: center; gap: var(--space-8); flex: 1; min-width: 0; }
.site-nav a {
  color: var(--text-muted); font-weight: var(--fw-medium); font-size: var(--fs-base);
}
.site-nav a:hover { color: var(--text-primary); }
/* Current page: color plus a non-color cue (WCAG 1.4.1). */
.site-nav a.is-active {
  color: var(--text-link-on-light);
  text-decoration: underline;
  text-underline-offset: 6px;
  text-decoration-thickness: 2px;
}
.header-search {
  position: relative; flex: 1; min-width: 120px; max-width: 360px;
}
.header-search i {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  font-size: 14px; color: var(--text-muted); pointer-events: none;
}
.header-search input {
  width: 100%; padding: 8px 12px 8px 36px;
  border: 1px solid var(--border-default); border-radius: var(--radius-sharp);
  background: var(--surface-page);
  font-family: inherit; font-size: var(--fs-sm); color: var(--text-primary);
}
.header-search input:focus-visible {
  outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring);
}

.breadcrumb {
  font-size: var(--fs-sm); color: var(--text-muted);
}
.breadcrumb ol {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  list-style: none; padding: 0;
}
.breadcrumb li::after { content: "/"; margin-left: 8px; color: var(--text-subtle); }
.breadcrumb li:last-child::after { content: ""; }
.breadcrumb a { color: var(--text-muted); }
.breadcrumb a:hover { color: var(--text-link-on-light); }
.breadcrumb li:last-child { color: var(--text-primary); font-weight: var(--fw-semibold); }

.pagination { display: inline-flex; align-items: center; gap: 4px; }
.pagination a, .pagination span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px;
  padding: 0 10px;
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--text-secondary);
  border-radius: var(--radius-sharp);
}
.pagination a:hover { background: var(--surface-callout); color: var(--text-link-on-light); }
.pagination .is-active { background: var(--action-primary); color: #fff; }
.pagination .is-disabled { color: var(--text-subtle); pointer-events: none; }

.stepper {
  display: flex; flex-wrap: wrap;
  gap: var(--space-3);
  counter-reset: step;
  list-style: none; padding: 0; margin: 0;
}
.step {
  flex: 1 1 200px;
  display: flex; flex-direction: column; gap: 6px;
  padding: var(--space-4);
  border-top: 3px solid var(--border-default);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.step .step-num {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-wider); text-transform: uppercase;
  color: var(--text-muted); font-weight: var(--fw-bold);
}
.step .step-title { font-weight: var(--fw-bold); color: var(--text-primary); font-size: var(--fs-base); }
.step.is-complete { border-top-color: var(--action-primary); }
.step.is-complete .step-num { color: var(--text-link-on-light); }
.step.is-current { border-top-color: var(--action-primary); }
.step.is-current .step-title { color: var(--text-link-on-light); }

.tabs {
  display: flex; gap: var(--space-2);
  border-bottom: 1px solid var(--border-default);
}
.tab {
  padding: 12px 16px;
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  border: 0; background: transparent;
  cursor: pointer; font-family: inherit;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab:hover { color: var(--text-primary); }
.tab.is-active {
  color: var(--text-link-on-light);
  border-bottom-color: var(--action-primary);
}

.accordion details {
  padding: var(--space-5) var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  margin-bottom: var(--space-2);
}
/* Default disclosure affordance for bare <details> in page bodies — the
   native marker is suppressed globally (input.css), and styled components
   (.accordion +/−, .content-sidebar chevron, .prose-section) override this
   zero-specificity default with their own indicators. */
:where(details) > :where(summary) { cursor: pointer; }
:where(details) > :where(summary)::after {
  content: "\203A";
  display: inline-block; margin-left: 8px;
  color: var(--text-subtle);
  transition: transform var(--dur-fast) var(--ease-std);
}
:where(details[open]) > :where(summary)::after { transform: rotate(90deg); }
/* Components whose summaries carry their own chevron/plus icon opt out */
summary:has(i[class*="fa-chevron"])::after,
summary:has(i[class*="fa-angle"])::after,
.outline-section > summary::after,
.accordion-card > summary::after { content: none; }
@media (prefers-reduced-motion: reduce) {
  :where(details) > :where(summary)::after { transition: none; }
}

.accordion summary {
  list-style: none;
  cursor: pointer;
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--fs-base); font-weight: var(--fw-bold);
  color: var(--text-primary);
}
.accordion summary::-webkit-details-marker { display: none; }
.accordion summary::after {
  content: "+";
  font-family: var(--font-mono); font-size: var(--fs-xl);
  font-weight: var(--fw-bold); color: var(--text-link-on-light);
}
.accordion details[open] summary::after { content: "\2212"; }
.accordion details p {
  margin-top: var(--space-3);
  color: var(--text-secondary); font-size: var(--fs-base);
  line-height: var(--lh-normal);
}
.accordion .faq-link { font-size: var(--fs-sm); }
.accordion .faq-link a { color: var(--text-link-on-light); }

.toc {
  padding: var(--space-5);
  background: var(--surface-raised);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-sm);
}
.toc h5 {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: var(--tracking-wider); text-transform: uppercase;
  color: var(--text-muted); font-weight: var(--fw-bold);
  margin: 0 0 var(--space-3);
}
.toc ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.toc a { color: var(--text-secondary); }
.toc a:hover { color: var(--text-link-on-light); }
.toc .is-active { color: var(--text-link-on-light); font-weight: var(--fw-semibold); }

.sidebar {
  padding: var(--space-5);
  background: var(--surface-raised);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sharp);
  min-height: 260px;
}
.sidebar h5 {
  font-size: var(--fs-sm); font-weight: var(--fw-bold);
  margin-bottom: var(--space-3); letter-spacing: var(--tracking-snug);
}
.sidebar nav { display: flex; flex-direction: column; gap: 4px; }
.sidebar nav a {
  padding: 8px 12px; border-radius: var(--radius-sharp);
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.sidebar nav a:hover { background: var(--surface-page); color: var(--text-primary); }
.sidebar nav a.is-active { background: var(--surface-callout); color: var(--text-link-on-light); font-weight: var(--fw-semibold); }

/* ---------------------------------------------------------------------
   Layout patterns
   --------------------------------------------------------------------- */
.hero {
  padding: 10rem var(--space-6) 8rem;
  background: var(--surface-page);
  text-align: center;
}
.hero h1 {
  font-size: var(--fs-7xl); line-height: 1.02;
  letter-spacing: var(--tracking-tightest);
  font-weight: var(--fw-extrabold);
  max-width: 52rem; margin: 0 auto var(--space-8);
}
.beat-2 {
  display: block; font-weight: var(--fw-regular); color: var(--text-secondary);
}
.hero .hero-ctas { display: flex; gap: var(--space-4); justify-content: center; flex-wrap: wrap; }

/* Campaign variant — a full-bleed dark gradient band. This is the only part
   of a campaign landing page the rest of the site had no equivalent for, and
   the only reason static/css/landing.css existed; everything else on those
   pages now uses the shared components.

   --campaign-accent tints the gradient. A new campaign page is on-brand with
   no CSS at all; give one its own colour by adding a theme class below.

   The default is a var() fallback, not a declaration on this rule: declaring
   it here would mean the element that consumes the variable also sets it, at
   a higher specificity than any single-class theme, so .theme-* could never
   win and every campaign would render brand blue. */
.hero.is-campaign {
  position: relative;
  overflow: hidden;
  padding: var(--space-20) var(--space-6) var(--space-16);
  color: var(--text-on-inverse);
  background: linear-gradient(125deg,
    var(--color-brand-primary-dark) 0%,
    var(--color-brand-primary) 45%,
    var(--campaign-accent, var(--color-brand-accent)) 130%);
}
.hero.is-campaign::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle at 82% 18%, rgba(255,255,255,0.14), transparent 46%);
}
.hero.is-campaign > * { position: relative; z-index: 1; }
.hero.is-campaign h1 { color: var(--text-on-inverse); font-size: var(--fs-6xl); }
.hero.is-campaign .hero-sub {
  max-width: 48rem; margin: 0 auto var(--space-4);
  font-size: var(--fs-xl); color: var(--text-on-inverse);
}
.hero.is-campaign .hero-lead {
  max-width: 42rem; margin: 0 auto var(--space-8);
  color: var(--text-on-inverse-muted);
}

/* Buttons invert on the dark band: solid white primary, hairline ghost. */
.hero.is-campaign .btn-primary { background: #fff; color: var(--color-brand-primary); }
.hero.is-campaign .btn-primary:hover:not(:disabled) { background: var(--color-brand-shimmer); color: var(--color-brand-primary-dark); }
/* Any dark surface, not just the hero: .btn-outline's resting colour is
   --text-primary, which on .callout.is-dark is the same #1a2332 as the
   background — the secondary CTA label rendered invisible at 1:1 contrast. */
.hero.is-campaign .btn-outline,
.callout.is-dark .btn-outline { color: #fff; border-color: rgba(255,255,255,0.6); }
.hero.is-campaign .btn-outline:hover:not(:disabled),
.callout.is-dark .btn-outline:hover:not(:disabled) { background: rgba(255,255,255,0.12); border-color: #fff; color: #fff; }

/* Inline document link under the CTAs. */
.hero.is-campaign .hero-doc {
  display: inline-block; margin-top: var(--space-4);
  font-size: var(--fs-sm); color: var(--color-brand-shimmer);
  text-decoration: underline; text-underline-offset: 3px;
}
.hero.is-campaign .hero-doc:hover { color: #fff; }
.hero.is-campaign .hero-doc i { margin-right: 6px; }

/* At-a-glance facts strip. */
.hero-meta {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--space-3) var(--space-6);
  margin-top: var(--space-8);
  font-size: var(--fs-sm); color: var(--text-on-inverse-muted);
}
.hero-meta span { display: inline-flex; align-items: center; gap: 7px; }
.hero-meta i { color: var(--color-brand-shimmer); }

/* Per-campaign accents. One line each; nothing else may be themed here. */
.theme-proxmox { --campaign-accent: #E57000; }

@media (max-width: 720px) {
  .hero.is-campaign { padding: var(--space-12) var(--space-4) var(--space-10); }
  .hero.is-campaign h1 { font-size: var(--fs-4xl); }
}

/* Event detail rows — label/value facts for a dated event page (workshop,
   webinar): dates, time, cost, who it's for. */
.event-details {
  max-width: 820px; margin: 0 auto;
  padding: var(--space-1) var(--space-6);
  background: var(--surface-callout);
  border-left: 4px solid var(--color-brand-accent);
  border-radius: 0 var(--radius-sharp) var(--radius-sharp) 0;
}
.event-details .event-row { display: flex; flex-wrap: wrap; padding: var(--space-4) 0; }
.event-details .event-row + .event-row { border-top: 1px solid var(--border-subtle); }
.event-details .event-label {
  flex: 0 0 150px;
  font-family: var(--font-mono); font-size: 11px; line-height: 24px;
  font-weight: var(--fw-bold); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text-link-on-light);
}
.event-details .event-val { flex: 1 1 280px; font-size: var(--fs-sm); line-height: 24px; color: var(--text-primary); }
/* .event-val is a div, so the unclassed-prose link fallback (p/li/td/…)
   doesn't reach it. Underline carries the affordance with inherited colour;
   a hover colour would need a token that works on the callout surface in
   both themes, which --action-primary-hover is not. */
.event-details .event-val a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.event-details .event-val a:hover { text-decoration-thickness: 2px; }
@media (max-width: 720px) {
  .event-details { padding: var(--space-1) var(--space-5); }
  .event-details .event-label { flex: 0 0 100%; margin-bottom: 2px; }
}

/* Course outline — one section per content type. Sections collapsible
   via accordion primitive; items inside are a flat list, no per-item
   dropdown nesting. */
.course-outline {
  display: flex; flex-direction: column;
  gap: var(--space-3);
}
.outline-section {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  overflow: hidden;
  background: var(--surface-page);
}
.outline-section > summary {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  cursor: pointer;
  background: var(--surface-raised);
  list-style: none;
  transition: background var(--dur-fast) var(--ease-std);
}
.outline-section > summary::-webkit-details-marker { display: none; }
.outline-section > summary:hover { background: var(--surface-callout); }
.outline-section[open] > summary { border-bottom: 1px solid var(--border-subtle); }
.outline-section .outline-type {
  flex: 1;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
}
.outline-section .outline-meta {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}
.outline-chevron {
  font-size: 14px;
  color: var(--text-muted);
  flex-shrink: 0;
  transition: transform var(--dur-normal) var(--ease-std);
  display: inline-block;
}
.outline-section[open] .outline-chevron { transform: rotate(180deg); }
.outline-items { display: flex; flex-direction: column; }
.outline-item {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}
.outline-item:last-child { border-bottom: none; }
.outline-item:nth-child(even) { background: var(--surface-raised); }
.outline-item-title {
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  line-height: 1.4;
}
.outline-item-desc {
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  line-height: 1.55;
}

/* Collapsible prose sections (Course outline, Certification, Resources) —
   match the FAQ accordion box so the toggle clearly reads as a button. */
.prose-section {
  padding: var(--space-5) var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
}
.prose-section > summary {
  display: flex; align-items: center; gap: var(--space-3);
  cursor: pointer; list-style: none;
}
.prose-section > summary::-webkit-details-marker { display: none; }
.prose-section .prose-section-title {
  flex: 1; margin: 0;
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
}
.prose-section .prose-section-meta {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-weight: var(--fw-medium);
}
.prose-section > summary::after {
  content: "+";
  font-family: var(--font-mono); font-size: var(--fs-xl);
  font-weight: var(--fw-bold); color: var(--text-link-on-light);
  line-height: 1;
}
.prose-section[open] > summary::after { content: "\2212"; }
/* Course-outline modules sit flush inside the box — no card-in-card. */
.prose-section .course-outline { gap: 0; }
.prose-section .course-outline .outline-section { border: 0; border-radius: 0; }
.prose-section .course-outline .outline-section + .outline-section { border-top: 1px solid var(--border-subtle); }
.prose-section .course-outline .outline-section > summary { background: transparent; padding-inline: 0; }
.prose-section .course-outline .outline-section > summary:hover { background: transparent; }
.prose-section .course-outline .outline-item { padding-inline: 0; }

/* Certification mark grid — small mark + cert name pair, grid-able. */
.cert-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-3);
}
.cert-item {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  background: var(--surface-page);
  transition: border-color var(--dur-fast) var(--ease-std), background var(--dur-fast) var(--ease-std);
  color: inherit;
}
.cert-item:hover { border-color: var(--action-primary); background: var(--surface-tint); }
.cert-item .cert-mark {
  flex-shrink: 0; width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-callout);
  border-radius: var(--radius-sharp);
  color: var(--text-link-on-light);
}
/* Bars mark — 4 ascending bars echoing the logo geometry */
.cert-mark-bars {
  display: inline-flex; align-items: end; gap: 2px;
  height: 18px;
}
.cert-mark-bars span {
  display: block; width: 3px; border-radius: 1px;
  background: var(--action-primary);
}
.cert-mark-bars span:nth-child(1) { height: 25%; }
.cert-mark-bars span:nth-child(2) { height: 50%; }
.cert-mark-bars span:nth-child(3) { height: 75%; }
.cert-mark-bars span:nth-child(4) { height: 100%; }
.cert-item:hover .cert-mark { background: var(--action-primary); }
.cert-item:hover .cert-mark-bars span { background: #fff; }
.cert-item .cert-stack { display: flex; flex-direction: column; line-height: 1.3; }
.cert-item .cert-name {
  font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.cert-item .cert-sub {
  font-size: var(--fs-xs); color: var(--text-muted);
}

/* Social-proof line — single statement with named examples, no logos. */
.social-proof {
  font-size: var(--fs-lg);
  color: var(--text-secondary);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  max-width: 56rem;
}
.social-proof strong {
  color: var(--text-primary); font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.social-proof a {
  color: var(--text-link-on-light); font-weight: var(--fw-semibold);
  border-bottom: 1px solid currentColor;
}

/* Newsletter signup — inline + stacked variants. */
.newsletter {
  padding: var(--space-6);
  background: var(--surface-callout);
  border-radius: var(--radius-sharp);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.newsletter h4 { font-size: var(--fs-lg); }
.newsletter p { font-size: var(--fs-sm); color: var(--text-secondary); }
.newsletter form {
  display: flex; gap: var(--space-2); align-items: stretch;
  flex-wrap: wrap;
}
.newsletter input[type="email"] {
  flex: 1; min-width: 240px;
  padding: 10px 14px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  background: var(--surface-page);
  font-family: inherit; font-size: var(--fs-sm);
  color: var(--text-primary);
}
.newsletter input[type="email"]:focus-visible {
  outline: none; border-color: var(--border-focus);
  box-shadow: var(--focus-ring);
}
.newsletter.is-inline {
  background: transparent; padding: 0;
  flex-direction: row; align-items: center; gap: var(--space-3);
  flex-wrap: wrap;
}
.newsletter.is-inline .copy { flex: 1; min-width: 220px; }
.newsletter.is-inline .copy h4 { font-size: var(--fs-base); }
.newsletter.is-inline .copy p { font-size: var(--fs-xs); margin-top: 2px; }
.newsletter.is-inline form { flex: 0 1 auto; }

/* Cookie consent banner — sticky-bottom-of-page style; dark surface. */
/* Bottom-left dock, matching the position the previous consent library used.
   Sits above page content but below the header dropdowns. */
.cookie-consent-dock {
  position: fixed; z-index: 900;
  left: var(--space-4); bottom: var(--space-4);
  width: min(30rem, calc(100vw - var(--space-8)));
}
.cookie-consent {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-sm);
  box-shadow: var(--shadow-lg);
}
.cookie-consent p { margin: 0; flex: 1; min-width: 280px; line-height: 1.5; }
/* At 320px the dock's content box is only ~248px after margins and padding,
   so the 280px floor forces horizontal overflow. */
@media (max-width: 400px) {
  .cookie-consent p { min-width: 0; }
  .cookie-consent .actions { width: 100%; }
}
.cookie-consent a { color: var(--text-link-on-dark); text-decoration: underline; }
.cookie-consent .actions { display: flex; gap: var(--space-2); flex-shrink: 0; }
.cookie-consent .btn-ghost {
  background: transparent; color: var(--text-on-inverse);
  border: 1px solid rgba(255,255,255,0.3); padding: 8px 16px;
  font-size: var(--fs-sm); border-radius: var(--radius-sharp);
  font-weight: var(--fw-semibold); cursor: pointer;
  font-family: inherit;
}
.cookie-consent .btn-ghost:hover { border-color: rgba(255,255,255,0.6); }

/* Links that rely on the text-link color inside prose must carry a
   non-color cue at rest (WCAG 1.4.1) — underline them always. */
a.text-link { text-decoration: underline; text-underline-offset: 2px; }

/* .container is unlayered and would override Tailwind's layered max-w-*
   utilities on "container max-w-*" wrappers — restate the caps explicitly. */
.container.max-w-2xl { max-width: 42rem; }
.container.max-w-3xl { max-width: 48rem; }
.container.max-w-4xl { max-width: 56rem; }
.container.max-w-5xl { max-width: 64rem; }
.container.max-w-6xl { max-width: 72rem; }
.container.max-w-7xl { max-width: 80rem; }

/* ---------------------------------------------------------------------
   NETLAB+ content-tree layout — vendor sidebar + prose page body.
   Replaces the legacy Bootstrap list-group/collapse wrappers under
   layout/content/. Page bodies keep the {% block page %} contract.
   ------------------------------------------------------------------ */
.content-layout {
  display: grid; grid-template-columns: 240px minmax(0, 1fr);
  gap: var(--space-8); align-items: start;
  max-width: var(--max-w-7xl); margin: 0 auto;
  padding: var(--space-8) var(--space-6) var(--space-16);
}
.content-sidebar {
  position: sticky; top: 88px;
  border: 1px solid var(--border-default); border-radius: var(--radius-sharp);
  background: var(--card-bg);
  padding: var(--space-4);
  font-size: var(--fs-sm);
}
.content-sidebar .sidebar-logo { display: block; max-width: 180px; margin: 0 auto var(--space-4); }
.content-sidebar .sidebar-title {
  font-weight: var(--fw-bold); color: var(--text-primary);
  margin: 0 0 var(--space-2); font-size: var(--fs-sm);
}
.content-sidebar a { display: block; padding: 5px 8px; color: var(--text-secondary); border-radius: 4px; }
.content-sidebar a:hover { background: var(--surface-callout); color: var(--text-link-on-light); }
.content-sidebar a.is-active { color: var(--text-link-on-light); font-weight: var(--fw-semibold); }
.content-sidebar details { margin: 0; }
.content-sidebar summary {
  cursor: pointer; padding: 5px 8px; border-radius: 4px;
  color: var(--text-primary); font-weight: var(--fw-semibold);
  list-style: none; display: flex; align-items: center; justify-content: space-between;
}
.content-sidebar summary::-webkit-details-marker { display: none; }
.content-sidebar summary::after { content: "\203A"; transition: transform var(--dur-fast) var(--ease-std); color: var(--text-subtle); }
.content-sidebar details[open] > summary::after { transform: rotate(90deg); }
.content-sidebar summary:hover { background: var(--surface-callout); }
.content-sidebar ul { list-style: none; margin: 0; padding: 0 0 0 var(--space-3); }
.content-sidebar details details { padding-left: var(--space-2); }
@media (prefers-reduced-motion: reduce) {
  .content-sidebar summary::after { transition: none; }
}
.content-page-title {
  max-width: var(--max-w-7xl); margin: 0 auto;
  padding: var(--space-6) var(--space-6) 0;
  font-family: var(--font-display);
  font-size: var(--fs-2xl); font-weight: var(--fw-bold);
  color: var(--text-primary); letter-spacing: var(--tracking-tight);
}
/* pages that ship their own <h1> in pagetitle get the same look, unnested */
.content-page-title h1 { font: inherit; color: inherit; letter-spacing: inherit; margin: 0; }

/* Breadcrumb trail — pages emit <ol class="breadcrumb"> in the pagetitle block */
.content-breadcrumb .breadcrumb {
  display: flex; flex-wrap: wrap; gap: 6px;
  list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
}
.content-breadcrumb .breadcrumb li + li::before { content: "/"; margin-right: 6px; color: var(--text-subtle); }
.content-breadcrumb .breadcrumb a { color: var(--text-muted); }
.content-breadcrumb .breadcrumb a:hover { color: var(--text-link-on-light); }
/* Prose defaults for legacy content bodies riding the new stack */
.content-body { color: var(--text-secondary); line-height: 1.6; }
.content-body h1, .content-body h2, .content-body h3, .content-body h4 {
  color: var(--text-primary); font-weight: var(--fw-bold);
  font-size: var(--fs-lg); margin: var(--space-8) 0 var(--space-3);
}
.content-body > :first-child, .content-body .card-block > :first-child { margin-top: 0; }
.content-body p { margin: 0 0 var(--space-4); }
.content-body ul { list-style: disc; margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.content-body ol { list-style: decimal; margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.content-body li { margin: var(--space-1) 0; }
/* :not(.btn) — a prose-link rule outranks .btn-primary on specificity and
   would otherwise repaint button labels link-blue on a blue fill. */
.content-body a:not(.btn) { color: var(--text-link-on-light); text-decoration: underline; }
.content-body img { max-width: 100%; height: auto; }
.content-body pre {
  overflow-x: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border-default); border-radius: var(--radius-sharp);
  padding: var(--space-4);
  font-size: var(--fs-sm); line-height: 1.5;
  margin: 0 0 var(--space-4);
}
.content-body table { width: 100%; border-collapse: collapse; margin: 0 0 var(--space-4); font-size: var(--fs-sm); }
.content-body th, .content-body td { border: 1px solid var(--border-default); padding: 8px 12px; text-align: left; vertical-align: top; }
.content-body th { background: var(--surface-raised); color: var(--text-primary); }
.content-body .bg-warning {
  display: block; border: 1px solid var(--status-warning-border, var(--border-default));
  background: var(--status-warning-bg); color: var(--status-warning-text);
  border-radius: var(--radius-sharp); padding: var(--space-4); margin: 0 0 var(--space-4);
}
.content-body .text-danger { color: var(--status-error-text); } /* darker than -fg: passes 4.5:1 as body text */

/* Legacy bootstrap-era status classes still emitted by the app.py
   requirements helper (enroll-card links, outside .content-body) —
   global, theme-aware compat. Links keep an underline: color alone
   must not be the only affordance. */
.text-warning { color: var(--status-warning-text); }
.text-danger { color: var(--status-error-text); }
a.text-warning, a.text-danger { text-decoration: underline; }
.content-body .img-responsive { display: block; max-width: 100%; height: auto; }
.content-body .center-block { margin-left: auto; margin-right: auto; }
/* Legacy Webflow open/close toggles degrade to always-open sections: the
   inert header link becomes a plain heading (its +/- icon hidden). */
.content-body .toggle-wrapper { border: 1px solid var(--border-default); border-radius: var(--radius-sharp); margin: 0 0 var(--space-4); }
.content-body .toggle-header { display: block; padding: var(--space-3) var(--space-4); font-weight: var(--fw-bold); color: var(--text-primary); text-decoration: none; pointer-events: none; background: var(--surface-raised); }
.content-body .toggle-header .toggle-ico { display: none; }
.content-body .toggle-content { padding: var(--space-4); }

/* Legacy Webflow carousels. Their JS never loads on the new stack, so the
   dead arrow/dot chrome is hidden and the slides become a plain list.

   These "portfolio cards" wrapped a generic stock image, an inert overlay
   link (aria-hidden, tabindex="-1") and the real title link. The image is the
   same handful of vendor photos reused across every lab, so it carried no
   information while dominating the page — 49 templates' worth of visual
   noise. Only the title link says anything, so that is all that renders now.
   Done in CSS rather than across 49 templates of hand-written Webflow markup. */
.content-body .w-slider-mask,
.content-body .w-slide { display: block; position: static; width: auto; }
.content-body .w-slider-arrow-left, .content-body .w-slider-arrow-right,
.content-body .w-slider-nav,
.content-body .portfolio-overlay,
.content-body .portfolio-wrapper { display: none; }
.content-body article.mix { max-width: none; margin: 0; }
.content-body .portfolio-text-wrapper {
  display: flex; align-items: baseline; gap: var(--space-2);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border-subtle);
  text-decoration: none;
}
.content-body .portfolio-text-wrapper::before {
  content: "\f0f6";  /* fa-file-lines */
  font: var(--fa-font-regular, normal 400 1em/1 "Font Awesome 6 Free");
  color: var(--text-subtle); flex-shrink: 0;
}
.content-body .portfolio-text-wrapper:hover { background: var(--surface-raised); }
.content-body .portfolio-tittle {
  margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-semibold);
  color: var(--text-link-on-light); text-decoration: underline;
}

/* Legacy Webflow grids in content bodies keep a side-by-side layout */
.content-body .w-row { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; }
.content-body .w-row > [class*="w-col"] { flex: 1 1 220px; min-width: 0; }
/* Legacy Bootstrap grids (thumbnail galleries etc.) get the same treatment */
.content-body .row { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; }
.content-body .row > [class*="col-"] { flex: 1 1 160px; min-width: 0; }
.content-body .table-responsive { overflow-x: auto; }
.content-body .well {
  border: 1px solid var(--border-default); border-radius: var(--radius-sharp);
  background: var(--card-bg); padding: var(--space-6); margin: 0 0 var(--space-6);
}
@media (max-width: 960px) {
  .content-layout { grid-template-columns: 1fr; }
  .content-sidebar { position: static; }
}

/* Attachment list for the vanilla support-form uploader (ndg-upload.js) */
.upload-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.upload-item {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); color: var(--text-secondary);
  padding: 4px 0;
}
.upload-item.is-error { color: var(--status-error-fg); }
.upload-remove {
  border: 0; background: none; cursor: pointer;
  color: var(--text-muted); font-size: var(--fs-lg); line-height: 1;
  padding: 0 4px;
}
.upload-remove:hover { color: var(--status-error-fg); }

.trust-strip {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
  padding: var(--space-12) var(--space-6);
}
.trust-strip--4 { grid-template-columns: repeat(4, 1fr); }
.trust-stat { display: flex; flex-direction: column; gap: 4px; text-align: center; }
.trust-stat .num {
  font-size: var(--fs-5xl); font-weight: 900;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
  letter-spacing: var(--tracking-tight); line-height: 1;
}
.trust-stat .label {
  font-size: var(--fs-base); color: var(--text-muted); font-weight: var(--fw-medium);
}

.step-rows { display: flex; flex-direction: column; }
.step-row {
  display: grid; grid-template-columns: 80px 1fr;
  gap: var(--space-8);
  padding: var(--space-6) var(--space-6);
  align-items: start;
  border-radius: var(--radius-sharp);
}
.step-row:nth-child(odd) { background: var(--surface-callout); }
.step-row .row-num {
  font-size: var(--fs-5xl); font-weight: 900;
  color: var(--text-link-on-light); font-variant-numeric: tabular-nums;
  line-height: 1; letter-spacing: var(--tracking-tightest);
}
.step-row h3 { font-size: var(--fs-xl); margin-bottom: var(--space-2); }
.step-row p { color: var(--text-secondary); font-size: var(--fs-base); line-height: var(--lh-normal); max-width: 38rem; }

.callout {
  padding: var(--space-5) var(--space-6);
  background: var(--surface-callout);
  border-radius: var(--radius-sharp);
  display: grid; grid-template-columns: auto 1fr;
  gap: var(--space-4); align-items: start;
}
.callout .c-icon {
  font-size: 24px; color: var(--text-link-on-light); flex-shrink: 0;
}
.callout h2, .callout h3, .callout h4 { font-size: var(--fs-base); margin-bottom: 4px; }
.callout p { font-size: var(--fs-sm); color: var(--text-secondary); }

/* Dark callout variant — standout section against the light surfaces.
   Use sparingly (1-2 per page max) for key conversion moments. */
.callout.is-dark {
  background: var(--surface-inverse);
  color: var(--text-on-inverse);
  padding: var(--space-8) var(--space-10);
  gap: var(--space-6);
  align-items: center;
}
.callout.is-dark .c-icon { color: var(--color-brand-shimmer); font-size: 32px; }
.callout.is-dark h2, .callout.is-dark h3, .callout.is-dark h4 { color: var(--text-on-inverse); font-size: var(--fs-xl); margin-bottom: var(--space-2); }
.callout.is-dark p { color: var(--text-on-inverse-muted); font-size: var(--fs-base); }
.callout.is-dark .callout-action {
  margin-left: auto; flex-shrink: 0;
}
.callout.is-dark.has-action { grid-template-columns: auto 1fr auto; }
.callout.is-dark.has-action.no-icon { grid-template-columns: 1fr auto; }
/* In dark theme the inverse surface blends into the page — keep the band
   distinct with a border. */
[data-theme="dark"] .callout.is-dark { border: 1px solid var(--border-strong); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .callout.is-dark { border: 1px solid var(--border-strong); }
}

.feature-card {
  padding: var(--space-5) var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  transition: border-color var(--dur-fast) var(--ease-std),
              box-shadow var(--dur-fast) var(--ease-std),
              transform var(--dur-fast) var(--ease-std);
}
.feature-card:hover {
  border-color: var(--action-primary);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.feature-card h3 { font-size: var(--fs-base); font-weight: var(--fw-bold); margin-bottom: var(--space-2); }
.feature-card p { font-size: var(--fs-sm); color: var(--text-secondary); margin: 0; }
.feature-card.on-dark {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.08);
}
.feature-card.on-dark:hover {
  border-color: var(--color-brand-shimmer);
  box-shadow: none;
  transform: translateY(-2px);
}
.feature-card.on-dark h3 { color: var(--text-on-inverse); }
.feature-card.on-dark p { color: var(--text-on-inverse-muted); }

/* ---------------------------------------------------------------------
   Course / lab structure
   --------------------------------------------------------------------- */
.meta-panel {
  padding: var(--space-6);
  background: var(--card-bg);
  border-radius: var(--radius-sharp);
  border: 1px solid var(--border-default);
}
.meta-panel h2 {
  font-size: 11px; font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wider); text-transform: uppercase;
  color: var(--text-muted); margin-bottom: var(--space-4);
  font-family: var(--font-mono);
}

.objectives { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.objective {
  display: grid; grid-template-columns: auto 1fr;
  align-items: start; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-base);
}
.objective .num {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  font-weight: var(--fw-bold); color: var(--text-link-on-light);
  font-variant-numeric: tabular-nums;
}

.feature-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  background: var(--surface-raised);
  padding: var(--space-2);
  border-radius: var(--radius-sharp);
}
.feature {
  display: grid; grid-template-columns: auto 1fr;
  align-items: center; gap: 10px;
  padding: var(--space-3) var(--space-4);
  background: var(--surface-page);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--text-primary);
}
.feature .icon { width: 18px; height: 18px; flex-shrink: 0; }
.feature.is-on .icon { color: var(--text-link-on-light); }

.prereq-list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.prereq-list li {
  padding: var(--space-3) var(--space-4);
  background: var(--surface-raised);
  border-left: 3px solid var(--action-primary);
  border-radius: 0 var(--radius-sharp) var(--radius-sharp) 0;
  font-size: var(--fs-base); color: var(--text-secondary);
}
.prereq-list strong { color: var(--text-primary); font-weight: var(--fw-bold); }

/* ---------------------------------------------------------------------
   Checkout / purchase / post-purchase
   --------------------------------------------------------------------- */
.checkout-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--space-8); align-items: start; }
.checkout-form {
  padding: var(--space-6);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  display: flex; flex-direction: column; gap: var(--space-5);
}
.order-summary {
  padding: var(--space-6);
  background: var(--surface-tint);
  border-radius: var(--radius-sharp);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.order-summary h4 { font-size: var(--fs-base); letter-spacing: var(--tracking-snug); }
.order-line {
  display: flex; justify-content: space-between;
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.order-line.is-total {
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-default);
  font-size: var(--fs-base); font-weight: var(--fw-extrabold); color: var(--text-primary);
}

.confirmation {
  padding: var(--space-12);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  text-align: center;
}
.confirmation .check-circle {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: var(--surface-callout); color: var(--text-link-on-light);
  display: inline-flex; align-items: center; justify-content: center;
  margin-bottom: var(--space-5);
}
.confirmation h3 { font-size: var(--fs-3xl); margin-bottom: var(--space-3); }
.confirmation p { color: var(--text-secondary); margin: 0 auto var(--space-6); max-width: 32rem; }

/* ---------------------------------------------------------------------
   Code blocks
   --------------------------------------------------------------------- */
pre.code {
  padding: var(--space-5);
  background: var(--bg-code);
  border: 1px solid var(--border-code);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--fg-code);
  overflow-x: auto;
}
code.inline {
  padding: 1px 6px;
  background: var(--bg-code);
  border: 1px solid var(--border-code);
  border-radius: 4px;
  font-size: 0.92em;
  color: var(--fg-code);
}
kbd.key {
  padding: 1px 6px;
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  border-bottom-width: 2px;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
}

/* ---------------------------------------------------------------------
   Footer
   --------------------------------------------------------------------- */
.site-footer {
  padding: var(--space-12) var(--space-6);
  background: var(--surface-page);
  border-top: 1px solid var(--border-default);
}
.site-footer-newsletter {
  display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap;
  gap: var(--space-8);
  padding-top: var(--space-10); margin-bottom: var(--space-10);
  border-top: 1px solid var(--border-default);
}
.site-footer-newsletter .copy { max-width: 28rem; }
.site-footer-newsletter .copy h2 { font-size: var(--fs-lg); font-weight: var(--fw-bold); margin: 0 0 var(--space-1); }
.site-footer-newsletter .copy p { color: var(--text-muted); font-size: var(--fs-sm); margin: 0; }
.site-footer-newsletter .footer-newsletter-form { flex: 1; min-width: 300px; max-width: 28rem; }

/* Newsletter signup form (newsletter_signup macro) — token-based, theme-aware */
.newsletter-signup form { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }
.newsletter-signup input[type="email"] {
  flex: 1; min-width: 200px;
  padding: 10px 14px;
  border: 1px solid var(--border-default); border-radius: var(--radius-sharp);
  background: var(--surface-page); color: var(--text-primary);
  font-family: inherit; font-size: var(--fs-sm);
}
.newsletter-signup input[type="email"]:focus-visible {
  outline: none; border-color: var(--border-focus); box-shadow: var(--focus-ring);
}
.newsletter-signup .consent { flex-basis: 100%; }
.site-footer-grid {
  display: grid; grid-template-columns: 2.5fr 1fr 1fr 1fr;
  gap: var(--space-12);
  margin-bottom: var(--space-10);
}
.site-footer .footer-brand p { color: var(--text-muted); font-size: var(--fs-sm); margin-top: var(--space-3); }
.site-footer .footer-col h2 { font-size: var(--fs-sm); font-weight: var(--fw-bold); margin-bottom: var(--space-3); }
.site-footer .footer-col ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer .footer-col a { color: var(--text-muted); font-size: var(--fs-sm); }
.site-footer .footer-col a:hover { color: var(--text-link-on-light); }
.site-footer-bottom {
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap;
  gap: var(--space-4); padding-top: var(--space-6);
  border-top: 1px solid var(--border-default);
  font-size: var(--fs-sm); color: var(--text-muted);
}
/* "Cookie settings" is a real <button> (it opens a dialog, it doesn't
   navigate) styled to match the neighboring footer links. */
.site-footer button.cookie-settings {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
}
.site-footer button.cookie-settings:hover { color: var(--text-link-on-light); text-decoration: underline; }

/* ---------------------------------------------------------------------
   Responsive — component rules
   --------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .objectives, .feature-grid { grid-template-columns: 1fr 1fr; }
  .checkout-grid { grid-template-columns: 1fr; }
  .site-footer-grid { grid-template-columns: 1fr 1fr 1fr; }
}
@media (max-width: 720px) {
  .objectives, .feature-grid { grid-template-columns: 1fr; }
  .trust-strip { grid-template-columns: 1fr; gap: var(--space-6); }
  .step-row { grid-template-columns: 56px 1fr; gap: var(--space-4); }
  .step-row .row-num { font-size: var(--fs-3xl); }
  .site-footer-grid { grid-template-columns: 1fr 1fr; }
  /* Hero scales down so the display headline doesn't hyphen-break words. */
  .hero { padding: 5rem var(--space-5) 4rem; }
  .hero h1 { font-size: var(--fs-4xl); text-wrap: balance; }
  /* Dark CTA band stacks: text above, full-width action below. */
  .callout.is-dark.has-action,
  .callout.is-dark.has-action.no-icon { grid-template-columns: 1fr; }
  .callout.is-dark { padding: var(--space-6); }
  .callout.is-dark .callout-action { margin-left: 0; width: 100%; }
  .callout.is-dark .callout-action .btn { width: 100%; justify-content: center; }
}

/* ---------------------------------------------------------------------
   Header — incremental-port additions.
   Sticky positioning lives here (not a utility class) so the header
   behaves identically on legacy pages, which load these rules from
   legacy-shim.css instead. z-index 900 stays below Bootstrap's modal
   stack (1040/1050) so legacy modals overlay the header.
   ------------------------------------------------------------------ */
.site-header { position: sticky; top: 0; z-index: 900; }
.header-utils { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; }

/* Disclosure nav dropdown (links, not role=menu) */
.nav-dropdown { position: relative; display: inline-flex; }
.nav-dropdown-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; cursor: pointer;
  color: var(--text-muted); font-weight: var(--fw-medium); font-size: var(--fs-base);
}
.nav-dropdown-btn:hover { color: var(--text-primary); }
.nav-dropdown-btn[aria-expanded="true"] { color: var(--text-primary); }
.nav-caret { font-size: 10px; transition: transform var(--dur-fast) var(--ease-std); }
.nav-caret.is-open { transform: rotate(180deg); }
.nav-dropdown-panel {
  position: absolute; top: calc(100% + 10px); left: 0; z-index: 950;
}
@media (prefers-reduced-motion: reduce) {
  .nav-caret { transition: none; }
}

/* Desktop nav can't fit tablet widths (logo + links + dropdowns + utils),
   so the hamburger takes over below 960px — keep in sync with legacy-shim.css
   and the .mobile-only breakpoint in brands.css. */
@media (max-width: 960px) {
  .site-header-inner {
    grid-template-columns: 1fr auto;
    padding: var(--space-3) var(--space-4);
    gap: var(--space-4);
  }
  .site-nav { display: none; }
}
@media (max-width: 480px) {
  /* Narrow phones: the utility cluster must fit 320px — drop the duplicate
     sign-in button (it lives in the mobile panel) and tighten gaps. */
  .header-signin { display: none; }
  .header-utils { gap: var(--space-2); }
  .site-header-inner { gap: var(--space-2); }
  .site-footer-grid { grid-template-columns: 1fr; }
}

/* Mobile panel groups */
.mobile-nav-group { display: flex; flex-direction: column; gap: var(--space-2); padding-left: var(--space-3); border-left: 2px solid var(--border-subtle); }
.mobile-nav-heading { font-size: var(--fs-xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); }

/* Footer bottom-bar separator */
.footer-sep { margin: 0 var(--space-1); color: var(--border-default); }

/* Newsletter macro — de-utilitied layout (was Tailwind classes on OPR) */
.nl-status { font-size: var(--fs-sm); margin: 0; color: var(--text-secondary); }
.nl-status .fa-check-circle { color: var(--action-primary); margin-right: 4px; }
.nl-status.nl-error { color: var(--status-error-fg, #b91c1c); margin-bottom: 4px; }
.newsletter-signup .consent { flex-basis: 100%; display: inline-flex; align-items: flex-start; gap: 8px; cursor: pointer; font-weight: normal; }
.newsletter-signup .consent span { font-size: var(--fs-xs); color: var(--text-muted); }
.newsletter-signup .consent a { text-decoration: underline; color: inherit; }
.newsletter-signup .consent input[type="checkbox"] { margin-top: 2px; accent-color: var(--action-primary); }

/* Hero product shot — framed screenshot beneath the hero CTAs */
.hero-shot {
  max-width: 60rem;
  margin: var(--space-16, 4rem) auto 0;
}

/* Browser chrome drawn rather than captured: sharp at any density, themeable,
   and the address bar shows our domain instead of the internal lab host that
   appears in a real screenshot. Decorative — aria-hidden in the markup. */
.browser-frame {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sharp);
  box-shadow: var(--shadow-xl);
  background: var(--surface-raised);
  overflow: hidden;
}
.browser-bar {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 10px var(--space-3);
  background: var(--surface-raised);
  border-bottom: 1px solid var(--border-default);
}
.browser-dots { display: inline-flex; gap: 6px; flex-shrink: 0; }
.browser-dots i {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--border-strong);
}
.browser-url {
  flex: 1; max-width: 22rem;
  padding: 3px 12px;
  border-radius: var(--radius-full);
  background: var(--surface-page);
  border: 1px solid var(--border-default);
  font-family: var(--font-mono); font-size: var(--fs-xs);
  color: var(--text-subtle);
  text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hero-shot img,
.browser-frame img {
  display: block; width: 100%; height: auto;
  background: var(--surface-page);
}
@media (max-width: 720px) {
  .hero-shot { margin-top: var(--space-8); }
  .browser-url { display: none; }
}

/* Long-form legal documents (privacy policies, agreements). The agreement
   *_include.html files are shared with PDF rendering in app.py and keep their
   bare legacy markup — this class restores document styling on-screen under
   the Tailwind preflight reset. */
.legal-doc h1,
.legal-doc h2 { font-size: var(--fs-lg, 1.125rem); font-weight: var(--fw-bold); color: var(--text-primary); margin: 0 0 var(--space-4); }
.legal-doc h3,
.legal-doc h4,
.legal-doc h5 { font-size: var(--fs-base); font-weight: var(--fw-bold); color: var(--text-primary); margin: var(--space-8) 0 var(--space-3); }
.legal-doc > :first-child { margin-top: 0; }
.legal-doc p { margin: 0 0 var(--space-4); }
.legal-doc ul { list-style: disc; margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.legal-doc ol { list-style: decimal; margin: 0 0 var(--space-4); padding-left: var(--space-6); }
/* Agreement clauses use typed lists — only type="a" exists in the legal
   docs today (CSS [type=] matching is case-insensitive, so add variants
   here with care if other letterings ever appear). */
.legal-doc ol[type="a"] { list-style-type: lower-alpha; }
.legal-doc ul ul, .legal-doc ol ol { margin-bottom: 0; }
.legal-doc li { margin: var(--space-1) 0; }
.legal-doc a:not(.btn) { color: var(--color-link); text-decoration: underline; }
.legal-doc a:not(.btn):hover { color: var(--action-primary-hover); }
.legal-doc table { width: 100%; border-collapse: collapse; margin: 0 0 var(--space-4); }
.legal-doc th, .legal-doc td { border: 1px solid var(--border-default); padding: 8px 12px; text-align: left; vertical-align: top; }
.legal-doc th { background: var(--surface-raised); font-weight: var(--fw-semibold); color: var(--text-primary); }

@media (max-width: 480px) {
  /* Narrow phones: let the form shrink instead of forcing horizontal scroll */
  .site-footer-newsletter .footer-newsletter-form { min-width: 0; width: 100%; }
  .newsletter-signup form { flex-direction: column; align-items: stretch; }
  .newsletter-signup input[type="email"] { min-width: 0; }
}
