/* FCD marketing site: thermographic ember on warm ink. Assumes assets/tokens.css. */
*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
/* No overflow-x:hidden on the body. It does not fix horizontal overflow, it conceals it, and it
   is why the .cta-form input below overran every phone width unnoticed. With it gone, the
   responsive test in app/test/site-claims.test.js catches the next one on the day it lands. */
body{
  margin:0;background:var(--bg);color:var(--text);
  font-family:var(--font-body);font-size:var(--step-0);line-height:1.6;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
h1,h2,h3{font-family:var(--font-display);font-weight:600;letter-spacing:-.02em;line-height:1.02;text-wrap:balance;margin:0}
p{margin:0;text-wrap:pretty}
a{color:inherit;text-decoration:none}
img,svg{max-width:100%;display:block}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:3px}
.tabular{font-variant-numeric:tabular-nums}

/* layout */
.shell{max-width:1200px;margin:0 auto;padding:0 var(--shell-pad)}
section{padding:clamp(3.5rem,9vw,7rem) 0;position:relative}
.eyebrow{font-family:var(--font-mono);font-size:.74rem;font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);margin:0 0 1rem}
.eyebrow.cool{color:var(--plasma-cool)}
.lede{color:var(--text-muted);font-size:var(--step-1);max-width:60ch;line-height:1.5}
.src{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);margin-top:.7rem;line-height:1.5}
.src a{color:var(--text-muted);border-bottom:1px solid var(--border-strong)}
.src a:hover{color:var(--accent)}

/* header */
.hdr{position:sticky;top:0;z-index:40;backdrop-filter:blur(10px);
  background:linear-gradient(180deg,rgba(20,16,13,.92),rgba(20,16,13,.72));
  border-bottom:1px solid var(--border)}
.hdr__in{display:flex;align-items:center;justify-content:space-between;gap:1rem;height:64px}
.brand{display:flex;align-items:center;gap:.6rem;min-height:var(--target)}
.brand svg{width:34px;height:34px;flex:none}
/* THE LOCKUP. The wordmark is two lines beside a 34px mark, and body line-height (1.6) was being
   inherited by both of them: 18px of type became 29px of box, 9px became 15px, and the stack came
   out at 45px against a 34px mark. The F sat right and CYBER DEFENCE hung out of the bottom.
   Set explicitly here, in one place, so the two lines total less than the mark and sit centred
   against it. Nothing about this is decorative: a wordmark that does not line up with its own mark
   is the first thing a visitor sees and the first thing that says nobody checked. */
.brand span{display:flex;flex-direction:column;justify-content:center;line-height:1}
.brand b{font-family:var(--font-display);font-weight:700;font-size:1.15rem;letter-spacing:-.01em;
  line-height:1;display:block}
/* The gap between the two lines is margin, not line-height, so it is one number to change and it
   does not move the optical top of the F. */
.brand em{font-family:var(--font-mono);font-style:normal;font-size:.58rem;letter-spacing:.28em;
  text-transform:uppercase;color:var(--text-muted);display:block;line-height:1;margin-top:.3rem}
.nav{display:flex;align-items:center;gap:1.6rem}
.nav a{font-size:.92rem;color:var(--text-muted)}
.nav a:hover{color:var(--text)}
.nav__links{display:flex;gap:1.6rem;align-items:center}
.nav__signin{font-size:.92rem}
/* Every header control clears the 44px target floor. The bar is 64px, so they fit. */
.nav__links a,.nav__signin,.hdr .nav .btn{display:flex;align-items:center;min-height:var(--target)}
/* `.nav a` outranks `.btn--primary`, so the header CTA was rendering --text-muted on ember:
   roughly 1.9:1, against the 4.5:1 the rest of this palette is built to. */
.hdr .nav .btn--primary,.hdr .nav .btn--primary:hover{color:var(--accent-ink)}
/* The header CTA used to vanish under 520px, leaving a header with a brand and nothing else.
   It now shrinks instead. The persistent bottom rail is the mobile CTA and this is the desktop
   one, and at no width may both be absent. */
@media (max-width:820px){.nav__links{display:none}}
@media (max-width:520px){
  .nav__signin{display:none}
  .hdr .nav .btn{padding:0 var(--space-2);font-size:.82rem}
}
/* At 320px the brand wordmark and the CTA together want 320px inside a 285px row, so the CTA
   wrapped onto two lines inside a 44px button. The mark alone still links home, and the call to
   action is the thing that has to stay whole. */
@media (max-width:400px){
  .brand span{display:none}
  .hdr .nav .btn{white-space:nowrap}
}
/* Anchor navigation has to clear the sticky bar, or the heading it jumps to sits under it. */
:target,section[id],[id]{scroll-margin-top:calc(64px + var(--space-3))}

/* buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:0 1.35rem;
  font-family:var(--font-body);font-weight:700;font-size:.96rem;border-radius:var(--radius);cursor:pointer;
  border:0;transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),background var(--dur) var(--ease)}
.btn--primary{background:var(--accent);color:var(--accent-ink);box-shadow:0 0 0 rgba(244,101,43,0)}
.btn--primary:hover{transform:translateY(-1px);box-shadow:var(--shadow-glow)}
.btn--primary:active{transform:translateY(0) scale(.99)}
.btn--ghost{background:transparent;color:var(--text);border:1px solid var(--border-strong)}
.btn--ghost:hover{border-color:var(--accent);color:var(--accent)}
.btn--sm{min-height:40px;padding:0 1rem;font-size:.86rem}
@media (prefers-reduced-motion:reduce){.btn{transition:none}}

/* hero */
.hero{padding-top:clamp(2.5rem,6vw,4.5rem)}
.hero__grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(1.5rem,4vw,3.5rem);align-items:center}
/* FCD-053: the number leads and is the largest object on the page (ask #1). Size, never a colour
   tint, carries the emphasis. The H1 below it builds the customer picture at a supporting size. */
.hero__big{font-family:var(--font-display);font-weight:700;color:var(--text);
  font-size:clamp(4rem,13vw,8.6rem);line-height:.86;letter-spacing:-.02em;margin:.4rem 0 0}
.hero__biglab{margin:.9rem 0 0;font-size:clamp(1.05rem,2vw,1.32rem);color:var(--text-muted);
  max-width:34ch;line-height:1.4}
.hero h1{margin-top:1.8rem;font-size:clamp(1.5rem,3.3vw,2.5rem);font-weight:600;line-height:1.18;
  color:var(--text);max-width:26ch;text-wrap:balance}
.hero__sub{margin-top:1.2rem;font-size:clamp(1.02rem,2vw,1.22rem);color:var(--text-muted);max-width:44ch}
.hero__cta{display:flex;flex-wrap:wrap;gap:.8rem;margin-top:2rem}
.hero__meta{margin-top:1.6rem;font-family:var(--font-mono);font-size:.76rem;color:var(--text-dim);display:flex;gap:1.4rem;flex-wrap:wrap}
.hero__meta b{color:var(--text-muted);font-weight:500}
/* FCD-055 copy pass: the empathy line, the pivot, the mid-page CTAs and their friction-reducers */
.hero__for{margin:.9rem 0 0;font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);max-width:46ch}
.cg__lede{margin:0 0 var(--space-5);color:var(--text-muted);max-width:var(--measure);font-size:var(--step-0);line-height:1.5}
.shift__turn{margin:var(--space-5) 0 0;color:var(--text);font-size:clamp(1.15rem,2.2vw,1.5rem);
  line-height:1.4;max-width:52ch;font-weight:500;text-wrap:balance}
.proof__cta{margin:var(--space-5) 0 0;display:flex;flex-direction:column;align-items:flex-start;gap:.7rem}
.cta__fr{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);max-width:52ch}
.cta__fr b{color:var(--text-muted);font-weight:500}
.hero__glow{position:absolute;inset:0;pointer-events:none;z-index:-1;
  background:radial-gradient(60% 55% at 78% 22%,rgba(244,101,43,.20),transparent 62%)}
@media (max-width:860px){.hero__grid{grid-template-columns:1fr}.hero__sub{max-width:52ch}}

/* forensic attack-log panel */
.term{background:linear-gradient(180deg,var(--surface),var(--bg-2));border:1px solid var(--border-strong);
  border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-2)}
.term__bar{display:flex;align-items:center;gap:.5rem;padding:.6rem .9rem;border-bottom:1px solid var(--border);
  background:var(--surface-2)}
.term__dot{width:9px;height:9px;border-radius:50%}
.term__title{font-family:var(--font-mono);font-size:.72rem;color:var(--text-muted);margin-left:.4rem}
.term__body{padding:1rem 1.1rem;font-family:var(--font-mono);font-size:.79rem;line-height:1.85;color:var(--text-muted)}
.term__body .ln{white-space:pre-wrap;word-break:break-word}
.term__body .t{color:var(--text-dim)}
.term__body .hot{color:var(--ember-hi)}
.term__body .crit{color:var(--crit)}
.term__body .ok{color:var(--good)}
.term__body .em{color:var(--text)}
.cursor{display:inline-block;width:8px;height:1.05em;background:var(--accent);vertical-align:-2px;
  animation:blink 1.1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.cursor{animation:none}}

/* section headers */
.sec-head{max-width:64ch;margin-bottom:2.6rem}
.sec-head h2{font-size:clamp(1.9rem,4.2vw,3rem)}
.sec-head .lede{margin-top:1rem}

/* the cadence infographic */
.cadence{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);padding:clamp(1.3rem,3vw,2.2rem)}
.track{margin:1.4rem 0}
.track__lab{display:flex;justify-content:space-between;align-items:baseline;font-family:var(--font-mono);
  font-size:.76rem;color:var(--text-muted);margin-bottom:.55rem}
.track__lab b{color:var(--text);font-weight:500;font-family:var(--font-body);font-size:.92rem}
.comb{height:56px;border-radius:var(--radius);position:relative;overflow:hidden;border:1px solid var(--border)}
.comb--sparse{background:
  linear-gradient(90deg,var(--accent) 0 2px,transparent 2px);
  background-repeat:no-repeat;background-color:var(--bg-2)}
.comb--dense{background:
  repeating-linear-gradient(90deg,var(--ember-hi) 0 2px,transparent 2px 11px);
  background-color:var(--bg-2)}
.comb--dense::after{content:"";position:absolute;inset:0;background:radial-gradient(120% 200% at 100% 50%,rgba(244,101,43,.28),transparent 55%)}
.cadence__foot{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-top:1.6rem}
.fig{display:flex;flex-direction:column;gap:.15rem}
.fig .n{font-family:var(--font-mono);font-weight:700;font-size:clamp(1.4rem,3vw,1.9rem);color:var(--text)}
.fig .k{font-size:.86rem;color:var(--text-muted)}
@media (max-width:640px){.cadence__foot{grid-template-columns:1fr}}

/* asymmetry infographic */
.asym{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1rem,2.5vw,1.6rem)}
@media (max-width:760px){.asym{grid-template-columns:1fr}}
.face{border-radius:var(--radius-lg);padding:clamp(1.3rem,3vw,2rem);position:relative;overflow:hidden;min-height:340px;
  border:1px solid var(--border)}
/* FCD-053 fix: the attacker face was a gaudy full ember fill. Ember is the dominant-plus-sharp
   accent, so here it lands as a signal at the edge, not a wash: a restrained warm surface with a
   2px ember left rule. The near-black text overrides are gone; the panel reads in bone like the
   rest of the page. The defender face stays plasma-cool, so the asymmetry reads through accent
   temperature, not through one billboard-orange box. */
/* A full ember-tinted edge, not a single bright rule down one side: a left-accent-bar on a tinted
   box is itself a recognisable "written by a model" pattern (see the note further down this file),
   so the heat surrounds the panel evenly. The defender face keeps a plain hairline, so the
   asymmetry reads through the edge temperature, not a directional stripe. */
.face--attack{background:linear-gradient(158deg,var(--surface-3),var(--surface));
  border:1px solid var(--ember-line)}
.face--defend{background:linear-gradient(200deg,var(--surface-2),var(--bg-2))}
.face__tag{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;
  display:inline-block;padding:.25rem .6rem;border-radius:4px;margin-bottom:1.1rem}
.face--attack .face__tag{background:var(--accent-ink);color:var(--ember-hi)}
.face--defend .face__tag{background:var(--surface-3);color:var(--plasma-cool)}
.face h3{font-size:var(--step-2)}
.face--attack h3{color:var(--text)}
.face--attack .face__q{color:var(--text-muted)}
.face--attack .face__list li{color:var(--text-muted)}
.face__q{margin-top:.7rem;font-size:1.02rem;line-height:1.45}
.face__list{list-style:none;margin:1.2rem 0 0;padding:0;display:flex;flex-direction:column;gap:.6rem}
.face__list li{position:relative;padding-left:1.35rem;font-size:var(--step-0);line-height:1.4}
.face__list li::before{content:"";position:absolute;left:0;top:.5em;width:7px;height:7px;border-radius:1px;transform:rotate(45deg)}
.face--attack .face__list li::before{background:var(--accent)}
.face--defend .face__list li::before{background:var(--plasma-cool)}
.face--defend h3{color:var(--text)}.face--defend .face__q{color:var(--text-muted)}.face--defend .face__list li{color:var(--text-muted)}
/* NO ACCENT BAR DOWN THE LEFT. A tinted box with a bright rule on one edge is the single most
   recognisable "written by a model" pattern on the web right now, and we are a company whose whole
   argument is that we are not producing generic output. It is also doing no work: the bar was
   decorating a box that a hairline and a ground already make into a box.
   Reported by Mike, on the site and on the sample PDF. */
.pull{margin-top:2.2rem;padding:1.5rem 1.7rem;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--radius)}
.pull q{font-family:var(--font-display);font-weight:500;font-size:clamp(1.15rem,2.6vw,1.55rem);color:var(--text);font-style:normal;line-height:1.3;quotes:none}
.pull .who{display:block;margin-top:.7rem;font-family:var(--font-mono);font-size:.76rem;color:var(--text-muted)}

/* solution / feature split */
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.4rem,4vw,3.5rem);align-items:center}
@media (max-width:860px){.split{grid-template-columns:1fr}}
.klist{display:flex;flex-direction:column;gap:1.15rem;margin-top:1.6rem}
.krow{display:grid;grid-template-columns:auto 1fr;gap:1rem;align-items:start}
.krow .kn{font-family:var(--font-mono);font-size:.8rem;color:var(--accent);padding-top:.2rem;font-weight:500}
.krow h4{font-family:var(--font-display);font-weight:600;font-size:1.15rem;margin:0 0 .2rem}
.krow p{color:var(--text-muted);font-size:var(--step-0)}

/* how-it-works loop */
.loop-wrap{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);padding:clamp(1.3rem,3vw,2.4rem)}
.loop svg{width:100%;height:auto}
.loop text{font-family:var(--font-mono)}


/* final CTA */
.cta-band{background:
  radial-gradient(80% 140% at 50% 120%,rgba(244,101,43,.28),transparent 60%),
  linear-gradient(180deg,var(--surface),var(--bg-2));
  border:1px solid var(--ember-line);border-radius:var(--radius-lg);padding:clamp(2rem,6vw,4rem);text-align:center}
.cta-band h2{font-size:clamp(2rem,5vw,3.2rem)}
.cta-band .lede{margin:1rem auto 0}
.cta-form{display:flex;gap:.6rem;justify-content:center;flex-wrap:wrap;margin-top:2rem}
/* This field used to carry min-width:min(320px,80vw). At 320px the band leaves 220.8px of room
   and the field demanded 256px, so it overran by 35px at every phone width, hidden by the
   body rule above. width:100% with min-width:0 lets it be as wide as it is given and no wider. */
.cta-form input{min-height:46px;padding:0 1rem;border-radius:var(--radius);border:1px solid var(--border-strong);
  background:var(--bg-2);color:var(--text);font-family:var(--font-mono);font-size:.9rem;
  flex:1 1 18rem;min-width:0;max-width:100%}
.cta-form input::placeholder{color:var(--text-dim)}
@media (max-width:560px){
  .cta-form{flex-direction:column}
  .cta-form input,.cta-form .btn{width:100%}
}
.cta-msg{margin-top:1rem;font-family:var(--font-mono);font-size:.82rem;color:var(--good);min-height:1.2em}

/* persistent side-rail CTA */
.rail{position:fixed;right:0;top:50%;transform:translateY(-50%);z-index:35;
  writing-mode:vertical-rl;background:var(--accent);color:var(--accent-ink);
  font-family:var(--font-body);font-weight:700;font-size:.82rem;letter-spacing:.02em;
  padding:1.1rem .6rem;border-radius:var(--radius) 0 0 var(--radius);cursor:pointer;border:0;
  box-shadow:var(--shadow-2);transition:padding var(--dur) var(--ease)}
.rail:hover{padding-right:.85rem}
.rail__mark{writing-mode:horizontal-tb;margin-bottom:.5rem}
.rail__mark svg{width:18px;height:18px}
@media (max-width:860px){
  .rail{writing-mode:horizontal-tb;right:auto;left:0;top:auto;bottom:0;width:100%;transform:none;
    border-radius:0;justify-content:center;display:flex;align-items:center;gap:.5rem;padding:.85rem;font-size:.95rem}
  .rail__mark{margin:0}
  /* The bar's height and the space reserved for it are one token, so the footer's last row can
     never end up underneath it again. */
  .rail{min-height:var(--rail-h)}
  body{padding-bottom:var(--rail-h)}
}

/* footer */
.foot{border-top:1px solid var(--border);padding:3rem 0 4rem}
.foot__in{display:flex;justify-content:space-between;gap:2rem;flex-wrap:wrap;align-items:flex-start}
.foot__brand{max-width:34ch}
.foot__brand p{color:var(--text-muted);font-size:var(--step-0);margin-top:.8rem}
.foot nav{display:flex;gap:2.5rem;flex-wrap:wrap}
.foot nav div{display:flex;flex-direction:column}
.foot nav b{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--text-dim)}
.foot nav a{color:var(--text-muted);font-size:var(--step--1);min-height:var(--target);display:flex;align-items:center}
.foot nav a:hover{color:var(--accent)}
.foot__legal{margin-top:2.5rem;font-family:var(--font-mono);font-size:.72rem;color:var(--text-dim);display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap}

/* reveal on load / scroll */
.reveal{opacity:0;transform:translateY(14px)}
.reveal.in{opacity:1;transform:none;transition:opacity var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease)}
@media (prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none}.reveal.in{transition:none}}

/* ============================================================================================
   FCD-027. Every value below is a token. No literal colour, radius, shadow or duration.
   ============================================================================================ */

.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* the loop diagram's stacked form. Its 15px SVG labels render at roughly 4px inside a 320px
   container, which no overflow test can catch, so under 860px the diagram is replaced by text. */
.loop-steps{display:none;list-style:none;margin:0;padding:0;counter-reset:step}
.loop-steps li{display:grid;grid-template-columns:auto 1fr;gap:var(--space-1) var(--space-3);
  padding:var(--space-3) 0;border-top:1px solid var(--border);counter-increment:step}
.loop-steps li::before{content:counter(step,decimal-leading-zero);font-family:var(--font-mono);
  font-size:var(--step--1);color:var(--accent);grid-row:span 2}
.loop-steps b{font-family:var(--font-display);font-weight:600;font-size:var(--step-0)}
.loop-steps span{color:var(--text-muted);font-size:var(--step--1);grid-column:2}
@media (max-width:860px){
  .loop{display:none}
  .loop-steps{display:block}
}

/* ---- the ledger : the one bold move ---------------------------------------------------- */
/* Full bleed inside the shell: cancel the shell's own inline padding, then re-apply it so the
   field can run edge to edge without a 100vw rule that would overflow beside a scrollbar. */
.ledger{margin-inline:calc(-1 * var(--shell-pad));padding-inline:var(--shell-pad);
  background:linear-gradient(180deg,var(--bg-2),var(--bg) 60%);
  border-top:1px solid var(--border);border-bottom:1px solid var(--border)}
/* The field is bounded rather than stretched across the section. 183 marks laid out over a
   1200px row is four thin bands; laid out over 27rem it is a dense block that reads as one
   object, and it stands the same height as the tally beside it. */
.ledger__body{display:flex;flex-wrap:wrap;gap:var(--space-5);align-items:flex-start}
.ledger__field{display:grid;grid-template-columns:repeat(auto-fill,var(--mark-size));
  gap:var(--mark-gap);align-content:start;width:min(100%,27rem)}
.mk{width:var(--mark-size);height:var(--mark-size);display:block}
.mk--pass{background:var(--mark-pass)}
.mk--fail{background:var(--mark-fail)}
.mk--na{background:transparent;border:1px solid var(--mark-na)}
.mk--skip{background:var(--mark-skip)}
/* FCD-067: a minor finding (below high severity) reads amber; a queued (deferred) check reads as a
   hollow dashed square, still waiting on a follow-up pass. A complete self-scan draws neither a
   not-applicable nor a skip tile at all: the graphic is the checks that ran. */
.mk--minor{background:var(--warn)}
.mk--queued{background:transparent;border:1px dashed var(--mark-na)}
/* The one orchestrated motion moment on the page: the field resolves in a single sweep in the
   order the checks ran, which is what a scan completing looks like. Opacity only. */
.ledger__field .mk{opacity:0}
.ledger__body.in .ledger__field .mk{animation:mkin var(--dur) var(--ease) forwards;
  animation-delay:calc(var(--i) * var(--mk-step))}
@keyframes mkin{to{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .ledger__field .mk,.ledger__body.in .ledger__field .mk{opacity:1;animation:none}
}
.ledger__tally{margin:0;font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  min-width:14rem;border-left:1px solid var(--border);padding-left:var(--space-4)}
.ledger__t{display:flex;justify-content:space-between;gap:var(--space-3);padding:var(--space-1) 0}
.ledger__t dt{color:var(--text-muted);font-size:var(--step--1)}
.ledger__t dd{margin:0;color:var(--text);font-weight:700}
.ledger__legend{list-style:none;display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);
  margin:var(--space-5) 0 0;padding:0;font-family:var(--font-mono);font-size:var(--step--1);
  color:var(--text-muted)}
.ledger__legend li{display:flex;align-items:center;gap:var(--space-1)}
.ledger__areas{margin-top:var(--space-5);overflow-x:auto;border:1px solid var(--border);
  border-radius:var(--radius-lg);background:var(--surface)}
.ledger__areas table{border-collapse:collapse;width:100%;min-width:34rem;font-size:var(--step--1)}
.ledger__areas th,.ledger__areas td{text-align:left;padding:var(--space-2) var(--space-3);
  border-bottom:1px solid var(--border);vertical-align:top}
.ledger__areas thead th{font-family:var(--font-mono);font-weight:500;color:var(--text-dim);
  text-transform:uppercase;letter-spacing:.1em;white-space:nowrap}
.ledger__areas tbody th{font-weight:500;color:var(--text);white-space:nowrap}
.ledger__what{color:var(--text-muted);max-width:46ch}
.ledger__res{font-family:var(--font-mono);white-space:nowrap}
.ledger__res--pass{color:var(--good)}
.ledger__res--fail{color:var(--crit)}
.ledger__res--not-applicable{color:var(--text-dim)}
.ledger__withheld,.ledger__note{color:var(--text-muted);font-size:var(--step--1);
  margin-top:var(--space-4);max-width:var(--measure)}
.ledger__note code{font-family:var(--font-mono);color:var(--text);overflow-wrap:anywhere}
/* FCD-067: the applicability pre-check explains the checks the graphic does not draw; the self-run
   line is the adjacent "what we ran on our own site" figure beside the catalogue. */
.ledger__precheck{color:var(--text-muted);font-size:var(--step--1);max-width:var(--measure);
  margin-top:var(--space-5)}
.ledger__ran{color:var(--text);font-size:var(--step--1);max-width:var(--measure);margin-top:var(--space-4)}
/* FCD-068: the "what we found and what we fixed" line. A quiet left rule marks it as the standing-behind
   statement, distinct from the neutral run tally above it, without shouting. */
.ledger__fixed{color:var(--text);font-size:var(--step--1);max-width:var(--measure);margin-top:var(--space-3);
  padding-left:var(--space-3);border-left:2px solid var(--accent)}
.ledger__what details summary{cursor:pointer;color:var(--text-dim);font-family:var(--font-mono);
  font-size:var(--step--2);list-style:none}
.ledger__what details summary::-webkit-details-marker{display:none}
.ledger__what details[open] summary{margin-bottom:var(--space-1)}
.ledger__what details p{margin:0;color:var(--text-muted);max-width:46ch}
.ledger__line{margin-top:var(--space-4);font-family:var(--font-display);font-weight:500;
  font-size:var(--step-1);color:var(--text);max-width:var(--measure)}
@media (max-width:640px){
  .ledger__tally{border-left:0;padding-left:0;border-top:1px solid var(--border);
    padding-top:var(--space-3);width:100%}
}

/* ---- the proving ground (FCD-030) ------------------------------------------------------ */
.pg-section{margin-top:var(--space-5)}
.pg{max-width:var(--measure)}
.pg__scoreboard{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,11rem),1fr));
  gap:var(--space-3);margin:0 0 var(--space-4)}
.pg__stat{border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface);
  padding:var(--space-4);min-width:0}
.pg__stat--miss{border-color:var(--crit);background:linear-gradient(180deg,var(--surface-2),var(--surface))}
.pg__statn{display:block;font-family:var(--font-display);font-weight:700;font-size:var(--step-4);
  line-height:1;color:var(--text)}
.pg__stat--miss .pg__statn{color:var(--crit)}
.pg__statl{display:block;margin-top:var(--space-2);font-size:var(--step--1);color:var(--text-muted)}
.pg__stamp{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);
  margin:0 0 var(--space-5);max-width:var(--measure)}
.pg__stamp code{color:var(--text)}
.pg__h{font-family:var(--font-display);font-weight:600;font-size:var(--step-1);margin:0 0 var(--space-2)}
.pg__misses{border-left:3px solid var(--crit);padding-left:var(--space-4);margin:0 0 var(--space-6)}
.pg__lede{color:var(--text-muted);max-width:var(--measure)}
.pg__misslist{list-style:none;margin:var(--space-3) 0 0;padding:0;display:flex;
  flex-direction:column;gap:var(--space-3)}
.pg__miss{border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface);
  padding:var(--space-3)}
.pg__miss-head{margin:0;font-family:var(--font-mono);font-size:var(--step--1)}
.pg__miss-head b{color:var(--text);font-weight:700}
.pg__miss-head code{color:var(--text-muted);margin-left:var(--space-2);overflow-wrap:anywhere}
.pg__miss-body{margin:var(--space-2) 0 0;color:var(--text-muted);font-size:var(--step--1)}
.pg__method{margin:0 0 var(--space-6)}
.pg__methodlist{margin:var(--space-3) 0 0;padding-left:1.2rem;display:flex;flex-direction:column;
  gap:var(--space-2);color:var(--text-muted);max-width:var(--measure)}
.pg__areas{overflow-x:auto;-webkit-overflow-scrolling:touch;min-width:0;max-width:100%;
  border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface)}
.pg__areas table{border-collapse:collapse;width:100%;min-width:40rem;font-size:var(--step--1)}
.pg__areas th,.pg__areas td{text-align:left;padding:var(--space-2) var(--space-3);
  border-bottom:1px solid var(--border);vertical-align:top}
.pg__areas thead th{font-family:var(--font-mono);font-weight:500;color:var(--text-dim);
  text-transform:uppercase;letter-spacing:.1em;white-space:nowrap}
.pg__areas tbody th{font-weight:500;color:var(--text);white-space:nowrap}
.pg__areas code{font-family:var(--font-mono);color:var(--text-muted);overflow-wrap:anywhere}
.pg__sev{font-family:var(--font-mono);white-space:nowrap}
.pg__sev--critical,.pg__sev--high{color:var(--crit)}
.pg__sev--medium{color:var(--warn)}
.pg__sev--low,.pg__sev--info{color:var(--text-dim)}
.pg__res{font-family:var(--font-mono);white-space:nowrap;font-weight:700}
.pg__res--found{color:var(--good)}
.pg__res--missed{color:var(--crit)}
.pg-foot{color:var(--text-muted);font-size:var(--step--1);margin-top:var(--space-6);
  max-width:var(--measure)}
.pg-foot code{font-family:var(--font-mono);color:var(--text);overflow-wrap:anywhere}

/* ---- proof states, the reach ladder, the verdict rule ---------------------------------- */
.proof-states{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-4);margin:0}
.pstate{border-top:1px solid var(--border-strong);padding-top:var(--space-3)}
.pstate__term{font-family:var(--font-mono);font-weight:700;color:var(--text)}
.pstate:last-child .pstate__term{color:var(--accent)}
.pstate__def{margin:var(--space-1) 0 0;color:var(--text-muted);font-size:var(--step--1);
  line-height:1.5}
.reach{margin-top:var(--space-6)}
.reach__h{font-family:var(--font-display);font-weight:600;font-size:var(--step-1);
  margin:0 0 var(--space-3)}
/* FCD-055: the reach ladder as an escalation infographic. Each rung's bar LENGTHENS and HEATS UP
   from recon (short, cool) to root (full width, ember), so the deeper the reach the longer and
   hotter the mark. The bars grow in on scroll. */
.ladder{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-2);
  max-width:var(--measure)}
.rung{display:grid;grid-template-columns:5.5rem 1fr;align-items:center;gap:var(--space-3)}
.rung__word{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);
  text-transform:uppercase;letter-spacing:.06em;text-align:right}
/* width scales with the rung; the gradient is sized so a longer bar reaches further into the ember */
.rung__bar{display:block;height:16px;border-radius:0 3px 3px 0;
  width:calc(var(--w) / 5 * 100%);
  background:linear-gradient(90deg,var(--plasma-cool),var(--ember-hi) 70%,var(--accent));
  background-size:calc(500% / var(--w)) 100%;background-repeat:no-repeat;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06);
  transform:scaleX(0);transform-origin:left}
.reach.in .rung__bar{transform:scaleX(1);transition:transform var(--dur-slow) var(--ease);
  transition-delay:calc((var(--w) - 1) * 90ms)}
@media (prefers-reduced-motion:reduce){.rung__bar{transform:none}.reach.in .rung__bar{transition:none}}
.reach__cap{margin-top:var(--space-3);color:var(--text-muted);font-size:var(--step--1);
  max-width:var(--measure)}
.vrule{margin-top:var(--space-6);max-width:var(--measure)}
.vrule p{color:var(--text-muted)}
.vrule__list{margin:var(--space-3) 0 0;padding-left:var(--space-4);color:var(--text-muted);
  display:flex;flex-direction:column;gap:var(--space-1)}
@media (max-width:760px){
  .proof-states{grid-template-columns:1fr}
  .rung{grid-template-columns:4.5rem 1fr}
  .rung__word{text-align:left}
}

/* ---- what you get ---------------------------------------------------------------------- */
.getgrid{display:grid;grid-template-columns:5fr 7fr;gap:clamp(1.4rem,4vw,3.5rem);align-items:start}
.getlist{list-style:none;margin:var(--space-4) 0 0;padding:0;display:flex;flex-direction:column;
  gap:var(--space-3);max-width:var(--measure)}
.getlist li{color:var(--text-muted);border-top:1px solid var(--border);padding-top:var(--space-3)}
.getlist b{color:var(--text);font-weight:700}
.samplecard{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-4);
  background:linear-gradient(180deg,var(--surface),var(--bg-2));border:1px solid var(--border-strong);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-2);
  transition:border-color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.samplecard:hover{border-color:var(--ember-line);transform:translateY(-1px)}
.samplecard:active{transform:translateY(0)}
.samplecard__eyebrow{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.18em;
  text-transform:uppercase;color:var(--accent)}
.samplecard__title{font-family:var(--font-display);font-weight:600;font-size:var(--step-2)}
.samplecard__body{color:var(--text-muted);font-size:var(--step--1)}
.samplecard__go{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text);
  border-top:1px solid var(--border);padding-top:var(--space-2);margin-top:var(--space-1)}
.getdemo{margin-top:var(--space-3)}
@media (prefers-reduced-motion:reduce){.samplecard{transition:none}}
@media (max-width:860px){.getgrid{grid-template-columns:1fr}}

/* ---- the badge ------------------------------------------------------------------------- */
.badge-show{display:flex;flex-wrap:wrap;gap:var(--space-5);justify-content:center;
  padding:var(--space-5);background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius-lg)}
.badge-show__one{margin:0;display:flex;flex-direction:column;gap:var(--space-2);align-items:center}
.badge-show__one svg{max-width:100%;height:auto}
.badge-show figcaption{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);
  text-align:center;max-width:26ch}
.badge-text{display:grid;grid-template-columns:1fr 1fr;gap:clamp(1.4rem,4vw,3.5rem);
  margin-top:var(--space-5);align-items:start}
.badge-text p{color:var(--text-muted);max-width:var(--measure)}
.badge-text p + p{margin-top:var(--space-3)}
@media (max-width:860px){.badge-text{grid-template-columns:1fr}}

/* ---- is this safe / the limits --------------------------------------------------------- */
.numstack{list-style:none;margin:0;padding:0;counter-reset:safe}
.numstack li{counter-increment:safe;border-top:1px solid var(--border);padding:var(--space-4) 0;
  display:grid;grid-template-columns:auto 1fr;gap:var(--space-1) var(--space-4)}
.numstack li::before{content:counter(safe,decimal-leading-zero);font-family:var(--font-mono);
  font-size:var(--step--1);color:var(--accent);grid-row:span 2}
.numstack h3{font-family:var(--font-display);font-weight:600;font-size:var(--step-1)}
.numstack p{grid-column:2;color:var(--text-muted);max-width:var(--measure)}
.klist--two{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3) var(--space-5);
  list-style:none;margin:0;padding:0}
.klist--two li{color:var(--text-muted);border-top:1px solid var(--border);padding-top:var(--space-3)}
@media (max-width:760px){.klist--two{grid-template-columns:1fr}}

/* ---- price ----------------------------------------------------------------------------- */
/* Two columns, and the free one carries the emphasis: after FCD-017 the free offer is the
   argument, so it takes the ember border and the paid column sits quiet on --surface. */
.pricing{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)}
.tier{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-3);align-items:start}
.tier--free{background:linear-gradient(180deg,var(--surface-2),var(--surface));
  border-color:var(--ember-line)}
.tier h3{font-family:var(--font-display);font-weight:600;font-size:var(--step-1)}
.tier__price{font-family:var(--font-mono);font-weight:700;font-size:var(--step-3);color:var(--text);
  font-variant-numeric:tabular-nums;line-height:1}
.tier__desc{color:var(--text-muted);font-size:var(--step-0);max-width:var(--measure)}
.vat{margin-top:var(--space-4);font-family:var(--font-mono);font-size:var(--step--1);
  color:var(--text-muted)}
.ce{margin-top:var(--space-5);padding-top:var(--space-4);border-top:1px solid var(--border);
  max-width:var(--measure)}
.ce h3{font-family:var(--font-display);font-weight:600;font-size:var(--step-1);
  margin-bottom:var(--space-2)}
.ce p{color:var(--text-muted)}
@media (max-width:520px){.pricing{grid-template-columns:1fr}}

/* ---- questions ------------------------------------------------------------------------- */
.questions{border-top:1px solid var(--border);max-width:var(--measure-doc)}
.questions details{border-bottom:1px solid var(--border)}
.questions summary{list-style:none;cursor:pointer;display:flex;align-items:center;
  justify-content:space-between;gap:var(--space-3);min-height:var(--target);
  padding:var(--space-3) 0;font-weight:700;font-size:var(--step-0)}
.questions summary::-webkit-details-marker{display:none}
/* The control is the affordance: a CSS-drawn plus that becomes a minus. No glyph, no chevron. */
.questions summary::after{content:"";position:relative;flex:none;width:var(--space-2);
  height:var(--space-2);
  background:linear-gradient(var(--text-muted),var(--text-muted)) center/100% 1px no-repeat,
             linear-gradient(var(--text-muted),var(--text-muted)) center/1px 100% no-repeat;
  transition:transform var(--dur) var(--ease)}
.questions details[open] summary::after{transform:rotate(90deg);
  background:linear-gradient(var(--accent),var(--accent)) center/100% 1px no-repeat}
.questions summary:hover{color:var(--accent)}
.questions summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.qa{padding:0 0 var(--space-4)}
.qa p{color:var(--text-muted);max-width:var(--measure)}
@media (prefers-reduced-motion:reduce){.questions summary::after{transition:none}}

.cta-contact{margin-top:var(--space-3);color:var(--text-muted);font-size:var(--step--1)}
.cta-contact a{border-bottom:1px solid var(--ember-line)}
.cta-contact a:hover{color:var(--accent)}
.foot__legal span{display:block}
.lede--who{margin-top:var(--space-3);font-size:var(--step-0)}

/* ---- the document template (safe, privacy, terms, acceptable use, security, about) ------ */
.doc{max-width:var(--measure-doc);padding-top:var(--space-6);padding-bottom:var(--space-7)}
.doc h1{font-size:var(--step-3);margin-bottom:var(--space-3)}
.doc__date{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);
  margin-bottom:var(--space-5)}
.doc h2{font-family:var(--font-display);font-weight:600;font-size:var(--step-1);
  margin:var(--space-6) 0 var(--space-3)}
.doc h3{font-family:var(--font-display);font-weight:600;font-size:var(--step-0);
  margin:var(--space-4) 0 var(--space-2)}
.doc p,.doc li{color:var(--text-muted)}
.doc p{margin-bottom:var(--space-3)}
.doc ul,.doc ol{margin:0 0 var(--space-4);padding-left:var(--space-4);display:flex;
  flex-direction:column;gap:var(--space-2)}
.doc a{border-bottom:1px solid var(--border-strong)}
.doc a:hover{color:var(--accent);border-color:var(--ember-line)}
.doc code{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text);
  overflow-wrap:anywhere}
.doc .lede{margin-bottom:var(--space-5);max-width:none}
.doc__wide{overflow-x:auto;margin-bottom:var(--space-4)}
.doc__wide table{border-collapse:collapse;width:100%;min-width:34rem;font-size:var(--step--1)}
.doc__wide th,.doc__wide td{text-align:left;padding:var(--space-2) var(--space-3);
  border-bottom:1px solid var(--border);vertical-align:top}
.doc__wide thead th{font-family:var(--font-mono);font-weight:500;color:var(--text-dim);
  text-transform:uppercase;letter-spacing:.1em}
.idblock{display:grid;grid-template-columns:auto 1fr;gap:var(--space-2) var(--space-4);
  margin:0 0 var(--space-4);font-size:var(--step--1)}
.idblock dt{font-family:var(--font-mono);color:var(--text-dim)}
.idblock dd{margin:0;color:var(--text)}

/* ---- FCD-049: the Year Rule --------------------------------------------------------------------
   One twelve-month scale drawn eight times at identical width. The comparison is geometric rather
   than rhetorical: we draw the year, put the assessment schedules on it, put the publication rate
   on it at the same scale, and let the reader conclude it.

   NOTHING HERE ATTACKS A CERTIFICATE. The assurance marks are the brightest element in the frame at
   full bone; the publication band is quiet at 34%. There is no red, no cross and no failure colour
   anywhere near a scheme. The only accent in the whole hero is the ~0.5% that CISA lists as known
   to be exploited, which is the number that makes us honest rather than the one that scares.

   THE OVERFLOW CLAUSE. This component is 24 absolutely positioned elements wide and this project
   has shipped four horizontal-overflow faults. Three defences, all three required:
     1. every track is position:relative and overflow:hidden, so nothing can leak out of one even
        if a percentage is wrong;
     2. NO ELEMENT USES left:100%. The only thing at the far end is the SOC 2 window's closing cap,
        drawn with right:0;
     3. no min-width in pixels anywhere except the 2px mark floor. */
.yr{margin:var(--space-5) 0 0;padding:0;max-width:100%}
.yr__head{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);align-items:baseline;
  justify-content:space-between;margin-bottom:var(--space-4)}
.yr__title{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);margin:0}
.yr__stamp{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);margin:0}
.yr__grp{margin-bottom:var(--space-4)}
.yr__group{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-dim);margin:0 0 var(--space-2)}
/* label | track | figure. The label and figure columns are rem, never min-width, so the track
   takes what is left and the row cannot push the page. */
.yr__row{display:grid;grid-template-columns:13rem 1fr 6rem;gap:var(--space-3);
  align-items:center;padding:var(--yr-row-gap) 0;border-top:1px solid var(--border)}
.yr__lab{min-width:0}
.yr__name{display:block;font-size:var(--step-0);color:var(--text);font-weight:500;line-height:1.2}
.yr__sub{display:block;font-size:var(--step--1);color:var(--text-dim);line-height:1.35;
  margin-top:.15rem;overflow-wrap:anywhere}
.yr__track{position:relative;overflow:hidden;height:var(--yr-track-h);
  background:var(--surface);border-radius:1px;min-width:0}
.yr__fig{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);
  text-align:right;overflow-wrap:anywhere}
.yr__n{color:var(--text);font-weight:500}

/* a point event: one assessment, on a date we do not know and will not invent */
.yr__mk{position:absolute;top:0;bottom:0;width:var(--yr-mark-w);background:var(--text)}
/* a window with end caps. `right:0` rather than `left:100%`, per defence 2 above. */
.yr__span{position:absolute;top:0;bottom:0;left:0;right:0;
  border-left:var(--yr-mark-w) solid var(--text);border-right:var(--yr-mark-w) solid var(--text);
  background:linear-gradient(var(--mark-pass),var(--mark-pass)) center/100% 1px no-repeat}
/* Cyber Essentials: one assessment, then the validity it buys, drawn as a hairline with no closing
   cap, because the certificate does not end with a second assessment. */
.yr__span--open{border-right:0}
/* the publication band: quiet, because it is the context and not the accusation */
.yr__fill{position:absolute;top:0;bottom:0;left:0;right:0;background:var(--mark-pass);
  transform:scaleX(0);transform-origin:left;animation:yr-sweep var(--dur-sweep) var(--ease) forwards}
@keyframes yr-sweep{to{transform:scaleX(1)}}
/* the one accent in the hero, drawn to scale, with a rendering floor the caption discloses */
.yr__slice{position:absolute;top:0;bottom:0;left:0;width:.464%;min-width:var(--yr-mark-w);
  background:var(--accent);opacity:0;animation:yr-in var(--dur) var(--ease) var(--dur-sweep) forwards}
.yr__leader{position:absolute;top:50%;left:.464%;width:5rem;height:1px;background:var(--border-strong);
  opacity:0;animation:yr-in var(--dur) var(--ease) var(--dur-sweep) forwards}
.yr__inline{position:absolute;top:50%;left:5.5rem;transform:translateY(-50%);white-space:nowrap;
  font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);
  opacity:0;animation:yr-in var(--dur) var(--ease) var(--dur-sweep) forwards}
@keyframes yr-in{to{opacity:1}}
/* a measured interval, bracketed. The third has no closing arm because the measurement stops. */
.yr__cyc{position:absolute;top:2px;bottom:2px;border:1px solid var(--plasma-cool);border-radius:1px}
.yr__cyc--open{border-right:0}
.yr__axis{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-3);
  font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);
  margin:var(--space-2) 0 0;padding-left:calc(13rem + var(--space-3));text-align:right}
.yr__cap{margin:var(--space-4) 0 0;color:var(--text-muted);max-width:var(--measure)}
.yr__cap p{margin:0 0 var(--space-3)}
.yr__cap p:last-child{margin-bottom:0}
.yr .src{margin-top:var(--space-4)}

/* THE MOTION IS ONE GESTURE AND IT IS OPTIONAL. Group one never animates at any point: animating
   the assurance rows would dramatise the exact thing we have committed not to attack. Under
   reduced motion the band is simply full and the slice is simply there, which is the same argument
   with no movement in it at all. */
@media (prefers-reduced-motion:reduce){
  .yr__fill{transform:scaleX(1);animation:none}
  .yr__slice,.yr__leader,.yr__inline{opacity:1;animation:none}
}

/* The hero, restructured: one column, the rule full width beneath it. */
.hero__lead{max-width:54ch}
.hero__foot{margin-top:var(--space-5)}

@media (max-width:860px){
  .yr__row{grid-template-columns:1fr 5.5rem;gap:var(--space-2) var(--space-3)}
  /* The label spans both columns above the track, so the track keeps its full width rather than
     being squeezed to nothing by a label that cannot shrink. */
  .yr__lab{grid-column:1 / -1}
  .yr__axis{padding-left:0}
  .yr__inline{display:none}          /* the caption says the same thing, in prose */
  .yr__leader{width:3rem}
}
@media (max-width:460px){
  .yr__row{grid-template-columns:1fr auto}
  .yr__sub{font-size:.72rem}
}

/* ---- FCD-053: the cadence gap ------------------------------------------------------------------
   One living infographic in three movements on a shared connective spine. Ember owns the risk side
   (Movements 2 and 3) and all the motion; the assurance side (Movement 1) is bone, still, and never
   animates its marks. Each movement comes alive as it enters the viewport (JS adds .is-in), so the
   whole thing plays as one story on scroll, not all at once. No new colour, face, radius or shadow;
   derived tokens only. */
.cg{margin:var(--space-6) 0 0;max-width:100%}
.cg__head{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);
  align-items:baseline;justify-content:space-between;margin-bottom:var(--space-5)}
.cg__title{font-family:var(--font-display);font-weight:700;font-size:var(--step-2);line-height:1.08;
  color:var(--text);margin:0;text-wrap:balance;max-width:24ch}
.cg__stamp{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);margin:0}
.cg__group{font-family:var(--font-mono);font-size:var(--step--1);letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-dim);margin:0 0 var(--space-3)}
.cg__mv{margin-bottom:var(--space-6)}
.cg__n{color:var(--text);font-weight:500}

/* the connective spine: a single rail down the left of all three movements, bone at the still top
   and ember toward the burning bottom, so the eye reads one composition, not three stacked charts.
   It draws downward once as the figure appears. */
.cg__movements{position:relative;padding-left:var(--space-5)}
.cg__spine{position:absolute;left:.35rem;top:.2rem;bottom:.2rem;width:var(--cg-spine);border-radius:2px;
  background:linear-gradient(var(--mark-pass) 0%,var(--mark-pass) 24%,var(--ember-line) 58%,var(--accent) 100%);
  transform:scaleY(0);transform-origin:top;transition:transform var(--dur-slow) var(--ease)}
.cg.in .cg__spine{transform:scaleY(1)}
@media (max-width:560px){.cg__movements{padding-left:var(--space-4)}.cg__spine{left:.15rem}}

/* --- CG:MV1-START --- The five checks. BONE ONLY, NEVER EMBER; the MARKS never animate. Only the
   rows fade up as the movement enters, which dramatises nothing about the schemes themselves. The
   info-eye is a help control on the assurance side, so it carries the cool analysis colour, not the
   risk ember: the accent lands nowhere in this movement, which app/test/hero-figures.test.js
   enforces on this exact CSS range and on the markup between the CG:MV1 comment markers. */
.cg__mv1{max-width:52rem}
.cg__rows{display:flex;flex-direction:column}
.cg__row{display:grid;grid-template-columns:14rem 1fr 5rem;gap:var(--space-3);
  align-items:center;padding:var(--space-1) 0;border-top:1px solid var(--border);
  opacity:0;transform:translateY(6px)}
.cg__mv1.is-in .cg__row{opacity:1;transform:none;
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease);
  transition-delay:calc(var(--ri,0)*55ms)}
.cg__lab{display:flex;align-items:center;gap:.3rem;min-width:0}
.cg__name{font-size:var(--step-0);color:var(--text);font-weight:500;line-height:1.2;overflow-wrap:anywhere}
/* a proper 12-month cadence rail, not a hairline: taller, top-lit, with faint quarter gridlines so
   the year reads as divided, and bolder cool event marks with a soft glow. Bone and plasma only,
   never ember (this is the assurance side). */
.cg__track{height:18px;border-radius:3px;box-shadow:inset 0 1px 0 rgba(255,255,255,.03);
  background:
    repeating-linear-gradient(90deg,transparent 0,transparent calc(25% - 1px),var(--border-strong) calc(25% - 1px),var(--border-strong) 25%,transparent 25%),
    linear-gradient(var(--surface-2),var(--surface))}
.cg__track .yr__mk{width:3px;border-radius:0 0 2px 2px;background:var(--plasma);
  box-shadow:0 0 5px rgba(203,185,160,.55)}
/* Cyber Essentials: the assessment mark, then a validity trail that fades across the year */
.cg__track .yr__span--open{border:0;background:linear-gradient(90deg,rgba(203,185,160,.24),transparent 66%)}
/* SOC 2: the observation window as a filled cool bar with a bright leading edge */
.cg__track .yr__span{border:0;border-left:3px solid var(--plasma);
  background:linear-gradient(90deg,rgba(203,185,160,.20),rgba(203,185,160,.09))}
.cg__fig{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);text-align:right}
/* ISO 27001: a faint three-year cycle bracket under the single yearly tick. Bone hairline. */
.cg__cyc3{position:absolute;left:0;right:0;bottom:0;height:4px;
  border:1px solid var(--border-strong);border-top:0;border-radius:0 0 1px 1px}
/* SOC 2: the bridge-letter tail past the window end, drawn muted and hatched, never ember. */
.cg__tail{position:absolute;top:0;bottom:0;right:0;width:9%;
  background:repeating-linear-gradient(90deg,var(--mark-na),var(--mark-na) 2px,transparent 2px,transparent 4px)}
.cg__axis{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-3);
  font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-dim);
  margin:var(--space-2) 0 0;padding-left:calc(14rem + var(--space-3));text-align:right}
/* the info-eye: a crafted glyph, cool not ember, a real 44px button target */
.cg__eye{flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:var(--target);height:var(--target);margin:calc((1.2em - var(--target))/2) 0;
  padding:0;background:none;border:0;color:var(--text-dim);cursor:pointer;border-radius:var(--radius)}
.cg__eyeglyph{width:var(--cg-eye);height:auto}
.cg__eyelid,.cg__pupil{fill:none;stroke:currentColor;stroke-width:1.5}
.cg__eye:hover,.cg__eye:focus-visible{color:var(--plasma)}
.cg__eye:focus-visible{outline:none;box-shadow:0 0 0 2px rgba(203,185,160,.5)}
.cg__eye[aria-expanded="true"]{color:var(--plasma-cool)}
.cg__eye[aria-expanded="true"] .cg__pupil{fill:var(--plasma-cool)}
.cg__eye-note{grid-column:1 / -1;margin:.15rem 0 .5rem;color:var(--text-muted);
  font-size:var(--step--1);line-height:1.5;max-width:56ch}
.cg__eye-note[hidden]{display:none}
.cg__eye-note:not([hidden]){animation:cg-note-in var(--dur) var(--ease)}
@keyframes cg-note-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
/* --- CG:MV1-END --- */

/* a horizontal scroller so a wide chart pans on a phone instead of shrinking its labels to nothing */
.cg__scroll{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}

/* Movement 2: the volume bar and the 1,665 pictogram. Ember lives here. */
.cg__mv2grid{display:grid;grid-template-columns:minmax(0,320px) 1fr;gap:var(--space-6);align-items:center}
/* let the columns shrink below their content's intrinsic width so a wide child (the volume SVG's
   19rem min) pans inside .cg__scroll instead of forcing the whole track past the phone viewport */
.cg__mv2grid>*{min-width:0}
.cg__volsvg{width:100%;min-width:19rem;max-width:320px;height:auto;overflow:visible;font-family:var(--font-mono)}
.cg__axisline{stroke:var(--border-strong);stroke-width:1}
.cg__grid{stroke:var(--border);stroke-width:1}
.cg__gridn{fill:var(--text-dim);font-size:var(--cg-lab)}
.cg__barchan{fill:var(--surface-2);stroke:var(--border);stroke-width:1}
/* the fill burns up from the baseline; the counter beside it rolls in step (JS) */
.cg__barfill{fill:url(#fcdHeat);transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;
  transition:transform 1000ms var(--ease) 120ms}
.cg__mv2.is-in .cg__barfill{transform:scaleY(1)}
/* a hot crest line that lands with the fill and then shimmers, so the top edge reads as live heat */
.cg__crest{fill:var(--ember-hi);opacity:0;filter:url(#cgGlow)}
.cg__mv2.is-in .cg__crest{animation:cg-crest 900ms var(--ease) 900ms forwards,cg-shimmer 2.4s var(--ease) 1800ms infinite}
@keyframes cg-crest{from{opacity:0}to{opacity:.9}}
@keyframes cg-shimmer{0%,100%{opacity:.55}50%{opacity:1}}
/* the projection grows upward out of the crest, dashed, visibly a forecast */
.cg__barproj{fill:none;stroke:var(--accent);stroke-width:1.5;stroke-dasharray:5 4;
  transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;
  opacity:0;transition:transform var(--dur-slow) var(--ease) 1000ms,opacity var(--dur) var(--ease) 1000ms}
.cg__mv2.is-in .cg__barproj{transform:scaleY(1);opacity:.72}
/* the reference line at all of 2025 sweeps across first, so the reader watches the fill overtop it */
.cg__refline{stroke:var(--border-strong);stroke-width:1.5;stroke-dasharray:4 3;
  transform:scaleX(0);transform-box:fill-box;transform-origin:left;transition:transform var(--dur) var(--ease) 300ms}
.cg__mv2.is-in .cg__refline{transform:scaleX(1)}
.cg__reflab,.cg__projlab,.cg__voleyebrow{fill:var(--text-muted);font-size:var(--cg-lab)}
.cg__reflab--n{fill:var(--text)}
.cg__projn,.cg__projlab{fill:var(--ember-hi)}
.cg__projn{font-size:var(--cg-lab-lg);font-weight:700}
.cg__voleyebrow{letter-spacing:.06em}
.cg__volnum{fill:var(--text);font-family:var(--font-display);font-weight:700;font-size:var(--cg-num)}
.cg__refline,.cg__reflab,.cg__reflab--n,.cg__projn,.cg__projlab,.cg__voleyebrow,.cg__volnum{
  opacity:0;transition:opacity var(--dur) var(--ease) 700ms}
.cg__mv2.is-in .cg__refline,.cg__mv2.is-in .cg__reflab,.cg__mv2.is-in .cg__reflab--n,
.cg__mv2.is-in .cg__projn,.cg__mv2.is-in .cg__projlab,.cg__mv2.is-in .cg__voleyebrow,.cg__mv2.is-in .cg__volnum{opacity:1}
/* the 1,665: a field of ember lines that all rise on scroll-in, with the number counting up beside
   it. Simple and quantity-honest, no unit to decode. */
.cg__kevbars{display:flex;align-items:flex-end;gap:2px;height:72px;max-width:34rem;margin:0 0 var(--space-4)}
.cg__kevbar{flex:1;height:var(--h);border-radius:1px 1px 0 0;
  background:linear-gradient(var(--ember-hi),var(--accent) 55%,var(--ember-deep));
  opacity:0;transform:scaleY(0);transform-origin:bottom}
.cg__mv2.is-in .cg__kevbar{animation:cg-bar-up 460ms var(--ease) forwards;
  animation-delay:calc(var(--gi)*13ms + 300ms)}
@keyframes cg-bar-up{to{opacity:1;transform:scaleY(1)}}
.cg__kevlab{display:flex;align-items:baseline;gap:.5rem .7rem;flex-wrap:wrap}
.cg__kevn{font-family:var(--font-display);font-weight:700;font-size:var(--step-4);color:var(--text);line-height:1}
.cg__kevlab span{color:var(--text-muted);font-size:var(--step-0);max-width:26ch;line-height:1.4}

/* Movement 3: the model-cadence climb, a bold rising AREA chart. Only 2024 = 58 is sourced (the one
   glowing solid anchor); the lead-in is a faint dotted cool line, the projection is a bold dashed
   ember line over a hatched area, and a bright comet climbs the whole path to the pulsing endpoint.
   Sized to fit a phone without horizontal scroll. */
.cg__crvsvg{width:100%;max-width:560px;height:auto;overflow:visible;font-family:var(--font-mono)}
.cg-a0{stop-color:var(--accent);stop-opacity:.42}
.cg-a1{stop-color:var(--accent);stop-opacity:0}
.cg-hx{stroke:var(--accent);stroke-width:1;opacity:.4}
/* the filled area grows up out of the baseline as the movement enters */
.cg__crvarea{fill:url(#cgArea);transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;
  transition:transform var(--dur-slow) var(--ease) 300ms}
.cg__mv3.is-in .cg__crvarea{transform:scaleY(1)}
.cg__crvhatch{fill:url(#cgHatch);transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;
  opacity:0;transition:transform var(--dur-slow) var(--ease) 900ms,opacity var(--dur) var(--ease) 900ms}
.cg__mv3.is-in .cg__crvhatch{transform:scaleY(1);opacity:1}
.cg__crvlead{fill:none;stroke:var(--plasma-cool);stroke-width:1.5;stroke-dasharray:1 4;stroke-linecap:round;
  opacity:0;transition:opacity var(--dur) var(--ease) 300ms}
.cg__mv3.is-in .cg__crvlead{opacity:.7}
.cg__crvproj{fill:none;stroke:var(--accent);stroke-width:2.5;stroke-dasharray:8 5;stroke-linecap:round;
  opacity:0;transition:opacity var(--dur) var(--ease) 1000ms}
.cg__mv3.is-in .cg__crvproj{opacity:1}
.cg__crvopen{fill:var(--bg);stroke:var(--plasma-cool);stroke-width:1.5;
  opacity:0;transition:opacity var(--dur) var(--ease) 500ms}
.cg__mv3.is-in .cg__crvopen{opacity:.85}
.cg__crvanchor{fill:var(--ember-hi);filter:url(#cgGlow);opacity:0;transform:scale(.3);transform-box:fill-box;transform-origin:center}
.cg__mv3.is-in .cg__crvanchor{animation:cg-pop 420ms var(--ease) 800ms forwards}
@keyframes cg-pop{0%{opacity:0;transform:scale(.3)}60%{opacity:1;transform:scale(1.35)}100%{opacity:1;transform:scale(1)}}
.cg__crvend{fill:var(--accent);filter:url(#cgGlow);opacity:0;transform:scale(.3);transform-box:fill-box;transform-origin:center}
.cg__mv3.is-in .cg__crvend{animation:cg-pop 420ms var(--ease) 1700ms forwards,cg-endpulse 1.8s var(--ease) 2200ms infinite}
@keyframes cg-endpulse{0%,100%{filter:url(#cgGlow)}50%{filter:url(#cgGlow) drop-shadow(0 0 7px rgba(244,101,43,.7))}}
.cg__comet{fill:#fff;filter:url(#cgGlow);opacity:0;offset-rotate:0deg}
.cg__crvyear{fill:var(--text-muted);font-size:var(--cg-lab-lg)}
.cg__crvlab{fill:var(--text-muted);font-size:var(--cg-lab)}
.cg__crvlab--proj{fill:var(--ember-hi)}
.cg__crvnum{fill:var(--text);font-family:var(--font-display);font-weight:700;font-size:var(--cg-num)}
.cg__crvend-n{fill:var(--ember-hi);font-family:var(--font-display);font-weight:700;font-size:var(--cg-num-sm)}
.cg__crvlab,.cg__crvlab--proj,.cg__crvnum,.cg__crvend-n,.cg__crvyear{opacity:0;transition:opacity var(--dur) var(--ease) 800ms}
.cg__mv3.is-in .cg__crvlab,.cg__mv3.is-in .cg__crvlab--proj,.cg__mv3.is-in .cg__crvnum,
.cg__mv3.is-in .cg__crvend-n,.cg__mv3.is-in .cg__crvyear{opacity:1}
@supports (offset-path:path("M0 0")){
  .cg__mv3.is-in .cg__comet{animation:cg-comet 1900ms var(--ease) 500ms forwards}
  @keyframes cg-comet{0%{opacity:0;offset-distance:0%}10%{opacity:1}90%{opacity:1}100%{opacity:0;offset-distance:100%}}
}

.cg__notes{margin:var(--space-5) 0 0;color:var(--text-muted);max-width:var(--measure)}
.cg__notes p{margin:0 0 var(--space-3)}
.cg__notes p:last-child{margin-bottom:0}
.cg .src{margin-top:var(--space-4)}

@media (max-width:720px){
  .cg__mv2grid{grid-template-columns:1fr;gap:var(--space-5)}
}
@media (max-width:560px){
  .cg__row{grid-template-columns:1fr 4.5rem;gap:var(--space-1) var(--space-3)}
  .cg__lab{grid-column:1 / -1}
  .cg__track{grid-column:1}
  .cg__fig{grid-column:2}
  .cg__axis{padding-left:0}
}

/* THE MOTION IS OPTIONAL. Under reduced motion every movement is simply in its final state: bar
   full, projection present, pictogram filled, curve drawn, comet gone, counters static. Same
   information, no movement. */
@media (prefers-reduced-motion:reduce){
  .cg__spine,.cg__barfill,.cg__barproj,.cg__crvarea,.cg__crvhatch{transform:none;transition:none;animation:none}
  .cg__refline{transform:none;transition:none}
  .cg__row,.cg__crest,.cg__barproj,.cg__refline,.cg__reflab,.cg__reflab--n,.cg__projn,.cg__projlab,
  .cg__voleyebrow,.cg__volnum,.cg__crvarea,.cg__crvhatch,.cg__crvlead,.cg__crvproj,.cg__crvopen,
  .cg__crvanchor,.cg__crvend,.cg__crvend-n,.cg__crvlab,.cg__crvlab--proj,.cg__crvnum,.cg__crvyear{opacity:1;transform:none;transition:none;animation:none}
  .cg__crest{opacity:.9}
  .cg__kevbar{opacity:1;transform:none;animation:none}
  .cg__comet{opacity:0;animation:none}
  .cg__eye-note:not([hidden]){animation:none}
}

/* ---- FCD-053: the escape schematic (replaces the fake incident.log) ----------------------------
   The attacker's ember thread crosses the wall and reaches the database; a bright comet runs its
   length and each node ignites as it passes. The defender's cool thread runs into a guardrail on
   its own side and reroutes DOWN FROM the wall. This is the PROOF section, so the single --crit ring
   on the production-database node is allowed here (it is not the hero). Animates on scroll-in. */
.escape{margin:var(--space-5) 0 0;padding:var(--space-4);overflow-x:auto;
  background:linear-gradient(158deg,var(--surface),var(--bg-2));
  border:1px solid var(--border);border-radius:var(--radius-lg)}
/* The schematic keeps a legible floor (33rem) and PANS inside its own overflow-x:auto scroller, so
   it never overruns the page the way a field min-width would; the .asym faces below carry the same
   content in text for a phone that would rather read than pan. The floor is in rem, not px, because
   the px-min-width ban exists to stop a padded FIELD overrunning the 320px page, which a scroll-
   contained diagram does not do. */
.escape__svg{width:100%;min-width:0;max-width:480px;height:auto;display:block;margin:0 auto;font-family:var(--font-mono)}
.escape__box{fill:var(--surface-2);stroke:var(--border-strong);stroke-width:1;
  opacity:0;transition:opacity var(--dur) var(--ease)}
.escape.is-in .escape__box{opacity:1}
.escape__boxlab{fill:var(--text-muted);font-size:var(--cg-lab-lg)}
.escape__thread{fill:none;stroke-width:2.5;stroke-linecap:round;
  stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset var(--dur-sweep) var(--ease)}
.escape.is-in .escape__thread{stroke-dashoffset:0}
.escape__thread--atk{stroke:var(--accent);filter:url(#cgGlow)}
.escape__thread--def{stroke:var(--plasma-cool);stroke-width:2}
/* the reroute leg draws only after the defender thread has hit the wall */
.escape__reroute{transition-delay:calc(var(--dur-sweep)*.9)}
.escape__comet{fill:#fff;filter:url(#cgGlow);opacity:0;offset-rotate:0deg}
.escape__pierce line{stroke:var(--accent);stroke-width:2;opacity:0;transition:opacity var(--dur) var(--ease) 380ms}
.escape.is-in .escape__pierce line{opacity:1}
.escape__piercelab,.escape__deflab,.escape__startlab{fill:var(--text-muted);font-size:var(--cg-lab)}
.escape__node{opacity:0}
.escape.is-in .escape__node{animation:cg-pop 360ms var(--ease) forwards;animation-delay:calc(var(--ni)*150ms + 300ms)}
.escape__node circle{fill:var(--surface-2);stroke:var(--accent);stroke-width:1.5}
.escape__node text{fill:var(--text);font-size:var(--cg-lab)}
.escape__node--def circle{stroke:var(--plasma-cool)}
.escape__node--def{transition-delay:0ms}
.escape__node--crit circle{stroke:var(--crit);filter:drop-shadow(0 0 6px rgba(229,72,77,.5))}
.escape__barrier{stroke:var(--border-strong);stroke-width:4;stroke-linecap:round;
  opacity:0;transition:opacity var(--dur) var(--ease) calc(var(--dur-sweep)*.7)}
.escape.is-in .escape__barrier{opacity:1;animation:cg-recoil 500ms var(--ease) calc(var(--dur-sweep)*.9)}
@keyframes cg-recoil{0%{stroke:var(--border-strong)}40%{stroke:var(--plasma)}100%{stroke:var(--border-strong)}}
.escape__cap{font-family:var(--font-mono);font-size:var(--step--1);color:var(--text-muted);
  margin:var(--space-3) 0 0;max-width:var(--measure);line-height:1.5}
@supports (offset-path:path("M0 0")){
  .escape.is-in .escape__comet{animation:cg-comet var(--dur-sweep) var(--ease) forwards}
}
@media (prefers-reduced-motion:reduce){
  .escape__thread{stroke-dashoffset:0;transition:none}
  .escape__box,.escape__pierce line,.escape__barrier{opacity:1;transition:none;animation:none}
  .escape__node{opacity:1;transform:none;animation:none}
  .escape__comet{opacity:0;animation:none}
}

/* ---- print ---------------------------------------------------------------------------------
 *
 * FCD-050. The site had no print styles at all, and the failure was specific: every element that
 * arrives by animation starts at `opacity:0` and is revealed by a class JavaScript adds on scroll.
 * A printed page has no scroll, so the browser printed the hero, the ledger and the Year Rule as
 * blank space with captions underneath — and the ledger is the one thing on this site somebody
 * would actually want on paper, because it is the evidence.
 *
 * So the first rule below is the whole point: everything that fades in is visible on paper. */
@media print {
  /* Nothing arrives. Every reveal, sweep and mark is simply there. The cadence-gap movements and
     the escape schematic all start hidden on screen and are revealed by a class JavaScript adds on
     scroll, so on paper each one is forced back to its final state or the figure prints blank. */
  .reveal, .cg__barfill, .cg__kevbar, .escape__node, .rung__bar,
  .cg *, .escape *,
  .ledger__field .mk, .ledger__body.in .ledger__field .mk {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
  /* The stroke-drawn marks (the model curve lead-in and projection, and the escape threads) are
     hidden by a dash offset, not by opacity, so they need the offset zeroed rather than opacity. */
  .cg__crvlead, .cg__crvproj, .escape__thread { stroke-dashoffset: 0 !important; }
  /* The comets are the one thing that should NOT print: a travelling dot is meaningless on paper. */
  .cg__comet, .escape__comet { opacity: 0 !important; }

  /* The one element that cannot survive the transfer: a fixed rail sits over the text on every
     printed page, because `position:fixed` in print means "on each sheet". */
  .rail, .cursor { display: none !important; }

  /* Ink. A dark ground costs a cartridge and reads worse on paper than the thing it replaced, and
     nobody has ever wanted a black page out of a printer. */
  :root {
    --bg: #fff; --surface: #fff; --surface-2: #fff; --surface-3: #f4f4f4;
    --text: #111; --text-muted: #444; --border: #ccc; --border-strong: #999;
  }
  body { background: #fff !important; color: #111 !important; }

  /* The marks keep their meaning without their colour, because a check log photocopied in black
     and white still has to be readable: a pass is filled, a fail is filled and outlined, a
     not-applicable is an empty box, a skip is hatched by its border. */
  .mk--pass { background: #111 !important; }
  .mk--fail { background: #111 !important; outline: 2px solid #111; outline-offset: 1px; }
  .mk--minor { background: #777 !important; }
  .mk--na { background: transparent !important; border: 1px solid #111 !important; }
  .mk--skip { background: #fff !important; border: 1px dashed #111 !important; }
  .mk--queued { background: #fff !important; border: 1px dashed #111 !important; }

  /* A URL a reader cannot follow is worth printing beside its link, and one they can already read
     is not — an anchor to the same page prints as noise. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .78em; word-break: break-all; }
  a[href^="#"]::after, .btn::after, nav a::after { content: ""; }

  /* Keep a heading with what it introduces, and never break a check row across two sheets. */
  h1, h2, h3 { break-after: avoid-page; }
  .ledger__t, .yr__row, figure, table { break-inside: avoid; }
  .ledger__field { break-inside: auto; }

  @page { margin: 18mm 14mm; }
}
