/* ══ OCRO BLOG SURFACE ══════════════════════════════════════════════════════
   One stylesheet for all 64 posts. It replaces the per-post <style> blocks,
   which had drifted into six different versions of the same design.

   Everything here is built from tokens.css. The two rules it inherits:
     SILVER says "this is important"  — the article title, nothing else.
     INDIGO says "this does something" — links, buttons, the progress bar.
   Load order: tokens.css, then this.
   ═══════════════════════════════════════════════════════════════════════════ */

*,*::before,*::after{box-sizing:border-box}

html{
  scroll-behavior:smooth;
  -webkit-text-size-adjust:100%;
  scrollbar-color:var(--charcoal) var(--void);
}
body{
  margin:0;
  background:var(--void);
  color:var(--ash);
  font-family:var(--font-body);
  font-size:var(--fs-0);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
img,svg{display:block;max-width:100%}
/* Links are undecorated by default; the prose rules below opt specific
   contexts back in. Otherwise every card that happens to be an <a> — sidebar
   tiles, blog cards, nav pills — arrives underlined. */
a{color:inherit;text-decoration:none}

::selection{background:var(--indigo-a45);color:var(--ink)}
:focus-visible{outline:2px solid var(--indigo-lit);outline-offset:2px}

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:var(--void)}
::-webkit-scrollbar-thumb{background:var(--charcoal);border:3px solid var(--void);border-radius:8px}
::-webkit-scrollbar-thumb:hover{background:var(--iron)}

/* ── reading progress ─────────────────────────────────────────────────────
   A live value, so it wears the action colour. */
.scroll-progress{
  position:fixed;top:0;left:0;z-index:120;
  height:2px;width:100%;
  /* Laid out at full width once and scaled down, rather than having its
     width written every frame. width is a layout property: animating it
     relayouts and repaints the bar and its glow on every scroll frame,
     while a transform is handled by the compositor and never touches
     layout. site.js writes the scaleX, so the two change together. */
  transform:scaleX(0);transform-origin:0 50%;
  background:var(--indigo);
  will-change:transform;
}

/* ── nav ──────────────────────────────────────────────────────────────────
   Scoped to the page's own header. A bare `nav` selector also catches every
   in-content navigation — the table of contents, breadcrumbs — and drags them
   into position:sticky. */
body > nav,nav#navbar{
  position:sticky;top:0;z-index:100;
  display:flex;align-items:center;gap:var(--sp-gutter);
  padding:0 var(--sp-gutter);height:64px;
  background:color-mix(in srgb,var(--void) 88%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom:1px solid transparent;
  transition:border-color var(--dur-2) var(--ease-std),background var(--dur-2) var(--ease-std),backdrop-filter var(--dur-2) var(--ease-std),-webkit-backdrop-filter var(--dur-2) var(--ease-std);
}
/* The frosted nav, kept where it reads and dropped where it cannot.

   backdrop-filter is the one thing left on these pages that makes the
   compositor read back the pixels behind an element, filter them and
   re-composite, every frame the backdrop moves. The nav is sticky, so the
   backdrop moves for the whole length of every scroll.

   Measured off the computed style: the plate is 88% opaque at rest and 96%
   once scrolled. So the blur is filtering the 12% of the backdrop that
   shows through at the top of the page, and the 4% that shows through
   while you are moving. It is doing its visible work at rest, when nothing
   is moving and it costs nothing, and paying its per-frame cost during the
   scroll, when 96% of what it produces is covered by the plate.

   So it stays on the idle nav and comes off the scrolled one. The plate
   ramping 88% to 96% and the blur ramping out share the same transition,
   so the handoff is a fade rather than a snap. */
body > nav.scrolled,nav#navbar.scrolled{
  border-bottom-color:var(--hairline);
  background:color-mix(in srgb,var(--void) 96%,transparent);
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
.nav-logo{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--font-display);font-size:1.5rem;letter-spacing:.03em;
  text-transform:uppercase;color:var(--ink);text-decoration:none;line-height:1;flex:none;
}
.nav-logo img,.nav-logo svg,.nav-logo-mark{width:30px;height:30px;object-fit:contain;object-position:center;flex:none}
.nav-links{
  display:flex;align-items:center;gap:28px;
  margin:0 0 0 auto;padding:0;list-style:none;
}
.nav-links a{
  font-size:.875rem;color:var(--smoke);text-decoration:none;
  transition:color var(--dur-2) var(--ease-std);
}
.nav-links a:hover{color:var(--ink)}
.nav-links a.blog-link{color:var(--ink)}
/* the last item is the action */
.nav-links li:last-child a{
  display:inline-flex;align-items:center;min-height:36px;padding:0 16px;
  background:var(--indigo-fill);color:var(--ink);
  border-radius:var(--r-2);corner-shape:squircle;font-weight:500;
}
.nav-links li:last-child a:hover{background:var(--indigo)}

.nav-toggle{
  display:none;flex-direction:column;justify-content:center;gap:5px;
  width:40px;height:40px;margin-left:auto;padding:0 8px;
  background:none;border:0;cursor:pointer;
}
.nav-toggle span{display:block;height:1.5px;width:100%;background:var(--bone);transition:transform var(--dur-2) var(--ease-std),opacity var(--dur-1)}

/* ── article header ─────────────────────────────────────────────────────── */
.article-header{padding:var(--sp-tight) var(--sp-gutter) 0}
/* Same measure as .article-inner below, not --read. The header sat in an
   880px column while the prose under it sat in a 68ch (~744px) one, so the
   breadcrumb, category, h1 and buttons all hung 68px to the left of the
   first paragraph — two left edges, one page. */
.article-header-inner{max-width:min(68ch,100%);margin:0 auto}

/* width:fit-content keeps it clickable only across its own text while still
   claiming its own line, so the category chip below never rides up beside it */
.article-back{
  display:flex;width:fit-content;align-items:center;gap:8px;
  font-size:.8125rem;color:var(--iron);text-decoration:none;
  transition:color var(--dur-2) var(--ease-std);
}
.article-back:hover{color:var(--ink)}
.article-back svg{width:15px;height:15px;flex:none}

.article-category{
  display:inline-block;margin:26px 0 18px;padding:5px 12px;
  background:var(--lift);border:1px solid var(--hairline);
  border-radius:var(--r-1);corner-shape:squircle;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--smoke);
}

/* the one silver moment on the page */
.article-h1{
  margin:0;
  font-family:var(--font-display);font-weight:400;
  font-size:var(--fs-6);line-height:.92;letter-spacing:.012em;
  text-transform:uppercase;
  /* The loud ramp, not the soft one. This is the page's h1, and the
     homepage's h1 carries --grad-chrome while its section headings carry
     --grad-chrome-soft. An article title lit one step below the homepage's
     was the same site opening two different ways. */
  background-image:var(--grad-chrome);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}

.article-meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:22px;
  margin-top:26px;padding-bottom:var(--sp-tight);
  border-bottom:1px solid var(--hairline);
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.07em;color:var(--iron);
}
.article-meta span{display:inline-flex;align-items:center;gap:8px}
.article-meta svg{width:14px;height:14px;flex:none;opacity:.75}
.byline a{color:var(--smoke);text-decoration:none}
.byline a:hover{color:var(--ink)}

/* ── article body ─────────────────────────────────────────────────────────
   READING RULES, and why each one is here.

   HALATION. On a dark ground, high-luminance text bleeds into the background
   for anyone with astigmatism — the counters inside letterforms fill in and a
   paragraph turns into a grey smear. Three things cause it, and all three are
   controlled below:
     1. Peak luminance. Long-form copy never uses --ink (21:1). Body sits on
        --ash (9.2:1) and prose headings on --bone, not white. Only the H1 and
        short labels get the top of the ramp, where a few words can carry it.
     2. Stroke thinness. DM Sans at 400 is the floor here; 300 exists in the
        loaded family and must not be used for running text on this ground.
     3. Tracking. Dark-on-light can be set tight; light-on-dark cannot, because
        the bloom closes the gaps. Body copy carries a small positive track.

   MEASURE. --read is 880px, which at this size runs to ~95 characters — half
   as long again as anyone can comfortably track back from. Prose is capped in
   ch so it stays 65–75 regardless of the font size the fluid scale lands on.
   ------------------------------------------------------------------------ */
.article-content{padding:var(--sp-tight) var(--sp-gutter) var(--sp-section)}
.article-inner{
  max-width:min(68ch,100%);margin:0 auto;
  letter-spacing:.006em;
}

.article-inner p{margin:0 0 1.35em;color:var(--ash);font-size:var(--fs-1);line-height:1.8}
.article-inner p strong,.article-inner li strong{color:var(--bone);font-weight:500}

/* the opening paragraph carries the summary, so it is set one step up */
.article-inner>p:first-child{
  font-size:var(--fs-2);line-height:1.65;color:var(--smoke);margin-bottom:1.6em;
}

/* A rule above each section does the separating, so the heading itself does
   not have to shout in pure white to register as a break. */
.article-inner h2{
  margin:2.6em 0 .75em;padding-top:1.5em;
  border-top:1px solid var(--hairline);
  font-family:var(--font-display);font-weight:400;
  font-size:clamp(1.75rem,1.2rem + 2vw,2.5rem);
  line-height:1.04;letter-spacing:.02em;
  text-transform:uppercase;color:var(--bone);
}
.article-inner>h2:first-child{margin-top:0;padding-top:0;border-top:0}
.article-inner h3{
  margin:2.1em 0 .55em;
  font-size:var(--fs-3);font-weight:500;line-height:1.3;
  letter-spacing:.004em;color:var(--bone);
}

.article-inner ul,.article-inner ol{margin:0 0 1.5em;padding-left:1.35em}
.article-inner li{margin-bottom:.7em;color:var(--ash);font-size:var(--fs-1);line-height:1.75}
.article-inner li::marker{color:var(--iron)}
.article-inner li>ul,.article-inner li>ol{margin:.7em 0 0}

/* ── contents ─────────────────────────────────────────────────────────────
   Built by article.js from the H2s, only on posts long enough to need it. */
.toc{
  display:block;position:static;
  margin:0 0 2.4em;padding:20px 22px;
  background:var(--surface-plain);border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
}
.toc h2{
  all:unset;display:block;margin-bottom:12px;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);
}
.toc ol{margin:0;padding:0;list-style:none;counter-reset:toc}
.toc li{counter-increment:toc;margin:0}
/* specificity has to beat `.article-inner a`, which is declared later */
.article-inner .toc a{
  display:flex;gap:12px;padding:7px 0;
  color:var(--smoke);font-size:.9375rem;line-height:1.45;
  text-decoration:none;
  transition:color var(--dur-2) var(--ease-std);
}
.article-inner .toc a:hover{color:var(--ink);text-decoration:none}
.toc a::before{
  content:counter(toc,decimal-leading-zero);
  font-family:var(--font-mono);font-size:var(--fs-mono);color:var(--charcoal);
  flex:none;padding-top:.2em;
}
.toc a:hover{color:var(--ink)}
.toc a:hover::before{color:var(--indigo-lit)}

/* headings get a quiet anchor once they have an id */
.article-inner h2[id],.article-inner h3[id]{scroll-margin-top:90px;position:relative}
.anchor{
  position:absolute;left:-1.1em;top:50%;transform:translateY(-50%);
  opacity:0;color:var(--charcoal);text-decoration:none;font-size:.7em;
  transition:opacity var(--dur-2) var(--ease-std);
}
h2:hover>.anchor,h3:hover>.anchor,.anchor:focus-visible{opacity:1}
.anchor:hover{color:var(--indigo-lit)}
@media (max-width:900px){.anchor{display:none}}

.article-inner a{
  color:var(--indigo-lit);
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--indigo-a45);
  transition:text-decoration-color var(--dur-2) var(--ease-std);
}
.article-inner a:hover{text-decoration-color:var(--indigo-lit)}

.article-inner blockquote{
  margin:1.8em 0;padding:2px 0 2px 22px;
  border-left:1px solid var(--indigo);
  color:var(--smoke);font-size:var(--fs-1);font-style:italic;
}
.article-inner code{
  font-family:var(--font-mono);font-size:.9em;
  padding:2px 6px;background:var(--lift);border:1px solid var(--hairline);
  border-radius:var(--r-1);color:var(--bone);
}
.article-inner img{margin:1.8em 0;border-radius:var(--r-3);border:1px solid var(--hairline)}
.article-inner hr{margin:2.4em 0;border:0;border-top:1px solid var(--hairline)}

/* ── panels: callout, sources, notice ───────────────────────────────────── */
.callout,.sources,.rg-notice,.cta-inline{
  position:relative;
  background-color:var(--surface-plain);
  background-image:var(--bloom-top),
    linear-gradient(180deg,rgba(255,255,255,.030) 0%,rgba(255,255,255,.008) 44%,rgba(255,255,255,0) 100%);
  border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
}
.callout::before,.sources::before,.rg-notice::before,.cta-inline::before{
  content:"";position:absolute;left:12%;right:12%;top:-1px;height:1px;
  background:var(--rim);opacity:.75;pointer-events:none;
}

.callout{margin:2em 0;padding:var(--pad-card)}
.callout h3{margin:0 0 .5em;font-size:var(--fs-2);font-weight:500;color:var(--ink)}
.callout p{margin:0 0 .8em;color:var(--smoke);font-size:var(--fs-0)}
.callout p:last-child{margin-bottom:0}
/* the two variants differ by the mark on the edge, not by a coloured fill */
.callout.method{border-left:2px solid var(--indigo)}
.callout.warn{border-left:2px solid var(--red)}

.sources{margin:var(--sp-tight) 0 0;padding:var(--pad-card)}
.sources h2{
  margin:0 0 .9em;padding-top:0;border-top:0;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);font-weight:400;
}
.sources ol{margin:0;padding-left:1.2em}
.sources li{margin-bottom:.55em;color:var(--smoke);font-size:.875rem;line-height:1.6}
.sources li::marker{color:var(--charcoal)}
.sources a{color:var(--smoke);text-decoration:underline;text-underline-offset:2px;text-decoration-color:var(--charcoal)}
.sources a:hover{color:var(--indigo-lit);text-decoration-color:var(--indigo-a45)}

.rg-notice{margin:2em 0;padding:18px 20px}
.rg-notice p{margin:0;color:var(--iron);font-size:.8125rem;line-height:1.6}
.rg-notice strong{color:var(--smoke);font-weight:500}
.rg-notice a{color:var(--smoke);text-decoration:underline;text-underline-offset:2px}
.rg-notice a:hover{color:var(--ink)}

/* ── inline CTA ─────────────────────────────────────────────────────────── */
.cta-inline{
  display:flex;flex-wrap:wrap;align-items:center;gap:20px;
  margin:2.4em 0;padding:var(--pad-card);
}
.cta-inline p{margin:0;flex:1 1 260px;color:var(--smoke);font-size:var(--fs-0)}
.article-inner .cta-inline p strong{display:block;color:var(--ink);font-size:var(--fs-2);font-weight:500;margin-bottom:4px}
/* The button sits inside .article-inner, so the prose link rule reaches it
   and outranks .btn: indigo text on the indigo fill, underlined. */
.article-inner .btn,.article-inner .btn:hover{color:var(--ink);text-decoration:none}

.article-cta-top{display:flex;flex-wrap:wrap;gap:12px;margin:28px 0 2em}
.article-cta-top .btn{width:auto}

/* ── buttons ────────────────────────────────────────────────────────────── */
.btn,.cta-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:44px;padding:12px 22px;
  font-family:var(--font-body);font-size:.9375rem;font-weight:500;
  color:var(--ink);background:var(--indigo-fill);
  border:1px solid transparent;border-radius:var(--r-2);corner-shape:squircle;
  text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:background var(--dur-2) var(--ease-std);
}
.btn:hover,.cta-btn:hover{background:var(--indigo)}
.btn-ghost{background:transparent;border-color:var(--hairline);color:var(--bone)}
.btn-ghost:hover{background:rgba(255,255,255,.04);border-color:var(--hairline-lit)}

/* ── tables ─────────────────────────────────────────────────────────────── */
.table-scroll{margin:2em 0;overflow-x:auto;-webkit-overflow-scrolling:touch}
table.cmp,.comparison-table{
  width:100%;border-collapse:collapse;
  font-size:.875rem;font-variant-numeric:tabular-nums;
}
table.cmp caption{
  caption-side:top;text-align:left;padding-bottom:.8em;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);
}
table.cmp th,table.cmp td,.comparison-table th,.comparison-table td{
  padding:12px 16px;text-align:left;border-bottom:1px solid var(--hairline);
}
table.cmp thead th,.comparison-table th{
  font-family:var(--font-mono);font-size:var(--fs-mono);font-weight:400;
  text-transform:uppercase;letter-spacing:.08em;color:var(--iron);
  border-bottom-color:var(--hairline-lit);white-space:nowrap;
}
table.cmp td{color:var(--ash)}
table.cmp td:first-child,table.cmp th:first-child{color:var(--bone)}
table.cmp tbody tr:hover td{background:var(--surface-lift)}
table.cmp .ocro{color:var(--ink)}
table.cmp .winner{color:var(--green)}
table.cmp .loser{color:var(--iron)}

/* ── hub / index pages ──────────────────────────────────────────────────── */
.crumbs{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.08em;color:var(--charcoal);
}
.crumbs a{color:var(--iron);text-decoration:none}
.crumbs a:hover{color:var(--ink)}
.crumbs span{color:var(--charcoal)}

.hub-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr));
  gap:var(--sp-7);margin:var(--sp-tight) 0 0;
}
.hub-card{
  display:block;padding:var(--pad-card);text-decoration:none;
  background-color:var(--surface-plain);
  border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
  transition:border-color var(--dur-2) var(--ease-std),background var(--dur-2) var(--ease-std),transform var(--dur-2) var(--ease-out);
}
.hub-card:hover{border-color:var(--hairline-lit);background-color:var(--surface-lift);transform:translateY(-2px)}
.hub-card h3{margin:0 0 .5em;font-size:var(--fs-3);font-weight:500;line-height:1.25;color:var(--ink)}
.hub-card p{margin:0 0 1em;color:var(--smoke);font-size:.9375rem;line-height:1.6}
.hub-card .hub-meta{
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.08em;color:var(--iron);
}

/* ── calculator (rate posts) ────────────────────────────────────────────── */
.calc{
  margin:2.2em 0;padding:var(--pad-card);
  background:var(--surface-plain);border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
}
.calc-row{display:flex;flex-wrap:wrap;gap:14px;margin-bottom:16px}
.calc-row label{flex:1 1 200px;display:flex;flex-direction:column;gap:6px;font-size:.875rem;color:var(--smoke)}
.calc-row label small{color:var(--iron);font-size:.75rem}
.calc input,.calc select{
  width:100%;min-height:44px;padding:10px 12px;
  background:var(--lift);border:1px solid var(--hairline);
  border-radius:var(--r-2);corner-shape:squircle;
  color:var(--ink);font-family:var(--font-mono);font-size:.875rem;
}
.calc input:focus,.calc select:focus{outline:none;border-color:var(--indigo);box-shadow:0 0 0 3px var(--indigo-a24)}
.calc-out{
  display:flex;flex-wrap:wrap;gap:26px;
  margin-top:20px;padding-top:20px;border-top:1px solid var(--hairline);
}
.calc-metric .k{
  display:block;font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.09em;color:var(--iron);margin-bottom:4px;
}
.calc-metric .v{
  display:block;font-family:var(--font-display);font-size:var(--fs-5);
  line-height:1;color:var(--ink);font-variant-numeric:tabular-nums;
}
.calc-metric .v.accent{color:var(--indigo-lit)}
.calc-note{margin:14px 0 0;font-size:.8125rem;color:var(--iron)}

/* ── closing CTA band ───────────────────────────────────────────────────── */
.cta-section{
  padding:var(--sp-section) var(--sp-gutter);
  border-top:1px solid var(--hairline);
  background:linear-gradient(180deg,var(--surface-plain) 0%,var(--void) 100%);
}
.cta-inner{max-width:var(--read);margin:0 auto;text-align:center}
.cta-h2{
  margin:0 0 .5em;
  font-family:var(--font-display);font-weight:400;
  font-size:var(--fs-5);line-height:1;letter-spacing:.012em;
  text-transform:uppercase;color:var(--ink);
}
/* The chrome fill, read off the homepage rather than invented here. There,
   every section heading carries --grad-chrome-soft and the accent phrase
   inside one repeats its PARENT'S gradient instead of changing hue. Both
   tokens already sat in tokens.css with values identical to the homepage's;
   only the wiring differed, which is how a heading ended up flat white with
   an indigo phrase in the middle of it while the homepage's was silver the
   whole way across.

   This lives in site.css, not pages.css: 63 of the 86 pages that carry this
   design are blog articles and they never load pages.css. .cta-h2 appears on
   16 of them.

   The accent gets its own background BOX, not its own colour. That is the
   whole mechanism: the heading's gradient is painted across the heading's
   box and the span's across the span's, so one gradient lands at two phases
   and the phrase separates by light rather than by hue. Emphasis here is a
   lighting decision, never a colour one. Colour is spoken for by the action
   system, and an indigo phrase inside a heading read as a link that could
   not be clicked.

   `.calc-metric .v.accent` above is a different thing and keeps the action
   colour: that one is a live value, not a heading. */
.cta-h2,.cta-h2 .accent{
  background-image:var(--grad-chrome-soft);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
.cta-p{margin:0 auto 1.8em;max-width:52ch;color:var(--smoke);font-size:var(--fs-1)}

/* ── related services / disclaimer (one-offs) ───────────────────────────── */
.related-services-section,.disclaimer-section{
  padding:var(--sp-tight) var(--sp-gutter);border-top:1px solid var(--hairline);
}
.related-services-inner,.disclaimer-inner{max-width:var(--read);margin:0 auto}
.related-services-label,.disclaimer-label{
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);margin-bottom:1em;
}
.related-services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr));gap:14px}
.related-service-card{
  display:block;padding:18px;text-decoration:none;
  background:var(--surface-plain);border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
}
.related-service-card:hover{border-color:var(--hairline-lit);background:var(--surface-lift)}
.related-service-title{display:block;color:var(--ink);font-weight:500;margin-bottom:4px}
.related-service-desc{display:block;color:var(--iron);font-size:.875rem;line-height:1.55}
.disclaimer-text{color:var(--iron);font-size:.8125rem;line-height:1.6}

/* ── footer ─────────────────────────────────────────────────────────────── */
footer{
  padding:var(--sp-section) var(--sp-gutter) 32px;
  border-top:1px solid var(--hairline);background:var(--void);
}
.footer-top{
  display:grid;grid-template-columns:1.6fr repeat(3,1fr);gap:44px;
  max-width:var(--page);margin:0 auto;
}
.footer-logo{
  font-family:var(--font-display);font-size:1.75rem;letter-spacing:.03em;
  text-transform:uppercase;color:var(--ink);text-decoration:none;line-height:1;
}
.footer-tagline{margin:12px 0 18px;color:var(--iron);font-size:.875rem;line-height:1.6;max-width:34ch}
.footer-links-group h3{
  margin:0 0 14px;
  font-family:var(--font-mono);font-size:var(--fs-mono);font-weight:400;
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);
}
.footer-links-group ul{margin:0;padding:0;list-style:none}
.footer-links-group li{margin-bottom:9px}
.footer-links-group a{color:var(--smoke);font-size:.875rem;text-decoration:none;transition:color var(--dur-2) var(--ease-std)}
.footer-links-group a:hover{color:var(--ink)}
.footer-contact-email{color:var(--smoke);font-size:.875rem;text-decoration:none}
.footer-contact-email:hover{color:var(--indigo-lit)}
.footer-bottom{
  display:flex;flex-wrap:wrap;align-items:center;gap:18px;
  max-width:var(--page);margin:var(--sp-tight) auto 0;
  padding-top:26px;border-top:1px solid var(--hairline);
}
.footer-copy{margin:0;color:var(--charcoal);font-size:.8125rem}
.footer-legal{display:flex;gap:20px;margin-left:auto}
.footer-legal a{color:var(--charcoal);font-size:.8125rem;text-decoration:none}
.footer-legal a:hover{color:var(--smoke)}

/* ── blog index ─────────────────────────────────────────────────────────
   The hub uses its own template: a category rail, then a card grid. */
.cat-nav,.cat-nav-alt{
  display:flex;flex-wrap:wrap;gap:10px;
  max-width:var(--page);margin:0 auto;padding:0;
}
.cat-nav{margin-top:var(--sp-tight)}
.cat-nav-alt{margin-top:10px}
.cat-nav a,.cat-nav-alt a{
  padding:8px 15px;text-decoration:none;
  background:var(--lift);border:1px solid var(--hairline);
  border-radius:var(--r-pill);
  font-size:.8125rem;color:var(--smoke);
  transition:border-color var(--dur-2) var(--ease-std),color var(--dur-2) var(--ease-std);
}
.cat-nav a:hover,.cat-nav-alt a:hover{border-color:var(--hairline-lit);color:var(--ink)}
.cat-nav-alt a{
  background:none;border-color:transparent;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.08em;color:var(--iron);
}
.cat-nav-alt a:hover{color:var(--indigo-lit);border-color:transparent}

.blog-section{padding:var(--sp-tight) var(--sp-gutter) var(--sp-section)}
.blog-inner{max-width:var(--page);margin:0 auto}
.blog-label{
  display:flex;align-items:center;gap:14px;margin-bottom:20px;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.1em;color:var(--iron);
}
.blog-label::after{content:"";flex:1;height:1px;background:var(--hairline)}
.blog-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(310px,100%),1fr));gap:var(--sp-7)}
.blog-card{
  display:flex;flex-direction:column;padding:var(--pad-card);text-decoration:none;
  background:var(--surface-plain);border:1px solid var(--hairline);
  border-radius:var(--r-3);corner-shape:squircle;
  transition:border-color var(--dur-2) var(--ease-std),background var(--dur-2) var(--ease-std),transform var(--dur-2) var(--ease-out);
}
/* the card is a div around one link; the link has to be the flex column or
   the excerpt cannot grow and the meta line floats at different heights */
.blog-card>a{display:flex;flex-direction:column;flex:1;text-decoration:none}
.blog-card:hover{border-color:var(--hairline-lit);background:var(--surface-lift);transform:translateY(-2px)}
.blog-tag{
  align-self:flex-start;margin-bottom:14px;padding:4px 11px;
  background:var(--lift);border:1px solid var(--hairline);
  border-radius:var(--r-1);corner-shape:squircle;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.09em;color:var(--smoke);
}
.blog-title{margin:0 0 .5em;font-size:var(--fs-3);font-weight:500;line-height:1.25;color:var(--ink)}
.blog-excerpt{margin:0 0 1.2em;color:var(--smoke);font-size:.9375rem;line-height:1.6;flex:1}
.blog-meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:16px;
  font-family:var(--font-mono);font-size:var(--fs-mono);
  text-transform:uppercase;letter-spacing:.08em;color:var(--iron);
}
.blog-meta span{display:inline-flex;align-items:center;gap:7px}
.cal-icon{width:13px;height:13px;flex:none;opacity:.75;
  fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* stragglers the templates use once each */
.stats-row .s{display:block}
.metric-name{color:var(--bone);font-weight:500}
.toast-content{flex:1;min-width:0}

/* ── responsive ─────────────────────────────────────────────────────────── */
@media (max-width:860px){
  .footer-top{grid-template-columns:1fr 1fr;gap:32px}
  .footer-top>*:first-child{grid-column:1/-1}
}
@media (max-width:768px){
  /* The nav rules that used to sit here now live in the 940px block at the
     end of this file, which subsumes them exactly. Two blocks saying the
     same thing at two widths is how the collapse width drifts. */
  .article-meta{gap:14px}
  /* stacked, the 260px basis on the paragraph would become a height */
  .cta-inline{flex-direction:column;align-items:flex-start}
  .cta-inline p{flex:none}
  .btn,.cta-btn{width:100%}
  .article-cta-top .btn{width:auto}
  .footer-bottom{flex-direction:column;align-items:flex-start;gap:12px}
  .footer-legal{margin-left:0}
}
@media (max-width:520px){
  .footer-top{grid-template-columns:1fr}
  .calc-out{gap:18px}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
  .hub-card:hover{transform:none}
}


/* ══ ATMOSPHERE ════════════════════════════════════════════════════════════
   Ported from assets/rework/styles/ocro.css, which only index.html loads.
   Without this every page outside the homepage sat on flat --void, which is
   the single biggest reason they did not read as the same site.

   Two fixed, pointer-transparent layers behind all content: an overhead lamp
   plus three shallow-diagonal beams, then a grain overlay. Sections are
   transparent, so these run unbroken from the nav to the footer. */
:root{
  /* Three beams at descending strength and uneven spacing — an evenly
     weighted set reads as a pattern rather than as one light source.
     169-171deg is about 9deg off horizontal: at 45deg a streak reads as a
     graphic device, at 0deg as a divider. Only the shallow diagonal reads as
     light arriving from off-screen. */
  --streaks:
    linear-gradient(170deg,
      rgba(214,235,253,0)    19.8%,
      rgba(214,235,253,.015) 22.2%,
      rgba(214,235,253,.072) 25.0%,
      rgba(214,235,253,.015) 27.8%,
      rgba(214,235,253,0)    30.2%),
    linear-gradient(171deg,
      rgba(214,235,253,0)    36.84%,
      rgba(214,235,253,.011) 38.44%,
      rgba(214,235,253,.046) 40.20%,
      rgba(214,235,253,.011) 41.96%,
      rgba(214,235,253,0)    43.56%),
    linear-gradient(169deg,
      rgba(214,235,253,0)    59.4%,
      rgba(214,235,253,.014) 62.2%,
      rgba(214,235,253,.048) 65.0%,
      rgba(214,235,253,.014) 67.8%,
      rgba(214,235,253,0)    70.6%);
  /* The overhead source the beams are a reflection of. */
  --lamp:radial-gradient(56% 40% at 50% -6%,
    rgba(214,235,253,.042) 0%,
    rgba(214,235,253,.018) 30%,
    rgba(214,235,253,.007) 55%,
    rgba(214,235,253,0)    78%);
  /* Streaks second so they paint behind the lamp's crown, not over it. */
  --atmos:var(--lamp),var(--streaks);
  /* A beam that stops dead at the viewport edge is a line someone drew.
     Faded out before it arrives, it has no beginning or end. Two mask layers
     composited with intersect — ends, then vertical weighting. */
  --atmos-falloff:
    linear-gradient(90deg,rgba(0,0,0,0) 0%,rgba(0,0,0,.55) 12%,rgba(0,0,0,1) 30%,rgba(0,0,0,1) 70%,rgba(0,0,0,.55) 88%,rgba(0,0,0,0) 100%),
    linear-gradient(180deg,rgba(0,0,0,1) 0%,rgba(0,0,0,1) 72%,rgba(0,0,0,.75) 88%,rgba(0,0,0,.4) 96%,rgba(0,0,0,.15) 100%);
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

body::before{
  content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:var(--atmos);
  -webkit-mask-image:var(--atmos-falloff);
          mask-image:var(--atmos-falloff);
  -webkit-mask-composite:source-in;
          mask-composite:intersect;
}
/* Grain. On a near-black ground `overlay` scales with the backdrop, so the
   particulate is strongest inside the beams and absent in the dark corners,
   which is the behaviour you would pick, and here it is free from the blend
   mode. It is also what stops ramps this shallow from banding on 8-bit panels.

   The blend mode has a real cost: an element carrying one cannot be composited
   on its own, so this fixed full-viewport layer loses its promotion and gets
   repainted with the scrolling contents. It was swapped to mix-blend-mode:
   normal at a re-solved opacity of 0.018, which matched the old look to within
   1.5/255, and put back because the difference was still visible and the look
   matters more here than the frames.

   If it ever needs to go again: normal mode at 0.018 / 0.014 / 0.010 / 0.010
   for the four opacities below reproduces this within one and a half levels,
   measured by compositing the texture onto the real ground tones in both
   modes. Do not simply switch the mode: at 0.55 normal lifts the ground from
   7/255 to 56/255 and greys out the whole site. */
body::after{
  content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--grain);background-size:180px 180px;
  mix-blend-mode:overlay;opacity:0.55;
}

/* The atmosphere is nearly invisible on a phone otherwise: the horizontal
   mask holds full opacity only between 30% and 70%, which on a 390px viewport
   is a narrow band, and beams at 170deg barely cross a tall narrow screen.
   Steeper angles and a wider mask below 768px. */
@media (max-width:768px){
  :root{
    --streaks:
      linear-gradient(154deg,
        rgba(214,235,253,0)    14%,
        rgba(214,235,253,.02)  18%,
        rgba(214,235,253,.085) 24%,
        rgba(214,235,253,.02)  30%,
        rgba(214,235,253,0)    34%),
      linear-gradient(158deg,
        rgba(214,235,253,0)    44%,
        rgba(214,235,253,.015) 47%,
        rgba(214,235,253,.055) 51%,
        rgba(214,235,253,.015) 55%,
        rgba(214,235,253,0)    58%),
      linear-gradient(150deg,
        rgba(214,235,253,0)    68%,
        rgba(214,235,253,.018) 72%,
        rgba(214,235,253,.06)  77%,
        rgba(214,235,253,.018) 82%,
        rgba(214,235,253,0)    86%);
    --lamp:radial-gradient(80% 34% at 50% -4%,
      rgba(214,235,253,.055) 0%,
      rgba(214,235,253,.022) 34%,
      rgba(214,235,253,0)    72%);
    --atmos-falloff:
      linear-gradient(90deg,rgba(0,0,0,.35) 0%,rgba(0,0,0,1) 12%,rgba(0,0,0,1) 88%,rgba(0,0,0,.35) 100%),
      linear-gradient(180deg,rgba(0,0,0,1) 0%,rgba(0,0,0,1) 62%,rgba(0,0,0,.6) 84%,rgba(0,0,0,.15) 96%,rgba(0,0,0,0) 100%);
  }
  body::after{opacity:.42}
}

/* The hairline system sits deliberately low-contrast; at this setting that is
   a liability. Pull the grain back so edges stay crisp. */
@media (prefers-contrast:more){
  body::after{opacity:0.25}
}
@media (prefers-reduced-transparency:reduce){
  body::after{opacity:0.3}
}
@media print{
  body::before,body::after{display:none !important}
}

/* ══ LONG-TOKEN SAFETY ═════════════════════════════════════════════════════
   URLs, email addresses and hashes are single unbreakable tokens. Because a
   grid or flex track measures its children's min-content width, one 28-char
   URL in a paragraph is enough to force page-level horizontal scroll on a
   narrow phone — this was the cause on contact.html (emails) and
   casino-clipping-agency.html (support.google.com/adspolicy).

   `break-word` is the gentler default for prose: it only breaks when a word
   genuinely cannot fit, and leaves normal text alone. `anywhere` is stronger
   and is the one that actually lowers the intrinsic min-content size, so it
   goes on the elements that carry the long tokens. */
p,li,dd,dt,td,th,figcaption,blockquote,.lead,.sb-meta{overflow-wrap:break-word}
a,code,kbd,samp,.sb-value,.url{overflow-wrap:anywhere}

/* ══ BAND & SPOTLIGHT ══════════════════════════════════════════════════════
   The two section-level devices the homepage uses and the inner pages had
   no access to. `.band` replaces a hard 1px border-top with a bloom plus a
   lit rim that dies at both ends: light catching an edge rather than a rule
   someone drew. A border runs the full viewport width and, where a section
   has large top padding, reads as a line with nothing under it — a rim can
   begin in empty space, a border cannot. */
.band{position:relative}
.band::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    var(--bloom-top),
    linear-gradient(180deg,rgba(255,255,255,0.032) 0%,rgba(255,255,255,0.012) 38%,rgba(255,255,255,0) 100%);
}
.band::after{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;z-index:0;
  pointer-events:none;background:var(--rim);opacity:0.55;
}
.band > *{position:relative;z-index:1}

/* A soft pool that tracks the cursor across a surface. Puts light on the
   object instead of behind it, and only where the reader is actually looking.
   Falls back to a static top-centre pool if the pointer script is absent. */
.spotlight{position:relative}
.spotlight::after{
  content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  border-radius:inherit;
  background:radial-gradient(300px circle at var(--mx,50%) var(--my,0%),
    rgba(255,255,255,0.10) 0%,rgba(99,102,241,0.14) 26%,
    rgba(99,102,241,0.05) 52%,rgba(99,102,241,0) 76%);
  opacity:0;transition:opacity 260ms var(--ease-std);
}
.spotlight:hover::after{opacity:1}
.spotlight > *{position:relative;z-index:2}
@media (hover:none){.spotlight::after{display:none}}

/* The end-of-page CTA carried a hard hairline border-top. Same block, same
   gradient, but lit at the seam instead of ruled — this is the single most
   repeated section on the site (48 pages), so it is what most readers see. */
.cta-section{border-top:0}
.cta-section::after{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;z-index:0;
  pointer-events:none;background:var(--rim);opacity:0.55;
}
.cta-section{position:relative}
.cta-section > *{position:relative;z-index:1}

/* The card components the inner pages actually use, opted into the spotlight.
   Done by selector rather than by adding a class to 400+ markup instances.
   Without the pointer script the gradient still resolves at its 50%/0%
   defaults, which reads as a glow from the top edge on hover — so the effect
   degrades to something deliberate rather than to nothing. */
.hub-card,.blog-card,.perk-card,.sb-item,.form-card{position:relative}
.hub-card::after,.blog-card::after,.perk-card::after,.sb-item::after,.form-card::after{
  content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  border-radius:inherit;
  background:radial-gradient(300px circle at var(--mx,50%) var(--my,0%),
    rgba(255,255,255,0.10) 0%,rgba(99,102,241,0.14) 26%,
    rgba(99,102,241,0.05) 52%,rgba(99,102,241,0) 76%);
  opacity:0;transition:opacity 260ms var(--ease-std);
}
.hub-card:hover::after,.blog-card:hover::after,.perk-card:hover::after,
.sb-item:hover::after,.form-card:focus-within::after{opacity:1}
.hub-card > *,.blog-card > *,.perk-card > *,.sb-item > *,.form-card > *{position:relative;z-index:2}
@media (hover:none){
  .hub-card::after,.blog-card::after,.perk-card::after,.sb-item::after,.form-card::after{display:none}
}

/* ══ SKIP LINK ═════════════════════════════════════════════════════════════
   Was defined only in ocro.css, so only the homepage had one. Hidden until
   focused, then slides down from the top edge. */
.skip-link{
  position:fixed;top:0;left:50%;transform:translate(-50%,-120%);
  z-index:10002;padding:12px 22px;
  font-family:var(--font-body);font-size:var(--fs-0);font-weight:600;
  color:#fff;background:var(--indigo-fill);
  border:1px solid rgba(255,255,255,0.2);
  border-radius:0 0 var(--r-2) var(--r-2);text-decoration:none;
  transition:transform var(--dur-2) var(--ease-out);
}
.skip-link:focus{transform:translate(-50%,0)}
/* The nav is sticky at 64px; without this the skip target lands under it. */
#main{scroll-margin-top:80px}

/* ══ HERO LIGHT ════════════════════════════════════════════════════════════
   Ported from the homepage (v4.css B3). The page-wide atmosphere provides a
   lamp from directly overhead, which is symmetrical and therefore inert; this
   is the off-axis stroke that makes the opening read as a lit room rather than
   a black rectangle. Without it the inner-page heroes were flat while the
   homepage's was lit — the same site opening two different ways.

   Same hue family as --lamp so it reads as more of the same light, and masked
   so it dissolves through the hero's foot instead of stopping on the section
   boundary. Only the opening section gets it: every section lit equally is the
   same as none of them being lit. */
#hero{position:relative}
#hero::after{
  content:'';position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(60% 22% at 12% 74%,rgba(180,205,232,0.09) 0%,rgba(180,205,232,0) 70%),
    linear-gradient(104deg,
      rgba(255,255,255,0) 34%,
      rgba(214,235,253,0.05) 47%,
      rgba(255,255,255,0) 60%);
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 62%,rgba(0,0,0,0) 100%);
          mask-image:linear-gradient(180deg,#000 0%,#000 62%,rgba(0,0,0,0) 100%);
}
/* The hero's own content has to sit above the light. */
#hero > *{position:relative;z-index:1}

/* ══ NAV · WHERE THE ROW ACTUALLY STOPS FITTING ═════════════════════════
   The nav collapsed to the toggle at 768px, and between 769px and 926px it
   did not fit. Seven items (six links and the Get Started button) sit in a
   flex row with a fixed 28px gap, and nothing held them at their content
   width, so the row kept shrinking its items instead of overflowing and every
   label broke inside itself: "Results" became "Result / s", "Network" became
   "Networ / k", and the 64px bar grew to 88px.

   Measured in a real viewport, not guessed. iPad portrait is 810 and 834 CSS
   px, which put the most common tablet there is squarely inside the band, on
   all 86 pages that load this sheet.

   Two rules, because the two failure modes are different:

     white-space:nowrap   a label is one word or it is nothing.
     max-width:1010px     the row is only shown at widths where it fits whole.

   The number was 940 for seven items. Store made it eight, and the inner row
   now measures 990px: logo 149, links 721, gutters 120. 1010 for a little
   headroom, and the homepage uses the same number even though its shorter row
   survives to 909, because a toggle that appears on /about but not on / at
   the same window size reads as a bug even when each page is fine on its own.
   The homepage's copy of this rule is in assets/rework/styles/v10.css and is
   bundled; change both or they drift.

   Below this the menu behaves exactly as it did at 768: same markup, same
   script (/assets/js/nav.js), reached sooner. */
.nav-links a,.nav-logo{white-space:nowrap}

@media (max-width:1010px){
  .nav-toggle{display:flex}
  .nav-links{
    position:absolute;top:64px;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    padding:8px var(--sp-gutter) 18px;
    background:var(--void);border-bottom:1px solid var(--hairline);
    display:none;
  }
  .nav-links.open,.nav-links.active{display:flex}
  .nav-links a{display:block;padding:13px 0;font-size:1rem}
  .nav-links li:last-child a{justify-content:center;margin-top:10px}
}
