/* =========================================================
   Components and sections. Mobile first; each block carries
   its own wider-screen rules directly underneath it, so a
   component is read in one place.

   Breakpoints: 40em (large phone), 48em (tablet),
   64em (laptop), 80em (desktop).
   ========================================================= */

/* ═══════════════════════════ PRIMITIVES ═══════════════════════════ */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-left: max(var(--gutter), env(safe-area-inset-left));
  padding-right: max(var(--gutter), env(safe-area-inset-right));
}

.container--narrow {
  max-width: var(--container-narrow);
}

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

.skip-link {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  background: var(--ink);
  color: var(--porcelain);
  font-weight: 700;
  text-decoration: none;
}

.skip-link:focus-visible {
  width: auto;
  height: auto;
  padding: 0.75rem 1.25rem;
  clip-path: none;
  outline-color: var(--sol);
  outline-offset: -4px;
}

/* ---------- The mark ---------- */

.mark {
  flex: none;
  overflow: visible;
}

.mark__face {
  fill: var(--mark-face, var(--porcelain));
  stroke: var(--mark-ink, var(--ink));
}

.mark__eye {
  fill: var(--mark-ink, var(--ink));
}

/* ---------- Icons ---------- */

.icon {
  flex: none;
  width: 1em;
  height: 1em;
  transition: transform 0.3s var(--ease);
}

/* ---------- Label ----------
   The eyebrow above a heading: tracked uppercase in the accent, and nothing
   else. No rule, no dash. An index, where a section has one, is a small key. */

.label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.label__index {
  display: inline-grid;
  place-items: center;
  min-width: 1.9rem;
  height: 1.9rem;
  padding-inline: 0.35rem;
  border: 2px solid var(--ink);
  border-radius: 8px;
  background: var(--accent-bright);
  box-shadow: 0 2px 0 0 var(--accent);
  color: var(--ink);
  font-size: var(--step--2);
  letter-spacing: 0.02em;
}

.heading--center .label {
  justify-content: center;
}

/* ---------- Section heading ---------- */

.heading {
  max-width: 48rem;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}

.heading--center {
  margin-inline: auto;
  text-align: center;
}

.heading__title {
  font-size: var(--step-4);
  font-weight: 700;
}

.heading__lead {
  max-width: 42rem;
  margin-top: 1rem;
  color: var(--ink-500);
  font-size: var(--step-1);
  line-height: 1.55;
}

.heading--center .heading__lead {
  margin-inline: auto;
}

/* ---------- Buttons ----------
   Printed labels. A solid fill with a 2px ink outline, standing on a hard
   diagonal ink offset. Hover lifts it up and left as the offset grows;
   pressing pushes it into the page and the offset disappears. `.is-pressed`
   is set by /js/play.js on pointerdown and on Enter or Space, because
   :active is unreliable on iOS and never fires for Enter on a link.

   The independent translate and scale properties, never `transform`, so the
   lift, the press and anything else compose instead of cancelling. */

.btn {
  --ledge: var(--ink);
  --ledge-y: 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 3rem;
  padding: 0.75rem 1.4rem;
  border: 2px solid var(--ink);
  border-radius: var(--radius-key);
  background: var(--white);
  color: var(--ink);
  box-shadow: var(--ledge-y) var(--ledge-y) 0 0 var(--ledge);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  translate: 0 0;
  scale: 1;
  transition:
    box-shadow 200ms var(--ease),
    translate 200ms var(--ease),
    scale 260ms var(--ease-spring),
    background-color 200ms var(--ease),
    color 200ms var(--ease);
}

.btn:hover {
  translate: -1px -1px;
  box-shadow: calc(var(--ledge-y) + 2px) calc(var(--ledge-y) + 2px) 0 0 var(--ledge);
}

.btn:active,
.btn.is-pressed {
  translate: 2px 2px;
  scale: 0.98;
  box-shadow: 0 0 0 0 var(--ledge);
  transition-duration: 80ms;
}

.btn .icon--arrow {
  transition: translate 280ms var(--ease-spring);
}

.btn:hover .icon--arrow {
  translate: 3px 0;
}

.btn:active .icon--arrow,
.btn.is-pressed .icon--arrow {
  translate: 6px 0;
}

.btn:focus-visible {
  outline-offset: 6px;
}

/* Variants change colours only. */
.btn--primary {
  background: var(--periwinkle-600);
  color: var(--white);
}

.btn--primary:hover {
  background: var(--periwinkle-700);
}

.btn--secondary {
  background: var(--white);
  color: var(--ink);
}

.btn--secondary:hover {
  background: var(--periwinkle-50);
}

.btn--sploit {
  background: var(--plum-300);
  color: var(--ink);
}

.btn--sploit:hover {
  background: var(--plum-200);
}

/* On the footer's colour. */
.btn--invert {
  --ledge: var(--periwinkle-900);
  border-color: var(--white);
  background: var(--white);
  color: var(--periwinkle-700);
}

/* The two keys in the hero, stacked and full width. */
.btn--block {
  width: 100%;
}

.btn--large {
  --ledge-y: 4px;
  min-height: 3.5rem;
  font-size: 1rem;
}

.btn--small {
  --ledge-y: 2px;
  min-height: 2.5rem;
  padding: 0.5rem 1rem;
  font-size: 0.8125rem;
}

.section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* ---------- Links ---------- */

.more {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.75rem;
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-weight: 600;
  text-decoration: none;
}

.more:hover {
  text-decoration: underline;
  text-decoration-thickness: 2px;
}

.more .icon--arrow {
  transition: translate 280ms var(--ease-spring);
}

.more:hover .icon--arrow {
  translate: 3px 0;
}

/* ---------- Tags ---------- */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.tag {
  padding: 0.2rem 0.65rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius-pill);
  background: var(--white);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  line-height: 1.5;
}

/* Direction, not a service: a ghost of a tag. */
.tag--future {
  border-color: var(--rule-mid);
  background: var(--ink-50);
  color: var(--text-3);
}

.tag--edu {
  border-color: var(--edu);
  background: var(--porcelain);
  color: var(--edu-ink);
}

.tags--large .tag {
  padding: 0.4rem 0.75rem;
  font-size: var(--step--1);
}

/* ---------- Check list ---------- */

.checks {
  display: grid;
  gap: 0.55rem;
}

.checks li {
  position: relative;
  padding-left: 1.75rem;
  color: var(--text-2);
}

.checks li::before {
  content: "";
  position: absolute;
  top: 0.42em;
  left: 0.2rem;
  width: 0.8rem;
  height: 0.45rem;
  border-bottom: 2.5px solid var(--accent);
  border-left: 2.5px solid var(--accent);
  transform: rotate(-45deg);
}

.checks--compact {
  gap: 0.3rem;
  margin-block: 0.75rem;
  font-size: var(--step--1);
}

/* ---------- Status ---------- */

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.status__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 0 3px rgb(63 122 90 / 0.15);
}

.status--warn .status__dot {
  background: var(--warn);
  box-shadow: 0 0 0 3px rgb(168 112 29 / 0.18);
}

.status--bad .status__dot {
  background: var(--bad);
}

.status--info .status__dot {
  background: var(--sol);
  box-shadow: 0 0 0 3px rgb(143 155 208 / 0.22);
}

/* ---------- Disclosure ---------- */

.disclosure {
  margin-top: 0.75rem;
}

.disclosure__summary {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 2.25rem;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}

.disclosure__summary::-webkit-details-marker {
  display: none;
}

.disclosure__summary:hover {
  color: var(--sol-ink);
}

.disclosure__icon {
  position: relative;
  width: 1.1rem;
  height: 1.1rem;
  border: 2px solid currentColor;
  border-radius: 6px;
}

.disclosure__icon::before,
.disclosure__icon::after {
  content: "";
  position: absolute;
  inset: calc(50% - 1px) 20% auto;
  height: 2px;
  background: currentColor;
  transition: transform 0.25s var(--ease);
}

.disclosure__icon::after {
  transform: rotate(90deg);
}

.disclosure[open] .disclosure__icon::after {
  transform: rotate(0deg);
}

.disclosure__body {
  padding: 0.75rem 0 0.25rem;
}

/* ---------- Skull illustrations ---------- */

.skull {
  margin: 0;
}

.skull__svg {
  width: 100%;
  max-width: 100%;
  height: auto;
}

.skull__caption {
  margin-top: 0.4rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  text-align: center;
}

/* The Skull's movement lives in motion.css. */

/* ═══════════════════════════ HEADER ═══════════════════════════ */

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  padding-top: env(safe-area-inset-top);
  background: var(--white);
}

/* Fills the band iOS paints behind its translucent status strip. */
.site-header::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: 100%;
  left: 0;
  height: 6rem;
  background: var(--white);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--ink);
  text-decoration: none;
}

/* The header lockup is the 30px mark alone, which is a 30px tap target. The
   padding grows it to a thumb's worth and the negative margin gives the space
   back, so nothing in the row moves. The footer lockup keeps its word and needs
   neither. */
.site-header .brand {
  margin: -0.45rem;
  padding: 0.45rem;
}

/* The header's mark is the animated Skull (the "brand" role), held to the
   glyph's box so the row does not move when it arrives. */
.brand .skull__svg {
  flex: none;
  width: 38px;
  height: auto;
}

.brand__word {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.005em;
  white-space: nowrap;
}

/* ---------- The pages (tabs below 64em) ----------
   One list at every width. Below 64em it leaves the header for the foot of
   the screen, docked under the thumb as an app's tabs: each destination's
   icon over its name, the current one marked. --dock is the room it takes,
   which the page, the assistant and anything stuck to the bottom keep clear.
   The header keeps the lockup and Contact. */

.nav__list {
  display: flex;
}

.nav__link {
  display: flex;
  align-items: center;
  color: var(--ink-500);
  font-family: var(--font-display);
  font-weight: 600;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

.nav__icon {
  flex: none;
}

@media (max-width: 63.99em) {
  :root {
    --tabs: 4rem;
    --dock: calc(var(--tabs) + env(safe-area-inset-bottom));
  }

  /* Keyboard focus and in-page links scroll clear of the tabs, too. */
  html {
    scroll-padding-bottom: calc(var(--dock) + 0.75rem);
  }

  body {
    padding-bottom: var(--dock);
  }

  .nav {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    border-top: 2px solid var(--ink);
    background: var(--white);
  }

  /* Away while reading down the page, back on the way up, with Safari's own
     toolbar (play.js, "The tabs follow Safari's toolbar"). Its full height
     and the rule on top, so nothing of it is left at the foot of the screen. */
  .nav {
    transition: transform 0.28s var(--ease);
  }

  .is-tabs-away .nav {
    transform: translateY(calc(100% + 2px));
  }

  /* The bar's white runs on below it, past the foot of the screen, so the
     strip iOS Safari tints its toolbar from never shows a sliver of the page
     between the two. */
  .nav::after {
    content: "";
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;
    height: 100vh;
    height: 100lvh;
    background: inherit;
  }

  .nav__list {
    height: var(--tabs);
    max-width: 36rem;
    margin-inline: auto;
  }

  .nav__list > li {
    flex: 1;
    min-width: 0;
  }

  .nav__link {
    flex-direction: column;
    justify-content: center;
    gap: 0.25rem;
    height: 100%;
    padding-inline: 0.15rem;
    font-size: 0.6875rem;
    letter-spacing: 0.02em;
    line-height: 1.1;
    text-align: center;
  }

  /* The icon sits on a pill that fills in for the current page, the way the
     site's buttons do: periwinkle with an ink edge. */
  .nav__icon {
    box-sizing: content-box;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0.2rem 1rem;
    border: 2px solid transparent;
    border-radius: var(--radius-pill);
    transition:
      background-color 160ms var(--ease),
      transform 0.3s var(--ease-spring);
  }

  /* The drawn icons (header.mjs): the Skull's own manner, a tint of the
     palette in an ink outline, each tab its own accent. */
  .nav__icon {
    overflow: visible;
    fill: none;
    stroke: var(--ink);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .nav__icon--services {
    --tab-fill: var(--rose-300);
  }

  .nav__icon--pricing {
    --tab-fill: var(--sunbeam-300);
  }

  .nav__icon--projects {
    --tab-fill: var(--mint-300);
  }

  .nav__icon--demos {
    --tab-fill: var(--aqua-200);
  }

  .ti-fill {
    fill: var(--tab-fill);
  }

  .ti-paper {
    fill: var(--white);
  }

  .ti-ink {
    fill: var(--ink);
    stroke: none;
  }

  .ti-faint {
    stroke-opacity: 0.45;
  }

  /* Each drawing's move: once when its page opens, and again on hover or a
     press. theme.css stills them all for reduced motion. */
  .ti-art {
    transform-box: view-box;
    transform-origin: 50% 90%;
  }

  .ti-art--swing {
    transform-origin: 69% 31%; /* the tag's hole */
  }

  .nav__link.is-current .ti-art--hop,
  .nav__link:active .ti-art--hop {
    animation: tab-hop 0.6s var(--ease-spring) both;
  }

  .nav__link.is-current .ti-art--swing,
  .nav__link:active .ti-art--swing {
    animation: tab-swing 0.9s var(--ease) both;
  }

  .nav__link.is-current .ti-art--wiggle,
  .nav__link:active .ti-art--wiggle {
    animation: tab-wiggle 0.6s var(--ease) both;
  }

  @media (hover: hover) {
    .nav__link:hover .ti-art--hop {
      animation: tab-hop 0.6s var(--ease-spring) both;
    }

    .nav__link:hover .ti-art--swing {
      animation: tab-swing 0.9s var(--ease) both;
    }

    .nav__link:hover .ti-art--wiggle {
      animation: tab-wiggle 0.6s var(--ease) both;
    }
  }

  @keyframes tab-hop {
    0%,
    100% {
      transform: none;
    }

    35% {
      transform: translateY(-3px) scale(1.06, 0.96);
    }

    60% {
      transform: translateY(0) scale(0.96, 1.04);
    }
  }

  @keyframes tab-swing {
    0%,
    100% {
      transform: none;
    }

    25% {
      transform: rotate(-14deg);
    }

    55% {
      transform: rotate(8deg);
    }

    80% {
      transform: rotate(-3deg);
    }
  }

  @keyframes tab-wiggle {
    0%,
    100% {
      transform: none;
    }

    20% {
      transform: rotate(-10deg);
    }

    45% {
      transform: rotate(8deg);
    }

    70% {
      transform: rotate(-4deg);
    }
  }

  /* The Skull's tab: the rigged head in the icon's box, a touch larger, since
     a filled face reads smaller than a line drawing of the same size. */
  .nav__icon--skull {
    display: grid;
    place-items: center;
  }

  .nav__icon--skull .skull__svg {
    width: 1.6rem;
    height: auto;
    overflow: visible;
  }

  .nav__link.is-current {
    color: var(--ink);
  }

  .nav__link.is-current .nav__icon {
    border-color: var(--ink);
    background: var(--periwinkle-300);
  }

  .nav__link:active .nav__icon {
    transform: scale(0.9);
  }

  .nav__link:focus-visible {
    outline-offset: -4px;
  }

  @media (max-width: 22em) {
    .nav__icon {
      padding-inline: 0.6rem;
    }
  }
}

@media (min-width: 64em) {
  .site-header__inner {
    gap: 2rem;
  }

  .nav {
    margin-left: auto;
  }

  .nav__list {
    gap: 1.75rem;
  }

  .nav__icon {
    display: none;
  }

  .nav__link {
    position: relative;
    padding-block: 1.4rem;
    font-size: 0.875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    transition: color 160ms var(--ease);
  }

  .nav__link:hover {
    color: var(--ink);
  }

  .nav__link::before {
    content: "";
    position: absolute;
    right: 0;
    bottom: 1rem;
    left: 0;
    height: 3px;
    border-radius: 3px;
    background: var(--periwinkle-300);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s var(--ease-spring);
  }

  .nav__link:hover::before,
  .nav__link:focus-visible::before,
  .nav__link.is-current::before {
    transform: scaleX(1);
  }

  .nav__link.is-current {
    color: var(--ink);
  }
}

@media print {
  .nav {
    display: none;
  }
}

/* ═══════════════════════════ SECTIONS ═══════════════════════════ */

.section {
  position: relative;
  padding-block: var(--section-space);
}

/* Every tone is the same white. The names stay because pages still say
   which surface they meant, and an operator reading a page module should not
   have to learn that the answer is always "white". */
.section--paper,
.section--porcelain,
.section--grid,
.section--periwinkle,
.section--edu,
.section--night {
  background: var(--white);
}

/* ═══════════════════════════ THE GROUND ═══════════════════════════

   The page ground follows the scroll. A section marked `data-ground` names
   the colour the page should be while it is being read; initGround in
   /js/play.js blends the body and the header from one to the next as each
   section comes up the screen, and adds `.is-grounded` to the root, which
   hands each marked section's white to the page. The colour is a pure
   function of the scroll position, so it reverses exactly and a fast scroll
   cannot leave it behind.

   This is configuration only. Without script, or under reduced motion,
   nothing below applies and every section is the white it always was. The
   top of every page is an implicit white stop, so the first paint is right.

     white       the page's own ground
     wash        the section's own accent class at -50 (a home row)
     periwinkle, plum, rose, sunbeam, aqua, mint, tangerine
                 that family's -50, for a section with no accent class of its
                 own; groundFor() in ui.mjs picks one from a section's tone.

   Every -700 ink and the ink-500 grey clear 4.5:1 on every -50. */
[data-ground] { --ground: var(--white); }
[data-ground="wash"] { --ground: var(--accent-wash); }
[data-ground="periwinkle"] { --ground: var(--periwinkle-50); }
[data-ground="plum"] { --ground: var(--plum-50); }
[data-ground="rose"] { --ground: var(--rose-50); }
[data-ground="sunbeam"] { --ground: var(--sunbeam-50); }
[data-ground="aqua"] { --ground: var(--aqua-50); }
[data-ground="mint"] { --ground: var(--mint-50); }
[data-ground="tangerine"] { --ground: var(--tangerine-50); }

.is-grounded [data-ground] { background-color: transparent; }

/* ═══════════════════════════ SPLIT LAYOUTS ═══════════════════════════ */

.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
}

.split__skull {
  width: min(100%, 15rem);
  margin-inline: auto;
}

.split__main > .heading:last-child {
  margin-bottom: 0;
}

.split__label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.split__label--sploit {
  margin-top: 1.5rem;
  margin-bottom: 0;
  --mark-face: var(--porcelain);
}

@media (min-width: 64em) {
  .split {
    grid-template-columns: 5fr 7fr;
    align-items: start;
  }

  .split--eng,
  .split--process,
  .split--stack {
    grid-template-columns: 7fr 5fr;
  }

  .split--about {
    grid-template-columns: 4fr 8fr;
    align-items: center;
  }

  .split--process .split__aside,
  .split--stack .split__aside {
    align-self: end;
  }

  .split__skull {
    margin-inline: 0;
  }

  .split--process .split__skull,
  .split--stack .split__skull,
  .split--net .split__skull {
    margin-inline: auto 0;
  }
}

/* ═══════════════════════════ CAPABILITIES ═══════════════════════════ */

.capabilities {
  display: grid;
  gap: 1rem;
}

.capability {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
  transition:
    transform 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}



.capability:focus-within {
  box-shadow: 6px 6px 0 var(--sol);
}

.capability__art {
  display: grid;
  place-items: center;
  min-height: 8.5rem;
  padding: 1rem;
  border-bottom: 2px solid var(--rule);
  background-color: var(--paper);
}

.capability__art .skull {
  width: 7.5rem;
}

@media (min-width: 64em) {
  .capability__art {
    min-height: 11rem;
  }

  .capability__art .skull {
    width: 9rem;
  }
}

.capability__text {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.25rem 1.25rem 1.4rem;
}

.capability__index {
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
}

.capability__title {
  font-size: var(--step-3);
}

/* The whole card is the link's hit area; the heading keeps the accessible name. */
.capability__link {
  text-decoration: none;
}

.capability__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.capability__link:focus-visible {
  outline: none;
}

.capability__link:focus-visible::after {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.capability__body {
  color: var(--text-2);
}

.capability__tags {
  margin-top: 0.25rem;
}

.capability__note {
  color: var(--text-2);
  font-size: var(--step--1);
}

.capability__note strong {
  color: var(--ink);
}

.capability__price {
  margin-top: 0.25rem;
}

.capability__more {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: auto;
  padding-top: 0.5rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.capability__more::after {
  content: "→";
  transition: transform 0.25s var(--ease);
}

.capability:hover .capability__more::after {
  transform: translateX(4px);
}

/* On a phone the art sits beside the text, so five categories scan in one or
   two screens instead of five. */
@media (max-width: 39.99em) {
  .capability {
    grid-template-rows: none;
    grid-template-columns: 5.5rem 1fr;
  }

  .capability__art {
    min-height: 0;
    padding: 0.5rem;
    border-right: 2px solid var(--rule);
    border-bottom: 0;
  }

  .capability__art .skull {
    width: 4.5rem;
  }

  .capability__text {
    gap: 0.4rem;
    padding: 1rem;
  }

  .capability__title {
    font-size: var(--step-2);
  }
}

@media (min-width: 40em) {
  .capabilities {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .capabilities {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 1.25rem;
  }

  .capability {
    grid-column: span 4;
  }

  .capability--wide {
    grid-column: span 6;
    grid-template-rows: none;
    grid-template-columns: 15rem 1fr;
  }

  .capability--wide .capability__art {
    border-right: 2px solid var(--rule);
    border-bottom: 0;
  }

  .capability--wide .capability__art .skull {
    width: 10rem;
  }
}

/* Demo cards in a row share their rows, so the tags, the note, the price and
   the closing link each sit on one line across the row instead of wherever a
   card's summary happened to end. Every card has all seven text rows. */
@media (min-width: 40em) {
  .demos-page .capabilities {
    row-gap: 0;
  }

  .demos-page .capability {
    grid-row: span 8;
    grid-template-rows: subgrid;
    row-gap: 0;
    margin-bottom: 1rem;
  }

  .demos-page .capability__text {
    display: grid;
    grid-row: 2 / -1;
    grid-template-rows: subgrid;
    row-gap: 0.6rem;
  }

  /* A row taller than its content leaves the content at the top of it, rather
     than stretching a card's tags into ovals to fill it. */
  .demos-page .capability__text > * {
    align-self: start;
  }
}

@media (min-width: 64em) {
  .demos-page .capability {
    grid-row: span 7;
    margin-bottom: 1.25rem;
  }

  .demos-page .capability__art,
  .demos-page .capability__text {
    grid-row: 1 / -1;
  }
}

.services-preview__more {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-top: 1.5rem;
  padding: 1rem 1.1rem;
  border-left: 3px solid var(--sol);
  background: var(--sol-tint);
}

.services-preview__more > p:first-child {
  max-width: 42rem;
  color: var(--text-2);
}

.services-preview__more .section-actions {
  margin-top: 0;
}

/* ═══════════════════════════ PROBLEMS ═══════════════════════════ */

.problems {
  display: grid;
  gap: 1.25rem 2rem;
}

.problem {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  grid-template-areas:
    "face quote"
    ". route";
  gap: 0.5rem 0.9rem;
  align-items: start;
}

.problem__face {
  grid-area: face;
  padding-top: 0.25rem;
}

.problem__quote {
  position: relative;
  grid-area: quote;
  padding: 0.9rem 1.1rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
}

/* The speech tail, pointing back at the Skull. Two triangles: the ink edge and
   the paper fill inside it. */
.problem__quote::before,
.problem__quote::after {
  content: "";
  position: absolute;
  top: 1.25rem;
  width: 0;
  height: 0;
  border-style: solid;
}

.problem__quote::before {
  left: -11px;
  border-width: 8px 11px 8px 0;
  border-color: transparent var(--ink) transparent transparent;
}

.problem__quote::after {
  left: -8px;
  border-width: 7px 9px 7px 0;
  margin-top: 1px;
  border-color: transparent var(--paper) transparent transparent;
}

.problem__quote p {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 500;
  line-height: 1.2;
}

.problem__quote p::before {
  content: "“";
}

.problem__quote p::after {
  content: "”";
}

.problem__route {
  grid-area: route;
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.04em;
}

.problem__route a {
  color: var(--sol-ink);
  font-weight: 500;
  text-decoration: none;
}

.problem__route a::before {
  content: "→ ";
}

.problem__route a:hover {
  text-decoration: underline;
}

@media (min-width: 48em) {
  .problems {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem 2.5rem;
  }

  /* The last two are the ones that route to a person; they read as the
     conversation's closing lines, so they sit apart. */
  .problem:nth-last-child(-n + 2) .problem__quote {
    background: var(--sol-tint);
  }

  .problem:nth-last-child(-n + 2) .problem__quote::after {
    border-right-color: var(--sol-tint);
  }
}

@media (min-width: 80em) {
  .problem {
    grid-template-columns: 5.25rem 1fr;
  }
}

/* ═══════════════════════════ SERVICE SCOPE & PRICES ═══════════════════════════ */

.service__note {
  margin-top: 0.75rem;
  padding-left: 0.9rem;
  border-left: 2px solid var(--sol);
  color: var(--text-2);
  font-size: var(--step--1);
}

.price {
  display: inline-block;
  padding: 0.3rem 0.6rem;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* A published price is a little key: bright fill on its ledge. */
.price--published {
  border-color: var(--ink);
  background: var(--sunbeam-300);
  box-shadow: 0 2px 0 0 var(--sunbeam-500);
  color: var(--ink);
  font-weight: 600;
}

/* ═══════════════════════════ DIAGRAMS ═══════════════════════════ */

.diagram {
  padding: clamp(1rem, 3vw, 1.75rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.diagram__caption {
  margin-bottom: 1.25rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.diagram__fig {
  margin-right: 0.5rem;
  padding: 0.1rem 0.4rem;
  border: 2px solid var(--rule);
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

/* ---------- Network: a column on phones, a row from tablet up ---------- */

.net {
  display: grid;
  gap: 1.5rem;
}

.net__stage {
  position: relative;
}

/* The wire between stages. */
.net__stage + .net__stage::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 1.25rem;
  width: 1.5px;
  height: 1.5rem;
  background: repeating-linear-gradient(to bottom, var(--ink) 0 4px, transparent 4px 7px);
}

.net__box {
  position: relative;
  display: grid;
  gap: 0.15rem;
  padding: 0.65rem 0.8rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
}

.net__box--muted {
  border-style: dashed;
  background: transparent;
}

.net__box--key {
  background: var(--sol-wash);
  box-shadow: 3px 3px 0 var(--ink);
}

.net__title {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
}

.net__detail {
  color: var(--text-2);
  font-size: var(--step--2);
  line-height: 1.4;
}

.net__badge {
  justify-self: start;
  margin-top: 0.3rem;
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--sol-ink);
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: 0.6875rem;
}

.net__branches {
  display: grid;
  gap: 0.6rem;
  padding-left: 1.25rem;
  border-left: 2px solid var(--rule);
}

.net__branch {
  position: relative;
}

.net__branch::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  width: 1.25rem;
  height: 1.5px;
  background: var(--ink);
}

@media (min-width: 48em) {
  .net {
    grid-template-columns: repeat(3, minmax(0, 0.8fr)) minmax(0, 1.4fr);
    align-items: center;
    gap: 1.25rem;
  }

  .net__stage + .net__stage::before {
    top: 50%;
    right: 100%;
    bottom: auto;
    left: auto;
    width: 1.25rem;
    height: 1.5px;
    background: repeating-linear-gradient(to right, var(--ink) 0 4px, transparent 4px 7px);
  }

  .net__stage--split::before {
    display: none;
  }

  .net__branches {
    padding-left: 1.25rem;
  }
}

/* ---------- Architecture: stacked layers ---------- */

.arch {
  display: grid;
  gap: 0.4rem;
}

.arch__layer {
  display: grid;
  gap: 0.4rem;
  padding: 0.6rem 0.75rem;
  border: 2px solid var(--rule);
  background: var(--paper);
}

.arch__layer--key {
  border: 2px solid var(--edge);
  background: var(--sol-wash);
}

.arch__name {
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.arch__parts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.arch__parts li {
  padding: 0.1rem 0.45rem;
  border: 2px solid var(--rule);
  background: var(--porcelain);
  font-size: var(--step--2);
}

@media (min-width: 40em) {
  .arch__layer {
    grid-template-columns: 6.5rem 1fr;
    align-items: center;
  }
}

.split__aside--eng {
  display: grid;
  gap: 1.5rem;
}

/* ═══════════════════════════ HEALTH CHECKUP ═══════════════════════════ */

.health {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

.health .heading__title em {
  color: var(--sol-ink);
}

.versus {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  margin-block: 0.5rem 1.5rem;
}

.versus__item {
  display: grid;
  justify-items: center;
  gap: 0.25rem;
}

.versus__item .skull {
  width: 7rem;
}

.versus__item figcaption {
  padding: 0.1rem 0.5rem;
  border: 2px solid var(--rule);
  background: var(--porcelain);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.versus__vs {
  align-self: center;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-style: italic;
}

.health__caveat,
.caveat {
  max-width: 40rem;
  padding-left: 0.9rem;
  border-left: 2px solid var(--sol);
  color: var(--text-2);
  font-size: var(--step--1);
}

.caveat {
  margin-top: 2rem;
}

/* The report: a printout on porcelain, with a torn top edge implied by a
   dashed rule, a header strip and rows like a form. */
.report {
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.report__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  padding: 0.9rem 1.1rem;
  border-bottom: 2px solid var(--rule);
}

.report__title {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
}

.report__meta {
  align-self: center;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.report__quarters {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 2px solid var(--rule);
}

.report__quarters li {
  padding: 0.5rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  text-align: center;
}

.report__quarters li + li {
  border-left: 2px solid var(--rule);
}

.report__quarters .is-now {
  background: var(--ink);
  color: var(--porcelain);
}

.report__row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "area state"
    "items items";
  gap: 0.25rem 1rem;
  padding: 0.8rem 1.1rem;
}

.report__row + .report__row {
  border-top: 2px solid var(--rule);
}

.report__area {
  grid-area: area;
  font-weight: 700;
}

.report__items {
  grid-area: items;
  color: var(--text-2);
  font-size: var(--step--1);
}

.report__state {
  grid-area: state;
}

@media (min-width: 64em) {
  .health {
    grid-template-columns: 5fr 6fr;
  }

  .report {
    transform: rotate(0.6deg);
  }
}

/* ═══════════════════════════ ENGINEERING ═══════════════════════════ */

.buildables {
  position: relative;
  display: grid;
  gap: 1.25rem;
  margin-top: clamp(2.5rem, 6vw, 4rem);
  padding: clamp(1.25rem, 3vw, 2rem);
  padding-bottom: 7rem;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
}

.buildables__title {
  font-size: var(--step-3);
}

.buildables__head p {
  max-width: 38rem;
  margin-top: 0.5rem;
  color: var(--text-2);
}

.buildables__skull {
  position: absolute;
  right: 1rem;
  bottom: 0.5rem;
  width: 6.5rem;
}

@media (min-width: 48em) {
  .buildables {
    grid-template-columns: 18rem 1fr;
    padding-bottom: clamp(1.25rem, 3vw, 2rem);
    padding-right: 9rem;
  }
}

/* ═══════════════════════════ CONSULTING ═══════════════════════════ */

/* The dividers are borders on the cells rather than a grey list showing
   through 1px gaps between white cells: the cells have no ground of their own,
   so the list reads the same on white and on a scrolled ground (see "The
   ground" above), and an odd last cell leaves no grey hole beside it. */
.minor-services {
  display: grid;
  margin-top: clamp(2rem, 4vw, 3rem);
  border-block: 2px solid var(--rule);
}

.minor-services li {
  padding: 1.25rem 0;
}

.minor-services li + li {
  border-top: 1px solid var(--rule-mid);
}

.minor-services h3 {
  font-size: var(--step-2);
}

.minor-services p {
  margin-top: 0.35rem;
  color: var(--text-2);
}

@media (min-width: 48em) {
  .minor-services,
  .minor-services--four,
  .minor-services--two {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .minor-services li {
    padding: 1.25rem 1.5rem 1.25rem 0;
  }

  .minor-services li:nth-child(even) {
    padding-left: 1.5rem;
    border-left: 1px solid var(--rule-mid);
  }

  .minor-services li + li { border-top: 0; }
  .minor-services li:nth-child(n + 3) { border-top: 1px solid var(--rule-mid); }
}

@media (min-width: 64em) {
  .minor-services--four {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .minor-services--four li,
  .minor-services--four li:nth-child(even) {
    padding: 1.25rem 1.25rem 1.25rem 0;
    border-left: 0;
  }

  .minor-services--four li + li {
    padding-left: 1.25rem;
    border-left: 1px solid var(--rule-mid);
  }

  .minor-services--four li:nth-child(4n + 1) { border-left: 0; }
  .minor-services--four li:nth-child(n + 3) { border-top: 0; }
  .minor-services--four li:nth-child(n + 5) { border-top: 1px solid var(--rule-mid); }
}

/* ═══════════════════════════ PROCESS ═══════════════════════════ */

.steps {
  display: grid;
  gap: 1.5rem 1.25rem;
  margin-top: clamp(1rem, 3vw, 2rem);
}

.step {
  padding-top: 0.9rem;
  border-top: 2px solid var(--ink);
}

.step__index {
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
}

.step__title {
  margin-block: 0.3rem 0.4rem;
  font-size: var(--step-2);
}

.step__body {
  color: var(--text-2);
  font-size: var(--step--1);
}

@media (min-width: 40em) {
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .steps--five {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.scale {
  margin-top: clamp(2.5rem, 6vw, 4rem);
}

/* position: relative gives the visually-hidden labels in the cells a containing
   block inside the scroller. Without it they are positioned against the page,
   escape the overflow clip, and widen the whole layout viewport on phones. */
.table-wrap {
  position: relative;
  overflow-x: auto;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.table-wrap:focus-visible {
  outline-offset: 4px;
}

.scale__table {
  width: 100%;
  min-width: 46rem;
  font-size: var(--step--1);
}

.scale__table caption {
  padding: 0.9rem 1rem;
  border-bottom: 2px solid var(--rule);
  font-weight: 700;
  text-align: left;
}

.scale__table caption span {
  color: var(--text-3);
  font-weight: 400;
}

.scale__table th,
.scale__table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 2px solid var(--rule);
  text-align: center;
}

.scale__table thead th {
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  white-space: nowrap;
}

.scale__table thead th span {
  color: var(--sol-ink);
}

.scale__table th[scope="row"] {
  font-weight: 700;
  text-align: left;
  white-space: nowrap;
}

/* The job names stay put while the stages scroll past them, so a row can be
   read to its end on a phone. */
.scale__table th[scope="row"],
.scale__table thead th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--porcelain);
  box-shadow: 1px 0 0 var(--rule);
}

.scale__table tbody tr:last-child > * {
  border-bottom: 0;
}

.dot {
  display: inline-block;
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 50%;
  vertical-align: middle;
}

.dot--yes {
  background: var(--ink);
}

.dot--some {
  border: 2px solid var(--ink);
  background: linear-gradient(90deg, var(--ink) 50%, transparent 50%);
}

.dot--no {
  width: 0.6rem;
  height: 1.5px;
  border-radius: 0;
  background: var(--rule-mid);
}

.scale__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.scale__legend .dot {
  margin-left: 0.5rem;
}

/* ═══════════════════════════ STACK ═══════════════════════════ */

.stack {
  display: grid;
  gap: 1px;
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  border: 2px solid var(--edge);
  background: var(--rule-mid);
}

.stack__group {
  padding: 1.1rem 1.25rem 1.3rem;
  background: var(--porcelain);
}

.stack__label {
  margin-bottom: 0.75rem;
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 700;
}

.stack__label span {
  margin-right: 0.35rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
}

.stack .tag {
  background: var(--paper);
}

@media (min-width: 48em) {
  .stack {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .stack__group:last-child {
    grid-column: 1 / -1;
  }
}

@media (min-width: 64em) {
  .stack {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .stack__group:last-child {
    grid-column: auto;
  }
}

/* ═══════════════════════════ PROJECTS ═══════════════════════════ */

.projects {
  margin-top: clamp(1.75rem, 4vw, 3rem);
}

.project-card {
  display: grid;
  border: 2px solid var(--edge);
  background: var(--porcelain);
}

.project-card__main,
.project-card__scope {
  padding: clamp(1.35rem, 3vw, 2.25rem);
}

.project-card__status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  width: fit-content;
  margin-bottom: 1.5rem;
  padding: 0.3rem 0.65rem;
  border: 1px solid var(--warn);
  background: color-mix(in srgb, var(--warn) 9%, var(--porcelain));
  color: #70480f;
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.project-card__status span {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--warn);
}

.project-card__type {
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.project-card__title {
  margin-top: 0.2rem;
  font-size: var(--step-4);
}

.project-card__summary {
  max-width: 42rem;
  margin-top: 0.75rem;
  color: var(--text-2);
  font-size: var(--step-1);
}

.project-card__stack {
  margin-top: 1.25rem;
}

.project-card__scope {
  border-top: 2px solid var(--rule);
  background: var(--paper);
}

.project-card__scope h4 {
  margin-bottom: 1rem;
  font-family: var(--font-body);
  font-size: var(--step-0);
}

.project-card__note {
  margin-top: 1.25rem;
  padding: 0.9rem 1rem;
  background: var(--sol-tint);
  color: var(--text-2);
  font-size: var(--step--1);
}

.project-card__art {
  display: grid;
  place-items: center;
  min-height: 12rem;
  padding: 1.5rem;
  border-top: 2px solid var(--rule);
  background-color: var(--porcelain);
}

@media (min-width: 58em) {
  .project-card {
    grid-template-columns: minmax(0, 1.2fr) minmax(18rem, 0.9fr) 13rem;
  }

  .project-card__scope,
  .project-card__art {
    border-top: 0;
    border-left: 2px solid var(--rule);
  }
}

/* ═══════════════════════════ ABOUT ═══════════════════════════ */

.principles {
  display: grid;
  gap: 1.25rem 2rem;
}

.principles li {
  padding-top: 0.9rem;
  border-top: 2px solid var(--rule);
}

.principles h3 {
  font-size: var(--step-2);
}

.principles p {
  margin-top: 0.35rem;
  color: var(--text-2);
}

.principles__index {
  display: block;
  margin-bottom: 0.3rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

@media (min-width: 64em) {
  .principles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .principles--numbered {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.people {
  display: grid;
  gap: 1.25rem;
}

.person {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 1.25rem;
  border: 2px solid var(--edge);
  background: var(--porcelain);
}

.person__name {
  font-size: var(--step-3);
}

.person__role {
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.person__background {
  margin-top: 0.6rem;
  color: var(--text-2);
}

.person > .more {
  margin-top: auto;
  padding-top: 0.75rem;
}

@media (min-width: 48em) {
  .people {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.prose {
  max-width: 40rem;
  display: grid;
  gap: 1rem;
  color: var(--text-2);
  font-size: var(--step-1);
  line-height: 1.65;
}

.prose a {
  color: var(--sol-ink);
}

.prose-split {
  display: grid;
  gap: 1rem 4rem;
}

@media (min-width: 64em) {
  .prose-split {
    grid-template-columns: 5fr 7fr;
  }
}

.subheading {
  margin-block: 1.5rem 0.75rem;
  font-size: var(--step-2);
}

/* ---------- Topics (cyber-safety, vibe code scope) ---------- */

.topics {
  display: grid;
  gap: 1px;
  border: 2px solid var(--edge);
  background: var(--rule-mid);
}

.topic {
  display: grid;
  align-content: start;
  gap: 0.3rem;
  padding: 1.1rem 1.25rem;
  background: var(--porcelain);
}

.topic__index {
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.topic__title {
  font-size: var(--step-2);
}

.topic__body {
  color: var(--text-2);
  font-size: var(--step--1);
}

@media (min-width: 40em) {
  .topics {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .topics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ═══════════════════════════ CONTACT ═══════════════════════════ */

.contact {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
}

.contact__intro {
  position: relative;
}

.contact__address {
  margin-top: 2rem;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.1;
}

.contact__address a {
  text-decoration-color: var(--sol);
  text-decoration-thickness: 2px;
}

/* Three enquiry types cabled to one team (the "merge" rig). */
.contact__rig {
  width: min(100%, 24rem);
  margin-top: 2rem;
}

.enquiries {
  display: grid;
  gap: 1rem;
  align-content: start;
}

.enquiry {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 1rem;
  padding: 1.25rem 1.4rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.enquiry__index {
  grid-row: 1 / 4;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--1);
}

.enquiry__title {
  font-size: var(--step-3);
}

.enquiry__body {
  color: var(--text-2);
}

.enquiry__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  justify-self: start;
  margin-top: 0.5rem;
  font-weight: 700;
  text-decoration-color: var(--sol);
  text-decoration-thickness: 2px;
}

.enquiry__link::after {
  content: "→";
}

/* The whole card opens the mail link. */
.enquiry__link::before {
  content: "";
  position: absolute;
  inset: 0;
}

@media (min-width: 64em) {
  .contact {
    grid-template-columns: 6fr 5fr;
  }

}

.contact-address {
  margin-top: 1.25rem;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.contact-address a {
  text-decoration-color: var(--sol);
  text-decoration-thickness: 2px;
}

/* ---------- The assistant hand-off line ---------- */

.ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-top: 2rem;
  color: var(--text-2);
}

.ask[hidden] {
  display: none;
}

.ask__button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.5rem;
  padding: 0.4rem 0.9rem;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--porcelain);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.ask__button:hover {
  box-shadow: 3px 3px 0 var(--ink);
}

/* The panel version: the end of a page, where the assistant is offered with
   starter questions rather than a single button. */
.ask--panel {
  position: relative;
  display: block;
  margin-top: 0;
  padding: clamp(1.25rem, 3vw, 1.75rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.ask__title {
  font-size: var(--step-3);
}

.ask__title em {
  color: var(--sol-ink);
}

.ask--panel .ask__lead {
  display: block;
  max-width: 24rem;
  margin-top: 0.5rem;
}

.ask__questions {
  display: grid;
  gap: 0.6rem;
  justify-items: start;
  margin-top: 1.25rem;
}

.ask__questions .ask__button {
  text-align: start;
  font-weight: 600;
}

/* On a phone the text needs the whole card, so the Skull sits on its top
   edge instead of beside the questions, looking over the card's corner. */
.ask__skull {
  position: absolute;
  right: 1rem;
  bottom: 100%;
  width: 4.5rem;
  margin-bottom: -1rem;
}

@media (max-width: 47.99em) {
  .contact-section .ask--panel {
    margin-top: 1.5rem;
  }
}

@media (min-width: 48em) {
  .ask--panel {
    padding-right: 9rem;
  }

  .ask__skull {
    bottom: 1rem;
    width: 7rem;
    margin-bottom: 0;
  }
}

/* ═══════════════════════════ PAGE HEAD ═══════════════════════════ */

/* The top of every inner page: on white, with no rule under it. The Skull
   doing that page's job floats beside the title, on nothing. */
.page-head {
  position: relative;
  padding-block: clamp(2rem, 5vw, 4rem) clamp(1.5rem, 4vw, 3rem);
}

.page-head__inner {
  position: relative;
  display: grid;
  gap: 2rem;
  align-items: center;
}

.page-head__title {
  font-size: var(--step-5);
  line-height: 1.04;
  letter-spacing: -0.02em;
}

.page-head__title em {
  color: var(--periwinkle-700);
}

.page-head__lead {
  max-width: 40rem;
  margin-top: 1.25rem;
  color: var(--ink-500);
  font-size: var(--step-1);
}

.page-head__meta {
  margin-top: 1rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.page-head__price {
  margin-top: 1.25rem;
}

.page-head__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: 1.75rem;
}

.page-head__art .skull {
  width: min(60vw, 16rem);
  margin-inline: auto;
}

.page-head--center {
  text-align: center;
}

.page-head--center .label,
.page-head--center .page-head__actions {
  justify-content: center;
}

.page-head--center .page-head__lead {
  margin-inline: auto;
}

.not-found__skull {
  width: 14rem;
  margin: 0 auto 1rem;
}

@media (min-width: 64em) {
  .page-head__inner {
    grid-template-columns: minmax(0, 1fr) 18rem;
  }

  .page-head__title {
    font-size: var(--step-5);
  }
}

/* Centred, because the links carry tap-target padding the current page does not. */
.trail ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 1.25rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.trail li + li::before {
  content: "/";
  margin-inline: 0.5rem;
  color: var(--rule-mid);
}

.trail a {
  display: inline-block;
  padding-block: 0.3rem;
  color: var(--text-2);
  text-decoration: none;
}

.trail a:hover {
  text-decoration: underline;
}

.page-toc ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 1.25rem;
  margin-top: 2.5rem;
  font-family: var(--font-display);
  font-size: var(--step--1);
}

/* The footer, the sea and the surfer are in play.css. */

/* ═══════════════════════════ CATALOGUE PAGES ═══════════════════════════ */

.capability__count {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.service-grid,
.category-audience,
.related-categories,
.service-directory {
  display: grid;
  gap: 1.25rem;
}

/* Cards in a row are one height, and their closing links sit on one baseline.
   Left to themselves they ended wherever their copy did, which made two cards
   describing equally real services look like one mattered less than the other. */
.service-card {
  display: grid;
  align-content: start;
  min-width: 0;
  padding: clamp(1rem, 2.5vw, 1.75rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
}

.service-card__links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.75rem;
}

.service-card:target {
  outline: 3px solid var(--sol-ink);
  outline-offset: 4px;
}

.service-card__head {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  gap: 0.75rem;
  align-items: center;
}

.service-card h3,
.category-audience h3,
.service-directory h3 {
  font-size: var(--step-2);
}

.service-card__summary,
.category-audience p,
.related-categories p {
  margin-top: 0.75rem;
  color: var(--text-2);
}

.service-card__price {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
}

.service-card__price > span:not(.price) {
  color: var(--text-3);
  font-size: var(--step--2);
}

/* Spacing between the closing links is the block's own gap. */
.service-card__links .more {
  margin-top: 0;
}

.service-card .disclosure__summary,
.service-finder > summary,
.problem-finder > summary,
.related-categories a,
.related-service-links a,
.service-directory a {
  min-height: 44px;
}

.category-audience li,
.related-categories li {
  min-width: 0;
  border-top: 2px solid var(--rule);
  padding-top: 1rem;
}

.related-categories a {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.15;
  letter-spacing: normal;
  text-transform: none;
}

.service-finder {
  margin-top: 2rem;
}

.service-directory ul {
  margin-top: 0.75rem;
}

.service-directory a {
  padding-block: 0.5rem;
  font-family: var(--font-body);
  font-size: var(--step--1);
  letter-spacing: normal;
  text-transform: none;
}

.related-service-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 1.5rem;
}

.related-service-links a {
  display: inline-flex;
  align-items: center;
}

.service-category .page-head__text,
.services-hub .page-head__text,
.capability__text {
  min-width: 0;
  overflow-wrap: break-word;
}

.service-category .trail li,
.services-hub .trail li {
  max-width: 100%;
}

.service-category .trail a,
.services-hub .trail a {
  display: inline-block;
  padding-block: 0.5rem;
}

@media (min-width: 48em) {
  .service-directory {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Side by side, each card hands its five rows back to the grid the cards
     share, so the summaries, the price chips, the scope line and the closing
     links each sit at one height across the pair — however many lines either
     card's copy runs to. The row gap goes to nothing (it would open inside the
     cards as well as between them) and the separation between rows of cards
     becomes the cards' own bottom margin. */
  .service-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 0;
  }

  .service-card {
    grid-row: span 5;
    grid-template-rows: subgrid;
    margin-bottom: 1.25rem;
  }

  .category-audience,
  .related-categories {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2rem;
  }

  .service-category .page-head__inner,
  .services-hub .page-head__inner {
    grid-template-columns: minmax(0, 1fr) 12rem;
  }
}

@media (min-width: 64em) {
  .capabilities--directory .capability--wide {
    grid-template-columns: 11rem minmax(0, 1fr);
  }

  .service-category .page-head__inner,
  .services-hub .page-head__inner {
    grid-template-columns: minmax(0, 1fr) 18rem;
  }

  .service-directory {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 47.99em) {
  .service-category .page-head__art .skull,
  .services-hub .page-head__art .skull {
    width: 8rem;
    margin-left: auto;
    margin-right: 0;
  }
}

/* ═══════════════════════════ MOBILE HORIZONTAL LISTS ═══════════════════════════
   Selected previews and supplementary choices scroll sideways on phones. Core
   catalogues stay vertical so services and contact options are never hidden. */

.scroll-hint {
  display: none;
}

@media (max-width: 47.99em) {
  .scroll-hint {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.45rem;
    margin: -1rem 0 0.75rem;
    color: var(--text-3);
    font-family: var(--font-display);
    font-size: var(--step--2);
  }

  /* Let the question carousel scroll inside its card instead of making the
     contact grid (and the entire home page) as wide as all its questions. */
  .page-home .contact {
    grid-template-columns: minmax(0, 1fr);
  }

  .scroll-hint span {
    color: var(--sol-ink);
    font-size: var(--step--1);
  }

  .mobile-snap {
    --snap-size: clamp(17rem, 84vw, 22rem);
    position: relative;
    /* The off-screen cards must not contribute to the document's width.
       Keep positioned descendants and swipe momentum inside this scroller. */
    contain: inline-size;
    min-width: 0;
    display: grid;
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: var(--snap-size);
    align-items: stretch;
    gap: 1rem;
    max-width: 100%;
    padding-bottom: 0.75rem;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-inline: contain;
    overscroll-behavior-block: auto;
    scroll-snap-type: inline mandatory;
    touch-action: pan-x pan-y;
    scrollbar-color: var(--sol) transparent;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
  }

  .mobile-snap > * {
    scroll-snap-align: start;
  }

  .mobile-snap::-webkit-scrollbar {
    height: 0.35rem;
  }

  .mobile-snap::-webkit-scrollbar-thumb {
    border-radius: var(--radius-pill);
    background: var(--sol);
  }

  /* Keep the home preview short as well as sideways: art and copy share a row. */
  .page-home .capabilities.mobile-snap .capability {
    grid-template-rows: none;
    grid-template-columns: 5.5rem minmax(0, 1fr);
  }

  .page-home .capabilities.mobile-snap .capability__art {
    min-height: 0;
    padding: 0.5rem;
    border-right: 2px solid var(--rule);
    border-bottom: 0;
  }

  .page-home .capabilities.mobile-snap .capability__art .skull {
    width: 4.5rem;
  }

  .page-home .capabilities.mobile-snap .capability__text {
    gap: 0.4rem;
    padding: 1rem;
  }

  .page-home .capabilities.mobile-snap .capability__title {
    font-size: var(--step-2);
  }

  .family-cards.mobile-snap {
    --snap-size: clamp(17rem, 86vw, 23rem);
  }

  .related-categories.mobile-snap {
    --snap-size: clamp(15rem, 76vw, 19rem);
  }

  .related-categories.mobile-snap > li {
    padding: 1rem;
    border: 2px solid var(--edge);
    background: var(--porcelain);
  }

}

@media (min-width: 48em) and (max-width: 63.99em) {
  .page-home .capabilities {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* A third of a tablet is too narrow for "Infrastructure" at step-3, and
     break-word would split it mid-word. One step down, hyphenated if still
     needed, keeps whole words. */
  .page-home .capability__title {
    font-size: var(--step-2);
    hyphens: auto;
  }
}

/* ═══════════════════════════ PRICING ═══════════════════════════

   /pricing is the one page where the numbers are the content, so the
   typographic job is to keep two kinds of number apart at a glance: what you
   pay once, and what you pay every month. Nothing distinguishes them by colour
   alone — a recurring amount carries its own label, a dashed frame and the
   interval in the figure itself.

   Mobile first throughout. The estimate builder stacks into one column with a
   sticky total that rides along inside the section, and only becomes two
   columns with a pinned summary at the laptop breakpoint. */

/* ---------- A price, with how often you pay it ---------- */

.pricebox {
  display: grid;
  gap: 0.15rem;
  padding: 0.6rem 0.8rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.pricebox__label {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pricebox__value {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

/* Recurring money is framed rather than filled, so a monthly figure never
   reads as the price of the project. */
.pricebox--recurring {
  border-style: dashed;
  background: var(--sol-tint);
}

.pricebox--recurring .pricebox__value {
  font-size: var(--step-1);
}

/* The same distinction on the service cards under /services. */
.price-recurring {
  padding: 0.25rem 0.5rem;
  border: 1px dashed var(--rule-mid);
  border-radius: var(--radius);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

/* ---------- Published builds ---------- */

/* Each card is a price and a door: the name, the thing in one line, the two
   numbers. Everything else is on the offering's own page, which is what keeps
   a card the height of its own content instead of the height of the longest
   piece of copy in the row. The grid packs whatever fits rather than holding a
   fixed column count, so eight of them never leave a hole in the last row. */
.offers {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15.5rem), 1fr));
}

.offer {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 1.1rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
  transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}



.offer:target {
  outline: 3px solid var(--sol-ink);
  outline-offset: 4px;
}

.offer__head {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
}

.offer__name {
  font-size: var(--step-1);
  line-height: 1.15;
}

/* The whole card is the link's hit area; the heading keeps the accessible name. */
.offer__link {
  text-decoration: none;
}

.offer__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.offer__link:focus-visible {
  outline: none;
}

.offer__link:focus-visible::after {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.offer__tagline {
  margin-top: 0.6rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* Two figures on two lines, because a one-time price and a monthly one sharing
   a row is exactly the confusion this page exists to avoid. */
.offer__prices {
  margin-top: auto;
  padding-top: 0.9rem;
  border-top: 2px solid var(--edge);
}

/* Label above figure, always, even where the two would fit on one line. A row
   that sets itself on one line in one card and wraps to two in the next gives
   every card a different height, which puts the rule above the prices at a
   different place in each — and a row of cards whose rules do not line up
   reads as a mistake before it reads as a price. */
.offer__price {
  padding-top: 0.55rem;
}

/* The browser indents a <dd> by default, which would set every figure in from
   the label above it. */
.offer__price dd {
  margin-inline-start: 0;
}

.offer__price dt {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.offer__price-value {
  margin-top: 0.1rem;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

/* Recurring money is set smaller and in mono, so the figure a project costs
   and the figure it costs every month can never be read as the same kind. */
.offer__price--recurring dd {
  margin-top: 0.15rem;
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  white-space: nowrap;
}

.offer__more {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding-top: 1rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.offer__more::after {
  content: "→";
  transition: transform 0.25s var(--ease);
}

.offer:hover .offer__more::after {
  transform: translateX(4px);
}

.offer__note,
.deploy__note,
.third-party__note {
  margin-top: 0.9rem;
  padding-left: 0.9rem;
  border-left: 2px solid var(--rule-mid);
  color: var(--text-3);
  font-size: var(--step--1);
}

/* ---------- What moves a range ---------- */

.ladder__ends {
  display: grid;
  gap: 0.5rem;
  padding: 0.9rem;
  border: 1px dashed var(--rule-mid);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.ladder__price {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
}

.ladder__end--high .ladder__price {
  color: var(--sol-ink);
}

.ladder__body {
  color: var(--text-2);
  font-size: var(--step--1);
}

.ladder__arrow {
  color: var(--sol-ink);
  font-size: var(--step-1);
  line-height: 1;
}

.ladder__lead {
  margin-top: 0.9rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ladder__moves {
  margin-top: 0.5rem;
  font-size: var(--step--1);
}

/* ---------- One offering, written up in full ---------- */

/* The two figures, side by side at the top of the page they belong to. */
.offer-detail__prices {
  display: grid;
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

/* The ladder is prose next to two numbers, so it is set to a reading measure
   rather than stretched across a desktop container. */
.offer-detail .ladder,
.offer-detail .caveat,
.offer-detail .offer__note {
  max-width: 44rem;
}

.offer-scope__cols {
  display: grid;
  gap: 1.5rem;
  margin-top: 1.5rem;
}

.offer-scope__heading {
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 0.75rem;
}

.offer-scope__col--not .crosses {
  color: var(--text-2);
}

.offer-scope__aside {
  padding: 1.1rem;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.offer-scope__skull {
  margin-bottom: 0.75rem;
}

.offer-scope__audience .tag {
  font-size: var(--step--2);
}

.offer-scope__note {
  margin-top: 1.5rem;
}

/* Where to go instead. A row of names and their prices, so leaving this page
   for a more honest one is a single click rather than a trip back through the
   catalogue. */
.offer-siblings {
  display: grid;
  gap: 0;
  margin: 1rem 0 1.5rem;
  border-top: 2px solid var(--edge);
}

.offer-siblings__item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.7rem 0;
  border-bottom: 2px solid var(--edge);
}

.offer-siblings__link {
  min-height: 44px;
  display: flex;
  align-items: center;
}

.offer-siblings__price {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--1);
}

.offer-next__heading {
  margin-top: 2rem;
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

@media (min-width: 48em) {
  .offer-detail__prices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 42rem;
  }

  .offer-scope__cols {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.8fr);
    gap: 2rem;
  }

  .offer-siblings {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 2rem;
  }
}

/* ---------- The estimate builder ---------- */

.builder {
  position: relative;
  margin-top: 2rem;
}

.builder__step {
  min-width: 0;
  margin: 0 0 1.5rem;
  padding: 1rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.builder__legend {
  padding: 0.3rem 0.8rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--periwinkle-300);
  box-shadow: 0 3px 0 0 var(--periwinkle-500);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.builder__step-index {
  color: var(--periwinkle-900);
}

.builder__hint,
.builder__group-body {
  margin-top: 0.6rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

.builder__group {
  margin-top: 1.5rem;
}

.builder__group-name {
  padding-bottom: 0.4rem;
  border-bottom: 2px solid var(--rule);
  font-size: var(--step-1);
}

.builder__notice {
  margin-top: 1rem;
  padding: 0.7rem 0.9rem;
  border-left: 3px solid var(--sol-ink);
  background: var(--sol-tint);
  color: var(--text-2);
  font-size: var(--step--1);
}

/* ---------- One choosable thing ---------- */

.options {
  display: grid;
  gap: 0.6rem;
  margin-top: 0.9rem;
}

.option {
  min-width: 0;
}

/* The control stays in the accessibility tree and in the tab order; the label
   is what you see and what you press. */
.option__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.option__label {
  display: grid;
  grid-template-columns: 1.3rem minmax(0, 1fr);
  gap: 0.2rem 0.7rem;
  min-height: 44px;
  padding: 0.7rem 0.8rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
  cursor: pointer;
  transition: border-color var(--t-micro, 150ms) var(--ease), background-color var(--t-micro, 150ms) var(--ease);
}

/* The box: square for a feature you can have several of, round for a choice
   between alternatives, the way the native controls read. */
.option__label::before {
  content: "";
  grid-row: 1 / span 3;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.15rem;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.option--type .option__label::before,
.option--deploy .option__label::before {
  border-radius: var(--radius-pill);
}

.option__name {
  grid-column: 2;
  font-weight: 700;
}

.option__body {
  grid-column: 2;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* The price sits on its own line, pushed to the right edge: the copy keeps the
   full width of the card, and the figures still line up into a column you can
   run your eye down. */
.option__price {
  grid-column: 2;
  justify-self: end;
  margin-top: 0.3rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.02em;
  text-align: right;
}

.option__state {
  grid-column: 2;
  margin-top: 0.35rem;
  padding-left: 2rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.option__label:hover {
  border-color: var(--ink);
}

.option__input:focus-visible + .option__label {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Selected: a filled box with a tick, a solid border and a tinted ground.
   Three signals, none of them colour on its own. */
.option__input:checked + .option__label {
  border-color: var(--ink);
  background: var(--sol-tint);
}

.option__input:checked + .option__label::before {
  border-color: var(--ink);
  background: var(--ink);
  background-image: linear-gradient(45deg, transparent 42%, var(--porcelain) 42%, var(--porcelain) 58%, transparent 58%),
    linear-gradient(-45deg, transparent 42%, var(--porcelain) 42%, var(--porcelain) 58%, transparent 58%);
  background-position: -0.1rem 0.1rem, 0.1rem 0.1rem;
  background-size: 60% 60%, 60% 60%;
  background-repeat: no-repeat;
}

.option__input:disabled + .option__label {
  cursor: default;
}

/* Already in the base price: ticked, but not charged for again. */
.option--included .option__label {
  border-style: dashed;
}

.option--included .option__price {
  text-decoration: line-through;
}

/* Does not belong in this kind of project: struck out, with the reason under it. */
.option--unavailable .option__label {
  border-color: var(--rule);
  background: transparent;
  opacity: 0.65;
}

.option--unavailable .option__name {
  text-decoration: line-through;
}

.option--unavailable .option__state {
  color: var(--text-3);
}

/* ---------- The summary ---------- */

.builder__panel {
  padding: clamp(1rem, 3vw, 1.4rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
  box-shadow: none;
}

.builder__panel-head {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 0.6rem;
  border-bottom: 2px solid var(--rule);
}

.builder__panel-title {
  font-size: var(--step-2);
}

.builder__skull {
  flex: none;
}

.builder__fallback {
  margin-top: 0.9rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* Stated in the markup as well as in the live panel, so the page never shows a
   figure without it — including with the script blocked. */
.builder__disclaimer {
  margin-top: 0.9rem;
  color: var(--text-3);
  font-size: var(--step--2);
}

.estimate__empty {
  margin-top: 0.9rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

.estimate__subhead {
  margin-top: 1rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.estimate__items {
  display: grid;
  gap: 0.35rem;
  margin: 0.5rem 0 1rem;
  padding: 0;
  list-style: none;
}

.estimate__item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.6rem;
  align-items: baseline;
  font-size: var(--step--1);
}

.estimate__item-name {
  flex: 1 1 auto;
  min-width: 0;
}

.estimate__item-price,
.estimate__item-note {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.estimate__item--type {
  padding-bottom: 0.35rem;
  border-bottom: 1px dashed var(--rule-mid);
  font-weight: 700;
}

.estimate__item--included {
  display: block;
  color: var(--text-3);
  font-size: var(--step--2);
}

.estimate__remove {
  flex: none;
  min-height: 32px;
  padding: 0.1rem 0.5rem;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  cursor: pointer;
}

.estimate__remove:hover {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--porcelain);
}

.estimate__rows {
  display: grid;
  gap: 0.1rem;
  margin-top: 1rem;
  padding: 0;
  list-style: none;
}

.estimate__row {
  display: flex;
  gap: 0.75rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.45rem 0;
  border-bottom: 1px dotted var(--rule-mid);
}

.estimate__label {
  color: var(--text-2);
  font-size: var(--step--1);
}

.estimate__value {
  flex: none;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  text-align: right;
}

/* The total gets its own two lines rather than squeezing a three-word label
   against a five-figure number in a column this narrow. */
.estimate__row--total {
  display: grid;
  gap: 0.1rem;
  margin-top: 0.4rem;
  padding-top: 0.7rem;
  border-top: 2px solid var(--rule);
  border-bottom: none;
}

.estimate__row--total .estimate__value {
  text-align: left;
}

.estimate__row--total .estimate__label {
  color: var(--ink);
  font-weight: 700;
}

.estimate__row--total .estimate__value {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
}

/* Recurring is framed and labelled, never just a second number in the list. */
.estimate__row--recurring {
  margin-top: 0.5rem;
  padding: 0.5rem 0.6rem;
  border: 1px dashed var(--rule-mid);
  border-radius: var(--radius);
  background: var(--sol-tint);
}

.estimate__row--recurring .estimate__label {
  font-weight: 700;
}

.estimate__row--separate {
  border-bottom: none;
  padding: 0.15rem 0;
}

.estimate__row--separate .estimate__label,
.estimate__row--separate .estimate__value {
  color: var(--text-3);
  font-size: var(--step--2);
}

.estimate__note,
.estimate__warning {
  margin-top: 0.8rem;
  padding-left: 0.8rem;
  border-left: 2px solid var(--sol);
  color: var(--text-2);
  font-size: var(--step--1);
}

.estimate__warning {
  border-left-color: var(--warn);
}

.estimate__disclaimer {
  margin-top: 0.9rem;
  color: var(--text-3);
  font-size: var(--step--2);
}

/* ---------- Sending it ---------- */

.builder__quote {
  margin-top: 1.2rem;
  padding-top: 1rem;
  border-top: 2px solid var(--rule);
}

.builder__quote-title {
  font-size: var(--step-1);
}

.builder__privacy,
.builder__note {
  margin-top: 0.4rem;
  color: var(--text-3);
  font-size: var(--step--2);
}

.field {
  margin-top: 0.8rem;
}

.field__label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: var(--step--1);
  font-weight: 700;
}

.field__optional {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.field__input {
  width: 100%;
  min-height: 44px;
  padding: 0.5rem 0.7rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
}

.field__input:focus-visible {
  border-color: var(--ink);
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.field__input--area {
  min-height: 5rem;
  resize: vertical;
}

.builder__actions {
  margin-top: 1rem;
}

/* ---------- The running total on a phone ---------- */

/* Sticky inside the builder rather than fixed to the window: the total rides
   along while you are choosing and scrolls away with the section, instead of
   sitting over the rest of the page. It clears the assistant's launcher, which
   is fixed to the same corner. */
.builder__bar {
  position: sticky;
  bottom: calc(3.75rem + max(var(--gutter), env(safe-area-inset-bottom)) + var(--dock, 0px));
  z-index: 6;
  display: flex;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
  margin-top: 1.5rem;
  padding: 0.6rem 0.75rem;
  border: 2px solid var(--ink);
  border-radius: var(--radius-key);
  background: var(--white);
  color: var(--ink);
  box-shadow: 3px 3px 0 0 var(--ink);
}

.builder__bar-total {
  min-width: 0;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
}

.builder__bar-label {
  display: block;
  color: var(--ink-500);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.builder__bar .btn {
  flex: none;
}

@media (min-width: 40em) {
  .option__state {
    padding-left: 0;
  }

  .options--types,
  .options--features {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .builder {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 23rem;
    gap: 2rem;
    align-items: start;
  }

  .builder__form {
    min-width: 0;
  }

  .builder__summary {
    position: sticky;
    top: calc(5.5rem + env(safe-area-inset-top));
    min-width: 0;
  }

  .builder__bar {
    display: none;
  }

  .builder__step {
    padding: 1.4rem;
  }
}

/* ---------- Existing projects ---------- */

.existing {
  display: grid;
  gap: 1.5rem;
}

.pipeline {
  display: grid;
  gap: 0;
  padding: 0;
  list-style: none;
  counter-reset: pipeline;
}

.pipeline__step {
  position: relative;
  padding: 0.9rem 0.9rem 0.9rem 3.2rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

/* The arrow between stages: the flow is the argument, so it is drawn rather
   than described. */
.pipeline__step + .pipeline__step {
  margin-top: 1.5rem;
}

.pipeline__step + .pipeline__step::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 1.6rem;
  width: 1.5px;
  height: 1.5rem;
  background: var(--ink);
}

.pipeline__step + .pipeline__step::after {
  content: "";
  position: absolute;
  bottom: calc(100% + 0.1rem);
  left: 1.25rem;
  border-top: 0.45rem solid var(--ink);
  border-right: 0.35rem solid transparent;
  border-left: 0.35rem solid transparent;
}

.pipeline__index {
  position: absolute;
  top: 0.9rem;
  left: 0.9rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.pipeline__name {
  font-size: var(--step-1);
}

.pipeline__body {
  margin-top: 0.25rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.existing__note {
  margin-top: 0.9rem;
  color: var(--text-2);
}

@media (min-width: 64em) {
  .existing {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 3rem;
  }

  .existing__aside {
    position: sticky;
    top: calc(6rem + env(safe-area-inset-top));
  }
}

/* ---------- Deployment ---------- */

.deploys,
.third-party {
  display: grid;
  gap: 1.25rem;
}

/* The third-party entries are rows of a list and keep their own heights; the
   two deployments are a comparison, so they are one height. */
.third-party {
  align-items: start;
}

.deploy {
  display: grid;
  align-content: start;
  min-width: 0;
  padding: clamp(1rem, 2.5vw, 1.6rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--paper);
}


.deploy__head {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
}

.deploy__name {
  font-size: var(--step-1);
  line-height: 1.15;
}

.deploy__platform {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.deploy__summary {
  margin: 0.9rem 0 0.75rem;
  color: var(--text-2);
}

/* What each one suits is the thing you are choosing between, so it is read
   rather than opened. Only the longer "what the work involves" list stays
   folded: it answers why the fee is what it is, not which one to pick. */
.deploy__suits {
  margin-bottom: 1rem;
}

.deploy__suits .tag {
  font-size: var(--step--2);
}

.deploy__infra {
  margin-top: 1rem;
  font-size: var(--step--1);
  color: var(--text-2);
}

.deploy__infra-label {
  display: block;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Side by side, the two are a comparison, and a comparison whose rows do not
   line up is harder to read than a list. Each card hands its own rows back to
   the section's grid, so the summaries, the tags, the fee, the platform
   charges and the disclosure each sit at one height across both — whatever
   length of copy any of them happens to carry. */
@media (min-width: 48em) {
  .deploys {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(8, auto);
    row-gap: 0;
  }

  .deploy {
    grid-row: span 8;
    grid-template-rows: subgrid;
    align-content: start;
  }

  /* Subgrid does the distributing; nothing needs pushing to the bottom. */
  .deploy .disclosure {
    margin-top: 0;
  }
}

/* ---------- Websites, as three sizes ---------- */

/* Three cards that are read across rather than down, so they hand their rows
   to the grid: label, price, line, inclusions, monthly, link. A tier whose
   list runs a line longer must not drag its price out of line with the others. */
.tiers {
  display: grid;
  gap: 1.25rem;
  margin-top: 2rem;
}

.tier {
  display: grid;
  align-content: start;
  min-width: 0;
  padding: 1.25rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.tier__head {
  padding-bottom: 0.75rem;
  border-bottom: 2px solid var(--rule);
}

.tier__label {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.tier__price {
  margin-top: 0.2rem;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.tier__body {
  margin-top: 0.75rem;
  color: var(--text-2);
  font-style: italic;
}

.tier__includes {
  margin-top: 0.9rem;
  font-size: var(--step--1);
}

.tier__monthly {
  margin-top: 0.9rem;
  padding: 0.3rem 0.6rem;
  justify-self: start;
  border: 1px dashed var(--rule-mid);
  border-radius: var(--radius);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.tier__more {
  margin-top: 0.9rem;
}

@media (min-width: 48em) {
  .tiers {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: repeat(6, auto);
    row-gap: 0;
  }

  .tier {
    grid-row: span 6;
    grid-template-rows: subgrid;
  }
}

/* ---------- How a price is reached ---------- */

/* The public shape of the model: five steps and the things that move a number.
   Deliberately the same furniture as the existing-software pipeline, because
   it is the same kind of claim — here is the sequence, in order, with nothing
   left out between two of the steps. */
.method {
  display: grid;
  gap: 2rem;
  margin-top: 2rem;
}

.method__steps {
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.method__step {
  min-width: 0;
  padding: 0.9rem 0.9rem 0.9rem 3.2rem;
  position: relative;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.method__index {
  position: absolute;
  top: 0.9rem;
  left: 0.9rem;
  color: var(--sol-ink);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.method__name {
  font-size: var(--step-1);
}

.method__body {
  margin-top: 0.25rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.method__heading,
.retainer__title,
.partner__title {
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

.method__heading {
  margin: 1rem 0 0.75rem;
}

.method__note {
  margin-top: 1rem;
  padding-left: 0.9rem;
  border-left: 2px solid var(--sol-ink);
  color: var(--text-2);
  font-size: var(--step--1);
}

@media (min-width: 64em) {
  .method {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 3rem;
  }

  .method__aside {
    position: sticky;
    top: calc(6rem + env(safe-area-inset-top));
  }
}

/* ---------- What a retainer reserves ---------- */

.retainer {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 2px solid var(--rule);
}

.retainer__lead {
  margin-top: 0.5rem;
  max-width: 48rem;
  color: var(--text-2);
}

.retainer__rules {
  display: grid;
  gap: 1rem;
  margin-top: 1.5rem;
}

.retainer__rule {
  min-width: 0;
  padding-top: 0.75rem;
  border-top: 1px dotted var(--rule-mid);
}

.retainer__rule dt {
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
}

.retainer__rule dd {
  margin-inline-start: 0;
  margin-top: 0.25rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

@media (min-width: 48em) {
  .retainer__rules {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 2rem;
  }
}

@media (min-width: 80em) {
  .retainer__rules {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ---------- The rate card ---------- */

/* A table, because it is one: three columns of figures that have to be
   compared down as well as across. It scrolls inside its own box rather than
   pushing the page sideways on a phone. */
/* The table scrolls inside its own box rather than pushing the page sideways
   on a phone, which is why it has a wrapper at all. */
.rate-card {
  overflow-x: auto;
  max-width: 44rem;
  margin-top: 2rem;
}

.rate-card__table {
  width: 100%;
  border-collapse: collapse;
}

.rate-card thead th {
  padding: 0.5rem 1rem 0.5rem 0;
  border-bottom: 2px solid var(--rule);
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: right;
}

.rate-card thead th:first-child,
.rate-card tbody th {
  width: 60%;
  text-align: left;
}

.rate-card tbody th {
  padding: 0.7rem 1rem 0.7rem 0;
  border-bottom: 1px dotted var(--rule-mid);
  font-weight: 400;
}

.rate-card td {
  padding: 0.7rem 0 0.7rem 1rem;
  border-bottom: 1px dotted var(--rule-mid);
  font-family: var(--font-display);
  font-size: var(--step--1);
  text-align: right;
  white-space: nowrap;
}

.rate-card__note {
  margin-top: 1rem;
  max-width: 48rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* ---------- Partner work ---------- */

.partner {
  margin-top: 2rem;
  padding: 1.25rem;
  border: 2px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper);
}

.partner__body {
  margin-top: 0.5rem;
  max-width: 48rem;
  color: var(--text-2);
}

.partner__note {
  margin-top: 0.75rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* ---------- What somebody else charges ---------- */

.third-party__item {
  min-width: 0;
  padding: 1rem;
  border-top: 2px solid var(--rule);
}

.third-party__head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  align-items: baseline;
  justify-content: space-between;
}

.third-party__name {
  font-size: var(--step-1);
}

.third-party__cost {
  padding: 0.2rem 0.5rem;
  border: 1px dashed var(--rule-mid);
  border-radius: var(--radius);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--2);
  white-space: nowrap;
}

.third-party__body {
  margin-top: 0.5rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.ownership {
  display: grid;
  gap: 1.5rem;
  margin-top: 2.5rem;
  padding: clamp(1rem, 3vw, 1.75rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--sol-tint);
}

.ownership__title {
  font-size: var(--step-2);
}

.ownership__body {
  margin-top: 0.6rem;
  color: var(--text-2);
}

.ownership__items {
  display: grid;
  gap: 0.5rem;
  margin-top: 1rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.ownership__art {
  justify-self: center;
}

@media (min-width: 48em) {
  .third-party {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .ownership {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }
}

/* ---------- Maintenance ---------- */

.maintenance {
  display: grid;
  gap: 1.5rem;
  margin-top: 2rem;
}

.maintenance__heading {
  padding-bottom: 0.4rem;
  border-bottom: 2px solid var(--rule);
  font-size: var(--step-1);
}

.maintenance__col .checks,
.maintenance__col .crosses {
  margin-top: 0.9rem;
}

.crosses {
  display: grid;
  gap: 0.55rem;
}

.crosses li {
  position: relative;
  padding-left: 1.75rem;
  color: var(--text-2);
}

/* A cross, drawn the same way the tick is, so the two lists read as opposites
   without relying on colour. */
.crosses li::before,
.crosses li::after {
  content: "";
  position: absolute;
  top: 0.62em;
  left: 0.3rem;
  width: 0.85rem;
  height: 2px;
  background: var(--text-3);
}

.crosses li::before {
  transform: rotate(45deg);
}

.crosses li::after {
  transform: rotate(-45deg);
}

.maintenance__boundary,
.maintenance__optional {
  margin-top: 0.9rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.maintenance__skull {
  margin-bottom: 0.5rem;
}

.maintenance-rates {
  display: grid;
  gap: 0;
  margin-top: 2rem;
  border-top: 2px solid var(--rule);
}

.maintenance-rates__item {
  display: flex;
  gap: 0.75rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.6rem 0.2rem;
  border-bottom: 1px dotted var(--rule-mid);
}

.maintenance-rates__name {
  font-weight: 700;
}

.maintenance-rates__price {
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: var(--step--1);
  text-align: right;
}

@media (min-width: 48em) {
  .maintenance-rates {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 2.5rem;
  }
}

/* Covers and does-not sit side by side; where the line is runs underneath them
   as a full-width band, so the two lists are compared rather than crowded by a
   column of prose twice their height. */
@media (min-width: 48em) {
  .maintenance {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem 2.5rem;
  }

  .maintenance__aside {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-column: 1 / -1;
    gap: 0 1.5rem;
    align-items: start;
    padding-top: 1.5rem;
    border-top: 2px solid var(--edge);
  }

  .maintenance__skull {
    grid-row: 1 / span 2;
    margin-bottom: 0;
  }

  .maintenance__boundary {
    margin-top: 0;
  }
}

@media (min-width: 64em) {
  .maintenance__aside {
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
    gap: 0 2.5rem;
  }

  .maintenance__skull {
    grid-row: 1;
  }

  .maintenance__optional {
    margin-top: 0;
  }
}

/* ---------- Training ---------- */

.training {
  display: grid;
  gap: 2rem;
  margin-top: 2rem;
}

.training__heading {
  padding-bottom: 0.4rem;
  border-bottom: 2px solid var(--rule);
  font-size: var(--step-1);
}

.training__aside .training__heading,
.training__aside .checks {
  margin-top: 1rem;
}

.training__format {
  margin-top: 1.5rem;
}

.spec {
  display: grid;
  gap: 0;
  margin-top: 0.9rem;
}

.spec__row {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px dotted var(--rule-mid);
}

.spec dt {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.spec dd {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.training__note {
  margin-top: 0.6rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.training__skull {
  margin-bottom: 1rem;
}

@media (min-width: 64em) {
  .training {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: 3rem;
  }
}

/* ---------- Something else ---------- */

.custom {
  display: grid;
  gap: 1.5rem;
  align-items: center;
}

@media (min-width: 48em) {
  .custom {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

/* ---------- Questions ---------- */

.faq {
  display: grid;
  gap: 0;
  margin-top: 1.5rem;
  border-top: 2px solid var(--rule);
}

.faq > div {
  border-bottom: 2px solid var(--rule);
}

.faq__item {
  margin: 0;
  padding: 0.35rem 0;
}

.faq__item .disclosure__summary {
  width: 100%;
  min-height: 48px;
  justify-content: space-between;
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 700;
  letter-spacing: normal;
  text-transform: none;
}

.faq__item .disclosure__body {
  max-width: 48rem;
  padding-bottom: 0.75rem;
  color: var(--text-2);
}

/* ═══════════════════════════ SCOPE ═══════════════════════════

   Three small blocks that came out of narrowing what the company
   sells: the home page's price band, the deployment rows on the
   catalogue, and the project-type mail links on /contact. All three
   reuse the existing ink-rule-and-mono vocabulary rather than
   introducing a fourth kind of card. */

/* ---------- The home page's price band ---------- */

.price-teaser {
  display: grid;
  gap: 0;
  margin-top: 2rem;
  border-top: 2px solid var(--rule);
}

.price-teaser__item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.75rem 0.2rem;
  border-bottom: 1px dotted var(--rule-mid);
}

/* Each name goes to the page that explains its range, so the band is a way in
   rather than four numbers you have to go and look up somewhere else. */
.price-teaser__name {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.price-teaser__value {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  white-space: nowrap;
}

.price-teaser__note {
  margin-top: 1.25rem;
  max-width: 44rem;
  color: var(--text-3);
  font-size: var(--step--2);
}

.prices-section .section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 1.5rem;
}

@media (min-width: 48em) {
  .price-teaser {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 2.5rem;
  }
}

/* ---------- Deployment, as two rows on the catalogue ---------- */

.deploy-rows {
  display: grid;
  gap: 1rem;
  margin-top: 2rem;
}

.deploy-rows__item {
  display: grid;
  gap: 1rem;
  align-items: center;
  min-width: 0;
  padding: clamp(1rem, 2.5vw, 1.5rem);
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
}

.deploy-rows__name {
  font-size: var(--step-2);
}

.deploy-rows__platform {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: var(--step--2);
}

.deploy-rows__summary {
  margin-top: 0.5rem;
  color: var(--text-2);
}

.deploy-rows .pricebox {
  justify-self: start;
}

/* Each row is its own grid, so an auto-sized price column made one fee box as
   wide as "from MVR 199" and the next as wide as "from MVR 1,999+" — two boxes
   on the same right edge whose left edges disagreed. The column is a fixed
   width instead, and both fees are one box. */
@media (min-width: 48em) {
  .deploy-rows__item {
    grid-template-columns: minmax(0, 1fr) 15rem;
  }

  .deploy-rows .pricebox {
    justify-self: stretch;
  }

  .deploy-rows .pricebox__value {
    white-space: nowrap;
  }
}

/* ---------- Project types on /contact ---------- */

.project-types {
  display: grid;
  gap: 0.6rem;
  margin-top: 2rem;
}

.project-types__link {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0.6rem 0.9rem;
  border: 2px solid var(--edge);
  border-radius: var(--radius);
  background: var(--porcelain);
  font-weight: 700;
  text-decoration: none;
}

.project-types__link::after {
  content: "→";
  margin-left: auto;
  padding-left: 0.75rem;
  color: var(--sol-ink);
}

.project-types__link:hover {
  border-color: var(--ink);
  box-shadow: none;
}

@media (min-width: 40em) {
  .project-types {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 64em) {
  .project-types {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ═══════════════════════════ CARDS ═══════════════════════════

   Every card is white with a 2px light edge and a round corner. Only a card
   that is itself a link stands on a ledge: a ledge promises "this presses",
   so a container never gets one. A clickable card lifts 2px and takes its
   accent on hover, and sinks onto its ledge when pressed. */

:is(.capability, .offer, .enquiry, .tier, .service-card, .project-card, .person, .pricebox,
  .deploy, .report, .diagram, .table-wrap, .stack, .topics, .ownership, .builder__panel,
  .builder__step, .pipeline__step, .method__step, .problem__quote) {
  border-radius: var(--radius-card);
}

:is(.capability, .offer, .enquiry) {
  --card-edge: var(--edge);
  border-color: var(--card-edge);
  box-shadow: 0 4px 0 0 var(--card-edge);
  translate: 0 0;
  transition:
    translate 200ms var(--ease),
    box-shadow 200ms var(--ease),
    border-color 200ms var(--ease);
}

:is(.capability, .offer, .enquiry):is(:hover, :focus-within) {
  --card-edge: var(--accent-bright);
  translate: 0 -2px;
  box-shadow: 0 6px 0 0 var(--card-edge);
}

:is(.capability, .offer, .enquiry):active {
  translate: 0 3px;
  box-shadow: 0 1px 0 0 var(--card-edge);
  transition-duration: 80ms;
}

