
/* ==========================================================================
   Scitools — Design System Stylesheet
   Raw CSS, no framework. This file is shared across every page of the site.
   Sections:
     1. Design tokens
     2. Reset & base
     3. Typography
     4. Layout utilities
     5. Buttons
     6. Badges
     7. Cards
     8. Forms
     9. Navbar (liquid glass)
     10. Footer
     11. Logo strip
     12. Misc utilities (glow, dividers, section backgrounds)
   ========================================================================== */

/* -----------------------------------------------------------------------
   1. Design tokens
   ----------------------------------------------------------------------- */
:root {
  /* Brand colors — as specified */
  --surface: #0A0F1C;
  --surface-rgb: 10, 15, 28;
  --card: #141F30;
  --card-rgb: 20, 31, 48;
  --accent-1: #3B82F6;      /* primary — blue */
  --accent-1-rgb: 59, 130, 246;
  --accent-2: #34D399;      /* secondary — green */
  --accent-2-rgb: 52, 211, 153;

  /* Text — carried over from earlier approved mockups, tweak freely */
  --text-primary: #E6E8EB;
  --text-muted: #8A93A6;
  --text-on-accent: #0A0F1C; /* dark text sitting on top of a bright accent fill */

  /* Borders & elevation */
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --shadow-sm: 0 8px 20px -10px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 20px 40px -18px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 30px 70px -25px rgba(0, 0, 0, 0.6);

  /* Radius scale */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --radius-full: 999px;

  /* Type */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "SF Mono", Menlo, Consolas, monospace;

  /* Layout */
  --container-max: 1160px;
  --section-py: 6.5rem;
  --section-py-sm: 3.5rem;

  /* Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Theme-aware special cases (see section 1b for light overrides) */
  --navbar-highlight: rgba(255, 255, 255, 0.06);
  --input-bg: rgba(255, 255, 255, 0.03);
  --logo-filter: grayscale(1) contrast(0) brightness(1.8);
  --logo-opacity: 0.55;

  color-scheme: dark;
}

/* -----------------------------------------------------------------------
   1b. Light theme overrides
   Auto-detected via prefers-color-scheme, or forced via [data-theme]
   (set by js/main.js). Brand accents stay fixed in both themes.
   ----------------------------------------------------------------------- */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --surface: #EEF2F8;
    --surface-rgb: 238, 242, 248;
    --card: #FFFFFF;
    --card-rgb: 255, 255, 255;
    --text-primary: #0F172A;
    --text-muted: #55607A;
    --border: rgba(15, 23, 42, 0.10);
    --border-strong: rgba(15, 23, 42, 0.18);
    --shadow-sm: 0 8px 20px -10px rgba(15, 23, 42, 0.12);
    --shadow-md: 0 20px 40px -18px rgba(15, 23, 42, 0.16);
    --shadow-lg: 0 30px 70px -25px rgba(15, 23, 42, 0.2);
    --navbar-highlight: rgba(15, 23, 42, 0.05);
    --input-bg: rgba(15, 23, 42, 0.035);
    --logo-filter: grayscale(1) contrast(0) brightness(0.85);
    --logo-opacity: 0.45;
    color-scheme: light;
  }
}
:root[data-theme="light"] {
  --surface: #EEF2F8;
  --surface-rgb: 238, 242, 248;
  --card: #FFFFFF;
  --card-rgb: 255, 255, 255;
  --text-primary: #0F172A;
  --text-muted: #55607A;
  --border: rgba(15, 23, 42, 0.10);
  --border-strong: rgba(15, 23, 42, 0.18);
  --shadow-sm: 0 8px 20px -10px rgba(15, 23, 42, 0.12);
  --shadow-md: 0 20px 40px -18px rgba(15, 23, 42, 0.16);
  --shadow-lg: 0 30px 70px -25px rgba(15, 23, 42, 0.2);
  --navbar-highlight: rgba(15, 23, 42, 0.05);
  --input-bg: rgba(15, 23, 42, 0.035);
  --logo-filter: grayscale(1) contrast(0) brightness(0.85);
  --logo-opacity: 0.45;
  color-scheme: light;
}

/* -----------------------------------------------------------------------
   2. Reset & base
   ----------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { font-size: 16px; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--surface);
  color: var(--text-primary);
  font-family: var(--font-sans);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img, svg { max-width: 100%; display: block; }
/* Every <img> carries width/height attributes now (added for CLS). Without a
   matching height:auto the attribute supplies the used height while CSS
   shrinks only the width, so the picture squashes horizontally -- the Onboard
   graphs rendered 240px wide at their full 474px natural height. This sits on
   the bare `img` selector (0,0,1) on purpose: any class that sets a real
   height, like .ob-nav-logo or .logo-taller, still outranks it. */
img { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, h5, p { margin: 0; }
::selection { background: rgba(var(--accent-1-rgb), 0.35); }

/* -----------------------------------------------------------------------
   3. Typography
   ----------------------------------------------------------------------- */

/* Space under a heading belongs to the type scale, not to each component.
   The reset above zeroes every margin; this puts the bottom one back, in em
   so it tracks the heading's own size. Measured across all 47 pages before
   adding it: 133 headings were sitting 0-4px above the paragraph under them
   because they relied on that zero, and almost all of them were an h2 in a
   .section-heading. Anything that already sets its own margin-bottom does so
   from a class selector, which outranks this, so none of those move. */
h1, h2, h3, h4 { margin-bottom: 0.5em; }

/* The one exception: inside a flex parent that is already spacing its
   children with `gap`, this margin would stack on top of that gap. Any new
   gapped flex or grid wrapper that takes a heading as a direct child needs
   adding here. */
.stack > h1, .stack > h2, .stack > h3, .stack > h4,
.row > h1, .row > h2, .row > h3, .row > h4 { margin-bottom: 0; }

h1, .h1 {
  font-size: clamp(2.25rem, 1.7rem + 2.2vw, 3.5rem);
  line-height: 1.08;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
h2, .h2 {
  font-size: clamp(1.75rem, 1.5rem + 1vw, 2.25rem);
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--text-primary);
}
h3, .h3 {
  font-size: 1.375rem;
  line-height: 1.3;
  font-weight: 600;
  color: var(--text-primary);
}
h4, .h4 {
  font-size: 1.0625rem;
  line-height: 1.4;
  font-weight: 600;
  color: var(--text-primary);
}
p {
  font-size: 1rem;
  color: var(--text-muted);
  line-height: 1.65;
}
p.lead {
  font-size: 1.125rem;
  line-height: 1.6;
  color: var(--text-muted);
}
.text-small { font-size: 0.8125rem; color: var(--text-muted); }
.text-muted { color: var(--text-muted); }
.text-accent-1 { color: var(--accent-1); }
.text-accent-2 { color: var(--accent-2); }
.eyebrow {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent-2);
  margin-bottom: 0.75rem;
}
.gradient-text {
  background: linear-gradient(90deg, var(--accent-1), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
a.link {
  color: var(--accent-1);
  font-weight: 600;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s var(--ease);
}
a.link:hover { border-color: currentColor; }
code {
  font-family: var(--font-mono);
  font-size: 0.85em;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
  padding: 0.15em 0.45em;
  border-radius: 6px;
  color: var(--accent-2);
}

/* -----------------------------------------------------------------------
   4. Layout utilities
   ----------------------------------------------------------------------- */
.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 1.75rem;
}
/* Screens bigger than a laptop get a wider content column instead of
   just more empty margin on either side. */
@media (min-width: 1440px) {
  :root { --container-max: 1440px; }
  /* The hero's two-column row (copy + hub diagram) doesn't get the same
     treatment: at this wider container, an even 1fr/1fr split leaves a
     visible dead gap where the copy (capped at 520px by its own
     paragraph) stops well short of filling its column before the
     diagram even starts. Capping the copy column's width lets the
     extra room go to the diagram instead of sitting empty. */
  #hero-intro .grid-2 { grid-template-columns: minmax(0, 560px) 1fr; }
  /* The hub diagram's own column also grew from the change above, and
     the expanded detail panel (which used to cover the whole diagram
     box edge to edge) grew right along with it — its content doesn't
     need that much room, so it was just empty space. Capping the
     panel's own width instead of stretching it full-bleed keeps it
     content-sized and lets the (still-dimmed) other surface nodes show
     through on the right, instead of being hidden behind blank card. */
  .hub-detail { right: auto; width: 460px; }
}
.section { padding: var(--section-py) 0; }
.section-sm { padding: var(--section-py-sm) 0; }
.section-heading {
  max-width: 620px;
  margin: 0 auto 3rem;
  text-align: center;
}
.section-heading.align-left { margin-left: 0; text-align: left; }
.stack { display: flex; flex-direction: column; }
.row { display: flex; align-items: center; }
.gap-sm { gap: 0.5rem; }
.gap-md { gap: 1rem; }
.gap-lg { gap: 1.75rem; }
.grid {
  display: grid;
  gap: 1.5rem;
}
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  :root { --section-py: 4rem; }
}
.divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 0;
}

/* -----------------------------------------------------------------------
   5. Buttons
   ----------------------------------------------------------------------- */
.btn {
  --btn-py: 0.8rem;
  --btn-px: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: var(--btn-py) var(--btn-px);
  border-radius: var(--radius-full);
  font-size: 0.9375rem;
  font-weight: 700;
  border: 1px solid transparent;
  color: var(--text-primary);
  cursor: pointer;
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease), background-color 0.15s var(--ease), border-color 0.15s var(--ease);
  white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn-sm { --btn-py: 0.55rem; --btn-px: 1.1rem; font-size: 0.8125rem; }
.btn-lg { --btn-py: 1rem; --btn-px: 2rem; font-size: 1rem; }

.btn-primary {
  background: var(--accent-1);
  color: #fff;
  box-shadow: 0 8px 24px -8px rgba(var(--accent-1-rgb), 0.55);
}
.btn-primary:hover { box-shadow: 0 10px 30px -6px rgba(var(--accent-1-rgb), 0.7); }

.btn-secondary {
  background: var(--accent-2);
  color: var(--text-on-accent);
  box-shadow: 0 8px 24px -8px rgba(var(--accent-2-rgb), 0.5);
}
.btn-secondary:hover { box-shadow: 0 10px 30px -6px rgba(var(--accent-2-rgb), 0.65); }

.btn-outline {
  background: transparent;
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.btn-outline:hover { border-color: var(--accent-1); }

.btn-ghost {
  background: transparent;
  color: var(--text-primary);
  padding-left: 0.25rem;
  padding-right: 0.25rem;
}
.btn-ghost:hover { color: var(--accent-1); }

.btn-icon {
  width: 2.5rem; height: 2.5rem; padding: 0; border-radius: var(--radius-full);
  background: var(--card); border-color: var(--border);
}
.btn-icon:hover {
  background: rgba(var(--accent-1-rgb), 0.15);
  border-color: var(--accent-1);
  color: var(--accent-1);
  transform: translateY(-2px);
}

.btn:disabled, .btn.is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}

/* -----------------------------------------------------------------------
   6. Badges
   ----------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.8125rem;
  font-weight: 600;
  padding: 0.4rem 0.9rem;
  border-radius: var(--radius-full);
}
.badge .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-2);
  flex-shrink: 0;
}
.badge-accent-1 { color: var(--accent-1); border-color: rgba(var(--accent-1-rgb), 0.35); background: rgba(var(--accent-1-rgb), 0.1); }
.badge-accent-1 .dot { background: var(--accent-1); }
.badge-accent-2 { color: var(--accent-2); border-color: rgba(var(--accent-2-rgb), 0.35); background: rgba(var(--accent-2-rgb), 0.1); }
.badge-accent-2 .dot { background: var(--accent-2); }

/* -----------------------------------------------------------------------
   7. Cards
   ----------------------------------------------------------------------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.75rem;
  transition: transform 0.2s var(--ease), border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.card-hover:hover {
  transform: translateY(-4px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}
.card-icon {
  width: 2.75rem; height: 2.75rem;
  border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 1.25rem;
  background: rgba(var(--accent-1-rgb), 0.14);
  color: var(--accent-1);
}
.card-icon.is-accent-2 { background: rgba(var(--accent-2-rgb), 0.14); color: var(--accent-2); }
.card-icon svg, .card-icon img { width: 1.35rem; height: 1.35rem; }
.card h3 { margin-bottom: 0.5rem; }
.card p { margin: 0; font-size: 0.9375rem; }

.card-bordered-glow {
  position: relative;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

/* -----------------------------------------------------------------------
   8. Forms
   ----------------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 0.45rem; margin-bottom: 1.1rem; min-width: 0; }
.field label { font-size: 0.8125rem; font-weight: 600; color: var(--text-primary); }
.input, .textarea, select.input {
  background: var(--input-bg);
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  border-radius: var(--radius-md);
  padding: 0.8rem 1rem;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.textarea { resize: vertical; min-height: 120px; }
.input::placeholder, .textarea::placeholder { color: var(--text-muted); }
.input:focus, .textarea:focus, select.input:focus {
  outline: none;
  border-color: var(--accent-1);
  box-shadow: 0 0 0 3px rgba(var(--accent-1-rgb), 0.25);
}
select.input option {
  background: var(--card);
  color: var(--text-primary);
}
/* A percentage width lets a select shrink below its longest option (the
   country list's "South Georgia and the South Sandwich Islands"), so it can't
   push a single-column form wider than a phone screen. */
.field select.input { width: 100%; min-width: 0; }
.field-hint { font-size: 0.75rem; color: var(--text-muted); }
.checkbox-row { display: flex; align-items: center; gap: 0.6rem; }
.checkbox-row input[type="checkbox"] {
  width: 1.05rem; height: 1.05rem; accent-color: var(--accent-1);
}

/* One-line email capture (newsletter, "send me the details"). The input
   takes the room and the button keeps its label; when there isn't room for
   both, the button drops under the input instead of squeezing it. */
.inline-form-row { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.inline-form-row .input { flex: 1 1 13rem; min-width: 0; }
.inline-form-row .btn { flex: 0 0 auto; }
.is-sent .inline-form-row { display: none; }

/* Status line under a form: a muted resting note, then sending / sent /
   failed. The icons are inline masks, so nothing extra is downloaded and
   they take the text color in either theme. */
.form-status {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--text-muted);
}
.form-status[hidden] { display: none; }
.form-status[data-state="success"],
.form-status[data-state="error"] { color: var(--text-primary); }
.form-status[data-state]::before {
  content: "";
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  margin-top: 0.05rem;
  background: currentColor;
  -webkit-mask: var(--status-icon) center / contain no-repeat;
  mask: var(--status-icon) center / contain no-repeat;
}
.form-status[data-state="wait"]::before {
  --status-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2a6 6 0 1 1-6 6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  animation: form-status-spin 0.9s linear infinite;
}
.form-status[data-state="success"]::before {
  --status-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5l3.2 3.2L13 5' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background: var(--accent-2);
}
.form-status[data-state="error"]::before {
  --status-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.4' fill='none' stroke='black' stroke-width='1.6'/%3E%3Cpath d='M8 4.7v4.1' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='11.3' r='1' fill='black'/%3E%3C/svg%3E");
}
@keyframes form-status-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .form-status[data-state="wait"]::before { animation: none; }
}

/* -----------------------------------------------------------------------
   9. Navbar — liquid glass, pinned
   ----------------------------------------------------------------------- */
.navbar {
  position: sticky;
  top: 0;
  z-index: 1000;
  width: 100%;
}
.navbar-inner {
  background: linear-gradient(180deg, rgba(var(--card-rgb), 0.55), rgba(var(--surface-rgb), 0.4));
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--navbar-highlight);
  transition: background-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.navbar.is-scrolled .navbar-inner {
  background: rgba(var(--surface-rgb), 0.78);
  box-shadow: inset 0 1px 0 var(--navbar-highlight), 0 10px 30px -12px rgba(0, 0, 0, 0.6);
}
.navbar .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 1rem;
  padding-bottom: 1rem;
}
.nav-logo { display: flex; align-items: center; gap: 0.6rem; }
/* The 2026 mark's artwork fills 97% of its box, where the old one filled 87%,
   so the same box height would render it ~11% larger and leave only ~4px
   between the wordmark and "Product" at 941px (the last width before the
   links collapse). 36/29 reproduce the previous optical size to within a
   pixel and restore the old spacing. */
.nav-logo img { height: 29px; width: auto; }
.navbar .nav-logo img { height: 36px; }
.nav-logo .logo-light { display: none; }
:root[data-theme="light"] .nav-logo .logo-dark { display: none; }
:root[data-theme="light"] .nav-logo .logo-light { display: block; }
.nav-links {
  display: flex;
  align-items: center;
  gap: 2rem;
}
.nav-links a,
.nav-links .nav-dropdown-trigger {
  font-size: 0.9rem;
  color: var(--text-muted);
  font-weight: 500;
  position: relative;
  padding: 4px 0;
  background: none;
  border: none;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  transition: color 0.15s var(--ease);
}
.nav-links a::after,
.nav-links .nav-dropdown-trigger::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--accent-1);
  border-radius: var(--radius-full);
  transition: width 0.25s var(--ease);
}
.nav-links a:hover,
.nav-links a.is-active,
.nav-links .nav-dropdown-trigger:hover,
.nav-dropdown.is-open .nav-dropdown-trigger { color: var(--text-primary); }
.nav-links a:hover::after,
.nav-dropdown.is-open .nav-dropdown-trigger::after { width: 100%; }
.nav-dropdown-trigger .chevron { transition: transform 0.2s var(--ease); flex-shrink: 0; }
.nav-dropdown.is-open .nav-dropdown-trigger .chevron { transform: rotate(180deg); }
.nav-actions { display: flex; align-items: center; gap: 1rem; }
/* A product bar (Understand, Onboard) carries its own trial action, so the
   sitewide one would be a second identical button in the same corner of the
   screen. Keyed on the bar actually being in the page rather than on a body
   class, so it stays right as pages gain or lose one. Browsers without :has()
   drop the rule and simply keep showing the button. */
body:has(.u-nav) .navbar .nav-actions .btn-primary,
body:has(.ob-nav) .navbar .nav-actions .btn-primary { display: none; }
.nav-toggle {
  display: none;
  width: 2.25rem; height: 2.25rem;
  border-radius: var(--radius-sm);
  background: transparent; border: 1px solid var(--border-strong);
  color: var(--text-primary);
  align-items: center; justify-content: center;
  cursor: pointer;
}
.nav-mobile-panel {
  display: none;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem 1.75rem 1.5rem;
  background: rgba(var(--surface-rgb), 0.96);
  backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
}
.nav-mobile-panel > a {
  padding: 0.75rem 0;
  font-size: 0.95rem;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
}
.navbar.is-open .nav-mobile-panel { display: flex; }

/* --- Product dropdown (desktop mega-menu) ---
   Opens on click/tap (JS toggles .is-open) rather than CSS :hover — a
   hover-only menu needs the trigger and panel to share one continuous
   hoverable area with no gap, which is fragile; a click toggle plus
   close-on-outside-click/Escape (see main.js) is simpler and works the
   same for mouse, touch, and keyboard. */
.nav-dropdown { position: relative; }
.nav-megamenu {
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  transform: translateX(-50%) translateY(6px);
  width: 424px;
  max-width: calc(100vw - 3rem);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s var(--ease), transform 0.18s var(--ease), visibility 0.18s;
  z-index: 1002;
  /* A safety net, not a layout tool: the menus are sized to fit without it.
     It stops any future addition from pushing content off the bottom of the
     screen, and on a short laptop window it scrolls instead of being cut. */
  max-height: calc(100vh - 8rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.nav-dropdown.is-open .nav-megamenu {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
/* The selector carries .nav-megamenu for specificity, not for scope: these are
   <a> elements inside .nav-links, and `.nav-links a` (0,1,1) sets
   align-items: center, which outranks a bare .nav-megamenu-item (0,1,0). The
   effect is invisible until two items in a grid row differ in height -- then
   the shorter one's icon floats to the middle of the stretched row and sits
   level with the description instead of the title. */
.nav-megamenu .nav-megamenu-item {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  padding: 0.8rem 0.85rem;
  border-radius: var(--radius-md);
  transition: background-color 0.15s var(--ease);
}
.nav-megamenu-item:hover { background: rgba(var(--accent-1-rgb), 0.10); }
.nav-megamenu-item:focus-visible { outline: 2px solid var(--accent-1); outline-offset: 2px; }
.nav-megamenu-icon {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-md);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 0.05rem;
  background: rgba(var(--accent-1-rgb), 0.14);
  color: var(--accent-1);
}
.nav-megamenu-icon.is-accent-2 { background: rgba(var(--accent-2-rgb), 0.14); color: var(--accent-2); }
.nav-megamenu-icon svg, .nav-megamenu-icon img { width: 1.15rem; height: 1.15rem; }
.nav-megamenu-copy { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.nav-megamenu-title { font-size: 0.9375rem; font-weight: 700; line-height: 1.35; color: var(--text-primary); }
.nav-megamenu-desc { font-size: 0.8125rem; color: var(--text-muted); line-height: 1.55; }
.nav-megamenu-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
  padding: 0.85rem 0 0.25rem;
  border-top: 1px solid var(--border);
  font-size: 0.84rem;
  font-weight: 700;
  color: var(--accent-1);
}
.nav-megamenu-footer svg { width: 13px; height: 13px; transition: transform 0.15s var(--ease); }
.nav-megamenu-footer:hover svg { transform: translateX(3px); }

/* --- Solutions dropdown: same item format as Product, on a wider surface.
   Twelve pains with a sentence each do not fit a 440px panel -- that version
   gave each description a 164px column and 11px type, and wrapped most of them
   to four lines. This one is 836px wide with the items 2-up inside it, so a
   description gets ~330px and almost all of them land on two lines at the same
   13px the Product menu uses.

   Categories stack rather than sitting side by side. With one category on
   screen a side-by-side row left half the panel empty; stacking keeps the
   panel one width whether "Who we help" is in it or not. --- */
.nav-megamenu.is-columns.is-rich { width: 836px; }
/* An 836px panel centred on its own trigger reaches the left edge of a 941px
   window -- the narrowest desktop there is, since the nav becomes a hamburger
   at 940. Anchoring it to the navbar's container instead of the trigger keeps
   an even gutter at every width. The id is the whole selector because the
   markup already carries it on all 47 pages; the Product dropdown is narrow
   enough to stay anchored to its trigger. */
.navbar .container { position: relative; }
#solutionsDropdown { position: static; }
.nav-megamenu-columns-row {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}
.nav-megamenu-col {
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.nav-megamenu-col + .nav-megamenu-col {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
}
.nav-megamenu-col-title {
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  padding: 0.1rem 0.85rem 0.7rem;
}
.nav-megamenu-col-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.15rem 0.75rem;
  align-items: start;   /* each item sizes to its own copy instead of being
                           stretched to its row partner's height */
}
.nav-megamenu-item-sm {
  gap: 0.75rem;
  padding: 0.7rem 0.85rem;
}
.nav-megamenu-icon-sm {
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-sm);
  margin-top: 0.1rem;
}
.nav-megamenu-icon-sm svg, .nav-megamenu-icon-sm img { width: 1rem; height: 1rem; }
.nav-megamenu-item-sm .nav-megamenu-title { font-size: 0.875rem; }
.nav-megamenu-item-sm .nav-megamenu-desc { font-size: 0.8125rem; line-height: 1.5; }

/* A category rendered as a title-only index, 3-up. "Common pains" carries a
   sentence each and runs 560px on its own; measured, a second category with
   descriptions takes the panel to 1322px, which no viewport has. So when
   "Who we help" is uncommented it goes on the column as
   <div class="nav-megamenu-col is-index">, its items keep their .nav-megamenu-desc
   in the markup for the mobile accordion, and this hides them on desktop. */
.nav-megamenu-col.is-index .nav-megamenu-col-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.nav-megamenu-col.is-index .nav-megamenu-item { align-items: center; padding: 0.5rem 0.7rem; }
.nav-megamenu-col.is-index .nav-megamenu-icon { width: 1.7rem; height: 1.7rem; margin-top: 0; }
.nav-megamenu-col.is-index .nav-megamenu-icon svg,
.nav-megamenu-col.is-index .nav-megamenu-icon img { width: 0.85rem; height: 0.85rem; }
.nav-megamenu-col.is-index .nav-megamenu-desc { display: none; }
/* The nav is a hamburger at <=940px, so the only desktop range to cover is
   941px up. 836 + the panel's own gutters needs about 890px of viewport;
   below that it falls back to one item per row rather than overflowing. */
@media (max-width: 900px) {
  .nav-megamenu-col-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-megamenu, .nav-megamenu-footer svg { transition-duration: 0.01ms; }
}

/* --- Mobile submenu category label (splits one accordion's list into
   labeled groups, e.g. Solutions' "Common pains" / "Who we help") --- */
.nav-mobile-submenu-label {
  padding: 0.65rem 0.6rem 0.3rem;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.nav-mobile-submenu-label:first-child { padding-top: 0.3rem; }

/* --- Product accordion (mobile slide-out panel) --- */
.nav-mobile-group { border-bottom: 1px solid var(--border); }
.nav-mobile-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: none;
  border: none;
  font: inherit;
  text-align: left;
  padding: 0.75rem 0;
  font-size: 0.95rem;
  color: var(--text-muted);
  cursor: pointer;
}
.nav-mobile-toggle .chevron { transition: transform 0.2s var(--ease); flex-shrink: 0; }
.nav-mobile-group.is-open .nav-mobile-toggle { color: var(--text-primary); }
.nav-mobile-group.is-open .nav-mobile-toggle .chevron { transform: rotate(180deg); }
.nav-mobile-submenu {
  display: none;
  flex-direction: column;
  gap: 0.1rem;
  padding-bottom: 0.65rem;
}
.nav-mobile-group.is-open .nav-mobile-submenu { display: flex; }
.nav-mobile-submenu a {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.55rem 0.6rem;
  border-radius: var(--radius-md);
}
.nav-mobile-submenu a:hover { background: rgba(var(--accent-1-rgb), 0.08); }
.nav-mobile-submenu a strong { font-size: 0.85rem; font-weight: 700; color: var(--text-primary); }
.nav-mobile-submenu a span { font-size: 0.75rem; color: var(--text-muted); line-height: 1.4; }

/* On phones and tablets the toolbar is just the wordmark and the menu
   button; the light/dark switch and the trial button live at the bottom of
   the menu instead (the 940px rule below hides their toolbar copies). */
.nav-mobile-theme-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  background: none;
  border: none;
  font: inherit;
  text-align: left;
  padding: 0.75rem 0;
  font-size: 0.95rem;
  color: var(--text-muted);
  cursor: pointer;
}
.nav-mobile-theme-toggle:hover { color: var(--text-primary); }
.nav-mobile-theme-toggle:focus-visible { outline: 2px solid var(--accent-1); outline-offset: 2px; }
.nav-mobile-theme-toggle svg { width: 18px; height: 18px; flex-shrink: 0; }
/* Beats ".nav-mobile-panel > a", which would otherwise give the button a
   muted link's padding, color and bottom rule. */
.nav-mobile-panel > a.nav-mobile-cta {
  margin-top: 0.75rem;
  padding: var(--btn-py) var(--btn-px);
  border-bottom: none;
  font-size: 0.9375rem;
  color: #fff;
}

.theme-toggle svg { display: block; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

/* The link row is swapped for the hamburger at 940px, not 780px: the
   wordmark and the "Product" trigger stop clearing each other at about
   880px, so between 780 and 880 they overlapped on every page. 940 leaves
   ~25px of clear space at the switch instead of 5px. */
@media (max-width: 940px) {
  .nav-links { display: none; }
  .nav-toggle { display: flex; }
  .nav-actions .btn-outline,
  .nav-actions .theme-toggle,
  .nav-actions .btn-primary { display: none; }
  .navbar .nav-logo img { height: 29px; }
}

/* -----------------------------------------------------------------------
   10. Footer
   ----------------------------------------------------------------------- */
.site-footer {
  background: var(--card);
  border-top: 1px solid var(--border);
  padding: 4rem 0 2rem;
}
.footer-top {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: 2.5rem;
  padding-bottom: 3rem;
}
.footer-brand .nav-logo { margin-bottom: 1rem; }
.footer-brand p { max-width: 260px; font-size: 0.875rem; }

/* Newsletter signup, under the brand blurb. Its label reads like the
   column headings so the row of headings stays one system. */
.footer-signup { margin-top: 1.75rem; max-width: 380px; }
.footer-signup-label {
  display: block;
  margin-bottom: 0.75rem;
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.footer-signup .input { padding-top: 0.7rem; padding-bottom: 0.7rem; }
.footer-signup .form-status { font-size: 0.75rem; max-width: none; }
.footer-col h4 { margin-bottom: 1.1rem; font-size: 0.8125rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.footer-col ul { display: flex; flex-direction: column; gap: 0.7rem; }
.footer-col a { font-size: 0.9rem; color: var(--text-muted); transition: color 0.15s var(--ease); }
.footer-col a:hover { color: var(--text-primary); }
.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 1.75rem;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
  gap: 1rem;
}
.footer-bottom p { font-size: 0.8125rem; margin: 0; }
/* Copyright and the legal links travel together, so .footer-bottom keeps two
   flex children and space-between still pins the social icons to the right.
   They wrap onto their own line on narrow screens instead of squeezing the
   icons. Sized to match .footer-bottom p, not the column links above. */
.footer-legal {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem 1.25rem;
}
.footer-legal a {
  font-size: 0.8125rem;
  color: var(--text-muted);
  transition: color 0.15s var(--ease);
}
.footer-legal a:hover { color: var(--text-primary); }
@media (max-width: 860px) {
  /* Two short links side by side are the easiest thing in the footer to
     mis-tap. Give them a real target without changing how they look. */
  .footer-legal a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Consent line under a form that collects more than an email address. Lives
   in style.css rather than pages.css because the quote form appears on the
   pricing page and on Understand, which load different second stylesheets. */
.form-consent {
  margin-top: 0.9rem;
  font-size: 0.8125rem;
  color: var(--text-muted);
}
.form-consent a { color: var(--text-muted); text-decoration: underline; }
.form-consent a:hover { color: var(--text-primary); }

.footer-social { display: flex; gap: 0.75rem; }
.footer-social a {
  width: 2.25rem; height: 2.25rem; border-radius: var(--radius-full);
  border: 1px solid var(--border); display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.footer-social a:hover { color: var(--text-primary); border-color: var(--border-strong); }
/* Tablet and below: the brand block and signup get a full row of their own,
   the link columns sit underneath. */
@media (max-width: 1023px) {
  .footer-top { grid-template-columns: repeat(3, 1fr); }
  .footer-brand { grid-column: 1 / -1; }
}
@media (max-width: 780px) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
  .footer-top { grid-template-columns: 1fr; }
}

/* -----------------------------------------------------------------------
   11. Logo strip
   ----------------------------------------------------------------------- */
.logo-strip-viewport {
  overflow: hidden;
  width: 100%;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.logo-strip-track {
  display: flex;
  align-items: center;
  gap: 3rem;
  width: max-content;
  animation: logo-scroll 32s linear infinite;
}
.logo-strip-track:hover { animation-play-state: paused; }
.logo-strip-track img {
  height: 26px;
  width: auto;
  max-width: 140px;
  flex-shrink: 0;
  filter: var(--logo-filter);
  opacity: var(--logo-opacity);
  transition: opacity 0.2s var(--ease), filter 0.2s var(--ease);
}
/* Some marks (icon stacked over wordmark) read much smaller than wide
   wordmark logos at the same height — size these up so visual weight
   across the strip stays balanced. Tuned by eye, not a fixed formula. */
.logo-strip-track img.logo-tall { height: 42px; }
/* US Air Force needs a touch more than the other tall marks to read at
   the same visual weight — its own modifier rather than bumping
   .logo-tall so NVIDIA (which shares that class) doesn't grow with it. */
.logo-strip-track img.logo-taller { height: 47px; }
.logo-strip-track img:hover { opacity: 1; filter: grayscale(0) brightness(1); }

@keyframes logo-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-25%); }
}
@media (prefers-reduced-motion: reduce) {
  .logo-strip-track { animation: none; }
}

/* -----------------------------------------------------------------------
   12. Misc utilities
   ----------------------------------------------------------------------- */
.glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  opacity: 0.18;
  pointer-events: none;
  background: radial-gradient(circle, var(--accent-1), var(--accent-2));
}
/* Clips just the static .glow blob to the hero's box (mainly so it can't
   cause horizontal overflow on narrow viewports). The cursor-glow lives
   outside this wrapper on purpose — see below. */
.hero-glow-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
/* Mouse-tracking glow: sized taller than the hero section itself (extra
   bottom reach past its own bottom edge) so the effect visually bleeds
   into the quiet gap above the credibility card below, rather than
   cutting off hard at the section boundary. The interaction stays
   "owned" by the hero regardless — main.js only reads mousemove events
   within #hero-intro, this is purely a paint-area change. Capped well
   short of the credibility card itself (see .proof-panel's own
   stacking below) so it never visually touches that card. */
.cursor-glow {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: -70px;
  pointer-events: none;
  background: radial-gradient(600px circle at var(--mx, 50%) var(--my, 30%), rgba(var(--accent-1-rgb), 0.16), transparent 55%);
  opacity: 1;
  transition: background 0.15s ease-out, opacity 0.4s var(--ease);
}
/* Mouse-leave state (main.js toggles this on the hero's mouseenter/
   mouseleave, separate from the mousemove tracking above): fades the
   glow out instead of leaving it parked at its last position once the
   cursor is gone. */
.cursor-glow.is-idle { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .cursor-glow { display: none; }
}

/* ---- Scroll reveal ---- */
.reveal {
  opacity: 0;
  transform: translateY(28px) scale(0.98);
  filter: blur(6px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease), filter 0.7s var(--ease);
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
  filter: blur(0);
}
.reveal-stagger > * {
  opacity: 0;
  transform: translateY(26px) scale(0.97);
  filter: blur(5px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease), filter 0.6s var(--ease);
}
.reveal-stagger.is-visible > * {
  opacity: 1;
  transform: none;
  filter: blur(0);
}
.reveal-stagger.is-visible > *:nth-child(1) { transition-delay: 0ms; }
.reveal-stagger.is-visible > *:nth-child(2) { transition-delay: 70ms; }
.reveal-stagger.is-visible > *:nth-child(3) { transition-delay: 140ms; }
.reveal-stagger.is-visible > *:nth-child(4) { transition-delay: 210ms; }
.reveal-stagger.is-visible > *:nth-child(5) { transition-delay: 280ms; }
.reveal-stagger.is-visible > *:nth-child(6) { transition-delay: 350ms; }
.reveal-stagger.is-visible > *:nth-child(7) { transition-delay: 420ms; }
.reveal-stagger.is-visible > *:nth-child(8) { transition-delay: 490ms; }
.reveal-stagger.is-visible > *:nth-child(n+9) { transition-delay: 560ms; }

/* Flagship variant — cards tilt up into place as they arrive */
.reveal-stagger.card-reveal > * {
  transform: translateY(34px) scale(0.96) perspective(800px) rotateX(8deg);
  transform-origin: bottom center;
}
.reveal-stagger.card-reveal.is-visible > * {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-stagger > * {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
}
.bg-card { background: var(--card); }
.bg-surface { background: var(--surface); }
.rounded-panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.swatch {
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  height: 88px;
  display: flex;
  align-items: flex-end;
  padding: 0.6rem;
}
.color-token-name { font-size: 0.75rem; font-weight: 700; }
.color-token-hex { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-muted); }

/* -----------------------------------------------------------------------
   13. Code panel — dark editor-style mockup for hero/feature visuals.
   Stays fixed-dark regardless of site theme, like a real code editor.
   ----------------------------------------------------------------------- */
.code-panel {
  background: #0F1729;
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  min-width: 0; /* prevent long code lines from forcing a grid/flex parent to overflow */
}
.code-panel-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.code-panel-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.code-panel-file {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: #8492A6;
  margin-left: 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.code-panel-body {
  padding: 1.375rem 1.5rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  line-height: 1.9;
  color: #D7DEEA;
  overflow-x: auto;
}
.code-panel-body .ln {
  color: #3A4A63;
  display: inline-block;
  width: 22px;
  text-align: right;
  margin-right: 16px;
  user-select: none;
}
.code-panel-body .tok-kw { color: #7DA9FF; }
.code-panel-body .tok-type { color: #6EE7C0; }
.code-panel-body .tok-fn { color: #F6C177; }
.code-panel-body .tok-str { color: #F5A0C5; }
.code-panel-body .tok-com { color: #5C6C84; }
.code-panel-flag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 10px;
  background: rgba(248, 113, 113, 0.14);
  color: #FCA5A5;
  border: 1px solid rgba(248, 113, 113, 0.3);
  font-size: 0.625rem;
  font-weight: 600;
  font-family: var(--font-sans);
  padding: 1px 9px;
  border-radius: var(--radius-full);
  white-space: nowrap;
}
.code-panel-flag.ok { background: rgba(52, 211, 153, 0.14); color: #6EE7C0; border-color: rgba(52, 211, 153, 0.3); }
.code-panel-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: #5C6C84;
}
.code-panel-status .ok-pill { display: flex; align-items: center; gap: 6px; color: #6EE7C0; }
.code-panel-status .ok-pill svg { width: 11px; height: 11px; flex-shrink: 0; }

/* -----------------------------------------------------------------------
   14. Credibility panel — logo strip + stats row, homepage.
   One bordered card rather than two stacked blocks, so the recognizable
   names on top and the numbers below them read as a single claim. The
   two halves meet at .proof-connector: a short gradient line with a
   center dot, echoing the accent-gradient flow lines in the hub diagram
   elsewhere on this page, so the "connection" isn't just a plain rule.
   ----------------------------------------------------------------------- */
.proof-panel {
  position: relative; /* its own stacking context (with z-index below),
    so the hero's bleeding cursor-glow always paints behind this card
    even though the glow is a positioned element and this card isn't
    otherwise one — belt-and-suspenders alongside capping the bleed
    distance itself in .cursor-glow. */
  z-index: 1;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--card);
  padding: 2.75rem clamp(1.5rem, 4vw, 3rem) 2.5rem;
}
.proof-eyebrow {
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 1.75rem;
}

.proof-connector {
  position: relative;
  height: 1px;
  margin: 2.5rem 0 2.25rem;
  background: linear-gradient(90deg, transparent, var(--border-strong) 20%, var(--border-strong) 80%, transparent);
}
.proof-connector span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
  box-shadow: 0 0 0 5px var(--card);
}

.stats-row { grid-template-columns: repeat(3, 1fr); text-align: center; }
.stat-item { padding: 0 0.5rem; }
.stat-value {
  font-size: clamp(1.5rem, 1.15rem + 1.2vw, 2.15rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
.stat-label { margin-top: 0.35rem; font-size: 0.8125rem; color: var(--text-muted); }

/* TÜV item pairs the seal artwork with its own value/label so it reads
   as one credential rather than a fourth plain number. */
.stat-item-tuv {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.9rem;
  text-align: left;
}
.stat-tuv-seal { width: 54px; height: 54px; flex-shrink: 0; }
.stat-tuv-copy .stat-value { font-size: clamp(1.25rem, 1.05rem + 0.6vw, 1.5rem); }
.stat-tuv-copy .stat-label { max-width: 28ch; }

@media (max-width: 620px) {
  .proof-panel { padding: 2.25rem 1.25rem 2rem; }
  .stats-row { grid-template-columns: repeat(2, 1fr); gap: 2rem 1rem; }
  .stat-item-tuv { grid-column: span 2; justify-content: center; }
}

/* -----------------------------------------------------------------------
   15. Card link — small arrow-link at the bottom of a feature card
   ----------------------------------------------------------------------- */
.card-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 1rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--accent-1);
}
.card-link svg { width: 14px; height: 14px; transition: transform 0.15s var(--ease); }
/* On touch widths it is the tile's only action, so give it a real hit area.
   min-height rather than padding, so nothing above it shifts. */
@media (max-width: 860px) {
  .card-link { min-height: 44px; }
}
.card-hover:hover .card-link svg { transform: translateX(3px); }

/* -----------------------------------------------------------------------
   16. Hub diagram — hero visual on the SciTools homepage.
   Pure inline SVG (see index.html) so it scales as one unit and never
   causes horizontal overflow; theme colors come from CSS custom
   properties referenced directly in the SVG's own <style> block.
   ----------------------------------------------------------------------- */
.hub-diagram { position: relative; width: 100%; }
.hub-diagram svg { display: block; width: 100%; height: auto; }

/* Outer nodes are real controls. The outer <g> keeps the positional
   translate() attribute; the nested .hub-node-inner carries the CSS
   hover/focus scale — a CSS `transform` on an SVG element replaces
   (rather than combines with) an attribute transform, so the two have
   to live on different elements or the positional translate would be
   wiped out the moment a scale is applied. */
.hub-node { cursor: pointer; outline: none; }
.hub-node-inner {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}
.hub-node:hover .hub-node-inner,
.hub-node:focus-visible .hub-node-inner {
  transform: scale(1.08);
}
.hub-node:focus-visible .hub-node-inner circle:first-child {
  stroke: var(--accent-1);
  stroke-width: 1.5;
}

/* Focused state: the clicked node's siblings (other nodes, the flow
   lines, the center engine) fade back so the detail panel reads as
   "zoomed into" the one node, not just a popup on top of everything. */
.hub-node.is-dimmed,
.hub-flow.is-dimmed,
.hub-center.is-dimmed {
  opacity: 0.16;
  transition: opacity 0.25s var(--ease);
}
.hub-node.is-dimmed .hub-node-inner:hover { transform: none; }
.hub-node.is-dimmed { pointer-events: none; }

/* Detail panel: absolutely positioned over the diagram, hidden until a
   node is activated. Faded/scaled in rather than just toggled so the
   "zoom into this node" feeling carries through. Given a solid card
   background (rather than sitting transparently over the still-dimmed
   diagram) so the dimmed nodes/lines behind it can never bleed through
   and compete with the text — that overlap was what made the expanded
   state hard to read. */
.hub-detail {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.85rem;
  padding: 2.25rem 2.75rem;
  text-align: left;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: scale(0.96);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease), visibility 0s linear 0.25s;
  pointer-events: none;
  overflow-y: auto; /* safety net: the panel's box height is locked to the
    SVG's aspect ratio, so on narrow phones + the longest surface
    descriptions there isn't always room to fit everything without
    scrolling — see the mobile overrides below, which are tuned to avoid
    needing this in the first place. */
}
.hub-detail.is-visible {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
  transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
  pointer-events: auto;
}
.hub-detail-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: none;
  border: none;
  padding: 0;
  margin-bottom: 0.15rem;
  color: var(--text-muted);
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s var(--ease);
}
.hub-detail-back:hover,
.hub-detail-back:focus-visible { color: var(--accent-1); }
.hub-detail-header {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.hub-detail-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: rgba(var(--accent-1-rgb), 0.14);
  color: var(--accent-1);
}
.hub-detail-icon.is-accent-2 { background: rgba(var(--accent-2-rgb), 0.14); color: var(--accent-2); }
.hub-detail-icon svg { width: 22px; height: 22px; }
.hub-detail-title { font-size: 1.5rem; font-weight: 700; margin: 0; }
.hub-detail-desc { color: var(--text-muted); font-size: 0.9375rem; line-height: 1.65; margin: 0; max-width: 38ch; }
.hub-detail-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.7rem 1.35rem;
  border-radius: var(--radius-full);
  background: var(--accent-1);
  color: #fff;
  font-size: 0.9rem;
  font-weight: 700;
  box-shadow: 0 8px 24px -8px rgba(var(--accent-1-rgb), 0.55);
  transition: box-shadow 0.15s var(--ease), transform 0.15s var(--ease);
}
.hub-detail-cta:hover {
  box-shadow: 0 10px 30px -6px rgba(var(--accent-1-rgb), 0.7);
  transform: translateY(-1px);
}
.hub-detail-cta svg { width: 14px; height: 14px; transition: transform 0.15s var(--ease); }
.hub-detail-cta:hover svg { transform: translateX(3px); }

@media (max-width: 640px) {
  .hub-detail { padding: 1.1rem 1.25rem; gap: 0.5rem; justify-content: flex-start; }
  .hub-detail-back { margin-bottom: 0; }
  .hub-detail-title { font-size: 1.15rem; }
  .hub-detail-icon { width: 38px; height: 38px; }
  .hub-detail-icon svg { width: 17px; height: 17px; }
  .hub-detail-desc { font-size: 0.875rem; line-height: 1.5; }
  .hub-detail-cta { margin-top: 0.2rem; padding: 0.6rem 1.15rem; font-size: 0.85rem; }
}

@media (prefers-reduced-motion: reduce) {
  .hub-node-inner,
  .hub-node.is-dimmed,
  .hub-flow.is-dimmed,
  .hub-center.is-dimmed,
  .hub-detail {
    transition: none;
  }
}

/* -----------------------------------------------------------------------
   17. Pains grid — "Show N more" expand on the homepage.
   The extra cards live inside a display:contents wrapper so they still
   tile as direct children of the surrounding .grid.grid-3; each card
   hides itself via its own [hidden] rather than the wrapper being
   hidden, since [hidden]'s built-in display:none would otherwise fight
   the wrapper's display:contents for who wins.
   ----------------------------------------------------------------------- */

/* Each pains card leads with a small illustrative "scene" (a dotted
   blueprint-style panel containing a purpose-built inline SVG) instead of
   the small single-glyph .card-icon used elsewhere, so the twelve pains
   read at a glance instead of needing the body copy to disambiguate them.
   Pure inline SVG per card — no image requests, themes via currentColor /
   CSS custom properties same as the rest of the page. */
.pain-illustration {
  width: 100%;
  aspect-ratio: 7 / 4;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: linear-gradient(160deg, rgba(var(--accent-1-rgb), 0.07), rgba(var(--accent-2-rgb), 0.05));
  overflow: hidden;
  margin-bottom: 1.5rem;
}
.pain-illustration svg { display: block; width: 100%; height: 100%; }
.pain-illustration img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Photo-style illustrations (screenshots, not the hand-drawn SVG scenes)
   use the source images' own native ratio — matching the box to that ratio
   instead of the SVG cards' 7:4 means the image fills it edge to edge,
   no letterboxing. */
.pain-illustration.pain-illustration-photo { aspect-ratio: 5 / 4; }
.pain-illustration-photo img { object-fit: cover; }

.pains-extra-group { display: contents; }
.pains-more-row {
  display: flex;
  justify-content: center;
  margin-top: 2.75rem;
}
#painsToggle .chevron { transition: transform 0.2s var(--ease); }
#painsToggle[aria-expanded="true"] .chevron { transform: rotate(180deg); }

/* -----------------------------------------------------------------------
   17b. "Who we help" role tiles — same show-more pattern as the pains
   grid above (.role-tiles-extra-group is display:contents so its
   children tile alongside the first six, each hiding itself via [hidden]).
   ----------------------------------------------------------------------- */
.role-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
.role-tiles-extra-group { display: contents; }
.role-tile {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 1.15rem 1.25rem;
  transition: transform 0.2s var(--ease), border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.role-tile:hover,
.role-tile:focus-visible {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-md);
}
.role-tile-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-sm);
  background: rgba(var(--accent-1-rgb), 0.14);
  color: var(--accent-1);
  flex-shrink: 0;
  margin-top: 0.1rem;
}
.role-tile-icon.is-accent-2 { background: rgba(var(--accent-2-rgb), 0.14); color: var(--accent-2); }
.role-tile-icon svg { width: 1.1rem; height: 1.1rem; }
.role-tile-copy {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}
.role-tile-label { font-weight: 600; font-size: 0.9375rem; }
.role-tile-desc { font-size: 0.8125rem; color: var(--text-muted); line-height: 1.5; }
.role-tile[hidden] { display: none; }
#rolesToggle .chevron { transition: transform 0.2s var(--ease); }
#rolesToggle[aria-expanded="true"] .chevron { transform: rotate(180deg); }

@media (max-width: 900px) {
  .role-tiles { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .role-tiles { grid-template-columns: 1fr; }
}


/* -----------------------------------------------------------------------
   18. Announcement bar — thin, dismissible strip above the navbar on
   every page. Not sticky itself (only the navbar below it is), so it
   scrolls away naturally. The close button is a sibling of the link,
   never nested inside it — an <a> can't legally contain a <button>.
   ----------------------------------------------------------------------- */
.announce-bar {
  position: relative;
  display: flex;
  align-items: stretch;
  background: linear-gradient(90deg, rgba(var(--accent-1-rgb), 0.16), rgba(var(--accent-2-rgb), 0.16));
  border-bottom: 1px solid var(--border);
}
.announce-bar-link {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.6rem;
  padding: 0.65rem 2.75rem 0.65rem 1rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  transition: background-color 0.15s var(--ease);
}
.announce-bar-link:hover { background: rgba(var(--accent-1-rgb), 0.08); }
.announce-bar-badge {
  display: inline-flex;
  align-items: center;
  background: var(--accent-1);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.55rem;
  border-radius: var(--radius-full);
  flex-shrink: 0;
}
.announce-bar-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--accent-1);
  font-weight: 700;
  white-space: nowrap;
}
.announce-bar-cta svg { width: 12px; height: 12px; flex-shrink: 0; }
.announce-bar-close {
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: 50%;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.announce-bar-close:hover { background: var(--border); color: var(--text-primary); }
/* Below 700px the full sentence wraps to two or three lines and the bar
   grows from 43px to 70-110px, pushing the page down on the screens that
   can least spare it. Phones and small tablets get the short headline on
   one line instead; "Learn more" still leads to the full story. */
@media (max-width: 699px) {
  .announce-bar-more { display: none; }
  .announce-bar-link { flex-wrap: nowrap; white-space: nowrap; }
}
@media (max-width: 480px) {
  .announce-bar-link { font-size: 0.75rem; padding: 0.6rem 2.5rem 0.6rem 0.75rem; }
}

/* -----------------------------------------------------------------------
   19. Why-pillars — "Why teams pick us" section, homepage (Section D in
   the site outline: Value / Flexibility / Customer satisfaction). Each
   pillar is a .card with a gradient top accent and a large faint index
   numeral watermarking the corner, plus a headline stat pulled out above
   the title so the single strongest number in each pillar reads before
   anything else — the section leads with numbers, not adjectives.
   ----------------------------------------------------------------------- */
.why-pillar {
  position: relative;
  overflow: hidden;
  padding-top: 2.25rem;
}
.why-pillar::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent-1), var(--accent-2));
}
.why-pillar-index {
  position: absolute;
  top: 0.65rem;
  right: 1.15rem;
  font-family: var(--font-mono);
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1;
  color: var(--text-primary);
  opacity: 0.06;
  pointer-events: none;
  user-select: none;
}
.why-pillar-stat {
  font-size: 1.625rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}
.why-pillar-stat-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0.15rem 0 1.1rem;
}
.why-pillar h3 { margin-bottom: 0.5rem; }
.why-pillar-desc { margin-bottom: 1.15rem; }
.why-pillar-list { display: flex; flex-direction: column; gap: 0.65rem; }
.why-pillar-list li { list-style: none; }


/* -----------------------------------------------------------------------
   20. Platform section — five feature rows ("One engine, five ways in").
   Five items don't tile cleanly into a 6-card grid, and a screenshot
   deserves more room than a card icon anyway, so each surface gets a full
   width row instead: a framed screenshot (or, for the two text-native
   surfaces, the same dark code-panel used for the hero's CLI mockup) on
   one side, larger copy on the other, alternating sides down the page.
   ----------------------------------------------------------------------- */
.platform-rows { display: flex; flex-direction: column; gap: 5rem; }
.platform-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3.5rem;
  align-items: center;
}
.platform-shot {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  background: #0F1729;
}
.platform-shot-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.platform-shot-label {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: #8492A6;
  margin-left: 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.platform-shot img { display: block; width: 100%; height: auto; }
/* A .code-panel dropped inside .platform-shot already brings its own
   dark chrome, border and shadow — drop the duplicates so it doesn't
   look double-framed. */
.platform-shot .code-panel { border: none; border-radius: 0; box-shadow: none; }
.platform-copy .card-icon { margin-bottom: 1.25rem; }
.platform-copy h3 { font-size: 1.625rem; margin-bottom: 0.75rem; }
.platform-copy p { font-size: 1.0625rem; max-width: 44ch; }

/* Video facade ("VS Code Plugin" row): a static thumbnail standing in
   for the embed so the only network cost on page load is one image —
   the real YouTube player is only requested once a visitor clicks
   (see main.js), never automatically. */
.video-facade {
  position: relative;
  cursor: pointer;
  outline: none;
}
.video-facade-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 48px;
  transition: transform 0.15s var(--ease);
  pointer-events: none;
}
.video-facade-play svg { display: block; width: 100%; height: 100%; }
.video-facade:hover .video-facade-play { transform: translate(-50%, -50%) scale(1.08); }
.video-facade:focus-visible {
  box-shadow: inset 0 0 0 2px var(--accent-1);
}
.video-embed {
  display: block;
  width: 100%;
  aspect-ratio: 1000 / 621;
  border: none;
}

@media (max-width: 860px) {
  .platform-rows { gap: 3rem; }
  .platform-row { grid-template-columns: 1fr; gap: 1.5rem; }
  /* Source order alternates shot/copy per row for the desktop zig-zag;
     on a single column always lead with the screenshot regardless of
     which side of the row it was written on. */
  .platform-row .platform-shot { order: 1; }
  .platform-row .platform-copy { order: 2; }
}

/* Animated CLI panel ("CLI & API" row): plays once when scrolled into
   view (see main.js) — the command types itself out, then each output
   line lands in sequence, like a real terminal session replaying. */
.code-panel-anim .code-panel-cmd {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  width: 0;
  border-right: 2px solid transparent;
}
.code-panel-anim.is-playing .code-panel-cmd {
  animation:
    cp-type 1.3s steps(38, end) 0.3s forwards,
    cp-caret 0.7s step-end 5 1.6s;
  border-right-color: var(--accent-2);
}
@keyframes cp-type { to { width: 38ch; } }
@keyframes cp-caret { 50% { border-right-color: transparent; } }
.code-panel-anim .code-panel-line:not(.code-panel-line--cmd) {
  opacity: 0;
  transform: translateY(4px);
}
.code-panel-anim.is-playing .code-panel-line:not(.code-panel-line--cmd) {
  animation: cp-line-in 0.4s var(--ease) forwards;
}
@keyframes cp-line-in { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .code-panel-anim .code-panel-cmd { width: auto; border-right: none; animation: none; }
  .code-panel-anim .code-panel-line { opacity: 1; transform: none; animation: none; }
}

/* ---------------------------------------------------------------------------
   Touch target sizes (added 2026-10-09)

   On a 320px screen the audit found 503 non-inline links and buttons under
   40px tall. These are the shared ones. 44px is the usual floor; where an
   element's painted size is deliberate (the logo, the social circles) the
   rule grows the hit area rather than the artwork, except where the artwork
   IS the hit area and growing it is harmless.

   Inline text links are left alone on purpose — the target-size guidance
   exempts a link inside a run of text, and padding them out would break the
   line spacing of the paragraphs they sit in.
   --------------------------------------------------------------------------- */
@media (max-width: 860px) {
  .btn-sm { min-height: 44px; }

  /* The anchor grows; .nav-logo img keeps its own height, so the mark is
     unchanged and only the tappable box gets taller. */
  .nav-logo { min-height: 44px; }

  .nav-toggle { min-height: 44px; min-width: 44px; }

  /* A missed close button on an announcement bar is a real annoyance, and
     this one was 28px. */
  .announce-bar-close { min-height: 44px; min-width: 44px; }

  .hub-detail-back { min-height: 44px; }
  .hub-detail-cta { min-height: 44px; }

  /* 36px circles -> 44px. Four of them plus gaps is 200px, which still fits
     a 320px screen with the page gutters. */
  .footer-social a { width: 44px; height: 44px; }
}
