/* Inter, self-hosted — no third-party requests, works offline */
@font-face{font-family:"Inter";font-style:normal;font-weight:400;font-display:swap;
  src:url("fonts/inter-latin-400-normal.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:450;font-display:swap;
  src:url("fonts/inter-latin-400-normal.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:500;font-display:swap;
  src:url("fonts/inter-latin-500-normal.woff2") format("woff2")}
@font-face{font-family:"Inter";font-style:normal;font-weight:600;font-display:swap;
  src:url("fonts/inter-latin-600-normal.woff2") format("woff2")}

:root{
    --ink:#101B16; --ink-2:#3B4741; --muted:#75817A;
    --paper:#FFFFFF; --off:#F6F5F1; --sand:#EDEAE2;
    --line:#E1DDD3; --line-2:#CFC9BC;
    --brand:#1D4438; --brand-d:#14332A; --brand-l:#E8F0EC;
    --accent:#B4894A;
    --max:1240px;
  }
  *{box-sizing:border-box;margin:0;padding:0}
  html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
  body{background:var(--paper);color:var(--ink);
    font:400 17px/1.7 "Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;
    -webkit-font-smoothing:antialiased;letter-spacing:-.002em}
  h1,h2,h3,h4{font-weight:600;letter-spacing:-.022em;line-height:1.13}
  a{color:inherit;text-decoration:none}
  .wrap{max-width:var(--max);margin:0 auto;padding:0 40px}
  @media(max-width:700px){.wrap{padding:0 22px}}
  section{padding:72px 0}
  /* SEPARATION TRIAL (independent of the padding change above).
     With the cream bands gone, padding alone gives space but no edge, so
     consecutive white sections read as one undifferentiated column. A hairline
     is a 1.36:1 divider -- stronger than the cream band it replaced (1.09:1) --
     and reads as editorial rule rather than a colour block.
     Applies only between two light sections: not before a .dark section, not
     on the first section after the hero.
     TO REMOVE: delete this block. Nothing else depends on it. */
  section + section:not(.dark){border-top:1px solid var(--line)}
  section.dark + section{border-top:none}
  /* STEP 1 TRIAL: cream section bands switched off. White vs cream measured
     1.09:1 -- weaker than the 1.36:1 hairline rules -- so the bands created
     seams without signalling structure. Structure now comes from spacing and
     rules instead. TO REVERT: .off{background:var(--off)}
     The .off class is still on the sections, so this is the only line to change. */
  .off{background:var(--paper)}
  .dark{background:var(--brand);color:#F0F4F1}
  .eyebrow{font-size:11.5px;letter-spacing:.19em;text-transform:uppercase;color:var(--brand);font-weight:600;margin-bottom:18px}
  .dark .eyebrow{color:#9FC0AE}
  h2{font-size:clamp(29px,3.7vw,44px);max-width:20ch}
  h2.w{max-width:28ch}
  .lede{font-size:19px;color:var(--ink-2);line-height:1.72;max-width:62ch;margin-top:18px}

  /* Private-label comparison. Green header like the pricing ladders, our column
     tinted so the eye knows which side it is being sold, and the label column on
     the off-white so the three-way read stays clear. */
  .cmp-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;margin-top:40px;
    border:1px solid var(--line);background:var(--paper);max-width:1000px}
  .cmp{width:100%;min-width:640px;border-collapse:collapse}
  .cmp th,.cmp td{text-align:left;padding:15px 22px;font-size:16px;line-height:1.5;
    border-top:1px solid var(--line);vertical-align:top}
  .cmp th{background:var(--brand);color:#fff;border-top:none;font-size:10.5px;
    letter-spacing:.14em;text-transform:uppercase;font-weight:600;padding-top:11px;padding-bottom:11px}
  .cmp td:first-child{background:var(--off);color:var(--ink);font-weight:500;width:30%}
  .cmp td:nth-child(2){color:var(--muted);width:33%}
  .cmp td:last-child{background:var(--brand-l);color:var(--brand);font-weight:600}
  .cmp th:last-child{background:var(--brand-d)}

  .cmp-close{margin-top:34px;max-width:70ch;font-size:17.5px;line-height:1.72;color:var(--ink)}

  @media(max-width:820px){
    .cmp th,.cmp td{padding:13px 16px;font-size:15px}
    .cmp-close{font-size:16.5px;margin-top:28px}
  }
  .dark .lede{color:#BFD2C6}
  .sig{height:72px;width:auto;max-width:300px;display:block;margin:26px 0 6px}
  .form-success{background:var(--brand-l);border:1px solid #C7DBCF;border-radius:6px;padding:30px 32px}
  .form-success h3{color:var(--brand);font-size:20px;margin-bottom:10px}
  .form-success p{color:var(--ink-2);font-size:16px;line-height:1.65}
  .form-error{color:#A3341F;font-size:14.5px;margin-top:16px}

  /* ---------- learn topic index ---------- */
  .topicnav{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
  .topicnav a{display:inline-flex;align-items:center;gap:9px;font-size:15px;font-weight:500;color:var(--brand);
    background:var(--brand-l);border:1px solid #CADDD1;border-radius:100px;padding:11px 20px;transition:background .15s,border-color .15s}
  .topicnav a:hover{background:#DCE8E0;border-color:#AFC8BB}
  .topicnav a::after{content:"↓";font-size:12px;opacity:.55}
  section[id]{scroll-margin-top:96px}
  .sm{font-size:14.5px} .muted{color:var(--muted)}
  p+p{margin-top:16px}
  .link{color:var(--brand);font-weight:500;border-bottom:1px solid #B9CEC2;padding-bottom:2px}
  .link:hover{border-color:var(--brand)}
  .dark .link{color:#fff;border-color:rgba(255,255,255,.4)}
  /* STEP 2: a section promoted to brand green. Headings inherit .dark's light
     colour, which is right for the section itself but wrong inside the white
     cards sitting on it -- those need re-anchoring to the light-ground palette,
     and their link has to win back the brand colour that .dark .link takes. */
  .dark .card,.dark .box,.dark .note,.dark .step-card,.dark .route{color:var(--ink)}
  /* On a white ground a 1px hairline is enough to define a card. On green it is
     not: a borderless white slab reads as a hole cut in the panel rather than an
     object resting on it. Elevation is what sells it -- a two-layer shadow
     (tight contact + wide ambient) in the same idiom as the co-packing cards,
     deepened because the ground underneath is dark. */
  .dark .card,.dark .box{border-color:transparent;
    box-shadow:0 2px 6px -3px rgba(0,0,0,.35), 0 22px 42px -28px rgba(0,0,0,.75)}
  .dark .card{transition:transform .18s ease, box-shadow .18s ease}
  .dark .card:hover{transform:translateY(-3px);
    box-shadow:0 4px 10px -4px rgba(0,0,0,.4), 0 28px 52px -26px rgba(0,0,0,.8)}
  .dark .card p,.dark .box p,.dark .note p{color:var(--ink-2)}
  .dark .card .link,.dark .box .link,.dark .note .link{color:var(--brand);border-color:#B9CEC2}

  /* ---------- market outlook (Learn) ---------- */
  .mkt{background:var(--off);color:var(--ink);padding:88px 0}
  .mkt .eyebrow{color:var(--brand)}
  .mkt h2{color:var(--ink);max-width:15ch}
  .mkt .sub{color:var(--ink-2);font-size:17px;line-height:1.7;margin-top:16px;max-width:46ch}
  .mkt-cagr{margin-top:24px;font-size:16.5px;color:var(--ink-2)}
  .mkt-cagr strong{color:var(--brand);font-weight:800}
  .mkt-top{display:grid;grid-template-columns:0.9fr 1.1fr;gap:56px;align-items:center}
  .mkt-plot{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;align-items:end;border-bottom:1px solid var(--line-2)}
  .bcol{display:flex;flex-direction:column;justify-content:flex-end}
  .bcol .val{font:900 clamp(28px,3vw,42px)/1 "Arial Black","Helvetica Neue",Helvetica,sans-serif;color:var(--ink);text-align:center;margin-bottom:14px;letter-spacing:-.01em}
  .bcol .bar{width:100%;background:#8FB5A2;border-radius:9px 9px 0 0}
  .bcol.big .bar{background:var(--brand)}
  .mkt-legend{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:16px}
  .mkt-legend .yr{font-weight:700;font-size:15px;color:var(--ink)}
  .mkt-legend .cap{font-size:13px;color:var(--muted);line-height:1.5;margin-top:4px}
  .mkt-foot{margin-top:54px;max-width:76ch}
  .mkt-foot p{color:var(--ink-2);font-size:16.5px;line-height:1.72}
  .mkt-foot p.mkt-note{margin-top:16px;font-size:12px;color:var(--muted);letter-spacing:.04em}
  @media(max-width:860px){
    .mkt{padding:64px 0}
    .mkt-top{grid-template-columns:1fr;gap:36px}
    .mkt h2,.mkt .sub{max-width:none}
  }

  /* ---------- utility bar ---------- */
  .util{background:var(--ink);color:#A9B4AD;font-size:13px;padding:10px 0}
  .util .wrap{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}
  .util b{color:#fff;font-weight:500}
  .util a:hover{color:#fff}

  /* ---------- header ---------- */
  header{position:sticky;top:0;z-index:80;background:#fff;border-bottom:1px solid var(--line)}
  nav{display:flex;align-items:center;justify-content:space-between;height:82px;gap:30px}
  .brand{display:flex;align-items:center}
  /* The whole lockup -- mark and wordmark -- is one supplied image, so nothing
     here re-sets the type. Sized by height only; the 533x256 intrinsic size on
     the <img> holds the box before it loads so the bar can't reflow.
     Two files rather than one recoloured asset: the mark is brand green and the
     wordmark black on the white header, and a single-colour mask can't paint
     both. Both ship in the markup so the green-header swap below has nothing
     left to fetch mid-transition. */
  .logo{display:block;width:auto;height:64px}
  .brand .logo-alt{display:none}
  .nav-r{display:flex;align-items:center;gap:34px}
  .nav-r>a:not(.btn){font-size:15px;color:var(--ink-2);font-weight:450;padding:6px 0;border-bottom:2px solid transparent}
  .nav-r>a:not(.btn):hover{color:var(--brand);border-color:var(--brand)}
  /* .btn and friends set their own display, which beats the browser's [hidden]
     rule - so hidden was being set in JS and ignored on screen. Author-level and
     !important so nothing can out-specify it. */
  [hidden]{display:none !important}
  .btn{display:inline-flex;align-items:center;gap:9px;background:var(--brand);color:#fff;
    padding:14px 26px;border-radius:2px;font-size:15px;font-weight:500;transition:background .18s;white-space:nowrap}
  .btn:hover{background:var(--brand-d);color:#fff}
  .btn.o{background:transparent;color:var(--brand);border:1px solid var(--line-2)}
  .btn.o:hover{background:var(--off);color:var(--brand)}
  .btn.w{background:#fff;color:var(--brand)} .btn.w:hover{background:var(--brand-l)}
  .btn.lg{padding:17px 34px;font-size:16px}
  @media(max-width:1080px){.nav-r>a:not(.btn){display:none}}
  @media(max-width:560px){
    nav{height:70px;gap:14px}
    .logo{height:50px}
    .btn{padding:12px 18px;font-size:14px}
  }

  /* ---------- hero ---------- */
  .hero{position:relative;min-height:560px;display:flex;align-items:center;
    background:var(--brand);overflow:hidden}
  .hero-img{position:absolute;inset:0;
    background:repeating-linear-gradient(45deg,#1D4438 0 22px,#1B3F34 22px 44px);
    display:flex;align-items:flex-end;justify-content:flex-end;padding:0 44px 30px}
  .hero-img span{color:rgba(255,255,255,.38);font-size:12px;letter-spacing:.14em;text-transform:uppercase;text-align:right;line-height:1.95}
  @media(max-width:940px){.hero-img{padding:0 22px 20px}
    .hero-img span{font-size:10px;color:rgba(255,255,255,.22);line-height:1.8}}
  .hero-scrim{position:absolute;inset:0;background:linear-gradient(100deg,rgba(16,27,22,.93) 0%,rgba(16,27,22,.82) 46%,rgba(16,27,22,.32) 100%)}
  .hero-in{position:relative;z-index:2;padding-top:96px;padding-bottom:96px}
  .hero h1{font-size:clamp(36px,4.9vw,60px);color:#fff;max-width:19ch;line-height:1.1}
  .hero p{font-size:19.5px;color:#C6D6CC;max-width:54ch;margin-top:24px;line-height:1.68}
  .hero .row{display:flex;flex-wrap:wrap;gap:14px;margin-top:38px}

  /* ---------- stats strip ---------- */
  .stats{background:var(--ink);color:#fff}
  .stats .wrap{display:grid;grid-template-columns:repeat(4,1fr)}
  .stat{padding:38px 38px;border-left:1px solid rgba(255,255,255,.13)}
  .stat:first-child{border-left:none;padding-left:0}
  .stat:last-child{padding-right:0}
  .stat b{display:block;font-size:34px;font-weight:600;letter-spacing:-.025em;line-height:1}
  .stat span{display:block;font-size:13.5px;color:#9AA8A0;margin-top:12px;line-height:1.45;max-width:20ch}
  @media(max-width:1080px){.stat{padding:34px 28px}.stat b{font-size:30px}}
  @media(max-width:860px){
    .stats .wrap{grid-template-columns:1fr 1fr}
    .stat{padding:28px 28px}
    .stat:nth-child(2n+1){padding-left:0;border-left:none}
    .stat:nth-child(2n){padding-right:0}
    .stat:nth-child(1),.stat:nth-child(2){border-bottom:1px solid rgba(255,255,255,.13);padding-top:34px}
    .stat:nth-child(3),.stat:nth-child(4){padding-bottom:34px}
  }
  /* Deliberately stays 2x2 on the narrowest screens rather than collapsing to
     a single column. Four stacked rows pushed the strip to ~470px tall, which
     buried the top of the page under a column of numbers before the reader
     reached any content. The 2x2 halves that at no cost to legibility -- the
     figures are short and the captions wrap happily in half the width. */
  @media(max-width:470px){
    .stat{padding:20px 14px}
    .stat b{font-size:25px}
    .stat span{font-size:12.5px;margin-top:7px;max-width:none}
    .stat:nth-child(1),.stat:nth-child(2){padding-top:26px}
    .stat:nth-child(3),.stat:nth-child(4){padding-bottom:26px}
  }

  /* ---------- intro split ---------- */
  .split{display:grid;grid-template-columns:1fr 1.05fr;gap:70px;align-items:center}
  .split.rev{grid-template-columns:1.05fr 1fr}
  @media(max-width:940px){
    .split,.split.rev{grid-template-columns:1fr;gap:38px}
    /* `.rev` exists to put the photo on the LEFT on wide screens, so its photo
       comes first in the markup. Stacked, that lands two photos back to back
       between the two blocks of copy. Sending the photo below its own text
       restores the intended text-photo-text-photo rhythm down the page. */
    .split.rev>:first-child{order:2}
  }

  /* ---------- image placeholders ---------- */
  .img{background:var(--sand);border:1px solid var(--line);position:relative;overflow:hidden;
    display:flex;align-items:center;justify-content:center;text-align:center;padding:26px}
  .img:before{content:'';position:absolute;inset:0;
    background:repeating-linear-gradient(45deg,transparent 0 13px,rgba(0,0,0,.028) 13px 26px)}
  .img em{position:relative;font-style:normal;color:#8A9088;font-size:12.5px;letter-spacing:.11em;
    text-transform:uppercase;line-height:2.1;max-width:24ch}
  .img.r4{aspect-ratio:4/3} .img.r1{aspect-ratio:1/1} .img.r16{aspect-ratio:16/9}
  .img.r21{aspect-ratio:21/9} .img.r34{aspect-ratio:3/4}

  /* ---------- solution cards ---------- */
  .cards{display:grid;grid-template-columns:repeat(4,1fr);gap:26px;margin-top:52px}
  @media(max-width:1000px){.cards{grid-template-columns:1fr 1fr}}
  @media(max-width:620px){.cards{grid-template-columns:1fr}}
  .card{background:#fff;border:1px solid var(--line);display:flex;flex-direction:column;transition:border-color .2s}
  .card:hover{border-color:var(--line-2)}
  .off .card{background:#fff}
  .card .img{border:none;border-bottom:1px solid var(--line)}
  .card-b{padding:26px 26px 30px;flex:1;display:flex;flex-direction:column}
  .card h3{font-size:19px;margin-bottom:10px}
  .card p{font-size:15.5px;color:var(--ink-2);flex:1}
  .card .link{margin-top:18px;align-self:flex-start;font-size:14.5px}

  /* Guide cards with no article behind them yet. Not anchors, so the hover
     lift and the "Read" affordance both have to go -- a card that looks
     clickable and isn't is worse than one that plainly says it's not ready. */
  .card.soon{cursor:default}
  .card.soon:hover{border-color:var(--line)}
  .card.soon .ph img{filter:grayscale(1);opacity:.55}
  .soon-tag{margin-top:18px;align-self:flex-start;font-size:11px;letter-spacing:.13em;
    text-transform:uppercase;color:var(--muted);font-weight:600}

  /* ---------- feature rows ---------- */
  .feat{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:center;padding:52px 0;border-top:1px solid var(--line)}
  .feat:first-of-type{border-top:none}
  /* Feature rows alternate on desktop, so every other one leads with the image.
     Once they stack, that source order puts a photo above the copy on one row
     and below it on the next -- the same section reading differently each time.
     Force the image last in every stacked row so the pattern is copy then
     picture throughout, whatever the desktop order was. */
  @media(max-width:940px){
    .feat{grid-template-columns:1fr;gap:32px}
    .feat>.ph{order:2}
  }
  .feat h3{font-size:26px;margin-bottom:14px}
  .feat p{color:var(--ink-2)}
  .feat ul{list-style:none;margin-top:20px}
  .feat li{font-size:16px;padding:11px 0 11px 26px;position:relative;border-top:1px solid var(--line);color:var(--ink-2)}
  .feat li:first-child{border-top:none}
  .feat li:before{content:'';position:absolute;left:2px;top:20px;width:8px;height:1px;background:var(--brand)}

  /* ---------- spec table in cards ---------- */
  .spec{margin-top:22px;border-top:1px solid var(--line)}
  .spec div{display:flex;justify-content:space-between;gap:16px;padding:11px 0;border-bottom:1px solid var(--line);font-size:15px}
  .spec div span:first-child{color:var(--muted)}
  .spec div span:last-child{font-weight:500}

  /* ---------- pricing ---------- */
  .pb{background:#fff;border:1px solid var(--line);margin-top:26px}
  .off .pb{background:#fff}
  .pb h3{font-size:19px;padding:26px 30px 0}
  .pb .sub{font-size:14.5px;color:var(--muted);padding:9px 30px 20px;max-width:82ch}
  /* Accordions inside a .pb card: base `details` has no horizontal padding,
     so without this the summary text sits hard against the card border. */
  .pb details{padding-left:30px;padding-right:30px}
  .pb details:last-child{border-bottom:none}
  table{width:100%;border-collapse:collapse}
  th,td{text-align:left;padding:15px 30px;font-size:15.5px;border-top:1px solid var(--line)}
  th{font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);font-weight:600;background:var(--off)}
  td.n{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
  td.s{text-align:right;font-variant-numeric:tabular-nums;color:var(--muted);font-size:14.5px}
  tr.hi td{background:var(--brand-l)}
  /* The two batch ladders. Own class because they want a heavier header than the
     rest of the site's tables, and because auto layout can't hold them: the
     "stepping up" strings are long and unbreakable enough to push the last
     column clean past the card's right edge. Fixed columns, widths off the
     header row. */
  .ladder{table-layout:fixed}
  .ladder th{background:var(--brand);color:#fff;border-top:none;padding-top:14px;padding-bottom:14px;
    font-size:10.5px;letter-spacing:.14em}
  .ladder th,.ladder td{padding-left:14px;padding-right:14px}
  /* The label column carries a batch size plus a tag; give it the room or
     "24,000 capsules" and its MOST COMMON badge wrap onto two lines and that
     one row grows 24px taller than the rest. */
  .ladder th:first-child,.ladder td:first-child{padding-left:30px;width:38%;white-space:nowrap}
  .ladder th:nth-child(2),.ladder td:nth-child(2){width:15%}
  .ladder th:nth-child(3),.ladder td:nth-child(3){width:19%}
  .ladder th:last-child,.ladder td:last-child{padding-right:30px;width:28%}

  /* The struck list price has to read as a price that was really there -- same
     tabular figures as the rest, just dimmed -- or the saving looks like
     decoration. "You pay" carries the weight instead. */
  td.was{text-align:right;font-variant-numeric:tabular-nums;color:var(--muted);font-size:14.5px}
  td.pay{text-align:right;font-variant-numeric:tabular-nums;font-weight:600;font-size:17px;
    color:var(--brand)}
  td.stepup{text-align:right;font-variant-numeric:tabular-nums;color:var(--muted);font-size:14px}

  /* Sale banner. Has to read as a promotion without leaving the palette, so:
     brand-green ground, the date on an accent pill, the figure set large. The
     accent is used here and nowhere else on the page, which is what stops it
     looking like a third-party ad dropped into the layout. */
  .sale{background:var(--brand);color:#fff;padding:32px 34px;margin-top:6px}
  .sale-tag{display:inline-block;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
    font-weight:600;color:var(--ink);background:var(--accent);padding:5px 11px}
  .sale h2{font-size:clamp(26px,3.2vw,34px);line-height:1.15;color:#fff;margin:16px 0 0;
    max-width:none;letter-spacing:-.02em}
  /* Wide enough to hold the offer sentence on one line at desktop; it still
     wraps naturally on narrower screens. */
  .sale p{margin:13px 0 0;font-size:15.5px;line-height:1.7;color:#C3CFC8;max-width:92ch}

  .pnote{background:var(--off);padding:26px 30px;margin-top:26px}
  /* With the descriptor line gone these cards are just a title and a table, so
     the h3 has to carry the gap the paragraph used to. */
  .ladcard h3{padding-bottom:20px}
  .pnote p{font-size:15.5px;line-height:1.7;color:var(--ink-2);max-width:74ch}
  .pnote p+p{margin-top:15px}
  .pnote strong{color:var(--ink);font-weight:600}

  .tag{display:inline-block;font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:#fff;
    background:var(--brand);padding:3px 8px;margin-left:9px;vertical-align:2px;font-weight:600}
  @media(max-width:820px){
    .g2>*,.g3>*,.cards>*,.feat>*,.steps>*,.split>*{min-width:0}
    table{display:block;max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}
    th,td{padding:13px 18px;font-size:14.5px}
    .pb h3,.pb .sub,.pb details{padding-left:18px;padding-right:18px}
    .sale{padding:26px 20px}
    .pnote{padding:22px 18px}
    td.pay{font-size:15.5px}
    .ladder{table-layout:auto;min-width:600px}
    .ladder th,.ladder td{width:auto;padding-left:14px;padding-right:14px}
    .ladder th:first-child,.ladder td:first-child{padding-left:18px;width:auto}
    .ladder th:last-child,.ladder td:last-child{padding-right:18px;width:auto}
  }

  .ex{background:var(--ink);color:#C3CFC8;padding:44px 46px;margin-top:34px}
  .ex h3{color:#fff;font-size:22px;margin-bottom:8px}
  .ex .s{font-size:14.5px;color:#8FA096;margin-bottom:26px}
  /* The example is three quotes side by side now, so it needs a table rather
     than label/value rows. Base table styling assumes a light card, so every
     colour and border is reset here. */
  .extw{overflow-x:auto;-webkit-overflow-scrolling:touch}
  /* Only meaningful where the table scrolls, so it is off at desktop widths. */
  .extw-hint{display:none}
  .extab{width:100%;min-width:540px}
  .extab th,.extab td{padding:13px 0 13px 24px;text-align:right;white-space:nowrap;
    font-size:15.5px;font-variant-numeric:tabular-nums;border-top:1px solid rgba(255,255,255,.11)}
  .extab th{background:none;border-top:none;padding-top:0;padding-bottom:12px;
    color:#8FA096;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600}
  .extab th:first-child,.extab td:first-child{text-align:left;padding-left:0;white-space:normal}
  .extab tbody tr.t td{border-top:1px solid rgba(255,255,255,.4);font-weight:600;color:#fff}
  .extab tbody tr.big td{font-size:20px;padding-top:16px;padding-bottom:16px}
  /* The list price the £500 came off, struck, sitting under what they pay --
     so the offer is visible in the example and not only in the ladder above. */
  .extab td small{display:block;margin-top:3px;font-size:12px;color:#6F8078;
    text-decoration:line-through}
  /* Same sub-line slot as the struck list price above, but this one is a live
     figure rather than a crossed-out one, so the strike has to come back off.
     Slightly brighter than the struck price for the same reason. */
  .extab td small.rate{text-decoration:none;color:#8FA096}
  .exf{margin-top:26px;font-size:15px;color:#8FA096;line-height:1.7;max-width:74ch}
  .exf b{color:#fff;font-weight:600}

  /* ---------- process (timeline) ----------
     Numbered dots on a rail down the left, cards all to the right of it.
     Deliberately static: every dot is filled and ringed from first paint,
     no scroll-activated state change, no reveal animation.
     --step-gap is the half-gap between rows (i.e. the box spacing).
     --dot-shift nudges the whole dot column and rail down without touching it.
     Each dot then gets its own extra drop, hand-tuned per segment. Because
     the boxes never move, a segment's length is the box pitch plus the
     difference between the two dots' drops:
       dot 1 +0, dot 2 +3  ->  1>2 is 3px longer
       dot 2 +3, dot 3 +5  ->  2>3 is 2px longer
       dot 3 +5, dot 4 +5  ->  3>4 is unchanged
     Per row, --dot-extra is this dot's drop, --dot-next is the next dot's. */
  .steps{counter-reset:s;margin-top:52px;position:relative;--step-gap:16px;--dot-shift:6px}
  .step{--dot-extra:0px;--dot-next:0px}
  .step:nth-child(1){--dot-extra:0px;--dot-next:3px}
  .step:nth-child(2){--dot-extra:3px;--dot-next:5px}
  .step:nth-child(3){--dot-extra:5px;--dot-next:5px}
  .step:nth-child(4){--dot-extra:5px}
  /* Rail: one segment per row, from this dot's centre (gap + shift + this
     row's drop + half the 48px dot) down to the next dot's centre.
     Last row: no segment. */
  .step:before{content:'';position:absolute;left:23px;
    top:calc(var(--step-gap) + var(--dot-shift) + var(--dot-extra) + 24px);
    bottom:calc(-1 * (var(--step-gap) + var(--dot-shift) + var(--dot-next) + 24px));
    width:2px;background:var(--brand);z-index:0}
  .step:last-child:before{display:none}
  .step{counter-increment:s;position:relative;padding:var(--step-gap) 0;min-height:96px}
  .step-dot{position:absolute;left:0;top:calc(var(--step-gap) + var(--dot-shift) + var(--dot-extra));width:48px;height:48px;border-radius:50%;
    background:var(--brand);border:1px solid var(--brand);display:flex;align-items:center;justify-content:center;
    z-index:2;box-shadow:0 0 0 6px rgba(29,68,56,.10),0 1px 3px rgba(16,27,22,.08)}
  .step-dot:before{content:counter(s);font-size:15px;font-weight:600;color:#fff;line-height:1;letter-spacing:-.01em}
  .step-card{margin-left:96px;width:calc(100% - 96px);max-width:780px;background:#fff;border:1px solid var(--line);
    padding:26px 28px 28px;box-shadow:0 2px 8px rgba(16,27,22,.04)}
  .off .step-card{background:#fff}
  .step h3{font-size:18px;margin-bottom:9px}
  .step p{font-size:15.5px;color:var(--ink-2)}
  @media(max-width:820px){
    .step-card{margin-left:68px;width:calc(100% - 68px);max-width:none}
  }
  @media(max-width:700px){
    .step-card{padding:22px 20px 24px}
  }

  /* ---------- accreditation strip ---------- */
  .accs{display:grid;grid-template-columns:repeat(5,1fr);gap:20px;margin-top:44px}
  @media(max-width:940px){.accs{grid-template-columns:repeat(2,1fr)}}
  .acc{border:1px solid var(--line);background:#fff;aspect-ratio:5/3;display:flex;align-items:center;justify-content:center;
    text-align:center;padding:16px;color:#8A9088;font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;line-height:1.9}

  /* ---------- notes / redlines ---------- */
  .note{background:#fff;border:1px solid var(--line);border-left:3px solid var(--brand);padding:34px 38px;margin-top:36px}
  .off .note{background:#fff}
  .note p{font-size:16.5px;color:var(--ink-2)}
  .redl{background:#FBF7F0;border:1px solid #E8DCC6;padding:34px 38px;margin-top:36px}
  .redl ul{list-style:none}
  .redl li{padding:16px 0 16px 26px;position:relative;border-top:1px solid #EFE5D3;font-size:16px;color:#4B4132}
  .redl li:first-of-type{border-top:none}
  .redl li:before{content:'';position:absolute;left:2px;top:26px;width:9px;height:1px;background:var(--accent)}
  .redl b{color:#7A5A28}

  details{border-bottom:1px solid var(--line);padding:24px 0}
  details summary{cursor:pointer;list-style:none;font-size:18px;font-weight:500;display:flex;justify-content:space-between;gap:26px;align-items:flex-start}
  details summary::-webkit-details-marker{display:none}
  details summary:after{content:"+";color:var(--brand);font-size:23px;line-height:1;font-weight:300;flex:none}
  details[open] summary:after{content:"–"}
  details p{margin-top:15px;font-size:16px;color:var(--ink-2);max-width:76ch}

  .g2{display:grid;grid-template-columns:1fr 1fr;gap:30px;margin-top:46px}
  .g3{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:46px}
  @media(max-width:880px){.g2,.g3{grid-template-columns:1fr;gap:22px}}

  /* ---------- swipeable pair (Two ways to bring your product to life) ----------
     Two long boxes stacked on a phone make the second one a scroll-discovery:
     you read path 1 and may never learn path 2 exists. Side-by-side swipe keeps
     them as what they are -- a choice between two options -- and mirrors the
     card carousel already used on the homepage. Same bleed-and-restore trick so
     a panel can run to the screen edge without breaking .wrap's gutter. */
  @media(max-width:880px){
    .g2.swipe{display:flex;grid-template-columns:none;gap:14px;
      overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
      margin-left:-22px;margin-right:-22px;padding:2px 22px 16px;scroll-padding-left:22px;
      scrollbar-width:none;-ms-overflow-style:none}
    .g2.swipe::-webkit-scrollbar{display:none}
    .g2.swipe>.box{flex:0 0 86%;min-width:0;scroll-snap-align:start}
    .g2.swipe:focus-visible{outline:2px solid var(--brand);outline-offset:3px}
  }
  @media(max-width:360px){
    .g2.swipe{margin-left:-16px;margin-right:-16px;padding-left:16px;padding-right:16px;
      scroll-padding-left:16px}
    .g2.swipe>.box{flex:0 0 90%}
  }
  .box{background:#fff;border:1px solid var(--line);padding:34px}
  .off .box{background:#fff}
  .box h3{font-size:20px;margin-bottom:12px}
  .box p{font-size:16px;color:var(--ink-2)}
  .box ul{list-style:none;margin-top:18px}
  .box li{font-size:15.5px;padding:10px 0 10px 24px;position:relative;border-top:1px solid var(--line);color:var(--ink-2)}
  .box li:first-child{border-top:none}
  .box li:before{content:'';position:absolute;left:2px;top:19px;width:8px;height:1px;background:var(--brand)}

  /* ---------- contact bar ---------- */
  .cbar{display:grid;grid-template-columns:repeat(3,1fr);border:1px solid var(--line);background:#fff;margin-top:46px}
  .cb{padding:30px 32px;border-right:1px solid var(--line)}
  .cb:last-child{border-right:none}
  .cb .l{font-size:11px;letter-spacing:.15em;text-transform:uppercase;color:var(--muted);font-weight:600}
  .cb b{display:block;font-size:19px;margin-top:9px;font-weight:600}
  .cb span{font-size:14.5px;color:var(--muted)}
  @media(max-width:780px){.cbar{grid-template-columns:1fr}.cb{border-right:none;border-bottom:1px solid var(--line)}.cb:last-child{border-bottom:none}}

  /* ---------- footer ---------- */
  footer{background:var(--ink);color:#909C94;padding:80px 0 46px;font-size:14.5px}
  .fg{display:grid;grid-template-columns:2.2fr 1fr 1fr 1fr;gap:46px}
  @media(max-width:880px){.fg{grid-template-columns:1fr 1fr;gap:34px}}
  footer h4{color:#fff;font-size:11.5px;letter-spacing:.15em;text-transform:uppercase;font-weight:600;margin-bottom:18px}
  footer a{color:#909C94;display:block;padding:6px 0}
  footer a:hover{color:#fff}
  /* Not a link, but it sits in a column of them, so it takes their colour and
     rhythm without the hover. */
  footer .faddr{color:#909C94;display:block;padding:6px 0;line-height:1.55}
  /* Companies Act trading disclosure. Quieter than the copyright beside it -
     it has to be present and findable, not prominent. */
  /* Dots sit outside the anchors, in a dimmer colour, so the three links read as
     a list rather than one run-on sentence. */
  .flegal{color:#5F6B65}
  .flegal a{color:#909C94;display:inline;padding:0}
  .flegal a:hover{color:#fff}
  .fco{color:#6F7B75;font-size:12.5px;line-height:1.6;max-width:70ch}
  .faddr-l{display:block;font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;
    color:#6F7B75;margin-bottom:3px}
  .fbot{margin-top:60px;padding-top:30px;border-top:1px solid #262F2A;display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:13.5px;color:#6C776F}
  .draft{background:var(--accent);color:#231A0C;font-size:13px;padding:9px 0;text-align:center;font-weight:500}

  /* ================= ADDITIONS FOR THE MULTI-PAGE SITE ================= */

  /* real photographs -- replaces the placeholder .img blocks */
  .ph{position:relative;overflow:hidden;background:var(--sand);border:1px solid var(--line)}
  .ph img{display:block;width:100%;height:100%;object-fit:cover}
  .ph.r4{aspect-ratio:4/3} .ph.r1{aspect-ratio:1/1} .ph.r16{aspect-ratio:16/9}
  .ph.r21{aspect-ratio:21/9} .ph.r34{aspect-ratio:3/4} .ph.r32{aspect-ratio:3/2}
  .card .ph{border:none;border-bottom:1px solid var(--line)}
  .cap{font-size:13px;color:var(--muted);margin-top:10px}

  /* page hero band on inner pages */
  .phero{background:var(--brand);color:#fff;padding:74px 0 78px;position:relative;overflow:hidden}
  .phero:before{content:'';position:absolute;inset:0;background:url("img/hero.jpg") center/cover no-repeat;opacity:.2}
  .phero .wrap{position:relative;z-index:2}
  .phero .eyebrow{color:#9FC0AE}
  .phero h1{font-size:clamp(32px,3.9vw,48px);color:#fff;max-width:20ch;line-height:1.12}
  .phero p{font-size:18.5px;color:#C6D6CC;max-width:60ch;margin-top:20px;line-height:1.66}

  /* active nav item */
  .nav-r>a.on{color:var(--brand);border-color:var(--brand)}

  /* ---------- header colour swap ----------
     White header while it sits over the green hero; brand green once the hero
     is behind you. Crossing that boundary in EITHER direction plays one move:
     the bar tucks up, recolours while out of sight, and slides back down. The
     bar is not tied to scroll direction, so the green version arrives as you
     scroll down past the hero rather than waiting for you to scroll back up.

     Easing is easeOutQuint on the return -- the curve IM8 use for nearly every
     motion on their site -- against a shorter accelerating exit, so the bar
     leaves briskly and settles softly. Durations live here as custom
     properties and scripts.js reads them back, so the JS timing can never
     drift out of sync with the CSS. */
  header{
    --hdr-hide:288ms; --hdr-show:504ms;
    /* Returning is the move you watch, so it is the slower, softer one. */
    transition:transform var(--hdr-show) cubic-bezier(.22,1,.36,1)}
  /* NB: deliberately no `will-change`/`backface-visibility` here. Those pin the
     header to its own GPU layer permanently, which drops the nav text from
     subpixel (ClearType) to greyscale antialiasing and makes it look flattened.
     The browser promotes the layer on its own for the duration of a transform
     transition, so the slide stays smooth without costing text quality. */
  /* Nothing animates until the first scroll, so the bar can't slide on load. */
  header:not(.hdr-ready){transition:none}
  header.hdr-away{
    transform:translate3d(0,-100%,0);
    pointer-events:none;
    transition:transform var(--hdr-hide) cubic-bezier(.55,0,.85,.35)}
  header.hdr-green{background:var(--brand);border-bottom-color:rgba(255,255,255,.16)}
  header.hdr-green .brand .logo-main{display:none}
  header.hdr-green .brand .logo-alt{display:block}
  header.hdr-green .nav-r>a:not(.btn){color:#D3E1D8}
  header.hdr-green .nav-r>a:not(.btn):hover,
  header.hdr-green .nav-r>a.on{color:#fff;border-color:#fff}
  header.hdr-green .btn{background:#fff;color:var(--brand)}
  header.hdr-green .btn:hover{background:var(--brand-l);color:var(--brand)}
  header.hdr-green .burger{color:#fff}
  @media(max-width:1080px){
    header.hdr-green .nav-r{background:var(--brand);border-bottom-color:rgba(255,255,255,.16)}
    header.hdr-green .nav-r>a:not(.btn){border-top-color:rgba(255,255,255,.16)}
  }
  @media(prefers-reduced-motion:reduce){
    header{transition:none}
  }

  /* ---------- mobile nav ----------
     Icon rather than a bordered "Menu" box: the box read as a button and so
     competed with the real CTA sitting beside it. Bare icon steps out of that
     fight. 44x44 keeps the tap target at the accessible minimum even though
     the glyph inside is 22px.
     The primary CTA now lives in the bar rather than inside the drawer -- on a
     site whose whole job is driving to one enquiry form, putting that behind a
     tap was costing conversions. */
  .nav-m{display:none;align-items:center;gap:10px}
  .nav-cta{padding:11px 18px;font-size:14.5px}
  .burger{display:none;background:none;border:0;padding:0;cursor:pointer;color:var(--ink-2);
    width:44px;height:44px;align-items:center;justify-content:center}
  .burger svg{width:23px;height:23px;display:block}
  .burger .i-x{display:none}
  .burger[aria-expanded="true"] .i-bars{display:none}
  .burger[aria-expanded="true"] .i-x{display:block}
  .burger:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:3px}
  @media(max-width:1080px){
    .nav-m{display:flex}
    .burger{display:flex}
    /* the drawer's own Contact button would now be a duplicate */
    .nav-r>a.btn{display:none}
    .nav-r{position:absolute;top:100%;left:0;right:0;background:#fff;border-bottom:1px solid var(--line);
      flex-direction:column;align-items:stretch;gap:0;padding:8px 22px 22px;display:none}
    .nav-r.open{display:flex}
    /* Dividers sit on TOP of each item, not underneath. The previous rule tried
       :last-of-type to strip the trailing border, but :last-of-type matches the
       last <a> child -- which is the .btn, hidden here -- so :not(.btn) then
       failed and it never fired, leaving a rule stacked on the drawer's own
       bottom edge. Top borders cannot produce a trailing rule at all, so the
       drawer edge is the only thing closing the list. */
    .nav-r>a:not(.btn){display:block;padding:14px 0;border-bottom:none;border-top:1px solid var(--line)}
    .nav-r>a:not(.btn):first-of-type{border-top:none}
    /* 8px top + 14px item padding above the first label; match it below the
       last so the drawer is evenly weighted top and bottom */
    .nav-r{padding-bottom:8px}
    header nav{position:relative}
  }

  /* anchor nav strip (guides page) */
  .jump{display:flex;flex-wrap:wrap;gap:10px;margin-top:36px}
  .jump a{border:1px solid var(--line-2);padding:10px 18px;font-size:14.5px;color:var(--ink-2);border-radius:2px}
  .jump a:hover{border-color:var(--brand);color:var(--brand);background:var(--brand-l)}

  /* long-form article body used on the guides page */
  .art{max-width:78ch}
  .art h3{font-size:24px;margin:44px 0 14px}
  .art h4{font-size:17.5px;margin:30px 0 10px}
  .art p{color:var(--ink-2);margin-bottom:16px}
  .art ul{list-style:none;margin:18px 0}
  .art li{font-size:16px;padding:11px 0 11px 26px;position:relative;border-top:1px solid var(--line);color:var(--ink-2)}
  .art li:first-child{border-top:none}
  .art li:before{content:'';position:absolute;left:2px;top:20px;width:8px;height:1px;background:var(--brand)}
  .art table{margin:26px 0;border:1px solid var(--line)}
  .art strong{color:var(--ink)}
  .gsec{padding:66px 0;border-top:1px solid var(--line)}
  .gsec:first-of-type{border-top:none;padding-top:0}

  /* enquiry form */
  .form{background:#fff;border:1px solid var(--line);padding:40px 42px}
  .off .form{background:#fff}
  .fr{display:grid;grid-template-columns:1fr 1fr;gap:20px}
  @media(max-width:700px){.fr{grid-template-columns:1fr}.form{padding:28px 22px}}
  .fld{margin-bottom:20px}
  .fld label{display:block;font-size:12px;letter-spacing:.11em;text-transform:uppercase;
    color:var(--muted);font-weight:600;margin-bottom:8px}
  .fld input,.fld select,.fld textarea{width:100%;border:1px solid var(--line-2);background:#fff;
    padding:13px 15px;font:400 16px/1.5 "Inter",system-ui,sans-serif;color:var(--ink);border-radius:2px}
  .fld input:focus,.fld select:focus,.fld textarea:focus{outline:none;border-color:var(--brand);
    box-shadow:0 0 0 3px var(--brand-l)}
  .fld textarea{min-height:132px;resize:vertical}
  .fld .hint{font-size:13.5px;color:var(--muted);margin-top:7px}
  .form button{margin-top:6px}
  .req{color:var(--accent)}

  /* small print block */
  .fine{font-size:14px;color:var(--muted);margin-top:20px;line-height:1.65;max-width:70ch}

  /* three-route cards for co-packing */
  .routes{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;margin-top:46px}
  @media(max-width:940px){.routes{grid-template-columns:1fr}}
  .route{background:#fff;border:1px solid var(--line);padding:34px;display:flex;flex-direction:column}
  .off .route{background:#fff}
  .route .n{font-size:13px;font-weight:600;color:var(--brand);letter-spacing:.1em;margin-bottom:14px}
  .route h3{font-size:20px;margin-bottom:11px}
  .route p{font-size:16px;color:var(--ink-2)}
  /* Only the LAST paragraph absorbs the leftover height, so a card with
     shorter copy gains its white space below the final paragraph rather
     than opening a gap between the paragraphs. */
  .route p:last-of-type{flex:1}
  .route .pr{margin-top:22px;padding-top:18px;border-top:1px solid var(--line);
    font-size:15px;font-weight:600;color:var(--brand)}

  /* highlight band */
  .band{background:var(--brand-l);border:1px solid #CFE0D6;padding:34px 38px;margin-top:36px}
  .band h3{font-size:20px;margin-bottom:10px;color:var(--brand-d)}
  .band p{font-size:16.5px;color:#2C4A3D}

  /* guides page: breathing room under the section headings */
  .gsec h2{margin-bottom:20px}
  .gsec .art>p:first-child{font-size:19px;color:var(--ink-2);line-height:1.72}
  .art h3:first-child{margin-top:0}


  /* ==========================================================================
     MOBILE
     Everything above is the desktop design with per-component breakpoints.
     This block is the phone pass, kept together at the end so the mobile
     behaviour can be read in one place rather than hunted for.
     ========================================================================== */

  /* ---- type scale ----
     The page had drifted to eight distinct body sizes between 14.5px and
     19.5px, which reads as inconsistency rather than hierarchy once the
     columns collapse and everything sits in one measure. Phone gets three
     steps and nothing else:
        17px   lead paragraphs (the opening line of a section)
        16px   body copy inside cards, features, articles
        14.5px small print, captions, table figures
     Desktop sizes are untouched -- there the wider measure earns the range. */
  @media(max-width:700px){
    .lede,
    .gsec .art>p:first-child{font-size:17px;line-height:1.68}
    .hero p{font-size:17px;line-height:1.66}
    .phero p{font-size:17px}
    .mkt .sub,.mkt-cagr,.mkt-foot p{font-size:16px}
    .box p,.route p,.feat p,.card p,.note p,.band p,.art p,.redl li,
    .feat li,.box li,.step p,details p{font-size:16px}
    .cap,.fine,.sm,.mkt-legend .cap{font-size:14.5px}
  }

  /* ---- vertical rhythm ----
     96px section padding and a 560px hero minimum are generous on a desktop
     canvas and simply long on a 375px one; the page ran to ~13,500px. These
     tighten the gaps without touching the desktop composition. */
  @media(max-width:700px){
    section{padding:56px 0}
    .hero{min-height:0}
    .hero-in{padding-top:58px;padding-bottom:58px}
    .hero h1{font-size:33px;line-height:1.14;max-width:none}
    .hero p{margin-top:18px;max-width:none}
    .hero .row{margin-top:28px;gap:10px}
    .phero{padding:56px 0 58px}
    .mkt{padding:56px 0}
    h2{font-size:27px}
    .split{gap:30px}
    .cards,.g2,.g3,.routes,.accs{margin-top:34px}
    .steps{margin-top:34px}
  }

  /* Full-width CTAs below the point where two buttons stop fitting side by
     side -- at 375px they were wrapping to two rows of ragged widths anyway. */
  @media(max-width:430px){
    .hero .row{flex-direction:column;align-items:stretch}
    .hero .row .btn{justify-content:center;width:100%}
  }

  /* ---- narrow tables ----
     The global mobile rule turns every table into a nowrap horizontal
     scroller, which is right for the wide price tables but wrong for a
     three-column comparison sitting inside a card: it fits, it just needed
     permission to wrap. Cards also give back some padding so it has room. */
  @media(max-width:820px){
    /* table-layout:fixed, because auto layout sizes to the widest unbreakable
       content -- the tracked-out "CAPSULES" header alone claimed 112px and
       pushed the table 7px past the card edge. Fixed hands out the columns by
       proportion instead, and the label column wraps to take up the slack. */
    .box table{display:table;width:100%;table-layout:fixed;white-space:normal;overflow:visible}
    .box th,.box td{padding:12px 8px;font-size:14px}
    .box th{font-size:10.5px;letter-spacing:.07em}
    .box th:first-child,.box td:first-child{padding-left:13px;width:42%}
    .box th:last-child,.box td:last-child{padding-right:13px}
    .box th:nth-child(2),.box td:nth-child(2),
    .box th:nth-child(3),.box td:nth-child(3){width:29%}
    .box td.s,.box td.n{font-size:14px;white-space:nowrap}
  }
  @media(max-width:560px){
    .box,.route,.note{padding:26px 20px}
    .redl,.band{padding:26px 20px}
    .ex{padding:30px 22px}
    /* Pulled halfway out of the wrap so the dark block sits closer to the screen
       edge -- it buys the table real width, which is scarce here. The pull has to
       match half the wrap padding at each breakpoint. */
    .ex{margin-left:-11px;margin-right:-11px}
    .extab th,.extab td{padding-left:16px;font-size:14.5px}
    .extab tbody tr.big td{font-size:17px}
  }

  /* Wide tables that genuinely must scroll get an edge fade, so the cut-off
     column reads as "there is more this way" instead of as a broken layout. */
  @media(max-width:820px){
    .pb{position:relative}
    .pb:after{content:'';position:absolute;top:0;right:0;bottom:0;width:26px;
      background:linear-gradient(to right,rgba(255,255,255,0),rgba(255,255,255,.92));
      pointer-events:none}
  }

  /* ---- narrow phones (320px) ----
     A grid track written as `1fr` is really `minmax(auto,1fr)`, and `auto`
     floors at min-content. One unbreakable token -- support@thebatchhouse.uk
     measures 189px -- therefore forces its whole column wider than the screen,
     which is what pushed every page 30px past the viewport at 320px.
     minmax(0,1fr) removes that floor; overflow-wrap lets the token break. */
  .fg,.cbar,.mkt-plot,.mkt-legend,.g2,.g3,.cards,.routes,.accs,.stats .wrap{
    grid-auto-columns:minmax(0,1fr)}
  .fg{grid-template-columns:2.2fr minmax(0,1fr) minmax(0,1fr) minmax(0,1fr)}
  @media(max-width:880px){.fg{grid-template-columns:repeat(2,minmax(0,1fr))}}
  footer a,.cb b,.cb span{overflow-wrap:anywhere}

  @media(max-width:360px){
    .wrap{padding:0 16px}
    .ex{margin-left:-8px;margin-right:-8px}
    .cbar{grid-template-columns:minmax(0,1fr)}
    .mkt-plot,.mkt-legend{gap:12px}
    .bcol .val{font-size:22px}
    .stat{padding:18px 10px}
    .stat b{font-size:23px}
    .box,.route,.note,.redl,.band{padding:22px 16px}
    .hero h1{font-size:30px}
  }

  /* ---------- closing CTA band ----------
     Single column, no photo: the section is a hand-off to the enquiry form,
     so anything competing with that one button is weight for nothing. */
  .cta-end{padding:66px 0}
  .cta-end h2{color:#fff;max-width:22ch}
  .cta-end .lede{color:#C6D6CC;max-width:56ch}
  .cta-end .btn{margin-top:30px}
  @media(max-width:700px){
    .cta-end{padding:50px 0}
    .cta-end .btn{margin-top:26px;width:100%;justify-content:center}
  }

  /* ---------- "What we do": grid on desktop, swipe deck on phone ----------
     The four cards stacked to roughly 1,600px of scrolling on a phone. As a
     snap-scrolling row they cost one screen. Cards sit at 78% width so the
     next one always peeks in from the right -- that peek is the only thing
     telling the reader there is more, so it has to survive any width change. */
  @media(max-width:620px){
    .cards{display:flex;grid-template-columns:none;gap:14px;
      overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
      /* bleed past .wrap's padding so a card can run to the screen edge, then
         restore the gutter inside as scroll padding */
      margin-left:-22px;margin-right:-22px;padding:2px 22px 16px;scroll-padding-left:22px;
      scrollbar-width:none;-ms-overflow-style:none}
    .cards::-webkit-scrollbar{display:none}
    .cards>.card{flex:0 0 78%;min-width:0;scroll-snap-align:start}
    .cards:focus-visible{outline:2px solid var(--brand);outline-offset:3px}
  }
  @media(max-width:360px){
    .cards{margin-left:-16px;margin-right:-16px;padding-left:16px;padding-right:16px;
      scroll-padding-left:16px}
    .cards>.card{flex:0 0 84%}
  }

  /* ---------- "Four things we do differently" ----------
     This section is the offer, so nothing here hides any of it: no accordion,
     no deck. Flat editorial rows sitting directly on the section background --
     no white cards floating on the grey -- with the number and headline held
     in a left column and the detail beside it, so all four headlines can be
     read straight down the page as a single argument.
     Number + headline stack above the copy once the two columns collapse. */
  .diffs{margin-top:46px;border-top:1px solid var(--line-2)}
  .diff{display:grid;grid-template-columns:0.85fr 1.15fr;gap:56px;
    padding:38px 0;border-bottom:1px solid var(--line-2);align-items:start}
  /* The section now carries its own hairline, so the last row's bottom border
     stacked into a double line. Padding is untouched, so all four rows keep
     identical height. */
  .diff:last-child{border-bottom:none}
  .diff-n{font-size:12.5px;font-weight:600;color:var(--brand);letter-spacing:.16em;margin-bottom:12px}
  .diff h3{font-size:23px;line-height:1.2;max-width:16ch}
  .diff-b>p{font-size:16.5px;color:var(--ink-2);line-height:1.7}
  .diff-b>p:first-child{margin-top:0}

  /* Boxed on all four sides, green header, label column tinted. The comparison
     only works if our row is the one that reads loudest, so it takes the brand
     tint and the brand ink while the competitor row stays plain. */
  .mins{margin-top:20px;max-width:420px;border:1px solid var(--line);background:var(--paper)}
  .mins th{background:var(--brand);color:#fff;padding:11px 16px;border-top:none;
    font-size:10.5px;letter-spacing:.14em}
  .mins td{padding:12px 16px;border-top:1px solid var(--line)}
  .mins td:first-child{background:var(--off);color:var(--ink);font-weight:500}
  .mins th:not(:first-child),.mins td:not(:first-child){text-align:right}
  .mins td.s{color:var(--ink-2);font-weight:600;font-size:15px}
  .mins tr.us td,.mins tr.us td:first-child{background:var(--brand-l);color:var(--brand);font-weight:600}


  /* ---------- MOBILE TABLES ----------
     Below 760px these stop being tables. Horizontal scroll inside a card means
     you can see the row label or the number but never both, so each row becomes
     a small stacked block instead. The example matrix can't stack -- it is a
     genuine grid -- so its label column is pinned instead. */
  @media(max-width:760px){

    /* The desktop column widths and side padding are set per-column, so they
       have to be unset per-column too or the cells keep their old proportions
       once the row becomes a grid. */
    .ladder th:first-child,.ladder td:first-child,
    .ladder th:nth-child(2),.ladder td:nth-child(2),
    .ladder th:nth-child(3),.ladder td:nth-child(3),
    .ladder th:last-child,.ladder td:last-child,
    .cmp td:first-child,.cmp td:nth-child(2),.cmp td:last-child{
      width:auto;padding-left:0;padding-right:0}

    /* --- batch ladder: one block per tier --- */
    .ladder{min-width:0;table-layout:auto;display:block;white-space:normal}
    .ladder thead{display:none}
    .ladder tbody{display:block}
    .ladder tr{display:grid;grid-template-columns:1fr auto;gap:0 14px;
      padding:12px 18px;border-top:1px solid var(--line)}
    .ladder tbody tr:first-child{border-top:none}
    .ladder tr.hi{background:var(--brand-l)}
    .ladder td{display:block;padding:0;border:none;width:auto}
    .ladder td:first-child{grid-column:1/-1;font-weight:600;font-size:15.5px;line-height:1.25;
      color:var(--ink);margin-bottom:5px;white-space:normal}
    .ladder td.was{grid-column:1;align-self:baseline;font-size:14px;line-height:1.35;text-align:left}
    .ladder td.pay{grid-column:2;align-self:baseline;font-size:18px;line-height:1.35;text-align:right}
    .ladder td.stepup{grid-column:1/-1;margin-top:4px;font-size:13px;line-height:1.4;
      text-align:left;white-space:normal}
    .ladder tr:first-child td.stepup{display:none}

    /* --- private-label comparison: label, then the two sides --- */
    .cmp{min-width:0;display:block;white-space:normal}
    .cmp thead{display:none}
    .cmp tbody{display:block}
    .cmp tr{display:block;padding:13px 18px;border-top:1px solid var(--line)}
    .cmp tbody tr:first-child{border-top:none}
    .cmp td{display:block;padding:0;border:none;width:auto;background:none;
      font-size:15.5px;line-height:1.5;white-space:normal}
    /* The desktop label column is tinted; on mobile that put it on the same grey
       as the private-label cell right beneath it and the two read as one block. */
    .cmp td:first-child{font-weight:600;color:var(--ink);margin-bottom:8px;width:auto;
      background:none;font-size:15px}
    .cmp td:nth-child(2),.cmp td:last-child{position:relative;padding:8px 11px;border-radius:2px;
      width:auto;font-size:15px;line-height:1.45}
    .cmp td:nth-child(2){background:var(--off);color:var(--muted)}
    .cmp td:last-child{background:var(--brand-l);color:var(--brand);margin-top:5px}
    .cmp td:nth-child(2)::before,.cmp td:last-child::before{
      display:block;font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;
      font-weight:600;margin-bottom:3px;opacity:.75}
    .cmp td:nth-child(2)::before{content:"Private label"}
    .cmp td:last-child::before{content:"Custom, with us"}

    /* --- worked example: a real matrix, so pin the label column instead --- */
    .extw-hint{display:block;margin:0 0 12px;font-size:13px;letter-spacing:.02em;
      color:var(--accent);font-weight:600}
    /* Sized so a slice of the 30 kg column is always visible -- a half-shown
       column is a stronger signal that there is more than any fade is. */
    .extab{min-width:400px}
    /* Let the label wrap so it stops taking two-thirds of the width -- that is
       what buys a second full column on screen. */
    .extab td:first-child,.extab th:first-child{position:sticky;left:0;z-index:1;
      background:var(--ink);padding-right:12px;white-space:normal;width:120px}
    .extab th,.extab td{padding-left:16px;font-size:14px}
    .extab tbody tr.big td{font-size:16px}
  }

  @media(max-width:860px){
    .diff{grid-template-columns:1fr;gap:14px;padding:30px 0}
    .diff h3{max-width:none;font-size:20px}
  }
  @media(max-width:700px){
    .diffs{margin-top:34px}
    .diff{padding:26px 0}
    .diff h3{font-size:19px}
    .diff-b>p{font-size:16px}
    .mins{max-width:none}
  }

  /* ---------- contact page ----------
     One column, form first. The green band above already carries the headline
     and the promise, so repeating it here only pushed the form further down --
     it started 1.7 screens deep on a phone. Hours/email/address are reference,
     not persuasion, so they sit under the form at supporting size. */
  .form-col{max-width:760px}
  .form-note{font-size:15px;color:var(--muted);line-height:1.65;margin:4px 0 20px;max-width:62ch}
  .cbar-sm{margin-top:26px;border:none;background:none;
    /* Two items since the address moved to the footer; a 3-track grid left a
       dead third column. */
    grid-template-columns:repeat(2,minmax(0,1fr));gap:0 30px}
  .cbar-sm .cb{padding:0;border-right:none}
  .cbar-sm .cb .l{font-size:10.5px;letter-spacing:.14em}
  .cbar-sm .cb b{font-size:15px;margin-top:6px;font-weight:600;line-height:1.5}
  .cbar-sm .cb b a:hover{color:var(--brand)}
  .cbar-sm .cb span{display:block;font-size:13.5px;margin-top:3px;line-height:1.5}
  @media(max-width:780px){
    .cbar-sm{grid-template-columns:minmax(0,1fr);gap:0}
    .cbar-sm .cb{padding:16px 0;border-bottom:1px solid var(--line)}
    .cbar-sm .cb:first-child{border-top:1px solid var(--line)}
    .cbar-sm .cb:last-child{border-bottom:none}
  }

  /* The minimums table left .box when the section went flat, so the global
     mobile rule caught it again and turned it into a nowrap scroller -- whose
     min-content width then blew the single-column .diff grid past 320px.
     Same fix as before: let it wrap, and hand out the columns by proportion. */
  @media(max-width:820px){
    .mins{display:table;width:100%;table-layout:fixed;white-space:normal;overflow:visible}
    .mins th:first-child,.mins td:first-child{width:44%}
    .mins th:nth-child(2),.mins td:nth-child(2),
    .mins th:nth-child(3),.mins td:nth-child(3){width:28%}
  }
  /* belt and braces: a 1fr track floors at min-content, so anything stubborn
     inside a row could push the grid wider than the screen again */
  @media(max-width:860px){.diff{grid-template-columns:minmax(0,1fr)}}

  /* At 320px the tracked-out "CAPSULES" header runs ~3px past its fixed cell.
     Invisible today, but a slightly different font stack turns it into a
     clipped letter, so give the number columns more room and less tracking. */
  @media(max-width:360px){
    .mins th{font-size:10px;letter-spacing:.08em}
    .mins th:not(:first-child),.mins td:not(:first-child){padding-left:10px}
    .mins th:first-child,.mins td:first-child{width:40%}
    .mins th:nth-child(2),.mins td:nth-child(2),
    .mins th:nth-child(3),.mins td:nth-child(3){width:30%}
  }

  /* ---------- form density on phone ----------
     Eight stacked fields at ~100px each ran the card to 1.7 screens. The space
     comes out of the gaps, not the controls: the 16px input font stays (below
     that, iOS zooms the page the moment a field is focused) and controls stay
     at ~48px, above the 44px touch minimum. Only the air between them moves. */
  @media(max-width:700px){
    .form{padding:24px 20px}
    .fld{margin-bottom:14px}
    .fld label{margin-bottom:6px}
    .fld input,.fld select,.fld textarea{padding:11px 14px}
    .fld textarea{min-height:104px}
    .fld .hint{font-size:13px;margin-top:6px}
    .form-note{margin:2px 0 16px;font-size:14.5px}
    .fine{font-size:13.5px;margin-top:16px}
    .form button{margin-top:2px}
  }

  /* ---------- green band runs up behind the header ----------
     The header is sticky and in flow, so it owns the top ~83px of the document.
     When the colour swap plays, the bar tucks up out of that space -- and at
     the top of the page there was nothing behind it but paper, so you got a
     white strip flashing above the green band mid-animation.
     Fix is to pull the band itself up under the header and give the height
     back as padding, so the content sits exactly where it did before but the
     green (and the band's own 20%-opacity photo, which a flat fill could not
     have matched) now covers the strip the header vacates.
     --hdr-h must track nav height + the 1px border. */
  :root{--hdr-h:83px}
  @media(max-width:560px){:root{--hdr-h:71px}}

  .phero{margin-top:calc(-1 * var(--hdr-h));padding-top:calc(74px + var(--hdr-h))}
  .hero{margin-top:calc(-1 * var(--hdr-h));min-height:calc(560px + var(--hdr-h))}
  .hero-in{padding-top:calc(96px + var(--hdr-h))}
  @media(max-width:700px){
    .phero{padding-top:calc(56px + var(--hdr-h))}
    .hero{min-height:var(--hdr-h)}
    .hero-in{padding-top:calc(58px + var(--hdr-h))}
  }

  /* ---------- capability cards on a phone ----------
     The section should land in one screen: swipe the cards, don't scroll past
     them. At 4:3 the card image alone was 192px of a 463px card, which pushed
     the section ~90px past the viewport once the sticky header is counted.
     The image is atmosphere, not information, so it gives up the height first
     -- the headline and lede keep theirs. */
  @media(max-width:700px){
    .cards>.card .ph.r4{aspect-ratio:16/9}
    .cards>.card .card-b{padding:20px 20px 22px}
    #capabilities .lede{font-size:16px;line-height:1.55}
    /* last 24px: the section is the one place a tighter band is worth it,
       because the whole point is that it lands in a single screen */
    #capabilities{padding-top:44px;padding-bottom:44px}
  }

  /* ---------- reviews ----------
     Matched to Kept's reviewsection.html (Primal Queen layout) rather than
     reinterpreted: 46px avatar, 15px bold name, 14px green "Verified Buyer",
     13px date, 15px stars inline with a 15px bold headline, 15px body at
     relaxed leading. Amber #FFC107 and green #1CB982 are theirs and are kept -
     both are recognised signals that would lose meaning recoloured. */
  .rv-top{display:grid;grid-template-columns:auto minmax(0,400px);gap:0 64px;
    align-items:center;margin-top:44px;padding-bottom:34px;border-bottom:1px solid var(--line)}
  .rv-scoreline{display:flex;align-items:center;gap:14px}
  .rv-num{font-size:52px;font-weight:700;letter-spacing:-.03em;line-height:1;color:var(--ink)}
  .rv-stars{color:#FFC107;letter-spacing:1px;font-size:22px;line-height:1}
  .rv-stars.sm{font-size:15px;letter-spacing:.5px}
  .rv-stars .off{color:#E3E3E3}
  .rv-count{margin-top:11px;font-size:15px;color:var(--ink-2)}

  /* Distribution rows. Resting is quiet - light grey stars, pale fill - and
     hovering lights ONLY that row's own parts: stars to near-black, fill to full
     amber, count to black. No background tint behind the row: the original has
     none, and adding one made the whole strip flash rather than the one bar. */
  .rv-bars{display:flex;flex-direction:column;gap:6px}
  .rv-bar{display:flex;align-items:center;gap:14px;cursor:default}
  .rv-lab{flex:0 0 78px;font-size:13px;letter-spacing:1.5px;color:#D4D4D4;
    transition:color .15s ease}
  .rv-lab .off{color:#E3E3E3;transition:color .15s ease}
  .rv-track{flex:1;height:10px;background:#F1F1F1;position:relative;overflow:hidden}
  .rv-track i{position:absolute;inset:0 auto 0 0;display:block;background:#FFE9A6;
    transition:background .15s ease}
  .rv-n{flex:0 0 46px;text-align:right;font-size:13px;color:#A8A8A8;
    font-variant-numeric:tabular-nums;transition:color .15s ease}
  .rv-bar:hover .rv-lab{color:#1A1A1A}
  .rv-bar:hover .rv-lab .off{color:#C9C9C9}
  .rv-bar:hover .rv-track i{background:#FFC107}
  .rv-bar:hover .rv-n{color:#1A1A1A}

  /* Cards */
  .rv-list{margin-top:10px}
  .rv-item{padding:22px 0;border-bottom:1px solid var(--line)}
  .rv-item:last-child{border-bottom:none}
  .rv-item[hidden]{display:none}
  .rv-item:focus{outline:none}
  .rv-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
  .rv-avatar{position:relative;width:46px;height:46px;border-radius:50%;
    background:#F9FAFB;border:1px solid #F1F1F1;color:#D4D4D4;
    display:flex;align-items:center;justify-content:center;flex-shrink:0;
    font-size:17px;font-weight:600;letter-spacing:.02em}
  /* Tick sits on the avatar, not beside the name: with "Verified Buyer" already
     in words, a second tick next to it would say the same thing twice. */
  .rv-tick{position:absolute;right:-2px;bottom:-2px;width:16px;height:16px;
    border-radius:50%;background:#1CB982;color:#fff;border:2px solid #fff;
    display:flex;align-items:center;justify-content:center;
    font-size:9px;line-height:1;font-weight:700;letter-spacing:0}
  .rv-name{font-size:15px;font-weight:700;color:var(--ink);margin-left:-6px}
  .rv-verified{font-size:14px;font-weight:400;color:#1CB982;margin-left:-6px}
  .rv-date{margin-left:auto;font-size:13px;color:#7C7C7C;font-variant-numeric:tabular-nums}
  .rv-line{display:flex;align-items:center;gap:12px;margin:12px 0 9px;flex-wrap:wrap}
  .rv-title{font-size:15px;font-weight:700;color:var(--ink);margin:0}
  .rv-body{font-size:15px;line-height:1.625;color:var(--ink-2);margin:0}
  .rv-body + .rv-body{margin-top:11px}

  .rv-more{margin-top:30px;display:flex;justify-content:center}

  @media(max-width:820px){
    .rv-top{grid-template-columns:1fr;gap:26px}
    .rv-num{font-size:42px}
    .rv-date{margin-left:0;flex-basis:100%;order:4;margin-top:2px}
  }

  /* ---------- legal pages ----------
     Long-form prose, set narrower than the marketing pages so it stays readable
     at length. Deliberately plain: this is a document, not a pitch. */
  .legal{max-width:74ch}
  .legal-meta{font-size:13.5px;color:var(--muted);margin-bottom:34px}
  .legal h2{font-size:22px;margin:38px 0 12px;max-width:none}
  .legal h2:first-of-type{margin-top:0}
  .legal p{font-size:16.5px;line-height:1.72;color:var(--ink-2);margin-bottom:14px}
  .legal ul{list-style:none;margin:0 0 18px}
  .legal li{font-size:16.5px;line-height:1.7;color:var(--ink-2);
    padding:6px 0 6px 24px;position:relative}
  .legal li:before{content:'';position:absolute;left:2px;top:17px;width:12px;height:1px;
    background:var(--brand)}
  .legal b{color:var(--ink);font-weight:600}
  @media(max-width:700px){
    .legal h2{font-size:20px;margin-top:32px}
    .legal p,.legal li{font-size:16px}
  }

  /* ---------- cookie consent ----------
     Accept and reject are the same size, same weight, side by side. That parity
     is the part PECR enforcement actually turns on, so it must not be "improved"
     into a prominent accept and a quiet link. */
  .cc-bar{position:fixed;left:0;right:0;bottom:0;z-index:9999;background:var(--brand);
    color:#F0F4F1;padding:20px 22px;display:flex;align-items:center;gap:26px;
    flex-wrap:wrap;justify-content:center;box-shadow:0 -6px 30px -18px rgba(0,0,0,.5)}
  .cc-bar p{margin:0;font-size:14.5px;line-height:1.6;max-width:70ch;color:#D3E1D8}
  .cc-bar a{color:#fff;text-decoration:underline;text-underline-offset:2px}
  .cc-btns{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  /* Both buttons get the same box. The outline variant carries a 1px border, so
     without this the reject button renders 2px shorter than accept - trivial to
     look at, but parity of prominence is the whole legal point. */
  .cc-bar .btn{padding:11px 20px;font-size:14.5px;border:1px solid transparent;
    min-height:44px;box-sizing:border-box}
  .cc-bar .btn:not(.o){background:#fff;color:var(--brand)}
  .cc-bar .btn:not(.o):hover{background:var(--brand-l)}
  .cc-bar .btn.o{background:transparent;color:#fff;border:1px solid rgba(255,255,255,.55)}
  .cc-bar .btn.o:hover{background:rgba(255,255,255,.12);color:#fff}
  .cc-link{appearance:none;border:0;background:none;color:#D3E1D8;cursor:pointer;
    font:inherit;font-size:14px;text-decoration:underline;text-underline-offset:2px;padding:6px}
  .cc-link:hover{color:#fff}

  .cc-panel-wrap{position:fixed;inset:0;z-index:10000;background:rgba(16,27,22,.55);
    display:flex;align-items:center;justify-content:center;padding:22px}
  .cc-panel{background:#fff;max-width:540px;width:100%;padding:30px 32px;
    max-height:86vh;overflow:auto}
  .cc-panel h2{font-size:22px;margin:0 0 20px;max-width:none}
  .cc-row{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;
    padding:16px 0;border-top:1px solid var(--line)}
  .cc-row b{display:block;font-size:15.5px;color:var(--ink);margin-bottom:3px}
  .cc-row span{font-size:14px;color:var(--ink-2);line-height:1.55}
  .cc-always{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
    font-weight:600;white-space:nowrap;padding-top:3px}
  .cc-sw{position:relative;flex-shrink:0;width:44px;height:24px;cursor:pointer}
  .cc-sw input{position:absolute;opacity:0;width:0;height:0}
  .cc-sw span{position:absolute;inset:0;background:var(--line-2);border-radius:100px;
    transition:background .18s}
  .cc-sw span:before{content:'';position:absolute;left:3px;top:3px;width:18px;height:18px;
    background:#fff;border-radius:50%;transition:transform .18s}
  .cc-sw input:checked + span{background:var(--brand)}
  .cc-sw input:checked + span:before{transform:translateX(20px)}
  .cc-sw input:focus-visible + span{outline:2px solid var(--brand);outline-offset:2px}
  .cc-acts{display:flex;gap:10px;margin-top:24px;flex-wrap:wrap}

  @media(max-width:700px){
    .cc-bar{gap:16px;padding:18px}
    .cc-bar p{font-size:14px}
    /* Stacked and full width on a phone. flex:1 alone left them unequal, because
       a flex item will not shrink below its own text - and "Essential only" is
       longer than "Accept all". Equal width is not cosmetic here. */
    .cc-btns{width:100%;flex-direction:column;align-items:stretch}
    .cc-bar .btn{width:100%;justify-content:center}
    .cc-link{align-self:center}
    .cc-panel{padding:24px 20px}
  }
