/* Cronitor marketing v5 — shared tokens + components (locked aesthetic) */
:root, [data-theme="light"] {
  --bg: #FFFFFF; --panel: #FAFAF8; --rule: #E4E4E0; --rule-strong: #0B0021;
  --ink: #0B0021; --body: #3E3B52; --muted: #6E6B80;
  --accent: #2E16B5; --accent-soft: #EEEBFB;
  /* the glyphs' live moment (CAPABILITY GLYPHS): the palette's up green */
  --accent-2: var(--up);
  --green: #00DF4D; --up: #00B833; --down: #E62144; --gold: #F5C51C;
  --card-shadow: 0 1px 2px rgba(11,0,33,0.06);
  --alert-bg: #FFFFFF; --band-bg: #0B0021; --band-text: #EFEDEA; --band-muted: #9B98AC;
  --band-rule: #2A2735; --band-accent: #9D8CFF;
  --logo: url("cronitor-logo.bbb5e4d2893d.svg"); --logofilter: none;
  /* incident lifecycle — status pages only, mirrors the app's ISSUE_STATE_BADGE_COLORS */
  --inc-investigating: #FF354C; --inc-identified: #FB923C;
  --inc-monitoring: #44B2FD; --inc-resolved: #00DF4D;
  /* RUM load-time series — app RUM_PERFORMANCE_DIMENSIONS. Series identities, not statuses. */
  --rum-frontend: #7C46EC; --rum-network: #FACC15; --rum-backend: #00961C;
}
[data-theme="dark"] {
  --bg: #0E0E12; --panel: #15151A; --rule: #26262E; --rule-strong: #EFEDEA;
  --ink: #EFEDEA; --body: #B9B7C4; --muted: #807E8C;
  --accent: #9D8CFF; --accent-soft: #1E1A33;
  --green: #00F770; --up: #00F770; --down: #FF354C; --gold: #F5C51C;
  --card-shadow: 0 12px 32px rgba(0,0,0,0.45);
  --alert-bg: #17171D; --band-bg: #15151A; --band-text: #EFEDEA; --band-muted: #807E8C;
  --band-rule: #26262E; --band-accent: #9D8CFF;
  --logo: url("cronitor-logo-light.b228d5deb878.svg"); --logofilter: invert(0.88) brightness(1.1);
  --inc-investigating: #FF354C; --inc-identified: #FB923C;
  --inc-monitoring: #44B2FD; --inc-resolved: #00F770;
}
* { box-sizing: border-box; }
html { border-top: 3px solid var(--gold); }
body { background: var(--bg); color: var(--ink); font-family: "JetBrains Mono", monospace; }
.sans { font-family: "Instrument Sans", sans-serif; }
.wrap { max-width: 1160px; margin: 0 auto; padding: 0 40px; }
a { color: inherit; }
h1, h2, h3 { letter-spacing: -0.025em; }

/* nav */
nav.site { border-bottom: 1px solid var(--rule); position: sticky; top: 0; background: var(--bg); z-index: 50; }
/* `>` matters: the nav row is the wrap that is a DIRECT child of the nav.
   A dropdown panel inside the nav carries its own .wrap so its columns
   land on the page's content column, and a descendant selector here made
   that panel a 66px centred flex row. */
nav.site > .wrap { display: flex; align-items: center; gap: 28px; height: 66px; }
.logo {
  width: 122px;
  height: 30px;
  background: var(--logo) no-repeat left center / contain;
  margin-top: -7px;
  background-image: url("cronitor-nav-logo.b4857294586b.svg");
}

nav.site a.nl { color: var(--muted); text-decoration: none; font-size: 13px; font-weight: 500; }
nav.site a.nl:hover { color: var(--accent); }
nav.site .spacer { flex: 1; }
.btn { display: inline-block; background: var(--ink); color: var(--bg); font-size: 13px; font-weight: 600;
  padding: 11px 20px; text-decoration: none; border-radius: 2px; border: 1px solid var(--ink); font-family: inherit; }
.btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.ghost { background: transparent; color: var(--ink); border: 1px solid var(--rule-strong); }
.btn.ghost:hover { background: var(--ink); color: var(--bg); }
.theme-toggle { cursor: pointer; border: 1px solid var(--rule); background: transparent; color: var(--muted);
  border-radius: 2px; padding: 8px 10px; font-size: 12px; font-family: inherit; }

/* type helpers */
@keyframes blink { 50% { opacity: 0; } }
.cursor { display: inline-block; width: 0.14em; height: 0.85em; background: var(--accent); margin-left: 8px;
  vertical-align: baseline; opacity: 0.8; animation: blink 1.3s steps(1) infinite; }
.seclabel { font-size: 10.5px; letter-spacing: 0.12em; color: var(--muted); display: flex; justify-content: space-between; }
.seclabel b { color: var(--accent); font-weight: 500; }
.agent-note { font-size: 12px; color: var(--muted); }
.agent-note a { color: var(--accent); text-decoration: none; }

/* monitor board */
.figure { border: 1px solid var(--rule-strong); background: var(--bg); border-radius: 3px; overflow: hidden; box-shadow: var(--card-shadow); }
.chrome { display: flex; justify-content: space-between; padding: 11px 16px; border-bottom: 1px solid var(--rule);
  background: var(--panel); font-size: 11px; color: var(--muted); }
.health i { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin: 0 5px 0 10px; }
.health .u { background: var(--up); } .health .d { background: var(--down); }
.board { width: 100%; border-collapse: collapse; font-size: 12px; background: var(--bg); }
.board td { padding: 11px 9px; border-top: 1px solid var(--rule); white-space: nowrap; }
.board td:first-child { padding-left: 16px; }
.board em { font-style: normal; font-size: 9px; letter-spacing: 0.08em; color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); padding: 2px 5px; border-radius: 2px; }
.ticks i { display: inline-block; width: 5px; height: 13px; border-radius: 1px; background: var(--green); margin-right: 2px; opacity: 0.9; }
.st { text-align: right; padding-right: 16px !important; color: var(--up); }
@keyframes rowFail { to { background: color-mix(in srgb, var(--down) 11%, var(--bg)); } }
@keyframes tickFail { to { background: var(--down); } }
@keyframes stFail { to { color: var(--down); font-weight: 700; } }
@keyframes slideIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
.fail-1 { animation: rowFail 0.3s 1.2s forwards; }
.fail-1 .st { animation: stFail 0.3s 1.2s forwards; }
.fail-1 .ticks i:nth-last-child(-n+2) { animation: tickFail 0.3s 1.2s forwards; }
.fail-2 { animation: rowFail 0.3s 2.6s forwards; }
.fail-2 .st { animation: stFail 0.3s 2.6s forwards; }
.fail-2 .ticks i:last-child { animation: tickFail 0.3s 2.6s forwards; }
.alert { position: absolute; width: 248px; background: var(--alert-bg); border: 1px solid var(--rule-strong);
  border-radius: 3px; padding: 10px 12px; box-shadow: 4px 4px 0 color-mix(in srgb, var(--ink) 14%, transparent);
  font-size: 11px; opacity: 0; z-index: 5; }
.alert .arow { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.alert .chan { font-size: 10px; color: var(--muted); }
.alert b { display: block; font-size: 11.5px; color: var(--down); font-weight: 600; }
.alert .chip { display: inline-block; font-size: 9px; color: #fff; border-radius: 2px; padding: 2px 6px; }
.alert.slack .chip { background: #4A154B; }
.alert.pd .chip { background: #04AC38; }
.alert.em .chip { background: #B23121; }

/* logo cells */
.logocell { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0;
  padding: 22px 8px; }
.logocell img { height: 24px; max-width: 88%; object-fit: contain;
  filter: brightness(0) saturate(100%) invert(0.44); }
[data-theme="dark"] .logocell img { filter: brightness(0) saturate(100%) invert(0.6); }
/* THE OPTICAL TABLE. `height` here is a CEILING, not the rendered height:
   `.logocell img` also carries `max-width` and `object-fit: contain`, so for
   any mark wider than ~4:1 the WIDTH cap binds first and the authored height
   is never reached. That is why this table does not — and cannot — agree with
   the marquee's `h` in v5-shared.js, which is a true rendered height because
   `.lm-item img` is `max-width: none`. Johnson & Johnson is the clearest
   case: 38px here against 12px there, but 10.27:1 under a 97% cap renders
   ~16.5px tall on the wall. The two numbers describe different quantities
   under different sizing regimes; they are not a discrepancy to reconcile.
   (Reported rather than "fixed" — see LOGO-WALL-SPEC.md §1.)

   AngelList retired 2026-08-27 with the churn; it is on no page. */
.logocell img[alt="Disney"] { height: 34px; max-width: 96%; }
.logocell img[alt="Johnson & Johnson"] { height: 38px; max-width: 97%; }
/* marks added in the 2026-08-27 refresh whose artwork is not a plain
   horizontal wordmark, so the 24px default reads wrong. Ratios measured from
   the shipped files. */
/* Keygen needs no height override — it is the full icon+wordmark lockup at
   4.73:1, which renders 114px at the default 24px. */
/* Pure-lowercase wordmarks whose box top is set by a lone ascender read low
   when the box is centred. -6% is the measured fit; -8% over-corrects.
   `%` not `px` deliberately — translateY(%) resolves against the element's
   own height, so one rule is right at both 24px and the wall's 30px. */
.logocell img[alt="Meesho"],
.logocell img[alt="Zendesk"] { transform: translateY(-6%); }
.logocell img[alt="Control Plane"] { height: 33px; }      /* two-line stacked, 2.88:1 */
.logocell img[alt="Primary"] { height: 42px; max-width: 96%; }  /* arched emblem, 1.75:1 */
.logocell img[alt="Good Eggs"] { height: 32px; }          /* two-line horizontal lockup, 3.365:1 */
.logocell img[alt="Ravelry"] { height: 26px; }            /* 3.21:1 */
.logocell img[alt="Razer"] { height: 22px; }              /* 6.30:1 */
.logocell img[alt="Stadium Goods"] { max-width: 96%; }    /* 9.70:1 — max-width binds before height */
.logocell img[alt="ZenGaming"] { max-width: 96%; }        /* 9.16:1 — widest in the set */
.logocell img[alt="Reddit"] { filter: grayscale(1) brightness(1.25) opacity(0.82); }
[data-theme="dark"] .logocell img[alt="Reddit"] { filter: grayscale(1) invert(0.75); }
.logocell span { display: none; }
.logocell:hover { background: var(--accent-soft); }

/* Customer wall: a row-major sequential deal, coordinated by v5-motion.
   The resting state is the complete wall. Only the running controller ghosts
   the marks, so a fast scroll, missing JS, or reduced motion never exposes an
   empty grid. The wrapper owns motion because several marks carry optical
   translateY corrections on the image itself. */
.logowall .grid[data-logo-deal] .logocell { position: relative; perspective: 480px; }
.logowall .grid[data-logo-deal] .logo-mark {
  display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
  opacity: 1; transform: none; backface-visibility: hidden;
  transition: opacity 120ms var(--ease-shift), transform 120ms var(--ease-shift);
}
.logowall .grid[data-logo-deal].is-sequencing .logo-mark { will-change: transform, opacity; }
.logowall .grid[data-logo-deal].is-sequencing .logocell.is-waiting .logo-mark {
  opacity: 0.16; transform: scale(0.96);
}
.logowall .grid[data-logo-deal].is-sequencing .logocell.is-dealing .logo-mark {
  animation: logoDealIn 300ms var(--ease-enter) both;
}
@keyframes logoDealIn {
  0% { opacity: 0.16; transform: translateX(var(--logo-slide)) rotateY(var(--logo-turn)) scale(0.92); }
  72% { opacity: 1; transform: translateX(var(--logo-bump)) rotateY(0) scale(1.025); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .logowall .grid[data-logo-deal] .logocell,
  .logowall .grid[data-logo-deal] .logo-mark {
    animation: none !important; transition: none !important;
    opacity: 1 !important; transform: none !important; box-shadow: none !important;
  }
}

/* mini-figures */
.minifig { border: 1px solid var(--rule-strong); background: var(--bg); border-radius: 3px; overflow: hidden;
  box-shadow: var(--card-shadow); font-size: 11.5px; }
.minifig .pad { padding: 15px; }
@keyframes lineIn { from { opacity: 0; } to { opacity: 1; } }
.loglines div { padding: 6px 0; border-top: 1px dashed var(--rule); color: var(--body); opacity: 0; animation: lineIn 0.15s forwards; }
.loglines div:first-child { border-top: 0; }
.loglines div:nth-child(1) { animation-delay: 0.2s; } .loglines div:nth-child(2) { animation-delay: 0.5s; }
.loglines div:nth-child(3) { animation-delay: 0.8s; } .loglines div:nth-child(4) { animation-delay: 1.1s; }
.loglines div:nth-child(5) { animation-delay: 1.4s; }
.loglines .t { color: var(--muted); margin-right: 10px; }
.loglines .okk { color: var(--up); }
@keyframes grow { from { width: 0; } }
.latrow { display: grid; grid-template-columns: 86px 1fr 52px; gap: 12px; align-items: center; padding: 7px 0; color: var(--body); }
.latrow .bar { height: 8px; border-radius: 1px; background: var(--accent); opacity: 0.85; animation: grow 0.8s ease-out both; }
.latrow:nth-child(2) .bar { animation-delay: 0.15s; } .latrow:nth-child(3) .bar { animation-delay: 0.3s; }
.latrow:nth-child(4) .bar { animation-delay: 0.45s; } .latrow:nth-child(5) .bar { animation-delay: 0.6s; }
.latrow .v { text-align: right; color: var(--muted); }
.ssl { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--rule); color: var(--up); font-size: 11px; }
@keyframes pulse { 0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 45%, transparent); } 60% { box-shadow: 0 0 0 9px transparent; } }
.hbrow { display: grid; grid-template-columns: 18px 1fr auto; gap: 10px; align-items: center; padding: 8px 0;
  border-top: 1px dashed var(--rule); color: var(--body); }
.hbrow:first-child { border-top: 0; }
.hbrow i { width: 8px; height: 8px; border-radius: 50%; background: var(--up); animation: pulse 2.2s infinite; }
.hbrow:nth-child(2) i { animation-delay: 0.4s; } .hbrow:nth-child(3) i { animation-delay: 0.9s; } .hbrow:nth-child(4) i { animation-delay: 1.3s; }
.hbrow .t { color: var(--muted); font-size: 10.5px; }
@keyframes tickIn { from { opacity: 0; transform: scaleY(0.3); } to { opacity: 1; transform: none; } }
.sp-title { display: flex; align-items: center; gap: 9px; color: var(--up); font-weight: 600; padding-bottom: 12px; font-size: 12.5px; }
.sp-title i { width: 9px; height: 9px; border-radius: 50%; background: var(--up); animation: pulse 2.6s infinite; }
.uprow { padding: 8px 0; border-top: 1px solid var(--rule); color: var(--body); }
.uprow .lbl { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 11px; }
.uprow .lbl b { color: var(--up); font-weight: 500; }
.upticks i { display: inline-block; width: 4px; height: 15px; border-radius: 1px; background: var(--green);
  margin-right: 1.5px; animation: tickIn 0.3s both; }
.upticks i.dn { background: var(--down); }
.upticks i:nth-child(3n) { animation-delay: 0.1s; } .upticks i:nth-child(3n+1) { animation-delay: 0.25s; }
@keyframes draw { from { stroke-dashoffset: 700; } to { stroke-dashoffset: 0; } }
.rum svg polyline { stroke-dasharray: 700; animation: draw 1.6s ease-out forwards; }
.rumstats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; margin-top: 12px; border: 1px solid var(--rule); }
.rumstats div { padding: 10px 12px; border-right: 1px solid var(--rule); }
.rumstats div:last-child { border-right: 0; }
.rumstats b { display: block; font-size: 17px; color: var(--ink); }
.rumstats span { font-size: 9px; color: var(--muted); letter-spacing: 0.06em; }

/* feature copy */
.kicker { font-size: 11px; letter-spacing: 0.12em; color: var(--accent); margin-bottom: 14px; }
.fcopy h2 { font-size: 25px; font-weight: 700; line-height: 1.25; margin-bottom: 14px; }
.fcopy p { font-family: "Instrument Sans", sans-serif; font-size: 15px; line-height: 1.65; color: var(--body); margin-bottom: 16px; }
.fcopy ul { list-style: none; margin-bottom: 22px; padding: 0; }
.fcopy li { font-size: 13px; color: var(--body); padding: 4px 0 4px 24px; position: relative; }
.fcopy li::before { content: "→"; position: absolute; left: 0; color: var(--accent); }

/* integration fan-out */
.route { position: relative; border: 1px solid var(--band-rule); border-radius: 3px; padding: 22px; font-size: 11.5px; }
.route .src { display: inline-block; border: 1px solid var(--down); color: var(--down); border-radius: 2px;
  padding: 8px 12px; margin-bottom: 26px; }
.route .dests { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; border: 1px solid var(--band-rule); }
.route .dest { border-right: 1px solid var(--band-rule); border-bottom: 1px solid var(--band-rule);
  padding: 10px 12px; color: var(--band-muted); }
.route .dest:nth-child(3n) { border-right: 0; }
.route .dest:nth-child(n+10) { border-bottom: 0; }
@keyframes routePulse { 0% { opacity: 0.2; } 12% { opacity: 1; color: var(--band-text);
  background: color-mix(in srgb, var(--band-accent) 22%, transparent); } 30%,100% { opacity: 0.75; background: transparent; } }
.route .dest { animation: routePulse 6s infinite; }
.route .dest:nth-child(1) { animation-delay: 0.2s; } .route .dest:nth-child(2) { animation-delay: 0.6s; }
.route .dest:nth-child(3) { animation-delay: 1.0s; } .route .dest:nth-child(4) { animation-delay: 1.4s; }
.route .dest:nth-child(5) { animation-delay: 1.8s; } .route .dest:nth-child(6) { animation-delay: 2.2s; }
.route .dest:nth-child(7) { animation-delay: 2.6s; } .route .dest:nth-child(8) { animation-delay: 3.0s; }
.route .dest:nth-child(9) { animation-delay: 3.4s; } .route .dest:nth-child(10) { animation-delay: 3.8s; }
.route .dest:nth-child(11) { animation-delay: 4.2s; } .route .dest:nth-child(12) { animation-delay: 4.6s; }
/* Every other looping component in this sheet has a `reduce` branch; this one
   did not, so the only infinite animation on the page stayed live for exactly
   the reader who asked for it not to. The resting frame of routePulse is
   30%–100% of the cycle — opacity 0.75, transparent fill — so stating that
   statically IS the finished drawing, not a blank one. */
@media (prefers-reduced-motion: reduce) {
  .route .dest { animation: none; opacity: 0.75; }
}

/* The shared motion coordinator owns authored content motion. CSS timelines
   inside an idle/paused figure must not keep speaking while another figure
   has the page-wide lock. Interactive hover/focus feedback lives outside
   [data-v5-motion] and is intentionally unaffected. */
[data-v5-motion-state="idle"] *,
[data-v5-motion-state="paused"] * {
  animation-play-state: paused !important;
}

/* footer */
footer.site { border-top: 1px solid var(--rule-strong); padding: 48px 0 40px; background: var(--panel); }
footer.site .wrap { display: grid; grid-template-columns: 1.2fr 1fr 1fr 1fr 1.2fr; gap: 32px; }
footer.site h4 { font-size: 10.5px; letter-spacing: 0.1em; color: var(--muted); margin-bottom: 14px; font-weight: 500; }
footer.site a { display: block; color: var(--body); text-decoration: none; font-size: 12px; padding: 3.5px 0; }
footer.site a:hover { color: var(--accent); }
footer.site .logo { margin-bottom: 12px; }
footer.site .fine { font-size: 10px; color: var(--muted); margin-top: 16px; line-height: 1.7; }

/* quotes / cases */
.qcard { padding: 24px; }
.qcard p { font-family: "Instrument Sans", sans-serif; font-size: 13.5px; line-height: 1.6; color: var(--body); margin-bottom: 18px; }
.qcard b { display: block; font-size: 12px; }
.qcard span { font-size: 10.5px; color: var(--muted); }
.ccard { padding: 24px; text-decoration: none; color: var(--ink); display: block; }
.ccard:hover { background: var(--accent-soft); }
.ccard em { font-style: normal; font-size: 9.5px; letter-spacing: 0.12em; color: var(--accent); }
.ccard p { font-family: "Instrument Sans", sans-serif; font-size: 15px; line-height: 1.5; margin: 10px 0 12px; }
.ccard span { font-size: 11px; color: var(--muted); }
.ornament { text-align: center; color: var(--muted); font-size: 13px; letter-spacing: 0.5em; }

/* company attribution logos */
.cologo { height: 17px; object-fit: contain; display: block; margin-top: 9px; }
.cologo.inline { display: inline-block; height: 13px; vertical-align: -3px; margin: 0 0 0 6px; }
[data-theme="dark"] .cologo { filter: grayscale(1) invert(0.85) brightness(1.4); }

/* case study plates (dark in both themes — real logos, real titles, real quotes) */
.casecard { background: var(--panel); color: var(--ink); padding: 28px; display: block; text-decoration: none; }
.casecard:hover { background: var(--accent-soft); }
.casecard .clogo { height: 24px; display: block; margin-bottom: 18px; }
.casecard em { font-style: normal; font-size: 9.5px; letter-spacing: 0.12em; color: var(--accent); }
.casecard h3 { font-family: "Instrument Sans", sans-serif; font-size: 17px; line-height: 1.4; margin: 10px 0; color: var(--ink); font-weight: 600; letter-spacing: 0; }
.casecard q { display: block; font-family: "Instrument Sans", sans-serif; font-size: 12.5px; line-height: 1.6; color: var(--body); margin-bottom: 16px; }
.casecard .rm { font-size: 11px; color: var(--accent); }

/* integration fan-out marks */
.dest img { height: 15px; vertical-align: -3px; margin-right: 9px; }

/* grouped board: type headers instead of per-row chips */
.board .ghead td { padding: 8px 16px 6px; font-size: 9px; letter-spacing: 0.14em; color: var(--muted);
  background: var(--panel); border-top: 1px solid var(--rule); font-weight: 600; }
.board .ghead:first-child td { border-top: 0; }

/* bands are light now — remap the band palette to the page palette */
.band { --band-bg: var(--panel); --band-text: var(--ink); --band-muted: var(--body);
  --band-rule: var(--rule); --band-accent: var(--accent); }
.band .btn { background: var(--ink) !important; color: var(--bg) !important; border-color: var(--ink) !important; }
.band .btn:hover { background: var(--accent) !important; border-color: var(--accent) !important; color: #fff !important; }

/* typographic integration cells (no borrowed logo art) */
.dest b { display: block; font-weight: 600; font-size: 12px; color: var(--band-text); margin-bottom: 3px; }
.dest span { display: block; font-size: 10px; color: var(--band-muted); }

.clogo.inv { filter: invert(0.93); }
[data-theme="dark"] .clogo.inv { filter: none; }

/* third failure in the sequence (job -> heartbeat -> check) */
.fail-3 { animation: rowFail 0.3s 4.0s forwards; }
.fail-3 .st { animation: stFail 0.3s 4.0s forwards; }
.fail-3 .ticks i:last-child { animation: tickFail 0.3s 4.0s forwards; }

/* ---------- product page grammar ---------- */
.phero { padding: 72px 0 80px; }
.phero .wrap { display: grid; grid-template-columns: 46% 54%; gap: 52px; align-items: center; }
.phero .kicker { font-size: 11px; letter-spacing: 0.12em; color: var(--accent); margin-bottom: 16px; }
.phero h1 { font-size: 46px; font-weight: 800; line-height: 1.12; letter-spacing: -0.03em; margin-bottom: 24px; }
.phero .checks { list-style: none; padding: 0; margin: 0 0 30px; }
.phero .checks li { font-family: "Instrument Sans", sans-serif; font-size: 15px; color: var(--body); padding: 5px 0 5px 26px; position: relative; }
.phero .checks li::before { content: "✓"; position: absolute; left: 0; color: var(--up); font-weight: 700; font-family: "JetBrains Mono", monospace; }
.phero .cta-row { display: flex; gap: 12px; }
.phero .stage { position: relative; }
/* HERO / MARQUEE RIGHT RULE. Hero drawings are 600px frames inside either a
   600px or 620px stage, with a hard-offset plate painted beyond the frame.
   Align the OUTER plate—not the foreground border—to the marquee's right rule:
   auto consumes any spare stage width, then `right` pulls the frame back by
   the plate depth. Page-local `margin: 0` continues to own stacked layouts;
   this shared desktop rule is the paired-hero alignment contract. */
@media (min-width: 1152px) {
  .phero .stage > :first-child {
    --hero-backplate-offset: 8px;
    margin-left: auto;
    right: var(--hero-backplate-offset);
  }
}
.phero .agent-note { margin-top: 20px; }

/* capability grid: 3-col ruled cells */
.capgrid { display: grid; grid-template-columns: repeat(3, 1fr); border: 1px solid var(--rule-strong); border-radius: 3px; overflow: hidden; }
.cap { padding: 20px 22px; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.cap:nth-child(3n) { border-right: 0; }
.cap b { display: block; font-size: 13px; font-weight: 700; margin-bottom: 7px; }
.cap p { font-family: "Instrument Sans", sans-serif; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.cap:hover { background: var(--accent-soft); }

/* code figure with tabs */
.codefig { border: 1px solid var(--rule-strong); border-radius: 3px; overflow: hidden; box-shadow: var(--card-shadow); }
.codetabs { display: flex; border-bottom: 1px solid var(--rule); background: var(--panel); font-size: 10.5px; color: var(--muted); }
.codetabs span { padding: 10px 14px; border-right: 1px solid var(--rule); cursor: pointer; }
.codetabs span.on { color: var(--accent); background: var(--bg); font-weight: 600; }
.codefig pre { margin: 0; padding: 18px; font-family: "JetBrains Mono", monospace; font-size: 11.5px; line-height: 1.75; color: var(--body); overflow-x: auto; background: var(--bg); }
.codefig .cmt { color: var(--muted); }
.codefig .hl { color: var(--accent); }

/* stats strip (real numbers from live site) */
.stats {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: var(--panel);
  margin-bottom: 20px;
}
.stats .grid { display: grid; grid-template-columns: repeat(6, 1fr); }
.stats .cell { padding: 26px 20px; border-right: 1px solid var(--rule); }
.stats .cell:last-child { border-right: 0; }
.stats b { display: block; font-size: 21px; font-weight: 800; letter-spacing: -0.02em; }
.stats span { font-size: 9.5px; letter-spacing: 0.08em; color: var(--muted); }

/* cross-sell strip: five tools */
/* A modest, shared transition into One Platform. This replaces the old large
   per-template top padding without letting the label collide with a preceding
   border (most visibly when it follows the stats strip). */
.platform-head { padding-top: 24px; }

/* .platform — section wrapper for the strip. Owns the component's own vertical
   rhythm so pages don't restate it: 24px above matches .capsection (44px clear of
   the section-head), 46px below pairs with the following section's 10px top pad for
   the 56px gap signed off on the Jobs page. */
/* ---------- COMPONENT: "FROM THE FIELD" PROOF BLOCK ---------------------
   One bordered frame divided into three cells: the rotating testimonial as a
   full-width top cell, two case studies sharing the row beneath it.

   The rotator's OWN border is dissolved here and replaced by a shared hairline
   against the case-study row. That is the whole trick — .fieldblock already
   supplies the strong border and 3px radius, so leaving the component's frame
   on would nest a box inside a box, which this system never does. Gutters are
   pulled to 28px so the quote, the attribution and the case-study logos all
   land on the same vertical rules.

   Usage:  <section class="fieldsec"><div class="wrap">
             <div class="seclabel"><span><b>06</b> / FROM THE FIELD</span></div>
             <div class="fieldblock" data-field-block></div>
           </div></section>
   v5-shared.js fills in the rotator and both case studies.

   NOTE: .fieldsec encodes the home page's 72px rhythm. Pages with a tuned gap
   (e.g. the 56px the cross-sell strip sets up) should bring their own section
   wrapper and use .fieldblock alone, or .fieldsec will silently overwrite it. */
.fieldsec { padding: 72px 0; }
.fieldsec .seclabel { padding-bottom: 12px; }
.fieldblock { border: 1px solid var(--rule-strong); border-radius: 3px; overflow: hidden; }
.fieldblock .quoterotator { border: 0; border-bottom: 1px solid var(--rule); border-radius: 0;
  padding: 30px 28px; align-content: center; }
/* data-cases="none": testimonial only, no case-study row. The rotator is then the
   frame's only cell, so its bottom hairline has nothing to divide and comes off. */
.fieldblock.fb-solo .quoterotator { border-bottom: 0; }
.fieldblock .fb-cases { display: grid; grid-template-columns: 1fr 1fr; }
.fieldblock .fb-cases .casecard { border-right: 1px solid var(--rule); }
.fieldblock .fb-cases .casecard:last-child { border-right: 0; }


.xsell { display: grid; grid-template-columns: repeat(5, 1fr); border: 1px solid var(--rule-strong); border-radius: 3px; overflow: hidden; }
.xsell a { padding: 18px; border-right: 1px solid var(--rule); text-decoration: none; color: var(--ink); }
.xsell a:last-child { border-right: 0; }
.xsell a:hover { background: var(--accent-soft); }
.xsell em { font-style: normal; font-size: 9px; letter-spacing: 0.1em; color: var(--muted); display: block; margin-bottom: 10px; }
.xsell b { display: block; font-size: 13.5px; margin-bottom: 6px; }
.xsell p { font-family: "Instrument Sans", sans-serif; font-size: 11.5px; line-height: 1.45; color: var(--muted); }
.xsell a.here { background: var(--accent-soft); }
.xsell a.here em { color: var(--accent); }

/* ---------- product figure library (moved from layout-d) ---------- */
/* JOBS figure — job status cards (current-site concept, restyled) */
.jcard { border: 1px solid var(--rule-strong); border-radius: 3px; background: var(--bg); padding: 14px 16px; margin-bottom: 12px; font-size: 11.5px; }
.jcard:last-child { margin-bottom: 0; }
.jtop { display: flex; justify-content: space-between; margin-bottom: 10px; }
.jtop b { font-size: 12.5px; }
.jtop span { color: var(--muted); }
.jprog { height: 6px; background: var(--rule); border-radius: 2px; overflow: hidden; margin-bottom: 10px; }
@keyframes fillbar { from { width: 0; } to { width: 74%; } }
.jprog i { display: block; height: 100%; background: var(--accent); animation: fillbar 2.4s 0.4s ease-out both; }
.jmeta { display: flex; justify-content: space-between; font-size: 10.5px; color: var(--muted); }
.jmeta .run { color: var(--accent); }
.jcard.failcard { border-color: color-mix(in srgb, var(--down) 55%, var(--rule)); }
.jcard.failcard .jmeta .bad { color: var(--down); font-weight: 600; }

/* CHECKS figure — url node + radiating assertions (current-site concept) */
.ckurl { border: 1px solid var(--rule-strong); border-radius: 3px; background: var(--bg); padding: 10px 14px;
  font-size: 12px; text-align: center; width: fit-content; margin: 0 auto; }
.ckstem { width: 1px; height: 16px; background: var(--rule-strong); margin: 0 auto; }
.ckgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@keyframes ckIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.ck { border: 1px solid var(--rule); border-radius: 3px; background: var(--bg); padding: 10px 12px; font-size: 10.5px;
  color: var(--body); animation: ckIn 0.35s both; }
.ck b { color: var(--up); font-weight: 600; margin-right: 6px; }
.ck:nth-child(1) { animation-delay: 0.3s; } .ck:nth-child(2) { animation-delay: 0.65s; }
.ck:nth-child(3) { animation-delay: 1.0s; } .ck:nth-child(4) { animation-delay: 1.35s; }

/* HEARTBEATS figure — event stream timelines (current-site concept) */
.hstream { display: grid; grid-template-columns: 110px 1fr; gap: 14px; align-items: center; padding: 11px 0; border-top: 1px dashed var(--rule); }
.hstream:first-child { border-top: 0; }
.hstream .hl { font-size: 10.5px; color: var(--muted); }
.hdots { display: flex; justify-content: space-between; align-items: center; }
@keyframes dotIn { from { opacity: 0; } to { opacity: 1; } }
.hdots i { width: 7px; height: 7px; border-radius: 50%; background: var(--up); animation: dotIn 0.2s both; }
.hdots i:nth-child(1) { animation-delay: 0.1s; } .hdots i:nth-child(2) { animation-delay: 0.35s; }
.hdots i:nth-child(3) { animation-delay: 0.6s; } .hdots i:nth-child(4) { animation-delay: 0.85s; }
.hdots i:nth-child(5) { animation-delay: 1.1s; } .hdots i:nth-child(6) { animation-delay: 1.35s; }
.hdots i:nth-child(7) { animation-delay: 1.6s; } .hdots i:nth-child(8) { animation-delay: 1.85s; }
.hdots i:last-child { animation-name: dotIn, pulse; animation-duration: 0.2s, 2.2s; animation-delay: 1.85s, 2.1s; animation-iteration-count: 1, infinite; }
.hdots i.gap { background: transparent; border: 1.5px solid var(--down); animation-name: dotIn; }
.hnote { font-size: 10px; color: var(--down); text-align: right; padding-top: 8px; }



/* ---------- THE SWEEP: motion signature + causal timing system ---------- */
:root {
  --ease-enter: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-shift: cubic-bezier(0.2, 0, 0, 1);
  --ease-data: cubic-bezier(0.45, 0, 0.55, 1);
  --time-micro: 110ms; --time-state: 180ms; --time-shift: 320ms; --time-enter: 420ms;
}
.sweepline { position: absolute; top: 0; bottom: 0; left: 0; width: 1px;
  background: var(--accent); opacity: 0.55; z-index: 4; pointer-events: none; }
.sweepline::after { content: ""; position: absolute; top: 0; left: -2px; width: 5px; height: 3px; background: var(--accent); }
[data-sweep-board] td { font-variant-numeric: tabular-nums; }
tr.preprint td { color: transparent; }
tr.preprint .ticks i, tr.preprint em { opacity: 0; }
tr td, tr .ticks i, tr em { transition: color 60ms steps(1, end), opacity 120ms var(--ease-shift); }
tr.swept-fail { background: color-mix(in srgb, var(--down) 8%, var(--bg)); box-shadow: inset 2px 0 0 var(--down); }
.st.st-bad { color: var(--down) !important; font-weight: 700; }
.ticks i.tick-bad { background: var(--down); }
/* alert cards: hidden until swept; controlled settle, no bounce */
.alert.sweep-card, .toast.sweep-card { opacity: 0; animation: none; }
@keyframes alertSettle {
  0% { opacity: 0; transform: translate3d(24px, 0, 0); }
  82% { opacity: 1; transform: translate3d(-2px, 0, 0); }
  100% { opacity: 1; transform: none; }
}
.alert.sweep-card.alert-on, .toast.sweep-card.alert-on { animation: alertSettle var(--time-enter) var(--ease-enter) forwards; }
/* backplate depth: the instrument sits on a plate, consequences escape it.
   MUST be a box-shadow, not a `z-index:-1` ::before. A negative-z-index child
   paints above its own stacking context's background AND border, but below
   in-flow descendants — so a pseudo-element plate with an opaque --panel fill
   (a) erased the slab's right + bottom --rule-strong border, (b) flooded the
   interior, since .top/.copycell/.boardcell are all transparent, and (c) drew
   its own hairline 7px INSIDE the top/left edges. Read: content inset from a
   frame top-left, spilling past a pale line bottom-right. An outer box-shadow
   paints strictly outside the border box and under the element's own border,
   so it cannot erase the frame or tint the content. */
/* THE BASE RULE. This sheet used to ship `.slab.backplate` and not `.slab`, so
   every page that used a slab redeclared the base locally — four properties
   copied N times, with `.backplate` below depending on the `overflow: hidden`
   it could not see. component-library 07 logged it as a known gap. */
.slab { border: 1px solid var(--rule-strong); border-radius: 3px; overflow: hidden; position: relative; }
.slab.backplate { overflow: visible !important; background: var(--bg);
  box-shadow: 7px 7px 0 0 var(--panel), 7px 7px 0 1px var(--rule); }
.slab.backplate .boardcell, .slab.backplate .top { border-radius: 3px 3px 0 0; }
.slab.backplate .statusbar { border-radius: 0 0 3px 3px; }

/* ---------- attribution headshots (press-credential treatment) ---------- */
.qcard .who { display: flex; align-items: flex-start; gap: 14px; margin-top: 4px; }
.qcard .who img.face { width: 56px; height: 56px; object-fit: cover; border: 1px solid var(--rule-strong);
  border-radius: 2px; filter: grayscale(1) contrast(1.04); transition: filter var(--time-state, 180ms) var(--ease-shift, ease); flex: none; }
.qcard:hover .who img.face { filter: grayscale(0) contrast(1); }
[data-theme="dark"] .qcard .who img.face { filter: grayscale(1) contrast(0.95) brightness(0.92); }
[data-theme="dark"] .qcard:hover .who img.face { filter: grayscale(0) brightness(0.98); }
.qcard .who .meta b { display: block; font-size: 12px; }
.qcard .who .meta span { font-size: 10.5px; color: var(--muted); }
.qcard .who .meta img.cologo { margin-top: 7px; }
.qcard .who .initials { width: 56px; height: 56px; flex: none; border: 1px solid var(--rule-strong);
  border-radius: 2px; background: var(--panel); display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 600; letter-spacing: 0.04em; color: var(--muted); }
/* attribution: name / role · company / customer since */
.qcard .who .meta { display: block !important; min-height: 0 !important; margin-top: -4px; }
.qcard .who .meta b { display: block; font-size: 13px; line-height: 1.4; }
.qcard .who .meta .role { display: block; font-family: "Instrument Sans", sans-serif; font-size: 13px;
  line-height: 1.4; color: var(--body); letter-spacing: 0; }
.qcard .who .meta .since { display: block; font-size: 10px; letter-spacing: 0.1em; color: var(--muted);
  line-height: 1.4; margin-top: 6px; }

/* h1 cursor retired — the blinking caret at the end of headlines was distracting.
   Kept as a no-op so existing markup/flap logic stays valid. */
h1 .cursor { display: none; }

/* ============================================================
   LOGO MARQUEE
   One continuous row of customer marks, no dividers. Hydrated by
   v5-shared.js out of the existing `.logos .grid` markup, so page HTML
   needs no changes. The `.lm` class is added by the script; the extra
   class beats the per-page `.logos .grid { display:grid }` rules on
   specificity without needing !important.

   Motion: the track holds the list twice and translates by -50%, so the
   wrap is invisible. It is parked by default and moves only while hovered.
   Only `transform` animates. Duration is set inline by the script from the
   measured set width (constant px/sec).
   ============================================================ */
.logos .grid.lm { display: block; padding: 0; border-left: 0; border-right: 0;
  grid-template-columns: none; }
.logos .grid.lm .lm-viewport { height: 96px; overflow: hidden; position: relative;
  border-left: 1px solid var(--rule); border-right: 1px solid var(--rule); }
.logos .grid.lm .lm-track { display: flex; width: max-content; height: 100%;
  align-items: center; will-change: transform; transform: translate3d(0, 0, 0);
  animation: lm-scroll 60s linear infinite; animation-play-state: paused; }
/* Hover is direct interaction: move while engaged, then hold that position.
   A background tab stays paused even if the pointer remains over the strip. */
.logos .grid.lm:hover .lm-track { animation-play-state: running; }
.logos .grid.lm .lm-track.is-paused { animation-play-state: paused; }
.logos .grid.lm .lm-set { display: flex; height: 100%; align-items: center;
  margin: 0; padding: 0; list-style: none; }
.logos .grid.lm .lm-item { flex: 0 0 auto; display: flex; height: 100%;
  align-items: center; justify-content: center; padding: 0 var(--lm-gap, 30px); }
.logos .grid.lm .lm-item img { display: block; width: auto; max-width: none;
  user-select: none; -webkit-user-drag: none;
  filter: grayscale(1) brightness(var(--lm-tone, 1)); }
[data-theme="dark"] .logos .grid.lm .lm-item img {
  filter: grayscale(1) brightness(var(--lm-tone, 1)) invert(1); }
@keyframes lm-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* prefers-reduced-motion: the FULL list, wrapped, no animation.
   ------------------------------------------------------------------------
   THIS BLOCK USED TO HIDE MOST OF THE MARKS FROM THE PEOPLE WHO ASKED FOR
   LESS MOTION. It set `width: 100%` on the track and `justify-content:
   space-between` on the set while `.lm-item` stayed `flex: 0 0 auto` and
   `.lm-viewport` stayed `overflow: hidden` at a fixed 96px/72px. A
   non-shrinking row is not made to fit by `space-between`: it simply
   overflows and the viewport eats it. Measured at 375: nine items summing
   751px in a 335px box — five marks entirely invisible, a sixth half-cut.
   The bug was invisible to every gate because the marquee's viewport is
   allowlisted in the clip gate (e1), and that blessing is only legitimate
   while the ribbon is ACTUALLY SCROLLING: a ribbon longer than its frame is
   the component when it moves, and is hidden content when it does not.
   **Do not allowlist `.lm-viewport` when `.is-static` is present.**

   Three things make it right, and they only work together:
     1. `flex-wrap: wrap` on the set, so a row that does not fit becomes rows;
     2. `height: auto` on the viewport, the track, the set and the items, so
        the extra rows have somewhere to go — the fixed 96px (72px below md)
        is what turned wrapping into clipping;
     3. `align-content` + `row-gap`, so the wrapped rows are spaced like rows
        and not jammed against the top edge.
   `overflow: hidden` is deliberately KEPT: with 1+2+3 nothing overflows, so
   the clip gate can now assert that honestly instead of being told to look
   away. */
.logos .grid.lm.is-static .lm-track { animation: none; width: 100%; height: auto; }
.logos .grid.lm.is-static .lm-viewport { height: auto; }
.logos .grid.lm.is-static .lm-set { width: 100%; height: auto;
  flex-wrap: wrap; justify-content: center; align-items: center;
  align-content: center; row-gap: 16px;
  padding: 22px var(--lm-gap, 30px); }
.logos .grid.lm.is-static .lm-item { height: auto; padding: 0 var(--lm-gap, 30px); }
@media (prefers-reduced-motion: reduce) {
  .logos .grid.lm .lm-track { animation: none; }
}

/* ============================================================
   COMPONENT — ALERT TOAST
   One component, many payloads. Used wherever Cronitor notifies
   a human: hero figures, product figures, integration fan-outs.

   Anatomy:
     .toast                       the card
       .toast-head                chip + destination on one line
         .toast-chip              platform badge (Slack, PagerDuty…)
         .toast-dest              where it went (#ops-alerts, on-call: primary)
       .toast-msg                 the event, one line, status-coloured
       .toast-meta                optional second line (muted, sparse)

   Status:  default = down/red.  .is-up = recovery.  .is-warn = degraded.
   Motion:  .is-hidden then .is-in  →  settle from the right, no bounce.
   Layout:  static by default; add .is-float + inline top/right for figures,
            or wrap several in .toast-stack for a pile.
   ============================================================ */
.toast { width: 248px; background: var(--alert-bg); border: 1px solid var(--rule-strong);
  border-radius: 3px; padding: 10px 12px; font-size: 11px;
  box-shadow: 4px 4px 0 color-mix(in srgb, var(--ink) 14%, transparent); }
.toast-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.toast-chip { display: inline-block; font-size: 9px; line-height: 1.5; color: #fff;
  background: var(--ink); border-radius: 2px; padding: 2px 6px; white-space: nowrap; }
.toast-dest { font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.toast-msg { display: block; font-size: 11.5px; font-weight: 600; color: var(--down); }
.toast-msg::before { content: "● "; }
.toast-meta { display: block; margin-top: 5px; font-size: 10px; color: var(--muted); }
.toast.is-up .toast-msg { color: var(--up); }
.toast.is-up .toast-msg::before { content: "✓ "; }
.toast.is-warn .toast-msg { color: var(--gold); }
.toast.is-warn .toast-msg::before { content: "▲ "; }

/* platform chips — brand colour is allowed here (it identifies a third party) */
.toast-chip.slack     { background: #4A154B; }
.toast-chip.pagerduty { background: #04AC38; }
.toast-chip.email     { background: #B23121; }
.toast-chip.sms       { background: #2E6F9E; }
.toast-chip.teams     { background: #4B53BC; }
.toast-chip.discord   { background: #5865F2; }
.toast-chip.opsgenie  { background: #172B4D; }
.toast-chip.telegram  { background: #2AABEE; }
.toast-chip.webhook   { background: var(--accent); }

/* entrance */
.toast.is-hidden { opacity: 0; }
.toast.is-in { animation: alertSettle var(--time-enter) var(--ease-enter) forwards; }
.toast.is-float { position: absolute; z-index: 5; }
.toast-stack { display: flex; flex-direction: column; gap: 8px; }

@media (prefers-reduced-motion: reduce) {
  .toast.is-hidden { opacity: 1; }
  .toast.is-in { animation: none; }
}

/* ============================================================
   THE HERO ALERT STACK — ONE PLACEMENT FOR EVERY HERO.

   Six heroes raise an alert over a 600px figure and, until this rule existed,
   all six placed it differently: `right:-24/top:64`, `right:-30/top:-53`,
   `right:-26/bottom:-52`, `right:-70/bottom:-44`, plus the homepage's own
   ladder. Four of them also carried a private media query to drop the card
   into the flow, at four different breakpoints (643.98 / 645.98 / 683.98 /
   689.98), each derived from that page's own overhang, each with its own
   forty-line comment explaining the derivation. That is five copies of one
   decision, and the next person to move the corner would have moved one of
   them.

   WEAR `herostack` ON THE POSITIONED WRAPPER — the box that already carries
   `position: relative` and the 600px figure track — and the cards inside it
   are placed by this rule alone. A page supplies its CARDS and, if its frame
   is inset inside that wrapper, its SHOULDER. It does not supply geometry.

   THE CARD NEVER JOINS THE FLOW. That is the substantive change and it is what
   removes the dead band: an in-flow card has to be RESERVED (or the figure
   reflows mid-story), and a reservation is a hole in the page for every frame
   the card is not up — 140px of it under the homepage board at 375, between
   the figure and the logo marquee. Absolute at every width means the stage is
   exactly as tall as its figure, there is nothing to reserve, and nothing can
   shift. The card overhangs the frame's top-right corner instead, which is
   where it already sat on desktop.

   THE OVERHANG IS A BUDGET, NOT A TASTE. `--hero-card-overhang` is the negative
   margin that moves the card past the frame's right rule, and it is capped by
   the gutter: the shared wrap gutter is 20px below md and 40px from md, so the
   card hangs 30px at md and up and sits FLUSH below it. Flush rather than 20px
   because the entrance still travels 24px sideways (alertSettle), and 20 + 24
   would push the document 4px wider than the viewport while it animates —
   a transient overflow a persistent-only clip gate cannot see. Below md the
   entrance is swapped for a vertical one instead, which is the same fix the
   homepage needed and which the four product pages were all still missing.

   `--hero-card-rise` is how far it clears the frame's top edge. 20px: a
   stacked hero has 36px of `.phero .wrap` gap above its figure, so the card
   still leaves 16px of air under the copy. Do not raise it without checking
   that gap — it is the only thing between the card and the CTA row.

   `--hero-card-slot` is the card's index in the stack, 0 for a hero with one
   card and written by the page's script for a hero with several. It must be
   DERIVED from the frame's own state, never accumulated, or seeking and
   scrubbing backwards land on stale offsets.
   ============================================================ */
.herostack {
  --hero-card-overhang: 0;
  /* past the frame's right rule */
  --hero-card-rise: 20px;
  /* above the frame's top rule */
  --hero-card-pitch: 69px;
  /* card height + gap; only used past slot 0 */
  --hero-frame-shoulder: 0px;
  /* frame inset inside this wrapper, if any */
}

@media (min-width: 768px) {
  .herostack {
    --hero-card-overhang: -30px;
  }
}

.herostack>.toast.is-float,
.herostack>.alert.sweep-card,
.herostack>.toast.sweep-card {
  position: absolute;
  /* Keep the two lengths out of calc(): Yuglify turns 0px custom properties
     into unitless 0, which invalidates mixed length arithmetic at runtime. */
  right: var(--hero-frame-shoulder);
  margin-right: var(--hero-card-overhang);
  top: calc(var(--hero-card-slot, 0) * var(--hero-card-pitch) - var(--hero-card-rise));
  bottom: auto;
  left: auto;
  transition: top var(--time-shift) var(--ease-shift);
}

/* A CARD THAT IS NOT ON SCREEN JUMPS, IT DOES NOT SLIDE. Off-screen cards park
   at the bottom of the stack so an arriving alert never travels, but the
   stack's depth changes underneath them — transitioning that is an invisible
   box moving for no reason, and it makes the geometry unmeasurable in flight.
   The only slide left is the one a reader is meant to see: a visible card
   moving up into space a withdrawal has just vacated. */
.herostack>.toast.is-hidden,
.herostack>.alert.sweep-card:not(.alert-on):not(.alert-out) {
  transition: none;
}

/* THE ENTRANCE COMES FROM THE FLOW'S DIRECTION WHEN THERE IS NO GUTTER TO FLY
   IN FROM. alertSettle starts at translate3d(24px,0,0), which is right for a
   card arriving past the right edge of a figure that has room beside it. Below
   md there is no room: the card is flush with the frame and those 24px are
   4px of horizontal document overflow for the ~400ms of the entrance.
   Measured at 375 on the homepage: scrollWidth 379 against clientWidth 375,
   transient, which is exactly why a persistent-only clip gate never saw it.
   Only `animation-name` is overridden, so duration, easing and fill still come
   from the rule above. */
@keyframes heroLand {
  0% {
    opacity: 0;
    transform: translate3d(0, 7px, 0);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 767.98px) {

  .herostack>.toast.is-in,
  .herostack>.alert.sweep-card.alert-on,
  .herostack>.toast.sweep-card.alert-on {
    animation-name: heroLand;
  }
}

@media (prefers-reduced-motion: reduce) {

  .herostack>.toast.is-float,
  .herostack>.alert.sweep-card,
  .herostack>.toast.sweep-card {
    transition: none;
  }
}

/* ============================================================
   COMPONENT — QUOTE ROTATOR
   The six customer testimonials, one at a time. Same anatomy as
   the cards on the Customers page: headshot + name / role · company
   / CUSTOMER SINCE. Swaps every 7s, pauses on hover, fixed height
   so the page never reflows.
   Usage:  <div class="quoterotator" data-quote-rotator></div>
   ============================================================ */
.quoterotator { border: 1px solid var(--rule-strong); border-radius: 3px; padding: 30px 34px;
  display: grid; grid-template-columns: 1fr 250px; gap: 40px; align-items: center; min-height: 132px; }
.quoterotator .qr-slot { position: relative; }
.quoterotator .qr-q { font-family: "Instrument Sans", sans-serif; font-size: 16px; line-height: 1.6;
  color: var(--body); margin: 0; }
.quoterotator .qr-who { display: flex; align-items: flex-start; gap: 14px; }
.quoterotator .qr-who img { width: 56px; height: 56px; object-fit: cover; border: 1px solid var(--rule-strong);
  border-radius: 2px; filter: grayscale(1) contrast(1.04); flex: none;
  transition: filter var(--time-state) var(--ease-shift); }
.quoterotator:hover .qr-who img { filter: grayscale(0) contrast(1); }
[data-theme="dark"] .quoterotator .qr-who img { filter: grayscale(1) contrast(0.95) brightness(0.92); }
[data-theme="dark"] .quoterotator:hover .qr-who img { filter: grayscale(0) brightness(0.98); }
.quoterotator .qr-meta { margin-top: -4px; }
.quoterotator .qr-name { display: block; font-size: 13px; font-weight: 700; line-height: 1.4; }
.quoterotator .qr-role { display: block; font-family: "Instrument Sans", sans-serif; font-size: 13px;
  line-height: 1.4; color: var(--body); }
.quoterotator .qr-since { display: block; font-size: 10px; letter-spacing: 0.1em; color: var(--muted);
  line-height: 1.4; margin-top: 6px; }
.quoterotator .qr-fade { animation: qrIn 320ms var(--ease-enter) both; }
@keyframes qrIn { from { opacity: 0; transform: translate3d(0, 5px, 0); } to { opacity: 1; transform: none; } }
.quoterotator .qr-dots { grid-column: 1 / -1; display: flex; gap: 6px; align-items: center; margin-top: 4px; }
.quoterotator .qr-dots i { width: 14px; height: 2px; background: var(--rule); display: block; cursor: pointer; }
.quoterotator .qr-dots i.on { background: var(--accent); }
.quoterotator .qr-idx { margin-left: auto; font-size: 9.5px; letter-spacing: 0.12em; color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .quoterotator .qr-fade { animation: none; } }

/* ============================================================
   COMPONENT — CAPABILITY GLYPHS
   Small graphical marks for the capability grids on product pages.
   Reference sheet: _capglyphs.html.

   Usage:  <div class="pgrid" data-glyph-grid data-glyph-cols="2">
             <div class="pcell" data-glyph="performance"> … </div>
             …
           </div>
   v5-shared.js builds the mark and runs the sweep. Adding a glyph to
   another grid is one attribute per cell plus one on the grid.

   GRAMMAR
   Every glyph is the same 48x28 instrument (28x28 in the square): a 1px
   --rule bezel over a --bg plate, marks drawn as one inline SVG on whole
   pixels, inset 3px from the bezel. Every glyph is a miniature of the
   data shape its concept actually produces, never a pictogram of it.

   Three inks. --muted for context. --accent (violet) for history and the
   subject, on one ladder: 1 for the subject, 0.55 for history, 0.3 for
   context, a 0.12 fill. --accent-2 for the live moment — the running
   job, the latest beat, the visitor, the check just added — once per
   glyph, and last in its entrance. --accent-2 is --up, the same green
   as a healthy monitor: the live moment is the system working. Gold and
   red stay reserved for monitor state. No gradients, no blur, no glow.

   MOTION
   The rules below are the RESTING state, which is also the FINAL state,
   so a glyph that never plays — reduced motion, JS off, an observer that
   never fires — is already correct and legible. Motion is scoped to
   .is-play only, one entrance per glyph under 550ms, and animates
   transform / opacity / clip-path only, with steps(1) for discrete marks.
   ============================================================ */

/* PLACEMENT — the kicker row becomes a chrome bar: label left,
   instrument flush right. Because it is flush right the glyphs land on a
   shared vertical edge down the grid and read as a column — a set, at a
   glance. Quotes .seclabel and .fchrome, which already do this. */
.gchrome { display: flex; align-items: center; justify-content: space-between;
  gap: 20px; min-height: 28px; }
/* a cell with no kicker to pair with — the instrument still hangs right */
.gchrome.is-bare { justify-content: flex-end; }
/* the chrome bar carries the kicker's leading, so the heading tightens up.
   Scoped through [data-glyph] so it outranks per-page .pcell/.cap rules. */
[data-glyph] .gchrome + h3,
[data-glyph] .gchrome + b { margin-top: 10px; }

.capglyph { position: relative; flex: none; display: block; width: 48px; height: 28px;
  border: 1px solid var(--rule); background: var(--bg); overflow: hidden; font-size: 0; }

/* ---- SQUARE VARIANT — 28x28, for a LEADING position ----
   Opt in with data-glyph-size="sq" on the cell or any ancestor of it
   (the nav puts it once on .nm-grid). 28 is the landscape mark's own
   height, so the vertical grid is the same grid and only the width
   moves. Each mark is REDRAWN for the square, not rescaled: a scale()
   puts every hairline on a fractional device pixel. */
.capglyph.is-sq { width: 28px; height: 28px; }

/* discrete marks step in — no fade on something that is either on or off */
@keyframes cgStep { from { opacity: 0; } }

/* ---- MARKS — product: jobs · checks · heartbeats · statuspages · sites;
   capability: performance · coverage · alerts ----
   Drawn by productGlyphSvg() (v5-shared.js and app/src/components/
   productGlyphSvg.js, twins). The SVG covers the whole box; the box's own
   border is the bezel. Paint classes: f- fill, s- stroke; ac = --accent,
   mu = --muted, ru = --rule, k2 = --accent-2, soft = --accent-soft. */
.capglyph > .cg-svg { position: absolute; left: -1px; top: -1px; display: block; overflow: hidden; }
.cg-svg .f-ac { fill: var(--accent); }
.cg-svg .f-mu { fill: var(--muted); }
.cg-svg .f-ru { fill: var(--rule); }
.cg-svg .f-k2 { fill: var(--accent-2); }
.cg-svg .f-soft { fill: var(--accent-soft); }
.cg-svg .f-bg { fill: var(--bg); }
.cg-svg .s-ac, .cg-svg .s-mu, .cg-svg .s-ru, .cg-svg .s-k2 { fill: none; stroke-width: 1; }
.cg-svg .s-ac { stroke: var(--accent); }
.cg-svg .s-mu { stroke: var(--muted); }
.cg-svg .s-ru { stroke: var(--rule); }
.cg-svg .s-k2 { stroke: var(--accent-2); }
.cg-svg polyline, .cg-svg .ln { stroke-linejoin: round; stroke-linecap: round; }
/* the visitor's cursor keeps a plate-coloured outline so it reads over the line */
.cg-svg .cur { stroke: var(--bg); stroke-width: 0.8; stroke-linejoin: round; paint-order: stroke; }

/* motion: context, then history, then the green live moment last */
.capglyph.is-play .x-sweep { animation: cgSweep 520ms var(--ease-data) both; transform-box: view-box; }
@keyframes cgSweep { from { opacity: 0.2; transform: rotate(-275deg); } }
.capglyph.is-play .x-pop, .capglyph.is-play .x-ping, .capglyph.is-play .x-up, .capglyph.is-play .x-bar,
.capglyph.is-play .x-grow { transform-box: fill-box; }
.capglyph.is-play .x-pop { animation: cgPop 200ms var(--ease-enter) both; animation-delay: var(--d, 0ms);
  transform-origin: center; }
@keyframes cgPop { from { opacity: 0; transform: scale(0.2); } }
/* one ping: overshoot, then settle at the resting opacity */
.capglyph.is-play .x-ping { animation: cgPing 420ms var(--ease-enter) both; animation-delay: var(--d, 0ms);
  transform-origin: center; }
@keyframes cgPing { 0% { opacity: 0; transform: scale(0.2); } 45% { opacity: 1; transform: scale(1.5); } 100% { transform: scale(1); } }
.capglyph.is-play .x-wipe { animation: cgWipe 520ms var(--ease-data) both; }
@keyframes cgWipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.capglyph.is-play .x-up { animation: cgUp 160ms var(--ease-data) both; animation-delay: var(--d, 0ms);
  transform-origin: bottom; }
@keyframes cgUp { from { transform: scaleY(0); } }
.capglyph.is-play .x-step { animation: cgStep 1ms steps(1, end) both; animation-delay: var(--d, 0ms); }
.capglyph.is-play .x-fade { animation: cgFade 260ms var(--ease-enter) both; animation-delay: var(--d, 0ms); }
@keyframes cgFade { from { opacity: 0; } }
.capglyph.is-play .x-cursor { animation: cgCursor 320ms var(--ease-enter) both; animation-delay: var(--d, 0ms); }
@keyframes cgCursor { from { opacity: 0; transform: translate(5px, 5px); } }
.capglyph.is-play .x-bar { animation: cgGrow 200ms var(--ease-shift) both; animation-delay: var(--d, 0ms);
  transform-origin: left; }
@keyframes cgGrow { from { transform: scaleX(0); } }
/* jobs: a bar fills while the playhead crosses it, so both run linear on one clock */
.capglyph.is-play .x-grow { animation: cgGrow var(--t, 100ms) linear both; animation-delay: var(--d, 0ms);
  transform-origin: left; }
.capglyph.is-play .x-ph { animation: cgPlayhead var(--t, 480ms) linear both; }
@keyframes cgPlayhead { from { transform: translateX(var(--from, 0px)); } }
.capglyph.is-play .x-arc { animation: cgArc 300ms var(--ease-enter) both; animation-delay: var(--d, 0ms);
  transform-box: view-box; }
@keyframes cgArc { from { opacity: 0; transform: translateX(-2px); } }
/* alerts: the notification card arrives from the right */
.capglyph.is-play .x-slide { animation: cgSlide 300ms var(--ease-enter) both; animation-delay: var(--d, 0ms); }
@keyframes cgSlide { from { opacity: 0; transform: translateX(8px); } }

/* the whole design has to stand without motion, and here it does: the
   resting state above IS the finished drawing. */
@media (prefers-reduced-motion: reduce) {
  .capglyph *, .capglyph *::after { animation: none !important; }
}

/* ============================================================
   COMPONENT — TOP-NAV DROPDOWN MENUS
   Built by v5-shared.js out of the plain `Product` / `Developers`
   links every page already ships. No page markup changes.

   PRODUCT is full width. Five cells will not fit under a trigger
   180px from the left edge without either stacking to two rows or
   shrinking below the width the descriptions need, and the strip
   already has a full-width precedent on this site: the cross-sell.
   The panel bleeds edge to edge, but the CELLS sit in a .wrap, so
   its five columns land on exactly the x positions of the
   cross-sell strip further down the same page. Two views of one
   object, aligned.

   DEVELOPERS is anchored: five one-line rows, ~330px, measured off
   its trigger. A full-width panel for five short rows would be a
   mostly-empty band across the viewport.

   DEPTH is a hard offset, never blur. The anchored
   panel takes the alert card's 4px 4px 0; the full-bleed panel
   takes a bottom-only offset, because a right-hand offset on an
   edge-to-edge panel is a shadow with nothing to fall on.

   MOTION is 130ms of opacity and a 4px lift, and nothing else. The
   panel is hidden with `visibility`, not `display`, so it holds a
   real box from first paint — which is what lets the capability
   glyphs inside it draw once at load, before the menu is ever
   opened, and lets `visibility: hidden` keep the links out of the
   tab order and the accessibility tree while closed.
   ============================================================ */
/* THE TRIGGER'S RESET AND TYPE ARE NOT NAV-SPECIFIC; ITS COLOURS ARE.
   This declaration used to be one `nav.site .nm-trigger` block bundling a UA
   button reset (background/border/padding/font-family) with the nav type and
   the nav hover colour. That made a component impossible to document or reuse:
   a `.nm-trigger` standing anywhere but inside a `nav.site` rendered as a
   default browser button, which is why component-library 24 had to point at
   the live nav instead of showing a specimen. Split, so the reset travels with
   the class and only the palette stays scoped.

   The reset is at (0,1,0) on purpose. Inside the nav it is *supposed* to lose
   to the sheet's `nav.site > .wrap > .nl` (0,3,1) below lg — it already did,
   since the old (0,2,1) form lost to it too — and there is no other rule in
   the sheet that matches the trigger, so desktop is unchanged. Verified by
   computed style at 1440: identical before and after. */
.nm-trigger { display: inline-flex; align-items: center; gap: 7px;
  font-family: inherit; font-size: 13px; font-weight: 500; color: var(--muted);
  background: none; border: 0; padding: 0; cursor: pointer; line-height: 1.2; }
nav.site .nm-trigger:hover,
nav.site .nm-trigger[aria-expanded="true"] { color: var(--accent); }
nav.site .nm-trigger:focus-visible { outline: 1px solid var(--accent); outline-offset: 4px; }

/* 1px chevron — same hairline grammar as the rules and glyphs, not an icon */
.nm-caret { width: 5px; height: 5px; margin-top: -3px; flex: none;
  border-right: 1px solid currentColor; border-bottom: 1px solid currentColor;
  transform: rotate(45deg); transition: transform var(--time-state) var(--ease-shift); }
.nm-trigger[aria-expanded="true"] .nm-caret { transform: rotate(225deg) translate(-2px, -2px); }

/* `top: 100%; margin-top: 1px`, NOT a calc() adding the 1px: the production
   bundle goes through yuglify, whose cssmin strips the spaces around `+`
   inside calc(), which is invalid CSS. The browser dropped the whole `top`
   and the panel opened over the nav bar. The 1px steps over nav.site's
   bottom rule. See tests/v5-shared.test.js. */
.nm-panel { position: absolute; top: 100%; margin-top: 1px; z-index: 1;
  background: var(--bg); opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-4px);
  transition: opacity 130ms var(--ease-shift), transform 130ms var(--ease-shift),
              visibility 0s 130ms; }
.nm-panel.is-open { opacity: 1; visibility: visible; pointer-events: auto;
  transform: none; transition-delay: 0s, 0s, 0s; }
.nm-panel a:focus-visible { outline: 1px solid var(--accent); outline-offset: -3px; }

.nm-wide { left: 0; right: 0; border-bottom: 1px solid var(--rule-strong);
  box-shadow: 0 4px 0 color-mix(in srgb, var(--ink) 8%, transparent); }
.nm-anchor { left: 0; width: 330px; border: 1px solid var(--rule-strong); border-radius: 2px;
  box-shadow: 4px 4px 0 color-mix(in srgb, var(--ink) 12%, transparent); }

/* ---- PRODUCT: a five-cell ruled row, the cross-sell strip's geometry ----

   TWO ROWS, not four. The cell used to run: chrome bar (`01` left,
   instrument right) / name / description / `Learn more →`. Both ends of
   that went:

   - the `01`–`05` index earns its place in the cross-sell strip, where it
     numbers five ordered products on a page. In a menu it is an ordinal
     nobody navigates by, and it was the only reason the instrument needed
     a row to itself.
   - `Learn more →` repeated five times inside five links, in a panel
     where every row is a link by definition. The sibling Developers menu
     never had one; with it, the two menus in one nav disagreed about what
     a menu row is. The hover fill and the accent name are the affordance.

   So the instrument moves down beside the NAME, pairing the mark with the
   thing it measures instead of with a number.

   Placement is explicit grid, which means the component's DOM order
   (chrome, name, description) is untouched — the glyph component still
   inserts its own bare .gchrome ahead of everything and knows nothing
   about this. */
.nm-grid { display: grid; grid-template-columns: repeat(5, 1fr); }

/* WHY THE INSTRUMENT LEADS THE NAME, AND WHAT IT COST.
   The cell is 216px at 1280 and 36px of that is padding, so 180px of
   content. Leading with the 48x28 landscape mark takes 58 of those 180,
   which is a third of the cell handed to a decoration, and the name is
   shunted 58px right of its own description. That is why the mark had to
   be redrawn square first: the 28x28 variant costs 40px including its
   gap — 22% of the cell instead of 32% — and the name still clears its
   longest string, `Status Pages`, by 28px inside the 140px that leaves.

   WHERE THE DESCRIPTION ALIGNS: the cell's left edge, not the name's.
   Both were built and looked at, and the arithmetic decides it before
   taste gets a vote. Measured on the live page, at 13.5px Instrument
   Sans / 1.6 the five descriptions all hold TWO lines down to a 153px
   measure and the longest two break to three at 152. Indenting the
   description to the name leaves 180 - 40 = 140px. So a name-aligned
   description is three lines for `Share uptime on a public or private
   status page.` and `Track website traffic, errors, and performance.`
   while the other three stay at two — the shared baseline gone, which is
   the whole thing this layout exists to protect. Getting a name-aligned
   description back to 153px would need the glyph and its gap under 27px
   TOTAL, and a ~20px instrument is a smudge, not an instrument.

   (This is where the previous pass went wrong, and it is worth writing
   down: it assumed the descriptions needed all 180px. They do not. The
   floor is 153. The 48x28 mark failed because 122 < 153, not because
   180 was required — and 153 is what leaves a square mark room to lead.)

   So the description keeps the full 180px and starts at the cell edge,
   under the glyph rather than under the name. The pair that shares a
   left edge is therefore INSTRUMENT + PROSE, with the name inset between
   them. Two things stop that reading as a ragged L. The inset is 40px,
   not 58 — closer to one indent than to a second column. And the mark is
   square, so it has a left edge of its own to hold the corner, where the
   48px landscape mark had a long horizontal top that pulled the eye
   right and away from the text below it.

   THE RHYTHM is unchanged, and that is the second dividend of drawing
   the square variant at 28: the row is still exactly as tall as the
   instrument. The name is centred in a 28px row — a 21px line box
   (15.5px JetBrains Mono) leaves 3.5px of slack under it, so 5px of
   row-gap reads as ~15px of white between the name's descender and the
   description's cap. Top pad 16 measures to the instrument; bottom 17
   measures to the last line of prose, whose 1.6 line-height already
   carries ~2px of half-leading under it, so the two optical margins
   match. The cell is the same height it was with the mark on the right. */
/* The column gap goes 10 -> 12 with the mark. Trailing, it was the space
   between a name and something hanging off the far edge of the cell and
   10px was plenty; leading, it is the space between a mark and the label
   it introduces, and 10 read as a collision. 12 is four of the glyph's
   own 3px increments and two thirds of the cell's 18px inset, so the
   pair still sits inside the cell as one object. 14 detaches them. */
.nm-cell { min-width: 0; display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; column-gap: 12px; row-gap: 5px; padding: 16px 18px 17px;
  border-left: 1px solid var(--rule); text-decoration: none; color: var(--ink); }
.nm-cell:first-child { border-left: 0; }
.nm-cell:hover { background: var(--accent-soft); }
/* TYPE IS NAV-ONLY, and deliberately not .xsell's.
   These sizes used to be inherited from the cross-sell strip — 13.5/11.5 —
   and that inheritance was the mistake. A footer strip is scanned
   peripherally on the way past; a dropdown is read at close attention by
   someone who deliberately opened it. They are different reading
   distances and want different scales. The tell is that 11.5px was below
   the design system's own prose floor: prose is Instrument Sans 13.5–15.5px /
   1.6–1.75, so the description was never set as prose at all. It is now,
   at the bottom of that range. The name goes to 15.5px to stay a heading
   above it, keeping the ~1.15 name/description ratio the old pair had.
   16.5px is the last size that fits `Status Pages` in the 122px name
   column and 17px wraps it, so 15.5 also keeps ~10px of slack in hand —
   and the square mark widened that column from 122 to 140, so the slack
   is now ~28px. .xsell's own type is untouched. */
.nm-cell b { grid-area: 1 / 2; font-size: 15.5px; }
.nm-cell .gchrome { grid-area: 1 / 1; }
/* the glyph component tightens a heading that sits UNDER its chrome bar;
   these sit side by side, so that 10px would be a stray indent */
.nm-cell .gchrome + b { margin-top: 0; }
.nm-cell:hover b { color: var(--accent); }
.nm-cell p { grid-area: 2 / 1 / 3 / -1; font-family: "Instrument Sans", sans-serif;
  font-size: 13.5px; line-height: 1.6; color: var(--muted); }

/* ---- DEVELOPERS: five ruled rows sharing 1px borders ---- */
.nm-list a { display: block; padding: 13px 16px; text-decoration: none; color: var(--ink);
  border-top: 1px solid var(--rule); }
.nm-list a:first-child { border-top: 0; }
.nm-list a:hover { background: var(--accent-soft); }
.nm-list b { display: block; font-size: 12.5px; font-weight: 600; }
.nm-list a:hover b { color: var(--accent); }
.nm-list p { font-family: "Instrument Sans", sans-serif; font-size: 11.5px; line-height: 1.45;
  color: var(--muted); margin-top: 4px; }
.nm-ext { color: var(--muted); font-size: 9.5px; margin-left: 6px; vertical-align: 1px; }

/* Narrow: five columns of prose stop working long before the nav wraps.
   The breakpoint is measured, not chosen, and it MOVES whenever the cell
   does — 1060 when the name ran at 13.5px, 1130 at 15.5px beside a 48px
   instrument, and 1050 now that the instrument is 28px and leads.

   TWO constraints, and for the first time the name is the tighter one.

   1. THE NAME. `Status Pages` is 12 characters of JetBrains Mono, whose
      advance is exactly 0.6em, so at 15.5px it is 111.6px of ink. Its
      column is the cell less 1px of border, 36px of padding, the 28px
      instrument and the 12px gap — cell - 77 — and .wrap (max-width
      1160, 40px gutters) makes cell = (vw - 80) / 5. One line therefore
      wants vw >= 1023. Measured rather than trusted: it still sets on one
      line at 1034 and wraps at 1032, the extra ~2px being the line
      breaker's own rounding.

   2. THE DESCRIPTIONS. They now take the full cell width, so their
      measure is cell - 37, and all five hold two lines down to 153px
      (152 breaks the longest two to three). That wants vw >= 1027.

   Stack at 1050, not 1034. Stacking at the wrap point leaves the layout
   a subpixel from breaking; at 1051 — the narrowest five-column width
   this leaves — the name column is 117.2px against 111.6 of ink and the
   description measure is 157.2 against a 152.2 break, so both carry
   ~5px, which is the margin every earlier version carried. Below
   it the longest name wraps and that one cell's description drops out of
   line with the other four — the shared baseline is the thing being
   protected.

   Note the direction of the change: the square mark bought 80px of
   five-column range back, because it takes 40px of the cell where the
   landscape mark took 58. */
@media (max-width: 1050px) {
  .nm-grid { grid-template-columns: 1fr; }
  .nm-cell { border-left: 0; border-top: 1px solid var(--rule); padding: 12px 0; }
  .nm-cell:first-child { border-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .nm-panel { transition: opacity 0s, transform 0s, visibility 0s; transform: none; }
  .nm-caret { transition: none; }
}

/* ============================================================
   COMPONENT: AUTH CARD   (page-login, page-signup)
   ============================================================
   The card shell and its form controls were copy-pasted into both auth
   pages' <style> blocks. That duplication is what produced the 302px vs
   400px mismatch: two definitions of one number, and only one of them
   got fixed. The width now exists once, as --authcard-w, and BOTH the
   card's max-width and page-signup's grid track read it — so the track
   and the card cannot disagree either.

   WIDTH — 468px, and the number is measured, not chosen.
   `Monitoring made for developers.` is 31 characters of JetBrains Mono
   700 at 22px. The advance is exactly 0.6em (13.2px) and letter-spacing
   is -0.025em (-0.55px), so the line is 31 x 12.65 = 392.16px of ink,
   confirmed against a nowrap clone on the live page. Add the card's two
   30px paddings and two 1px borders and the heading needs a 454.16px
   card to set on one line. 468 clears it with 13.8px — about one
   character — of slack.

   468 also squares the layout: page-signup's grid runs
   [card | 72px gutter | aside] inside .wrap's 1080px content column,
   so a 468px card leaves the aside exactly 540px, half the measure.

   BOTH PAGES TAKE IT. page-login's `Sign in to continue` needs only
   ~250px, so login does not need the width — but the two pages link to
   each other from the nav, and a card that jumps 68px wider when you
   click "Sign In" is the visible inconsistency, not the extra
   whitespace. One component, one width. The cost is a 406px email
   field, which is well inside normal for a centred auth form.
   ============================================================ */
:root { --authcard-w: 468px; }

.authcard { position: relative; max-width: var(--authcard-w); width: 100%;
  border: 1px solid var(--rule-strong); border-radius: 3px; background: var(--bg);
  padding: 32px 30px 28px;
  /* MUST be an outer box-shadow, not a `z-index:-1` ::before. A negative-z-index
     child paints above its own stacking context's background AND border but below
     in-flow descendants, so an opaque plate erased the card's right + bottom
     --rule-strong border, flooded the interior with --panel, and drew its own
     hairline 7px inside the top/left edges. An outer box-shadow paints strictly
     outside the border box and under the element's own border. */
  box-shadow: 7px 7px 0 0 var(--panel), 7px 7px 0 1px var(--rule); }
.authcard h1 { font-size: 22px; font-weight: 700; line-height: 1.3; margin-bottom: 22px; }

/* `.or` and `.field` are names generic enough to collide with any page
   added later, so now that they live in the shared sheet they are scoped
   to the card that owns them rather than left loose in the global space. */
.authcard .or { display: flex; align-items: center; gap: 12px; font-size: 10px; letter-spacing: 0.12em;
  color: var(--muted); margin-bottom: 20px; }
.authcard .or::before, .authcard .or::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

.authcard .field { margin-bottom: 16px; }
.authcard .password-field { margin-bottom: 0; }
.authcard .field label { display: block; font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); }
.authcard .field > label { margin-bottom: 7px; }
.authcard .field input { display: block; width: 100%; border: 1px solid var(--rule); border-radius: 0;
  background: var(--bg); color: var(--ink); font-family: inherit; font-size: 13px; padding: 10px 12px; }
.authcard .field input:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }

.authcard .btn.primary { display: block; width: 100%; text-align: center; margin-top: 20px; border: 0;
  cursor: pointer; padding: 12px 0; }
/* Set by subscription_workflow.js while the form posts. The label stays; a spinner sits before it. */
.btn.is-loading { cursor: progress; }
.btn.is-loading::before { content: ""; display: inline-block; width: 12px; height: 12px; margin-right: 8px;
  vertical-align: -1px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: btnSpin .7s linear infinite; }
@keyframes btnSpin { to { transform: rotate(360deg); } }

/* slim footer — both auth pages, identical */
footer.slim { border-top: 1px solid var(--rule); padding: 16px 0; }
footer.slim .wrap { display: flex; justify-content: space-between; font-size: 10px; color: var(--muted); }
footer.slim a { color: var(--muted); text-decoration: none; }
footer.slim a:hover { color: var(--accent); }

/* ============================================================
   COMPONENT: OAUTH PROVIDER BUTTONS   (page-login, page-signup)
   ============================================================
   Both auth pages carry the same two buttons, so the whole treatment —
   the stack, the button box and the marks — lives here once. It used to
   be duplicated in each page's <style>.

   THE MARKS ARE INK, NOT ART. Monochrome, painted with `currentColor`
   through a CSS mask. One glyph then serves every state the button has:
   --ink on --bg in light, the inverse in dark, and inverted again on
   :hover, where .btn.ghost flips to a solid --ink fill. A hardcoded
   black SVG would have needed three variants and would have gone
   invisible the moment the button filled.

   The marks live beside this stylesheet as external SVGs. Keeping them
   in the static pipeline gives each one a fingerprinted production URL
   while the relative CSS reference is rewritten with it. Do not inline
   these as percent-encoded data URIs: the CSS minifier normalises the
   whitespace inside path data and corrupts the mask in production.

   THE LEGACY RASTER MARKS ARE UNUSABLE, and were not used. In
   cronitorio/static/img/icons/: social/github.png is a 28x66 two-state
   sprite of the old Octocat mascot sitting on an OPAQUE matte (grey
   over slate-blue); social2/github.png is a 40x80 mascot sprite; and
   there is no Google mark at all — social/ carries only googleplus.png,
   a brand dead since 2019, and social2/google.png is a 40x80 sprite of
   the pre-2015 lowercase serif "g". All raster, all sprites, all
   incapable of taking currentColor.

   - GitHub: the Invertocat. One closed path on a 16-unit circle.
   - Google: the four-colour G reduced to its outline as a single closed
     path — outer r=22, inner r=13 about (24,24), crossbar spanning
     y 20..28.5. Because it is one path and not four abutting ones,
     there are no seams for the mask's alpha to leak through. The
     viewBox is cropped to `2 2 44 44` so the ring fills its box exactly
     the way the Invertocat's circle fills its own 16 — same box in,
     same circle out, so the two marks read at one size.

   OPTICAL CENTRING — against the cap band, not the line box.
   `align-items: center` centres on the LINE BOX, which carries the
   font's descender space below the baseline. These labels ("Sign in
   with Google") have no descenders, so the ink they actually show is
   the cap band, and a mark centred on the line box sits visibly high.

   So: baseline-align first. An empty block flex item has no baseline of
   its own, so flexbox synthesises one from its border box bottom edge,
   which parks the mark's bottom exactly ON the text baseline. Then push
   it down by half the difference between the mark box and the cap
   height. The mark's centre then lands on the middle of the cap band,
   and — this is the point — the result does not depend on line-height,
   so nothing drifts if the button's leading is ever touched.

   JetBrains Mono reports sCapHeight 730/1000, hence --oauth-cap: 0.73em
   (9.49px at the 13px label). Verified against canvas TextMetrics on
   the live page: actualBoundingBoxAscent of "H" measures 9.49px.

   IDENTICAL GEOMETRY. Both buttons take the same mark box, the same
   gap and the same padding, and both labels are 19 characters of a
   monospaced face — so the centred [mark + gap + label] group resolves
   to the same width and the same left offset on both. Stacked directly
   on top of each other, any mismatch would be obvious; there is none to
   see because there is none to have.
   ============================================================ */
.authcard .oauth { display: grid; gap: 10px; margin-bottom: 20px; }

.btn.btn-oauth {
  --oauth-cap: 0.73em;   /* JetBrains Mono sCapHeight — 9.49px at 13px */
  --oauth-mark: 1em;     /* mark box = 1.37x cap: a sibling of the type, not a badge */
  --oauth-gap: 10px;
  display: flex; align-items: baseline; justify-content: center; gap: var(--oauth-gap);
  width: 100%; padding: 11px 0; text-align: center;
}
.btn-oauth::before {
  content: ""; flex: 0 0 auto;
  width: var(--oauth-mark); height: var(--oauth-mark);
  background-color: currentColor;
  -webkit-mask: var(--oauth-glyph) no-repeat center / contain;
          mask: var(--oauth-glyph) no-repeat center / contain;
  transform: translateY(calc((var(--oauth-mark) - var(--oauth-cap)) / 2));
}
.btn-oauth[data-provider="github"] {
  --oauth-glyph: url("oauth-github.e306cf05d77b.svg");
}
.btn-oauth[data-provider="google"] {
  --oauth-glyph: url("oauth-google.5396e4ab9b04.svg");
}

/* ============================================================
   COMPONENT: SIGNUP VALUE COLUMN   (page-signup)
   ============================================================
   The column beside the form used to be four static bullets, on a site
   where every other page argues with an instrument. It now argues in
   the site's own grammar — three ruled rows, each carrying the
   capability glyph that belongs to it — then answers the two questions
   that actually stop a signup (what does it cost, who else uses it).

   WHY THE HOUSE GLYPHS AND NOT A FIGURE. This page's job is a completed
   form, so the right column must not compete with the fields. A monitor
   board flipping rows red beside a password input is spectacle. The
   capability glyphs are the quietest instrument the system has: 48x28,
   one entrance under 550ms, and — per their own contract — their
   RESTING state is their FINAL state, so reduced motion, JS off, or an
   observer that never fires all render the complete column. No page
   hero here, so nothing loops.

   Each glyph is the one that genuinely describes its row: `schedule`
   is expected slots over actual runs, `performance` is durations
   against a budget, `alerts` is an event routed to a destination. They
   are not decoration picked for shape.

   NO LAYOUT SHIFT, which matters more here than anywhere else on the
   site — a column that grows while someone is typing their password
   moves the field under the cursor. Two reservations below: the kicker
   pre-reserves the chrome bar's height, and the logo marks take equal
   flex shares so the row is settled before any SVG has loaded.
   ============================================================ */
.valuecol > .seclabel { padding-bottom: 14px; border-bottom: 1px solid var(--rule-strong); }

.valuecol .vrow { padding: 15px 0; border-bottom: 1px dashed var(--rule); }
.valuecol .vrow em { font-style: normal; font-size: 10.5px; letter-spacing: 0.12em;
  font-weight: 500; color: var(--accent); }
/* PRE-HYDRATION HEIGHT RESERVATION — and note the child combinator.
   v5-shared.js lifts this <em> into a .gchrome bar (min-height 28px)
   with the 48x28 instrument flush right. Before that runs the kicker is
   a bare 14px line, so all three rows would jump 14px taller the moment
   the script mounted. Giving the un-lifted kicker the same 28px makes
   the swap a no-op. `>` is deliberate: once the em is inside .gchrome
   this rule stops matching and .gchrome's own min-height takes over, so
   the 28px is asserted exactly once at any moment. */
.valuecol .vrow > em { display: flex; align-items: center; min-height: 28px; }
/* The column is 540px but the measure is not: 13.5px Instrument Sans runs
   about 95 characters at full width, well past a comfortable line. 430px
   holds it near 68. The kicker and the glyph still span the full width,
   so the row keeps its rule and the glyphs keep their shared right edge. */
.valuecol .vrow p { font-family: "Instrument Sans", sans-serif; font-size: 13.5px; line-height: 1.6;
  color: var(--body); margin-top: 8px; max-width: 430px; }
/* the last row runs straight into the FREE PLAN cell; a dashed rule 20px
   above a solid one is two rules doing one rule's job */
.valuecol .vrow:last-child { border-bottom: 0; padding-bottom: 4px; }

/* the price answer, given as a ruled cell rather than a bullet */
.valuecol .vfree { display: flex; align-items: baseline; gap: 16px; margin-top: 20px;
  border: 1px solid var(--rule-strong); border-radius: 2px; padding: 13px 16px; }
.valuecol .vfree b { flex: none; font-size: 10px; letter-spacing: 0.12em; font-weight: 600; color: var(--ink); }
.valuecol .vfree span { font-family: "Instrument Sans", sans-serif; font-size: 13px; line-height: 1.5;
  color: var(--body); }

.valuecol .agent-note { margin-top: 14px; }
.valuecol .agent-note i { font-style: normal; color: var(--muted); margin-right: 7px; }

/* social proof at the moment of commitment — static, not the marquee.
   The marquee is ambient texture that belongs on a page you are reading;
   beside a form it is one more thing moving while you try to type. */
.valuecol .vproof { margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--rule); }
.valuecol .vproof > span { display: block; font-size: 10px; letter-spacing: 0.12em; color: var(--muted); }
.valuecol .vproof-row { display: flex; align-items: center; gap: 20px; height: 26px; margin-top: 14px; }
/* equal flex shares, not intrinsic widths: an <img> with no width is 0px
   until its SVG lands, so intrinsic sizing would reflow this row once per
   mark as the five arrive. Fixed slots settle at first layout. */
.valuecol .vproof-row img { flex: 1 1 0; min-width: 0; height: 18px; object-fit: contain;
  filter: brightness(0) saturate(100%) invert(0.44); }
[data-theme="dark"] .valuecol .vproof-row img { filter: brightness(0) saturate(100%) invert(0.6); }
/* the Disney wordmark is a tall script and sets small at a shared cap —
   the same 1.42x .logocell already gives it */
.valuecol .vproof-row img[alt="Disney"] { height: 25px; }

/* ============================================================================
   ============================================================================
   RESPONSIVE LAYER            (added Phase 1 — see RESPONSIVE-CONVENTIONS.md)
   ============================================================================
   ============================================================================

   Everything below this line is responsive behaviour for the SHARED
   structures. It is deliberately one appended block rather than edits
   scattered through the sheet above, for three reasons:

   1. ORDER IS THE MECHANISM. These rules have the same specificity as the
      authored rules above them, so being last is what lets a mobile-first
      base value win — and what lets the `@media (min-width: …)` blocks that
      follow it restore the authored desktop value. No `!important`, no
      specificity fights, exactly as the conventions doc requires.
   2. IT IS A REVIEWABLE DIFF. The authored drawing above is untouched, so
      any 1440px regression can only have come from this block.
   3. PAGES DO NOT HAVE TO KNOW. Eleven pages share these structures. Solving
      the footer / capgrid / xsell / stats / marquee / megamenu once here
      means a per-page agent only has to solve its own hero, its own feature
      rows and its own figures.

   BREAKPOINTS. Mobile-first, min-width, and only the seven in tw-input.css:
      (base) 375 · md 768 · lg 1024 · xl 1280 · 2xl 1440 · 3xl 1920 · 4xl 2560
   The one exception is a COMPONENT THRESHOLD — a max-width query derived
   from a component's own intrinsic size rather than from the page grid. The
   megamenu's `max-width: 1050px` above is the existing precedent; the figure
   track's 640px (600px figure + 2 x 20px base gutter) is the new one, and it
   lives in the product pages. Component thresholds are measured, never
   chosen, and they are always max-width so the authored drawing stays the
   base value.

   1440 IS THE CONTRACT. Every rule below either sits inside a media query
   that cannot match at 1440, or restates the authored value at `lg`/`xl`.
   Verified with a whole-document geometry digest (every element's rect,
   hashed) — before and after are byte-identical at 1440 in both themes.

   RESTATE THE AUTHORED TRACK LIST CHARACTER FOR CHARACTER. `1fr` is
   `minmax(auto, 1fr)` and `minmax(0, 1fr)` is not the same track: the first
   floors each column at its min-content size, the second does not, and the
   two distribute sub-pixel remainders differently. Writing the cross-sell
   strip back as `repeat(5, minmax(0, 1fr))` — which is what you reach for
   out of habit, and which looks identical — made cells 3 and 4 exactly 1px
   wider at 1440. The digest caught it; an eye would not have. Below the
   restore breakpoint `minmax(0, 1fr)` is the right default, because there a
   long unbreakable string SHOULD be allowed to overflow its cell rather
   than widen the grid past the viewport. Above it, copy the original.
   ============================================================================ */

/* ---------- CONTAINER ------------------------------------------------------
   40px gutters at 375 would spend 21% of the viewport on air. 20px is the
   base; the authored 40 returns at md, which is also the width at which the
   600px figures stop needing every pixel. .wrap's 1160 max-width is
   unchanged, so >= 1240 viewport is untouched either way. */
.wrap { padding: 0 20px; }
@media (min-width: 768px) { .wrap { padding: 0 40px; } }

/* ---- EXTRA-WIDE ------------------------------------------------------------
   `roomy` WON and is set on <html> in base_v5.html. Above 1920 the column
   opens to 1520; below it nothing changes, which is why the whole port's
   1440 reference is untouched by construction rather than by care.

   `fluid` LOST and is kept only so responsive-decisions.html can still show
   the comparison. It is deliberately NOT gated by a media query, so unlike
   roomy it WOULD move the 1440 reference — do not switch to it without
   re-verifying every page. Delete it once the decision page is retired. */
@media (min-width: 1920px) { [data-wide="roomy"] .wrap { max-width: 1520px; } }
[data-wide="fluid"] .wrap { max-width: min(2200px, 92vw); }

/* ---------- NAV: THE SHEET -------------------------------------------------
   WHY 1024 AND NOT 768. Measured, like the megamenu's own 1050. The bar at
   its authored 13px/28px-gap sets to: logo 122 + Product 68 + Customers 78 +
   Pricing 54 + Developers 86 + toggle 29 + Sign In 50 + button 130 = 617 of
   ink, plus seven 28px gaps = 196, plus 80 of gutter — 893px before anything
   touches. So the bar itself survives to ~900 and the burger could wait
   until 900. It does not, because `lg` is where the megamenu panel is
   already one column (1050) and where the 600px figure track has already
   stacked: a nav that keeps five desktop links over a stacked page is the
   only thing on screen still pretending to be a desktop. One boundary, not
   three.

   HOW IT WORKS — no second markup, no second component. Below lg the nav's
   own .wrap simply wraps: logo / spacer / theme toggle / burger stay on the
   66px row, and every .nl and .btn after them takes a full flex line and is
   hidden until `nav.site.is-open`. The megamenu panels move INSIDE that
   .wrap (v5-shared.js), directly after their own trigger, so on the sheet
   they read as accordions under the row that opens them — and every bit of
   the existing megamenu behaviour (hover intent, click, Escape, arrow keys,
   focus return, outside-click, one-at-a-time) carries over untouched,
   because open/close is still just `.is-open` on the same panel.

   The move is invisible at desktop: nav.site is `position: sticky` and
   therefore the panels' containing block either way — .wrap is not
   positioned — and an absolutely positioned child of a flex container is
   not a flex item, so it does not join the row. */
.nm-burger { display: inline-flex; flex-direction: column; justify-content: center;
  gap: 4px; width: 44px; height: 44px; padding: 0 13px; flex: none;
  background: none; border: 0; cursor: pointer; color: var(--muted); }
.nm-burger:hover, .nm-burger[aria-expanded="true"] { color: var(--accent); }
.nm-burger:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
/* three 1px rules, not an icon — same hairline grammar as every divider on
   the page. 150ms is the "micro" tier in the design system's motion table. */
.nm-burger i { display: block; height: 1px; background: currentColor;
  transition: transform 150ms var(--ease-shift), opacity 150ms var(--ease-shift); }
.nm-burger[aria-expanded="true"] i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.nm-burger[aria-expanded="true"] i:nth-child(2) { opacity: 0; }
.nm-burger[aria-expanded="true"] i:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
@media (prefers-reduced-motion: reduce) { .nm-burger i { transition: none; } }
@media (min-width: 1024px) { .nm-burger { display: none; } }

@media (max-width: 1023.98px) {
  nav.site > .wrap { flex-wrap: wrap; gap: 0 14px; height: auto; min-height: 66px; }
  nav.site > .wrap > .logo { order: 0; }
  nav.site > .wrap > .spacer { order: 1; }
  nav.site > .wrap > .theme-toggle { order: 2; min-width: 44px; min-height: 44px; }
  nav.site > .wrap > .nm-burger { order: 3; margin-right: -13px; }
  /* every remaining bar item becomes a full-width sheet row, in source order */
  nav.site > .wrap > .nl,
  nav.site > .wrap > .btn,
  nav.site > .wrap > .nm-panel { order: 4; flex: 0 0 100%; display: none; }
  nav.site.is-open > .wrap > .nl,
  nav.site.is-open > .wrap > .btn { display: flex; }
  nav.site.is-open > .wrap > .nm-panel.is-open { display: block; }

  nav.site > .wrap > .nl {
    align-items: center; min-height: 44px; width: 100%;
    border-top: 1px solid var(--rule); font-size: 15px; color: var(--ink);
    text-align: left; justify-content: space-between; padding: 0; }
  nav.site > .wrap > .btn { justify-content: center; align-items: center;
    min-height: 44px; margin: 14px 0 18px; }
  nav.site.is-open > .wrap { max-height: 100vh; overflow-y: auto; overscroll-behavior: contain; }

  /* the panel is in flow now: no drop shadow, no absolute placement, and the
     `visibility: hidden` that keeps a closed desktop panel measurable would
     leave a full-height hole in the sheet, so a closed sheet panel is
     display:none instead. Consequence, and it is the right one: the
     capability glyphs inside draw on first open rather than at load,
     because their IntersectionObserver cannot fire on a display:none box. */
  /* `left` is cleared by place() in v5-shared.js rather than fought here —
     it is written as an inline style, and no stylesheet beats an inline
     style without !important, which this system does not use. */
  nav.site > .wrap > .nm-panel { position: static; transform: none; margin-top: 0;
    border: 0; box-shadow: none; width: auto;
    border-top: 1px solid var(--rule); background: var(--panel); }
  nav.site > .wrap > .nm-panel > .wrap { padding: 0; max-width: none; }
  .nm-cell { padding: 12px 0 14px; }
  .nm-list a { padding: 12px 0; min-height: 44px; }
  .nm-list a:first-child { border-top: 0; }
}

/* ---- MOBILE NAV: THE OTHER TWO OPTIONS ------------------------------------
   Switched with `data-nav` on <html>. No attribute = SHEET, the default
   above. These are live so responsive-decisions.html can show the real nav
   in each pattern rather than a picture of one; whichever the user picks,
   the other two blocks come out and the winner loses its attribute guard.

   B — FLAT.  Same sheet, no accordion: the Product menu is already open, so
   the whole inventory is one scroll and nothing is one tap deeper than
   anything else. Costs a longer sheet; buys a reader who never has to guess
   which row hides the thing they want.

   C — RAIL.  No burger and no hidden state at all: the links simply wrap
   onto a second row under the logo and stay there. Cheapest possible
   interaction — there is nothing to open — at the cost of ~90px of every
   scroll position, since the nav is sticky. The megamenus stay absolute
   drop-downs, exactly as they are on the desktop bar. */
@media (max-width: 1023.98px) {
  /* B — FLAT.  `display` alone is not enough: a closed panel is also
     `visibility: hidden` and `opacity: 0`, which is what keeps its links out
     of the tab order at desktop. All three have to come off together or the
     panel reserves its full height and shows nothing in it. */
  [data-nav="flat"] nav.site.is-open > .wrap > .nm-panel {
    display: block; visibility: visible; opacity: 1; pointer-events: auto; }
  [data-nav="flat"] nav.site .nm-caret { display: none; }
  [data-nav="flat"] nav.site > .wrap > .nm-trigger { pointer-events: none; }
  [data-nav="flat"] .nm-cell { padding: 10px 0 12px; }

  /* C — RAIL */
  /* the burger is the line break. It already sits between the theme toggle
     (order 2) and the links (order 4), so rather than adding a spacer
     element the rail keeps it in flow at zero height and full width: the
     logo row ends there and the links start cleanly on the next one.
     `visibility: hidden` keeps it out of the tab order and off the screen. */
  [data-nav="rail"] .nm-burger { display: block; visibility: hidden;
    width: 100%; height: 0; min-height: 0; padding: 0; margin: 0; flex: 0 0 100%; }
  [data-nav="rail"] nav.site > .wrap { row-gap: 0; padding-bottom: 8px; }
  [data-nav="rail"] nav.site > .wrap > .nl { display: inline-flex; flex: 0 0 auto;
    width: auto; min-height: 38px; border-top: 0; font-size: 13.5px; color: var(--muted); }
  [data-nav="rail"] nav.site > .wrap > .nl:first-of-type { margin-left: 0; }
  [data-nav="rail"] nav.site > .wrap > .btn { display: inline-flex; flex: 0 0 auto;
    width: auto; margin: 0 0 0 auto; min-height: 38px; padding: 9px 14px; }
  /* the rail keeps the desktop drop-down: absolute, full nav width, one column */
  [data-nav="rail"] nav.site > .wrap > .nm-panel { position: absolute; display: block;
    left: 0; right: 0; top: 100%; border-top: 1px solid var(--rule-strong);
    border-bottom: 1px solid var(--rule-strong); background: var(--bg); }
  [data-nav="rail"] nav.site > .wrap > .nm-panel:not(.is-open) { display: none; }
}

/* Tap targets follow input capability, not viewport width. A 1024px tablet in
   landscape is still a coarse pointer, while a narrow desktop window is not.
   The layout breakpoints above remain width-driven; only the interaction
   floor belongs here. Inline links in running prose remain exempt. */
@media (pointer: coarse) {
  .btn { min-height: 44px; padding: 13px 20px; }
  .nl { display: inline-flex; align-items: center; min-height: 44px; }
  .theme-toggle { min-width: 44px; min-height: 44px; padding: 12px 14px; }
  .agent-note a { display: inline-flex; align-items: center; min-height: 44px; }
  .capcta a { display: inline-flex; align-items: center; min-height: 44px; }

  /* THE FOOTERS WERE NEVER COVERED BY THIS RULE, and both are all-link
     surfaces. Measured before: `footer.slim a` 30x13 and 42x13;
     `footer.site .wrap a` 23px tall at every width.

     `footer.site a` is already `display: block` in its own column, so it is
     wide enough and only needs height: 12px/1.35 is a 16.2px line box, and
     14px of padding a side makes 44.2. The links stack, so this does grow the
     footer below lg — which is the correct trade and the reason it is gated.

     `footer.slim`'s two links stay INLINE, separated by a middot. Vertical
     padding grows the hit box without touching the line box or the footer's
     height, so it is free. Horizontal padding is deliberately NOT added: it
     would move the `·`, and a run of inline links in running text is exactly
     what WCAG 2.5.8 exempts. They end 30x44 and 42x44. Same reasoning applies
     to prose links inside body copy — do not pad those. */
  footer.site .wrap a { padding-top: 14px; padding-bottom: 14px; }
  footer.slim a { padding-top: 15.5px; padding-bottom: 15.5px; }
}

/* ---------- PRODUCT HERO ---------------------------------------------------
   The figure track never yields (see RESPONSIVE-CONVENTIONS.md (b)), so the
   two-column hero survives exactly as long as 600px of figure + 52 of gap +
   a readable copy measure fits inside .wrap: 600 + 52 + 400 = 1052 of
   content, i.e. a 1132px viewport. The shared 1152px fit breakpoint leaves a
   little safety for borders and the wider 620px stages; below it the hero
   stacks. Pages override the paired columns; nobody
   needs `!important` for that any more, because the page's own <style> is
   already later in the cascade than this sheet. */
.phero { padding: 44px 0 52px; }
.phero .wrap { grid-template-columns: minmax(0, 1fr); gap: 36px; }
/* Phone headings sit one step below the authored mobile size. 29px keeps the
   longest headline word (`heartbeat`, 9ch) at 157px inside a 335px box, so the
   measure is unchanged in kind — this is weight, not fit. Section heads follow
   the same step so the hero-to-section ratio survives. Both restore at `md`,
   which is why 1440 cannot move. */
.phero h1 { font-size: 29px; margin-bottom: 16px; }
.fcopy h2 { font-size: 22px; margin-bottom: 12px; }
.phero .checks { margin-bottom: 24px; }
.phero .cta-row { flex-wrap: wrap; }
@media (min-width: 768px) {
  .phero { padding: 60px 0 68px; }
  .phero h1 { font-size: 38px; margin-bottom: 22px; }
  .fcopy h2 { font-size: 25px; margin-bottom: 14px; }
  .phero .checks { margin-bottom: 28px; }
}
@media (min-width: 1280px) {
  .phero { padding: 72px 0 80px; }
  .phero .wrap { grid-template-columns: 46% 54%; gap: 52px; }
  .phero h1 { font-size: 46px; margin-bottom: 24px; }
  .phero .checks { margin-bottom: 30px; }
}

/* ---------- RULED GRIDS ----------------------------------------------------
   THE RULE FOR RULED CELLS: the column count lives in CSS, next to the
   hairline suppression it implies, and NEVER in a Tailwind utility. A ruled
   grid is not a box — it is an nth-child contract between siblings, and
   splitting `repeat(3, 1fr)` (utility) from `:nth-child(3n)` (stylesheet)
   is the --authcard-w bug waiting to happen: two copies of one number, one
   of which gets updated. Tailwind owns the padding, the gap and the type
   inside these cells. It does not own how many of them are in a row. */

/* capability grid — 3 -> 2 -> 1 */
.capgrid { grid-template-columns: minmax(0, 1fr); }
.cap { border-right: 0; }
@media (min-width: 768px) {
  .capgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cap { border-right: 1px solid var(--rule); }
  /* d4.2/d4.4: the authored 3-column suppressor (`.cap:nth-child(3n)`, 0-2-0)
     outranks the bare `.cap` restore (0-1-0), so at two columns it silently ate
     the right rule on cells 3 and 9. Restate it at the authored selector, and
     before the 2n suppression, so order decides between equals. */
  .cap:nth-child(3n) { border-right: 1px solid var(--rule); }
  .cap:nth-child(2n) { border-right: 0; }
}
@media (min-width: 1024px) {
  .capgrid { grid-template-columns: repeat(3, 1fr); }
  .cap:nth-child(2n) { border-right: 1px solid var(--rule); }
  .cap:nth-child(3n) { border-right: 0; }
}

/* stats strip — 6 -> 3 -> 2. The authored strip is one row and therefore has
   no horizontal rules at all; wrapped into 2 or 3 columns it needs them, and
   they have to come off the LAST row, which is what the :nth-last-child
   pairs do.

   A SUPPRESSOR DOES NOT EXPIRE AT THE NEXT BREAKPOINT. `.stats .cell:nth-
   child(3n) { border-right: 0 }` written at md is (0,3,1); `.stats .cell
   { border-right: 1px }` written at lg is (0,2,1). Media queries add no
   specificity, so at 1440 the md rule is still winning and every third cell
   is still missing its rule. This bit the cross-sell strip below for real —
   two of its five cells lost their hairline at 1440 and the geometry digest
   caught it only because the missing border made the cell 1px wider. A
   border that changes COLOUR and not width would have been invisible to the
   digest entirely; that is why the screenshots are a separate gate.

   So: every breakpoint restates EVERY suppressor it inherits, at the same
   selector, whether or not the value changes. Verbose on purpose. */
.stats .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.stats .cell { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 20px 16px; }
.stats .cell:nth-child(2n) { border-right: 0; }
.stats .cell:nth-child(3n) { border-right: 1px solid var(--rule); }
/* TWO COLUMNS, SO THE LAST ROW IS THE LAST **TWO** CELLS — and the general
   restore has to be stated BEFORE the specific suppression, because the two
   selectors are the same specificity and a cell matching both takes whichever
   came last. Written the other way round (which is how this block shipped),
   `-n+3` restated md's three-column value here and cell 4 — the right-hand
   cell of the middle row — lost the rule under it, at 375 on HB, RUM, CUS and
   LIB. See d4 #4. */
.stats .cell:nth-last-child(-n+3) { border-bottom: 1px solid var(--rule); }
.stats .cell:nth-last-child(-n+2) { border-bottom: 0; }
.stats .cell:last-child { border-right: 0; }
.stats b { font-size: 18px; }
@media (min-width: 768px) {
  .stats .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .stats .cell { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
  .stats .cell:nth-child(2n) { border-right: 1px solid var(--rule); }
  .stats .cell:nth-child(3n) { border-right: 0; }
  .stats .cell:nth-last-child(-n+2) { border-bottom: 1px solid var(--rule); }
  .stats .cell:nth-last-child(-n+3) { border-bottom: 0; }
  .stats .cell:last-child { border-right: 0; }
}
@media (min-width: 1024px) {
  .stats .grid { grid-template-columns: repeat(6, 1fr); }
  .stats .cell { border-right: 1px solid var(--rule); border-bottom: 0; padding: 26px 20px; }
  .stats .cell:nth-child(2n) { border-right: 1px solid var(--rule); }
  .stats .cell:nth-child(3n) { border-right: 1px solid var(--rule); }
  .stats .cell:nth-last-child(-n+2) { border-bottom: 0; }
  .stats .cell:nth-last-child(-n+3) { border-bottom: 0; }
  .stats .cell:last-child { border-right: 0; }
  .stats b { font-size: 21px; }
}

/* cross-sell strip — 5 -> 2 (+ the odd fifth spanning the row) -> 1 */
.xsell { grid-template-columns: minmax(0, 1fr); }
.xsell a { border-right: 0; border-bottom: 1px solid var(--rule); }
.xsell a:nth-child(2n) { border-right: 0; }
.xsell a:last-child { border-right: 0; border-bottom: 0; }
@media (min-width: 768px) {
  .xsell { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .xsell a { border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
  .xsell a:nth-child(2n) { border-right: 0; }
  .xsell a:last-child { grid-column: 1 / -1; border-right: 0; border-bottom: 0; }
}
@media (min-width: 1024px) {
  .xsell { grid-template-columns: repeat(5, 1fr); }
  .xsell a { border-right: 1px solid var(--rule); border-bottom: 0; }
  .xsell a:nth-child(2n) { border-right: 1px solid var(--rule); }
  .xsell a:last-child { grid-column: auto; border-right: 0; border-bottom: 0; }
}

/* proof block */
.fieldsec { padding: 48px 0; }
.fieldblock .quoterotator { padding: 24px 20px; }
.fieldblock .fb-cases { grid-template-columns: minmax(0, 1fr); }
.fieldblock .fb-cases .casecard { border-right: 0; border-bottom: 1px solid var(--rule); padding: 22px 20px; }
.fieldblock .fb-cases .casecard:last-child { border-bottom: 0; }
.quoterotator { grid-template-columns: minmax(0, 1fr); gap: 22px; padding: 24px 20px; min-height: 0; }
@media (min-width: 768px) {
  .fieldsec { padding: 60px 0; }
  .fieldblock .quoterotator { padding: 30px 28px; }
  .fieldblock .fb-cases { grid-template-columns: 1fr 1fr; }
  .fieldblock .fb-cases .casecard { border-right: 1px solid var(--rule); border-bottom: 0; padding: 28px; }
  .fieldblock .fb-cases .casecard:last-child { border-right: 0; }
  .quoterotator { padding: 30px 34px; }
}
@media (min-width: 1024px) {
  .fieldsec { padding: 72px 0; }
  .quoterotator { grid-template-columns: 1fr 250px; gap: 40px; min-height: 132px; }
}

/* footer — five desktop columns -> one legal row over a balanced 2x2 link
   grid. The sticky mobile header already carries the wordmark, so repeating it
   here only creates a fake first column and staggers Product against the legal
   copy. Keep the footer logo for desktop, but let every navigation group begin
   below the same compact copyright / Terms / Privacy row on smaller screens. */
footer.site { padding: 36px 0 32px; }
footer.site .wrap { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 32px 24px; }
footer.site .fbrand { grid-column: 1 / -1; padding-bottom: 16px; border-bottom: 1px solid var(--rule); }
footer.site .fbrand .logo { display: none; }
footer.site .fbrand .fine { display: flex; flex-wrap: wrap; align-items: center;
  margin-top: 0; text-align: left; line-height: 1.3; }
footer.site .fbrand .copyright::after { content: " \00b7\00a0"; white-space: pre; }
footer.site .fbrand .fine-links { display: inline; white-space: nowrap; }
@media (min-width: 1024px) {
  footer.site { padding: 48px 0 40px; }
  footer.site .wrap { grid-template-columns: 1.2fr 1fr 1fr 1fr 1.2fr; gap: 32px; }
  footer.site .fbrand { grid-column: auto; padding-bottom: 0; border-bottom: 0; }
  footer.site .fbrand .logo { display: block; margin-bottom: 12px; }
  footer.site .fbrand .fine { display: block; margin-top: 16px; line-height: 1.7; }
  footer.site .fbrand .copyright::after { content: none; }
  footer.site .fbrand .fine-links { display: block; }
}

/* ---------- COMPONENTS THAT ONLY NEED A CEILING ---------------------------
   The toast is 248px and every content column it lands in is wider than that
   from 375 up, so it needs a ceiling and nothing else. Stated as max-width so
   the 248 stays the authored number in one place. */
.toast { max-width: 100%; }

/* ---------- THE FIGURE FRAME — CLIPPING IS WORSE THAN OVERFLOW -------------
   `.board td { white-space: nowrap }` and `.figure { overflow: hidden }`
   between them mean a board narrower than its own min-content is not narrow,
   it is CUT OFF: the status column stops existing, with no scrollbar, no wider
   document and no clue. It is more dangerous than overflow precisely because
   every document-level gate passes — this is the failure the clip gate (e1)
   exists to catch, and the reason (a)'s component-library row was wrong to
   call it "overflow".

   MEASURED THRESHOLD (d2), not a chosen one: the widest `.board` in the tree
   is 430px, and a `.figure` clientWidth is the viewport less 40px of base
   gutter, its 2px of border and its host's padding — 430 of that needs a
   ~502px viewport. Above it nothing clips, so this is inert; below it the
   drawing scrolls inside its own frame rather than losing a column. 767.98 is
   the smallest standard threshold that provably covers every measured board
   AND sits under the 768 gutter change, so one query covers the whole range.

   `overflow-y` stays `hidden` deliberately: `.toast.is-float` demos are
   authored to escape their frame and be clipped, and only the horizontal axis
   is the bug. Redrawing the board is not an option — its columns are the
   product's own truth, and dropping one would document a board that does not
   ship. */
@media (max-width: 767.98px) {
  .figure { overflow-x: auto; overflow-y: hidden; }
}

/* The logo marquee is already fluid — a `width: max-content` track inside an
   `overflow: hidden` viewport — so it needs no columns. While the hero is
   stacked it uses a slightly tighter tablet rhythm; phones take one more step
   down so the strip does not eat a third of the screen. */
@media (max-width: 1151.98px) {
  .logos .grid.lm .lm-viewport { height: 80px; }
  .logos .grid.lm .lm-item { padding: 0 var(--lm-gap-tablet, 24px); }
  .logos .grid.lm.is-static .lm-viewport { height: auto; }
  .logos .grid.lm.is-static .lm-item { padding: 0 var(--lm-gap-tablet, 24px); }
  .logos .grid.lm.is-static .lm-set {
    padding: 20px var(--lm-gap-tablet, 24px);
    row-gap: 15px;
  }
}
@media (max-width: 767.98px) {
  .logos .grid.lm .lm-viewport { height: 72px; }
  .logos .grid.lm .lm-item { padding: 0 var(--lm-gap-narrow, 20px); }
  /* d4.2 in the other direction: `.lm.is-static .lm-item` is (0,5,0) and this
     narrow-stride rule is (0,4,0), so the reduced-motion state would keep the
     30px desktop stride on a 335px phone unless it is restated here at equal
     specificity. Same for the viewport height, which must stay `auto` — a
     72px ceiling is exactly what made the old subset clip. */
  .logos .grid.lm.is-static .lm-viewport { height: auto; }
  .logos .grid.lm.is-static .lm-item { padding: 0 var(--lm-gap-narrow, 20px); }
  .logos .grid.lm.is-static .lm-set { padding: 18px var(--lm-gap-narrow, 20px); row-gap: 14px; }
}

/* Prose measures are set in ch-free px above; below md the container is the
   measure, so the max-widths only need to stop being wider than it. */
@media (max-width: 767.98px) {
  .qcard, .ccard { padding: 20px; }
  .casecard { padding: 22px 20px; }

  /* THE CRON ORNAMENT IS ONE WORD, NOT FIVE STARS. `.seclabel` is a two-span
     `space-between` flex row, and both spans default to `flex: 0 1 auto` —
     shrinkable. Once the label is long enough (`BUSINESS PLAN / HOW THE BILL
     IS CALCULATED`) it takes the row and the ornament gets squeezed to its
     min-content, which for `* * * * *` is a single star: it renders as four
     stars stacked over one. `flex: none` stops the shrink and `nowrap` stops
     the break; `align-items: flex-start` then keeps the ornament on the
     label's first line instead of centring it against a wrapped block. */
  .seclabel { gap: 12px; align-items: flex-start; }
  .seclabel span + span { flex: none; white-space: nowrap; }
}

/* ============================================================================
   DJANGO PORT — THE ONLY ADDITION TO THIS FILE relative to
   .design/proposals/v5-shared.css. Appended, not scattered, so re-syncing the
   proposal copy is one diff at the end of the file. If you overwrite this
   sheet from .design/proposals, RE-APPEND THIS BLOCK.

   The proposals draw the wordmark as an inert <div class="logo">. On the real
   site it is a link home (partials/header.html), which makes it a tap target,
   and .logo is 122x24 — below the 44px coarse-pointer floor applied above.
   This extends that same floor to the one control the proposals did not have.

   Scoped to nav.site and to coarse pointers, so:
     - mouse-driven desktop geometry is unchanged at every width;
     - the footer wordmark, which is still an inert <div>, is untouched and
       its column geometry does not move.
   The 24px background box is unchanged — `background: ... left center` keeps
   the mark on the same baseline inside the taller box, and nav.site > .wrap
   is align-items:center, so the drawing does not move.
   ============================================================================ */
@media (pointer: coarse) {
  nav.site > .wrap > a.logo { display: flex; align-items: center; min-height: 44px; }
}

/* The proposals render the footer's fine print as PLAIN TEXT
   ("Terms & Conditions · Privacy Policy"), because every href in a static
   mock is "#". On the real site these are the legal pages and the legacy
   footer links them, so partials/footer.html links them too.

   `footer.site a` is `display: block` (it is authored for the stacked link
   columns) and gains `padding: 14px 0` at touch widths, so a linked fine
   print would stack onto two lines and inflate the footer on mobile. These
   restore the proposal's exact single-line rendering.

   Specificity, deliberately (0,3,1): it beats BOTH `footer.site a` (0,2,1)
   and the touch-width `footer.site .wrap a` (0,2,1) regardless of source
   order or media query, so this cannot be undone by a later block the way
   a tying selector could (d4.2).

   A coarse-pointer rule below raises these two controls to the 44px floor
   without returning the column-link padding that made them stack. */
/* `font-size: inherit` is not optional: `footer.site a` sets 12px and
   `.fine` is 10px, so without it the links render 20% larger than the
   line they sit on and "Terms & Conditions · Privacy Policy" wraps to a
   third line. Measured: 7.2px/char against the sheet's 6px. */
footer.site .wrap .fine a { display: inline; padding: 0; font-size: inherit;
  line-height: inherit; color: inherit; text-decoration: none; }
footer.site .wrap .fine a:hover { color: var(--accent); }
@media (pointer: coarse) {
  footer.site .wrap .fine a { display: inline-flex; align-items: center; min-height: 44px; }
}

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:"Instrument Sans", sans-serif;--font-mono:"JetBrains Mono", monospace;--spacing:4px;--container-xs:20rem;--container-sm:24rem;--container-lg:32rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--leading-tight:1.25;--leading-snug:1.375;--ease-in:cubic-bezier(.4, 0, 1, 1);--ease-out:cubic-bezier(0, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--breakpoint-xl:1280px;--breakpoint-2xl:1440px;--text-prose-lg:15.5px;--text-prose-lg--line-height:1.75;--text-prose-sm:13.5px;--text-prose-sm--line-height:1.6;--text-cap:12px;--text-cap--line-height:1.5;--tracking-display:-.025em;--radius-fig:3px;--color-paper:var(--bg);--color-panel:var(--panel);--color-rule:var(--rule);--color-rule-strong:var(--rule-strong);--color-ink:var(--ink);--color-body:var(--body);--color-muted:var(--muted);--color-accent:var(--accent)}}@layer base{*{margin:0}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.-top-0\.5{top:calc(var(--spacing) * -.5)}.-top-12{top:calc(var(--spacing) * -12)}.top-0{top:0}.top-\[6px\]{top:6px}.top-\[33px\]{top:33px}.top-\[46px\]{top:46px}.top-\[79px\]{top:79px}.top-\[118px\]{top:118px}.top-\[129px\]{top:129px}.top-\[190px\]{top:190px}.top-\[195px\]{top:195px}.top-\[267px\]{top:267px}.right-0{right:0}.right-1{right:var(--spacing)}.right-\[-12px\]{right:-12px}.right-\[-28px\]{right:-28px}.bottom-0{bottom:0}.bottom-0\.5{bottom:calc(var(--spacing) * .5)}.bottom-128{bottom:calc(var(--spacing) * 128)}.bottom-\[6px\]{bottom:6px}.bottom-\[20\%\]{bottom:20%}.bottom-\[27px\]{bottom:27px}.bottom-\[60\%\]{bottom:60%}.bottom-\[94\%\]{bottom:94%}.-left-1{left:calc(var(--spacing) * -1)}.left-0{left:0}.left-1\/2{left:50%}.left-1\/4{left:25%}.left-3\/4{left:75%}.left-\[6px\]{left:6px}.left-full{left:100%}.isolate{isolation:isolate}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.col-span-12{grid-column:span 12/span 12}.col-span-full{grid-column:1/-1}.container{width:100%}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1440px){.container{max-width:1440px}}@media (min-width:1920px){.container{max-width:1920px}}@media (min-width:2560px){.container{max-width:2560px}}.-m-3{margin:calc(var(--spacing) * -3)}.-m-5{margin:calc(var(--spacing) * -5)}.m-0\.5{margin:calc(var(--spacing) * .5)}.-mx-2{margin-inline:calc(var(--spacing) * -2)}.-mx-3{margin-inline:calc(var(--spacing) * -3)}.-mx-8{margin-inline:calc(var(--spacing) * -8)}.mx-auto{margin-inline:auto}.-my-1\.5{margin-block:calc(var(--spacing) * -1.5)}.-my-4{margin-block:calc(var(--spacing) * -4)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-10{margin-block:calc(var(--spacing) * 10)}.my-12{margin-block:calc(var(--spacing) * 12)}.my-auto{margin-block:auto}.-mt-5{margin-top:calc(var(--spacing) * -5)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-9{margin-top:calc(var(--spacing) * 9)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-13{margin-top:calc(var(--spacing) * 13)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mt-\[18px\]{margin-top:18px}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-2\.5{margin-right:calc(var(--spacing) * 2.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-10{margin-right:calc(var(--spacing) * 10)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-3\.5{margin-bottom:calc(var(--spacing) * 3.5)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.mb-12{margin-bottom:calc(var(--spacing) * 12)}.mb-64{margin-bottom:calc(var(--spacing) * 64)}.mb-\[30px\]{margin-bottom:30px}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-6{margin-left:calc(var(--spacing) * 6)}.ml-12{margin-left:calc(var(--spacing) * 12)}.ml-14{margin-left:calc(var(--spacing) * 14)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-20{height:calc(var(--spacing) * 20)}.h-28{height:calc(var(--spacing) * 28)}.h-32{height:calc(var(--spacing) * 32)}.h-\[58px\]{height:58px}.h-\[70px\]{height:70px}.h-\[106px\]{height:106px}.h-full{height:100%}.w-1\/3{width:33.3333%}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-28{width:calc(var(--spacing) * 28)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-\[72\%\]{width:72%}.w-\[94\%\]{width:94%}.w-full{width:100%}.w-px{width:1px}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[660px\]{max-width:660px}.max-w-\[780px\]{max-width:780px}.max-w-\[820px\]{max-width:820px}.max-w-\[830px\]{max-width:830px}.max-w-\[860px\]{max-width:860px}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.max-w-screen-2xl{max-width:var(--breakpoint-2xl)}.max-w-screen-xl{max-width:var(--breakpoint-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-80{min-width:calc(var(--spacing) * 80)}.min-w-full{min-width:100%}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.grow{flex-grow:1}.table-fixed{table-layout:fixed}.origin-top{transform-origin:top}.origin-top-left{transform-origin:0 0}.origin-top-right{transform-origin:100% 0}.translate-x-full{--tw-translate-x:100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/4{--tw-translate-y:calc(calc(1 / 4 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-90{rotate:90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.transform-gpu{transform:translateZ(0) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-10{gap:calc(var(--spacing) * 10)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-\[17px\]>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(17px * var(--tw-space-y-reverse));margin-block-end:calc(17px * calc(1 - var(--tw-space-y-reverse)))}.gap-x-10{column-gap:calc(var(--spacing) * 10)}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-3>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 3) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-6>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 6) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-8>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 8) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-x-reverse)))}.gap-y-7{row-gap:calc(var(--spacing) * 7)}.gap-y-12{row-gap:calc(var(--spacing) * 12)}:where(.divide-y-2>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(2px * var(--tw-divide-y-reverse));border-bottom-width:calc(2px * calc(1 - var(--tw-divide-y-reverse)))}.self-stretch{align-self:stretch}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-x-scroll{overflow-x:scroll}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.rounded-fig{border-radius:var(--radius-fig)}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.border-t-2{border-top-style:var(--tw-border-style);border-top-width:2px}.border-t-4{border-top-style:var(--tw-border-style);border-top-width:4px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-r-0{border-right-style:var(--tw-border-style);border-right-width:0}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-0{border-left-style:var(--tw-border-style);border-left-width:0}.border-rule{border-color:var(--color-rule)}.border-rule-strong{border-color:var(--color-rule-strong)}.bg-panel{background-color:var(--color-panel)}.bg-paper{background-color:var(--color-paper)}.bg-transparent{background-color:#0000}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-tr{--tw-gradient-position:to top right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.fill-rule{fill:var(--color-rule)}.p-0{padding:0}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.px-9{padding-inline:calc(var(--spacing) * 9)}.px-12{padding-inline:calc(var(--spacing) * 12)}.px-16{padding-inline:calc(var(--spacing) * 16)}.px-\[14px\]{padding-inline:14px}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-11{padding-block:calc(var(--spacing) * 11)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-13{padding-block:calc(var(--spacing) * 13)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-28{padding-block:calc(var(--spacing) * 28)}.py-\[13px\]{padding-block:13px}.pt-0{padding-top:0}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-11{padding-top:calc(var(--spacing) * 11)}.pt-12{padding-top:calc(var(--spacing) * 12)}.pt-13{padding-top:calc(var(--spacing) * 13)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-16{padding-top:calc(var(--spacing) * 16)}.pt-19{padding-top:calc(var(--spacing) * 19)}.pt-20{padding-top:calc(var(--spacing) * 20)}.pt-24{padding-top:calc(var(--spacing) * 24)}.pt-28{padding-top:calc(var(--spacing) * 28)}.pt-32{padding-top:calc(var(--spacing) * 32)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pb-0{padding-bottom:0}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-4\.5{padding-bottom:calc(var(--spacing) * 4.5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pb-10{padding-bottom:calc(var(--spacing) * 10)}.pb-12{padding-bottom:calc(var(--spacing) * 12)}.pb-13{padding-bottom:calc(var(--spacing) * 13)}.pb-14{padding-bottom:calc(var(--spacing) * 14)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pb-20{padding-bottom:calc(var(--spacing) * 20)}.pb-24{padding-bottom:calc(var(--spacing) * 24)}.pb-\[18px\]{padding-bottom:18px}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-cap{font-size:var(--text-cap);line-height:var(--tw-leading,var(--text-cap--line-height))}.text-prose-lg{font-size:var(--text-prose-lg);line-height:var(--tw-leading,var(--text-prose-lg--line-height))}.text-prose-sm{font-size:var(--text-prose-sm);line-height:var(--tw-leading,var(--text-prose-sm--line-height))}.text-\[9\.5px\]{font-size:9.5px}.text-\[9px\]{font-size:9px}.text-\[12\.5px\]{font-size:12.5px}.text-\[15px\]{font-size:15px}.text-\[21px\]{font-size:21px}.text-\[24px\]{font-size:24px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.7\]{--tw-leading:1.7;line-height:1.7}.leading-\[1\.22\]{--tw-leading:1.22;line-height:1.22}.leading-\[1\.65\]{--tw-leading:1.65;line-height:1.65}.leading-\[1\.68\]{--tw-leading:1.68;line-height:1.68}.leading-\[1\.72\]{--tw-leading:1.72;line-height:1.72}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-black{--tw-font-weight:var(--font-weight-black);font-weight:var(--font-weight-black)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-extrabold{--tw-font-weight:var(--font-weight-extrabold);font-weight:var(--font-weight-extrabold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.01em\]{--tw-tracking:.01em;letter-spacing:.01em}.tracking-\[0\.1em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.02em\]{--tw-tracking:.02em;letter-spacing:.02em}.tracking-\[0\.14em\]{--tw-tracking:.14em;letter-spacing:.14em}.tracking-display{--tw-tracking:var(--tracking-display);letter-spacing:var(--tracking-display)}.whitespace-nowrap{white-space:nowrap}.text-\[var\(--band-muted\)\]{color:var(--band-muted)}.text-accent{color:var(--color-accent)}.text-body{color:var(--color-body)}.text-ink{color:var(--color-ink)}.text-muted{color:var(--color-muted)}.uppercase{text-transform:uppercase}.not-italic{font-style:normal}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-100{opacity:1}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-100:hover{opacity:1}}@media (min-width:768px){.md\:-mt-28{margin-top:calc(var(--spacing) * -28)}.md\:mt-0{margin-top:0}.md\:mt-10{margin-top:calc(var(--spacing) * 10)}.md\:mb-24{margin-bottom:calc(var(--spacing) * 24)}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:justify-start{justify-content:flex-start}.md\:px-4{padding-inline:calc(var(--spacing) * 4)}.md\:px-8{padding-inline:calc(var(--spacing) * 8)}.md\:py-5{padding-block:calc(var(--spacing) * 5)}.md\:py-14{padding-block:calc(var(--spacing) * 14)}.md\:py-15{padding-block:calc(var(--spacing) * 15)}.md\:py-16{padding-block:calc(var(--spacing) * 16)}.md\:py-\[13px\]{padding-block:13px}.md\:py-\[14px\]{padding-block:14px}.md\:pt-5{padding-top:calc(var(--spacing) * 5)}.md\:pt-10{padding-top:calc(var(--spacing) * 10)}.md\:pt-13{padding-top:calc(var(--spacing) * 13)}.md\:pt-14{padding-top:calc(var(--spacing) * 14)}.md\:pt-15{padding-top:calc(var(--spacing) * 15)}.md\:pt-16{padding-top:calc(var(--spacing) * 16)}.md\:pt-32{padding-top:calc(var(--spacing) * 32)}.md\:pb-12{padding-bottom:calc(var(--spacing) * 12)}.md\:pb-13{padding-bottom:calc(var(--spacing) * 13)}.md\:pb-15{padding-bottom:calc(var(--spacing) * 15)}.md\:pb-16{padding-bottom:calc(var(--spacing) * 16)}.md\:pb-17{padding-bottom:calc(var(--spacing) * 17)}.md\:pb-18{padding-bottom:calc(var(--spacing) * 18)}.md\:pb-32{padding-bottom:calc(var(--spacing) * 32)}.md\:pb-\[22px\]{padding-bottom:22px}.md\:text-center{text-align:center}.md\:text-\[23px\]{font-size:23px}.md\:text-\[28px\]{font-size:28px}}@media (min-width:1024px){.lg\:col-span-2{grid-column:span 2/span 2}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-6{grid-column:span 6/span 6}.lg\:mt-16{margin-top:calc(var(--spacing) * 16)}.lg\:ml-0{margin-left:0}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:table-cell{display:table-cell}.lg\:h-6{height:calc(var(--spacing) * 6)}.lg\:h-full{height:100%}.lg\:w-1\/4{width:25%}.lg\:w-6{width:calc(var(--spacing) * 6)}.lg\:w-96{width:calc(var(--spacing) * 96)}.lg\:max-w-5xl{max-width:var(--container-5xl)}.lg\:max-w-sm{max-width:var(--container-sm)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:items-center{align-items:center}.lg\:items-end{align-items:flex-end}.lg\:items-stretch{align-items:stretch}.lg\:justify-between{justify-content:space-between}.lg\:justify-start{justify-content:flex-start}.lg\:gap-3{gap:calc(var(--spacing) * 3)}.lg\:gap-x-24{column-gap:calc(var(--spacing) * 24)}:where(.lg\:space-x-6>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 6) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-x-reverse)))}:where(.lg\:space-x-14>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 14) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 14) * calc(1 - var(--tw-space-x-reverse)))}.lg\:gap-y-0{row-gap:0}.lg\:overflow-y-auto{overflow-y:auto}.lg\:px-6{padding-inline:calc(var(--spacing) * 6)}.lg\:px-8{padding-inline:calc(var(--spacing) * 8)}.lg\:px-14{padding-inline:calc(var(--spacing) * 14)}.lg\:py-4{padding-block:calc(var(--spacing) * 4)}.lg\:py-7{padding-block:calc(var(--spacing) * 7)}.lg\:py-10{padding-block:calc(var(--spacing) * 10)}.lg\:py-12{padding-block:calc(var(--spacing) * 12)}.lg\:py-24{padding-block:calc(var(--spacing) * 24)}.lg\:pt-32{padding-top:calc(var(--spacing) * 32)}.lg\:pt-36{padding-top:calc(var(--spacing) * 36)}.lg\:pb-16{padding-bottom:calc(var(--spacing) * 16)}.lg\:pb-40{padding-bottom:calc(var(--spacing) * 40)}.lg\:text-\[25px\]{font-size:25px}.lg\:font-black{--tw-font-weight:var(--font-weight-black);font-weight:var(--font-weight-black)}}@media (min-width:1280px){.xl\:mt-21{margin-top:calc(var(--spacing) * 21)}.xl\:mt-\[18px\]{margin-top:18px}.xl\:mb-\[26px\]{margin-bottom:26px}.xl\:gap-6{gap:calc(var(--spacing) * 6)}.xl\:py-18{padding-block:calc(var(--spacing) * 18)}.xl\:py-21{padding-block:calc(var(--spacing) * 21)}.xl\:pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.xl\:pt-6{padding-top:calc(var(--spacing) * 6)}.xl\:pt-12{padding-top:calc(var(--spacing) * 12)}.xl\:pt-16{padding-top:calc(var(--spacing) * 16)}.xl\:pt-17{padding-top:calc(var(--spacing) * 17)}.xl\:pt-18{padding-top:calc(var(--spacing) * 18)}.xl\:pt-19{padding-top:calc(var(--spacing) * 19)}.xl\:pt-21{padding-top:calc(var(--spacing) * 21)}.xl\:pt-22{padding-top:calc(var(--spacing) * 22)}.xl\:pb-5{padding-bottom:calc(var(--spacing) * 5)}.xl\:pb-16{padding-bottom:calc(var(--spacing) * 16)}.xl\:pb-18{padding-bottom:calc(var(--spacing) * 18)}.xl\:pb-19{padding-bottom:calc(var(--spacing) * 19)}.xl\:pb-21{padding-bottom:calc(var(--spacing) * 21)}.xl\:pb-22{padding-bottom:calc(var(--spacing) * 22)}.xl\:pb-25{padding-bottom:calc(var(--spacing) * 25)}.xl\:pl-3{padding-left:calc(var(--spacing) * 3)}.xl\:text-\[27px\]{font-size:27px}.xl\:text-\[34px\]{font-size:34px}}@media (min-width:1440px){.\32 xl\:mr-3{margin-right:calc(var(--spacing) * 3)}.\32 xl\:w-40{width:calc(var(--spacing) * 40)}.\32 xl\:w-44{width:calc(var(--spacing) * 44)}.\32 xl\:w-auto{width:auto}.\32 xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.\32 xl\:pt-2{padding-top:calc(var(--spacing) * 2)}}.\[\&_b\]\:text-\[12\.5px\] b{font-size:12.5px}.\[\&_b\]\:font-bold b{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.\[\&_b\]\:tracking-\[0\.01em\] b{--tw-tracking:.01em;letter-spacing:.01em}.\[\&_b\]\:text-ink b{color:var(--color-ink)}.\[\&_em\]\:mb-2 em{margin-bottom:calc(var(--spacing) * 2)}.\[\&_em\]\:block em{display:block}.\[\&_em\]\:text-\[9px\] em{font-size:9px}.\[\&_em\]\:text-\[10px\] em{font-size:10px}.\[\&_em\]\:font-bold em{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.\[\&_em\]\:tracking-\[0\.14em\] em{--tw-tracking:.14em;letter-spacing:.14em}.\[\&_em\]\:text-ink em{color:var(--color-ink)}.\[\&_em\]\:text-muted em{color:var(--color-muted)}.\[\&_em\]\:not-italic em{font-style:normal}.\[\&_h2\]\:mb-2\.5 h2{margin-bottom:calc(var(--spacing) * 2.5)}.\[\&_h2\]\:text-\[21px\] h2{font-size:21px}.\[\&_h2\]\:text-\[26px\] h2{font-size:26px}.\[\&_h2\]\:font-bold h2{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.\[\&_h2\]\:tracking-\[-0\.02em\] h2{--tw-tracking:-.02em;letter-spacing:-.02em}@media (min-width:768px){.md\:\[\&_h2\]\:text-\[23px\] h2{font-size:23px}}@media (min-width:1280px){.xl\:\[\&_h2\]\:text-\[26px\] h2{font-size:26px}}.\[\&_i\]\:text-muted i{color:var(--color-muted)}.\[\&_i\]\:not-italic i{font-style:normal}.\[\&_p\]\:max-w-\[700px\] p{max-width:700px}.\[\&_p\]\:font-sans p{font-family:var(--font-sans)}.\[\&_p\]\:text-prose-sm p{font-size:var(--text-prose-sm);line-height:var(--tw-leading,var(--text-prose-sm--line-height))}.\[\&_p\]\:text-\[14px\] p{font-size:14px}.\[\&_p\]\:text-\[15px\] p{font-size:15px}.\[\&_p\]\:leading-\[1\.6\] p{--tw-leading:1.6;line-height:1.6}.\[\&_p\]\:leading-\[1\.65\] p{--tw-leading:1.65;line-height:1.65}.\[\&_p\]\:text-body p{color:var(--color-body)}.\[\&_p_b\]\:font-semibold p b{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_p_b\]\:text-ink p b{color:var(--color-ink)}.\[\&_p\+p\]\:mt-2\.5 p+p{margin-top:calc(var(--spacing) * 2.5)}.\[\&_p\.compare-intro\]\:max-w-none p.compare-intro{max-width:none}.\[\&_u\]\:text-accent u{color:var(--color-accent)}.\[\&_u\]\:no-underline u{text-decoration-line:none}.\[\&\>\.pcell\]\:px-\[22px\]>.pcell{padding-inline:22px}.\[\&\>\.pcell\]\:py-6>.pcell{padding-block:calc(var(--spacing) * 6)}@media (min-width:768px){.md\:\[\&\>\.pcell\]\:px-\[30px\]>.pcell{padding-inline:30px}.md\:\[\&\>\.pcell\]\:py-7>.pcell{padding-block:calc(var(--spacing) * 7)}}.\[\&\>\.pcell\>em\]\:text-\[9\.5px\]>.pcell>em{font-size:9.5px}.\[\&\>\.pcell\>em\]\:tracking-\[0\.14em\]>.pcell>em{--tw-tracking:.14em;letter-spacing:.14em}.\[\&\>\.pcell\>em\]\:text-accent>.pcell>em{color:var(--color-accent)}.\[\&\>\.pcell\>em\]\:not-italic>.pcell>em{font-style:normal}.\[\&\>\.pcell\>h3\]\:my-3>.pcell>h3{margin-block:calc(var(--spacing) * 3)}.\[\&\>\.pcell\>h3\]\:text-\[17px\]>.pcell>h3{font-size:17px}.\[\&\>\.pcell\>h3\]\:font-bold>.pcell>h3{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.\[\&\>\.pcell\>h3\]\:tracking-\[-0\.02em\]>.pcell>h3{--tw-tracking:-.02em;letter-spacing:-.02em}.\[\&\>\.pcell\>p\]\:font-sans>.pcell>p{font-family:var(--font-sans)}.\[\&\>\.pcell\>p\]\:text-\[14px\]>.pcell>p{font-size:14px}.\[\&\>\.pcell\>p\]\:leading-\[1\.68\]>.pcell>p{--tw-leading:1.68;line-height:1.68}.\[\&\>\.pcell\>p\]\:text-body>.pcell>p{color:var(--color-body)}.\[\&\>div\]\:flex>div{display:flex}.\[\&\>div\]\:flex-col>div{flex-direction:column}.\[\&\>div\]\:gap-1\.5>div{gap:calc(var(--spacing) * 1.5)}.\[\&\>div\]\:px-\[14px\]>div{padding-inline:14px}.\[\&\>div\]\:py-3>div{padding-block:calc(var(--spacing) * 3)}.\[\&\>div\]\:py-4>div{padding-block:calc(var(--spacing) * 4)}@media (min-width:768px){.md\:\[\&\>div\]\:p-4>div{padding:calc(var(--spacing) * 4)}.md\:\[\&\>div\]\:px-4>div{padding-inline:calc(var(--spacing) * 4)}}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}