/* ===========================================================================
   PULSE — ONE STYLESHEET FOR EVERY PAGE

   Every Pulse page links this file. Do not fork it per page. The reason the
   site read as inconsistent was three pages each carrying their own copy of
   the tokens, which drift the moment one is edited.

   TYPE — Fraunces (display) / Newsreader (body) / Inter (small labels)
   These are the same three families Callie uses. Typefaces are not anyone's
   property and this is the pairing the owner wants; because the families now
   match, their px sizes are directly portable and are used verbatim rather
   than cap-height converted.

   NO ITALIC FOR EMPHASIS. An earlier version set headline emphasis in true
   italic, which switches mid-sentence and reads as a coding tic rather than a
   typographic decision. `em` is deliberately neutralised below — if a word
   needs emphasis, rewrite the sentence.

   METRICS, measured off b2b.getcallie.care:
     container 1152 · section padding 112 · nav 81
     h1 68/1.05/-.022em/700 · h2 64/1.04/-.02em/500 · h3 30/1.18/-.012em/500
     body 16/1.55 · paragraph 20/31 · eyebrow Inter 12/.22em/500 · radius 4

   COLOUR — light default, dark from the MarketFramework palette. Dark is warm
   (#171614 bg, #E5E3DF text), which is why it sits under a bone-and-clay
   system instead of fighting it. Every pair is measured:
     light: ink 16.6:1 · muted 5.5:1 · clay 4.93:1
     dark:  text 14.1:1 · muted 6.1:1 · accent #E09A78 7.8:1
   Light-mode clay (#A9553B) is only 3.5:1 on dark, so dark swaps the accent.
   Measure any new pair before adding it.
   =========================================================================== */

:root{
  --paper:#FBF9F5; --band:#F3EFE7; --deep:#22352C; --ink:#191A17;
  --close:#22352C;   /* the closing ask keeps the brand forest */
  --foot:#141210;    /* warm near-black: the INK side of the paper, not a third green */
  --muted:#6A655C; --clay:#A9553B; --clay-l:#E09A78;
  --rule:#E4DFD6;      /* hairline dividers only */
  --edge:#8E8577;      /* card boundaries: 3.46:1 on paper, 3.17:1 on surface (WCAG 1.4.11) */
  /* Sketch register: fine ink on cream with one gold accent. Deliberately unlike the flat
     objects — line only, no fills except the accent, so it reads as drawn rather than built. */
  --ink-line:#2C3557; --ink-ground:#F7F3EA; --ink-gold:#C39B45;
  --surface:#F3EFE7;   /* card fill on a paper section */
  --surface-on-band:#FBF9F5; --rule-d:rgba(251,249,245,.15);
  --lede:#4A463E; --btn-fg:#fff; --ghost-bd:#CFC8BB;
  --hdr:rgba(251,249,245,.97); --grain:.055;   /* retained: dark theme dials the noise back */
  --art-bg:#F3EFE7; --art-floor:#E7E0D3; --art-fill:#FBF9F5; --art-fill2:#EBE3D6;
  --art-line:#C9BFAE; --art-ink:#8E8577; --art-accent:#A9553B;

  /* Measured off getcallie.care — their MAIN site, not the b2b one. The two use different
     systems and the b2b page was the wrong reference: it is Fraunces + Fraunces + Inter,
     while the main site is Fraunces for display and NEWSREADER for everything you read,
     including the nav and the wordmark. Serif chrome and ~20px body is most of why theirs
     feels warm where a 14px sans nav feels like an app. */
  --display:"Fraunces",ui-serif,Georgia,serif;
  --text:"Newsreader",ui-serif,Georgia,serif;
  --ui:"Inter",system-ui,-apple-system,sans-serif;   /* small tracked caps ONLY */
  --gut:clamp(18px,3.6vw,48px); --maxw:1200px;
}
:root.dark{
  --paper:#171614; --band:#211F1C; --deep:#23312A; --ink:#E5E3DF;
  --close:#23312A;
  --foot:#100E0C;
  --muted:#9A9590; --clay:#E09A78; --clay-l:#E09A78;
  --rule:#2E2A27;
  --edge:#756B55;   /* dark: 3.44:1 / 3.12:1 */
  --ink-line:#C3CAE4; --ink-ground:#1D1F26; --ink-gold:#D9B466;
  --surface:#211F1C;
  --surface-on-band:#171614; --rule-d:rgba(229,227,223,.16);
  --lede:#BDB8B2; --btn-fg:#171614; --ghost-bd:#3A3632;
  --hdr:rgba(23,22,20,.97); --grain:.030;
  --art-bg:#211F1C; --art-floor:#191715; --art-fill:#2A2724; --art-fill2:#242220;
  --art-line:#4A443E; --art-ink:#8A837B; --art-accent:#E09A78;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;overflow-x:clip}
body,main{overflow-x:clip}
body{margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--text);font-size:20px;line-height:1.62;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
/* Paper is never one flat value; a flat fill reads as an unpainted div.
   Painted onto the body rather than a position:fixed pseudo-element. A fixed layer gets
   captured into the view-transition snapshot and then holds still while the page moves
   beneath it, which tears and flashes. background-attachment does the same job with no
   extra element for the transition to fight over. */
body{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.035'/%3E%3C/svg%3E");background-attachment:fixed;
  background-blend-mode:multiply}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)}
section{padding:112px 0}
/* The opening section sets up the page; it is not a peer of the sections below it. */
main > section:first-of-type{padding:72px 0 64px}
main > section:first-of-type:has(.hero){
  padding:56px 0;
  min-height:calc(100svh - 82px);
  display:flex;align-items:center;
}
main > section:first-of-type:has(.hero) > .wrap{width:100%}
@supports not (height:100svh){
  main > section:first-of-type:has(.hero){min-height:calc(100vh - 82px)}
}
.band{background:var(--band)}
hr.rule{border:0;border-top:1px solid var(--rule);margin:0}

h1,h2,h3{font-family:var(--display);margin:0;font-optical-sizing:auto}
h1{font-size:clamp(32px,3.9vw,50px);font-weight:500;line-height:1.05;letter-spacing:-.025em}
h2{font-size:clamp(26px,2.9vw,37px);font-weight:500;line-height:1.11;letter-spacing:-.02em}
h3{font-size:clamp(20px,2.1vw,28px);font-weight:500;line-height:1.33;letter-spacing:-.02em}
/* Emphasis is NOT italic. If a word must stand out, rewrite the sentence. */
em,i{font-style:normal}
p{margin:0 0 1.05em}
/* A heading and the prose under it were touching wherever the body was not a .lede. */
h2 + p,h2 + div,h1 + p,h3 + p{margin-top:22px}
.lede{font-size:22px;line-height:1.45;color:var(--lede);max-width:58ch;margin-top:24px}
.small{font-size:15px;color:var(--muted);line-height:1.6}
.eyebrow{font-family:var(--ui);font-size:12px;font-weight:500;letter-spacing:.22em;
  line-height:18.6px;text-transform:uppercase;color:var(--clay);margin:0 0 20px}

.btn{display:inline-block;font-family:var(--text);font-size:16px;font-weight:500;
  padding:16px 32px;border-radius:4px;text-decoration:none;border:1px solid transparent;
  cursor:pointer;transition:background .18s ease,border-color .18s ease,color .18s ease}
.btn-primary{background:var(--ink);color:var(--btn-fg)}
.btn-primary:hover{background:var(--clay);color:#fff}
.btn-ghost{border-color:var(--ghost-bd);color:var(--ink);background:transparent}
.btn-ghost:hover{border-color:var(--ink)}
.cta-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:34px;align-items:center}

header{border-bottom:1px solid var(--rule);background:var(--hdr);
  backdrop-filter:saturate(1.15) blur(8px);position:sticky;top:0;z-index:20}
nav{display:flex;align-items:center;justify-content:space-between;height:81px;gap:24px}
.brand{display:flex;align-items:center;gap:11px;text-decoration:none;color:var(--ink)}
.brand-ic{width:26px;height:26px;display:block;flex:none}
.brand-word{font-family:var(--display);font-size:22.5px;font-weight:600;
  letter-spacing:-.025em;line-height:1}
.brand-dot{color:var(--clay)}
.navlinks{display:flex;gap:30px;font-family:var(--text);font-size:18px}
.nav-cta{display:none}
.navlinks a{color:var(--ink);text-decoration:none;opacity:.72}
.navlinks a:hover{opacity:1}
.navend{display:flex;align-items:center;gap:10px}

.theme-t{background:none;border:1px solid var(--ghost-bd);border-radius:4px;cursor:pointer;
  width:44px;height:44px;display:grid;place-items:center;color:var(--ink);padding:0;flex:none;
  transition:border-color .18s ease}
.theme-t:hover{border-color:var(--ink)}
.theme-t svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}


/* ---- ILLUSTRATION PALETTE ----
   Deliberately WIDER than the brand palette. The brand is bone + one clay, which is right for
   type and chrome and is exactly why the page read as austere: with no colour anywhere, a page
   is just ruled boxes. Illustration is where colour lives.

   These stay the SAME in dark mode on purpose. Desaturating art for dark is what makes a themed
   site look switched rather than designed — the drawings keep their colour, only the surface
   under them changes. Every value is picked to sit on both #FBF9F5 and #211F1C. */
:root{
  --i-line:#4A3F35; --i-cream:#F7EEDF; --i-yellow:#E9B44C; --i-yellow-d:#D19A32;
  --i-sage:#9BB08A;  --i-sage-d:#7A9068; --i-teal:#6E9E9B; --i-peach:#F0B48C;
  --i-clay:#C4694A;  --i-rose:#D97A6C;   --i-brown:#9A7355; --i-sky:#A8C4CC;
}
:root.dark{ --i-line:#D8CFC2; --i-cream:#2E2A25; }
.art{background:var(--art-bg)}
.art.ico{width:78px;height:78px;border:0;background:none;margin:0 0 16px}
.art .ln{stroke:var(--i-line);stroke-width:2.4;fill:none;stroke-linecap:round;stroke-linejoin:round}

/* ---- THEME SWAP: circular reveal ----
   Ported from marketframework-frontend (src/app/global.css). The new theme's snapshot is
   clipped to a circle centred on the click and grown past the far corner, so the theme appears
   to wipe out from the button rather than blink.

   The UA's default root cross-fade is neutralised first — leaving it on makes the whole page
   look like it fades out and back in, which is the thing that reads as a cheap toggle.

   Skipped entirely under prefers-reduced-motion and on browsers without startViewTransition;
   both fall back to an instant swap, which is correct, not degraded. */
.theme-t .moon{display:block}
:root.dark .theme-t .sun{display:block}
:root.dark .theme-t .moon{display:none}

/* ---- hero ----
   The reference hero has NO BOX. The image bleeds off the right edge of the viewport and fades
   into the paper on the left through a gradient mask, so there is no seam between picture and
   page. A bordered rectangle sitting inside the content column is a picture in an article —
   which is exactly what made this read as a blog.

   The right column therefore escapes .wrap: it is pulled to the viewport edge with a negative
   margin sized from the gutter, and masked so its own background dissolves into --paper. */
.hero{display:grid;grid-template-columns:1.18fr .82fr;gap:clamp(24px,4vw,56px);
  align-items:center;position:relative}
.hero .art-wrap{min-width:0;position:relative;
  margin-right:calc(-1 * (var(--gut) + max(0px, (100vw - var(--maxw)) / 2)));
}
@media (max-height:740px){.hero-art{max-height:58svh}}
.hero-art{width:100%;height:auto;display:block;border:0;background:none;
  object-fit:contain;object-position:left center;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 22%,#000 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 22%,#000 100%)}
@media(max-width:900px){
  /* Text FIRST on a phone. Art-first pushed the headline and the buttons off the first screen,
     so the thing a visitor landed for was the last thing they saw. */
  .hero{grid-template-columns:1fr;gap:28px}
  .hero .art-wrap{order:2;margin-right:calc(-1 * var(--gut));margin-left:calc(-1 * var(--gut))}
  .hero-art{max-height:38svh}
  body{font-size:18px}
  .lede{font-size:19px;line-height:1.5}
  .btn{width:100%;text-align:center}      /* full-width taps, no 38px targets */
  .cta-row{gap:10px}
  .hero-art{-webkit-mask-image:linear-gradient(to bottom,#000 60%,transparent 100%);
            mask-image:linear-gradient(to bottom,#000 60%,transparent 100%)}
}

/* ---- cards ---- */
.cells{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px}
.cells.two{grid-template-columns:repeat(2,1fr)}
.cell{border:1px solid var(--edge);padding:30px 28px 32px;background:var(--surface)}
.cell h3{margin-bottom:10px}
.cell p{margin:0;font-size:17px;color:var(--muted);line-height:1.6}
.step{font-family:var(--ui);font-size:11px;font-weight:500;letter-spacing:.22em;
  text-transform:uppercase;color:var(--clay);display:block;margin-bottom:16px}

.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:44px}
.stat{border:1px solid var(--edge);padding:32px 28px;background:var(--surface)}
.stat .n{font-family:var(--display);font-size:clamp(40px,4.6vw,60px);font-weight:500;
  line-height:1.02;letter-spacing:-.025em}
.stat p{margin:12px 0 0;font-size:16px;color:var(--muted);line-height:1.55}
.stat .src{font-family:var(--ui);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-top:14px;display:block;opacity:.75}

/* ---- numbered rail (company page signature) ---- */
.rail{display:grid;grid-template-columns:180px 1fr;gap:clamp(24px,5vw,72px);align-items:start}
.rail-n{font-family:var(--ui);font-size:11px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted);position:sticky;top:120px;padding-top:8px;
  border-top:2px solid var(--ink)}
.rail-n b{display:block;font-family:var(--display);font-size:38px;font-weight:500;
  letter-spacing:-.02em;color:var(--ink);margin-bottom:2px}

/* ---- product cards ---- */
.prods{display:grid;grid-template-columns:repeat(2,1fr);gap:20px;margin-top:44px}
.prod{border:1px solid var(--edge);background:var(--surface);padding:30px 28px 30px;display:flex;flex-direction:column;
  background:var(--surface);text-decoration:none;color:inherit;transition:border-color .18s ease}
a.prod:hover{border-color:var(--ink)}
.prod-top{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:16px}
.status{font-family:var(--ui);font-size:9.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;padding:4px 9px;border-radius:999px;white-space:nowrap}
.status.live{background:rgba(34,53,44,.10);color:var(--deep)}
.status.soon{background:rgba(106,101,92,.11);color:var(--muted)}
:root.dark .status.live{background:rgba(159,192,169,.14);color:#9FC0A9}
:root.dark .status.soon{background:rgba(229,227,223,.09)}
.prod h3{margin-bottom:10px}
.prod p{font-size:17px;color:var(--muted);line-height:1.6;margin:0 0 18px}
.prod ul{margin:0 0 20px;padding:0;list-style:none;font-size:15px;color:var(--muted)}
.prod li{padding:7px 0;border-top:1px solid var(--rule)}
.prod .go{margin-top:auto;font-family:var(--ui);font-size:13px;font-weight:500;color:var(--clay)}
.prod.ghost{background:transparent;border-style:dashed}
/* "for everyone" — industries scroll past. NO box, NO border, but it is padded EXACTLY like a
   product card (30px 28px) so its content sits in the same column as the cards' content — the
   fourth cell of a clean 2x2 grid, just without the box. `.prods-next` pulls the row gap down to
   the 20px column gap so the grid reads as even. Single-line focus like the reference: a
   triangular mask, sharp only at the centre, everything else fading hard. */
.prods-next{margin-top:20px}
/* min-width:0 is load-bearing: the feed's white-space:nowrap lines have a huge min-content, and
   without this they force this grid column WIDER than its 1fr share — which shrank the ghost card
   and pushed the feed out of alignment with the card above it. min-width:0 lets the column stay a
   true 1fr and the lines clip (overflow:hidden + ellipsis) instead of blowing it out. */
.vfeed-col{align-self:start;min-width:0;display:flex;flex-direction:column;padding:30px 28px}
.vfeed-eyebrow{font-family:var(--ui);font-weight:600;font-size:12.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted);margin:0 0 12px}
.vfeed-eyebrow b{color:var(--clay);font-weight:600}
.vfeed{position:relative;height:364px;overflow:hidden;
  -webkit-mask-image:linear-gradient(180deg,transparent 6%,#000 50%,transparent 94%);
          mask-image:linear-gradient(180deg,transparent 6%,#000 50%,transparent 94%)}
.vfeed-track{display:flex;flex-direction:column;animation:vfeed 34s linear infinite;will-change:transform}
@keyframes vfeed{from{transform:translateY(0)}to{transform:translateY(-50%)}}
.vfeed-line{display:flex;align-items:center;gap:14px;height:52px;flex:none;white-space:nowrap;
  transition:opacity .3s ease}
.vfeed-line .ic{flex:none;width:22px;height:22px;color:var(--clay);opacity:.85}
.vfeed-line .ic svg{width:22px;height:22px;display:block}
.vfeed-line .tx{font-size:17px;line-height:1.25;overflow:hidden;text-overflow:ellipsis}
.vfeed-line .ind{font-family:var(--display);font-weight:600;color:var(--ink)}
.vfeed-line .say{color:var(--muted)}
.vfeed-focus{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:52px;
  border-radius:10px;background:rgba(169,85,59,.06);pointer-events:none}
:root.dark .vfeed-focus{background:rgba(224,154,120,.08)}
@media (prefers-reduced-motion:reduce){
  .vfeed-track{animation:none}
  .vfeed{-webkit-mask-image:none;mask-image:none;height:auto}
  .vfeed-focus{display:none}
}
.art{display:block;width:100%;height:auto;margin-bottom:22px;border:1px solid var(--rule)}

/* ---- comparison table ---- */
.cmp{width:100%;border-collapse:collapse;margin-top:44px;font-size:16px}
.cmp th,.cmp td{border:1px solid var(--rule);padding:15px 16px;text-align:left}
.cmp thead th{font-family:var(--ui);font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);background:var(--band)}
.cmp thead th.us{color:var(--clay)}
.cmp td.c{text-align:center;font-size:18px}
.cmp .yes{color:var(--deep)} :root.dark .cmp .yes{color:#9FC0A9}
.cmp .no{color:var(--muted);opacity:.5}
.cmp tbody th{font-weight:400;color:var(--ink)}

/* ---- faq ---- */
.faq{margin-top:44px;border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{cursor:pointer;list-style:none;padding:22px 0;font-family:var(--display);
  font-size:23px;font-weight:500;letter-spacing:-.01em;display:flex;justify-content:space-between;
  gap:20px;align-items:center}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";font-family:var(--ui);font-size:20px;color:var(--clay);flex:none}
.faq details[open] summary::after{content:"\2013"}
.faq p{margin:0 0 22px;color:var(--muted);max-width:74ch}

/* ---- inverted sections + footer ----
   NOTE: this is .invert, NOT .dark. The theme class lives on <html class="dark">, so a
   section modifier named .dark would match every descendant of the page in dark mode. */
.invert{background:var(--close,#22352C);color:#DCE3DB}
.invert h2,.invert h3{color:#F7F5EF}
.invert .eyebrow{color:var(--clay-l)}
.invert p,.invert .lede{color:#BAC5B9}
.invert .btn-primary{background:var(--paper);color:var(--ink)}
.invert .btn-primary:hover{background:var(--clay-l);color:#171614}
.invert .btn-ghost{border-color:rgba(251,249,245,.5);color:#DCE3DB}
.invert .rail-n{color:#9DAA9C;border-top-color:#DCE3DB}
.invert .rail-n b{color:#F7F5EF}

/* ---- long-form documents (legal, policies) ---- */
.doc{max-width:74ch}
.doc h2{font-size:clamp(26px,2.9vw,37px);font-weight:500;line-height:1.11;letter-spacing:-.02em}
.doc h3{font-size:clamp(20px,2.1vw,28px);font-weight:500;line-height:1.33;letter-spacing:-.02em}
.doc p,.doc li{color:var(--lede);font-size:17px;line-height:1.65}
.doc ul{padding-left:20px}
.doc li{margin:6px 0}
.doc a{color:var(--clay)}
.updated{font-family:var(--ui);font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-top:8px}

/* ---- contact form ---- */
.cform{margin-top:40px;max-width:64ch}
.cform label{display:block;margin-bottom:20px;font-family:var(--ui);font-size:12px;
  font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.cform input,.cform textarea{display:block;width:100%;margin-top:9px;padding:14px 15px;
  font-family:var(--text);font-size:17px;color:var(--ink);background:var(--paper);
  border:1px solid var(--rule);border-radius:4px;letter-spacing:normal;text-transform:none}
.cform input:focus,.cform textarea:focus{outline:2px solid var(--clay);outline-offset:1px;
  border-color:var(--clay)}
.cform textarea{resize:vertical;line-height:1.55}
.frow{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* ---- form status ----
   The status line lives in the DOM permanently and its TEXT was swapped in place, so each state
   replaced the previous one with no bridge. On a fast connection "Sending..." and "Got it." are
   ~300ms apart and flickered past each other; on failure the bad news arrived with exactly the
   same weight as the good.

   Each state now fades and lifts in. The script removes .show, forces a reflow, then re-adds it,
   which is what makes the transition replay on an element that never leaves the page. Under
   reduced motion the opacity fade stays — it still marks the change — and only the travel goes. */
.fmsg{font-family:var(--ui);font-size:14px;color:var(--muted);
  opacity:0;transform:translateY(4px);
  transition:opacity 200ms cubic-bezier(.22,.61,.36,1),transform 200ms cubic-bezier(.22,.61,.36,1)}
.fmsg.show{opacity:1;transform:none}
.fmsg:empty{opacity:0}
@media(prefers-reduced-motion:reduce){
  .fmsg{transform:none;transition:opacity 120ms linear}
}

/* ---- press feedback ----
   There were no :active states anywhere. Desktop partly hides that behind hover; touch has no
   hover at all, so tapping produced no acknowledgement until the page changed — which is what
   makes people tap a second time. Deliberately small: .985 is felt rather than seen, and these
   are large targets where a bigger scale reads cheap. Cards get a border shift instead of a
   scale, because scaling a 400px card is a different, sillier gesture. */
.btn,.theme-t,.navburger,.foot-cta{transition:background .18s ease,border-color .18s ease,
  color .18s ease,transform 120ms cubic-bezier(.22,.61,.36,1)}
.btn:active,.theme-t:active,.navburger:active,.foot-cta:active{transform:scale(.985)}
a.prod:active,a.post-card:active,a.cell:active{border-color:var(--ink)}
.btn[disabled],.btn:disabled{opacity:.55;cursor:progress;transform:none;
  transition:opacity 140ms cubic-bezier(.22,.61,.36,1)}
@media(prefers-reduced-motion:reduce){
  .btn:active,.theme-t:active,.navburger:active,.foot-cta:active{transform:none;opacity:.8}
}
.fmsg.good{color:var(--deep)} :root.dark .fmsg.good{color:#9FC0A9}
.fmsg.bad{color:var(--clay)}
.fmsg a{color:var(--clay)}
@media(max-width:640px){.frow{grid-template-columns:1fr}}


/* ---- UX corrections ----
   Each of these is invisible until it bites somebody. */

/* An anchor link scrolled its target UNDER the 82px sticky header, so "See the products" landed
   on a heading you could not read. */
:target,[id]{scroll-margin-top:98px}

/* There was no visible focus ring anywhere. Keyboard and switch users had no idea where they
   were on the page. :focus-visible keeps it off for mouse clicks. */
a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible,
label.navburger:focus-visible,.theme-t:focus-visible{
  outline:2.5px solid var(--clay);outline-offset:3px;border-radius:2px}

/* 38px is below every touch-target guideline; 44px is Apple's floor. */
.theme-t,.navburger{width:44px;height:44px}

/* Footer copy was 13.5px, which is small for a legal/company block people actually read. */
footer{font-size:14.5px}
.foot-brand p{font-size:14.5px}

/* Long words (URLs, emails) must not push a phone layout sideways. */
body{overflow-wrap:break-word}

/* Respect the OS setting rather than animating regardless. */
/* Reduced motion asks for LESS movement, not none. A blanket 0.01ms kill also removes the
   hover, focus and open/close feedback that tells someone their action registered — which is
   worse for the people who requested it. So: looping and travelling motion stops outright,
   and short state-change transitions survive at a reduced duration. */
@media(prefers-reduced-motion:reduce){
  /* decorative and looping: off */
  .hero-art .ph-bar,.hero-art .wave,.hero-art .ticket{animation:none !important}
  .rise{opacity:1 !important;transform:none !important;transition:none !important}
  .hero > div:first-child > *,.hero .art-wrap{animation:none !important}
  /* travelling motion: no journey, but the state still changes */
  .navlinks{transition:none !important}
  html{scroll-behavior:auto !important}
  /* feedback: kept, just brisk — this is the part a blanket rule wrongly destroys */
  a,button,input,textarea,.btn,.prod,.theme-t,.navburger{
    transition-duration:80ms !important;animation-duration:80ms !important;
    animation-iteration-count:1 !important}
}


/* ---- narrow-screen corrections ---- */

/* The comparison table is 467px of columns. On a 320px phone it was simply clipped, so the
   "Pulse" column — the entire argument of the table — was off-screen and unreachable. It scrolls
   inside its own box now, with the row labels pinned so a reader can tell what they are comparing. */
.cmp-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:40px}
.cmp{min-width:520px;margin-top:0}
.cmp th:first-child,.cmp td:first-child{position:sticky;left:0;background:var(--paper);z-index:1}
.band .cmp th:first-child,.band .cmp td:first-child{background:var(--band)}

@media(max-width:420px){
  /* The header ran past the viewport at 320: wordmark + toggle + burger + a text button do not
     fit. The CTA is already the first thing in the hero and in the menu, so it goes. */
  .navend .btn{display:none}
}


/* ---- theme swap ----
   The old snapshot is held still while the new one wipes in as a circle from the button. The
   default cross-fade is switched off: with it on, both snapshots fade at once and every element
   with a load-time entrance animation replays underneath, which reads as the page flickering.
   Scoped to .theme-vt so it can only ever affect a theme change, never a page navigation. */
/* While a theme transition is on screen, freeze the page's own motion. The new pseudo-element
   is a live view, so a hero entrance or the ringing phone would otherwise play inside the
   bubble and read as flicker. Paused, not disabled: they resume exactly where they were. */
html.theme-vt *,html.theme-vt *::before,html.theme-vt *::after{
  animation-play-state:paused !important}
@keyframes vt-hold{from,to{opacity:1}}
/* Theme swap — CSS ported from MarketFramework's global.css.

   The new theme's snapshot is clipped to a circle at the cursor: a small bubble while previewing,
   grown to cover the viewport on commit. circle() throughout so it stays a true circle when it
   runs past the viewport corners.

   vt-hold keeps the transition alive; without it the pseudo-elements play once and the browser
   tears the whole thing down mid-hover. The default cross-fade is switched off outright — with it
   on, removing the previewing class while the pseudo-elements still exist makes the entire page
   fade, which reads as the content flashing. */
::view-transition-old(root),
::view-transition-new(root){animation:none}

html.theme-previewing::view-transition-old(root){
  animation:vt-hold 1s linear infinite;z-index:1;mix-blend-mode:normal;pointer-events:none;
  opacity:1;transition:opacity var(--vt-dur,220ms) linear}
html.theme-committing::view-transition-old(root){opacity:0}
html.theme-previewing::view-transition-new(root){
  animation:vt-hold 1s linear;z-index:9999;mix-blend-mode:normal;pointer-events:none;
  clip-path:circle(var(--vt-r,0px) at var(--vt-x,50vw) var(--vt-y,50vh));
  transition:clip-path var(--vt-dur,220ms) var(--vt-ease,cubic-bezier(.65,0,.35,1))}
html.theme-previewing::view-transition,
html.theme-previewing::view-transition-group(root),
html.theme-previewing::view-transition-image-pair(root){pointer-events:none}

/* The live page keeps rendering underneath a held transition, so its own motion would play
   inside the bubble. Frozen for the duration, resumed exactly where it was. */
html.theme-previewing *,html.theme-previewing *::before,html.theme-previewing *::after{
  animation-play-state:paused !important}

/* Icon swap is class-driven, never scripted, so each snapshot captures the right one. */
.theme-t .sun{display:none}.theme-t .moon{display:block}
html.dark .theme-t .sun{display:block}html.dark .theme-t .moon{display:none}

/* Visually hidden but read aloud. The comparison table's yes/no was a bare tick or dash, which
   a screen reader announces as "check mark" / "em dash" — neither of which means yes or no. */
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.cmp .c{position:relative}
.cmp .c.yes::before{content:"\2713";color:var(--deep)}
.cmp .c.no::before{content:"\2014";color:var(--muted);opacity:.7}
:root.dark .cmp .c.yes::before{color:#9FC0A9}

.band .cell,.band .prod,.band .stat{background:var(--surface-on-band)}

/* ---- sketch band ---- */
.sketch{background:var(--ink-ground);border-top:1px solid var(--edge);border-bottom:1px solid var(--edge)}
.sketch .wrap{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(28px,5vw,64px);
  align-items:center}
.sketch svg{width:100%;height:auto;max-width:430px;margin-left:auto;display:block}
.sketch .eyebrow{color:var(--ink-gold)}
.sketch h2,.sketch p{color:var(--ink-line)}
.sketch blockquote{margin:0;font-family:var(--display);font-weight:500;
  font-size:clamp(22px,2.4vw,31px);line-height:1.25;letter-spacing:-.015em;color:var(--ink-line)}
.sketch cite{display:block;margin-top:20px;font-family:var(--ui);font-size:12px;
  letter-spacing:.16em;text-transform:uppercase;font-style:normal;opacity:.72}
@media(max-width:900px){.sketch .wrap{grid-template-columns:1fr}
  .sketch svg{margin:0 auto;max-width:300px;order:-1}}

/* ---- big footer ---- */
.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);
  padding:12px 18px;z-index:100;font-family:var(--ui);font-size:14px}
.skip:focus{left:8px;top:8px}
.foot-grid{display:grid;grid-template-columns:1.6fr repeat(3,1fr);gap:40px;
  padding-bottom:36px}
.foot-brand .foot-mark{display:flex;align-items:center;gap:11px;color:#DCE3DB;font-size:15px}
.foot-brand p{margin:16px 0 0;max-width:34ch;line-height:1.6;color:#93A192}
.foot-grid h4{font-family:var(--ui);font-size:11px;font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:#DCE3DB;margin:0 0 16px}
.foot-grid ul{list-style:none;margin:0;padding:0}
.foot-grid li{margin:0 0 11px}
.foot-base{display:flex;justify-content:flex-end;gap:20px;flex-wrap:wrap;
  border-top:1px solid var(--rule-d);padding-top:24px;font-size:12.5px}
@media(max-width:900px){.foot-grid{grid-template-columns:1fr 1fr;gap:32px}}
@media(max-width:560px){.foot-grid{grid-template-columns:1fr}}

footer{background:var(--foot,#141210);color:#8E877C;font-family:var(--ui);font-size:13.5px;
  padding:0 0 34px;position:relative;overflow:hidden}
footer a{color:#C4BEB4;text-decoration:none}
footer a:hover{color:#F7F5EF}

/* ---- long-form posts ---- */
.post h2{font-size:clamp(24px,2.6vw,32px);margin:44px 0 14px}
.post h3{font-size:21px;margin:30px 0 8px}
.post p,.post li{color:var(--lede);font-size:18px;line-height:1.7}
.post ul,.post ol{padding-left:20px}
.post li{margin:8px 0}
.post blockquote{margin:28px 0;padding:2px 0 2px 22px;border-left:2px solid var(--clay);
  font-family:var(--display);font-size:22px;line-height:1.4;color:var(--ink)}
.post a{color:var(--clay)}
.post-card{display:flex;flex-direction:column;text-decoration:none;color:inherit}
.post-card h3{margin:6px 0 10px}
.post-card .go{margin-top:auto;padding-top:16px;font-family:var(--ui);font-size:13px;
  font-weight:500;color:var(--clay)}

/* ---- the last offer ----
   A footer is where someone lands after reading everything, so it makes an offer rather than
   listing links. It must be VERTICAL-NEUTRAL: the demo line is a restaurant agent on a restaurant
   menu, so it belongs on /restaurants/ and nowhere else. Sending a senior-living operator to it
   from a site-wide footer is worse than having no number at all. */
.foot-call{display:grid;grid-template-columns:1fr auto;gap:28px;align-items:end;
  padding:64px 0 44px;border-bottom:1px solid rgba(247,245,239,.10)}
.foot-kicker{font-family:var(--ui);font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:#8E877C;margin:0 0 14px}
.foot-line{font-family:var(--display);font-weight:500;font-size:clamp(26px,3.4vw,40px);
  line-height:1.18;letter-spacing:-.02em;color:#F7F5EF;margin:0;max-width:22ch}
.foot-cta{font-family:var(--ui);font-size:14px;color:#C4BEB4;white-space:nowrap;
  border:1px solid rgba(247,245,239,.22);border-radius:4px;padding:14px 20px;
  transition:border-color .18s ease}
.foot-cta:hover{border-color:#F7F5EF}

.foot-grid{display:grid;grid-template-columns:1.6fr repeat(3,1fr);gap:40px;padding:48px 0 40px}
.foot-brand p{margin:14px 0 0;font-family:var(--text);font-size:15px;color:#8E877C;max-width:34ch}
.foot-mark{display:flex;align-items:center;gap:10px;font-family:var(--display);font-size:19px;
  color:#F7F5EF}
footer h4{font-family:var(--ui);font-size:11px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:#6E675D;margin:0 0 16px}
footer ul{list-style:none;margin:0;padding:0}
footer li{margin:0 0 11px}

/* The wordmark is a GRAPHIC, not a heading — aria-hidden, and sized to bleed. At 1.1:1 it reads
   as texture in passing and as a signature if you actually look at it. */
.foot-sign{font-family:var(--display);font-weight:500;color:#221E1A;
  font-size:clamp(90px,19vw,260px);line-height:.78;letter-spacing:-.045em;
  margin:0 0 -.14em;user-select:none;pointer-events:none}
.foot-sign span{color:var(--clay)}

.foot-base{display:flex;justify-content:flex-end;gap:20px;flex-wrap:wrap;
  border-top:1px solid rgba(247,245,239,.10);padding-top:22px;font-size:12.5px;color:#6E675D}

@media(max-width:760px){
  .foot-call{grid-template-columns:1fr;align-items:start;gap:22px;padding:48px 0 34px}
  .foot-cta{justify-self:start}
  .foot-grid{grid-template-columns:1fr 1fr;gap:32px;padding:38px 0 30px}
  .foot-brand{grid-column:1/-1}
}

/* ---- entrance ---- */
.rise{opacity:0;transform:translateY(14px);
  transition:opacity .7s cubic-bezier(.22,.61,.36,1),transform .7s cubic-bezier(.22,.61,.36,1)}
.rise.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.rise{opacity:1;transform:none;transition:none}}

/* ---- mobile nav ----
   .navlinks was simply hidden below 900px with nothing replacing it, so every page except the
   one you landed on was unreachable on a phone. A checkbox-driven panel needs no JS, so it works
   even if the theme script fails. */
.navtoggle{display:none}
.navburger{display:none;background:none;border:1px solid var(--ghost-bd);border-radius:4px;
  width:44px;height:44px;cursor:pointer;padding:0;place-items:center;color:var(--ink)}
.navburger span,.navburger span::before,.navburger span::after{
  content:"";display:block;width:16px;height:1.5px;background:currentColor;position:relative}
.navburger span::before{top:-5px}.navburger span::after{top:3.5px}

@media(max-width:900px){
  section{padding:72px 0}
  .navburger{display:grid}
  .navlinks{display:none;position:fixed;inset:82px 0 auto 0;background:var(--paper);
    border-bottom:1px solid var(--rule);padding:8px var(--gut) 22px;
    z-index:19;max-height:calc(100svh - 82px);overflow-y:auto}
  .navtoggle:checked ~ .navlinks{display:block;
    animation:nav-in .24s cubic-bezier(.22,.61,.36,1)}
  @keyframes nav-in{from{opacity:0;transform:translateY(-10px)}}
  .navlinks a{display:block;padding:15px 0;font-size:20px;opacity:1;
    border-bottom:1px solid var(--rule)}
  .navlinks a.nav-cta{display:block;margin-top:18px;border-bottom:0;text-align:center;
    background:var(--ink);color:var(--btn-fg);border-radius:4px;padding:16px;
    font-family:var(--text);font-weight:500;font-size:17px}
  @media(prefers-reduced-motion:reduce){.navtoggle:checked ~ .navlinks{animation:none}}
  .cells,.cells.two,.prods,.stats{grid-template-columns:1fr}
  .rail{grid-template-columns:1fr;gap:22px}
  .rail-n{position:static;display:flex;align-items:baseline;gap:12px}
  .rail-n b{margin:0}
  .cmp{display:block;overflow-x:auto}
}

/* ---- hero: the phone actually rings ----
   The illustration already draws a ringing phone with sound waves. Here the handset
   gives a short vibration and the waves radiate outward, then rest before the next
   ring (~1.9s cadence). Transform + opacity only, so it runs off the main thread.

   Entrance curve is the site's house ease-out (.22,.61,.36,1), the same one .rise and
   the nav use — not a second easing system.

   Reduced motion is handled by the global reset above (animation-iteration-count:1,
   duration:.01ms). With fill-mode:none the waves revert to their authored, static,
   fully-visible state, so the illustration is never left mid-ring. */
.hero-art{--ring:1.9s}
@keyframes ph-ring{
  0%,58%,100%{transform:rotate(0)}
  3%{transform:rotate(-1.5deg)}   7%{transform:rotate(1.5deg)}
  11%{transform:rotate(-1.1deg)} 15%{transform:rotate(.8deg)} 19%{transform:rotate(0)}
}
.hero-art .ph-bar{transform-box:fill-box;transform-origin:center;
  animation:ph-ring var(--ring) ease-in-out infinite}
@keyframes wave{
  0%{opacity:0;transform:translateX(0)}
  10%{opacity:var(--peak,.9)}
  58%{opacity:0;transform:translateX(var(--dx,0))}
  100%{opacity:0}
}
.hero-art .wave{transform-box:fill-box;
  animation:wave var(--ring) cubic-bezier(.22,.61,.36,1) infinite}
.hero-art .w-r1{transform-origin:left center; --dx:6px;  --peak:.9}
.hero-art .w-r2{transform-origin:left center; --dx:11px; --peak:.55; animation-delay:.22s}
.hero-art .w-l1{transform-origin:right center;--dx:-6px; --peak:.9}
.hero-art .w-l2{transform-origin:right center;--dx:-11px;--peak:.55; animation-delay:.22s}

/* The freshly-printed ticket eases down once on arrival — the restaurant equivalent of the
   phone ringing: it shows the thing the product actually does rather than decorating. Once,
   not looping, because a ticket that keeps re-printing reads as a bug. */
@keyframes ticket-drop{from{transform:translateY(-14px);opacity:0}to{transform:none;opacity:1}}
.hero-art .ticket{transform-box:fill-box;transform-origin:top center;
  animation:ticket-drop .75s .35s cubic-bezier(.22,.61,.36,1) both}

/* hero copy settles in on load — the other half of "less static" */
@keyframes hero-rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
/* The H1 moves but is NEVER hidden. It is the Largest Contentful Paint element, and an element
   at opacity 0 does not count as painted — fading it in pushes LCP out by the delay plus the
   duration, on the one page we most want ranking. It also means a stalled animation leaves the
   headline invisible rather than merely unanimated, which is the worse failure. So: transform
   only here, opacity fade for everything that is not the LCP candidate. */
@keyframes hero-shift{from{transform:translateY(10px)}to{transform:none}}
.hero > div:first-child > .eyebrow{animation:hero-rise .6s      cubic-bezier(.22,.61,.36,1) both}
.hero > div:first-child > h1     {animation:hero-shift .6s      cubic-bezier(.22,.61,.36,1) both}
.hero > div:first-child > .lede  {animation:hero-rise .6s .12s  cubic-bezier(.22,.61,.36,1) both}
.hero > div:first-child > .cta-row{animation:hero-rise .6s .18s cubic-bezier(.22,.61,.36,1) both}
.hero .art-wrap                  {animation:hero-rise .7s .1s   cubic-bezier(.22,.61,.36,1) both}
