/* Breeder Web Studio — layout and components.
   Mobile first. Every width breakpoint is min-width; a max-width query in this
   codebase is a bug, per build standard §5. The one permitted exception is
   prefers-reduced-motion and prefers-reduced-transparency. */

*,*::before,*::after{box-sizing:border-box}
html{background:var(--ground);overflow-x:clip;scroll-behavior:smooth}
/* The wash at the top of the page stops after one screen, on purpose. This is the
   quieter half of it: a fixed accent tint over the whole viewport so the page keeps
   a hint of colour however far down you are. Held at 3 to 5 per cent, which moves
   the paper from #FCFBF9 to about #F6F7FA and leaves every measured contrast ratio
   in theme.css still clearing AA. Raise it and re-check those numbers. */
body{margin:0;color:var(--ink);font-family:var(--f-body);
  background:
    linear-gradient(180deg,
      color-mix(in srgb,var(--wash-tint) 5%,transparent) 0%,
      color-mix(in srgb,var(--wash-tint) 3%,transparent) 45%,
      color-mix(in srgb,var(--wash-tint) 5%,transparent) 100%),
    var(--ground);
  background-attachment:fixed,fixed;
  font-size:var(--step-0);line-height:1.6;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
figure{margin:0}                       /* browser default is 1em 40px and eats card width */
img{max-width:100%}
img[width][height]{height:auto}
h1,h2,h3{font-family:var(--f-display);font-weight:300;letter-spacing:-0.02em;margin:0;text-wrap:pretty}
p{margin:0}
a{color:var(--accent);text-decoration:none}
a:hover{color:var(--accent-2)}
a:focus-visible,button:focus-visible,input:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r)}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.wrap{max-width:1240px;margin:0 auto;padding:0 var(--pad)}
.rule{height:1px;background:var(--line)}
.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--deep);color:var(--ground);padding:12px 18px}
/* :focus-visible, not :focus. The back-to-top button moves focus here for screen readers, and on
   an iPhone that left the link showing over the page (Mark, 2 Sep 2026). A keyboard user still
   sees it; a tap does not. */
.skip:focus-visible{left:8px;top:8px}

/* grain sits on a fixed inert layer so it never repaints while scrolling */
.grain{position:fixed;inset:0;z-index:60;pointer-events:none;opacity:.28;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.3'/></svg>")}

/* the page wash.
   A plain white page reads as unfinished on a phone, where the header is most of
   what she sees. This is two soft accent glows and a dot grid over the top of the
   page, gone by the time she has scrolled one screen. It sits BEHIND everything and
   takes no clicks. Colour comes from the accent token, so it moves with the palette.
   The dots are painted with a mask rather than a fixed rgba so they stay honest
   against any ground colour. */
.wash{position:absolute;top:0;left:0;right:0;height:min(820px,92vh);z-index:0;pointer-events:none;overflow:hidden}
.wash::before,.wash::after{content:"";position:absolute;inset:0}
.wash::before{background:
  radial-gradient(1000px 460px at 8% -14%, color-mix(in srgb,var(--wash-tint) 34%,transparent), transparent 66%),
  radial-gradient(880px 420px at 96% -18%, color-mix(in srgb,var(--wash-tint) 22%,transparent), transparent 68%),
  linear-gradient(180deg, color-mix(in srgb,var(--wash-tint) 14%,transparent), transparent 72%)}
.wash::after{background-image:radial-gradient(circle at 1px 1px, color-mix(in srgb,var(--ink) 26%,transparent) 1px, transparent 0);
  background-size:24px 24px;opacity:.42;
  -webkit-mask-image:linear-gradient(180deg,#000,rgba(0,0,0,.3) 58%,transparent 88%);
          mask-image:linear-gradient(180deg,#000,rgba(0,0,0,.3) 58%,transparent 88%)}
/* the wash is painted over the body background, so the page itself has to sit above it.
   .nav is already sticky at z-index 40 and must not be given position:relative here. */
main,.foot{position:relative;z-index:1}

/* the marker line under a phrase. Use it on ONE phrase per page.
   Drawn as a background so the phrase can wrap: on a phone each line of it gets its own stroke
   (box-decoration-break:clone) instead of the whole phrase being forced onto one line and leaving
   a stray word above it. A background also paints under the text of the line below, so where the
   stroke reaches the next line it passes behind the letters rather than over them. Above 760px the
   phrase stays unbreakable, because the headings were set with that in mind.
   The stroke colour is --accent from theme.css, written out here because a data URI cannot read a
   token. Change both or neither. */
.swash{display:inline;padding-bottom:.02em;-webkit-box-decoration-break:clone;box-decoration-break:clone;
  background:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 20' preserveAspectRatio='none'><path d='M5 14C55 7 108 4 158 5c42 1 84 4 137 10' fill='none' stroke='%231F3D73' stroke-opacity='.85' stroke-width='6' stroke-linecap='round'/></svg>") no-repeat 0 100%/100% .28em}
@media (min-width:760px){.swash{display:inline-block}}

/* Hero drawings on the article pages, 2 Sep 2026. Every article hero was a headline and a
   paragraph in the left half of a wide screen with nothing in the right half (Mark: "the site
   looks flat"). Each page now carries one drawing there, in the same vocabulary as the editor
   diagram on the home page: boxes and lines, every label a phrase lifted from the page itself, so
   the picture cannot say anything the page does not. Drawn, never photographed, so nothing in it
   goes stale. Desktop only: on a phone there is no empty half and the pages are long enough.
   The drawing animates once on load; with reduced motion it is simply there. */
.hero-fig{margin:0;display:none}
@media (min-width:1000px){.hero-fig{display:block;justify-self:end;width:100%;max-width:470px;padding-top:36px}}
.hero-fig svg{display:block;width:100%;height:auto;overflow:visible}
.hero-fig figcaption{margin-top:12px;font-size:.8125rem;line-height:1.55;color:var(--ink-2);max-width:44ch}
.hf-line{fill:none;stroke:var(--accent);stroke-opacity:.7;stroke-width:1.25}
.hf-arrow{fill:var(--accent);fill-opacity:.7}
.hf-chip rect{fill:var(--surface);stroke:var(--line);stroke-width:1;
  filter:drop-shadow(0 1px 1.5px color-mix(in srgb,var(--ink) 10%,transparent)) drop-shadow(0 10px 18px color-mix(in srgb,var(--deep) 14%,transparent))}
.hf-chip text{fill:var(--ink-3);font-family:var(--f-body);font-size:13.5px}
.hf-chip .hf-n{fill:var(--accent);font-size:12px;font-weight:600}
.hf-tight .hf-chip text{font-size:12.5px}
.hf-src rect{fill:var(--accent);
  filter:drop-shadow(0 2px 3px color-mix(in srgb,var(--deep) 30%,transparent)) drop-shadow(0 12px 22px color-mix(in srgb,var(--deep) 26%,transparent))}
.hf-src text{fill:#FEFEFD;font-family:var(--f-body);font-size:14px}
.hf-old rect{fill:var(--raise);stroke:var(--line)}
.hf-old text{fill:var(--muted)}
.hf-mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.5px}
.hf-label{fill:var(--muted);font-family:var(--f-body);font-size:11px;letter-spacing:.1em;text-transform:uppercase}
@media (prefers-reduced-motion:no-preference){
  .hero-fig .hf-line{stroke-dasharray:1;stroke-dashoffset:1;animation:hf-draw .9s cubic-bezier(.2,.7,.2,1) both}
  .hero-fig .hf-chip,.hero-fig .hf-src,.hero-fig .hf-arrow{opacity:0;animation:hf-pop .5s ease both}
  .hero-fig .hf-d0{animation-delay:.1s}.hero-fig .hf-d1{animation-delay:.35s}.hero-fig .hf-d2{animation-delay:.6s}
  .hero-fig .hf-d3{animation-delay:.85s}.hero-fig .hf-d4{animation-delay:1.1s}.hero-fig .hf-d5{animation-delay:1.35s}
}
@keyframes hf-draw{to{stroke-dashoffset:0}}
@keyframes hf-pop{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* small caps label with a dot in front of it */
.kicker{display:inline-flex;align-items:center;gap:9px;font-size:.75rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--accent);font-weight:600;margin-bottom:14px}
.kicker::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}

/* the pill above a headline, the one that carries a number */
.pill{display:inline-flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--line);
  border-radius:99px;padding:7px 15px 7px 12px;font-size:.8125rem;color:var(--ink-2);margin-bottom:20px;
  box-shadow:0 1px 2px color-mix(in srgb,var(--ink) 5%,transparent)}
.pill::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--accent);flex:none}

/* Screenshots of client sites, on /, /work and the two case studies, sit on a shadow so they
   read as a thing placed on the page rather than printed flat on it (Mark, 2 Sep 2026). The four
   pages each carry their own .shot img rule inline; figure.shot img outranks those, so the shadow
   lives here once. The before/after slider on the case studies gets the same treatment. */
figure.shot img,.ba-stage{box-shadow:0 3px 6px color-mix(in srgb,var(--ink) 9%,transparent),
      0 28px 56px -18px color-mix(in srgb,var(--deep) 52%,transparent)}
figure.shot{border-radius:var(--r)}

/* lifted card, for the one panel that should look like it is floating */
.lift{box-shadow:0 1px 2px color-mix(in srgb,var(--ink) 6%,transparent),
      0 26px 50px -28px color-mix(in srgb,var(--deep) 42%,transparent)}

/* Phones: one call to action fixed to the bottom of the screen once the hero has scrolled
   away, so the free check is never more than a thumb away. Added by site.js; not on /audit or
   /contact (already the whole page), hidden while the menu panel is open. The back-to-top button
   moves up to sit above it. (Mark, 2 Sep 2026) */
.ctabar{display:none}
@media (max-width:759px){
  .ctabar{display:block;position:fixed;left:0;right:0;bottom:0;z-index:45;padding:10px 14px calc(10px + env(safe-area-inset-bottom));
    background:color-mix(in srgb,var(--surface) 92%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border-top:1px solid var(--line);box-shadow:0 -8px 24px -12px color-mix(in srgb,var(--deep) 30%,transparent);
    transform:translateY(110%);transition:transform .3s cubic-bezier(.22,1,.36,1)}
  .ctabar.is-on{transform:none}
  .ctabar .btn{display:flex;justify-content:center;width:100%;min-height:48px;font-size:1rem}
  header.nav.open ~ .ctabar{transform:translateY(110%)}
  html.has-ctabar body{padding-bottom:72px}
  html.has-ctabar .totop{bottom:84px}
  @media (prefers-reduced-motion:reduce){.ctabar{transition:none}}
}

/* nav */
/* transparent at the top so the wash runs behind it in one piece; the frosted
   background only appears once the page has scrolled under it. */
.nav{position:sticky;top:0;z-index:40;background:transparent;
  border-bottom:1px solid transparent;transition:border-color .3s,background .3s}
.nav.stuck{background:color-mix(in srgb,var(--ground) 84%,transparent);
  backdrop-filter:blur(14px) saturate(140%);-webkit-backdrop-filter:blur(14px) saturate(140%);
  border-bottom-color:var(--line)}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:16px;height:66px;transition:height .3s}
.nav.stuck .nav-in{height:56px}
.brand{font-family:var(--f-display);font-size:1.25rem;color:var(--ink)}
.brand:hover{color:var(--ink)}
.nav-links{display:flex;align-items:center;gap:26px;font-size:.9375rem}
/* Mobile keeps the brand and the one action. Five links do not fit on one line at
   390px, and a two-line nav is broken design, so the section links are dropped
   rather than wrapped. They come back at 860px. */
.nav-links a:not(.btn){display:none}
.nav-links a{color:var(--ink-2)}
.nav-links a:hover{color:var(--ink)}

/* buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;background:var(--deep);color:var(--ground);
  padding:14px 24px;border-radius:var(--r);font-size:.9375rem;font-weight:500;white-space:nowrap;
  transition:transform .2s cubic-bezier(.16,1,.3,1),background .2s}
.btn:hover{background:var(--deep-hover);color:var(--ground)}
.btn:active{transform:translateY(1px) scale(.99)}
.btn-sm{padding:10px 18px;font-size:.875rem}
.btn-accent{background:var(--accent);color:#fff}
.btn-accent:hover{background:var(--accent-2);color:#fff}
.btn-ghost{background:none;color:var(--ink);border:1px solid var(--line)}
.btn-ghost:hover{border-color:var(--muted);color:var(--ink)}
.link-u{color:var(--ink-2);border-bottom:1px solid var(--hair);padding-bottom:3px}
.link-u:hover{color:var(--ink);border-color:var(--ink-2)}

/* cards */
.card{position:relative;background:var(--surface);border:1px solid var(--line);border-radius:var(--r)}
.spot::before{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .35s;border-radius:inherit;
  background:radial-gradient(340px circle at var(--mx,50%) var(--my,50%),color-mix(in srgb,var(--accent) 12%,transparent),transparent 62%)}
.spot:hover::before{opacity:1}

/* forms */
.field{width:100%;font-family:var(--f-body);font-size:.9375rem;color:var(--ink);background:var(--field);
  border:1px solid var(--edge);border-radius:var(--r);padding:14px}
.field::placeholder{color:var(--placeholder)}
.field:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.label{display:block;font-size:.8125rem;color:var(--ink-2);margin-bottom:8px}
.hint{font-size:.8125rem;color:var(--muted);margin-top:8px}

/* sections */
section{padding:clamp(24px,5vw,52px) 0} /* overridden below; kept only as the base */
.sec-head{max-width:60ch;margin-bottom:24px}
h1{font-size:var(--step-4);line-height:1.06}
h1 em{font-style:italic;color:var(--accent);line-height:1.12;padding-bottom:2px}
h2{font-size:var(--step-3);line-height:1.14}
h3{font-size:var(--step-2);line-height:1.2}
.lede{font-size:1.25rem;line-height:1.6;color:var(--ink-2);max-width:46ch}
.sec-sub{font-size:var(--step-1);color:var(--ink-2);margin-top:12px;line-height:1.65}
.eyebrow{font-size:.8125rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}

/* hero */
.hero{padding-top:clamp(48px,6vw,86px);padding-bottom:clamp(48px,6vw,74px)}
.hero-grid{display:grid;gap:36px;align-items:start}
.hero-cta{display:flex;align-items:center;gap:20px;flex-wrap:wrap}

/* marquee, the only one on the site */
.marq{overflow:hidden;border-block:1px solid var(--line);background:var(--raise);padding:15px 0}
.marq-track{display:flex;gap:40px;width:max-content;animation:slide 38s linear infinite}
.marq span{font-size:.875rem;color:var(--ink-2);white-space:nowrap}
.marq .sep{color:var(--accent)}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* why block */
.why-grid{display:grid;gap:32px;align-items:start}
.why-lead{font-size:1.3125rem;line-height:1.6;color:var(--ink-2);margin-top:18px;max-width:34ch}
.why-body p{font-size:var(--step-1);line-height:1.75;color:var(--ink-2);max-width:52ch}

/* availability engine */
.eng{display:grid;gap:20px}
/* Grid and flex children default to min-width:auto, which refuses to shrink below
   their content. The JSON block is one long unwrapped line, so without this the
   whole section pushes the page wider than the viewport on a phone. */
.eng > *,.panel{min-width:0}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:22px}
.panel-h{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px}
.panel-t{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
/* ---------------------------------------------------------------------------
   The editor demo. Left is the admin panel, right is the site it drives.
   The card proportions came from a real breeder site that was studied for it
   (4:3 image, name, colour line, description, badge, enquire link) but the type
   and the colour are this site's own tokens: the demo is a demonstration of the
   product, not a copy of anybody's page.
   --------------------------------------------------------------------------- */
.ed-form{display:grid;gap:14px}
.ed-f{display:grid;gap:6px}
.ed-file{padding:10px 12px;font-size:.8125rem;cursor:pointer}
.ed-file::file-selector-button{font:inherit;font-size:.8125rem;margin-right:12px;padding:6px 12px;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r);background:var(--raise);color:var(--ink-2)}
.ed-list-h{margin-top:24px;padding-top:16px;border-top:1px solid var(--line)}
.ed-list{display:grid;gap:8px;margin-top:12px}
.ed-row{display:grid;grid-template-columns:36px 1fr auto auto;gap:10px;align-items:center;
  padding:8px;border:1px solid var(--line);border-radius:var(--r);background:var(--surface)}
.ed-thumb{width:36px;height:36px;border-radius:4px;background:var(--shot) center/cover no-repeat;flex:none}
.ed-name{font-size:.875rem;line-height:1.25;min-width:0}
.ed-line{display:block;font-size:.75rem;color:var(--muted)}
.ed-state{font:inherit;font-size:.8125rem;color:var(--ink-2);background:var(--field);
  border:1px solid var(--edge);border-radius:var(--r);padding:7px 8px;min-height:40px}
.ed-x{display:grid;place-items:center;width:36px;height:36px;border-radius:var(--r);color:var(--muted)}
.ed-x:hover{background:var(--raise);color:var(--ink)}
.ed-empty{font-size:.875rem;color:var(--muted);padding:14px 2px}

.kits{display:grid;grid-template-columns:1fr;gap:16px}
.kit{background:var(--surface);border:1px solid var(--line);border-radius:8px;overflow:hidden;
  transition:border-color .25s,transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s;
  animation:pop .45s cubic-bezier(.16,1,.3,1)}
.kit:hover{border-color:var(--accent-soft);transform:translateY(-3px);
  box-shadow:0 12px 32px -20px color-mix(in srgb,var(--deep) 55%,transparent)}
@keyframes pop{from{opacity:0;transform:scale(.97) translateY(8px)}to{opacity:1;transform:none}}
.kit-img{aspect-ratio:4/3;overflow:hidden;background:var(--shot);display:grid;place-items:center}
.kit-img img{width:100%;height:100%;object-fit:cover;object-position:top;display:block}
.kit-ph{font-size:.625rem;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.kit-b{padding:16px 18px}
.kit-n{font-family:var(--f-display);font-size:1.25rem;font-weight:400;line-height:1.2;margin:0 0 4px;color:var(--ink)}
.kit-c{font-size:.8125rem;color:var(--accent);margin:0 0 8px}
.kit-d{font-size:.8125rem;color:var(--ink-2);line-height:1.65;margin:0}
.kit-badges{display:flex;gap:7px;margin-top:12px;flex-wrap:wrap}
.bdg{font-size:.75rem;font-weight:500;padding:4px 10px;border-radius:3px;letter-spacing:.02em;white-space:nowrap}
.bdg-available{background:var(--ok-bg);color:var(--ok-ink)}
.bdg-reserved{background:var(--warn-bg);color:var(--warn-ink)}
.bdg-sold{background:var(--line);color:#5A5A63}
.kit-cta{display:inline-flex;align-items:center;margin-top:14px;padding:8px 16px;border-radius:var(--r);
  border:1px solid var(--line);font-size:.78rem;font-weight:500;color:var(--ink-2)}
.kit.is-sold{opacity:.6}
.kit.is-sold .kit-n{text-decoration:line-through;text-decoration-thickness:1px}

/* where one edit lands */
.spread{list-style:none;margin:0;padding:0;display:grid;gap:9px}
.sp{display:flex;align-items:flex-start;gap:10px;font-size:.875rem;line-height:1.45;color:var(--ink-2)}
.sp-tick{flex:none;width:18px;height:18px;border-radius:50%;display:grid;place-items:center;
  background:var(--ok-bg);color:var(--ok-ink);margin-top:1px}
.sp.hit{animation:hit .5s ease-out}
@keyframes hit{0%{transform:translateX(0)}25%{transform:translateX(3px)}100%{transform:translateX(0)}}
.eng-log{margin-top:16px;font-size:.8125rem;line-height:1.5;color:var(--muted);min-height:2.4em}
.eng-log.on{animation:fadein .5s ease-out}
@keyframes fadein{from{opacity:0}to{opacity:1}}
.eng-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
.eng-note{font-size:.9375rem;line-height:1.7;color:var(--ink-2);max-width:64ch;margin-top:22px}

/* work */
.work-list{display:grid;gap:0}
.work-row{display:grid;gap:12px;padding:22px 0;border-top:1px solid var(--line)}
.work-head{display:grid;gap:6px;align-content:start}
.work-head h3 a{display:inline-block;padding:8px 0;margin:-8px 0;color:var(--ink);border-bottom:1px solid var(--hair)}
.work-head h3 a:hover{border-color:var(--accent)}
.work-body{display:grid;gap:16px;align-content:start}
.work-row:last-child{border-bottom:1px solid var(--line)}
.work-meta{font-size:.875rem;color:var(--muted)}
.work-row p{font-size:var(--step-1);line-height:1.65;color:var(--ink-2);max-width:56ch}
.work-specs{list-style:none;margin:2px 0 0;padding:0;display:grid;gap:8px;max-width:60ch}
.work-specs li{position:relative;padding-left:20px;font-size:.9375rem;line-height:1.6;color:var(--ink-2)}
.work-specs li::before{content:"";position:absolute;left:2px;top:.6em;width:6px;height:1px;background:var(--accent)}

/* who */
.who{background:var(--raise)}
.who p{font-size:1.1875rem;line-height:1.7;color:var(--ink-3);max-width:64ch;margin-top:14px}

/* long-form article pages */
.art-grid{display:grid;gap:40px}
.toc{display:none}
.toc-h{font-size:.75rem;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);margin-bottom:12px}
.toc a{display:block;font-size:.875rem;line-height:1.45;color:var(--ink-2);padding:7px 0 7px 13px;border-left:2px solid var(--line)}
.toc a:hover{color:var(--ink);border-color:var(--accent)}
.art{max-width:none}
.art-head{max-width:22ch}
.prose{max-width:64ch}
.prose p{font-size:var(--step-1);line-height:1.75;color:var(--ink-2);margin-top:16px}
.prose p:first-child{margin-top:0}
.prose h2{font-size:var(--step-2);margin-top:52px}
.prose h2,.prose h3{scroll-margin-top:88px}
.prose h3{font-size:1.375rem;margin-top:38px}
.prose h2 + p,.prose h3 + p{margin-top:14px}
.prose ul{list-style:none;margin:18px 0 0;padding:0;display:grid;gap:10px}
.prose li{position:relative;padding-left:22px;font-size:var(--step-0);line-height:1.7;color:var(--ink-2)}
.prose li::before{content:"";position:absolute;left:2px;top:.7em;width:7px;height:1px;background:var(--accent)}
.prose a{border-bottom:1px solid var(--hair);padding-bottom:1px}
.prose a:hover{border-color:var(--accent)}
.prose strong{color:var(--ink);font-weight:600}
/* 1 Sep 2026: a .wrap.prose block used to centre a 64ch column in the page while the hero and the
   grey sections above it aligned to the left edge, so the reading column floated to the right on a
   wide screen. The wrap keeps the page width; the column limit moves to its children. */
.wrap.prose{max-width:1240px}
.wrap.prose>*{max-width:64ch}

/* a checked fact, set apart from the argument around it */
.fact{margin-top:22px;padding:18px 20px;background:var(--surface);border:1px solid var(--line);
  border-left:3px solid var(--accent);border-radius:var(--r)}
.fact p{font-size:.9375rem;line-height:1.65;margin-top:0;color:var(--ink-2)}
.fact p + p{margin-top:10px}
.fact cite{display:block;font-style:normal;font-size:.8125rem;color:var(--muted);margin-top:10px}
.quote{font-family:var(--f-display);font-size:1.1875rem;line-height:1.5;color:var(--ink)}
.fact.testi .quote{font-family:var(--f-display);font-size:1.1875rem;line-height:1.5;color:var(--ink)}

/* the price comparison strip */
.cmp{list-style:none;margin:20px 0 0;padding:0;display:grid;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.cmp li{display:grid;gap:2px;padding:14px 16px;background:var(--surface);font-size:.9375rem;color:var(--ink-2)}
.cmp li::before{display:none}
.cmp b{font-family:var(--f-display);font-weight:400;font-size:1.0625rem;color:var(--ink)}
.cmp span{font-size:.8125rem;color:var(--muted)}

/* sources */
.src{margin-top:16px}
.src li{font-size:.875rem;line-height:1.6;padding-left:0}
/* The hit area is grown with padding and pulled back with an equal negative margin, so
   these clear 44px on a phone without turning the list into a page of its own. */
.src li a,.crumb a{display:inline-block;padding:13px 0;margin:-13px 0}
.src li::before{display:none}
.src a{color:var(--ink-2)}
.crumb{font-size:.875rem;color:var(--muted);margin-bottom:18px}
.crumb a{color:var(--ink-2);border-bottom:1px solid var(--hair)}

/* template shop */
.prod{border:1px solid var(--line);border-radius:var(--r);background:var(--surface);padding:26px;display:grid;gap:14px;align-content:start}
.prod.hero-prod{background:var(--raise)}
.prod-h{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap}
.prod-h h3{font-size:1.375rem}
.prod-p{font-family:var(--f-display);font-size:1.75rem;color:var(--ink);line-height:1}
.prod-p span{font-size:.8125rem;font-family:var(--f-body);color:var(--muted);display:block;margin-top:4px}
.prod-for{font-size:var(--step-0);line-height:1.65;color:var(--ink-2)}
.prod ul{list-style:none;margin:0;padding:0;display:grid;gap:7px}
.prod li{position:relative;padding-left:20px;font-size:.9375rem;line-height:1.55;color:var(--ink-2)}
.prod li::before{content:"";position:absolute;left:2px;top:.62em;width:7px;height:1px;background:var(--accent)}
.prod-meta{font-size:.8125rem;color:var(--muted);line-height:1.5}
.prods{display:grid;gap:20px}
.gap-t{width:100%;border-collapse:collapse;font-size:.9375rem;margin-top:18px}
.gap-t th,.gap-t td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line)}
.gap-t th{font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:500}
.gap-t td.n{text-align:right;font-family:var(--f-display);color:var(--accent);white-space:nowrap}
.gap-t td.note{color:var(--muted);font-size:.8125rem}
.tw{overflow-x:auto;max-width:100%}

/* tool shop */
.tool{border-top:1px solid var(--line);padding:38px 0;display:grid;gap:26px}
.tool > *,.paste,.demo{min-width:0;max-width:100%}
.tool:last-of-type{border-bottom:1px solid var(--line)}
.tool-h{display:flex;align-items:baseline;justify-content:space-between;gap:18px;flex-wrap:wrap}
.tool-h h3{font-size:1.5rem}
.tool-price{font-family:var(--f-display);font-size:1.375rem;color:var(--ink);white-space:nowrap}
.tool-price span{font-size:.875rem;font-family:var(--f-body);color:var(--muted)}
.tool-for{font-size:var(--step-1);line-height:1.65;color:var(--ink-2);max-width:54ch;margin-top:8px}
.tool p.small{font-size:.9375rem;color:var(--muted);line-height:1.6;margin-top:10px;max-width:60ch}
.demo{background:var(--raise);border:1px solid var(--line);border-radius:var(--r);padding:20px}
.demo-t{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin-bottom:14px}
.paste{margin-top:14px}
.paste code{display:block;font-family:var(--f-mono);font-size:.75rem;line-height:1.6;color:var(--ink-3);
  background:var(--field);border:1px solid var(--line);border-radius:var(--r);padding:12px 14px;overflow-x:auto;white-space:pre}
.copy{margin-top:8px;font-size:.8125rem;color:var(--muted)}
.steps{display:grid;gap:22px;counter-reset:s}
.step{display:grid;gap:6px;padding-left:44px;position:relative}
.step::before{counter-increment:s;content:counter(s);position:absolute;left:0;top:-2px;width:30px;height:30px;border-radius:50%;
  display:grid;place-items:center;background:var(--accent);color:#fff;font-size:.875rem;font-weight:600}
.step b{font-family:var(--f-display);font-weight:400;font-size:1.1875rem}
.step p{font-size:var(--step-0);color:var(--ink-2);line-height:1.65;max-width:52ch}
.bundle{background:var(--deep);color:var(--ground);border-radius:var(--r);padding:26px 28px;display:grid;gap:8px}
.bundle h3{color:var(--ground);font-size:1.5rem}
.bundle p{color:var(--on-deep-2);font-size:var(--step-0);line-height:1.6;max-width:52ch}
.bundle .big{font-family:var(--f-display);font-size:2.25rem;line-height:1;color:var(--ground)}

/* prices */
.prow{display:grid;gap:8px;padding:24px 16px;margin:0 -16px;transition:background .25s;align-items:center}
.prow:hover{background:var(--raise)}
.prow.hot{background:var(--raise)}
.pname{font-family:var(--f-display);font-size:1.5rem}
.pprice{font-family:var(--f-display);font-size:2.125rem;line-height:1}
.pmo{font-size:.875rem;color:var(--muted)}
.pfor{font-size:var(--step-0);color:var(--ink-2);line-height:1.6}
.pmeta{font-size:.875rem;color:var(--muted);line-height:1.5}
.rec{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent);margin-top:4px}
.terms{font-size:.875rem;color:var(--muted);margin-top:16px}
.seg{display:inline-flex;background:var(--raise);border:1px solid var(--line);border-radius:99px;padding:3px}
.seg button{padding:9px 20px;border-radius:99px;font-size:.875rem;color:var(--ink-2);transition:color .2s}
.seg button[aria-pressed="true"]{background:var(--surface);color:var(--ink);box-shadow:0 1px 3px color-mix(in srgb,var(--ink) 10%,transparent)}

/* closing + footer */
.close{background:var(--deep)}
.close h2{color:var(--ground)}
.close p{color:var(--on-deep-2);margin-top:12px}
.close .btn{background:var(--accent-soft);color:var(--deep);font-weight:600}
.close .btn:hover{background:#fff;color:var(--deep)}
.foot{background:var(--deep);color:var(--on-deep-2);padding-bottom:44px;font-size:.875rem}
.foot a{color:var(--on-deep-2);border-bottom:1px solid var(--deep-line);padding-bottom:2px}
.foot a:hover{color:var(--ground);border-color:var(--ground)}
.foot-cols{display:grid;gap:26px;padding-top:38px;padding-bottom:34px}
.foot-h{font-size:.75rem;letter-spacing:.12em;text-transform:uppercase;color:var(--ground);opacity:.55;margin-bottom:12px}
.foot-col nav{display:grid;gap:6px;justify-items:start}
.foot-in{display:grid;gap:14px;border-top:1px solid var(--deep-line);padding-top:24px}
.foot-nav{display:flex;flex-wrap:wrap;gap:18px}

@media (min-width:760px){
  .kits{grid-template-columns:repeat(2,minmax(0,1fr))}
  .foot-in{grid-template-columns:1fr auto;align-items:center}
  .foot-cols{grid-template-columns:repeat(3,1fr);gap:44px}
}
@media (min-width:1000px){
  .hero-grid{grid-template-columns:1.35fr 1fr;gap:60px}
  .why-grid{grid-template-columns:1fr 1.3fr;gap:60px}
  .eng{grid-template-columns:1fr 1fr;gap:24px;align-items:start}
  .work-row{grid-template-columns:300px 1fr;gap:20px 56px;padding:28px 0;align-items:start}
  .prow{grid-template-columns:190px 220px 1fr 160px;gap:28px;padding:24px 20px;margin:0 -20px}
  .cmp{grid-template-columns:repeat(3,1fr);gap:1px}
  .tool{grid-template-columns:1fr 1fr;gap:46px;align-items:start}
  .steps{grid-template-columns:repeat(3,1fr);gap:30px}
  .prods{grid-template-columns:1fr 1fr;gap:24px}
  .prods.three{grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
  .art-grid{grid-template-columns:minmax(0,1fr) 216px;gap:70px;align-items:start}
  /* the list travels with the reader on a page this long */
  .toc{display:block;position:sticky;top:92px}
  .close-grid{display:grid;grid-template-columns:1.4fr 1fr;gap:52px;align-items:center}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
  .marq-track{animation:none}
}
@media (prefers-reduced-transparency:reduce){
  .nav{background:var(--ground);backdrop-filter:none;-webkit-backdrop-filter:none}
}

/* free report */
.scan-mini{margin-top:16px;padding-top:14px;border-top:1px solid var(--line);font-size:.875rem;color:var(--ink-2);line-height:1.55}

/* Results open in a dialog. Inline, they doubled the length of the page and the
   visitor lost her place; the findings are a lookup, not part of the argument. */
.modal{width:min(1140px,94vw);max-height:88vh;padding:0;border:1px solid var(--line);border-radius:var(--r);
  background:var(--ground);color:var(--ink);overflow:hidden;box-shadow:0 24px 70px color-mix(in srgb,var(--ink) 26%,transparent)}
.modal::backdrop{background:color-mix(in srgb,var(--ink) 52%,transparent);backdrop-filter:blur(3px)}
.modal[open]{display:flex;flex-direction:column;animation:modalIn .28s cubic-bezier(.16,1,.3,1)}
@keyframes modalIn{from{opacity:0;transform:translateY(12px) scale(.985)}to{opacity:1;transform:none}}
.modal-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;
  border-bottom:1px solid var(--line);background:var(--surface);flex-shrink:0}
.modal-x{display:grid;place-items:center;width:36px;height:36px;border-radius:var(--r);color:var(--ink-2);flex-shrink:0}
.modal-x:hover{background:var(--raise);color:var(--ink)}
.modal-body{overflow-y:auto;padding:18px 16px 24px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}

.scan-head{font-family:var(--f-mono);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
  display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.plat{background:var(--raise);border:1px solid var(--line);color:var(--ink-2);padding:2px 8px;border-radius:99px;letter-spacing:.04em}
.scan-sum{font-family:var(--f-display);font-weight:300;font-size:var(--step-2);line-height:1.2}
.scan-plat{font-size:.9375rem;line-height:1.55;color:var(--ink-2);margin-top:14px;padding:12px 14px;
  background:var(--surface);border-left:2px solid var(--accent);border-radius:0 var(--r) var(--r) 0;max-width:70ch}
.res-cols{display:grid;gap:14px;margin-top:18px}
.find-group{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:16px}
.find-h{font-family:var(--f-body);font-size:.8125rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink);padding-bottom:8px;border-bottom:1px solid var(--line);display:flex;gap:4px;flex-direction:column}
.find-n{font-size:.75rem;font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted)}
.finds{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:10px}
.find{display:flex;gap:10px;align-items:flex-start}
.find-i{flex-shrink:0;margin-top:1px}
.find-bad .find-i,.find-good .find-i{color:var(--accent)}
.find-part .find-i{color:var(--muted)}
.find-l{display:block;font-size:.9375rem;line-height:1.35}
.find-d{display:block;font-size:.8125rem;color:var(--muted);margin-top:1px;line-height:1.42}
.find-good .find-l{color:var(--ink-2)}
.scan-note{font-size:.8125rem;color:var(--muted);margin-top:16px;line-height:1.55;max-width:74ch}
.capture{margin-top:20px;padding:20px;max-width:700px}
.capture-h{font-family:var(--f-display);font-size:1.375rem;line-height:1.3;margin-bottom:10px}
.capture p{font-size:.9375rem;line-height:1.65;color:var(--ink-2)}
.capture p + p{margin-top:12px}
.capture-row{display:flex;flex-wrap:wrap;gap:10px}

/* Below 900px the three groups become tabs. Stacked, 28 findings is a very long
   scroll on a phone and she loses track of which group she is in. */
.res-tabs{display:flex;gap:6px;margin-top:16px;border-bottom:1px solid var(--line)}
.res-tabs button{flex:1;padding:11px 8px;min-height:44px;font-size:.8125rem;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);border-bottom:2px solid transparent;margin-bottom:-1px}
.res-tabs button[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--accent)}
.res-tabs .tab-n{display:block;font-size:.75rem;font-weight:400;letter-spacing:0;text-transform:none;color:var(--muted);margin-top:2px}
.res-cols > .find-group{display:none}
.res-cols > .find-group.on{display:block}
.find-group{border:none;border-radius:0;padding:12px 0 0}
/* The tab already names the group, so the panel heading would say it twice. */
.find-h{border:none;padding-bottom:0}
.find-h > span:first-child{display:none}
.find-n{font-size:.8125rem;color:var(--muted)}

@media (min-width:900px){
  .res-tabs{display:none}
  .find-h{border-bottom:1px solid var(--line);padding-bottom:8px}
  .find-h > span:first-child{display:block}
  .find-n{font-size:.75rem}
  .res-cols{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}
  .res-cols > .find-group{display:block;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:16px}
  .modal-body{padding:24px 28px 30px}
  .modal-bar{padding:14px 28px}
}
@media (max-width:640px){
  .modal{width:100vw;max-width:100vw;max-height:100dvh;height:100dvh;border-radius:0;border:none}
}

/* The 90 day re-check.
   Deliberately quiet: a strip, not a card, so it never competes with the buy
   CTA above it and never reads as a gate. Nothing is withheld behind it. The
   rule for this site is that an email buys a FUTURE thing, never a present one. */
.recheck{max-width:680px;margin-top:14px;padding:16px 18px;border:1px dashed var(--edge);border-radius:var(--r)}
.recheck-h{font-size:.9375rem;font-weight:500;color:var(--ink)}
.recheck-p{font-size:.8125rem;line-height:1.6;color:var(--muted);margin-top:6px}
.recheck-form{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
.recheck-form .field{flex:1 1 220px;padding:11px 13px;font-size:.875rem}
.recheck-form .btn{padding:11px 18px;font-size:.875rem}
.recheck-done{font-size:.875rem;line-height:1.6;color:var(--ink-2)}

/* Touch targets. Anything tappable clears 44px on a phone, which several of
   these did not: the nav CTA, the footer links, the pricing toggle and the
   quiet text links were all between 25 and 42px. */
@media (max-width:899px){
  .btn-sm{padding:12px 18px;min-height:44px}
  .brand{display:inline-flex;align-items:center;min-height:44px}
  .link-u{display:inline-flex;align-items:center;min-height:44px}
  .seg button{min-height:44px;padding:12px 20px}
  .foot-nav{gap:4px 20px}
  .foot-nav a,.foot-col a,.foot-in a{display:inline-flex;align-items:center;min-height:44px}
  /* Work, Prices and About are short words, so the link was 36 to 43px wide.
     Stretching them makes the whole row the target instead of the text. */
  .foot-col nav{justify-items:stretch}
  .foot-col nav a{width:100%}
  /* Home in the breadcrumb was 39px wide. The negative margin keeps it
     sitting where it looks like it should while the target grows. */
  .crumb a{padding:13px 7px;margin:-13px -7px}
  /* the editor demo: its status menu was 40px tall and its remove button 36 square */
  .ed-state{min-height:44px}
  .ed-x{min-width:44px;min-height:44px}
  /* a bare link in a list, outside the .src pattern that already handles this */
  .prose ul li > a:only-child{display:inline-block;padding:12px 0;margin:-12px 0}
  .nav-links a.btn{min-height:44px}
  .modal-x{width:44px;height:44px}
  .recheck-form .btn{min-height:44px}
  .recheck-form .field{min-height:44px}
  .field{min-height:46px}
  .eng-actions .btn{min-height:44px}
}

/* The jump list is a sticky sidebar from 1000px up. Below that it was hidden
   altogether, which is backwards: the phone is where these pages run 10 to 17
   screens and where skipping ahead is worth most. It moves above the prose,
   because in the markup it sits after it. */
@media (max-width:999px){
  .toc{display:block;order:-1;position:static;background:var(--surface);
    border:1px solid var(--line);border-radius:var(--r);padding:14px 16px 8px}
  .toc-h{margin-bottom:4px}
  .toc a{display:flex;align-items:center;min-height:44px;padding:4px 0 4px 13px}
}

/* Read next: curated internal links at the foot of every page. Added 28 Aug 2026. */
.nextup{padding-top:0}
.nextup .toc-h{margin:0 0 16px}
.next-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
@media (max-width:860px){.next-grid{grid-template-columns:1fr}}
.next-card{display:flex;flex-direction:column;gap:6px;padding:18px 20px;border:1px solid var(--line);
  border-radius:10px;background:var(--surface);text-decoration:none;transition:border-color .18s ease,transform .18s ease}
.next-card:hover{border-color:var(--accent);transform:translateY(-2px)}
.next-card:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.next-t{font-family:var(--f-display);font-size:1.0625rem;color:var(--ink);line-height:1.3}
.next-d{font-size:.875rem;line-height:1.55;color:var(--muted)}
@media (prefers-reduced-motion:reduce){.next-card{transition:none}.next-card:hover{transform:none}}

/* Brand mark, added 28 Aug 2026. The logo artwork is white on a near black ground, so it sits
   in a small dark tile rather than being recoloured. /assets/img/brand-mark-navy.png is the
   alternative if the tile is ever unwanted: swap the background for it and drop the colour. */
.brand{display:inline-flex;align-items:center;gap:10px}
.brand-mark{width:30px;height:30px;flex:none;border-radius:7px;background:#010914
  url("/assets/img/brand-mark.png") center/66% auto no-repeat}
@media (max-width:560px){.brand-mark{width:26px;height:26px;border-radius:6px}}

/* Header fit on small screens. The brand wordmark was wrapping to two lines once the mark was
   added on 28 Aug 2026, which inflated the header. Nowrap plus a smaller mark and button. */
.brand{white-space:nowrap}
@media (max-width:560px){
  .nav-in{gap:10px}
  .brand{font-size:1.0625rem;gap:8px}
  .nav-links a.btn{padding:9px 14px;font-size:.8125rem}
}
@media (max-width:380px){
  .brand{font-size:1rem}
  .nav-links a.btn{padding:9px 12px;font-size:.75rem}
}

/* Mobile menu, added 28 Aug 2026. Until now the header offered no navigation at all below
   760px: the section links were set to display:none and nothing replaced them, so on a phone
   the only way to Packages or Work was the footer, ten screens down. The button is labelled
   in words rather than being a bare icon, because the reader is a sixty year old breeder. */
.nav-toggle{display:inline-flex;align-items:center;gap:9px;min-height:44px;padding:8px 15px;
  font:inherit;font-size:.9375rem;color:var(--ink);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r);cursor:pointer}
.nav-toggle:hover{border-color:var(--muted)}
.nav-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.nav-bars{position:relative;display:block;width:16px;height:11px;flex:none}
.nav-bars::before,.nav-bars::after,.nav-bars span{content:"";position:absolute;left:0;right:0;
  height:1.5px;background:currentColor;border-radius:2px;transition:transform .2s,opacity .2s}
.nav-bars::before{top:0}
.nav-bars span{top:5px}
.nav-bars::after{bottom:0}
.nav.open .nav-bars::before{transform:translateY(5px) rotate(45deg)}
.nav.open .nav-bars::after{transform:translateY(-4.5px) rotate(-45deg)}
.nav.open .nav-bars span{opacity:0}
/* 860, not 760. Measured 30 Aug 2026: the desktop nav needs an 815px viewport to fit.
   At 760 it was shown 55px too early, so between 760 and 800 the "Talk about your site"
   button was clipped off the right edge and "Free tools" wrapped onto two lines, on
   every page. iPad portrait is 768. 860 leaves 43px of slack instead of 3px.
   site.js has the same breakpoint in matchMedia; change both together. */
@media (min-width:860px){
  .nav-links a:not(.btn){display:inline}
  .nav-toggle{display:none}
}
@media (max-width:859px){
  /* The panel used to go display:none -> display:flex, which cannot be animated, so it
     snapped open while the hamburger beside it animated. It now stays displayed and is
     hidden with visibility, which keeps it out of the tab order exactly as display:none
     did, and can be transitioned. Panel reveal from transitions.dev. */
  .nav-links{position:absolute;left:0;right:0;top:100%;display:flex;flex-direction:column;
    align-items:stretch;gap:0;padding:14px 0 18px;background:var(--ground);
    border-bottom:1px solid var(--line);box-shadow:0 20px 34px -26px rgba(20,20,25,.45);
    visibility:hidden;transform:translateY(var(--nav-panel-travel));opacity:0;
    filter:blur(var(--panel-blur));pointer-events:none;
    transition:transform var(--panel-close-dur) var(--panel-ease),
      opacity var(--panel-close-dur) var(--panel-ease),
      filter var(--panel-close-dur) var(--panel-ease),
      visibility 0s linear var(--panel-close-dur);
    will-change:transform,opacity,filter}
  .nav.open .nav-links{visibility:visible;transform:translateY(0);opacity:1;filter:blur(0);
    pointer-events:auto;
    transition:transform var(--panel-open-dur) var(--panel-ease),
      opacity var(--panel-open-dur) var(--panel-ease),
      filter var(--panel-open-dur) var(--panel-ease),visibility 0s}
  /* laid out whether or not the panel is open, since the panel itself is what hides now */
  .nav-links a:not(.btn){display:flex;align-items:center;min-height:52px;
    padding:0 24px;font-size:1.0625rem;color:var(--ink);border-top:1px solid var(--line)}
  .nav-links a.btn{order:-1;margin:0 24px 6px;justify-content:center}
}
@media (prefers-reduced-motion:reduce){
  .nav-links{transition:none !important;filter:none !important;transform:none !important}
}
@media (prefers-reduced-motion:reduce){
  .nav-bars::before,.nav-bars::after,.nav-bars span{transition:none}
}

/* Byline. Google's guidance on helpful content asks outright whether a page carries one and
   whether it leads somewhere that says who the person is. Added 28 Aug 2026. */
.byline{margin-top:18px;font-size:.875rem;color:var(--muted)}
.byline a{color:var(--ink-2);border-bottom:1px solid var(--hair)}
.byline a:hover{color:var(--ink);border-color:var(--accent)}

/* Footer and spacing, 28 Aug 2026. Mark: the footer is too big and the text is hard to read.
   The colour was not the problem, #C0BFBF on #26262B is 8.2 to 1. The problem was a permanent
   underline beneath every one of eighteen links, headings at 55% opacity, and a lot of air. */
.foot{padding-bottom:26px;font-size:.9375rem}
.foot a{color:#DEDDDC;border-bottom-color:transparent}
.foot a:hover{color:#fff;border-bottom-color:#fff}
.foot-h{opacity:.72;margin-bottom:9px}
.foot-cols{padding-top:26px;padding-bottom:22px;gap:22px}
.foot-col nav{gap:2px}
.foot-in{padding-top:16px;gap:10px}
.foot-in a{color:#EDECEA}
@media (min-width:760px){.foot-cols{gap:36px}}

/* Less air between sections, and much less inside the closing block, which was one heading
   and one sentence sitting in ninety pixels of padding at each end. */
/* One rule for every width. This sits AFTER the min-width:900px block and is not
   inside it, so it wins everywhere; the earlier `section{padding:...}` near the top
   of this file never applies. Do not add a third one. 24px on a phone, 52px on a
   desktop, scaling between. */
section{padding:clamp(14px,3.4vw,38px) 0}
.close{padding:clamp(16px,2.8vw,36px) 0}
.nextup{padding-top:0;padding-bottom:clamp(24px,2.8vw,36px)}

/* Where you are on the page. The contents list marks the section you are reading. */
.toc a.current{color:var(--ink);border-left-color:var(--accent);font-weight:500}
/* The Lapdolls sidebar is a summary, not a contents list. It was four links to "#", which went
   nowhere when clicked. Same look, no false affordance. Fixed 28 Aug 2026. */
.toc-facts{list-style:none;margin:0;padding:0;display:grid;gap:0}
.toc-facts li{font-size:.875rem;line-height:1.45;color:var(--ink-2);padding:7px 0 7px 13px;
  border-left:2px solid var(--line)}
/* Four link groups in a three column grid left the fourth stranded on its own row with a wide
   empty space beside it. Four columns on wide screens, which also shortens the footer again. */
@media (min-width:1000px){.foot-cols{grid-template-columns:repeat(4,1fr);gap:32px}}

/* The nav call to action was unreadable, and had been since it was built: .nav-links a sets
   colour at specificity (0,1,1) and .btn sets it at (0,1,0), so the link colour won and the
   button rendered #666669 on #26262B, a contrast ratio of 2.63 to 1 where 4.5 is the floor.
   Measured on the live site 28 Aug 2026, not eyeballed. */
.nav-links a.btn{color:var(--ground)}
.nav-links a.btn:hover{color:var(--ground)}

/* ============================================================================
   Motion, added 30 Aug 2026. Two transitions from transitions.dev, no more.
   The scale is theirs; the colours are ours, so the shimmer matches the site
   instead of their grey and black. Every rule below has a reduced motion guard.
   ============================================================================ */
:root{
  --panel-open-dur:400ms;
  --panel-close-dur:350ms;
  --panel-blur:2px;
  --panel-ease:cubic-bezier(.22,1,.36,1);
  --nav-panel-travel:-10px;   /* the drawer starts just above where it lands */

  --think-hold:1600ms;
  --think-swap:150ms;
  --think-gap:50ms;
  --think-distance:8px;
  --think-blur:2px;
  --think-shimmer:2000ms;
  --think-ease:ease-in-out;
  --think-base:var(--ink-2);
  --think-highlight:var(--ink);
}

/* The free check used to sit on one static line for the whole scan, which is a
   few seconds of nothing while a visitor decides whether the thing is broken.
   The line now says what the scanner is actually doing, shimmering while each
   step holds and swapping to the next. The states in audit.js are literal: the
   scanner reads the home page, then robots and the sitemap, then up to four
   inner pages, then runs its checks. No model is involved and nothing in the
   copy suggests one is. */
.t-think{position:relative;display:inline-block;text-align:left}
.t-think-sizer{display:block;visibility:hidden;white-space:nowrap}
.t-think-text{position:absolute;top:0;left:0;right:0;display:block;
  color:var(--think-base);white-space:nowrap;
  transform:translateY(0);filter:blur(0);opacity:1;
  transition:transform var(--think-swap) var(--think-ease),
    filter var(--think-swap) var(--think-ease),
    opacity var(--think-swap) var(--think-ease);
  will-change:transform,filter,opacity}
.t-think-text::before{content:attr(data-text);position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(90deg,transparent 0%,transparent 40%,
    var(--think-highlight) 50%,transparent 60%,transparent 100%);
  background-size:400% 100%;background-repeat:no-repeat;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  -webkit-text-fill-color:transparent;
  animation:t-think-shimmer var(--think-shimmer) linear infinite}
@keyframes t-think-shimmer{0%{background-position:100% 0}100%{background-position:0% 0}}
.t-think-text.is-exit{transform:translateY(calc(var(--think-distance) * -1));
  filter:blur(var(--think-blur));opacity:0}
.t-think-text.is-enter-start{transition:none;transform:translateY(var(--think-distance));
  filter:blur(var(--think-blur));opacity:0}
@media (prefers-reduced-motion:reduce){
  .t-think-text{transition:none !important;transform:none !important;filter:none !important}
  .t-think-text::before{display:none !important}
}


/* ---- before/after comparison slider (.ba) -------------------------------
   Used on the home page and on /work/lapdolls. The drag target is an
   <input type="range"> laid over the whole image, so touch, mouse, keyboard
   and screen readers all work without hand-written handlers. No transitions,
   so there is nothing to disable under prefers-reduced-motion. */
.ba{margin:22px 0 6px}
.ba-stage{position:relative;aspect-ratio:1200/750;overflow:hidden;border:1px solid var(--line);background:var(--shot);touch-action:pan-y}
.ba-img,.ba-img img{display:block;width:100%;height:100%;object-fit:cover}
.ba-clip{position:absolute;inset:0;clip-path:inset(0 calc(100% - var(--p,50%)) 0 0)}
.ba-div{position:absolute;top:0;bottom:0;left:var(--p,50%);width:2px;margin-left:-1px;background:var(--surface);box-shadow:0 0 0 1px rgba(0,0,0,.28);pointer-events:none}
.ba-grip{position:absolute;top:50%;left:50%;width:46px;height:46px;margin:-23px 0 0 -23px;border-radius:50%;background:var(--surface);border:1px solid var(--edge);box-shadow:0 1px 7px rgba(0,0,0,.3)}
.ba-grip::before,.ba-grip::after{content:"";position:absolute;top:50%;margin-top:-5px;width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent}
.ba-grip::before{left:11px;border-right:7px solid var(--accent)}
.ba-grip::after{right:11px;border-left:7px solid var(--accent)}
.ba-range{position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;opacity:0;cursor:ew-resize;-webkit-appearance:none;appearance:none;background:transparent}
.ba-range::-webkit-slider-thumb{-webkit-appearance:none;width:46px;height:46px}
.ba-range::-moz-range-thumb{width:46px;height:46px;border:0;background:transparent}
.ba-stage:has(.ba-range:focus-visible) .ba-grip{outline:3px solid var(--accent);outline-offset:3px}
.ba-tag{position:absolute;bottom:10px;font:600 12px/1 ui-sans-serif,system-ui,-apple-system,sans-serif;letter-spacing:.09em;text-transform:uppercase;color:#fff;background:rgba(30,30,34,.82);padding:7px 10px;pointer-events:none}
.ba-l{left:10px}.ba-r{right:10px}
.ba figcaption{margin-top:10px;font-size:.8125rem;line-height:1.55;color:var(--ink-2)}
@media (max-width:560px){.ba-tag{font-size:11px;padding:5px 7px;bottom:7px;letter-spacing:.06em}.ba-grip{width:44px;height:44px;margin:-22px 0 0 -22px}}


/* ---- section eyebrows, FAQ grid, and one restrained reveal ---------------
   Added 31 Aug 2026. The pages below the fold were a single left-aligned
   column of grey text on a white ground for four sections running. This is
   layout and colour, not decoration: an accent label per section, the FAQ in
   two columns so it stops leaving half the screen empty, and one alternating
   ground so the run of whites breaks up.
   Motion is the transitions.dev texts-reveal, the same system already used
   for the mobile menu and the audit thinking line. One deviation from the
   snippet, on purpose: the hidden state is scoped to .is-armed, which only
   JavaScript adds, so with JavaScript off nothing is ever invisible. */

:root{
  --stagger-dur:500ms;
  --stagger-distance:12px;
  --stagger-stagger:40ms;
  --stagger-blur:3px;
  --stagger-ease:cubic-bezier(0.22, 1, 0.36, 1);
}

.eyebrow{
  font:600 12px/1 ui-sans-serif,system-ui,-apple-system,sans-serif;
  letter-spacing:.14em;text-transform:uppercase;
  color:var(--accent);margin:0 0 10px;
}
.eyebrow::after{
  content:"";display:block;width:26px;height:2px;
  background:var(--accent);margin-top:8px;opacity:.55;
}

#faq{background:var(--raise)}

.qa-grid{margin-top:20px;display:grid;gap:24px 44px}
@media (min-width:900px){.qa-grid{grid-template-columns:1fr 1fr}}
.qa{border-top:2px solid var(--accent-soft);padding-top:16px}
.qa h3{margin:0 0 8px;color:var(--ink)}
.qa p{margin:0;max-width:52ch}

/* texts-reveal, from transitions.dev */
.t-stagger.is-armed .t-stagger-line{
  opacity:0;
  transform:translateY(var(--stagger-distance));
  filter:blur(var(--stagger-blur));
  transition:
    opacity   var(--stagger-dur) var(--stagger-ease),
    transform var(--stagger-dur) var(--stagger-ease),
    filter    var(--stagger-dur) var(--stagger-ease);
  will-change:transform,opacity,filter;
}
.t-stagger.is-armed .t-stagger-line--2{transition-delay:var(--stagger-stagger)}
.t-stagger.is-armed.is-shown .t-stagger-line{
  opacity:1;transform:translateY(0);filter:blur(0);
}
@media (prefers-reduced-motion:reduce){
  .t-stagger.is-armed .t-stagger-line{transition:none!important;opacity:1;transform:none;filter:none}
}


/* the studio band, with a face in it */
.who-grid{display:grid;gap:24px;align-items:start}
@media (min-width:760px){.who-grid{grid-template-columns:190px 1fr;gap:40px}}
.who-shot{margin:0;width:140px}
@media (min-width:760px){.who-shot{width:190px}}
.who-shot img{display:block;width:100%;height:auto;border-radius:50%;border:4px solid var(--surface);box-shadow:0 2px 16px rgba(0,0,0,.16)}


/* Work cards: the screenshot spans the whole card rather than sitting in the
   right-hand column, so it renders about 1100px wide instead of 744px. Added
   31 Aug 2026. Nothing is cropped; the picture is simply given the full width. */
@media (min-width:900px){
  .work-row > .work-shot{grid-column:1 / -1;margin:0 0 10px}
}


/* The editor demo on a phone. Everything below 900px was one full-width kitten
   card after another, so the right-hand panel alone ran to about 900px. Two
   columns and tighter chrome puts it back inside a screen or so, and it reads
   more like the phone site it is imitating. */
@media (max-width:899px){
  .eng{gap:14px}
  .panel{padding:14px}
  .panel-h{margin-bottom:10px}
  .kits{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .kit-b{padding:10px 11px}
  .kit-n{font-size:1rem}
  .kit-c{font-size:.75rem;margin:0 0 5px}
  .kit-d{font-size:.75rem;line-height:1.5}
  .kit-badges{margin-top:8px}
  .kit-cta{margin-top:9px;padding:7px 11px;font-size:.75rem}
  .ed-row{gap:8px}
  .eng-note{margin-top:14px}
}


/* Back to top. Injected by site.js so it exists on every page without touching
   26 files. Shown only once the hero has scrolled away, using the same
   IntersectionObserver approach as the sticky nav rather than a scroll handler.
   46px square, which clears the 44px tap target floor. */
.totop{position:fixed;right:18px;bottom:18px;z-index:50;width:46px;height:46px;
  display:grid;place-items:center;border:1px solid var(--edge);border-radius:50%;
  background:var(--surface);color:var(--accent);cursor:pointer;padding:0;
  box-shadow:0 2px 12px rgba(0,0,0,.16);
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity .25s ease,transform .25s cubic-bezier(.22,1,.36,1),visibility .25s}
.totop.is-on{opacity:1;visibility:visible;transform:translateY(0)}
.totop:hover{border-color:var(--accent);color:var(--accent-2)}
.totop:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
.totop svg{width:19px;height:19px;display:block}
@media (max-width:560px){.totop{right:12px;bottom:12px;width:44px;height:44px}}
@media (prefers-reduced-motion:reduce){.totop{transition:opacity .01s}}


/* ---------------------------------------------------------------------------
   1 September 2026.

   Two things Mark saw on a wide screen, both fixed here rather than in the markup.

   1. Sections sat in about 104px of padding between them at 1440px. The section
      rule above is now clamp(20px,3.4vw,38px), so the same gap is about 76px.
      There is still only ONE section padding rule. Do not add another.

   2. Recent work: the screenshot spanned the whole card, so it rendered about
      1100px wide and one project filled a screen on its own. It now sits in a
      440px column to the right of the writing, from 1000px up. Below that it is
      still full width above the text, which is right on a phone. The `sizes`
      attribute on those pictures was updated to match, so the browser stops
      downloading the 1200px file for a 440px slot.
   --------------------------------------------------------------------------- */
@media (min-width:1000px){
  .work-row{grid-template-columns:minmax(0,1fr) 440px;gap:16px 48px}
  .work-row > .work-head{grid-column:1}
  .work-row > .work-body{grid-column:1}
  .work-row > .work-shot{grid-column:2;grid-row:1 / span 2;margin:0}
}

/* The editor section was a heading, a sentence and a button in the left half of a
   wide screen and nothing at all in the right. The diagram makes the same claim the
   sentence does: one edit, four places. It is drawn, not photographed, so there is
   nothing in it that has to be kept current. It is fully visible with no animation;
   the animation only runs for people who have not asked for less motion. */
.eng-split{display:grid;gap:26px;align-items:center}
@media (min-width:1000px){.eng-split{grid-template-columns:1fr 1fr;gap:56px}}
.fanout{margin:0;display:none}
/* It exists to fill the empty right half of a wide screen. On a phone there is no empty
   half, the sentence above says the same thing, and the home page is already long. */
@media (min-width:1000px){.fanout{display:block}}
.fanout svg{display:block;width:100%;height:auto;max-width:520px}
.fanout figcaption{margin-top:12px;font-size:.8125rem;line-height:1.55;color:var(--ink-2);max-width:46ch}
.fo-line{fill:none;stroke:var(--accent);stroke-opacity:.75;stroke-width:1.25}
.fo-src rect{fill:var(--accent)}
.fo-src text{fill:#FEFEFD;font-family:var(--f-body);font-size:14px}
.fo-chip rect{fill:var(--surface);stroke:var(--line);stroke-width:1}
/* depth on the diagram, 2 Sep 2026: the chips and the source box cast a small shadow so the
   panel does not read as flat print. drop-shadow follows the rect's rounded corners; a box-shadow
   on an SVG element would not. */
.fo-chip rect{filter:drop-shadow(0 1px 1.5px color-mix(in srgb,var(--ink) 10%,transparent)) drop-shadow(0 10px 18px color-mix(in srgb,var(--deep) 14%,transparent))}
.fo-src rect{filter:drop-shadow(0 2px 3px color-mix(in srgb,var(--deep) 30%,transparent)) drop-shadow(0 12px 22px color-mix(in srgb,var(--deep) 26%,transparent))}
.fo-chip text{fill:var(--ink-3);font-family:var(--f-body);font-size:13.5px}
@media (prefers-reduced-motion:no-preference){
  .fanout .fo-line{stroke-dasharray:1;animation:fo-draw 6s ease-in-out infinite}
  .fanout .fo-chip{animation:fo-pop 6s ease-in-out infinite}
  .fanout .fo-d1{animation-delay:0s}
  .fanout .fo-d2{animation-delay:.4s}
  .fanout .fo-d3{animation-delay:.8s}
  .fanout .fo-d4{animation-delay:1.2s}
}
@keyframes fo-draw{
  0%,4%{stroke-dashoffset:1;opacity:1}
  26%{stroke-dashoffset:0}
  88%{stroke-dashoffset:0;opacity:1}
  96%,100%{stroke-dashoffset:0;opacity:0}
}
@keyframes fo-pop{
  0%,18%{opacity:0}
  30%,88%{opacity:1}
  96%,100%{opacity:0}
}

/* ---------------------------------------------------------------------------
   1 September 2026, second pass. Mark, on a phone: these sections are way too
   long. Measured at 390x844 before changing anything: the home page was
   11,188px, about 13 screens, and Recent work alone was 3,054px of that. The
   two phone-shaped screenshots were 747px each, so a reader scrolled a whole
   screen of picture per project before reaching a word about it.
   --------------------------------------------------------------------------- */
@media (max-width:999px){
  /* The top of each screenshot rather than all of it. Same picture, same phone
     shape, cut where the reader has already got the idea, with the cut softened
     so it reads as deliberate rather than broken. */
  /* First attempt cropped these to 400px and Mark was right: it cut the example in
     half and the reader saw a header and nothing else. Nothing is cut now. The phone
     screenshot is simply shown narrower, so the whole page is there at about 480px
     instead of 747px. */
  .work-shot{width:64%;min-width:200px;max-width:260px;margin-inline:0}
  .work-shot img{max-height:none}

  /* 1.75 line-height is generous on a 390px screen. It costs about 2.5px a line
     across roughly sixty lines of body copy on this page. 1.62 still reads
     easily at 17px, which is the size that matters and is not being changed. */
  .why-body p,.work-row p,.work-specs li{line-height:1.62}
  .why-grid{gap:22px}
  .why-lead{margin-top:14px;line-height:1.5}
  .work-row{padding:18px 0;gap:10px}
}

/* One project on a phone, both on a desktop. 1 September 2026, Mark's call.
   Recent work was still 2,337px on a 390px screen after the picture was capped,
   and the rest of it is writing rather than spacing. The second card is hidden
   below 1000px, not deleted: it stays in the HTML, so search engines and the AI
   answers still read both client builds, and both are on /work. The sentence
   under the heading changes with it, so the page never says two and show one. */
.narrow-only{display:none}
@media (max-width:999px){
  .wide-only{display:none}
  .narrow-only{display:inline}
  #work .work-list > .work-row:nth-child(2){display:none}
  /* :last-child still matches the hidden card, so the visible one needs its own rule */
  #work .work-list > .work-row:first-child{border-bottom:1px solid var(--line)}
}

/* Less air inside a section on a phone as well as between them. 1 September 2026. */
@media (max-width:999px){
  .sec-head{margin-bottom:16px}
  .work-row{padding:14px 0}
  .work-shot figcaption{margin-top:6px}
}

/* Same dashes as the work cards, for prose that is really a list. The first
   paragraph of "Why it matters" packed three requirements into one sentence and
   then said "all three", which asked the reader to count them out of a sentence. */
.dash-list{list-style:none;margin:0;padding:0;display:grid;gap:8px;max-width:60ch}
.dash-list li{position:relative;padding-left:20px;font-size:.9375rem;line-height:1.6;color:var(--ink-2)}
.dash-list li::before{content:"";position:absolute;left:2px;top:.6em;width:6px;height:1px;background:var(--accent)}

/* The five cost bands on /breeder-website-cost were five paragraphs, each opening
   with a price in bold. A price ladder is a table: the prices line up and can be
   compared down a column, which is the whole point of the section.
   Three columns do not fit a 390px screen, so below 760px the table becomes
   stacked blocks, with each cell labelled by its column heading. No horizontal
   scrolling, and nothing is hidden. 1 September 2026. */
.band-t td.band-p{font-family:var(--f-display);color:var(--accent);white-space:nowrap;font-size:1.0625rem}
.band-t td.band-p span{display:block;font-family:var(--f-body);font-size:.75rem;color:var(--muted);white-space:normal}
@media (min-width:760px){
  .band-t th:first-child,.band-t td:first-child{width:150px}
  .band-t th:nth-child(2),.band-t td:nth-child(2){width:210px}
}
@media (max-width:759px){
  .band-t,.band-t tbody,.band-t tr,.band-t td{display:block;width:100%}
  .band-t thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .band-t tr{padding:14px 0;border-bottom:1px solid var(--line)}
  .band-t td{border:0;padding:0}
  .band-t td.band-p{font-size:1.25rem;margin-bottom:2px}
  .band-t td:nth-child(2){color:var(--ink);font-weight:500;margin-bottom:4px}
  .band-t td:nth-child(3){color:var(--ink-2);line-height:1.6}
}

/* A link inside a sentence goes back to being inline. 1 September 2026.

   The 31 August tap-target sweep gave every .link-u `display:inline-flex` and
   `min-height:44px` below 900px. That is right for a link standing on its own,
   and wrong for one inside running text: an inline-flex link cannot break across
   lines and forces a 44px line box, so paragraphs containing a link rendered with
   uneven line spacing and stranded fragments on a phone. Found by screenshotting
   the home page at 390px, not by reading the CSS.

   WCAG 2.5.8 exempts targets that are inline in a sentence from the minimum size
   rule for exactly this reason, so nothing is lost by scoping it. Standalone
   .link-u links keep their 44px. */
@media (max-width:899px){
  p .link-u,li .link-u,figcaption .link-u{display:inline;min-height:0;align-items:initial}
}

/* The about page had no photograph of the person it is about, and an empty right
   half on a wide screen next to a 22ch heading. Same picture as the home page,
   which is the only photograph of Mark on the site. 1 September 2026. */
.about-hero{display:grid;gap:26px}
.me-shot{margin:0;width:150px}
.me-shot img{display:block;width:100%;height:auto;border-radius:50%;border:4px solid var(--surface);box-shadow:0 2px 16px rgba(0,0,0,.16)}
.me-shot figcaption{margin-top:10px;font-size:.8125rem;color:var(--ink-2)}
@media (min-width:900px){
  .about-hero{grid-template-columns:minmax(0,1fr) 240px;gap:56px;align-items:center}
  .me-shot{width:240px}
}

/* Folds. Only ever created by site.js on phones, so nothing here reaches a desktop. */
.fold{border-top:1px solid var(--line)}
.fold > summary{list-style:none;display:flex;align-items:center;justify-content:space-between;gap:14px;min-height:48px;padding:10px 0;cursor:pointer;color:var(--ink);font-weight:500;font-size:1rem;line-height:1.35}
.fold > summary::-webkit-details-marker{display:none}
.fold > summary::after{content:"";flex:none;width:9px;height:9px;border:solid var(--accent);border-width:0 1.5px 1.5px 0;transform:rotate(45deg);margin-right:6px;transition:transform .2s}
.fold[open] > summary::after{transform:rotate(225deg);margin-top:5px}
.fold > summary h3{margin:0;font-size:1.0625rem;line-height:1.35}
.fold > summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.fold > *:not(summary){margin-bottom:14px}
.fold.fold-q > p{margin-top:0}
.fold.fold-t,.fold.fold-s{margin-top:18px}
.fold.fold-foot{border-top:0}
.fold.fold-foot > summary{color:var(--ink-2)}
.fold.fold-foot .foot-cols{padding-top:6px}
.prose .fold > summary h3,.art .fold > summary h3{margin-top:0}
.qa .fold{border-top:0}
.qa .fold > summary{padding-top:0;min-height:0}
@media (prefers-reduced-motion:reduce){.fold > summary::after{transition:none}}
