@import "tailwindcss";

@theme {
  --font-display: "Inter Tight", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Monochrome scale — the body of the page still lives here. */
  --color-paper: #fafafa;
  --color-ink: #0a0a0a;

  /* Brand green. Deliberately a DEEP forest green, well clear of the
     mid-green used for a healthy gauge, so brand surfaces and status
     readings never get mistaken for each other. */
  --color-brand: #0c4a2f;
  --color-brand-strong: #10613c;
  --color-lime: #4ade80;

  /* Status colors. These are DATA, not decoration: they appear only inside
     the dashboard mockup's gauges and the live-status dot. */
  --color-ok: #16a34a;
  --color-warn: #d97706;
  --color-crit: #dc2626;
}

@layer base {
  html {
    scroll-behavior: smooth;
  }

  /* "Back to top" animates the whole page height. Honour the OS setting. */
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
  }

  body {
    background-color: var(--color-paper);
    color: var(--color-ink);
    font-family: var(--font-sans);
    -webkit-font-smoothing: antialiased;
  }

  ::selection {
    background: var(--color-brand);
    color: #fff;
  }
}

@layer components {
  .header-login {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-width: 2.5rem;
    min-height: 2.5rem;
    padding: 0.5rem;
    border: 1px solid var(--color-neutral-200);
    border-radius: 9999px;
    background: #fff;
    color: #000;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    transition: background-color 180ms ease, border-color 180ms ease;
  }
  .header-login:hover { background: var(--color-neutral-100); border-color: var(--color-neutral-400); }
  @media (min-width: 640px) { .header-login { padding-inline: 0.875rem; } }
  .header-login:focus-visible,
  .auth-page a:focus-visible,
  .auth-page button:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 3px;
  }
  .auth-page { min-height: 100svh; display: flex; flex-direction: column; }
  .auth-main { flex: 1; padding: 2rem 1.25rem; }
  .auth-shell {
    display: grid;
    grid-template-columns: minmax(0, 26rem) minmax(0, 1fr);
    gap: 1.5rem;
    width: min(100%, 72rem);
    margin-inline: auto;
    align-items: stretch;
  }
  .auth-content {
    width: 100%;
    min-height: 42rem;
    padding: clamp(1.25rem, 3vw, 2.5rem);
    border: 1px solid var(--color-neutral-200);
    border-radius: 20px;
    background: #fff;
    box-shadow: 0 24px 70px rgba(10, 10, 10, 0.06);
  }
  .auth-eyebrow { color: var(--color-brand); font-size: 12px; font-weight: 500; }
  .auth-content h1 { margin-top: 0.875rem; font-size: 32px; line-height: 1.15; letter-spacing: 0; }
  .auth-description { margin-top: 0.75rem; color: var(--color-neutral-500); font-size: 14px; line-height: 1.6; }
  .auth-tabs { display: grid; grid-template-columns: 1fr 1fr; margin-top: 2rem; border-bottom: 1px solid var(--color-neutral-200); }
  .auth-tabs a { padding: 0.875rem 0.5rem; border-bottom: 2px solid transparent; text-align: center; font-size: 14px; color: var(--color-neutral-500); }
  .auth-tabs a[aria-current] { border-color: var(--color-brand); color: var(--color-brand); font-weight: 500; }
  .auth-notice { margin-block: 1.5rem; padding-left: 0.875rem; border-left: 2px solid var(--color-neutral-300); color: var(--color-neutral-500); font-size: 12px; line-height: 1.7; }
  .auth-field { margin-bottom: 1.25rem; }
  .auth-field label { display: block; font-size: 13px; font-weight: 500; }
  .auth-field input {
    display: block;
    width: 100%;
    height: 46px;
    margin-top: 0.5rem;
    border: 1px solid var(--color-neutral-300);
    border-radius: 8px;
    background: #fff;
    padding: 0.75rem;
    font-size: 16px;
    outline: none;
  }
  .auth-field input:focus { border-color: var(--color-brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 10%, transparent); }
  .auth-field input:user-invalid { border-color: var(--color-crit); }
  .auth-field input::placeholder { color: var(--color-neutral-400); }
  .auth-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; font-size: 12px; }
  .auth-link { color: var(--color-brand); text-underline-offset: 3px; }
  .auth-link:hover { text-decoration: underline; }
  .auth-password { position: relative; }
  .auth-password input { padding-right: 4rem; }
  .auth-password button { position: absolute; right: 3px; top: 3px; width: 3.5rem; height: 40px; color: var(--color-neutral-600); font-size: 12px; cursor: pointer; border-radius: 6px; }
  .auth-password button:hover { color: var(--color-brand); background: var(--color-neutral-100); }
  .auth-hint { margin-top: 0.5rem; font-size: 12px; color: var(--color-neutral-500); }
  .auth-consent { display: flex; align-items: start; gap: 0.625rem; margin-block: 0.25rem 1.5rem; font-size: 12px; line-height: 1.7; color: var(--color-neutral-600); }
  .auth-consent input { flex: 0 0 16px; width: 16px; height: 16px; margin-top: 3px; accent-color: var(--color-brand); }
  .auth-submit { width: 100%; min-height: 46px; justify-content: center; font-size: 14px; cursor: pointer; }
  .auth-message { margin-top: 1rem; font-size: 13px; line-height: 1.7; color: var(--color-brand); }
  .auth-message:empty { margin-top: 0; }
  .auth-visual {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    min-height: 42rem;
    padding: clamp(1.25rem, 3vw, 2.25rem);
    border-radius: 20px;
    background:
      radial-gradient(circle at 82% 12%, rgba(74, 222, 128, 0.24), transparent 28rem),
      linear-gradient(145deg, #073821 0%, #0c4a2f 46%, #092b1c 100%);
    color: #fff;
  }
  .auth-visual::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: radial-gradient(circle, rgba(255, 255, 255, 0.18) 1px, transparent 1px);
    background-size: 22px 22px;
    opacity: 0.28;
    pointer-events: none;
  }
  .auth-visual > * { position: relative; z-index: 1; }
  .auth-visual-copy { max-width: 30rem; }
  .auth-visual-logo {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    color: #fff;
  }
  .auth-visual-logo .display {
    font-size: 18px;
    line-height: 1;
  }
  .auth-visual-logo .display span { color: rgba(255, 255, 255, 0.46); }
  .auth-visual-logo-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.08);
  }
  .auth-visual-logo-mark svg { width: 1.125rem; height: 1.125rem; }
  .auth-visual-kicker {
    margin-top: clamp(1.75rem, 4vw, 3.5rem);
    color: var(--color-lime);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .auth-visual h2 {
    margin-top: 0.75rem;
    max-width: 13em;
    font-size: clamp(1.8rem, 3vw, 3rem);
    line-height: 1.04;
    letter-spacing: 0;
  }
  .auth-visual-text {
    max-width: 30rem;
    margin-top: 1rem;
    color: rgba(255, 255, 255, 0.72);
    font-size: 14px;
    line-height: 1.7;
  }
  .auth-preview-card {
    overflow: hidden;
    width: min(100%, 30rem);
    margin: 1.75rem 0 1.25rem auto;
    padding: 1rem;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.08);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.28);
  }
  .auth-preview-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    color: rgba(255, 255, 255, 0.58);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
  }
  .auth-preview-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
    margin-top: 1rem;
  }
  .auth-preview-grid div {
    min-height: 5.25rem;
    padding: 0.875rem;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.08);
  }
  .auth-preview-grid span {
    display: block;
    color: rgba(255, 255, 255, 0.58);
    font-size: 11px;
    font-weight: 500;
  }
  .auth-preview-grid strong {
    display: block;
    margin-top: 0.5rem;
    color: #fff;
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3vw, 2rem);
    line-height: 1;
  }
  .auth-preview-line {
    overflow: hidden;
    height: 0.5rem;
    margin-top: 1rem;
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.12);
  }
  .auth-preview-line span {
    display: block;
    width: 68%;
    height: 100%;
    border-radius: inherit;
    background: var(--color-lime);
  }
  .auth-preview-card p {
    margin-top: 1rem;
    color: rgba(255, 255, 255, 0.68);
    font-size: 12px;
    line-height: 1.6;
  }
  .auth-trust {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.75rem 1rem;
    align-items: center;
    max-width: 30rem;
    margin-left: auto;
    padding: 1rem;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(18px);
  }
  .auth-trust-label {
    color: rgba(255, 255, 255, 0.72);
    font-size: 12px;
    font-weight: 500;
  }
  .auth-trust-score {
    margin-top: 0.2rem;
    font-size: 20px;
    font-weight: 700;
  }
  .auth-stars {
    display: inline-flex;
    gap: 0.25rem;
    color: var(--color-lime);
    font-size: 17px;
    letter-spacing: 0;
  }
  .auth-trust-note {
    grid-column: 1 / -1;
    color: rgba(255, 255, 255, 0.52);
    font-size: 11px;
  }
  .auth-footer { display: flex; justify-content: center; flex-wrap: wrap; gap: 1.5rem; padding: 1.5rem; border-top: 1px solid var(--color-neutral-200); color: var(--color-neutral-500); font-size: 12px; }
  .auth-footer a:hover { color: var(--color-brand); }
  @media (max-width: 900px) {
    .auth-shell { grid-template-columns: 1fr; max-width: 40rem; }
    .auth-content,
    .auth-visual { min-height: auto; }
    .auth-visual { order: -1; }
    .auth-visual h2 { font-size: clamp(1.75rem, 7vw, 2.75rem); }
    .auth-preview-card,
    .auth-trust { margin-left: 0; }
  }
  @media (max-width: 480px) {
    .auth-main { padding: 1rem; }
    .auth-content,
    .auth-visual { border-radius: 16px; }
    .auth-preview-grid { gap: 0.5rem; }
    .auth-preview-grid div { min-height: 4.75rem; padding: 0.75rem; }
    .auth-trust { grid-template-columns: 1fr; }
  }

  /* Parallax dot field.
     .hero-field carries the perspective and the fade mask. The stage holds
     three dot layers at real Z depths, each scaled to compensate for the
     perspective divide so all three read at the intended density. Rotating
     the stage on cursor move makes the layers separate — that separation is
     the depth cue, not a filter or a shadow.
     JS only writes --px/--py/--mx/--my; every default here is the resting
     state, so the field renders correctly with no JS at all. */
  .hero-field {
    overflow: hidden;
    perspective: 900px;
    -webkit-mask-image: radial-gradient(ellipse 90% 65% at 50% 22%, #000 0%, transparent 78%);
    mask-image: radial-gradient(ellipse 90% 65% at 50% 22%, #000 0%, transparent 78%);
  }

  .hero-field__stage {
    position: absolute;
    inset: -10%;
    transform-style: preserve-3d;
    transform:
      rotateX(calc(var(--py, 0) * -5deg))
      rotateY(calc(var(--px, 0) * 5deg))
      translate3d(calc(var(--px, 0) * -14px), calc(var(--py, 0) * -14px), 0);
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .dot-layer {
    position: absolute;
    inset: 0;
    background-repeat: repeat;
  }

  /* scale = (perspective + |z|) / perspective, so each layer keeps its size. */
  .dot-layer--far {
    background-image: radial-gradient(circle, rgba(10, 10, 10, 0.11) 1px, transparent 1px);
    background-size: 46px 46px;
    transform: translateZ(-300px) scale(1.3334);
  }

  .dot-layer--mid {
    background-image: radial-gradient(circle, rgba(10, 10, 10, 0.15) 1px, transparent 1px);
    background-size: 26px 26px;
    transform: translateZ(-150px) scale(1.1667);
  }

  .dot-layer--near {
    background-image: radial-gradient(circle, rgba(10, 10, 10, 0.22) 1px, transparent 1px);
    background-size: 14px 14px;
  }

  /* The actual effect: a brand-green copy of the near grid, revealed only
     inside a soft circle at the cursor. It sits inside the stage so it shares
     the near layer's grid exactly — the green dots land on the black ones
     rather than beside them. */
  .dot-layer--spot {
    background-image: radial-gradient(circle, var(--color-brand) 2px, transparent 2px);
    background-size: 14px 14px;
    opacity: 0;
    -webkit-mask-image: radial-gradient(240px circle at var(--mx, 50%) var(--my, 34%), #000 0%, rgba(0, 0, 0, 0.4) 48%, transparent 74%);
    mask-image: radial-gradient(240px circle at var(--mx, 50%) var(--my, 34%), #000 0%, rgba(0, 0, 0, 0.4) 48%, transparent 74%);
    transition: opacity 500ms ease;
  }

  .hero-field.is-tracking .dot-layer--spot {
    opacity: 1;
  }

  /* Cursor glow. Rests centred and dim; JS moves it and raises the opacity
     while the pointer is over the hero. */
  .hero-glow {
    position: absolute;
    inset: 0;
    opacity: 0;
    background: radial-gradient(
      340px circle at var(--mx, 50%) var(--my, 34%),
      color-mix(in srgb, var(--color-brand) 12%, transparent),
      transparent 70%
    );
    transition: opacity 450ms ease;
  }

  .hero-field.is-tracking .hero-glow {
    opacity: 1;
  }

  @media (prefers-reduced-motion: reduce) {
    .hero-field__stage { transition: none; }
    .hero-glow,
    .dot-layer--spot { display: none; }
  }

  .card-dashed {
    @apply rounded-2xl border border-dashed border-neutral-300 bg-white/70 transition-colors duration-200;
  }

  .card-dashed:hover {
    @apply border-neutral-400 bg-white;
  }

  /* The header has two states. At the top of the page it is a flush,
     transparent, full-width bar. Past the scroll threshold JS adds
     --floating and it becomes the detached pill. Every property that
     differs between the two is transitioned, so it morphs rather than
     snaps. */
  .site-nav {
    max-width: 80rem;
    margin-top: 0;
    padding: 1rem 0.75rem 1rem 0.5rem;
    border: 1px solid transparent;
    border-radius: 0;
    background-color: transparent;
    /* Same gradient structure as the floating state, but fully transparent,
       so the two states interpolate instead of the sheen popping in. */
    background-image: linear-gradient(
      180deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, 0) 45%,
      rgba(255, 255, 255, 0) 100%
    );
    box-shadow: none;
    transition:
      max-width 420ms cubic-bezier(0.16, 1, 0.3, 1),
      margin-top 420ms cubic-bezier(0.16, 1, 0.3, 1),
      padding 420ms cubic-bezier(0.16, 1, 0.3, 1),
      border-radius 420ms cubic-bezier(0.16, 1, 0.3, 1),
      border-color 300ms ease,
      background-color 300ms ease,
      background-image 300ms ease,
      box-shadow 300ms ease;
  }

  .site-nav--floating {
    max-width: 64rem;
    margin-top: 0.875rem;
    padding: 0.625rem 0.625rem 0.625rem 1.25rem;
    border-radius: 9999px;

    /* Glass. Three things make it read as glass rather than as a translucent
       rectangle:
       1. a vertical sheen — brightest at the top edge, thinnest through the
          middle, lifting again at the bottom, the way light falls on a curved
          surface;
       2. a specular rim: a white border plus inset highlights on the top and
          bottom edges, which is what separates glass from frosted plastic;
       3. saturation boost on the backdrop, so colour passing underneath
          intensifies through the panel instead of going flat and grey. */
    background-color: rgba(255, 255, 255, 0.38);
    background-image: linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.72) 0%,
      rgba(255, 255, 255, 0.28) 45%,
      rgba(255, 255, 255, 0.5) 100%
    );
    border-color: rgba(255, 255, 255, 0.7);
    -webkit-backdrop-filter: blur(28px) saturate(1.9);
    backdrop-filter: blur(28px) saturate(1.9);
    box-shadow:
      inset 0 1px 0 0 rgba(255, 255, 255, 0.95),
      inset 0 -1px 0 0 rgba(255, 255, 255, 0.4),
      inset 0 0 24px 0 rgba(255, 255, 255, 0.3),
      0 0 0 1px rgba(10, 10, 10, 0.05),
      0 2px 6px -2px rgba(10, 10, 10, 0.06),
      0 18px 44px -20px rgba(12, 74, 47, 0.4);
  }

  /* No backdrop-filter (older Firefox, some embedded webviews): fall back to
     a mostly opaque panel so the nav never becomes unreadable. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .site-nav--floating {
      background-color: rgba(255, 255, 255, 0.94);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .site-nav { transition: none; }
  }

  /* Mobile menu button. Two bars that rotate into a cross — state is driven
     entirely by aria-expanded, so the visual and the accessible state cannot
     drift apart. */
  .menu-toggle {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    width: 2.25rem;
    border-radius: 9999px;
    color: var(--color-neutral-700);
    cursor: pointer;
    transition: background-color 200ms ease, color 200ms ease;
  }

  .menu-toggle:hover {
    background-color: color-mix(in srgb, var(--color-brand) 8%, transparent);
    color: var(--color-brand);
  }

  .menu-toggle__bar {
    position: absolute;
    height: 1.5px;
    width: 1.0625rem;
    border-radius: 2px;
    background: currentColor;
    transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .menu-toggle__bar:nth-child(1) { transform: translateY(-3.5px); }
  .menu-toggle__bar:nth-child(2) { transform: translateY(3.5px); }

  .menu-toggle[aria-expanded='true'] .menu-toggle__bar:nth-child(1) { transform: rotate(45deg); }
  .menu-toggle[aria-expanded='true'] .menu-toggle__bar:nth-child(2) { transform: rotate(-45deg); }

  .mobile-menu {
    margin: 0.5rem auto 0;
    max-width: 64rem;
    padding: 0.5rem;
    border: 1px solid rgba(255, 255, 255, 0.7);
    border-radius: 1.25rem;
    background-color: rgba(255, 255, 255, 0.78);
    -webkit-backdrop-filter: blur(28px) saturate(1.9);
    backdrop-filter: blur(28px) saturate(1.9);
    box-shadow:
      inset 0 1px 0 0 rgba(255, 255, 255, 0.95),
      0 0 0 1px rgba(10, 10, 10, 0.05),
      0 18px 44px -20px rgba(12, 74, 47, 0.4);
    opacity: 0;
    transform: translateY(-8px) scale(0.985);
    transform-origin: top center;
    pointer-events: none;
    transition:
      opacity 240ms ease,
      transform 240ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .mobile-menu.is-open {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .mobile-menu a {
    display: block;
    padding: 0.75rem 1rem;
    border-radius: 0.75rem;
    font-size: 15px;
    color: var(--color-neutral-700);
    transition: background-color 180ms ease, color 180ms ease;
  }

  .mobile-menu a:hover,
  .mobile-menu a:focus-visible {
    background-color: color-mix(in srgb, var(--color-brand) 8%, transparent);
    color: var(--color-brand);
  }

  @media (prefers-reduced-motion: reduce) {
    .menu-toggle__bar,
    .mobile-menu { transition: none; }
  }

  .pill {
    @apply inline-flex items-center gap-2 rounded-full border border-neutral-200 bg-white/80 px-3 py-1.5 text-[11px] font-medium tracking-[0.12em] uppercase text-neutral-600;
  }

  .btn-primary {
    @apply relative inline-flex items-center justify-center gap-1.5 rounded-full px-5 py-3 text-sm font-medium text-white;
    background: linear-gradient(180deg, var(--color-brand-strong) 0%, var(--color-brand) 100%);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.16),
      0 1px 1px rgba(12, 74, 47, 0.18);
    outline-color: var(--color-brand);
    transition:
      background 200ms ease,
      box-shadow 200ms ease,
      transform 200ms ease;
  }

  .btn-primary:hover {
    background: linear-gradient(180deg, #14744a 0%, var(--color-brand-strong) 100%);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.22),
      0 10px 24px -12px rgba(12, 74, 47, 0.6);
    transform: translateY(-1px);
  }

  .btn-primary:active {
    transform: translateY(0);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
  }

  .btn-primary:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 3px;
  }

  .btn-primary:disabled,
  .btn-primary[aria-busy='true'] {
    cursor: wait;
    opacity: 0.78;
    transform: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  }

  .btn-primary .btn-icon {
    width: 0.85rem;
    height: 0.85rem;
    flex-shrink: 0;
    transition: transform 200ms ease;
  }

  .btn-primary:hover .btn-icon {
    transform: translateX(2px);
  }

  .btn-primary[aria-busy='true'] .btn-icon {
    display: none;
  }

  /* Lime CTA on the dark Pro card — same mechanics, inverted palette. */
  .btn-pro-cta {
    @apply mt-6 inline-flex w-full items-center justify-center gap-1.5 rounded-full px-5 py-2.5 text-[13.5px] font-medium;
    color: var(--color-brand);
    background: var(--color-lime);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45);
    transition:
      background-color 200ms ease,
      box-shadow 200ms ease,
      transform 200ms ease;
  }

  .btn-pro-cta:hover {
    background: #fff;
    transform: translateY(-1px);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.7),
      0 10px 20px -12px rgba(0, 0, 0, 0.35);
  }

  .btn-pro-cta:active {
    transform: translateY(0);
  }

  .btn-pro-cta .btn-icon {
    width: 0.85rem;
    height: 0.85rem;
    flex-shrink: 0;
    transition: transform 200ms ease;
  }

  .btn-pro-cta:hover .btn-icon {
    transform: translateX(2px);
  }

  @media (prefers-reduced-motion: reduce) {
    .btn-primary,
    .btn-pro-cta,
    .btn-primary .btn-icon,
    .btn-pro-cta .btn-icon {
      transition: background-color 200ms ease, box-shadow 200ms ease;
    }

    .btn-primary:hover,
    .btn-pro-cta:hover {
      transform: none;
    }

    .btn-primary:hover .btn-icon,
    .btn-pro-cta:hover .btn-icon {
      transform: none;
    }
  }

  .btn-ghost {
    @apply inline-flex items-center justify-center gap-2 rounded-full border border-neutral-300 bg-white px-5 py-3 text-sm font-medium text-neutral-800 transition-colors duration-200 hover:border-neutral-400 hover:bg-neutral-50;
  }

  /* Full-bleed logo marquee. Two identical tracks sit side by side and both
     translate a full track width, so the seam is never visible. Duration is
     per-row via --marquee-duration; --marquee--reverse flips direction. */
  .marquee {
    display: flex;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  }

  .marquee__track {
    display: flex;
    flex: 0 0 auto;
    gap: 0.75rem;
    padding-right: 0.75rem;
    animation: marquee-scroll var(--marquee-duration, 48s) linear infinite;
    will-change: transform;
  }

  .marquee--reverse .marquee__track {
    animation-direction: reverse;
  }

  .marquee:hover .marquee__track {
    animation-play-state: paused;
  }

  @keyframes marquee-scroll {
    from { transform: translateX(0); }
    to { transform: translateX(-100%); }
  }

  .logo-card {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    min-width: 11.5rem;
    padding: 1.375rem 2rem;
    border: 1px solid rgba(10, 10, 10, 0.06);
    border-radius: 0.875rem;
    background: #fff;
    box-shadow:
      0 1px 2px rgba(10, 10, 10, 0.04),
      0 10px 24px -18px rgba(12, 74, 47, 0.35);
  }

  @media (min-width: 640px) {
    .logo-card { min-width: 13.5rem; }
  }

  /* No motion: the rows become plain horizontal scrollers instead. */
  @media (prefers-reduced-motion: reduce) {
    .marquee { overflow-x: auto; }
    .marquee__track { animation: none; }
  }

  /* Oversized ghosted wordmark. Scales with the viewport so it always spans
     the footer, and sits just above the surface in luminance — legible as a
     shape, never as a competing block of text. */
  .footer-ghost {
    font-size: clamp(3.25rem, 15.5vw, 12rem);
    line-height: 0.85;
    letter-spacing: -0.05em;
    color: rgba(255, 255, 255, 0.07);
    white-space: nowrap;
  }

  /* Footer links sit on near-black, where the brand green outline used
     elsewhere would barely register — so the ring is lime, the one accent
     already carrying interaction in this section. */
  .footer-link {
    border-radius: 0.25rem;
    transition: color 180ms ease;
  }
  .footer-link:hover { color: var(--color-lime); }
  .footer-link:focus-visible {
    outline: 2px solid var(--color-lime);
    outline-offset: 3px;
    color: var(--color-lime);
  }

  .footer-dots {
    background-image: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
    background-size: 16px 16px;
    -webkit-mask-image: linear-gradient(180deg, #000, transparent 75%);
    mask-image: linear-gradient(180deg, #000, transparent 75%);
  }

  /* Feature card icon tile. Brand green on a faint green wash — the only
     place green appears in the light body of the page besides CTAs. */
  .feature-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    width: 2.25rem;
    border-radius: 0.625rem;
    background: color-mix(in srgb, var(--color-brand) 8%, transparent);
    color: var(--color-brand);
  }

  /* Pricing backdrop: a pale green ground with two soft corner glows.
     The glow colour is a mid green rather than the deep brand green — deep
     forest at low alpha turns grey and muddy when spread this wide, so it
     needs a more saturated green to stay green as it fades. */
  .pricing-field {
    background-color: #f4faf7;
    background-image:
      radial-gradient(58% 72% at 0% 0%, rgba(34, 150, 87, 0.3), rgba(34, 150, 87, 0) 62%),
      radial-gradient(52% 66% at 100% 100%, rgba(34, 150, 87, 0.26), rgba(34, 150, 87, 0) 64%);
  }

  /* 3D glass pricing cards.
     The grid supplies the perspective; each card sits on the Z axis and moves
     toward the viewer on hover, so the lift is a real perspective change
     rather than a scale. Glass reads through the same three cues as the nav:
     a diagonal sheen, a specular rim, and a saturated backdrop so the green
     field behind intensifies through the panel. */
  .pricing-grid {
    perspective: 1200px;
  }

  .price-card {
    position: relative;
    border-radius: 1rem;
    border: 1px solid transparent;
    transform: translate3d(0, 0, 0);
    transform-style: preserve-3d;
    -webkit-backdrop-filter: blur(20px) saturate(1.7);
    backdrop-filter: blur(20px) saturate(1.7);
    transition:
      transform 480ms cubic-bezier(0.16, 1, 0.3, 1),
      box-shadow 480ms ease;
  }

  .price-card:hover {
    transform: translate3d(0, -6px, 28px);
  }

  .price-card--free {
    background-color: rgba(255, 255, 255, 0.55);
    background-image: linear-gradient(
      158deg,
      rgba(255, 255, 255, 0.88) 0%,
      rgba(255, 255, 255, 0.24) 44%,
      rgba(255, 255, 255, 0.52) 100%
    );
    border-color: rgba(255, 255, 255, 0.85);
    box-shadow:
      inset 0 1px 0 0 rgba(255, 255, 255, 0.95),
      inset 0 -1px 0 0 rgba(255, 255, 255, 0.5),
      inset 0 0 32px 0 rgba(255, 255, 255, 0.35),
      0 0 0 1px rgba(12, 74, 47, 0.05),
      0 18px 38px -24px rgba(12, 74, 47, 0.45);
  }

  .price-card--free:hover {
    box-shadow:
      inset 0 1px 0 0 rgba(255, 255, 255, 1),
      inset 0 -1px 0 0 rgba(255, 255, 255, 0.55),
      inset 0 0 32px 0 rgba(255, 255, 255, 0.4),
      0 0 0 1px rgba(12, 74, 47, 0.06),
      0 34px 60px -28px rgba(12, 74, 47, 0.5);
  }

  .price-card--pro {
    /* Flat green — no gradient, no sheen. backdrop-filter is dropped too:
       nothing shows through an opaque surface, so it would only cost paint. */
    background-color: #0f6a41;
    background-image: none;
    border-color: rgba(255, 255, 255, 0.14);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow:
      0 0 0 1px rgba(10, 10, 10, 0.06),
      0 22px 46px -26px rgba(12, 74, 47, 0.7);
  }

  .price-card--pro:hover {
    box-shadow:
      0 0 0 1px rgba(10, 10, 10, 0.07),
      0 38px 68px -28px rgba(12, 74, 47, 0.78);
  }

  /* Without backdrop-filter the panels would be washed-out flat colour, so
     fall back to opaque surfaces instead. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .price-card--free { background-color: rgba(255, 255, 255, 0.96); }
    .price-card--pro { background-color: #0f6a41; }
  }

  @media (prefers-reduced-motion: reduce) {
    .price-card { transition: box-shadow 480ms ease; }
    .price-card:hover { transform: translate3d(0, 0, 0); }
  }

  /* Billing toggle. The active state is a single sliding thumb whose position
     and width are measured in JS — the two labels are different widths, so a
     50% thumb cannot work. State lives entirely in aria-pressed; nothing here
     depends on class toggling. */
  .billing-toggle {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem;
    border: 1px solid rgba(12, 74, 47, 0.12);
    border-radius: 9999px;
    background-color: rgba(255, 255, 255, 0.7);
    -webkit-backdrop-filter: blur(14px) saturate(1.5);
    backdrop-filter: blur(14px) saturate(1.5);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
  }

  .billing-toggle__thumb {
    position: absolute;
    top: 0.25rem;
    bottom: 0.25rem;
    left: 0;
    width: var(--thumb-w, 0);
    border-radius: 9999px;
    background: linear-gradient(160deg, rgba(23, 133, 79, 1) 0%, rgba(12, 74, 47, 1) 100%);
    box-shadow: 0 6px 16px -8px rgba(12, 74, 47, 0.7);
    opacity: 0;
    transform: translateX(var(--thumb-x, 0));
    transition:
      transform 420ms cubic-bezier(0.16, 1, 0.3, 1),
      width 420ms cubic-bezier(0.16, 1, 0.3, 1),
      opacity 200ms ease;
  }

  /* Hidden until measured, so it never flashes at width 0 in the corner. */
  .billing-toggle.is-ready .billing-toggle__thumb {
    opacity: 1;
  }

  .billing-toggle__btn {
    position: relative;
    z-index: 1;
    border-radius: 9999px;
    padding: 0.375rem 1rem;
    font-size: 13px;
    font-weight: 500;
    color: var(--color-neutral-600);
    cursor: pointer;
    transition: color 280ms ease;
  }

  .billing-toggle__btn[aria-pressed='true'] {
    color: #fff;
  }

  .billing-toggle__note {
    color: var(--color-neutral-500);
    transition: color 280ms ease;
  }

  .billing-toggle__btn[aria-pressed='true'] .billing-toggle__note {
    color: rgba(255, 255, 255, 0.62);
  }

  /* The price changes width between $79 and $9, so it fades and lifts across
     the swap instead of snapping to a new number mid-layout. */
  .price-value {
    transition:
      opacity 170ms ease,
      transform 170ms ease;
  }

  .price-value.is-swapping {
    opacity: 0;
    transform: translateY(-6px);
  }

  @media (prefers-reduced-motion: reduce) {
    .billing-toggle__thumb,
    .price-value {
      transition: none;
    }
  }

  /* ------------------------------------------------------------ docs ---- */
  .skip-link {
    position: absolute;
    left: 0.75rem;
    top: -3rem;
    z-index: 100;
    border-radius: 9999px;
    background: var(--color-brand);
    padding: 0.6rem 1.1rem;
    font-size: 14px;
    color: #fff;
    transition: top 180ms ease;
  }

  .skip-link:focus {
    top: 0.75rem;
  }

  .docs-topbar > a { min-width: 0; }

  .docs-topbar {
    position: sticky;
    top: 0;
    /* Above the drawer (45) and its backdrop (44), so the close button stays
       crisp and tappable while the drawer is open. */
    z-index: 46;
    display: flex;
    align-items: center;
    gap: 1rem;
    border-bottom: 1px solid var(--color-neutral-200);
    background: rgba(250, 250, 250, 0.85);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    padding: 0.875rem 1.25rem;
  }

  /* Below sm the logo, search and menu button cannot share a row: the search
     pushed the button off screen. Search drops to its own line instead. */
  @media (max-width: 639px) {
    .docs-topbar { flex-wrap: wrap; gap: 0.625rem; padding: 0.625rem 1rem 0.75rem; }
    .docs-search { padding: 0.4rem 0.7rem; }
    .docs-search {
      order: 3;
      flex-basis: 100%;
      max-width: none;
      margin: 0;
    }
  }

  .docs-search {
    display: flex;
    flex: 1;
    align-items: center;
    gap: 0.6rem;
    max-width: 34rem;
    margin: 0 auto;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-neutral-200);
    border-radius: 0.75rem;
    background: #fff;
    transition: border-color 180ms ease, box-shadow 180ms ease;
  }

  .docs-search:focus-within {
    border-color: color-mix(in srgb, var(--color-brand) 45%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 12%, transparent);
  }

  .docs-search input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    font-size: 14px;
    color: var(--color-neutral-900);
    outline: none;
  }

  .docs-search input::placeholder { color: var(--color-neutral-400); }
  .docs-search input::-webkit-search-cancel-button { appearance: none; }

  .docs-search kbd {
    flex-shrink: 0;
    border: 1px solid var(--color-neutral-200);
    border-radius: 0.375rem;
    padding: 0.125rem 0.375rem;
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--color-neutral-500);
  }

  .docs-shell {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
    max-width: 96rem;
    margin: 0 auto;
    padding: 0 1.25rem;
  }

  @media (min-width: 1024px) {
    .docs-shell {
      grid-template-columns: 16rem minmax(0, 1fr) 14rem;
      gap: 3rem;
    }
  }

  .docs-sidebar {
    padding: 2rem 0;
  }

  @media (min-width: 1024px) {
    .docs-sidebar {
      position: sticky;
      top: calc(var(--topbar-h, 4rem) + 1rem);
      align-self: start;
      max-height: calc(100vh - var(--topbar-h, 4rem) - 2rem);
      overflow-y: auto;
      border-right: 1px solid var(--color-neutral-200);
      padding-right: 1.25rem;
    }
  }

  /* Below lg the sidebar becomes a disclosure driven by the same button
     pattern as the landing page nav. */
  /* Below lg the sidebar is an overlay drawer. As a static block it pushed the
     article ~770px down the page, so opening the menu looked like navigating
     away from the article you were reading. */
  @media (max-width: 1023px) {
    .docs-sidebar {
      display: none;
      position: fixed;
      z-index: 45;
      top: var(--topbar-h, 4rem);
      left: 0;
      right: 0;
      bottom: 0;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      background: var(--color-paper);
      padding: 1.5rem 1.5rem 3rem;
      box-shadow: 0 18px 44px -20px rgba(12, 74, 47, 0.35);
    }

    .docs-sidebar.is-open { display: block; }

    .docs-backdrop {
      position: fixed;
      z-index: 44;
      inset: 0;
      background: rgba(10, 10, 10, 0.25);
      -webkit-backdrop-filter: blur(2px);
      backdrop-filter: blur(2px);
    }

    /* Bigger tap targets once the links are a full-screen list. */
    .docs-sidebar a { padding: 0.6rem 0.7rem; font-size: 15px; }
  }

  .docs-backdrop[hidden] { display: none; }

  .docs-group {
    margin-top: 1.75rem;
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--color-neutral-500);
  }

  .docs-group:first-child { margin-top: 0; }

  .docs-sidebar ul { margin-top: 0.5rem; }

  .docs-sidebar a {
    display: block;
    border-radius: 0.5rem;
    padding: 0.4rem 0.6rem;
    font-size: 14px;
    color: var(--color-neutral-600);
    transition: background-color 160ms ease, color 160ms ease;
  }

  .docs-sidebar a:hover,
  .docs-sidebar a:focus-visible {
    background: color-mix(in srgb, var(--color-brand) 7%, transparent);
    color: var(--color-brand);
  }

  .docs-sidebar a.is-current {
    background: color-mix(in srgb, var(--color-brand) 9%, transparent);
    color: var(--color-brand);
    font-weight: 500;
  }

  .docs-search-empty {
    margin-top: 1rem;
    padding: 0 0.6rem;
    font-size: 14px;
    color: var(--color-neutral-500);
  }

  .docs-main {
    min-width: 0;
    padding: 2.5rem 0 5rem;
  }

  /* The topbar is 122px on mobile (search wraps to its own row) and ~57px on
     desktop. A fixed scroll-margin left every anchor landing under it, so
     docs.js measures the bar into --topbar-h. */
  .docs-main section {
    margin-top: 3.5rem;
    scroll-margin-top: calc(var(--topbar-h, 4rem) + 1.25rem);
  }

  .docs-main h2 {
    font-size: 26px;
    letter-spacing: -0.03em;
    color: var(--color-neutral-950);
  }

  .docs-main section > p { margin-top: 1rem; line-height: 1.75; color: var(--color-neutral-700); }
  .docs-main a { color: var(--color-brand); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--color-brand) 35%, transparent); }
  .docs-main a:hover { text-decoration-color: var(--color-brand); }

  .docs-main code {
    border-radius: 0.375rem;
    background: color-mix(in srgb, var(--color-brand) 7%, transparent);
    padding: 0.1rem 0.35rem;
    font-family: var(--font-mono);
    font-size: 0.86em;
    color: var(--color-brand);
  }

  .docs-callout {
    margin-top: 1.75rem;
    border-radius: 0.875rem;
    border: 1px dashed var(--color-warn);
    background: color-mix(in srgb, var(--color-warn) 6%, transparent);
    padding: 1.125rem 1.25rem;
    font-size: 14px;
    line-height: 1.7;
    color: var(--color-neutral-700);
  }

  .docs-planned {
    display: inline-block;
    border-radius: 9999px;
    border: 1px solid color-mix(in srgb, var(--color-warn) 35%, transparent);
    background: color-mix(in srgb, var(--color-warn) 8%, transparent);
    padding: 0.2rem 0.7rem;
    font-family: var(--font-mono);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: #8a5209;
  }

  .docs-table {
    width: 100%;
    margin-top: 1.25rem;
    border: 1px solid var(--color-neutral-200);
    border-radius: 0.75rem;
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
    font-size: 14px;
  }

  .docs-table th {
    background: color-mix(in srgb, var(--color-brand) 5%, transparent);
    text-align: left;
    font-weight: 500;
    color: var(--color-neutral-800);
  }

  .docs-table th,
  .docs-table td {
    border-bottom: 1px solid var(--color-neutral-200);
    padding: 0.75rem 1rem;
    vertical-align: top;
    color: var(--color-neutral-700);
  }

  .docs-table tr:last-child td { border-bottom: 0; }

  .docs-steps { margin-top: 1.25rem; counter-reset: step; }

  .docs-steps li {
    position: relative;
    margin-top: 1rem;
    padding-left: 2.25rem;
    line-height: 1.75;
    color: var(--color-neutral-700);
  }

  .docs-steps li::before {
    counter-increment: step;
    content: counter(step);
    position: absolute;
    left: 0;
    top: 0.1rem;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 1.5rem;
    width: 1.5rem;
    border-radius: 9999px;
    background: color-mix(in srgb, var(--color-brand) 10%, transparent);
    font-size: 12px;
    font-weight: 500;
    color: var(--color-brand);
  }

  .docs-list { margin-top: 1rem; }

  .docs-list li {
    position: relative;
    margin-top: 0.6rem;
    padding-left: 1.1rem;
    line-height: 1.75;
    color: var(--color-neutral-700);
  }

  .docs-list li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.75rem;
    height: 4px;
    width: 4px;
    border-radius: 9999px;
    background: var(--color-brand);
  }

  /* Tables carry code identifiers that must not be broken across lines, so
     they scroll horizontally rather than squash. The metrics table was 381px
     wide inside a 375px viewport. */
  .docs-table-wrap {
    margin-top: 1.25rem;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border-radius: 0.75rem;
  }

  .docs-table-wrap .docs-table {
    margin-top: 0;
    min-width: 30rem;
  }

  .docs-toc-mobile {
    margin-top: 1.75rem;
    border: 1px solid var(--color-neutral-200);
    border-radius: 0.875rem;
    background: #fff;
    padding: 0.25rem 0.5rem;
  }

  @media (min-width: 1024px) {
    .docs-toc-mobile { display: none; }
  }

  .docs-toc-mobile summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    cursor: pointer;
    list-style: none;
    padding: 0.75rem 0.6rem;
    font-size: 12px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--color-neutral-600);
  }

  .docs-toc-mobile summary::-webkit-details-marker { display: none; }

  .docs-toc-mobile summary svg {
    height: 1rem;
    width: 1rem;
    color: var(--color-neutral-400);
    transition: transform 240ms ease;
  }

  .docs-toc-mobile[open] summary svg { transform: rotate(180deg); }

  .docs-toc-mobile a {
    display: block;
    padding: 0.5rem 0.6rem;
    border-radius: 0.5rem;
    font-size: 14px;
    color: var(--color-neutral-600);
    text-decoration: none;
  }

  .docs-toc-mobile a:hover { background: color-mix(in srgb, var(--color-brand) 7%, transparent); color: var(--color-brand); }
  .docs-toc-mobile a.is-current { color: var(--color-brand); font-weight: 500; }

  .docs-toc { display: none; }

  @media (min-width: 1024px) {
    .docs-toc {
      display: block;
      position: sticky;
      top: calc(var(--topbar-h, 4rem) + 1rem);
      align-self: start;
      max-height: calc(100vh - var(--topbar-h, 4rem) - 2rem);
      overflow-y: auto;
      padding: 2.5rem 0;
    }
  }

  .docs-toc__title {
    font-size: 11px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--color-neutral-500);
  }

  .docs-toc a {
    display: block;
    border-left: 2px solid var(--color-neutral-200);
    padding: 0.35rem 0 0.35rem 0.75rem;
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-neutral-500);
    transition: color 160ms ease, border-color 160ms ease;
  }

  .docs-toc a:hover { color: var(--color-neutral-900); }

  .docs-toc a.is-current {
    border-left-color: var(--color-brand);
    color: var(--color-brand);
    font-weight: 500;
  }

  /* Honeypot. Moved off-canvas rather than display:none — some bots skip
     hidden inputs, and the point is that they fill this one in. Formspree
     also drops submissions containing a non-empty `_gotcha` server side. */
  .honeypot {
    position: absolute;
    left: -9999px;
    top: auto;
    height: 1px;
    width: 1px;
    overflow: hidden;
  }

  .why-anim {
    max-width: 25rem;
    padding: 1rem;
    border: 1px solid var(--color-neutral-200);
    border-radius: 16px;
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.68)),
      radial-gradient(circle at 20% 0%, color-mix(in srgb, var(--color-lime) 18%, transparent), transparent 18rem);
  }

  .why-anim__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 0.75rem;
    color: var(--color-neutral-500);
    font-size: 12px;
    line-height: 1.4;
  }

  .why-anim__row span:last-child {
    text-align: right;
    color: var(--color-neutral-900);
    font-weight: 500;
  }

  .why-anim__dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 9999px;
    background: var(--color-neutral-300);
  }

  .why-anim__dot--brand {
    background: var(--color-brand);
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--color-brand) 10%, transparent);
  }

  .why-anim__track {
    position: relative;
    height: 4.5rem;
    margin-block: 0.5rem;
  }

  .why-anim__track::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 0.25rem;
    bottom: 0.25rem;
    width: 1px;
    background: var(--color-neutral-200);
    transform: translateX(-50%);
  }

  .why-anim__guess,
  .why-anim__peek {
    position: absolute;
    top: 50%;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.75rem;
    padding: 0.35rem 0.7rem;
    border-radius: 9999px;
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    transform: translateY(-50%);
  }

  .why-anim__guess {
    left: 0;
    border: 1px dashed var(--color-neutral-300);
    color: var(--color-neutral-500);
    background: #fff;
  }

  .why-anim__peek {
    right: 0;
    color: #fff;
    background: var(--color-brand);
  }

  .why-anim__signal {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 9999px;
    background: var(--color-lime);
    box-shadow: 0 0 0 7px color-mix(in srgb, var(--color-lime) 22%, transparent);
    transform: translate(-50%, -50%);
  }

  .js .why-anim__guess,
  .js .why-anim__peek,
  .js .why-anim__signal {
    opacity: 0;
  }

  .js .why-anim.is-in .why-anim__guess {
    animation: why-guess 1600ms cubic-bezier(0.16, 1, 0.3, 1) 180ms both;
  }

  .js .why-anim.is-in .why-anim__signal {
    animation: why-signal 1600ms cubic-bezier(0.16, 1, 0.3, 1) 360ms both;
  }

  .js .why-anim.is-in .why-anim__peek {
    animation: why-peek 700ms cubic-bezier(0.16, 1, 0.3, 1) 1250ms both;
  }

  .js .why-anim.is-in .why-anim__dot--brand {
    animation: why-pulse 1500ms ease-out 1150ms both;
  }

  @keyframes why-guess {
    0% { opacity: 0; transform: translateY(-50%) translateX(-0.75rem); }
    28%, 58% { opacity: 1; transform: translateY(-50%) translateX(0); }
    100% { opacity: 0.42; transform: translateY(-50%) translateX(3.8rem); }
  }

  @keyframes why-signal {
    0% { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
    22% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 1; transform: translate(calc(-50% + 6.4rem), -50%) scale(1); }
  }

  @keyframes why-peek {
    0% { opacity: 0; transform: translateY(-50%) translateX(0.75rem); }
    100% { opacity: 1; transform: translateY(-50%) translateX(0); }
  }

  @keyframes why-pulse {
    0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-brand) 28%, transparent); }
    100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--color-brand) 0%, transparent); }
  }

  /* Hero mockup reveal.
     Runs ONCE, the first time the figure scrolls into view, then the observer
     disconnects. Nothing loops: a permanently animating dashboard would keep
     the compositor awake for as long as the tab is open, which is exactly the
     cost this is meant to avoid.
     Everything here animates transform, opacity or stroke-dashoffset — no
     width, no layout, no paint of the surrounding page. */
  .js .gauge-fill {
    transform: scaleX(0);
    transform-origin: left center;
    will-change: transform;
  }

  #mock.is-live .gauge-fill:nth-of-type(1) { --d: 120ms; }

  #mock.is-live .gauge-fill {
    transform: scaleX(1);
    transition: transform 1100ms cubic-bezier(0.16, 1, 0.3, 1) var(--d, 120ms);
  }

  /* pathLength="1" lets the dash be expressed in fractions, so the draw needs
     no getTotalLength() call and no layout read. */
  .js .spark-line {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
  }

  #mock.is-live .spark-line {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 1500ms cubic-bezier(0.33, 1, 0.68, 1) 260ms;
  }

  .js .spark-area { opacity: 0; }

  #mock.is-live .spark-area {
    opacity: 1;
    transition: opacity 800ms ease 900ms;
  }

  .js .mock-row {
    opacity: 0;
    transform: translateY(6px);
  }

  #mock.is-live .mock-row {
    opacity: 1;
    transform: none;
    transition:
      opacity 520ms ease var(--d, 0ms),
      transform 520ms cubic-bezier(0.16, 1, 0.3, 1) var(--d, 0ms);
  }

  /* Once the reveal is done, drop the compositor-layer hint. */
  #mock.is-settled .gauge-fill { will-change: auto; }

  @media (prefers-reduced-motion: reduce) {
    .js .gauge-fill { transform: scaleX(1); }
    .js .spark-line { stroke-dashoffset: 0; }
    .js .spark-area { opacity: 1; }
    .js .mock-row { opacity: 1; transform: none; }
    .js .why-anim__guess,
    .js .why-anim__peek,
    .js .why-anim__signal {
      opacity: 1;
      animation: none;
    }
    #mock.is-live .gauge-fill,
    #mock.is-live .spark-line,
    #mock.is-live .spark-area,
    #mock.is-live .mock-row { transition: none; }
  }

  .section-label {
    @apply text-[11px] font-medium uppercase tracking-[0.18em] text-neutral-500;
  }

  /* =====================================================================
     DASHBOARD PREVIEW (app.html)
     A logged-in shell showing sample data. Borrows the docs page's topbar
     and drawer mechanics rather than inventing a third navigation pattern.
     ===================================================================== */

  .app-body {
    background: var(--color-paper);
    min-height: 100svh;
  }

  .app-topbar {
    position: sticky;
    top: 0;
    z-index: 46;
    display: flex;
    align-items: center;
    gap: 0.875rem;
    border-bottom: 1px solid var(--color-neutral-200);
    background: rgba(250, 250, 250, 0.85);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    padding: 0.75rem 1.25rem;
  }

  /* At 320–380px the logo, badge and two buttons overflow the row. Tighten
     the gutters and drop the "Preview" pill — the notice below the header
     says the same thing at length, so the badge is the redundant one. */
  @media (max-width: 400px) {
    .app-topbar { gap: 0.5rem; padding-inline: 0.875rem; }
    .app-topbar .pill { display: none; }
  }

  .app-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 2.25rem;
    width: 2.25rem;
    border-radius: 0.625rem;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    color: var(--color-neutral-600);
    transition: background-color 180ms ease, border-color 180ms ease, color 180ms ease;
  }
  .app-icon-btn:hover { background: var(--color-neutral-100); color: var(--color-neutral-900); }

  /* Inert site label, not a control — no hover or pointer affordance. */
  .app-siteswitch {
    display: none;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    max-width: 16rem;
    border-radius: 9999px;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 0.4rem 0.8rem;
    color: var(--color-neutral-600);
  }
  @media (min-width: 640px) { .app-siteswitch { display: flex; } }

  .app-shell {
    display: grid;
    grid-template-columns: 1fr;
    max-width: 90rem;
    margin: 0 auto;
    padding: 0 1.25rem;
  }
  @media (max-width: 400px) {
    .app-shell { padding-inline: 0.875rem; }
  }
  @media (min-width: 1024px) {
    .app-shell { grid-template-columns: 15rem minmax(0, 1fr); gap: 2.5rem; }
  }

  .app-sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding: 1.75rem 0;
  }
  @media (min-width: 1024px) {
    .app-sidebar {
      position: sticky;
      top: calc(var(--topbar-h, 3.5rem) + 1rem);
      align-self: start;
      max-height: calc(100vh - var(--topbar-h, 3.5rem) - 2rem);
      overflow-y: auto;
      border-right: 1px solid var(--color-neutral-200);
      padding-right: 1.25rem;
    }
  }

  /* Below lg the sidebar is an overlay drawer. As a static block it pushed
     the dashboard far down the page, so opening the menu read as navigating
     away from the numbers you came to look at.

     It starts BELOW the sticky topbar rather than at top:0. The topbar sits a
     layer above the drawer, so a drawer pinned to the top of the viewport had
     its first group label and first nav item hidden underneath it. Starting at
     --topbar-h also leaves the menu button visible, so the control that opened
     the drawer is the same one that closes it. */
  @media (max-width: 1023px) {
    .app-sidebar {
      position: fixed;
      top: var(--topbar-h, 3.5rem);
      left: 0;
      bottom: 0;
      z-index: 45;
      width: min(17rem, 84vw);
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      /* Stops the dashboard scrolling once the drawer hits its own end. */
      overscroll-behavior: contain;
      border-right: 1px solid var(--color-neutral-200);
      background: #fff;
      box-shadow: 0 18px 44px -20px rgba(12, 74, 47, 0.35);
      /* Generous bottom padding so the plan card clears the home indicator
         on iOS rather than sitting flush against the edge. */
      padding: 1.25rem 1.125rem calc(2.5rem + env(safe-area-inset-bottom, 0px));
      gap: 1.25rem;
      transform: translateX(-100%);
      transition: transform 220ms ease;
    }
    .app-sidebar.is-open { transform: translateX(0); }

    /* Bigger tap targets once the links are a touch target rather than a
       pointer one. 15px matches the docs drawer. */
    .app-nav a { padding: 0.6rem 0.7rem; font-size: 15px; }
    .app-nav__group { padding-inline: 0.7rem; }

    /* The plan card is a footnote on desktop, but in a drawer it would push
       the nav up if it stayed in flow at auto height. Keep it last, compact. */
    .app-plan { margin-top: 0.25rem; }
  }

  .app-backdrop {
    position: fixed;
    inset: 0;
    z-index: 44;
    background: rgba(10, 10, 10, 0.25);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }
  .app-backdrop[hidden] { display: none; }
  @media (min-width: 1024px) { .app-backdrop { display: none; } }

  .app-nav__group {
    padding: 0 0.75rem;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-neutral-400);
  }
  .app-nav__group:not(:first-child) { margin-top: 1.5rem; }

  .app-nav ul { margin-top: 0.5rem; }

  .app-nav a {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    border-radius: 0.625rem;
    padding: 0.5rem 0.75rem;
    font-size: 14px;
    color: var(--color-neutral-600);
    transition: background-color 160ms ease, color 160ms ease;
  }
  .app-nav a svg { height: 1.05rem; width: 1.05rem; flex-shrink: 0; }
  .app-nav a:hover { background: var(--color-neutral-100); color: var(--color-neutral-900); }
  .app-nav a.is-current {
    background: color-mix(in srgb, var(--color-brand) 8%, transparent);
    color: var(--color-brand);
    font-weight: 500;
  }
  .app-nav a:focus-visible,
  .app-plan__link:focus-visible,
  .app-link:focus-visible,
  .app-foot a:focus-visible,
  .app-icon-btn:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 2px;
  }

  .app-nav__count {
    margin-left: auto;
    border-radius: 9999px;
    background: var(--color-neutral-100);
    padding: 0.05rem 0.45rem;
    font-family: var(--font-mono);
    font-size: 10.5px;
    color: var(--color-neutral-500);
  }
  .app-nav a.is-current .app-nav__count {
    background: color-mix(in srgb, var(--color-brand) 14%, transparent);
    color: var(--color-brand);
  }

  .app-plan {
    border-radius: 0.875rem;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 1rem;
  }
  @media (min-width: 1024px) { .app-plan { margin-top: auto; } }

  .app-plan__link {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.875rem;
    font-size: 13px;
    color: var(--color-brand);
    transition: gap 160ms ease;
  }
  .app-plan__link:hover { gap: 0.55rem; }

  .app-main { padding: 1.75rem 0 3rem; min-width: 0; }

  /* The preview disclosure. Amber, because it is a caveat about the data
     rather than a status reading — the status palette stays with the gauges. */
  .app-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    border-radius: 0.875rem;
    border: 1px solid color-mix(in srgb, var(--color-warn) 30%, transparent);
    background: color-mix(in srgb, var(--color-warn) 7%, #fff);
    padding: 0.875rem 1rem;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--color-neutral-700);
  }
  .app-notice svg { margin-top: 0.15rem; color: var(--color-warn); }

  .app-link {
    color: var(--color-brand);
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-color: color-mix(in srgb, var(--color-brand) 35%, transparent);
  }
  .app-link:hover { text-decoration-color: currentColor; }

  .app-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin: 1.75rem 0 1.25rem;
  }

  .app-stamp {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    border-radius: 9999px;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 0.35rem 0.7rem;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--color-neutral-500);
  }

  .app-grid { display: grid; gap: 1rem; }
  @media (min-width: 640px) {
    .app-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .app-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  }
  @media (min-width: 900px) {
    .app-grid--split { grid-template-columns: 1.6fr 1fr; }
  }

  .app-card {
    border-radius: 0.875rem;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 1.25rem;
  }

  .app-card__label {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-neutral-500);
  }

  .app-metric {
    margin-top: 0.5rem;
    font-family: var(--font-display);
    font-size: 2.25rem;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    color: var(--color-ink);
  }
  .app-metric__unit { color: var(--color-neutral-400); }

  .app-bar {
    margin-top: 0.75rem;
    height: 0.375rem;
    overflow: hidden;
    border-radius: 9999px;
    background: var(--color-neutral-100);
  }
  .app-bar__fill { height: 100%; border-radius: 9999px; }

  .app-card__foot {
    margin-top: 0.55rem;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--color-neutral-500);
  }
  .app-card__foot--warn { color: var(--color-warn); }

  /* 30 day bars. Fixed height so a run of good days still reads as a row. */
  .app-spark {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    margin-top: 1rem;
    height: 2.5rem;
  }
  .app-spark span {
    flex: 1;
    height: 100%;
    border-radius: 1px;
    background: color-mix(in srgb, var(--color-ok) 45%, transparent);
  }
  .app-spark span.is-warn { background: var(--color-warn); height: 62%; }

  .app-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  .app-alert {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    border-radius: 0.75rem;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 0.875rem 1rem;
  }
  .app-alert__dot {
    height: 0.5rem;
    width: 0.5rem;
    flex-shrink: 0;
    border-radius: 9999px;
  }

  .app-tag {
    margin-left: auto;
    flex-shrink: 0;
    border-radius: 9999px;
    border: 1px solid var(--color-neutral-200);
    padding: 0.15rem 0.55rem;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-neutral-500);
  }
  .app-tag--ok {
    border-color: color-mix(in srgb, var(--color-ok) 30%, transparent);
    color: var(--color-ok);
  }
  .app-tag--warn {
    border-color: color-mix(in srgb, var(--color-warn) 30%, transparent);
    color: var(--color-warn);
  }
  .app-tag--crit {
    border-color: color-mix(in srgb, var(--color-crit) 30%, transparent);
    color: var(--color-crit);
  }

  .app-empty {
    margin-top: 1rem;
    border-radius: 0.875rem;
    border: 1px dashed var(--color-neutral-300);
    background: rgba(255, 255, 255, 0.7);
    padding: 2rem 1.25rem;
    text-align: center;
  }

  .app-dl { margin-top: 0.875rem; display: grid; gap: 0.5rem; }
  @media (min-width: 640px) {
    .app-dl--wide { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem 2rem; }
  }
  .app-dl > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    border-bottom: 1px solid var(--color-neutral-100);
    padding-bottom: 0.5rem;
    font-size: 13.5px;
  }
  .app-dl > div:last-child { border-bottom: 0; padding-bottom: 0; }
  .app-dl dt { font-family: var(--font-mono); font-size: 12px; color: var(--color-neutral-500); }
  .app-dl dd { font-family: var(--font-mono); font-size: 12.5px; color: var(--color-neutral-900); }

  .app-field { margin-bottom: 1rem; }
  .app-field label {
    display: block;
    margin-bottom: 0.4rem;
    font-size: 13px;
    font-weight: 500;
    color: var(--color-neutral-700);
  }
  .app-field input {
    width: 100%;
    border-radius: 0.625rem;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 0.6rem 0.8rem;
    font-size: 14px;
    color: var(--color-neutral-900);
  }
  /* Disabled is the resting state here, so it must not look broken. */
  .app-field input:disabled {
    background: var(--color-neutral-100);
    color: var(--color-neutral-500);
    cursor: not-allowed;
  }

  .app-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2.5rem;
    border-top: 1px solid var(--color-neutral-200);
    padding-top: 1.5rem;
    font-size: 12.5px;
    color: var(--color-neutral-500);
  }
  .app-foot a { transition: color 160ms ease; }
  .app-foot a:hover { color: var(--color-brand); }

  @media (prefers-reduced-motion: reduce) {
    .app-sidebar { transition: none; }
    .app-plan__link { transition: none; }
  }

  /* =====================================================================
     CLOSING-CTA DEMO ("Know before it breaks")
     A simulated CPU ramp that crosses the alert threshold. The markup
     ships in its end state — alert already fired, payoff visible — so the
     section reads correctly with JS off or motion reduced. JS zeroes the
     bar and replays the ramp when the section first scrolls into view.
     ===================================================================== */

  .cta-demo {
    border-radius: 1rem;
    border: 1px solid var(--color-neutral-200);
    background: var(--color-paper);
    padding: 1.25rem;
  }

  .cta-demo__replay {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    border-radius: 9999px;
    border: 1px solid var(--color-neutral-200);
    background: #fff;
    padding: 0.25rem 0.6rem;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--color-neutral-500);
    transition: color 160ms ease, border-color 160ms ease;
  }
  .cta-demo__replay:hover { color: var(--color-brand); border-color: var(--color-brand); }
  .cta-demo__replay:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 2px;
  }

  /* Threshold marker: a hairline at 90% of the bar's width, label centred
     under it. Positioned over the bar's container, not the bar itself, so
     it never scales with the fill. */
  .cta-demo__threshold {
    position: relative;
    height: 10px;
    margin-top: 2px;
  }
  .cta-demo__threshold::before {
    content: '';
    position: absolute;
    left: 90%;
    top: 0;
    width: 1px;
    height: 7px;
    background: var(--color-neutral-400);
  }
  .cta-demo__threshold span {
    position: absolute;
    left: 90%;
    top: 8px;
    transform: translateX(-50%);
    font-family: var(--font-mono);
    font-size: 9.5px;
    letter-spacing: 0.04em;
    color: var(--color-neutral-400);
  }

  /* Alert row: hidden until the demo crosses the threshold, then drops in.
     Shipped visible and JS-hidden — reverse of the usual pattern so the
     no-JS state is the finished one. */
  .cta-demo__alert {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1.25rem;
    border-radius: 0.625rem;
    border: 1px solid color-mix(in srgb, var(--color-crit) 25%, transparent);
    background: color-mix(in srgb, var(--color-crit) 5%, #fff);
    padding: 0.6rem 0.75rem;
    font-size: 13px;
  }
  .js .cta-demo__alert.is-armed { opacity: 0; }

  .cta-demo.is-firing .cta-demo__alert {
    opacity: 1;
    animation: cta-drop 420ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .cta-demo__alert-dot {
    height: 0.5rem;
    width: 0.5rem;
    flex-shrink: 0;
    border-radius: 9999px;
    background: var(--color-crit);
  }
  .cta-demo.is-firing .cta-demo__alert-dot {
    animation: cta-pulse 1.6s ease-in-out infinite;
  }

  /* The payoff line, weighted so it reads as the point of the whole block. */
  .cta-demo__payoff {
    margin-top: 0.75rem;
    font-size: 14px;
    font-weight: 500;
    color: var(--color-brand);
  }
  .js .cta-demo__payoff.is-armed { opacity: 0; }
  .cta-demo.is-firing .cta-demo__payoff {
    opacity: 1;
    animation: cta-drop 420ms cubic-bezier(0.16, 1, 0.3, 1) 350ms backwards;
  }

  @keyframes cta-drop {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
  }

  @keyframes cta-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-crit) 35%, transparent); }
    50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--color-crit) 0%, transparent); }
  }

  @media (prefers-reduced-motion: reduce) {
    .cta-demo.is-firing .cta-demo__alert,
    .cta-demo.is-firing .cta-demo__alert-dot,
    .cta-demo.is-firing .cta-demo__payoff { animation: none; }
    .cta-demo__replay { transition: none; }
  }
}

@layer utilities {
  .display {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.045em;
    line-height: 0.95;
  }

  /* Scroll reveal. Elements are only hidden once JS has confirmed it is
     running, so the page stays fully readable with JS disabled. */
  .js .reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  }

  .js .reveal.is-in {
    opacity: 1;
    transform: none;
  }

  .caret {
    display: inline-block;
    width: 0.06em;
    margin-left: 0.04em;
    background: currentColor;
    animation: blink 1.1s steps(1, end) infinite;
  }

  @keyframes blink {
    0%, 50% { opacity: 1; }
    50.01%, 100% { opacity: 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    .js .reveal { opacity: 1; transform: none; transition: none; }
    .caret { animation: none; }
    html { scroll-behavior: auto; }
  }
}
