/* ===========================================================================
   reidmorrison.com

   ONE stylesheet for the whole site. The design system is the one built for
   the EOL exposure check at /eol/: Spectral for display, IBM Plex Sans for
   body, IBM Plex Mono for labels and data, a muted navy accent, and semantic
   critical / warning / ok colours kept separate from that accent.

   This replaced the stylesheet copied from semantic_logger/docs. The doc sites
   keep their own look; they serve engineers reading API documentation, and
   this site now serves someone deciding whether to trust a vendor with
   production access. See CLAUDE.md.

   Theme rules, in order, so all three viewer states resolve:
     :root                                    complete light palette
     @media (prefers-color-scheme:dark)       dark, unless light was chosen
     :root[data-theme="dark"]                 explicit dark wins either way
   Never declare a colour only inside a media block.

   color-scheme rides along with each palette. Tokens only reach what this
   stylesheet paints; the select popup, scrollbars, autofill and the caret are
   drawn by the browser and follow color-scheme instead. Print forces light.
   =========================================================================== */

:root{
  color-scheme:light;
  --ground:#F2F4F7; --surface:#FFFFFF; --surface-2:#E9EDF2;
  --ink:#131A22; --ink-2:#3D4854; --ink-3:#6B7684;
  --rule:#D3DAE3; --rule-2:#BFC8D4;
  --accent:#1B4B7A; --accent-ink:#FFFFFF; --accent-soft:#DCE7F2;
  --crit:#9E2A20; --crit-soft:#F7E2E0;
  --warn:#8A5300; --warn-soft:#FAECD8;
  --ok:#1A5C43;  --ok-soft:#DCEDE5;
  --shadow:0 1px 2px rgba(19,26,34,.06),0 8px 24px -12px rgba(19,26,34,.18);
  --bar:rgba(242,244,247,.88);
}

@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --ground:#0E1319; --surface:#161D26; --surface-2:#1E2731;
    --ink:#E6EBF2; --ink-2:#B4BECB; --ink-3:#818D9C;
    --rule:#28323E; --rule-2:#3A4654;
    --accent:#7FB2E0; --accent-ink:#0E1319; --accent-soft:#1B2B3B;
    --crit:#F0918A; --crit-soft:#33191A;
    --warn:#E5B369; --warn-soft:#2E2415;
    --ok:#7BC7A5;  --ok-soft:#12291F;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px -12px rgba(0,0,0,.6);
    --bar:rgba(14,19,25,.88);
  }
}

:root[data-theme="dark"]{
  color-scheme:dark;
  --ground:#0E1319; --surface:#161D26; --surface-2:#1E2731;
  --ink:#E6EBF2; --ink-2:#B4BECB; --ink-3:#818D9C;
  --rule:#28323E; --rule-2:#3A4654;
  --accent:#7FB2E0; --accent-ink:#0E1319; --accent-soft:#1B2B3B;
  --crit:#F0918A; --crit-soft:#33191A;
  --warn:#E5B369; --warn-soft:#2E2415;
  --ok:#7BC7A5;  --ok-soft:#12291F;
  --shadow:0 1px 2px rgba(0,0,0,.4),0 8px 24px -12px rgba(0,0,0,.6);
  --bar:rgba(14,19,25,.88);
}

/* --------------------------------------------------------------- reset --- */

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

html{
  -webkit-text-size-adjust:100%;
  /* Keeps in-page anchor targets clear of the sticky bar. Replaces the
     JavaScript that measured the old banner's height at every breakpoint. */
  scroll-padding-top:5rem;
}

body{
  margin:0;
  background:var(--ground);
  color:var(--ink);
  font-family:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}

img{max-width:100%;height:auto}

:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* The top bar and wordmark live in stylesheets/topbar.css, shared with
   eol.html. The --bar token they use is defined above. */

/* -------------------------------------------------------------- layout --- */

/* One width for the whole site, and it is the top bar's width: .topbar-inner
   carries the same 1120px, so the wordmark, the nav, the masthead rule, every
   card and every paragraph share two vertical edges. Nothing is capped to a
   reading measure below it; the page width IS the measure. */
.page{max-width:1120px;margin:0 auto;padding:0 20px 72px}

.masthead{border-bottom:2px solid var(--ink);margin:34px 0 30px;padding-bottom:14px}

.content > :first-child{margin-top:0}

/* ---------------------------------------------------------- typography --- */

h1{
  font-family:Spectral,Georgia,serif;font-weight:700;
  font-size:clamp(30px,4.6vw,44px);line-height:1.08;
  margin:0;letter-spacing:-.015em;text-wrap:balance;
}

h2{
  font-family:Spectral,Georgia,serif;font-weight:700;font-size:26px;
  line-height:1.2;margin:38px 0 14px;letter-spacing:-.01em;text-wrap:balance;
}

h3{
  font-family:"IBM Plex Sans",sans-serif;font-weight:600;font-size:17px;
  margin:28px 0 8px;letter-spacing:.005em;text-wrap:balance;
}

h4{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-weight:600;
  font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);margin:24px 0 8px;
}

p,ul,ol{margin:0 0 15px}
/* Text runs the full width of the page. Reid's call, 2026-09-01: p and li were
   capped at 68ch and .lede and .standfirst at 64ch and 62ch, which left every
   paragraph stopping well short of the masthead rule once the page matched the
   top bar at 1120px. The cap is stated rather than deleted so it is clear the
   full width is deliberate and not an omission. */
p,li{max-width:none}
ul,ol{padding-left:22px}
li{margin-bottom:7px}
strong{font-weight:600;color:var(--ink)}

a{color:var(--accent);text-decoration:underline;text-underline-offset:2px}
a:hover{text-decoration-thickness:2px}

hr{border:0;border-top:1px solid var(--rule);margin:34px 0}

blockquote{
  margin:0 0 15px;padding:2px 0 2px 18px;
  border-left:3px solid var(--accent);color:var(--ink-2);
}

/* Lede paragraph under a page title. */
.lede{font-size:18px;line-height:1.55;color:var(--ink-2);max-width:none}

/* ---------------------------------------------------------------- code --- */

code{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:.88em;
  background:var(--surface-2);color:var(--ink-2);
  padding:1px 5px;border-radius:3px;
}

pre{
  background:var(--surface);border:1px solid var(--rule);border-radius:4px;
  padding:14px 16px;margin:0 0 15px;overflow-x:auto;font-size:13.5px;line-height:1.5;
}
pre code{background:none;padding:0;font-size:inherit;color:var(--ink)}

/* Rouge highlighting, kept to the token palette so it works in both themes. */
.highlight .c,.highlight .c1,.highlight .cm{color:var(--ink-3);font-style:italic}
.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr{color:var(--accent);font-weight:600}
.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb{color:var(--ok)}
.highlight .n,.highlight .nn,.highlight .nx{color:var(--ink)}
.highlight .nc,.highlight .nf{color:var(--crit)}
.highlight .m,.highlight .mi,.highlight .mf{color:var(--warn)}

/* -------------------------------------------------------------- tables --- */

.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 0 18px}

table{
  border-collapse:collapse;width:100%;font-size:14.5px;
  background:var(--surface);border:1px solid var(--rule);border-radius:4px;
}
th,td{
  text-align:left;padding:10px 14px;
  border-bottom:1px solid var(--rule);vertical-align:top;
}
th{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);font-weight:600;border-bottom:1px solid var(--rule-2);
}
tbody tr:last-child td{border-bottom:0}

/* --------------------------------------------------------------- cards --- */

/* Open-source libraries and talks. Same record shape as the findings on /eol/,
   so a visitor who arrives from the tool recognises the page as the same site. */
.project-card{
  background:var(--surface);
  border:1px solid var(--rule);border-left:3px solid var(--accent);
  border-radius:4px;box-shadow:var(--shadow);
  padding:18px 22px;margin-bottom:16px;
}

.project-card.is-stable{
  border-left-color:var(--rule-2);
  background:var(--surface-2);
}

.project-card h3{
  font-family:Spectral,Georgia,serif;font-weight:600;font-size:20px;
  letter-spacing:-.005em;margin:0 0 6px;
}
.project-card h3 a{text-decoration:none}
.project-card h3 a:hover{text-decoration:underline}
.project-card p{margin-bottom:10px;color:var(--ink-2);font-size:15px}
.project-card p:last-child{margin-bottom:0}

.project-meta{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:12px;color:var(--ink-3);
}
.project-meta a{color:var(--accent)}
.project-meta a + a::before{
  /* inline-block stops the parent link's underline propagating into the
     separator, which otherwise renders as an underscore. */
  content:"\00b7";display:inline-block;margin:0 .55rem;color:var(--ink-3);
}

.project-downloads{
  display:inline-block;vertical-align:middle;margin-left:.5rem;
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  font-variant-numeric:tabular-nums;
  padding:4px 9px;border-radius:2px;
  color:var(--warn);background:var(--warn-soft);
}
.project-card.is-stable .project-downloads{
  color:var(--ink-3);background:var(--surface);border:1px solid var(--rule);
}

/* ---------------------------------------------------------- about page --- */

.about-intro{display:flex;align-items:center;gap:1.75rem;margin-bottom:1.75rem}
.about-intro p{margin:0}

.about-intro blockquote{
  margin:0;padding:0;border-left:0;
  font-family:Spectral,Georgia,serif;font-weight:600;font-size:21px;
  line-height:1.45;color:var(--ink);max-width:34ch;
}

.avatar{
  flex:none;width:8rem;height:8rem;margin:0;border-radius:50%;
  object-fit:cover;border:3px solid var(--surface);
  box-shadow:0 0 0 2px var(--accent);
}

@media (max-width:36em){
  .about-intro{flex-direction:column;align-items:flex-start;gap:1.25rem}
  .about-intro blockquote{max-width:none}
}

/* -------------------------------------------------------- scaffolding --- */

/* Marks a section still needing Reid's input. Deliberately loud so it cannot
   ship by accident. Delete the whole div once filled in, not just the class. */
.needs-input{
  padding:.85rem 1.1rem;margin:1rem 0;
  border:2px dashed var(--warn);border-radius:4px;
  background:var(--warn-soft);color:var(--ink-2);font-size:14.5px;
}
.needs-input::before{
  content:"TO FILL IN: ";font-weight:700;color:var(--warn);
}

/* ------------------------------------------------------------ masthead --- */

.eyebrow{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:11px;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);margin:0 0 10px;
}

.standfirst{
  margin:14px 0 0;max-width:none;
  color:var(--ink-2);font-size:18px;line-height:1.5;
}

/* --------------------------------------------------------- call to action --- */

.cta-row{display:flex;flex-wrap:wrap;gap:12px;margin:0 0 8px}

.btn{
  display:inline-block;padding:11px 20px;border-radius:3px;
  font-weight:600;font-size:15px;text-decoration:none;
  border:1px solid var(--accent);
}
.btn-primary{background:var(--accent);color:var(--accent-ink)}
.btn-primary:hover{filter:brightness(1.1);text-decoration:none}
.btn-secondary{background:transparent;color:var(--accent)}
.btn-secondary:hover{background:var(--accent-soft);text-decoration:none}

/* ------------------------------------------------------------- options --- */

/* Three ways to respond to the finding. A grid because they are alternatives
   to weigh side by side, not a sequence. */
.options{display:grid;gap:16px;margin:0 0 18px}
@media (min-width:52em){.options{grid-template-columns:repeat(3,1fr)}}

.option{
  background:var(--surface);border:1px solid var(--rule);
  border-top:3px solid var(--rule-2);border-radius:4px;
  padding:18px 20px;box-shadow:var(--shadow);
}
.option--crit{border-top-color:var(--crit)}
.option--warn{border-top-color:var(--warn)}
.option--ok{border-top-color:var(--ok)}
.option h3{margin:0 0 8px;font-size:16px}
.option p{font-size:14.5px;color:var(--ink-2);margin:0 0 10px;max-width:none}
.option p:last-child{margin-bottom:0}
.option .verdict{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
}
.option--crit .verdict{color:var(--crit)}
.option--warn .verdict{color:var(--warn)}
.option--ok .verdict{color:var(--ok)}

/* --------------------------------------------------------------- price --- */

.price{
  display:flex;flex-wrap:wrap;gap:6px 26px;align-items:baseline;
  background:var(--surface);border:1px solid var(--rule);
  border-left:4px solid var(--accent);border-radius:4px;
  box-shadow:var(--shadow);padding:20px 24px;margin:0 0 18px;
}
.price-figure{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:30px;font-weight:600;color:var(--accent);
  font-variant-numeric:tabular-nums;line-height:1.1;
}
.price-terms{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);
}
.price p{margin:0;font-size:14.5px;color:var(--ink-2)}

/* ---------------------------------------------------------------- form --- */

.form{
  background:var(--surface);border:1px solid var(--rule);border-radius:4px;
  box-shadow:var(--shadow);padding:22px 24px;margin:0 0 20px;
}
.form-row{display:grid;gap:14px}
@media (min-width:40em){.form-row{grid-template-columns:1fr 1fr}}

.field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px}
.field label{font-size:13px;font-weight:600;color:var(--ink-2)}
.field .hint{font-size:12.5px;color:var(--ink-3);margin:0;line-height:1.4}

.field input[type=text],
.field input[type=email],
.field select,
.field textarea{
  width:100%;padding:10px 11px;border:1px solid var(--rule-2);border-radius:3px;
  background:var(--surface);color:var(--ink);font:inherit;font-size:15px;
}
.field select,.field input[type=text]{font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:14px}
.field textarea{min-height:88px;resize:vertical;font-family:inherit;font-size:15px}

/* The block submit button. .panel and .capture are /eol/'s cards: the same
   component as .form, in a page that builds its own shell. */
.form button,.panel button,.capture button{
  width:100%;padding:12px;border:0;border-radius:3px;
  background:var(--accent);color:var(--accent-ink);
  font:inherit;font-weight:600;font-size:15px;cursor:pointer;
}
.form button:hover,.panel button:hover,.capture button:hover{filter:brightness(1.1)}
.form button:disabled,.capture button:disabled{opacity:.6;cursor:default}

.note{margin:12px 0 0;font-size:13.5px;color:var(--ink-3)}
.note--err{color:var(--crit)}

.done{
  background:var(--ok-soft);color:var(--ok);border:1px solid var(--ok);
  border-radius:3px;padding:16px 18px;font-size:14.5px;font-weight:500;
}
.hidden{display:none}

/* -------------------------------------------- /eol/ the exposure check --- */

/* The tool at /eol/ builds its own shell: its own <head>, its own sources
   footer, and a letterhead that only appears in print. The look is this
   design system, so only what is particular to the page lives here. Its
   fields, buttons, tables, notes, links and print palette are the site-wide
   rules above, and changing one now changes both.

   Two columns, the version form beside the finding it generates. The findings
   track is minmax(0,...) in both states and never a bare 1fr: the controls
   table carries a 560px min-width so it stays readable while it scrolls
   inside .table-scroll, and an auto minimum lets that 560px size the track
   and push the whole page sideways on a phone. */
.cols{display:grid;grid-template-columns:320px minmax(0,1fr);gap:28px;align-items:start}
@media (max-width:860px){.cols{grid-template-columns:minmax(0,1fr)}}

.panel{
  background:var(--surface);border:1px solid var(--rule);border-radius:4px;
  box-shadow:var(--shadow);padding:20px;
}
.panel--sticky{position:sticky;top:20px}
@media (max-width:860px){.panel--sticky{position:static}}

.panel-title{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:11px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);
  margin:0 0 16px;padding-bottom:10px;border-bottom:1px solid var(--rule);
}

.placeholder{
  color:var(--ink-3);font-size:15px;padding:36px 20px;text-align:center;
  border:1px dashed var(--rule-2);border-radius:4px;
}

/* ---- the finding --- */

.stack{display:flex;flex-direction:column;gap:16px}

.record{
  background:var(--surface);border:1px solid var(--rule);
  border-left:4px solid var(--rule-2);border-radius:4px;
  box-shadow:var(--shadow);padding:18px 20px;
}
.record--crit{border-left-color:var(--crit)}
.record--warn{border-left-color:var(--warn)}
.record--ok{border-left-color:var(--ok)}

.rec-head{
  display:flex;flex-wrap:wrap;gap:10px;
  align-items:baseline;justify-content:space-between;margin-bottom:12px;
}
.rec-title{
  font-family:Spectral,Georgia,serif;font-weight:600;font-size:21px;
  margin:0;letter-spacing:-.005em;
}

.pill{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:10px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;
  padding:4px 9px;border-radius:2px;white-space:nowrap;
}
.pill--crit{background:var(--crit-soft);color:var(--crit)}
.pill--warn{background:var(--warn-soft);color:var(--warn)}
.pill--ok{background:var(--ok-soft);color:var(--ok)}

.dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:7px 18px;margin:0;font-size:14px}
.dl dt{
  color:var(--ink-3);font-size:12px;letter-spacing:.04em;
  text-transform:uppercase;font-weight:600;align-self:center;
}
.dl dd{
  margin:0;font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-variant-numeric:tabular-nums;
}

/* The controls table sits inside a record, which is already a bordered card
   on a surface, so it drops the frame the site table carries elsewhere. The
   min-width keeps three columns legible and hands the overflow to
   .table-scroll rather than to the page. */
.record table{border:0;background:transparent;min-width:560px}
/* The control reference itself, set as data and never broken across lines:
   "164.308(a)(1)(ii)(A)-(B)" is a citation, not a sentence. */
.record td.ctl{
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-weight:500;
  white-space:nowrap;color:var(--accent);
}

/* ---- the elapsed counter --- */

/* The number of days without patches is the whole argument of this page, so
   it is set as the headline of each record rather than as a table row. */
.counter{
  display:flex;align-items:flex-end;gap:18px;flex-wrap:wrap;
  margin:2px 0 16px;padding-bottom:16px;border-bottom:1px solid var(--rule);
}
.counter-n{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:clamp(44px,8.5vw,66px);font-weight:600;line-height:.88;
  letter-spacing:-.035em;font-variant-numeric:tabular-nums;
}
.counter--crit .counter-n{color:var(--crit)}
.counter--ok   .counter-n{color:var(--ok)}
.counter-l{
  font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);line-height:1.5;max-width:23ch;padding-bottom:6px;
}

/* ---- the version trap and its ladder --- */

.trap{
  background:var(--surface);border:1px solid var(--crit);border-radius:4px;
  box-shadow:var(--shadow);overflow:hidden;
}
.trap-head{background:var(--crit-soft);padding:16px 20px;border-bottom:1px solid var(--crit)}
.trap-head .rec-title{color:var(--crit)}
.trap-body{padding:18px 20px}
.trap p{margin:0 0 14px}

.ladder{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-direction:column}
/* margin:0 undoes the site-wide list spacing. The connector line is drawn
   from each rung to the next, and a gap between them would break it. */
.rung{
  display:grid;grid-template-columns:26px minmax(0,1fr);gap:14px;align-items:start;
  margin:0;padding-bottom:14px;position:relative;
}
.rung:not(:last-child)::before{
  content:"";position:absolute;left:12px;top:24px;bottom:0;width:2px;background:var(--rule-2);
}
.rung-n{
  width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:11px;font-weight:600;
  background:var(--surface-2);color:var(--ink-2);border:1px solid var(--rule-2);
  position:relative;z-index:1;
}
.rung--rails .rung-n{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}
.rung--ruby  .rung-n{background:var(--warn-soft);color:var(--warn);border-color:var(--warn)}
.rung-body strong{font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:15px;display:block}
.rung-why{font-size:13px;color:var(--ink-3);margin-top:2px}

/* ---- what to do about it --- */

.capture{background:var(--surface-2);border:1px solid var(--rule);border-radius:4px;padding:20px}
.capture + .capture{margin-top:-2px}
.capture h3{font-family:Spectral,Georgia,serif;font-size:20px;margin:0 0 6px}
.capture p{margin:0 0 16px;font-size:14px;color:var(--ink-2)}
.capture .hint{margin:0 0 14px;font-size:12.5px;color:var(--ink-3);line-height:1.4}

/* ---- sources and disclaimer --- */

/* Not .site-footer: this one carries prose, and /eol/ does not run the
   shared layout's link row. Full width like everything else: capped, its rule
   stopped short of the finding above it. */
.eol-footer{
  margin-top:36px;padding-top:18px;border-top:1px solid var(--rule);
  font-size:12.5px;color:var(--ink-3);
}
/* The entity, set apart from the sources and the disclaimer above it. This
   line prints with the finding, which is the point of it being here at all:
   an engineer forwards the printout to an auditor, and the document has to
   say who produced it. The privacy link is screen furniture and comes out. */
.eol-footer-entity{margin:16px 0 0}
.eol-footer a{color:var(--ink-3);text-decoration:underline}
.eol-footer a:hover{color:var(--accent)}

@media (prefers-reduced-motion:no-preference){
  .record,.trap{animation:rise .32s ease-out both}
  @keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
}

/* The print letterhead, which appears nowhere on screen. */
.printhead{display:none}

/* -------------------------------------------------------------- footer --- */

.site-footer{
  margin-top:52px;padding-top:20px;border-top:1px solid var(--rule);
  font-size:13.5px;color:var(--ink-3);
}

/* Two rows, not one. The entity line is the counterparty rather than a nav
   item, and at this size the name, the form and the address already fill most
   of a laptop line: folded into the flex row below it, the address wrapped
   against the copyright on anything narrower. It sits first because that is
   the order the sentence reads in. */
.site-footer-entity{margin:0 0 10px}
.site-footer-row{
  display:flex;flex-wrap:wrap;gap:8px 20px;justify-content:space-between;
}
.site-footer a{color:var(--ink-3)}
.site-footer a:hover{color:var(--accent)}
.site-footer-links a + a::before{
  content:"\00b7";display:inline-block;margin:0 .55rem;color:var(--ink-3);
}

/* --------------------------------------------------------------- print --- */

@media print{
  /* Force the light palette: a dark-theme visitor would otherwise print a
     black page, and the /eol/ finding goes to an auditor. Every semantic
     colour is restated, not only the ones this rule changes: the theme rules
     above match :root with the same specificity, so a token left out here
     keeps its dark value and the finding prints a salmon counter. */
  :root,:root[data-theme="dark"],:root:not([data-theme="light"]){
    color-scheme:light;
    --ground:#FFFFFF; --surface:#FFFFFF; --surface-2:#F2F4F7;
    --ink:#131A22; --ink-2:#3D4854; --ink-3:#55606D;
    --rule:#C9D1DB; --rule-2:#AEB9C6;
    --accent:#1B4B7A; --accent-soft:#DCE7F2;
    --crit:#9E2A20; --crit-soft:#F7E2E0;
    --warn:#7A4900; --warn-soft:#FAECD8;
    --ok:#1A5C43;  --ok-soft:#DCEDE5;
    --shadow:none;
  }
  *{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  @page{margin:16mm}
  /* For the parts of a footer that are navigation on screen and dead text on
     paper: print strips link styling, so a "Privacy" link prints as a word
     with nowhere to go. */
  .print-hide{display:none !important}
  body{background:#fff;font-size:11pt;line-height:1.45}
  .topbar{display:none}
  .page{max-width:none;padding:0}
  .project-card{break-inside:avoid;page-break-inside:avoid;box-shadow:none}
  .table-scroll{overflow:visible}
  a{color:var(--ink);text-decoration:none}

  /* /eol/ prints as the finding itself. The masthead, the version form and
     the calls to action are screen furniture and come out; the letterhead,
     which names the versions and the date, goes in. Scoped to body.eol so
     the rest of the site still prints its own title. */
  .eol .masthead,.eol .panel,.eol .capture,.eol .placeholder{display:none !important}
  .eol .printhead{
    display:block;border-bottom:2px solid var(--ink);
    padding-bottom:10px;margin-bottom:18px;
  }
  /* The letterhead. It was images/logo-lockup.png until 2026-09-03, a raster
     of the master artwork whose middle tier read "CONSULTING": a name no
     entity holds. It is now the same construction as the top bar, the shield
     beside "Reid Morrison" over "EOL REMEDIATION" on the 2px rule, which
     means the printed finding and the screen carry one mark and nothing on
     this site depends on the master art any more.

     Set in mm and pt because this only ever renders on paper. The tier label
     is the part that used to turn to mush when the lockup was reproduced
     small; as live type at 8pt it sets cleanly at any printer resolution,
     which is the second reason the raster is gone. */
  .eol .ph-lockup{display:flex;align-items:center;gap:4mm;margin:0 0 3mm}
  .eol .ph-lockup .brand-mark{height:15mm}
  .eol .ph-type{
    display:inline-block;border-bottom:2px solid var(--ink);padding-bottom:1.5mm;
  }
  .eol .ph-name{
    font-family:Spectral,Georgia,serif;font-weight:700;font-size:21pt;
    letter-spacing:-.015em;color:var(--ink);
  }
  .eol .ph-tier{
    font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:8pt;font-weight:500;
    letter-spacing:.18em;text-transform:uppercase;color:var(--accent);margin-left:3mm;
  }
  .eol .ph-sub{
    font-family:"IBM Plex Mono",ui-monospace,monospace;font-size:8pt;
    letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin:5px 0 0;
  }
  .eol .cols{display:block}
  .eol .stack{gap:12px}
  .eol .record,.eol .trap{
    border:1px solid var(--rule);box-shadow:none;animation:none;
    break-inside:avoid;page-break-inside:avoid;
  }
  .eol .rec-title{font-size:15pt}
  .eol .counter{margin-bottom:12px;padding-bottom:12px}
  .eol .counter-n{font-size:34pt}
  .eol .counter-l{font-size:7.5pt}
  .eol table{min-width:0;font-size:9.5pt}
  .eol th,.eol td{padding:6px 8px}
  .eol-footer{margin-top:18px;font-size:8pt}
}
