/* =================================================================
   BB Cloud Developments site styles

   The palette is taken verbatim from lib/contracts/housestyle.py so
   the site and the agreements read as one document system. Purple
   (#6B2FA0) is deliberately absent: per brand/README.md it is
   contract furniture and never appears in the logo or online.

   One first-party script, site.js, adds the interactive tools. The CSP
   is script-src 'self': no inline script and no third party. Every
   rule that depends on scripting is scoped under html.js, so with the
   script blocked the page falls back to a complete static layout.
   ================================================================= */

:root {
  --bg:          #ffffff;
  --bg-alt:      #f7f8fa;
  --text:        #1a1a1a;   /* housestyle INK */
  --text-muted:  #666666;   /* housestyle MUTED */
  --rule:        #d6d6d6;   /* housestyle RULE_GREY */
  --heading:     #1f3864;   /* NAVY */
  --accent:      #2e9aa8;   /* TEAL, graphics, rules, the mark */
  --accent-text: #1d6b76;   /* darkened for AA contrast at small sizes */
  --bar:         #1f3864;
  --bar-end:     #2e9aa8;
  --mark-back:   #1f3864;
  --mark-front:  #2e9aa8;
  --warn:        #b7791f;
  --bad:         #b0413e;
  --measure: 70ch;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:          #0f1c2e;
    --bg-alt:      #16263d;
    --text:        #e8eef6;
    --text-muted:  #9aabbf;
    --rule:        #2b3f59;
    --heading:     #ffffff;
    --accent:      #3fb6c6;
    --accent-text: #6bd0de;
    --bar:         #2e9aa8;
  --bar-end:     #4a6fa5;
    --mark-back:   #4a6fa5;
    --mark-front:  #3fb6c6;
    --warn:        #e0a43c;
    --bad:         #e07a6f;
  }
}

:root[data-theme="dark"] {
  --bg:          #0f1c2e;
  --bg-alt:      #16263d;
  --text:        #e8eef6;
  --text-muted:  #9aabbf;
  --rule:        #2b3f59;
  --heading:     #ffffff;
  --accent:      #3fb6c6;
  --accent-text: #6bd0de;
  --bar:         #2e9aa8;
  --bar-end:     #4a6fa5;
  --mark-back:   #4a6fa5;
  --mark-front:  #3fb6c6;
  --warn:        #e0a43c;
  --bad:         #e07a6f;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Segoe UI", "Segoe UI Web (West European)", -apple-system,
               BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* The navy rule that tops every agreement PDF. It runs out into teal at the
   right, which is the same navy-to-teal move the wordmark makes. */
.bar {
  height: 4px;
  background: linear-gradient(90deg,
              var(--bar) 0%, var(--bar) 38%, var(--bar-end) 100%);
  transform-origin: left center;
  animation: draw 620ms cubic-bezier(.22,.61,.36,1) both;
  flex: none;
}
@keyframes draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* The container width is what decides whether the site reads as centred.
   The text blocks inside are capped at --measure and set flush left, so a
   very wide container leaves the copy hugging the left edge of a big screen
   with nothing on the right. Keep this close to the width the hero headline
   actually needs and the whole column sits centred in the window. */
.wrap {
  width: 100%;
  max-width: 1120px;
  margin-inline: auto;
  padding-inline: clamp(1.4rem, 5vw, 4rem);
}

/* --- masthead and navigation ----------------------------------- */
/* Sticky so the nav is always one move away on the long tool pages. The
   padding is fixed rather than shrinking on scroll: a sticky element that
   changes height moves everything under it and makes the page jump. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  padding-block: clamp(0.9rem, 2vw, 1.3rem);
  background: var(--bg);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease, box-shadow 200ms ease;
  flex: none;
}
.masthead.is-stuck {
  border-bottom-color: var(--rule);
  box-shadow: 0 6px 18px -14px rgba(15, 28, 46, .45);
}

.nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem 2rem;
  flex-wrap: wrap;
}

.lockup {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  text-decoration: none;
}

.mark { width: 42px; height: auto; flex: none; display: block; }
.mark .back  { fill: var(--mark-back); }

/* The teal disc is the only moving part of the mark. It sweeps in on load and
   opens up again on hover, which reads as light crossing the cloud rather than
   as a logo doing a trick.

   fill-mode is `backwards`, not `both`, and that is load-bearing: `both` would
   leave the finished animation applying `transform: none` forever, and an
   animated value beats a transition in the cascade, so the hover below would
   silently never fire. `backwards` only covers the delay before it starts.

   transform-box: view-box makes the translate values user units, so they are
   in the same coordinate space as the viewBox and stay put at any rendered
   size of the mark. */
.mark .front {
  fill: var(--mark-front);
  transform-box: view-box;
  transform-origin: center;
  animation: mark-drift 900ms cubic-bezier(.22,.61,.36,1) backwards;
  transition: transform 340ms cubic-bezier(.22,.61,.36,1);
}
@keyframes mark-drift {
  from { transform: translate(96px, 36px); }
  to   { transform: none; }
}
.lockup:hover .mark .front,
.lockup:focus-visible .mark .front { transform: translate(-26px, -12px); }

.wordmark {
  font-size: 1.24rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--heading);
}
.wordmark .dev { color: var(--accent-text); font-weight: 400; }

.nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.9rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav a {
  display: inline-block;
  font-size: 0.945rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  padding-block: 0.3rem;
  position: relative;
  /* Kept transparent and kept here: it reserves the 2px so the row does not
     shift when the underline below arrives. */
  border-bottom: 2px solid transparent;
  transition: color 140ms ease;
}
/* The underline is a pseudo-element so it can sweep rather than switch on.
   The current page holds it open; hover and keyboard focus draw it. */
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 240ms cubic-bezier(.22,.61,.36,1);
}
.nav a:hover,
.nav a:focus-visible { color: var(--heading); }
.nav a:hover::after,
.nav a:focus-visible::after,
.nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] {
  color: var(--heading);
  font-weight: 600;
}

/* --- shared section furniture ---------------------------------- */
main { flex: 1 0 auto; }

.band { border-top: 1px solid var(--rule); }
.band--alt { background: var(--bg-alt); }

.section { padding-block: clamp(2.75rem, 6vw, 4.5rem); }

/* The short teal tick echoes the masthead rule and the step rules, so the
   same mark introduces every section. */
.eyebrow::before {
  content: "";
  display: inline-block;
  width: 1.7rem;
  height: 2px;
  margin-right: 0.75rem;
  vertical-align: middle;
  background: var(--accent);
}

.eyebrow {
  margin: 0 0 1.75rem;
  font-size: 0.715rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* --- home hero -------------------------------------------------- */
.hero { padding-block: clamp(2.25rem, 7vw, 5.25rem) clamp(2.75rem, 8vw, 6rem); }

.hero h1 {
  margin: 0 0 1.4rem;
  max-width: 24ch;
  font-size: clamp(2.35rem, 4.6vw, 5rem);
  font-weight: 300;
  letter-spacing: -0.033em;
  line-height: 1.04;
  color: var(--heading);
}

.lead {
  margin: 0 0 2.4rem;
  max-width: var(--measure);
  font-size: clamp(1.03rem, 1.5vw, 1.22rem);
  color: var(--text-muted);
}

/* --- interior page header --------------------------------------- */
.pagehead { padding-block: clamp(2rem, 5vw, 3.5rem) clamp(2rem, 4vw, 3rem); }

.pagehead h1 {
  margin: 0 0 1.1rem;
  max-width: 22ch;
  font-size: clamp(2.05rem, 3.6vw, 3.3rem);
  font-weight: 300;
  letter-spacing: -0.028em;
  line-height: 1.08;
  color: var(--heading);
}

.pagehead .lead { margin-bottom: 0; }

/* --- links and calls to action ---------------------------------- */
/* No buttons. A two-client consultancy has an email address,
   not a signup funnel. */
.mailto {
  display: inline-block;
  font-size: clamp(1.02rem, 1.5vw, 1.18rem);
  font-weight: 600;
  color: var(--accent-text);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 2px;
  transition: color 140ms ease, border-color 140ms ease;
}
.mailto:hover,
.mailto:focus-visible { color: var(--heading); border-color: var(--heading); }
.mailto .arrow { display: inline-block; transition: transform 160ms ease; }
.mailto:hover .arrow { transform: translateX(3px); }

.textlink {
  color: var(--accent-text);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  transition: border-color 140ms ease;
}
.textlink:hover,
.textlink:focus-visible { border-bottom-color: var(--accent); }

/* --- definition list: the agreement's scope table ---------------- */
.defs { margin: 0; }

.def {
  display: grid;
  grid-template-columns: minmax(0, 23rem) minmax(0, 1fr);
  gap: 0.35rem clamp(1.5rem, 4vw, 3.5rem);
  padding-block: 1.45rem;
  border-top: 1px solid var(--rule);
}
.def:last-child { border-bottom: 1px solid var(--rule); }

.def dt {
  margin: 0;
  font-size: 1.06rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--heading);
}
.def dd { margin: 0; max-width: var(--measure); color: var(--text-muted); }

/* --- process steps: numbered because it genuinely is a sequence -- */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: clamp(1.75rem, 4vw, 3rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The rule above each step is a pseudo-element rather than a border so it can
   draw itself left to right, the same gesture as the masthead bar. It defaults
   to scaleX(1), so a browser that cannot drive it from scroll just shows a
   static teal rule and nothing looks broken. */
.step { position: relative; padding-top: 1.1rem; }
.step::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--accent);
  transform: scaleX(1);
  transform-origin: left center;
}

.step .num {
  display: block;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--accent-text);
  margin-bottom: 0.5rem;
  font-variant-numeric: tabular-nums;
}
.step h3 {
  margin: 0 0 0.5rem;
  font-size: 1.06rem;
  font-weight: 600;
  color: var(--heading);
}
.step p { margin: 0; color: var(--text-muted); }

/* --- long-form prose (services detail, about) -------------------- */
/* Order matters here: both selectors below are specificity (0,1,0), so the
   second wins on the adjacent siblings. Do not add `margin` to `.prose p`
   - a type selector raises it to (0,1,1) and silently kills the spacing. */
.prose { max-width: var(--measure); }
.prose > * { margin: 0; }
.prose > * + * { margin-top: 1.1rem; }
.prose p { color: var(--text-muted); }
.prose strong { color: var(--text); font-weight: 600; }
.prose ul,
.prose ol { padding-left: 1.3rem; color: var(--text-muted); }
.prose li + li { margin-top: 0.45rem; }
.prose h3 { font-size: 1.05rem; color: var(--heading); }

/* --- guides: byline, and the copyable template block --------------- */
.byline { margin: 1rem 0 0; font-size: 0.9rem; color: var(--text-muted); }
.template {
  max-width: var(--measure);
  margin-top: 1.4rem;
  padding: 1.2rem 1.4rem;
  border-left: 3px solid var(--accent);
  background: var(--bg-alt);
}
.band--alt .template { background: var(--bg); }

.detail + .detail { margin-top: clamp(2.5rem, 5vw, 3.75rem); }

.detail h2 {
  margin: 0 0 0.85rem;
  font-size: clamp(1.4rem, 2.6vw, 1.8rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--heading);
}

.detail .kicker {
  margin: 0 0 0.4rem;
  font-size: 0.715rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}

/* A plain list of inclusions, set like the contract's scope rows. */
.includes {
  margin: 1.4rem 0 0;
  padding: 0;
  list-style: none;
  max-width: var(--measure);
}
.includes li {
  padding: 0.7rem 0 0.7rem 1.4rem;
  border-top: 1px solid var(--rule);
  color: var(--text-muted);
  position: relative;
}
.includes li:last-child { border-bottom: 1px solid var(--rule); }
.includes li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.35rem;
  width: 6px;
  height: 6px;
  background: var(--accent);
}

/* --- contact facts ---------------------------------------------- */
.facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.8rem 2rem;
  margin: 0;
  max-width: 34rem;
}
.facts dt {
  margin: 0;
  font-size: 0.715rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-top: 0.28rem;
}
.facts dd { margin: 0; color: var(--text); }
/* Cookie names are case-sensitive identifiers, so they are shown as written. */
.facts--cookies { margin: 1.4rem 0; }
.facts--cookies dt {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: 0.85rem;
  letter-spacing: 0;
  text-transform: none;
  padding-top: 0.12rem;
}

/* --- colophon: the signature element -----------------------------
   The document system stamps a status block on every deliverable.
   Here it carries the entity's public record, because the one thing
   a cautious client wants from a new vendor is verifiable facts.
   ---------------------------------------------------------------- */
.colophon {
  border-top: 1px solid var(--rule);
  padding-block: clamp(2.25rem, 5vw, 3.25rem);
  flex: none;
}

.entity {
  margin: 0 0 1.5rem;
  font-size: 0.775rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--heading);
}

.record {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.55rem 1.75rem;
  margin: 0 0 1.75rem;
  font-size: 0.875rem;
  max-width: 34rem;
}
.record dt {
  color: var(--text-muted);
  font-size: 0.73rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  align-self: baseline;
  padding-top: 0.18rem;
}
.record dd { margin: 0; color: var(--text); font-variant-numeric: tabular-nums; }

.fineprint { margin: 0; font-size: 0.815rem; color: var(--text-muted); }
.fineprint a {
  color: var(--accent-text);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* --- accessibility and motion ------------------------------------ */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

.rise {
  animation: rise 640ms cubic-bezier(.22,.61,.36,1) both;
  animation-delay: 140ms;
}
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@keyframes reveal {
  from { opacity: 0; transform: translateY(13px); }
  to   { opacity: 1; transform: none; }
}

/* --- reveal on scroll, without JavaScript -------------------------
   Scroll-driven animations tie an element's progress to its own position in
   the viewport, which is the one thing that previously would have required an
   IntersectionObserver and therefore a script. It stays in CSS so the reveal
   does not depend on site.js loading.

   Everything here is inside @supports and every base style above already
   renders the finished state. A browser without scroll-driven animations shows
   a normal, fully visible page and loses only the motion. Do not move any of
   these declarations out of this block, and do not give an element a hidden
   base state, or that browser gets blank sections.

   animation-duration must be `auto` so each animation spans its whole range;
   the longhands are written out because the `animation` shorthand would reset
   duration to 0s. Elements already on screen at load sit at the end of their
   range, so they are simply visible, not waiting to animate.
   ------------------------------------------------------------------ */
@supports (animation-timeline: view()) {
  .def,
  .step,
  .includes li,
  .detail,
  .eyebrow {
    animation-name: reveal;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: view();
    animation-range: entry 5% entry 55%;
  }

  /* The steps sit side by side, so they would otherwise all arrive at once.
     Offsetting the range per column cascades them across the row. */
  .steps .step:nth-child(3n+2) { animation-range: entry 14% entry 64%; }
  .steps .step:nth-child(3n+3) { animation-range: entry 23% entry 73%; }

  /* Each step's rule draws itself in, like the masthead bar. */
  .step::before {
    animation-name: draw;
    animation-duration: auto;
    animation-timing-function: cubic-bezier(.22,.61,.36,1);
    animation-fill-mode: both;
    animation-timeline: view();
    animation-range: entry 10% entry 70%;
  }
  .steps .step:nth-child(3n+2)::before { animation-range: entry 19% entry 79%; }
  .steps .step:nth-child(3n+3)::before { animation-range: entry 28% entry 88%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    /* Scroll-driven animations ignore duration, so cutting the duration above
       is not enough to stop them. Putting the timeline back on the document
       clock lets that 0.01ms apply and every fill-mode:both rule snap to its
       finished, visible state. */
    animation-timeline: auto !important;
  }
}

/* --- narrow screens ----------------------------------------------- */
@media (max-width: 620px) {
  .def { grid-template-columns: 1fr; gap: 0.3rem; }
  .record,
  .facts { grid-template-columns: 1fr; gap: 0.1rem 0; }
  .record dd,
  .facts dd { margin-bottom: 0.7rem; }
  .nav ul { gap: 0.35rem 1.35rem; }
}

/* --- small one-off spacing helpers ------------------------------- */
.after-defs { margin: 1.75rem 0 0; }
.contact-cta { margin: 0 0 2.5rem; }

/* --- about: portrait beside the bio -------------------------------
   The figure is omitted entirely by build.py when the image file is
   absent, so .bio must read correctly with one child or two.
   ------------------------------------------------------------------ */
/* Portrait sits beside the page title, not inside a section, so that every
   heading below it starts from the same left edge. */
.bio-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 17rem);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: end;
}
/* build.py omits the figure when the image file is absent; the text block is
   then the only child and should span the whole row. */
.bio-head > :only-child { grid-column: 1 / -1; }
.bio-head__text { min-width: 0; }

.portrait { margin: 0; }
.portrait img {
  display: block;
  width: 100%;
  /* height:auto is required. The width/height attributes on the <img> are
     presentational hints that map to CSS height, and an explicit height
     beats aspect-ratio, which renders the portrait at its full 1600px. */
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--bg-alt);
}
.portrait figcaption {
  margin-top: 0.6rem;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--text-muted);
}

/* The second photo sits beside the Background prose, top-aligned so it starts
   level with the first paragraph. Same omit-when-absent rule as .bio-head. */
.bio-body {
  display: grid;
  grid-template-columns: minmax(0, var(--measure)) minmax(0, 15rem);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.bio-body > :only-child { grid-column: 1 / -1; }

@media (max-width: 760px) {
  .bio-head,
  .bio-body { grid-template-columns: 1fr; }
  .portrait { max-width: 20rem; }
}

/* =================================================================
   Interactive layer

   Everything below styles markup that build.py renders in full. Rules
   that only make sense once site.js is running are scoped to html.js,
   which site.js sets before first paint. Without it, tabs show as
   stacked sections, the menu is a plain wrapped list, and the tools are
   readable checklists.
   ================================================================= */

html { scroll-padding-top: 5.5rem; }
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0.5rem;
  z-index: 50;
  padding: 0.6rem 1rem;
  background: var(--heading);
  color: var(--bg);
  font-weight: 600;
  text-decoration: none;
}
.skip:focus { left: 0.5rem; }

code {
  font-family: ui-monospace, "Cascadia Mono", Consolas, "SFMono-Regular", Menlo, monospace;
  font-size: 0.88em;
  padding: 0.05em 0.35em;
  background: var(--bg-alt);
  border: 1px solid var(--rule);
  border-radius: 2px;
}

.muted { color: var(--text-muted); }
.cta-copy { margin-bottom: 1.75rem; }

.section__lead {
  margin: -0.75rem 0 2rem;
  max-width: var(--measure);
  font-size: 1.04rem;
  color: var(--text-muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 1rem 2.25rem;
  margin: 0;
}

.pagehead .kicker {
  margin: 0 0 0.9rem;
  font-size: 0.715rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* "On this page" links under a page title. */
.jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.6rem;
  margin-top: 1.9rem;
}
.jump a {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--accent-text);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  transition: border-color 140ms ease;
}
.jump a:hover,
.jump a:focus-visible { border-bottom-color: var(--accent); }

.detail__try { margin: 1.3rem 0 0; }
.tool__title {
  margin: 0 0 0.85rem;
  font-size: clamp(1.45rem, 2.7vw, 2rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.2;
  color: var(--heading);
}
.contact-tools { margin: 2.25rem 0 0; max-width: var(--measure); color: var(--text-muted); }

/* --- controls ------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.95rem;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--accent-text);
  background: var(--bg);
  border: 1px solid var(--accent);
  border-radius: 2px;
  text-decoration: none;
  cursor: pointer;
  transition: color 140ms ease, border-color 140ms ease, background-color 140ms ease;
}
.btn:hover,
.btn:focus-visible { color: var(--heading); border-color: var(--heading); }
.btn[aria-pressed="true"] { background: var(--heading); border-color: var(--heading); color: var(--bg); }

.iconbtn {
  width: 2.5rem;
  height: 2.5rem;
  font: inherit;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 2px;
  cursor: pointer;
  transition: color 140ms ease, border-color 140ms ease;
}
.iconbtn:hover,
.iconbtn:focus-visible { color: var(--heading); border-color: var(--heading); }

.field label {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.field input[type="text"],
.field input[type="number"] {
  width: 100%;
  min-width: 0;
  padding: 0.55rem 0.7rem;
  font: inherit;
  font-size: 1rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 2px;
  font-variant-numeric: tabular-nums;
  transition: border-color 140ms ease;
}
.field input:hover { border-color: var(--text-muted); }
.field input:focus { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 0; }
.field__help { margin: 0.45rem 0 0; max-width: 30rem; font-size: 0.82rem; color: var(--text-muted); }

/* Range sliders. --fill is set by site.js to colour the track up to the
   thumb; without it the track is a plain rule. */
.range {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4.75rem;
  align-items: center;
  gap: 0.9rem;
  margin-top: 0.45rem;
}
.range output {
  font-weight: 600;
  color: var(--heading);
  text-align: right;
  font-variant-numeric: tabular-nums;
}
input[type="range"] {
  --fill: 0%;
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 24px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  background: linear-gradient(90deg, var(--accent) var(--fill), var(--rule) var(--fill));
}
input[type="range"]::-moz-range-track { height: 4px; background: var(--rule); }
input[type="range"]::-moz-range-progress { height: 4px; background: var(--accent); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  margin-top: -7px;
  border-radius: 50%;
  background: var(--heading);
  border: 3px solid var(--bg);
  box-shadow: 0 0 0 1px var(--heading);
  transition: transform 140ms ease;
}
input[type="range"]::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--heading);
  border: 3px solid var(--bg);
  box-shadow: 0 0 0 1px var(--heading);
}
input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.15); }

/* --- mobile menu ----------------------------------------------------- */
.nav-toggle { display: none; }

@media (max-width: 900px) {
  .js .nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.8rem;
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--heading);
    background: transparent;
    border: 1px solid var(--rule);
    border-radius: 2px;
    cursor: pointer;
  }
  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    display: block;
    width: 16px;
    height: 2px;
    background: currentColor;
    transition: transform 200ms ease, background-color 200ms ease;
  }
  .nav-toggle__bars { position: relative; }
  .nav-toggle__bars::before,
  .nav-toggle__bars::after { content: ""; position: absolute; left: 0; }
  .nav-toggle__bars::before { top: -5px; }
  .nav-toggle__bars::after { top: 5px; }
  .nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
  .nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(5px) rotate(45deg); }
  .nav-toggle[aria-expanded="true"] .nav-toggle__bars::after { transform: translateY(-5px) rotate(-45deg); }

  .js .nav { display: none; flex-basis: 100%; }
  .js .nav.is-open { display: block; animation: rise 260ms cubic-bezier(.22,.61,.36,1) both; }
  .js .nav ul { flex-direction: column; gap: 0; }
  .js .nav li { border-top: 1px solid var(--rule); }
  .js .nav a { display: block; padding-block: 0.75rem; font-size: 1rem; }
  .js .nav a::after { display: none; }
  .js .nav a[aria-current="page"] { color: var(--accent-text); }
}

/* --- tabs -------------------------------------------------------------
   No script: the tab strip is hidden and each panel shows under its own
   heading, one after another. With script: one panel at a time.
   ------------------------------------------------------------------- */
.tablist { display: none; }
.js .tablist { display: grid; }

.tablist [role="tab"] {
  position: relative;
  display: block;
  width: 100%;
  margin: 0;
  font: inherit;
  text-align: left;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color 160ms ease, background-color 160ms ease;
}
.tablist [role="tab"]:hover { color: var(--heading); }
.tablist [role="tab"][aria-selected="true"] { color: var(--heading); }

.tabpanel + .tabpanel { margin-top: 2rem; }
.js .tabpanel + .tabpanel { margin-top: 0; }
.js .tabpanel:not([hidden]) { animation: rise 340ms cubic-bezier(.22,.61,.36,1) both; }
.tabpanel:focus-visible { outline-offset: 6px; }

.tabpanel__title {
  margin: 0 0 0.8rem;
  font-size: clamp(1.2rem, 2.2vw, 1.45rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--heading);
}
.panel__lead { margin: 0 0 1rem; max-width: var(--measure); color: var(--text-muted); }
.panel__links { margin: 1.1rem 0 0; }
.panel__links + .panel__links { margin-top: 0.6rem; }
.includes--tight { margin-top: 0.4rem; }
.includes--tight li { padding-block: 0.5rem; }
.includes--tight li::before { top: 1.12rem; }

/* Side tabs: the problem picker on the home page. Reads like the scope
   table: rows of statements, the chosen one marked with a teal bar. */
.tabs--side .tabpanel {
  padding: clamp(1.3rem, 3vw, 2.1rem);
  background: var(--bg);
  border: 1px solid var(--rule);
}
.js .tabs--side {
  display: grid;
  grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
  gap: 0 clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
}
.js .tabs--side .tablist { border-bottom: 1px solid var(--rule); }
.tabs--side [role="tab"] {
  padding: 1rem 1rem 1rem 1.15rem;
  font-size: 1.02rem;
  font-weight: 600;
  line-height: 1.35;
  border-top: 1px solid var(--rule);
}
.tabs--side [role="tab"]::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  bottom: 0;
  width: 3px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 240ms cubic-bezier(.22,.61,.36,1);
}
.tabs--side [role="tab"][aria-selected="true"] { background: var(--bg); }
.tabs--side [role="tab"][aria-selected="true"]::before { transform: scaleY(1); }
/* The tab already says it; the heading stays for screen readers. */
.js .tabs--side .tabpanel__title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Pipeline tabs: the four stages of an AI answer, read left to right. */
.js .tabs--pipeline .tablist {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.75rem;
}
.tabs--pipeline [role="tab"] {
  padding: 0.95rem 0.25rem 0.4rem;
  font-size: 1.12rem;
  font-weight: 600;
  border-top: 3px solid var(--rule);
  transition: color 160ms ease, border-color 240ms ease;
}
.tabs--pipeline [role="tab"][aria-selected="true"] { border-top-color: var(--accent); }
.tab__num {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}
.tabs--pipeline .tabpanel { max-width: var(--measure); }

/* --- tool cards -------------------------------------------------------- */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16.5rem, 1fr));
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cards--single { max-width: 36rem; grid-template-columns: 1fr; }
.card__link {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 100%;
  padding: 1.5rem 1.5rem 3.25rem;
  color: inherit;
  text-decoration: none;
  background: var(--bg);
  border: 1px solid var(--rule);
  transition: border-color 180ms ease, transform 220ms cubic-bezier(.22,.61,.36,1), box-shadow 220ms ease;
}
.card__link:hover,
.card__link:focus-visible {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 14px 28px -22px rgba(15, 28, 46, .55);
}
.card__meta {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-text);
}
.card__title { font-size: 1.16rem; font-weight: 600; color: var(--heading); line-height: 1.3; }
.card__body { color: var(--text-muted); font-size: 0.96rem; }
.card__go {
  position: absolute;
  left: 1.5rem;
  bottom: 1.1rem;
  font-size: 1.2rem;
  color: var(--accent-text);
  transition: transform 200ms ease;
}
.card__link:hover .card__go { transform: translateX(5px); }

/* --- one-task calculator (home) ----------------------------------------- */
.minicalc {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
  gap: 1.2rem 2.2rem;
  margin: 1.25rem 0 0.25rem;
  padding: clamp(1.1rem, 2.5vw, 1.6rem);
  background: var(--bg-alt);
  border: 1px solid var(--rule);
}
.minicalc__out,
.minicalc__note { grid-column: 1 / -1; }
.minicalc__out {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
}
.minicalc__out p { margin: 0; color: var(--text-muted); }
.big {
  display: block;
  font-size: clamp(1.9rem, 3.4vw, 2.5rem);
  font-weight: 300;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
}
.minicalc__note { margin: 0; font-size: 0.86rem; color: var(--text-muted); }
.field--range > label {
  display: block;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --- full calculator ---------------------------------------------------- */
.calc__settings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.5rem 3rem;
  margin-bottom: 2rem;
  max-width: 56rem;
}
.calc__settings .field input[type="number"] { max-width: 9rem; }

.calc__row {
  display: grid;
  grid-template-columns: minmax(0, 2.6fr) repeat(3, minmax(0, 0.85fr)) minmax(0, 1.4fr) auto;
  gap: 0.75rem 1rem;
  align-items: end;
  padding-block: 1rem;
  border-top: 1px solid var(--rule);
}
.calc__row:last-child { border-bottom: 1px solid var(--rule); }
.js .calc__row { animation: rise 300ms cubic-bezier(.22,.61,.36,1) both; }
.calc__rowout {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding-bottom: 0.55rem;
}
.calc__hours { font-weight: 600; color: var(--heading); font-variant-numeric: tabular-nums; }
.calc__barwrap { display: block; height: 6px; background: var(--rule); }
.calc__bar {
  display: block;
  width: 0;
  height: 100%;
  background: var(--accent);
  transition: width 320ms cubic-bezier(.22,.61,.36,1);
}
[data-add] { margin-top: 1rem; }

.calc__totals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 1.25rem 2rem;
  margin: 2.25rem 0 1rem;
}
.calc__totals > div { padding-top: 0.8rem; border-top: 2px solid var(--rule); }
.calc__totals dt {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.calc__totals dd {
  margin: 0.2rem 0 0;
  font-size: clamp(1.7rem, 3vw, 2.3rem);
  font-weight: 300;
  letter-spacing: -0.02em;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
}
.calc__totals .is-key { border-top-color: var(--accent); }
.calc__totals .is-key dd { color: var(--accent-text); font-weight: 400; }
.calc__note { margin: 0 0 1.5rem; max-width: var(--measure); font-size: 0.88rem; color: var(--text-muted); }

/* --- self-checks --------------------------------------------------------
   Questions on the left, the running score pinned beside them on a wide
   screen so you can watch it move as you answer.
   ---------------------------------------------------------------------- */
.check {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: 2rem clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}
.check > noscript { grid-column: 1 / -1; }
.qs { margin: 0; padding: 0; list-style: none; }
.q { padding-block: 1.35rem; border-top: 1px solid var(--rule); }
.q:last-child { border-bottom: 1px solid var(--rule); }
.q fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.q legend {
  display: flex;
  gap: 0.9rem;
  padding: 0;
  font-size: 1.04rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--heading);
}
.q__num {
  flex: none;
  width: 1.6rem;
  padding-top: 0.12rem;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}
.q__why,
.choices { margin-left: 2.5rem; }
.q__why { margin-top: 0.4rem; margin-bottom: 0.85rem; max-width: var(--measure); font-size: 0.94rem; color: var(--text-muted); }
.choices { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.choice { position: relative; }
.choice input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}
.choice span {
  display: inline-block;
  min-width: 4.6rem;
  padding: 0.42rem 0.95rem;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: center;
  color: var(--text-muted);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 2px;
  cursor: pointer;
  transition: color 140ms ease, border-color 140ms ease, background-color 140ms ease;
}
.choice span:hover { border-color: var(--accent); color: var(--heading); }
.choice input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.choice input:checked + span { color: var(--bg); background: var(--heading); border-color: var(--heading); }
.choice input[value="no"]:checked + span { background: var(--bad); border-color: var(--bad); color: #fff; }
.choice input[value="unsure"]:checked + span { background: var(--warn); border-color: var(--warn); color: #1a1a1a; }

.check__result {
  position: sticky;
  top: 6rem;
  padding: 1.5rem;
  background: var(--bg-alt);
  border: 1px solid var(--rule);
}
.band--alt .check__result { background: var(--bg); }
.check__hint { margin: 0; font-size: 0.92rem; color: var(--text-muted); }

.score__num {
  margin: 0;
  font-size: 3.4rem;
  font-weight: 300;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--heading);
  font-variant-numeric: tabular-nums;
}
.score__of { margin-left: 0.2rem; font-size: 1rem; letter-spacing: 0; color: var(--text-muted); }
.score__meter { height: 6px; margin: 0.9rem 0 0.8rem; background: var(--rule); }
.score__fill {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 420ms cubic-bezier(.22,.61,.36,1), background-color 300ms ease;
}
.score__fill[data-level="mid"] { background: var(--warn); }
.score__fill[data-level="low"] { background: var(--bad); }
.score__band { margin: 0; font-size: 0.95rem; color: var(--text); }

.eyebrow--small { margin: 1.5rem 0 0.4rem; font-size: 0.68rem; }
.eyebrow--small::before { width: 1rem; }
.gaps { margin: 0; padding: 0 0 0 1.25rem; font-size: 0.92rem; }
.gaps li { padding: 0.45rem 0 0.45rem 0.2rem; color: var(--text-muted); border-top: 1px solid var(--rule); }
.gaps li::marker { color: var(--accent-text); font-weight: 600; font-size: 0.85rem; }
.gaps li.is-high .gaps__text { color: var(--text); font-weight: 600; }
.gaps__tag {
  display: inline-block;
  margin-left: 0.45rem;
  padding: 0 0.4rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: 0.1em;
  color: var(--text-muted);
  border: 1px solid var(--rule);
}
.check__mail { margin: 1.4rem 0 0; }
.check__mail .mailto { font-size: 1rem; }

/* --- crawler view -------------------------------------------------------- */
.crawler__controls { display: flex; flex-wrap: wrap; gap: 0.55rem; margin-bottom: 1rem; }
.crawler__out {
  margin: 0;
  max-height: 32rem;
  overflow: auto;
  padding: 1.1rem 1.25rem;
  font-family: ui-monospace, "Cascadia Mono", Consolas, "SFMono-Regular", Menlo, monospace;
  font-size: 0.8rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text);
  background: var(--bg-alt);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
}

/* --- questions ------------------------------------------------------------ */
.faqs { max-width: 52rem; }
.faq { border-top: 1px solid var(--rule); }
.faq:last-child { border-bottom: 1px solid var(--rule); }
.faq summary {
  position: relative;
  padding: 1.1rem 2.75rem 1.1rem 0;
  font-size: 1.06rem;
  font-weight: 600;
  color: var(--heading);
  list-style: none;
  cursor: pointer;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  margin-top: -0.75rem;
  font-size: 1.5rem;
  font-weight: 300;
  line-height: 1.5rem;
  color: var(--accent-text);
  transition: transform 220ms cubic-bezier(.22,.61,.36,1);
}
.faq[open] summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--accent-text); }
.faq .prose { padding-bottom: 1.3rem; }
.faq[open] .prose { animation: rise 280ms cubic-bezier(.22,.61,.36,1) both; }

/* --- footer navigation ---------------------------------------------------- */
.colophon__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2rem 4rem;
}
.footnav ul { margin: 0; padding: 0; list-style: none; columns: 2; column-gap: 2.5rem; }
.footnav li { padding-block: 0.22rem; break-inside: avoid; }
.footnav a { font-size: 0.875rem; color: var(--text-muted); text-decoration: none; }
.footnav a:hover,
.footnav a:focus-visible { color: var(--accent-text); }

/* --- narrow screens for the interactive layer ------------------------------ */
@media (max-width: 900px) {
  .check { grid-template-columns: 1fr; }
  .check__result { position: static; }
  .js .tabs--side { grid-template-columns: 1fr; }
  .js .tabs--side .tablist { margin-bottom: 1rem; }
  .colophon__grid { grid-template-columns: 1fr; }
}

@media (max-width: 760px) {
  .calc__row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .calc__row .field--task { grid-column: 1 / -1; }
  .calc__rowout { grid-column: 1 / 3; }
  .calc__row .iconbtn { justify-self: end; }
  .js .tabs--pipeline .tablist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
  .q__why,
  .choices { margin-left: 0; }
  .footnav ul { columns: 1; }
}

/* On a phone the lockup and the Menu button have to share one row. */
@media (max-width: 900px) {
  .nav-row { column-gap: 1rem; }
  .js .nav-toggle { margin-left: auto; }
}
@media (max-width: 480px) {
  .mark { width: 34px; }
  .lockup { gap: 0.6rem; }
  .wordmark { font-size: 1.04rem; }
}

/* Google Tag Manager's <noscript> iframe. Google's snippet hides it with a
   style attribute, which the CSP drops, so the class does it instead. */
.gtm-ns { display: none; visibility: hidden; }
