/* Kavarn, operated by Konvergence Inc.
   Self-contained. No external fonts, no CDN, no third-party calls.
   Display type is Bricolage Grotesque. Body and secondary text are DM Sans.
   Both ship from /fonts/. */

@font-face{
  font-family:"Bricolage Grotesque";
  src:url("/fonts/BricolageGrotesque-Variable.ttf") format("truetype");
  font-weight:200 800;
  font-stretch:75% 100%;
  font-style:normal;
  font-display:swap;
}

@font-face{
  font-family:"DM Sans";
  src:url("/fonts/DMSans-Variable.ttf") format("truetype");
  font-weight:100 1000;
  font-style:normal;
  font-display:swap;
}

@font-face{
  font-family:"DM Sans";
  src:url("/fonts/DMSans-Italic-Variable.ttf") format("truetype");
  font-weight:100 1000;
  font-style:italic;
  font-display:swap;
}

:root{
  --ink:#0d1117;
  --ink-2:#131b2b;
  --ink-3:#1a2338;
  --line:#243049;
  --paper:#f4f2ec;
  --paper-2:#e8e4d9;
  --paper-line:#cdc7b8;
  --violet:#673AE4;
  --violet-dim:#5429C8;
  --cyan:#06b6d4;
  --text:#f0f6fc;
  --muted:#8b98ad;
  --muted-2:#6b7889;
  --ink-text:#1d2433;
  --ink-muted:#5c6474;
  --ok:#10b981;
  --pend:#d99b3a;

  --sans:"DM Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --display:"Bricolage Grotesque",var(--sans);
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;

  --measure:64ch;
  --gut:clamp(1.25rem,4vw,3rem);
  --maxw:1140px;
  --root-size:16px;
  --text-size:17px;
  --h1-max:50px;
  --h2-max:32px;
  --h3-size:18px;
  --hero-h1-max:36px;
  --btn-size:.95rem;
  --btn-pad-y:.72rem;
  --btn-pad-x:1.25rem;
  --btn-min:44px;
  --glyph-size:44px;
  --nav-size:.93rem;
  --nav-gap:1.55rem;
  --mast-min:66px;
}

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

html{font-size:var(--root-size);-webkit-text-size-adjust:100%}

body{
  margin:0;
  background:var(--ink);
  color:var(--text);
  font-family:var(--sans);
  font-optical-sizing:auto;
  font-size:var(--text-size);
  line-height:1.6;
  font-feature-settings:"kern","liga","cv05";
  -webkit-font-smoothing:antialiased;
}

h1,h2,h3,h4,h5,h6{font-family:var(--display);font-optical-sizing:auto}
h1,h2,h3,h4{margin:0;font-weight:640;letter-spacing:-0.012em;line-height:1.12}
h1{font-size:clamp(2.15rem,5.2vw,var(--h1-max));letter-spacing:-0.022em}
h2{font-size:clamp(1.6rem,3.2vw,var(--h2-max));letter-spacing:-0.016em}
h3{font-size:var(--h3-size);letter-spacing:-0.004em;line-height:1.3}
p{margin:0 0 1.05em;max-width:var(--measure)}
a{color:inherit}
ul{margin:0;padding:0;list-style:none}
strong{font-weight:640}

.wrap{max-width:var(--maxw);margin:0 auto;padding-inline:var(--gut)}
/* Desktop column is 73vw from 1280 up, matching the 1680 proportion.
   Type scales with that viewport so 1280 and 1440 read like a smaller 1680. */
@media (min-width:1280px){
  :root{
    --maxw:73vw;
    --root-size:15px;
    --text-size:15px;
    --h1-max:42px;
    --h2-max:26px;
    --h3-size:15px;
    --hero-h1-max:28px;
    --glyph-size:36px;
    --nav-size:.82rem;
    --nav-gap:1.15rem;
    --mast-min:60px;
  }
  nav.primary a{white-space:nowrap}
}
@media (min-width:1440px){
  :root{
    --maxw:73vw;
    --root-size:16px;
    --text-size:16px;
    --h1-max:48px;
    --h2-max:32px;
    --h3-size:16px;
    --hero-h1-max:34px;
    --glyph-size:44px;
    --nav-size:.93rem;
    --nav-gap:1.55rem;
    --mast-min:66px;
  }
}
@media (min-width:1680px){
  :root{
    --maxw:73vw;
    --root-size:18px;
    --text-size:18px;
    --h1-max:56px;
    --h2-max:36px;
    --h3-size:18px;
    --hero-h1-max:40px;
    --btn-size:1.02rem;
    --btn-pad-y:.84rem;
    --btn-pad-x:1.48rem;
    --btn-min:48px;
  }
}
.lede{font-size:clamp(1.06rem,1.9vw,1.25rem);color:var(--muted);line-height:1.55}

/* ---------- Bates endorsement: the one signature device ---------- */
.bates{
  font-family:var(--mono);
  font-size:.68rem;
  letter-spacing:.1em;
  color:var(--muted-2);
  display:block;
  margin-bottom:2.1rem;
  padding-bottom:.5rem;
  border-bottom:1px solid var(--line);
}
.paper .bates{color:#8d8674;border-bottom-color:var(--paper-line)}

/* ---------- header ---------- */
.masthead{
  position:sticky;top:0;z-index:60;
  background:rgba(13,17,23,.86);
  backdrop-filter:saturate(150%) blur(14px);
  border-bottom:1px solid var(--line);
}
.masthead .wrap{display:flex;align-items:center;gap:1.5rem;min-height:var(--mast-min)}
.brand{display:flex;align-items:center;gap:.62rem;text-decoration:none;font-family:var(--display);font-optical-sizing:auto;font-weight:660;letter-spacing:-.02em;margin-right:auto}
/* The brand mark. Until 21 October 2026 this was a CSS gradient square with a letter K
   drawn in it; it is now the real icon, public/kavarn-icon-512.png, at 44px in the
   header and the footer.
   DECORATIVE, and marked so: alt="" plus aria-hidden="true", which is what the old span
   carried. The word "Kavarn" is live text inside the same link, so a described image made
   a screen reader read the brand twice. Chris's call, 22 October 2026. */
.brand .glyph{
  width:var(--glyph-size);height:var(--glyph-size);flex:none;display:block
}
/* Mobile pages with the hero dark wordmark: hide the masthead glyph while that
   image is still on screen, then reveal it once the wordmark has scrolled under
   the sticky bar. body.mast-glyph-on is toggled from Nav.astro. */
@media (max-width:960px){
  body:has(.home2-logo-m) .masthead .brand{
    gap:0;
    transition:gap .32s cubic-bezier(.22,.61,.36,1);
  }
  body:has(.home2-logo-m) .masthead .brand .glyph{
    width:0;max-width:0;height:0;margin:0;opacity:0;
    transform:scale(.65);
    overflow:hidden;
    transition:
      opacity .28s ease,
      transform .32s cubic-bezier(.22,.61,.36,1),
      width .32s cubic-bezier(.22,.61,.36,1),
      max-width .32s cubic-bezier(.22,.61,.36,1),
      height .32s cubic-bezier(.22,.61,.36,1);
  }
  body:has(.home2-logo-m).mast-glyph-on .masthead .brand{gap:.62rem}
  body:has(.home2-logo-m).mast-glyph-on .masthead .brand .glyph{
    width:var(--glyph-size);max-width:var(--glyph-size);height:var(--glyph-size);
    opacity:1;transform:scale(1);
  }
}
@media (max-width:960px) and (prefers-reduced-motion:reduce){
  body:has(.home2-logo-m) .masthead .brand,
  body:has(.home2-logo-m) .masthead .brand .glyph{transition:none}
}
.brand small{display:block;font-family:var(--sans);font-size:.7rem;font-weight:500;color:var(--muted-2);letter-spacing:0}
nav.primary{display:flex;gap:var(--nav-gap);align-items:center}
nav.primary a{color:var(--muted);text-decoration:none;font-size:var(--nav-size);padding:.3rem 0;border-bottom:1px solid transparent}
nav.primary a:hover,nav.primary a[aria-current]{color:var(--text);border-bottom-color:var(--violet)}
.navtoggle{display:none;background:none;border:1px solid var(--line);color:var(--text);border-radius:8px;padding:.42rem .6rem;font:inherit;font-size:.85rem;cursor:pointer}

/* ---------- buttons ---------- */
.btn{
  display:inline-block;text-decoration:none;font-size:var(--btn-size);font-weight:600;
  padding:var(--btn-pad-y) var(--btn-pad-x);border-radius:9px;border:1px solid transparent;cursor:pointer;
  font-family:inherit;line-height:1.2;min-height:var(--btn-min)
}
.btn-primary{background:var(--violet);color:#fff}
.btn-primary:hover{background:var(--violet-dim)}
.btn-ghost{border-color:var(--line);color:var(--text)}
.btn-ghost:hover{border-color:var(--violet);color:#fff}
.paper .btn-ghost{border-color:var(--paper-line);color:var(--ink-text)}
.paper .btn-ghost:hover{border-color:var(--violet)}
.btnrow{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:1.6rem}

/* ---------- sections ---------- */
section{padding-block:clamp(3.4rem,7vw,5.6rem)}
.paper{background:var(--paper);color:var(--ink-text)}
.paper h1,.paper h2,.paper h3{color:#12161f}
.paper .lede{color:var(--ink-muted)}
.rule{border:0;border-top:1px solid var(--line);margin:0}

/* ---------- hero ---------- */
.hero{padding-top:clamp(3.2rem,7vw,5.4rem);padding-bottom:clamp(3rem,6vw,4.6rem)}
.hero-grid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);gap:clamp(2rem,5vw,4rem);align-items:start}
.hero h1{margin-bottom:1.1rem}

/* ---- Homepage hero, rebuilt 10 October 2026 to sell on the first phone screen. -------
   The h1 is three block spans in one element, so the page keeps one main heading and the
   three phrases still stack. Type values are the h1's own; only the color differs on the
   middle line. */
/* ITS OWN SIZE, AND MEASURED OFF THE COLUMN RATHER THAN THE VIEWPORT. The three phrases
   have to sit one per line at every width, and the longest of them was "AI search assistance
   included." at 12.98em wide in this face at this weight. That line was replaced on
   21 October 2026 by the shorter "Add AI when you need it"; the measurement below is kept
   at the old, longer value deliberately, because it is a ceiling and a shorter headline
   simply clears it with room to spare. So the largest type that fits
   is the column width divided by 12.98, which is 7.7cqi; 7.2cqi is that with margin for a
   fallback face. A vw term cannot do this job: between 681px and about 1100px the hero is
   two columns and the copy column shrinks while the viewport grows, so any vw value large
   enough to look right at 1280 wraps the third line in the middle of that range.
   The floor and ceiling are both real limits rather than taste. 1.42rem is the smallest
   the headline should ever be; 2.45rem is the size at which three lines take 142px, which
   is the most of a 800px viewport the headline can have and still leave the plan cards and
   the button above the fold. */
/* NAMED. .hero-copy and .plancards are both containers, and an unnamed @container query
   binds to the nearest container ancestor rather than the one it was written for. That
   is not a hypothetical: the plan-card query below was written against the card row and
   silently matched the copy column instead, which stacked both cards on a 390px phone
   and cost 80px of the one screen the rebuild exists to fit. Names remove the class. */
.hero-copy{container-type:inline-size;container-name:herocopy}
.hero-h1{font-size:clamp(1.42rem,7.2cqi,var(--hero-h1-max));line-height:1.14;margin-bottom:.8rem}
.hero-h1 .hh{display:block}
.hero-h1 .hh-accent{color:var(--violet)}

/* A div, not a paragraph: the answer-first rule must keep measuring the identity
   sentence below the CTAs. See the comment in index.astro. */
.hero-sub{
  font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.5;color:var(--muted);
  max-width:46ch;margin-bottom:1.25rem;
}
.hero-sub strong{color:var(--text);font-weight:560}

/* Two plan cards: stacked on a phone, side by side from 681px. The agreement card is the
   one being recommended, so it carries the accent border and a tint; the other is plain.
   Nothing here is a price: both figures interpolate from pricing.json. */
.plancards{display:grid;grid-template-columns:1fr;gap:.6rem;margin-bottom:1.15rem}
.plancard{
  display:grid;grid-template-columns:1fr auto;align-items:center;gap:.2rem .8rem;
  border:1px solid var(--line);border-radius:10px;padding:.7rem .9rem;background:var(--ink-2);
}
a.plancard{text-decoration:none;color:inherit;cursor:pointer}
a.plancard:hover{border-color:var(--muted)}

.plancard-pick{border-color:var(--violet);background:color-mix(in srgb,var(--violet) 9%,var(--ink-2))}
a.plancard-pick:hover{border-color:var(--violet)}
.pc-name{font-family:var(--display);font-optical-sizing:auto;font-size:.95rem;font-weight:600;color:var(--text)}
.pc-note{grid-column:1;font-size:.8rem;color:var(--muted)}
.plancard-pick .pc-note{color:var(--violet)}
.pc-fig{grid-column:2;grid-row:1 / span 2;font-size:1.32rem;font-weight:650;color:var(--text);white-space:nowrap}
.pc-per{font-size:.82rem;font-weight:450;color:var(--muted)}

/* The AI Suite add-on, 21 October 2026. One rule below the two plan cards and visibly
   lighter than them: no tint, no accent border, smaller type. The hierarchy is the point.
   A firm picks one of the two cards; this is a thing added to whichever it picked, and
   giving it a third card of equal weight would read as a third plan. */
.aiaddon{
  display:grid;gap:.15rem;
  border:1px solid var(--line);border-radius:10px;
  padding:.7rem .9rem;margin:-.3rem 0 1.15rem;
  background:transparent;
}
a.aiaddon{text-decoration:none;color:inherit;cursor:pointer}
a.aiaddon:hover{border-color:var(--muted)}
#ai-suite{scroll-margin-top:5.5rem}
.aia-name{font-size:.9rem;font-weight:600;color:var(--text)}
.aia-price{font-size:.9rem;color:var(--violet)}
.aia-note{font-size:.8rem;line-height:1.4;color:var(--muted)}
@media (min-width:681px){
  .aiaddon{padding:.75rem 1rem}
}

/* One primary button, then a text link. Not two buttons: the second choice should read as
   secondary, and on a phone two full-width buttons push the chart off the screen. */
.hero-ctas{display:flex;flex-direction:column;align-items:flex-start;gap:.7rem;margin-bottom:1.1rem}
/* The CTA block is the last thing in the copy column now that the identity sentence and
   the testimonial are grid children, so its bottom margin would stack on top of the
   grid's row gap and push the card 32px below the price-sheet link instead of 16. */
.hero-copy > .hero-ctas:last-child{margin-bottom:0}
.hero-ctas .btn-primary{width:100%;text-align:center}
.hero-link{color:var(--cyan);font-size:.95rem;text-decoration:underline;text-underline-offset:3px}

@media (min-width:681px){
  .plancards{grid-template-columns:1fr 1fr;gap:.8rem}
  /* The figure sits beside the name while there is room for both, and under it when there
     is not. Which of those applies does not follow the viewport: the hero copy column is
     627px wide at a 681px viewport and 526px at 1280px, because the layout goes to two
     columns in between, so the card is WIDER on the narrower screen. A media query sees
     exactly the wrong thing here. The container query measures the row the cards sit in:
     below 562px of row the two cards are under 275px each, which is not enough for
     "12-month agreement" and "$3,250 / mo" on one line, and the figure drops below.
     The container is the row rather than the card because an element cannot be restyled
     by a query on itself. */
  .plancards{container-type:inline-size;container-name:plancards}
  .hero-ctas{flex-direction:row;align-items:center;gap:1.1rem}
  .hero-ctas .btn-primary{width:auto}
}
@container plancards (max-width:562px){
  .plancard{grid-template-columns:1fr;gap:.1rem}
  .pc-fig{grid-column:1;grid-row:auto;margin-top:.35rem}
}
@media (max-width:680px){
  /* The Bates endorsement is the site's motif, not information. On a phone it costs
     ~50px of the one screen that has to sell, so it goes; it stays on desktop. */
  .hero-split .hero-copy > .bates{display:none}
  /* Every remaining gap on the first screen, tightened. The target is the h1, the sub,
     both cards and the primary button above the fold at 390x844 WITH the consent banner
     up, which leaves about 720px once the banner takes its share. */
  .hero-split{padding-top:1.5rem;padding-bottom:1.6rem}
  .hero-sub{margin-bottom:1rem;font-size:.95rem;line-height:1.45}
  .plancards{margin-bottom:.95rem}
  .hero-ctas{margin-bottom:1rem}
  .hero-pitch{font-size:.92rem;line-height:1.5}
}

.hero .lede{margin-bottom:0}

/* The .specimen illustration was removed on 5 October 2026. It drew a produced page with
   redaction blocks and a Bates endorsement, and redaction is not surfaced in the UI yet,
   so it implied a feature the real screenshot correctly does not show. The hero now
   carries that screenshot. Nothing else used the class; see CONTEXT 7f. */

/* The stat/claim strip was removed on 5 October 2026. It sat between the hero and the fees
   comparison saying in three facts what the section below it says in five, with figures.
   On a phone it filled a whole screen to do that. Nothing else used the class. */

/* ---------- generic column grids ---------- */
.cols{display:grid;gap:clamp(1.5rem,3vw,2.4rem)}
.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}
.block h3{margin-bottom:.5rem}
.block p{color:var(--muted);font-size:.96rem;margin:0}
.paper .block p{color:var(--ink-muted)}

/* section heading pair */
.shead{max-width:60ch;margin-bottom:clamp(2rem,4vw,2.9rem)}
.shead h2{margin-bottom:.7rem}
.shead p{margin:0}

/* ---------- workflow sequence (genuinely sequential) ---------- */
.flow{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;margin-bottom:2.6rem;font-family:var(--mono);font-size:.76rem;letter-spacing:.06em;color:var(--muted)}
.flow span{border:1px solid var(--line);border-radius:5px;padding:.34rem .62rem}
.flow span[data-on]{border-color:var(--violet);color:var(--text)}
.flow i{color:var(--muted-2);font-style:normal}
/* On a phone the chips wrap, and a wrapped separator starts a line: "› Analyze". The
   separators carry no information the order does not already carry, so below 680 they are
   hidden and the chips read as a plain row of tags. `display:none` rather than visibility,
   so they take no space in the flex gap either. Desktop is unchanged. */
@media (max-width:680px){
  .flow i{display:none}
  .flow{gap:.4rem;margin-bottom:2rem}
}

/* ---------- capability lists w/ status ---------- */
.caps{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.caps .grp{background:var(--ink-2);padding:1.35rem 1.4rem}
.caps h3{margin-bottom:.9rem;font-size:1.02rem}
.caps li{display:flex;gap:.6rem;align-items:baseline;font-size:.94rem;color:var(--muted);padding:.26rem 0}
.caps li::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--cyan);flex:none;transform:translateY(-2px)}
.caps li[data-status="pending"]{color:var(--muted-2)}
.caps li[data-status="pending"]::before{background:var(--pend)}
.tag{
  font-family:var(--mono);font-size:.6rem;letter-spacing:.08em;
  border:1px solid currentColor;border-radius:3px;padding:0 .3rem;color:var(--pend);
  white-space:nowrap;margin-left:.15rem
}
.legend{display:flex;gap:1.4rem;flex-wrap:wrap;margin-top:1.3rem;font-size:.85rem;color:var(--muted-2)}
.legend span{display:flex;align-items:center;gap:.45rem}
.legend i{width:6px;height:6px;border-radius:50%;display:inline-block}

/* ---------- pricing ---------- */
.price-lead{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);gap:clamp(2rem,5vw,3.5rem);align-items:start}
.pricetag{font-size:clamp(3rem,7vw,4.4rem);font-weight:660;letter-spacing:-.04em;line-height:1;margin:0}
.pricetag sub{font-size:1rem;font-weight:500;letter-spacing:-.01em;color:var(--ink-muted);vertical-align:baseline;margin-left:.4rem}
.pricenote{font-size:.95rem;color:var(--ink-muted);margin-top:.7rem}

table{width:100%;border-collapse:collapse;font-size:.94rem}
caption{text-align:left;font-weight:640;font-size:1.02rem;margin-bottom:.8rem;letter-spacing:-.012em}
th,td{text-align:left;padding:.72rem .8rem;border-bottom:1px solid var(--paper-line);vertical-align:top}
thead th{font-size:.76rem;letter-spacing:.06em;font-family:var(--mono);color:#7d7767;font-weight:500;border-bottom-width:1px}
td.num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.dark-table th,.dark-table td{border-bottom-color:var(--line)}
.dark-table thead th{color:var(--muted-2)}
.tablewrap{overflow-x:auto;margin-bottom:2.6rem}
.fine{font-size:.85rem;color:var(--ink-muted);max-width:72ch}
.stamp{padding-top:8px}
.paper .fine{color:#6d6656}

/* ---------- callout ---------- */
.note{
  border-left:2px solid var(--violet);
  padding:.15rem 0 .15rem 1.15rem;
  color:var(--muted);font-size:.96rem;max-width:66ch
}
.note.note-contact{margin-top:20px;margin-bottom:-10px}
@media (max-width:960px){
  .note.note-contact{margin-top:40px}
}
.paper .note{color:var(--ink-muted)}

/* ---------- CTA band ---------- */
.cta{background:var(--ink-2);border-block:1px solid var(--line)}
.cta .wrap{display:flex;gap:2rem;flex-wrap:wrap;align-items:center;justify-content:space-between}
.cta h2{margin-bottom:.5rem}
.cta p{color:var(--muted);margin:0}

/* ---------- form ---------- */
form{max-width:520px}
form .field{margin-bottom:1.15rem}
label{display:block;font-size:.9rem;font-weight:560;margin-bottom:.38rem}
/* min-height is the 44px tap-target floor, on the shared control rule rather than on one
   id: a <select> renders with line-height:normal where the inputs inherit 1.6, so the same
   padding left it at 42.8px at 390 while every input was 48.4px. */
input:not([type=range]),select,textarea{
  width:100%;font:inherit;font-size:var(--btn-size);color:var(--text);
  background:var(--ink-2);border:1px solid var(--line);border-radius:8px;padding:.65rem .75rem;
  min-height:var(--btn-min)
}
input:not([type=range]):focus,select:focus,textarea:focus{outline:2px solid var(--violet);outline-offset:1px;border-color:transparent}
textarea{min-height:120px;resize:vertical}
.hint{font-size:.83rem;color:var(--muted-2);margin:.35rem 0 0}

/* ---------- footer ---------- */
footer{background:var(--ink);border-top:1px solid var(--line);padding-block:2.8rem;font-size:.9rem;color:var(--muted-2)}
footer .fgrid{display:grid;grid-template-columns:1.6fr minmax(0,3fr);gap:2rem;margin-bottom:2.2rem}
footer .fnavs{display:grid;grid-template-columns:repeat(3,max-content);justify-content:space-between;gap:2rem;padding-left:40px}
footer h2{font-size:.76rem;font-family:var(--mono);letter-spacing:.09em;color:var(--muted-2);font-weight:500;margin-bottom:.75rem}
footer a{color:var(--muted);text-decoration:none;display:block;padding:.2rem 0}
footer a:hover{color:var(--text)}
footer .base{border-top:1px solid var(--line);padding-top:1.4rem;display:flex;gap:1.2rem;flex-wrap:wrap;justify-content:space-between}
footer p{margin:0;max-width:52ch}
footer .fop{display:flex;align-items:center;gap:8px;max-width:none}
footer .fop-icon{width:18px;height:18px;flex:none;display:block}
footer .fco{
  display:flex;align-items:center;gap:8px;
  margin:0 0 .55rem;max-width:none;
  color:var(--muted);
  font-family:var(--display);font-optical-sizing:auto;font-weight:660;
  font-size:.95rem;letter-spacing:-.02em;line-height:1.2
}
footer a.fco{padding:0}
footer .fco-icon{width:32px;height:32px;flex:none;display:block}
footer .fco-name{padding-left:4px}
footer .floc{color:var(--muted);padding:.2rem 0;font-size:.8rem}

/* ---------- a11y / motion ---------- */
:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;border-radius:4px}
.skip{position:absolute;left:-9999px}
.skip:focus{left:.75rem;top:.6rem;z-index:99;background:var(--violet);color:#fff;padding:.55rem .9rem;border-radius:8px}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important;scroll-behavior:auto!important}}

/* ---------- responsive ---------- */
@media (max-width:960px){
  :root{--gut:calc(clamp(1.25rem,4vw,3rem) - 4px)}
  .hero-grid,.price-lead{grid-template-columns:1fr}
  .cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cols-3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .strip{grid-template-columns:1fr}
  footer .fgrid{grid-template-columns:1fr}
  footer .fnavs{grid-template-columns:repeat(3,max-content);justify-content:space-between;padding:0 4px;gap:1.2rem}
}
@media (max-width:680px){
  body{font-size:16px}
  .caps{grid-template-columns:1fr}
  .cols-2,.cols-3,.cols-4{grid-template-columns:1fr}
  .navtoggle{display:block}
  nav.primary{
    display:none;position:absolute;top:66px;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--ink-2);border-bottom:1px solid var(--line);padding:.5rem var(--gut) 1rem
  }
  nav.primary.open{display:flex}
  nav.primary a{padding:.6rem 0;border-bottom:1px solid var(--line)}
  footer .fgrid{grid-template-columns:1fr}
}
@media print{.masthead,.cta,footer nav{display:none}body{background:#fff;color:#000}}

/* ---------- cost comparison ---------- */
.compare{max-width:880px;display:grid;gap:1px;background:var(--paper-line);border:1px solid var(--paper-line);border-radius:10px;overflow:hidden;margin-bottom:1.6rem}
.compare .row{background:var(--paper);display:grid;grid-template-columns:8.5rem 1fr;gap:1.1rem;align-items:center;padding:.95rem 1.2rem}
.compare .row.head{background:var(--paper-2);font-family:var(--mono);font-size:.7rem;letter-spacing:.07em;color:#7d7767}
.compare .vol{font-weight:620;font-variant-numeric:tabular-nums}
.compare .bars{display:grid;grid-template-columns:minmax(0,1fr) max-content;gap:.4rem .75rem;align-items:center;font-size:.86rem;font-variant-numeric:tabular-nums}
/* Both bars share one grid so the label column is as wide as the widest label
   and the two tracks still line up. A fixed column clipped larger figures. */
.compare .bar{display:contents}
.compare .bar .track{display:block;min-width:0}
.compare .bar .fill{display:block;height:16px;border-radius:3px;min-width:3px}
/* The market bar is a SPAN, not a length: it starts at the low figure and ends at the high
   one, on the same scale as the flat bar below it. Drawn as one length it said the range
   was a single number, which is the thing the section exists to argue against. */
.compare .bar .fill.mkt{background:#c9c2b1}
.compare .bar .fill.flat{background:var(--violet)}
.compare .bar .lab{color:var(--ink-muted);white-space:nowrap}
/* The all-in figure under the covers table, on the paper ground. */
.covers-allin{font-size:1.02rem;font-weight:620;color:var(--ink-text);margin:0 0 .5rem}
@media (max-width:680px){.compare .bars{grid-template-columns:1fr;gap:.25rem}.compare .bar .lab{white-space:normal}.compare .row{grid-template-columns:1fr;gap:.6rem}}
.byline{font-size:.9rem;color:var(--muted-2);margin:.55rem 0 0}
.authorblock{border-top:1px solid var(--line);margin:2.4rem 0 0;padding-top:1.1rem;max-width:70ch}
.authorblock p{color:var(--muted);font-size:.95rem;margin:0 0 .4rem}
.feeswrap .cardshead{font-family:var(--display);font-optical-sizing:auto;font-size:1.35rem;margin:0 0 1.1rem;color:var(--c-ink)}
/* glossary A to Z jump navigation */
.azjump{display:flex;flex-wrap:wrap;gap:.4rem;margin:0 0 2rem;padding:0;list-style:none}
.azjump a{display:inline-grid;place-items:center;min-width:2rem;padding:.35rem .5rem;border:1px solid var(--line);border-radius:6px;color:var(--muted);text-decoration:none;font-family:var(--mono);font-size:.8rem}
.azjump a:hover{color:var(--text);border-color:var(--violet)}
.azgroup{margin-bottom:2.2rem;scroll-margin-top:2rem}
.azgroup h3{font-family:var(--mono);font-size:.85rem;letter-spacing:.11em;color:var(--muted-2);margin:0 0 .8rem;padding-bottom:.4rem;border-bottom:1px solid var(--line)}
.breakeven{max-width:880px;background:var(--paper-2);border-radius:8px;padding:1.1rem 1.25rem;font-size:.95rem;color:var(--ink-text);max-width:66ch}

/* ---------- proof ---------- */
.quote{border-left:2px solid var(--violet);padding-left:1.3rem;max-width:60ch}
.quote blockquote{margin:0 0 .9rem;font-size:1.16rem;line-height:1.45;letter-spacing:-.014em}
.quote cite{font-style:normal;font-size:.9rem;color:var(--muted)}
.paper .quote cite{color:var(--ink-muted)}
/* A quote carrying an argument rather than decorating one: larger type, a thicker
   violet rule, more room. Used where the quote corroborates the claim beside it, so it
   has to register as testimony and not as body copy. No box: the rule and the scale do
   the work, and a filled panel would read as a pull-quote ornament. */
.quote-lead{border-left-width:3px;padding-left:1.6rem;max-width:66ch;margin-top:2rem}
.quote-lead blockquote{font-size:1.44rem;line-height:1.34;letter-spacing:-.018em}
.quote-lead cite{font-size:.95rem}
@media (max-width:700px){.quote-lead blockquote{font-size:1.22rem}}

/* ---------- faq ---------- */
/* Questions read open. The rule between entries carries the section, in place of
   the disclosure affordance this block used to have. */
.faq{border-top:1px solid var(--line);max-width:74ch}
.faq .qa{border-bottom:1px solid var(--line);padding:1.05rem 0}
.faq .qa h3{font-weight:600;font-size:1.02rem;margin:0 0 .45rem}
.faq .qa p{color:var(--muted);font-size:.97rem;padding-right:2rem;margin:0}
.paper .faq{border-top-color:var(--paper-line)}
.paper .faq .qa{border-bottom-color:var(--paper-line)}
.paper .faq .qa p{color:var(--ink-muted)}

/* in-body contextual links */
.note a,.block p a,p.lede a{color:var(--cyan);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
.paper .note a,.paper .block p a,.paper p.lede a{color:var(--violet-dim)}

/* ---------- collections ---------- */
.glossary-list{max-width:74ch}
.glossary-list > div{padding:1.1rem 0;border-bottom:1px solid var(--line)}
.glossary-list dt{font-weight:640;font-size:1.05rem;letter-spacing:-.012em;margin-bottom:.3rem}
.glossary-list dt a{text-decoration:none}
.glossary-list dt a:hover{color:var(--cyan)}
.glossary-list dd{margin:0;color:var(--muted);font-size:.96rem}

/* ---------- markdown prose ---------- */
.prose > *{max-width:70ch}
.prose pre{max-width:none;overflow-x:auto}
.prose h2{margin:2.4rem 0 .8rem;font-size:1.45rem}
.prose h3{margin:1.8rem 0 .6rem}
.prose p,.prose li{color:var(--muted);font-size:1.02rem;line-height:1.65}
.prose ul,.prose ol{padding-left:1.3rem;margin:0 0 1.1rem;list-style:disc}
.prose ol{list-style:decimal}
.prose li{margin:.3rem 0}
.prose strong{color:var(--text)}
.prose a{color:var(--cyan);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
.prose table{margin:1.2rem 0 1.6rem}
.prose th,.prose td{border-bottom-color:var(--line)}
.prose thead th{color:var(--muted-2)}
.prose blockquote{border-left:2px solid var(--violet);margin:1.4rem 0;padding-left:1.15rem;color:var(--muted)}
.prose code{font-family:var(--mono);font-size:.88em;background:var(--ink-3);padding:.1em .35em;border-radius:4px}

/* ---------- clickable cards for collection indexes ---------- */
.card{display:flex;flex-direction:column;gap:.55rem;text-decoration:none;color:inherit;background:var(--ink-2);border:1px solid var(--line);border-radius:12px;padding:1.4rem 1.5rem;transition:border-color .15s}
.card:hover{border-color:var(--violet)}
.card h3{margin:0}
.card p{color:var(--muted);font-size:.96rem;margin:0}
.card-go{margin-top:auto;padding-top:.6rem;font-size:.88rem;color:var(--cyan);font-weight:600}

/* ---------- glossary index: one DOM, two orderings by CSS `order` ---------- */
/* This page's list sits on the dark section, so the toolbar uses the dark tokens. */
.glwrap{display:block}
.glshead{max-width:70ch;margin-bottom:.7rem}
.glintro{margin:.45rem 0 0;font-size:.95rem;color:var(--muted);max-width:68ch}
.glwrap[data-view="stage"] .azjump{display:none}
.gltools{position:sticky;top:64px;z-index:40;background:rgba(11,16,27,.96);backdrop-filter:blur(8px);padding:.9rem 0 .8rem;border-bottom:1px solid var(--line);margin-bottom:.4rem}
.glviews{display:inline-flex;border:1px solid var(--line);border-radius:8px;overflow:hidden;margin-right:.6rem;vertical-align:middle}
.glview{appearance:none;border:0;background:transparent;font:inherit;font-size:.9rem;padding:.5rem .9rem;cursor:pointer;color:var(--muted)}
.glview:hover{color:#fff}
.glview.active{background:var(--violet);color:#fff}
.glsearch{display:inline-block;vertical-align:middle;margin-right:.6rem}
.glsearch input{font:inherit;font-size:.95rem;padding:.5rem .75rem;border:1px solid var(--line);border-radius:8px;background:var(--ink-2);color:#f0f6fc;min-width:min(330px,70vw)}
.glsearch input::placeholder{color:var(--muted)}
.glchips{display:inline-flex;flex-wrap:wrap;gap:.4rem;vertical-align:middle;max-width:100%}
.glchip{appearance:none;font:inherit;font-size:.85rem;padding:.42rem .7rem;border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--muted);cursor:pointer;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.glchip:hover{color:#fff}
.glchip.active{background:#fff;border-color:#fff;color:var(--ink-2)}
.glcount{margin:.7rem 0 0;font-size:.85rem;color:var(--muted)}
.gllist{display:flex;flex-direction:column;gap:0}
.glwrap[data-view="stage"] .gllist>*{order:var(--so)}
.glwrap[data-view="az"] .gllist>*{order:var(--ao)}
.glhead{font-family:var(--mono);font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);border-bottom:1px solid var(--line);padding:1.6rem 0 .5rem;margin-bottom:.5rem}
/* A single letter at strip size reads as a stray glyph, so the A to Z labels get more
   weight to carry the same authority as a stage label. Same box, same rule, same colour
   role: only the glyph is scaled up, because one character has to do the work of four
   words. Markup is identical, so neither view is a heading and neither trips the
   duplicate-heading rule. */
.glhead-az{font-family:var(--display);font-optical-sizing:auto;font-size:1.02rem;font-weight:700;letter-spacing:.14em;color:var(--muted);padding-top:1.65rem}
/* Jump targets clear the sticky chrome. --gl-stick is measured from the sticky elements
   themselves (see index.astro); the fallback is the masthead plus a typical toolbar. */
.glhead,.glrow{scroll-margin-top:calc(var(--gl-stick, 173px) + 14px)}
.glrow{padding:.62rem 0;border-bottom:1px solid var(--line)}
.glrow dt{margin:0}
.glrow dt a{font-weight:640;text-decoration:none;color:#f0f6fc}
.glrow dt a:hover{text-decoration:underline}
.glrow dd{margin:.12rem 0 0;display:flex;flex-wrap:wrap;align-items:baseline;gap:.28rem .7rem}
.glone{color:var(--muted);font-size:.95rem}
.glmeta{display:inline-flex;flex-wrap:wrap;gap:.35rem}
.glpill{font-size:.74rem;padding:.16rem .55rem;border-radius:999px;text-decoration:none;white-space:nowrap;border:1px solid transparent}
.glpill-fee{background:rgba(139,92,246,.16);border-color:rgba(139,92,246,.4);color:#c4b5fd}
.glpill-guide{background:rgba(255,255,255,.05);border-color:var(--line);color:var(--muted)}
.glpill:hover{text-decoration:underline}
.glempty{padding:1.6rem 0;color:var(--muted)}
.glempty p{margin:0 0 .4rem;max-width:60ch}
.glempty strong{color:#f0f6fc}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@media (max-width:680px){
  .gltools{position:static;padding-top:0;backdrop-filter:none}
  .glviews,.glsearch,.glchips{display:flex;margin:0 0 .5rem;width:100%}
  /* 16px minimum: below it iOS Safari zooms the page on focus and the reader has to
     pinch back out to see the results they just filtered. */
  .glsearch input{font-size:16px}
  .glsearch input{width:100%;min-width:0}
  .glviews{width:100%}
  .glview{flex:1;text-align:center}
  .glrow dd{gap:.2rem .5rem}
}

/* ---------- index-page hero, narrow widths only ----------
   The four index pages exist to route people into a list. At 390px the hero plus the
   stacked toolbar consumed the whole first screen, so nothing to route into was visible.
   Scoped to .hero-index and to <=680px: desktop and every content page are untouched.
   The Bates eyebrow and the H1 stay; only spacing, H1 scale and the standfirst move. */
@media (max-width:680px){
  .hero-index{padding-top:1.4rem;padding-bottom:.9rem}
  .hero-index h1{font-size:1.72rem;margin-bottom:.5rem;letter-spacing:-.018em}
  /* On the three hub indexes the standfirst repeats the meta description verbatim, so
     hiding it at phone width loses no unique copy. */
  .hero-index .lede{display:none}
  /* /fees/ carries unique copy here, so it is clamped rather than dropped. */
  .hero-index.hero-lede-clamp .lede{
    display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden;
    margin-top:.6rem!important;font-size:.95rem
  }
  .hero-index .bates{margin-bottom:.5rem}
}

/* Guides index: the list is pulled into the hero padding on desktop. On a phone
   that overlap sits on the last lines of the intro, so the pull is dropped. */
.guides-list{padding-top:0;margin-top:-60px}
@media (max-width:680px){
  .guides-list{margin-top:-16px;padding-top:1.6rem}
}

/* Tools index: same desktop pull. On a phone the compressed hero leaves the H1
   sitting on the list heading, so the pull is dropped. */
.tools-list{padding-top:0;margin-top:-40px}
@media (max-width:680px){
  .tools-list{margin-top:0;padding-top:1.6rem}
}

/* ---------- iOS zoom floor, narrow widths only ----------
   Safari on iOS zooms the page when a text-entry control smaller than 16px receives
   focus, and does not zoom back out. The reader ends up pinching to see the result of
   their own typing. This is an accessibility floor rather than a style choice, so it
   carries !important: tool CSS is prefixed by wrapper class and would otherwise win on
   specificity. Scoped to <=680px, so desktop sizing is untouched. Non-text controls
   (range, checkbox, radio, buttons) never trigger the zoom and are excluded. */
@media (max-width:680px){
  input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]),
  select,
  textarea{font-size:16px!important}
}

/* ---------- /fees/ reading order on phones ----------
   At 390px the example invoice and the "why this guide exists" copy pushed the first
   fee card to 1,539px, so a phone reader saw no fee at all. The intro block is lifted
   into its own .feesintro section purely so it can be reordered here: at <=680px the
   cards come straight after the toolbar and the intro follows them. Nothing is hidden
   and desktop DOM order is unchanged, so the reading order on a wide screen still runs
   invoice, rationale, then cards. */
/* Splitting the intro into its own section lets a margin collapse out between the two
   .paper sections, so the dark page background showed through a 21px strip. The section
   is pulled up over the seam and pads the same amount back: that repaints exactly the
   strip and moves no content. Painting .feeswrap instead recomposited the
   semi-transparent toolbar sitting on top of it. */
/* The gap between the lede and the intro block used to be a collapsed margin inside one
   section. Split across two sections it escaped between them and the dark page background
   showed through. Both margins are zeroed and the same 21px is paid as padding inside the
   paper section, so the strip paints and no content moves. */
.feeswrap>section.hero-index .lede{margin-bottom:0}
.feeswrap>section.feesintro .herogrid{margin-top:0}
.feeswrap>section.feesintro{padding-top:21px!important}
@media (max-width:680px){
  .feeswrap{display:flex;flex-direction:column}
  .feeswrap>section.hero-index{order:1}
  .feeswrap>.toolbar{order:2}
  .feeswrap>section.paper:not(.hero-index):not(.feesintro){order:3}
  .feeswrap>section.feesintro{order:4;padding-top:1.6rem!important}
  .feeswrap>.toast{order:5}
  /* the cards start immediately under the toolbar on a phone */
  .feeswrap>section.paper:not(.hero-index):not(.feesintro){padding-top:1rem!important}
  .feeswrap .cardshead{margin-bottom:.8rem}
}

/* ---------- product screenshots ---------- */
/* The three demo-instance captures. They are a white UI dropped on a dark page that has
   no light mode, so a shadow lifts them off the dark ground. The caption sits
   outside the image, where it reads as our label on
   the capture rather than as part of the screenshot. */
.shot{margin:0}
.shot-frame{
  background:transparent;
  border-radius:6px;
  box-shadow:0 22px 60px -24px rgba(0,0,0,.8);
  overflow:hidden
}
/* height:auto keeps the aspect ratio when the intrinsic width/height attributes Astro
   writes are overridden by the 100% width. display:block closes the inline-element gap
   under the image, which would otherwise show as a stripe of frame along the bottom. */
.shot-frame img{display:block;width:100%;height:auto}
.shot figcaption{
  margin-top:.6rem;
  color:var(--muted-2);
  font-family:var(--mono);
  font-size:.75rem;
  letter-spacing:.09em;
  text-transform:uppercase
}
/* ---------- the homepage hero ---------- */
/* Stacked, not two columns: copy, then the screenshot at the container's full width.
   Left-aligned rather than centred. The lede runs to about 58 words, and centred text
   that long starts every line at a different x, which is the thing that slows scanning.
   Left also keeps the copy on the same optical axis as the image's left edge, so the two
   read as one composition instead of two stacked blocks, and it matches every other hero
   on the site. */
/* The stacked hero is tighter than the others because it carries four blocks rather than
   two. Measured at 1440x900 with scripts/cdp-render.py: with the section's own padding the
   buttons landed 85px below the fold, and a primary CTA below the fold on a laptop is a
   real cost. Scoped to .hero-stack so /platform/, /security/, /pricing/ and /contact/ keep
   the airier hero they were designed with. */
.hero-split{padding-top:clamp(1.9rem,4vw,2.8rem);padding-bottom:clamp(2.4rem,5vw,3.6rem)}
/* Two columns, the copy a little narrower than the card: the card holds a chart that wants
   width, and the copy is three short blocks that do not. Stacks at 960 with the rest of
   the site, copy first, which is also the DOM order, so the reading order is the same. */
/* DOM order is copy, card, quote, which is the mobile reading order. Desktop puts the
   quote back under the copy with grid areas rather than `order:`, so reading order and tab
   order match what is on screen at every width. `order:` would have moved the quote
   visually and left a keyboard user tabbing from the buttons into the card and back out
   again to reach it. */
.hero-grid2{
  display:grid;
  /* The copy column was the narrower of the two until 10 October 2026. It is the wider
     one now because the headline is three sentences and each has to sit on one line: at
     the old .92fr the copy measured 457px and the longest line needed about 510px, so two
     of the three wrapped and a three-line headline rendered as five. The chart keeps
     enough width to stay legible, which was checked rather than assumed. */
  grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
  /* Desktop: copy and identity stacked in the left column beside the chart, and the
     testimonial as a full-width band across the bottom. The band is the fallback Chris
     specified on 10 October 2026, taken because the card inside the copy column measured
     the hero at 1047px against a 1000px ceiling. It is cheaper across the full width: the
     quote sets in two lines there rather than four. */
  grid-template-areas:"copy card" "idy card" "tmnl tmnl";
  grid-template-rows:auto auto auto;
  /* Row gap is small because the rows are a copy column, the sentence under it and the
     testimonial band, which read as one stack rather than three sections. The column gap
     is the one that has to stay generous: it separates the copy from the chart. */
  gap:1rem clamp(1.8rem,4vw,3.2rem);
  align-items:start
}
.hero-grid2 > .hero-copy{grid-area:copy}
.hero-grid2 > .hero-pitch{grid-area:idy;align-self:start}
.hero-grid2 > .tmnl-hero{grid-area:tmnl}
main:not(:has(.home2-hero)) .hero-grid2 > .tmnl-hero{margin-top:20px}
@media (min-width:681px){
  main:not(:has(.home2-hero)) section.hero-split{
    padding-bottom:calc(clamp(2.4rem,5vw,3.6rem) - 20px);
  }
}
.hero-grid2 > .heroest{grid-area:card}
/* Platform uses this grid without the calculator, so the card column would otherwise
   sit empty beside the copy. Collapse to one column when .heroest is absent. */
.hero-grid2:not(:has(.heroest)){
  grid-template-columns:minmax(0,1fr);
  grid-template-areas:"copy" "idy" "tmnl";
}
/* Desktop only: the left column starts with the Bates stamp, the right column
   with the calculator. Drop the calculator by the stamp's height so its top
   meets the headline. Hidden with the stamp at 680, and unused in the stacked
   layout at 960. */
@media (min-width:961px){
  .hero-grid2 > .heroest{
    margin-top:calc(.68rem * 1.6 + .5rem + 1px + 2.1rem);
  }
}
.hero-split .hero-copy{max-width:60ch}
.hero-pitch{font-size:clamp(1.06rem,1.6vw,1.2rem);color:var(--muted);margin:0;max-width:44ch}
.hero-split .btnrow{margin-top:1.5rem}

/* The testimonial, compact, under the buttons. A rule rather than quote marks: the page
   already uses a left rule for the pull quote and this is the same device at a smaller
   size. */
/* No top margin: the grid's row gap does the spacing now, and a margin on top of it put
   the quote 38px lower than the layout intended. */


/* ---------- the estimate chart ---------- */
/* Palette only: a muted grey band, the accent for our line, no gradient and no glow. The
   band and the flat line are drawn across the whole axis and do not move with the slider,
   because both are functions of volume; the slider moves the marker along them. */
.heroch{display:block;width:100%;height:auto;margin:0 0 1rem}
.hc-grid{stroke:var(--line);stroke-width:1}
.hc-band{fill:var(--muted-2);fill-opacity:.22;stroke:var(--muted-2);stroke-opacity:.5;stroke-width:1}
.hc-flat{stroke:var(--violet);stroke-width:2.5}
/* The segment past the volume the published ingestion fee covers. Dashed because it is
   a floor and not a total: it plots the recurring rate alone, with the one-time
   ingestion above that volume quoted rather than published. Same color and weight, so
   it reads as the same line in a different state rather than a second series. */
.hc-flat-q{stroke:var(--violet);stroke-width:2.5;stroke-dasharray:7 5;stroke-opacity:.85}
.hc-quotelab{fill:var(--violet);font-size:11px;font-weight:560;font-family:var(--sans)}
.hc-flatlab{fill:var(--violet);font-size:13px;font-weight:620;font-family:var(--sans)}
.hc-marker{stroke:var(--text);stroke-width:1.5;stroke-dasharray:4 4;stroke-opacity:.75}
.hc-ylab,.hc-xlab{fill:var(--muted-2);font-size:12px;font-family:var(--mono)}
/* A 2 TB axis puts seven x labels in about 330 physical pixels on a phone, which
   collides. The three the chart can lose are marked in hero-chart.ts and dropped here;
   the two ends and the volume where ingestion stops being covered always stay. */
@media (max-width:680px){.hc-xopt{display:none}}

@media (max-width:960px){
  /* One column: the areas collapse to the DOM order, copy then card then quote. */
  /* Phone: the card sits between the buttons and the identity sentence, which is the
     placement the rebuild is for. Source order already reads copy, card, identity, chart,
     so this area list only has to keep it. */
  .hero-grid2{grid-template-columns:1fr;grid-template-areas:"copy" "tmnl" "idy" "card";grid-template-rows:auto}
  .hero-grid2:not(:has(.heroest)){grid-template-areas:"copy" "tmnl" "idy"}
  .hero-split .hero-copy{max-width:62ch}
}

/* ---- Testimonial card, 10 October 2026. ---------------------------------------------
   One component, one look, two placements: under the hero CTAs on `/` and under the lede
   on `/about/`. The quote is the loudest copy on the page after the headline, which is
   the point of moving it: a proof point below the buttons is read, and the same words in
   a quiet rule-left block two screens down are not.
   The disclosure is part of the card and not an option. An FTC material connection has to
   travel with the endorsement, so it is styled small and muted but never hidden, never
   collapsed behind a control and never conditional. */
.tmnl{
  margin:0 0 1.15rem;
  position:relative;
  border:1px solid var(--violet-dim);
  border-radius:12px;
  padding:1.15rem 1.15rem 1rem;
  background:color-mix(in srgb,var(--violet) 7%,var(--ink-2));
  display:grid;gap:.75rem;
}
/* The opening mark is set as a large glyph rather than a background image so it scales
   with the type and needs no asset. It is lifted out of the text flow by a negative
   margin so the first line of the quote starts at the card's text edge. */
.tmnl-mark{
  display:block;
  font-size:2.6rem;line-height:.6;
  color:var(--violet);
  margin:.15rem 0 -.5rem;
  font-family:Georgia,'Times New Roman',serif;
}
.tmnl-q{
  margin:0;
  font-size:1.2rem;line-height:1.45;letter-spacing:-.012em;
  font-weight:450;color:var(--text);
}
.tmnl-cap{display:grid;gap:.15rem}
.tmnl-name{font-size:.95rem;font-weight:600;color:var(--text)}
.tmnl-role{font-size:.88rem;color:var(--muted)}
/* The disclosure, set apart by a hairline so it reads as a note on the endorsement rather
   than as more of the attribution. Small, but at a contrast that is actually readable:
   --muted-2 is the dimmest text on the site and a required disclosure does not belong in
   it. */
.tmnl-disc{
  margin-top:.5rem;padding-top:.55rem;
  border-top:1px solid var(--line);
  font-size:.78rem;line-height:1.45;color:var(--muted);
}
/* The band spans both columns, so the quote can run the full hero width. Capped at a
   readable measure rather than the full span: 75ch of 24px type is already a long line.
   THE MARK HANGS instead of sitting on its own line from 681px up. That is better placed
   on a wide card, where there is margin for it, and it is also what brings the desktop
   hero under its ceiling: a block mark and its gap cost about 39px of height, and with
   the tighter row gap below it took the 1280x800 hero from 1040px to under 1000px. On a
   phone the column is 350px and there is no margin to hang it in, so it stays in flow. */
@media (min-width:681px){
  .tmnl-hero{margin:0}
  .tmnl-hero .tmnl-q{max-width:75ch}
  .tmnl{padding:1.4rem 1.5rem 1.2rem;gap:.85rem;padding-left:4.1rem}
  .tmnl-mark{
    position:absolute;left:1.4rem;top:1.1rem;
    font-size:3.4rem;margin:0;
  }
  .tmnl-q{font-size:1.5rem;line-height:1.38}
}
/* `/about/` shows the three-sentence version, which runs four times the length of the
   homepage one, so the same type size would make a wall. It keeps the card and the
   disclosure and takes a step down in size. */
.tmnl-lead{margin-top:2rem;max-width:66ch}
.tmnl-lead .tmnl-q{font-size:1.12rem}
@media (min-width:681px){
  .tmnl-lead .tmnl-q{font-size:1.3rem}
}

/* ---- Cost cross-link, 23 October 2026, redesigned the same day. --------------------
   A contained card between a reference article and its FAQ, on every glossary and guide
   page. It uses the surface the other cards on the site use, --ink-2 on --line at 10px,
   so it reads as one of them rather than as a new kind of thing.

   SPACING, AND WHY NONE OF IT IS A NEGATIVE MARGIN. Every <section> on the site carries
   padding-block: clamp(3.4rem,7vw,5.6rem), which is 89.6px at desktop and is the rhythm
   between blocks. The section ABOVE this one already spends that below its own content,
   so a default top padding here would stack two of them and open a 180px hole. Setting
   only padding-top to 0 leaves exactly one gap above, the normal one, and keeps the
   default below, so the card has equal air on both sides and clear space before the light
   FAQ section begins. The first version zeroed the bottom instead, which is why the card
   had 90px above it and butted straight into the paper. */
.costlinks{padding-top:0}
.cl-card{
  max-width:70ch;                 /* the article text measure, .prose > * */
  border:1px solid var(--line);border-radius:10px;
  background:var(--ink-2);
  padding:1.3rem 1.4rem;
}
/* One left edge for all three rows. Nothing is indented against anything else. */
.cl-lead{margin:0 0 .35rem;font-size:1.02rem;font-weight:620;color:var(--text);line-height:1.4}
.cl-note{margin:0 0 1.1rem;font-size:1.02rem;line-height:1.6;color:var(--muted)}
.cl-nb{white-space:nowrap}
.cl-row{display:flex;flex-wrap:wrap;align-items:center;gap:.8rem 1.1rem}
/* The outline button, not the filled one. On a reference page the article is the point;
   a primary violet button here competes with the heading it sits under. */
.cl-btn{font-size:.92rem;padding:.6rem 1rem;min-height:40px}
.cl-link{color:var(--cyan);font-size:.95rem;text-decoration:underline;text-underline-offset:3px}
@media (max-width:680px){
  .cl-card{padding:1.15rem 1.1rem}
  .cl-row{flex-direction:column;align-items:flex-start;gap:.85rem}
  .cl-btn{width:100%;text-align:center}
}

/* ---------- the hero estimate widget ---------- */
/* Every selector is prefixed .heroest, like the tools, so nothing here can reach the rest
   of the page. The two columns collapse at 680 with the rest of the site. */
.heroest{
  max-width:none;
  margin-bottom:clamp(1.2rem,2.5vw,1.5rem);
  padding:clamp(1.1rem,2.2vw,1.4rem);
  background:var(--ink-2);
  border:1px solid var(--line);
  border-radius:10px
}
.heroest-h{
  font-family:var(--display);
  font-optical-sizing:auto;
  font-weight:660;
  font-size:1.28rem;
  letter-spacing:-0.016em;
  line-height:1.2;
  margin:0 0 .55rem;
}
/* Homepage only: a second copy of the calculator heading, shown above the pitch on
   mobile and kept out of the tree on desktop so the in-card heading stays alone. */
.hero-calc-h-m{display:none}
.heroest-label{display:block;font-family:var(--display);font-optical-sizing:auto;font-weight:620;margin-bottom:.85rem;font-size:1.02rem}
.heroest-input{display:flex;align-items:center;gap:1rem;margin-bottom:1.2rem}
.heroest-input input[type=range]{
  flex:1;min-width:0;height:1.5rem;
  -webkit-appearance:none;appearance:none;background:transparent;cursor:pointer
}
/* The track is drawn rather than left to the browser: accent-color paints the fill and the
   thumb but leaves the unfilled track near-white, which on --ink reads as a bright bar
   across the hero. Vendor pseudo-elements cannot be combined in one selector list, so the
   two rules are deliberately duplicated. */
.heroest-input input[type=range]::-webkit-slider-runnable-track{
  height:5px;border-radius:3px;background:var(--line)
}
.heroest-input input[type=range]::-moz-range-track{
  height:5px;border-radius:3px;background:var(--line)
}
.heroest-input input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:18px;height:18px;margin-top:-6.5px;border-radius:50%;
  background:var(--violet);border:2px solid var(--ink-2)
}
.heroest-input input[type=range]::-moz-range-thumb{
  width:18px;height:18px;border:2px solid var(--ink-2);border-radius:50%;
  background:var(--violet)
}
.heroest-input input[type=range]::-moz-range-progress{height:5px;border-radius:3px;background:var(--violet)}
.heroest-input input[type=range]:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
.heroest-num{display:flex;align-items:center;gap:.4rem;flex:0 0 auto}
/* 16px floor: anything smaller makes iOS Safari zoom the page on focus. input_zoom_hits
   in scripts-check.py asserts this across the site. */
.heroest-num input{
  width:6.5rem;font-size:16px;font-family:var(--mono);
  padding:.45rem .55rem;border-radius:6px;
  border:1px solid var(--line);background:var(--ink);color:var(--text)
}
.heroest-num span{color:var(--muted);font-size:.86rem}
.heroest-out{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:8px;overflow:hidden}
.heroest-col{background:var(--ink);padding:.9rem 1rem}
.heroest-ours{background:var(--ink-3)}
.heroest-k{color:var(--muted);font-size:.78rem;letter-spacing:.02em;margin-bottom:.3rem}
.heroest-v{font-size:1.32rem;font-weight:660;letter-spacing:-.02em;line-height:1.15}
.heroest-s{color:var(--muted-2);font-size:.8rem;margin-top:.25rem}
.heroest-verdict{margin:.9rem 0 0;font-size:.95rem;color:var(--text)}
.heroest-verdict a{color:var(--cyan)}
.heroest-note{margin:.55rem 0 0;font-size:.82rem;color:var(--muted-2)}
.heroest-note a{color:var(--muted)}
@media (max-width:680px){
  .heroest-out{grid-template-columns:1fr}
  /* The row becomes a column here, which turns the range input's `flex:1 1 0%` from a width
     basis into a HEIGHT basis: flex-basis 0 beat the declared 1.5rem and the handle's hit
     area collapsed to the 5px track. `flex:none` returns sizing to the declared height. */
  .heroest-input{flex-direction:column;align-items:stretch;gap:.7rem}
  .heroest-input input[type=range]{flex:none}
  .heroest-num{justify-content:flex-start}
}

/* ---------- the homepage screenshot band ---------- */
/* Below the quote now rather than in the hero: the widget leads, the picture corroborates. */
.shotband{background:var(--ink-2);border-block:1px solid var(--line);padding:clamp(2.4rem,5vw,3.6rem) 0}
.shotband .shothead{max-width:60ch;margin-bottom:clamp(1.4rem,3vw,2rem)}
.shotband .shothead h2{font-size:1.28rem;margin-bottom:.5rem}
.shotband .shothead p{color:var(--muted);font-size:.96rem;margin:0}

/* A deep soft shadow and one restrained glow behind the top edge, violet at low alpha,
   because a bright white screenshot otherwise sits on --ink like a sheet of paper dropped
   on a desk. No device mockup and no browser chrome: the point of the image is that it is
   the real screen. */
.heroshot{position:relative}
.heroshot::before{
  content:"";
  position:absolute;
  /* Horizontal inset stays 0. A negative one put the glow 8px past the viewport on a
     390px phone and gave the whole page a horizontal scroll, measured with
     scripts/cdp-render.py. The blur spreads it sideways without any box to overflow. */
  inset:-14% 0 28%;
  background:radial-gradient(64% 70% at 50% 0%,rgba(139,92,246,.28),transparent 70%);
  filter:blur(52px);
  z-index:0;
  pointer-events:none
}
.heroshot .shot-frame{
  position:relative;z-index:1;
  background:transparent;
  border-radius:10px;
  box-shadow:0 40px 90px -30px rgba(0,0,0,.92)
}
/* The two crops have different ratios. The sources carry width and height, and this
   repeats it in CSS so a browser that ignores those attributes still reserves the right
   box and the page does not shift when the image lands. */
.heroshot img{aspect-ratio:3664/2172}
@media (max-width:680px){.heroshot img{aspect-ratio:2376/2038}}
@media (prefers-reduced-transparency:reduce){.heroshot::before{display:none}}
/* A tall narrow panel crop. Capped and centred so it does not stretch across the full
   measure, which would make a 600px-wide capture soft. */
.shot-panel{margin-inline:auto}
/* A screenshot following a grid of cards needs the gap the grid does not give it. */
.caps + .shot,.cols + .shot{margin-top:clamp(2rem,4vw,3rem)}
/* Text beside a panel crop. .cols-2 collapses at 680 like every other pair on the site,
   and align-items:start stops the short text block stretching to the image's height. */
.shot-pair{align-items:start;margin-top:clamp(2rem,4vw,3rem)}
.shot-pair .block p{max-width:46ch}
.shot-pair .shot{margin-top:-160px}
@media (max-width:680px){
  .shot-pair .shot{margin-top:0}
}
.sec-faq{margin-top:-40px}

/* ---------- mobile corrections, 5 October 2026 ---------- */
/* Three things measured at a real 390px viewport with scripts/cdp-render.py rather than
   guessed at from a clamped --window-size capture. */

/* 1. The masthead tagline. "eDiscovery for law firms and legal departments" wrapped to two
      lines under the wordmark below about 480px and pushed the whole header down. Hidden
      rather than shortened: a truncated tagline reads as a bug, and the same words are in
      the title and the meta description where a phone user is served by them anyway. */
@media (max-width:480px){.brand small{display:none}}

/* 2. Stacked buttons are full width and equal. Side by side they size to their text, and
      "Book a walkthrough" against "See the full price sheet" stacked at two different
      widths reads as a hierarchy that is not intended. */
@media (max-width:680px){
  .btnrow{flex-direction:column;align-items:stretch}
  .btnrow .btn{width:100%;justify-content:center;text-align:center}
}

/* ---------- "Fees we don't charge" cards ---------- */
/* Nine cards, 3 x 3. A plain three-column grid fills exactly, so no spanning is needed:
   that was only there to close the hole five cards left in a second row of three.

   It is a real <ul>. The fee name is an <h3>, the figure, the note and the "Others:" line
   are all text, and the label is a <span> rather than a pseudo-element, so nothing here
   exists only in the styling: a screen reader gets "User seats, $0, No per-user fee,
   Others: $75 to $125 per user, per month" in that order. */
.hero-split + section:has(.feecards){margin-top:-40px}
main:has(#ai-suite) section:has(.feecards){margin-top:-40px}
main:has(#ai-suite) #sources{margin-top:-40px}
main:has(#ai-suite) section:has(#ai-suite){margin-top:-40px}
.feecards{list-style:none;padding:0;margin:0 0 1.6rem;display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.feecard{background:var(--ink);padding:1.3rem 1.2rem}
.feecard h3{font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;font-family:var(--mono);color:var(--muted-2);font-weight:500;margin:0 0 .7rem}
.fc-fig{font-size:clamp(1.8rem,3vw,2.3rem);font-weight:660;letter-spacing:-.03em;line-height:1;margin:0;color:var(--violet)}
/* The one card that is a price rather than a zero takes the body colour. The accent is
   doing work here: it says "this is nothing". Nine accented figures with one of them
   $1,725 would read as nine savings, which is the thing the lede exists to correct. The
   class is set from the same test the lede's count uses, so colour and count cannot
   disagree about which card is which. */
.fc-fig-paid{color:var(--text)}
.fc-note{color:var(--text);font-size:.95rem;margin:.45rem 0 0;max-width:30ch}
.fc-others{color:var(--muted-2);font-size:.86rem;margin:.9rem 0 0;padding-top:.75rem;border-top:1px solid var(--line);max-width:34ch}
.fc-lab{font-family:var(--mono);font-size:.7rem;letter-spacing:.07em;text-transform:uppercase}
/* The cards are link targets from elsewhere; a jump must clear the sticky masthead. */
.feecard[id]{scroll-margin-top:5.5rem}

/* The one line that turns five cards into a number. */
.feemoney{font-size:1.06rem;color:var(--text);margin:0 0 1.5rem;max-width:62ch}

.feenote{color:var(--muted);max-width:72ch}
.feenote a{color:var(--cyan)}

@media (max-width:860px){
  .feecards{grid-template-columns:repeat(2,1fr)}
}
/* Below 680 the cards become compact rows: name and figure on one line, the note and the
   "Others" line beneath in small text. Nine full cards ran to 2,378px on a 390px phone,
   which is nearly three screens to read nine short facts. Layout only: the markup, the
   order and the anchors are unchanged, so the reading order and the tab sequence are the
   same on both. */
@media (max-width:680px){
  .feecards{grid-template-columns:1fr;border-radius:8px}
  .feecard{
    padding:.55rem .8rem;
    display:grid;
    grid-template-columns:1fr auto;
    column-gap:.8rem;
    align-items:baseline
  }
  .feecard h3{
    grid-column:1;grid-row:1;
    margin:0;
    font-size:1.08rem;letter-spacing:.01em;text-transform:none;
    font-family:var(--sans);font-weight:620;color:var(--text)
  }
  .fc-fig{
    grid-column:2;grid-row:1;
    font-size:1.32rem;letter-spacing:-.02em;
    text-align:right;white-space:nowrap
  }
  .fc-note{grid-column:1 / -1;grid-row:2;margin:.1rem 0 0;font-size:.82rem;line-height:1.35;color:var(--muted);max-width:none}
  .fc-others{
    grid-column:1 / -1;grid-row:3;
    margin:.2rem 0 0;padding-top:0;border-top:0;
    font-size:.75rem;line-height:1.35;max-width:none
  }
  .fc-lab{font-size:.64rem}
}

/* ---------- mobile corrections, 5 October 2026 ---------- */
/* Three things measured at a real 390px viewport with scripts/cdp-render.py rather than
   guessed at from a clamped --window-size capture. */

/* 1. The masthead tagline. "eDiscovery for law firms and legal departments" wrapped to two
      lines under the wordmark below about 480px and pushed the whole header down. Hidden
      rather than shortened: a truncated tagline reads as a bug, and the same words are in
      the title and the meta description where a phone user is served by them anyway. */
@media (max-width:480px){.brand small{display:none}}

/* 2. Stacked buttons are full width and equal. Side by side they size to their text, and
      "Book a walkthrough" against "See the full price sheet" stacked at two different
      widths reads as a hierarchy that is not intended. */
@media (max-width:680px){
  .btnrow{flex-direction:column;align-items:stretch}
  .btnrow .btn{width:100%;justify-content:center;text-align:center}
}

/* ---------- "Fees we don't charge" comparison ---------- */
/* A table on desktop, cards on a phone. Not .tablewrap with a scrollbar: three columns of
   prose scrolled sideways is unreadable on a phone and hides the third column, which is
   the one making the point. The borders and the mono header follow the site's existing
   table styling on a dark section, which is what .dark-table does elsewhere. */
.feecmp{margin-bottom:1.6rem}
.feecmp table{width:100%;border-collapse:collapse}
.feecmp caption{color:var(--text)}
.feecmp th,.feecmp td{border-bottom:1px solid var(--line)}
.feecmp thead th{color:var(--muted-2)}
.feecmp tbody th{font-weight:620;color:var(--text);width:9.5rem}
.feecmp tbody td{color:var(--muted)}
/* The Kavarn column is the answer, so it reads as the emphasised one. */
.feecmp tbody td:last-child{color:var(--text);font-weight:560}
.feenote{color:var(--muted);max-width:72ch}
.feenote a{color:var(--cyan)}

@media (max-width:680px){
  /* Each row becomes a card: the fee name as its heading, then two labelled lines. The
     labels come from data-k on the cells, so the header row is not repeated in markup
     and the table stays a table for a screen reader. */
  .feecmp thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  .feecmp table,.feecmp tbody,.feecmp tr,.feecmp th,.feecmp td{display:block;width:auto}
  /* The caption needs its own display and width here. Left as table-caption inside a
     table that is now display:block it shrink-wraps to the widest word and renders one
     word per line, which is what the first capture showed. */
  .feecmp caption{display:block;width:100%;margin-bottom:1rem}
  .feecmp tr{
    border:1px solid var(--line);border-radius:8px;
    padding:.9rem 1rem;margin-bottom:.8rem;background:var(--ink-2)
  }
  .feecmp th,.feecmp td{border-bottom:0;padding:0}
  .feecmp tbody th{font-size:1.02rem;margin-bottom:.6rem;width:auto}
  .feecmp tbody td{padding-top:.5rem}
  .feecmp tbody td + td{border-top:1px solid var(--line);margin-top:.5rem}
  .feecmp tbody td::before{
    content:attr(data-k);
    display:block;
    font-family:var(--mono);font-size:.68rem;letter-spacing:.07em;
    color:var(--muted-2);margin-bottom:.15rem
  }
}

/* ---------- tables that stack into cards on a phone ---------- */
/* `.tablewrap` scrolls an oversized table sideways, which means nothing looks broken and a
   column is simply not there: the Rate column on the /pricing/ overage table was off-screen
   at 390px and so was the caption's tail. Below 680 these tables become one card per row.
   ROLES ARE SET IN THE MARKUP because display:block strips a table's implicit roles in most
   browsers; the cell labels come from data-k, which duplicates for sighted readers what the
   headers already give a screen reader. scripts/check-tables.py fails the build if any
   table still overflows its container at 390. */
@media (max-width:680px){
  .stacks,.stacks tbody,.stacks tr,.stacks th,.stacks td{display:block;width:auto}
  .stacks thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  .stacks caption{display:block;width:100%}
  .stacks tr{
    border:1px solid var(--paper-line);border-radius:8px;
    padding:.8rem .9rem;margin-bottom:.7rem
  }
  .dark-table.stacks tr{border-color:var(--line);background:var(--ink-2)}
  .stacks th,.stacks td{border-bottom:0;padding:0}
  /* The first cell of a stacked row is the card's title, whether the Markdown gave it a
     th or a td. hash-value's first column is a td, so keying only on th left its algorithm
     name unemphasised and unlabelled, which reads as a stray value. */
  .stacks tbody tr > :first-child{font-size:1.02rem;font-weight:620;margin-bottom:.5rem;color:inherit}
  .stacks td{margin-top:.45rem}
  /* A hash digest is 64 characters with nowhere to break. overflow-wrap:anywhere breaks
     only where a word would otherwise overflow, so prose is untouched and the digest on
     glossary/hash-value wraps instead of pushing the card 144px wide. */
  .stacks th,.stacks td{overflow-wrap:anywhere}
  .stacks td.num{text-align:left;white-space:normal}
  .stacks td[data-k]::before{
    content:attr(data-k);
    display:block;
    font-family:var(--mono);font-size:.66rem;letter-spacing:.07em;text-transform:uppercase;
    color:#8c8471;margin-bottom:.1rem
  }
  .dark-table.stacks td[data-k]::before{color:var(--muted-2)}
}

/* ---- Consent banner. Rendered only when SITE.ANALYTICS is 'ga4'. ---------------------
   Accept and Decline are deliberately IDENTICAL: same class, same size, same weight, same
   colour, side by side in source order. There is no primary button here. A consent choice
   where one option is louder than the other is not a choice, and the whole point of this
   banner is that declining costs the visitor nothing. */
.kv-consent{
  position:fixed;left:0;right:0;bottom:0;z-index:60;
  background:var(--ink-2);border-top:1px solid var(--violet);
  padding:1.1rem var(--gut);
}
.kv-consent:focus{outline:2px solid var(--violet);outline-offset:-2px}
.kv-consent-in{
  max-width:var(--maxw);margin:0 auto;
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:1.2rem;align-items:center;
}
.kv-consent h2{font-size:1rem;margin:0 0 .35rem}
.kv-consent p{font-size:.9rem;line-height:1.55;color:var(--muted);margin:0;max-width:78ch}
.kv-consent a{color:var(--cyan);text-decoration:underline;text-underline-offset:2px}
.kv-consent-btns{display:flex;gap:.6rem;flex-wrap:wrap}
.kv-consent-btn{
  font:inherit;font-size:.9rem;font-weight:560;
  padding:.6rem 1rem;border-radius:8px;cursor:pointer;white-space:nowrap;
  background:var(--ink-3);color:var(--text);border:1px solid var(--line);
}
.kv-consent-btn:hover{border-color:var(--violet)}
.kv-consent-btn:focus-visible{outline:2px solid var(--violet);outline-offset:2px}
/* The short copy is in the DOM at every width and shown at one of them. */
.kv-consent .kv-short{display:none}
@media (max-width:760px){
  .kv-consent-in{grid-template-columns:1fr}
  /* Full width and equal at 390, so neither button is easier to hit than the other. */
  .kv-consent-btns{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}
  .kv-consent-btn{width:100%;white-space:normal;padding:.6rem .5rem}
}

/* ---- Compact consent bar below 680px, 10 October 2026. ------------------------------
   THE CONSENT BEHAVIOUR IS UNCHANGED. Same dialog, same two buttons in the same source
   order, same cookie, same default of loading nothing. What shrinks is presentation: the
   full paragraph gives way to the short one, the labels drop the words that repeat the
   question, and the heading becomes the dialog's accessible name only. The reason is
   arithmetic rather than taste. At 390x844 the full banner took 325px, two fifths of the
   viewport, and a visitor cannot judge an offer they cannot see past. */
@media (max-width:680px){
  .kv-consent{padding:.75rem var(--gut) .85rem}
  /* Visually hidden, not display:none: aria-labelledby still resolves to it. */
  .kv-consent h2{
    position:absolute;width:1px;height:1px;margin:-1px;padding:0;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;
  }
  .kv-consent-in{gap:.7rem}
  .kv-consent .kv-long{display:none}
  /* The trailing words of each button label are hidden the same way the heading is, not
     with display:none. display:none would take them out of the accessibility tree too, so
     a screen reader on a phone would hear "Accept" and "Decline" with nothing to say what
     is being accepted. Hidden this way the visible label is one word and the accessible
     name is still "Accept analytics cookies". */
  .kv-consent-btn .kv-long-i{
    position:absolute;width:1px;height:1px;margin:-1px;padding:0;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;
  }
  .kv-consent-btn{position:relative}
  .kv-consent .kv-short{display:block;font-size:.88rem;line-height:1.45}
  .kv-consent-btn{padding:.62rem .5rem}
}

/* Home 2 layout draft. Prefixed so nothing here reaches the rest of the site.
   Section padding matches the hero: the rest of the site keeps the larger block rhythm. */
main:has(.home2-hero) section:not(.hero-split){padding-block:clamp(1.6rem,3.6vw,2.8rem)}
main:has(.home2-hero) section.home2-instance{
  padding-top:calc(clamp(1.6rem,3.6vw,2.8rem) + 16px);
  padding-bottom:calc(clamp(1.6rem,3.6vw,2.8rem) + 10px);
}
main:has(.home2-hero) section.home2-edrm-sec{
  padding-top:calc(clamp(1.6rem,3.6vw,2.8rem) - 50px);
}
main:has(.home2-hero) .hero-split .tmnl-hero{
  margin:-24px 0 60px;
  padding-bottom:10px;
}
main:has(.home2-hero) .hero-split .hero-grid2{margin-top:12px}
main:has(.home2-hero) section.home2-compare-sec{
  padding-top:calc(clamp(1.6rem,3.6vw,2.8rem) - 20px);
  margin-top:-24px;
}
/* /flat-rate/: the same slider sits under the calculator, without the Home 2 pulls. */
main:not(:has(.home2-hero)) .home2-compare-sec{
  padding-top:clamp(1.2rem,3vw,2rem);
  padding-bottom:clamp(1.6rem,3.6vw,2.8rem);
  margin-top:-20px;
}
@media (min-width:961px){
  main:has(.home2-hero) section.home2-compare-sec{margin-top:-32px}
}
/* /platform/ has no plans block above this, so the pull-up sits against the EDRM
   caption. Drop it 20px on that page only. Homepage still has .hero-split. */
main:has(.home2-hero):not(:has(.hero-split)) section.home2-compare-sec{
  margin-top:calc(-24px + 60px);
}
@media (min-width:961px){
  main:has(.home2-hero):not(:has(.hero-split)) section.home2-compare-sec{
    margin-top:calc(-32px + 20px);
  }
}
main:has(.home2-hero) section.home2-shot-sec{
  padding-top:8px;
  padding-bottom:calc(clamp(1.6rem,3.6vw,2.8rem) + 20px);
}
main:has(.home2-hero) .cta{margin-bottom:20px}
main:has(.home2-hero) .cta + section{margin-top:-10px}
main:has(.home2-hero) .caps{gap:2px;border-width:2px;margin-top:-12px}
main:has(.home2-hero) .caps .grp{
  background:#191c22;
  padding:calc(1.35rem + 4px) calc(1.4rem + 4px);
}
main:has(.home2-hero) .caps h3{font-size:calc(1.16rem + 2px)}
main:has(.home2-hero) .caps li{font-size:calc(1.06rem - 2px)}
main:has(.home2-hero) .caps li::before{width:9px;height:9px}
main:has(.home2-hero) .hero-link{text-underline-offset:4px}
.home2-grid{
  display:grid;
  grid-template-columns:minmax(28rem,1.4fr) minmax(16rem,.8fr);
  gap:clamp(1.6rem,4vw,3.2rem);
  align-items:center;
}
.home2-logo-m{display:none}
.home2-copy{max-width:none}
.home2-copy h1{max-width:none}
main:has(.home2-hero):has(.hero-split) .home2-copy h1{
  font-size:clamp(2.28rem,5.6vw,calc(var(--h1-max) + 4px));
}
.home2-sub{
  margin:calc(.45rem - 4px) 0 -6px;
  font-family:var(--display);
  font-optical-sizing:auto;
  font-weight:560;
  font-size:clamp(1.1rem,2.2vw,1.3rem);
  letter-spacing:.04em;
  line-height:1.25;
  color:var(--muted);
  text-transform:uppercase;
}
@media (min-width:961px){
  .home2-sub{font-size:clamp(1rem,1.6vw,1.15rem)}
}
.home2-copy .lede{font-size:clamp(1rem,1.5vw,1.12rem)}
@media (min-width:961px){
  .home2-copy .lede{font-size:clamp(.95rem,1.35vw,1.05rem)}
}
.home2-orbit-wrap{
  display:flex;justify-content:center;align-items:center;transform:translate(-32px,-12px);
  mix-blend-mode:lighten;
  text-decoration:none;color:inherit;cursor:pointer;
}
.home2-orbit{
  display:block;
  width:min(calc(100% - 6px),458px);
  height:auto;
  background:transparent;
}
.home2-edrm-fig{margin:0 auto;width:calc(100% - 54px);padding-right:0;transform:translate(-30px,4px)}
main:has(.home2-hero):has(.hero-split) .home2-edrm-fig{width:calc(100% - 44px);transform:translate(-24px,4px)}
.home2-edrm{display:block;width:100%;height:auto;margin:0}
.home2-edrm-cap{
  margin:.86rem auto 0;
  text-align:center;
  max-width:70ch;
}
.home2-edrm-title{display:block;margin-bottom:.4rem;color:var(--muted);font-size:.9rem}
.home2-edrm-attr{display:block;color:var(--muted-2);font-size:.8rem;line-height:1.46}
.home2-edrm-attr a{color:var(--cyan);text-decoration:underline;text-underline-offset:2px}
.home2-compare{margin:0}
.home2-tabs{
  display:flex;
  width:fit-content;
  margin:10px auto .96rem;
  padding:4px;
  gap:2px;
  border-radius:16px;
  background:#161b24;
  border:2px solid var(--line);
}
.home2-tab{
  appearance:none;border:0;
  background:transparent;
  color:var(--muted);
  font:inherit;font-size:.92rem;font-weight:620;
  padding:.52rem 1.16rem;
  border-radius:12px;
  cursor:pointer;
  line-height:1.2;
}
.home2-tab:hover{color:var(--text)}
.home2-tab[aria-selected=true]{
  background:#2a3140;
  color:var(--text);
}
.home2-compare-stage{
  position:relative;
  overflow:hidden;
  user-select:none;
  touch-action:none;
  cursor:ew-resize;
  --pos:50%;
}
.home2-compare-img{display:block;width:100%;height:auto}
.home2-compare > .home2-compare-img{margin-top:10px}
.home2-compare-light{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:fill;
  clip-path:inset(0 calc(100% - var(--pos)) 0 0);
}
.home2-compare-handle{
  position:absolute;top:0;bottom:0;left:var(--pos);
  width:2px;
  background:#fff;
  box-shadow:0 0 0 2px rgba(13,17,23,.28);
  transform:translateX(-50%);
  pointer-events:none;
}
.home2-compare-knob{
  position:absolute;top:50%;left:50%;
  width:48px;height:36px;
  display:grid;place-items:center;
  border-radius:12px;
  background:#fff;
  color:var(--ink);
  box-shadow:0 6px 18px rgba(13,17,23,.28);
  transform:translate(-50%,-50%);
}
.home2-compare-range{
  position:absolute;inset:0;
  width:100%;height:100%;margin:0;
  opacity:0;cursor:ew-resize;
  appearance:none;background:transparent;
}
.home2-compare-h{margin:.9rem 0 .36rem;font-size:clamp(1.36rem,2.4vw,27px)}
.home2-compare figcaption{
  margin-top:0;
  color:var(--muted-2);
  font-family:var(--mono);
  font-size:.76rem;
  letter-spacing:.10em;
  text-transform:uppercase
}
@media (max-width:960px){
  .home2-grid{grid-template-columns:1fr}
  .home2-copy{max-width:62ch}
  .home2-orbit-wrap{justify-content:flex-start}
  main:has(.home2-hero) .home2-grid{
    grid-template-areas:"logo" "bates" "orbit" "body";
    gap:.5rem;
  }
  main:has(.home2-hero) .home2-logo-m{
    display:block;
    grid-area:logo;
    width:min(66.67%,235px);
    height:auto;
    margin:0 0 0 -4px;
    padding:8px 0;
  }
  main:has(.home2-hero) .home2-copy{display:contents}
  main:has(.home2-hero) .home2-copy > .bates{
    grid-area:bates;
    margin-bottom:0;
  }
  main:has(.home2-hero) .home2-copy-body{
    grid-area:body;
    max-width:62ch;
  }
  main:has(.home2-hero):has(.hero-split) .home2-copy h1{
    font-size:clamp(1.82rem,4.4vw,calc(var(--h1-max)));
    margin-top:-1px;
  }
  main:has(.home2-hero) .home2-orbit-wrap{
    grid-area:orbit;
    justify-content:center;
    transform:none;
    padding-top:4px;
    margin-bottom:-12px;
  }
  main:has(.home2-hero) .home2-orbit{width:min(calc(50% + 40px),265px)}
  main:has(.home2-hero) section.home2-hero{padding-top:.35rem;padding-bottom:1.15rem}
  main:has(.home2-hero) section.home2-edrm-sec{display:none}
  main:has(.home2-hero) section:not(.hero-split):not(.home2-hero){
    padding-block:calc(clamp(1.6rem,3.6vw,2.8rem) + 12px);
  }
  main:has(.home2-hero) section.hero-split{
    padding-top:calc(clamp(1.9rem,4vw,2.8rem) + 20px);
    padding-bottom:calc(clamp(2.4rem,5vw,3.6rem) + 20px);
  }
  main:has(.home2-hero) .hero-split .hero-h1{margin-bottom:1rem}
  main:has(.home2-hero) .hero-split .hero-sub{margin-bottom:1.25rem}
  main:has(.home2-hero) .hero-split .plancards{gap:.85rem;margin-bottom:.85rem}
  main:has(.home2-hero) .hero-split .plancard{padding:.85rem 1rem}
  main:has(.home2-hero) .hero-split .aiaddon{padding:.85rem 1rem;margin:0 0 1.4rem}
  main:has(.home2-hero) .hero-split .hero-ctas{gap:.9rem}
  main:has(.home2-hero) section.home2-compare-sec{margin-top:-22px}
  main:has(.home2-hero):not(:has(.hero-split)) section.home2-compare-sec{margin-top:-22px}
  main:has(.home2-hero) section.home2-shot-sec{margin-top:-20px}
  main:has(.home2-hero) .cta{margin-bottom:28px}
  main:has(.home2-hero) .cta + section{margin-top:4px}
  main:has(.home2-hero) .hero-split .wrap{display:flex;flex-direction:column}
  main:has(.home2-hero) .hero-split .hero-grid2{
    margin-top:0;
    grid-template-areas:"copy" "calch" "idy" "card";
  }
  main:has(.home2-hero) .hero-split .hero-calc-h-m{
    display:block;grid-area:calch;
    padding-top:30px;
    margin:0 0 calc(10px - 1rem);
  }
  main:has(.home2-hero) .hero-split .hero-pitch{padding-bottom:0;margin-bottom:-12px}
  main:has(.home2-hero) .hero-split .heroest > .heroest-h{display:none}
  main:has(.home2-hero) .hero-split .heroest{margin-top:20px}
  main:has(.home2-hero) .hero-split .tmnl-hero{order:1;margin:calc(1.25rem + 36px) 0 0;padding-bottom:10px}
}
@media (max-width:520px){
  .home2-tabs{flex-wrap:wrap;justify-content:center;max-width:100%}
  .home2-tab{padding:.48rem .72rem;font-size:.82rem}
}
@media (prefers-reduced-motion:reduce){
  .home2-orbit-wrap{display:none}
  .home2-grid{grid-template-columns:1fr}
}
