@charset "utf-8";

/* ============================================================================
   Product microsites
   ----------------------------------------------------------------------------
   One stylesheet, forty-three sites. Nothing here names a project: the whole
   identity arrives as custom properties set on <html> at build time, derived
   in src/microsite-brand.mjs. That is what lets a site be genuinely its own
   colour — a hue from its discipline's band, with a ramp built in OKLCH so the
   steps are perceptually even — without forty-three stylesheets.

   The layout language is editorial rather than SaaS: hairlines instead of
   cards, one serif reserved for statements, a mono reserved for labels and
   figures, and large quiet fields. Sections alternate between the dark ground
   and paper so a long page has a rhythm you can feel while scrolling.

   Structure
     1  tokens and reset
     2  typography
     3  furniture: header, footer, buttons, links
     4  splash sections
     5  interior pages: page head, prose, documents
     6  gallery and the animated demos
     7  responsive
     8  reduced motion and print

   Palette properties, all set inline per site:
     --accent --accent-deep --accent-soft --accent-wash --on-accent
     --counter --counter-deep
     --bg --raise --sink --line --line-soft --dim --text
     --paper --paper-deep --paper-ink --paper-dim --paper-line
   ========================================================================== */

/* ── 1. Tokens and reset ─────────────────────────────────────────────────── */

:root {
  --ui: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "DM Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --serif: Newsreader, ui-serif, Georgia, "Times New Roman", serif;

  --s1: 0.5rem;
  --s2: 1rem;
  --s3: 1.5rem;
  --s4: 2rem;
  --s5: 3rem;
  --s6: 4.5rem;
  --s7: 7rem;
  --s8: 10rem;

  /* Page gutter and content measure. Everything lines up to these two. */
  --gutter: clamp(1.25rem, 5vw, 5rem);
  --measure: 78rem;

  --radius: 3px;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
}

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

html {
  scroll-behavior: smooth;
  /* The scroll target must clear the sticky header. */
  scroll-padding-top: 6rem;
  background: var(--bg);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--ui);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg {
  display: block;
  max-width: 100%;
}

/* ── 2. Typography ───────────────────────────────────────────────────────── */

:where(h1, h2, h3, h4, p, li, dd, dt) {
  text-wrap: pretty;
  margin: 0;
}

h1,
h2,
h3 {
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 1.02;
  text-wrap: balance;
}

/* The one serif on the site. Reserved for statements — the sentence a section
   exists to make — so that it always means "read this one slowly". */
.serif {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.028em;
  line-height: 1.08;
}

.kicker {
  margin: 0;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  line-height: 1.5;
  text-transform: uppercase;
}

.eyebrow {
  margin: 0;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.lead {
  color: var(--dim);
  font-size: clamp(1.05rem, 1.4vw, 1.3rem);
  line-height: 1.65;
}

code {
  padding: 0.1em 0.35em;
  border-radius: 2px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-soft);
  font-family: var(--mono);
  font-size: 0.86em;
}

a {
  color: inherit;
  text-decoration: none;
}

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

.skip {
  position: fixed;
  z-index: 50;
  top: -6rem;
  left: 1rem;
  padding: 0.85rem 1.15rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
  transition: top 0.2s var(--ease);
}

.skip:focus {
  top: 1rem;
}

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ── 3. Furniture ────────────────────────────────────────────────────────── */

.masthead {
  position: sticky;
  z-index: 30;
  top: 0;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}

.masthead__inner {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 4.5rem;
}

/* The product's own wordmark. A site is standalone or it is not; this is the
   first thing that decides which. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-right: auto;
  font-size: 1.12rem;
  font-weight: 700;
  letter-spacing: -0.05em;
}

.wordmark__mark {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 2px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--mono);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: -0.04em;
}

.sitenav {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.sitenav a {
  display: grid;
  align-items: center;
  min-height: 44px;
  color: var(--dim);
  font-size: 0.9rem;
  font-weight: 500;
  border-bottom: 2px solid transparent;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}

.sitenav a:hover {
  color: var(--text);
}

.sitenav a[aria-current] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  min-height: 44px;
  padding: 0.8rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--on-accent);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  /* A button's width follows its content, and one of these carries an email
     address. At a raised text size that single token was wider than the
     viewport and took the page with it. The cap stops the box outgrowing what
     holds it; the wrap lets the text inside reflow rather than spill. Neither
     does anything while the label fits. */
  max-width: 100%;
  overflow-wrap: break-word;
  transition: transform 0.16s var(--ease), background 0.18s var(--ease),
    box-shadow 0.18s var(--ease);
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 0 -2px color-mix(in srgb, var(--accent) 40%, transparent);
}

.btn:active {
  transform: translateY(0);
  box-shadow: none;
}

.btn--ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--text);
}

.btn--ghost:hover {
  border-color: var(--accent);
  box-shadow: none;
}

.btn--on-paper {
  background: var(--paper-ink);
  color: var(--paper);
}

/* A text link that shows its underline as a rule in the accent, so it reads as
   a link at a glance without borrowing the button's weight. */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.35em;
  transition: color 0.18s var(--ease), text-decoration-color 0.18s var(--ease);
}

.tlink:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

.tlink__arrow {
  transition: transform 0.18s var(--ease);
}

.tlink:hover .tlink__arrow {
  transform: translateX(3px);
}

.colophon {
  padding-block: var(--s6) var(--s4);
  border-top: 1px solid var(--line-soft);
}

.colophon__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: var(--s4);
}

.colophon h2 {
  margin-bottom: var(--s2);
  font-size: 0.68rem;
  font-family: var(--mono);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}

.colophon ul {
  display: grid;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.colophon li a {
  display: inline-grid;
  align-items: center;
  min-height: 34px;
  font-size: 0.92rem;
  color: var(--text);
  transition: color 0.18s var(--ease);
}

.colophon li a:hover {
  color: var(--accent);
}

.colophon__blurb {
  max-width: 24rem;
  color: var(--dim);
  font-size: 0.92rem;
  line-height: 1.65;
}

/* The one place the holding company appears above the fold of the footer: a
   line of provenance, not a co-brand. */
.colophon__base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  margin-top: var(--s5);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-soft);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.colophon__base a {
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 0.3em;
}

.colophon__base a:hover {
  color: var(--text);
  text-decoration-color: var(--accent);
}

.colophon__base .spacer {
  margin-left: auto;
}

/* ── 4. Splash ───────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3.5rem, 9vw, 8rem) clamp(3rem, 6vw, 5rem);
  border-bottom: 1px solid var(--line-soft);
}

/* A very large, very quiet field of the accent behind the headline. It is the
   only gradient on the site and it exists so the top of the page is coloured
   rather than dark-grey-with-a-button. */
.hero::before {
  position: absolute;
  z-index: 0;
  inset: -40% 30% 20% -20%;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--accent) 20%, transparent),
    transparent
  );
  content: "";
  pointer-events: none;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: stretch;
  gap: clamp(2rem, 5vw, 4.5rem);
}

.hero h1 {
  margin: var(--s3) 0 var(--s3);
  font-size: clamp(3rem, 8vw, 6.4rem);
  letter-spacing: -0.062em;
  line-height: 0.93;
  /* Product names are unbreakable tokens — `@dwmm/platform` is one word 359px
     wide at the 3rem floor. On a 320px phone that word set the min-content of
     the whole copy column, `.hero` clips, and the promise and audience
     paragraphs beside it were cut off mid-sentence rather than wrapped. This
     only ever applies where a word genuinely does not fit. */
  overflow-wrap: break-word;
}

.hero__promise {
  max-width: 34rem;
  color: var(--text);
  font-family: var(--serif);
  font-size: clamp(1.25rem, 2.1vw, 1.85rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.32;
}

.hero__audience {
  max-width: 32rem;
  margin-top: var(--s3);
  color: var(--dim);
  font-size: 1rem;
  line-height: 1.65;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  margin-top: var(--s4);
}

.hero__stage {
  position: relative;
  /* Hug the illustration rather than stretch to the copy column's height: the
     SVG keeps a fixed ratio, so stretching only letterboxed it inside its own
     border and read as broken padding. */
  align-self: center;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--sink);
  overflow: hidden;
}


.hero__stage figcaption {
  padding: 0.7rem var(--s2);
  border-top: 1px solid var(--line-soft);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* ── The pane ──────────────────────────────────────────────────────────────
   The splash shows a close crop of the product behind a sheet of glass. The
   glass is a rim and a sheen, deliberately not a blur across the middle: the
   thing under it is small interface text, and frosting that would undo the
   reason the crop is there at all.

   Everything below is decoration over a complete, legible image. Without the
   pointer script — no mouse, reduced motion, no JavaScript — the pane sits
   flat and lit from the top left, which is how it is drawn here.
   ------------------------------------------------------------------------- */
.pane {
  --mx: 50%;
  --my: 0%;
  --rx: 0deg;
  --ry: 0deg;

  perspective: 1200px;
}

.pane__tilt {
  position: relative;
  transform: rotateX(var(--rx)) rotateY(var(--ry));
  transition:
    transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 420ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Lifted while the pointer is over it, and only then. */
.pane[data-live] .pane__tilt {
  box-shadow:
    0 1px 1px rgb(0 0 0 / 22%),
    0 18px 40px -12px rgb(0 0 0 / 45%);
  transition-duration: 120ms;
}

.pane .shot__pic img {
  display: block;
  width: 100%;
  height: auto;
}

/* The rim. An outer hairline and an inner highlight along the top edge is what
   reads as a pane of glass; the faint wash across the top eighth is the only
   place anything is diffused, and it lands on chrome rather than on content. */
.pane__glass {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 70%),
    inset 0 0 0 1px rgb(255 255 255 / 18%),
    inset 0 -18px 30px -22px rgb(14 18 34 / 30%),
    inset 0 -1px 0 rgb(0 0 0 / 14%);
  /* A pane of glass is not perfectly clear, and that matters here: a white
     highlight on a near-white screenshot is invisible, so there has to be a
     faint veil for the light to lift out of. Five per cent of a cool grey is
     below the threshold that would cost any legibility and is enough for the
     specular to read against. */
  background:
    linear-gradient(
      170deg,
      rgb(255 255 255 / 18%) 0%,
      rgb(255 255 255 / 5%) 12%,
      transparent 34%
    ),
    linear-gradient(0deg, rgb(14 18 34 / 5%), rgb(14 18 34 / 5%));
  pointer-events: none;
}

/* The specular. It sits where the pointer is, and is invisible until there is
   a pointer to sit under. */
.pane__shine {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: 0;
  /* Two parts, because one does not read: a hotspot under the pointer, and a
     streak across it, which is what makes a flat rectangle look like it has a
     surface.

     Plain alpha, deliberately — no mix-blend-mode. Blending is resolved
     against the backdrop within a stacking context, and an element promoted to
     its own compositing layer inside a 3D context is exactly where some GPU
     and driver combinations quietly drop it. It rendered on macOS and was
     invisible on Windows. White at a stated opacity over the veil below
     composites identically everywhere, which is worth more here than the
     physics. */
  background:
    radial-gradient(
      38% 50% at var(--mx) var(--my),
      rgb(255 255 255 / 40%) 0%,
      rgb(255 255 255 / 12%) 40%,
      transparent 72%
    ),
    linear-gradient(
      100deg,
      transparent 40%,
      rgb(255 255 255 / 20%) 50%,
      transparent 60%
    );
  transition: opacity 320ms ease;
  pointer-events: none;
}

.pane[data-live] .pane__shine {
  opacity: 1;
}

.hero__stage--pane {
  border: 0;
  background: none;
  overflow: visible;
}

/* The bezel is where the glass is actually glass.
   Real diffusion needs something behind it to diffuse, and it must not land on
   the crop — so the sheet is larger than the screenshot and frosted only in the
   margin, over the hero's gradient. `backdrop-filter` is progressive: without
   it the frame is still a translucent edge rather than nothing. */
.hero__stage--pane .pane__tilt {
  padding: 0.85rem;
  border: 1px solid rgb(255 255 255 / 12%);
  border-radius: calc(var(--radius) + 0.55rem);
  background: rgb(255 255 255 / 6%);
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
  box-shadow:
    0 1px 0 rgb(255 255 255 / 16%) inset,
    0 20px 50px -28px rgb(0 0 0 / 70%);
}

/* The screenshot keeps its own hard edge inside the sheet, so the frosting
   reads as a surround rather than as a haze over the interface. */
.hero__stage--pane .shot__pic {
  overflow: hidden;
  border: 1px solid rgb(0 0 0 / 22%);
  border-radius: var(--radius);
}

/* The rim and the specular belong to the glass sheet, not to the picture. */
.hero__stage--pane .pane__glass,
.hero__stage--pane .pane__shine {
  border-radius: calc(var(--radius) + 0.55rem);
}

.hero__stage--pane figcaption {
  padding-inline: 0;
}

@media (prefers-reduced-motion: reduce) {
  .pane__tilt {
    transition: none;
    transform: none;
  }

  .pane__shine {
    transition: none;
  }
}

/* ── Screenshots of the running application ───────────────────────────────
   Andare is the one product on the site that is photographed rather than
   drawn — see src/captures.mjs. The frame matters: these are light screenshots
   landing on a dark page, and without an edge they read as a hole punched in
   the layout rather than a window onto something.
   ------------------------------------------------------------------------- */
.shot__pic,
.shot__pic img {
  /* Block, both of them. Left inline the <picture> carries a line box under the
     image and the frame gains a few pixels of dead space along the bottom. */
  display: block;
}

.shot__pic img {
  width: 100%;
  height: auto;
}

.hero__stage--shot,
.stage--shot {
  background: var(--sink);
}

.hero__stage--shot .shot__pic,
.stage--shot .shot__pic {
  border-bottom: 1px solid var(--line);
}

/* The gallery stack. One capture to a row at any width: these are dense
   application screens, and two-up on a laptop makes both unreadable. */
.shots {
  display: grid;
  gap: var(--s5);
  margin-top: var(--s5);
}

.shot {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--sink);
  overflow: hidden;
}

.shot .shot__pic {
  border-bottom: 1px solid var(--line-soft);
}

.shot figcaption {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem var(--s3);
  justify-content: space-between;
  padding: 0.8rem var(--s2);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.shot figcaption span:first-child {
  color: var(--text);
}

.shot figcaption span:last-child {
  text-transform: none;
  letter-spacing: 0.02em;
}

/* The strip of facts directly under the hero. Three columns of hairline-ruled
   figures — the page's first claim that it is describing something real. */
.proof {
  border-bottom: 1px solid var(--line-soft);
}

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

.proof__grid > div {
  padding: var(--s4) var(--s3) var(--s4) 0;
  border-right: 1px solid var(--line-soft);
}

.proof__grid > div:last-child {
  border-right: 0;
}

.proof__grid > div + div {
  padding-left: var(--s3);
}

.proof dt {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.proof dd {
  margin: 0.65rem 0 0;
  font-size: clamp(1rem, 1.4vw, 1.16rem);
  font-weight: 500;
  line-height: 1.45;
}

/* The paper section. Every microsite inverts exactly twice — once for the
   statement, once for the specification — so the page has a spine. */
.paper {
  background: var(--paper);
  color: var(--paper-ink);
}

.paper .eyebrow,
.paper .lead {
  color: var(--paper-dim);
}

.paper .kicker {
  color: var(--accent-deep);
}

.paper .tlink {
  text-decoration-color: var(--accent-deep);
}

.paper .tlink:hover {
  color: var(--accent-deep);
}

.section {
  padding-block: clamp(4rem, 9vw, 8.5rem);
}

.section--tight {
  padding-block: clamp(3rem, 6vw, 5.5rem);
}

/* Section headings run flush left, above their content.
 *
 * They used to sit in the right-hand column of a 0.42fr/1fr grid, with the
 * label alone on the left — which put every heading at 42% of the page width
 * while the list beneath it started at the gutter. On a screenshot that does
 * not read as an editorial two-column head; it reads as text that has been
 * centred by accident. Flush left, everything shares one edge. */
.section__head {
  display: grid;
  gap: var(--s2);
  margin-bottom: var(--s5);
}

.section__head h2 {
  max-width: 20ch;
  font-size: clamp(2rem, 4vw, 3.4rem);
}

.section__head p {
  max-width: 42rem;
}

/* Two sections on the same ground would otherwise stack their vertical padding
   and leave up to seventeen rems of nothing between them. A change of ground
   keeps both, because that gap is the edge. */
.section:not(.paper):not(.cta) + .section:not(.paper):not(.cta) {
  padding-top: 0;
}

.statement {
  max-width: 46rem;
  font-size: clamp(1.9rem, 4.2vw, 3.6rem);
}

/* The support paragraph under a roadmap's opening statement. Body copy on the
   dark ground, where .statement + p is coloured for paper. */
.standing__more {
  max-width: 44rem;
  margin-top: var(--s4);
  color: var(--dim);
  font-size: 1.05rem;
  line-height: 1.8;
}

.statement + p {
  max-width: 40rem;
  margin-top: var(--s4);
  color: var(--paper-dim);
  font-size: 1.05rem;
  line-height: 1.8;
}

/* Roadmap themes. The same hairline-ruled row as .features, but the leading
   column carries a horizon rather than a number: on a roadmap the ordering is
   the information, and a decimal counter would imply a sequence the themes do
   not actually promise. */
.track {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.track > li {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr) minmax(0, 0.9fr);
  gap: var(--s2) var(--s3);
  align-items: start;
  padding-block: var(--s4);
  border-top: 1px solid var(--line-soft);
}

.track > li:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.track__when {
  margin: 0;
  padding-top: 0.3rem;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.11em;
  line-height: 1.5;
  text-transform: uppercase;
}

.track__what h3 {
  font-size: clamp(1.15rem, 1.7vw, 1.45rem);
  letter-spacing: -0.035em;
}

.track__what p {
  margin-top: var(--s2);
  color: var(--dim);
  font-size: 1rem;
  line-height: 1.65;
}

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

.track__items li {
  position: relative;
  padding-left: 1.1rem;
  color: var(--dim);
  font-size: 0.94rem;
  line-height: 1.55;
}

/* A bullet drawn rather than a list-marker, so it lands on the first line's
   optical centre at every clamp size instead of the line box's. */
.track__items li::before {
  content: '';
  position: absolute;
  top: 0.62em;
  left: 0;
  width: 5px;
  height: 1px;
  background: var(--accent);
}

/* Below the three-column breakpoint the horizon reads as a label above the
   theme rather than a gutter beside it. */
@media (max-width: 60rem) {
  .track > li {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s2);
  }

  .track__when {
    padding-top: 0;
  }
}

/* Numbered capability statements. Hairline-ruled rows rather than cards —
   a card grid of four features is the most generic thing a product page can
   do, and these are the least generic sentences on the site. */
.features {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: feature;
}

.features li {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 0.85fr) minmax(0, 1.35fr);
  gap: var(--s2) var(--s3);
  align-items: start;
  padding-block: var(--s4);
  border-top: 1px solid var(--line-soft);
  counter-increment: feature;
}

.features li:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.features li::before {
  content: counter(feature, decimal-leading-zero);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  padding-top: 0.35rem;
}

.features h3 {
  font-size: clamp(1.15rem, 1.7vw, 1.45rem);
  letter-spacing: -0.035em;
}

.features p {
  color: var(--dim);
  font-size: 1rem;
  line-height: 1.65;
}

.paper .features li,
.paper .features li:last-child {
  border-color: var(--paper-line);
}

.paper .features p {
  color: var(--paper-dim);
}

.paper .features li::before {
  color: var(--accent-deep);
}

/* How it works. Numbered steps across the page with a rule joining them. */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--s4);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: stepn;
}

.steps li {
  padding-top: var(--s3);
  border-top: 2px solid var(--accent);
  counter-increment: stepn;
}

.steps li:nth-child(n + 2) {
  border-top-color: var(--line);
}

.steps h3 {
  margin-bottom: 0.6rem;
  font-size: 1.2rem;
}

.steps h3::before {
  display: block;
  margin-bottom: 0.5rem;
  content: "Step " counter(stepn);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.steps p {
  color: var(--dim);
  font-size: 0.97rem;
  line-height: 1.65;
}

.paper .steps li {
  border-top-color: var(--paper-line);
}

.paper .steps li:first-child {
  border-top-color: var(--accent-deep);
}

.paper .steps h3::before {
  color: var(--accent-deep);
}

.paper .steps p {
  color: var(--paper-dim);
}

/* The specification block: what it is made of, and what state it is in. */
.spec {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: 1px;
  margin: 0;
  background: var(--paper-line);
  border: 1px solid var(--paper-line);
}

.spec > div {
  padding: var(--s3);
  background: var(--paper);
}

.spec dt {
  color: var(--paper-dim);
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.spec dd {
  margin: 0.9rem 0 0;
  font-size: 1.28rem;
  font-weight: 600;
  letter-spacing: -0.035em;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.chips li {
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--paper-line);
  border-radius: 2px;
  color: var(--paper-ink);
  font-family: var(--mono);
  font-size: 0.7rem;
}

.chips--dark li {
  border-color: var(--line);
  color: var(--accent-soft);
}

/* Language share, as one honest bar rather than a pie. */
.langbar {
  display: flex;
  overflow: hidden;
  height: 8px;
  margin-top: var(--s3);
  border-radius: 4px;
}

.langkey {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin: var(--s2) 0 0;
  padding: 0;
  list-style: none;
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--paper-dim);
}

.langkey li {
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.langkey i {
  width: 9px;
  height: 9px;
  border-radius: 2px;
}

/* The closing call to action, in full accent. */
.cta {
  background: var(--accent);
  color: var(--on-accent);
}

.cta .kicker {
  color: color-mix(in srgb, var(--on-accent) 72%, transparent);
}

.cta h2 {
  max-width: 22ch;
  margin: var(--s2) 0 var(--s3);
  font-size: clamp(2.2rem, 5.4vw, 4.4rem);
  /* The heading names the product, so it inherits whatever unbreakable token
     the product is called. Same guard as the hero: only bites when a word
     genuinely cannot fit. */
  overflow-wrap: break-word;
}

.cta p {
  max-width: 34rem;
  color: color-mix(in srgb, var(--on-accent) 82%, transparent);
  font-size: 1.05rem;
  line-height: 1.7;
}

.cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  margin-top: var(--s4);
}

.cta .btn {
  background: var(--on-accent);
  color: var(--accent-soft);
}

.cta .btn:hover {
  box-shadow: 0 6px 0 -2px color-mix(in srgb, var(--on-accent) 35%, transparent);
}

.cta .tlink {
  color: var(--on-accent);
  text-decoration-color: color-mix(in srgb, var(--on-accent) 45%, transparent);
}

.cta .tlink:hover {
  text-decoration-color: currentColor;
}

/* The install block: the commands themselves, for a product you can actually
   have. Ruled rows on the accent ground rather than a card, so it reads as part
   of the call to action rather than a widget dropped into it. The command is
   selectable text — nobody should have to retype what they came here for. */
.install {
  display: grid;
  max-width: 46rem;
  margin-top: var(--s4);
  border-top: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
}

.install__row {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: var(--s2);
  align-items: baseline;
  padding-block: 0.85rem;
  border-bottom: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
}

.install__where {
  color: color-mix(in srgb, var(--on-accent) 68%, transparent);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

/* Overrides the global `code`, which is tinted for the dark ground and is
   invisible against the accent. */
.install__cmd {
  padding: 0;
  overflow-x: auto;
  background: none;
  color: var(--on-accent);
  font-family: var(--mono);
  font-size: 0.88rem;
  line-height: 1.5;
  /* Scribe's installer is a one-line curl pipe longer than a phone is wide.
     Soft-wrapping keeps the whole command readable; copying it still yields
     one line. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cta .install__note {
  max-width: 44rem;
  margin-top: var(--s3);
  color: color-mix(in srgb, var(--on-accent) 72%, transparent);
  font-size: 0.92rem;
}

.cta .install__note code {
  padding: 0 0.2em;
  background: color-mix(in srgb, var(--on-accent) 10%, transparent);
  color: var(--on-accent);
  white-space: nowrap;
}

.cta .install__ask {
  margin-top: var(--s4);
  color: color-mix(in srgb, var(--on-accent) 72%, transparent);
  font-size: 0.92rem;
}

.cta .install__ask .tlink {
  min-height: 0;
  font-size: inherit;
}

@media (max-width: 40rem) {
  .install__row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.35rem;
  }
}

/* Sibling products, so a microsite is a door into the rest and not a dead end. */
.siblings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
}

.siblings a {
  display: grid;
  gap: 0.5rem;
  align-content: start;
  padding: var(--s3);
  background: var(--bg);
  transition: background 0.18s var(--ease);
}

.siblings a:hover {
  background: var(--raise);
}

.siblings strong {
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.03em;
}

.siblings span {
  color: var(--dim);
  font-size: 0.88rem;
  line-height: 1.5;
}

/* ── 5. Interior pages ───────────────────────────────────────────────────── */

.pagehead {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3rem, 7vw, 6rem) clamp(2.5rem, 5vw, 4rem);
  border-bottom: 1px solid var(--line-soft);
}

.pagehead::before {
  position: absolute;
  inset: -60% 40% 30% -30%;
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--accent) 14%, transparent),
    transparent
  );
  content: "";
  pointer-events: none;
}

.pagehead > * {
  position: relative;
  z-index: 1;
}

.pagehead h1 {
  margin: var(--s2) 0 var(--s3);
  font-size: clamp(2.4rem, 5.6vw, 4.4rem);
}

.pagehead .lead {
  max-width: 44rem;
}

.crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.crumb a:hover {
  color: var(--accent);
}

/* Touch target size. The breadcrumb and colophon links are set at 0.68rem and
   come out 14-18px tall — under the 24px WCAG 2.5.8 minimum, and fiddly on a
   phone. The pseudo-element grows the tappable box without moving a pixel of
   what is drawn. Each inset stays inside its container's row gap, so when the
   flex row wraps into a column the neighbouring links never overlap each
   other's target — .colophon__base wraps into a 16px-gap column. */
@media (hover: none) {
  .crumb a,
  .colophon__base a {
    position: relative;
  }

  /* Every breadcrumb on the site carries exactly one link — the rest of the
     trail is plain spans — so nothing interactive sits above or below to
     overlap, and this one can have the full 44px. */
  .crumb a::after {
    position: absolute;
    inset: -0.95rem 0;
    content: "";
  }

  .colophon__base a::after {
    position: absolute;
    inset: -0.5rem 0;
    content: "";
  }
}

/* A word that cannot fit its box breaks rather than pushing the section that
   holds it. At 200% text a product name, an email address and several headings
   stopped fitting; each one took the whole document sideways with it. Only ever
   applies where the word genuinely does not fit. */
:where(h1, h2, h3, h4, p, li, dd, dt, figcaption, blockquote) {
  overflow-wrap: break-word;
}

/* Long-form document body: legal pages, support, the deep dive. A single
   column at a real reading measure with a sticky index beside it. */
.doc {
  display: grid;
  grid-template-columns: minmax(0, 16rem) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  padding-block: clamp(3rem, 7vw, 6rem);
  align-items: start;
}

.doc__index {
  position: sticky;
  top: 6rem;
  display: grid;
  gap: 0.15rem;
}

.doc__index h2 {
  margin-bottom: var(--s2);
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.doc__index a {
  display: grid;
  align-items: center;
  min-height: 40px;
  padding-left: 0.85rem;
  border-left: 2px solid var(--line-soft);
  color: var(--dim);
  font-size: 0.9rem;
  line-height: 1.4;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}

.doc__index a:hover {
  color: var(--text);
  border-left-color: var(--accent);
}

.doc__body {
  max-width: 44rem;
}

.doc__body section + section {
  margin-top: var(--s5);
  padding-top: var(--s5);
  border-top: 1px solid var(--line-soft);
}

.doc__body h2 {
  margin-bottom: var(--s3);
  font-size: clamp(1.35rem, 2.2vw, 1.8rem);
}

.doc__body p {
  margin-bottom: var(--s2);
  color: var(--dim);
  font-size: 1.02rem;
  line-height: 1.8;
}

.doc__body p:last-child {
  margin-bottom: 0;
}

.doc__body strong {
  color: var(--text);
}

.doc__note {
  margin-top: var(--s3);
  padding: var(--s3);
  border-left: 2px solid var(--accent);
  background: var(--raise);
  color: var(--dim);
  font-size: 0.95rem;
  line-height: 1.7;
}

/* The legal hub: one row per document. */
.docindex {
  display: grid;
  gap: 1px;
  background: var(--line-soft);
  border-block: 1px solid var(--line-soft);
}

.docindex a {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr) auto;
  gap: var(--s2) var(--s3);
  align-items: baseline;
  padding: var(--s4) var(--s2);
  background: var(--bg);
  transition: background 0.18s var(--ease);
}

.docindex a:hover {
  background: var(--raise);
}

.docindex strong {
  font-size: 1.22rem;
  font-weight: 600;
  letter-spacing: -0.035em;
}

.docindex span {
  color: var(--dim);
  font-size: 0.97rem;
  line-height: 1.6;
}

.docindex em {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.68rem;
  font-style: normal;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* Frequently asked, as real disclosure widgets. */
.faq {
  display: grid;
  border-top: 1px solid var(--line-soft);
}

.faq details {
  border-bottom: 1px solid var(--line-soft);
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: 60px;
  padding-block: var(--s2);
  cursor: pointer;
  font-size: clamp(1.02rem, 1.5vw, 1.2rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  flex: none;
  color: var(--accent);
  content: "+";
  font-family: var(--mono);
  font-size: 1.3rem;
  transition: transform 0.2s var(--ease);
}

.faq details[open] summary::after {
  transform: rotate(45deg);
}

.faq p {
  max-width: 44rem;
  padding-bottom: var(--s3);
  color: var(--dim);
  font-size: 1rem;
  line-height: 1.75;
}

/* ── 6. Gallery and demos ────────────────────────────────────────────────── */

.stage {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--sink);
  overflow: hidden;
}

.stage figcaption {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  justify-content: space-between;
  padding: var(--s2) var(--s3);
  border-top: 1px solid var(--line-soft);
  color: var(--dim);
  font-size: 0.88rem;
  line-height: 1.55;
}

.plates {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
}

.plate {
  display: grid;
  gap: var(--s2);
  align-content: start;
  padding: var(--s3);
  background: var(--bg);
}

.plate__art {
  display: grid;
  place-items: center;
  height: 13rem;
  padding: var(--s3);
  background: var(--sink);
  border: 1px solid var(--line-soft);
  border-radius: 2px;
  overflow: hidden;
}

/* object-fit rather than max-height: the mark carries explicit width and height
   attributes, and inside a fixed-height grid cell those were winning — so the
   sparser marks were being cropped at the bottom edge of their plate. */
.plate__art img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.plate h3 {
  font-size: 1.05rem;
}

.plate p {
  color: var(--dim);
  font-size: 0.9rem;
  line-height: 1.6;
}

.swatches {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  width: 100%;
  border-radius: 2px;
  overflow: hidden;
}

.swatches i {
  aspect-ratio: 1 / 1.35;
}

.typespec {
  display: grid;
  gap: 0.4rem;
  width: 100%;
  text-align: center;
}

.typespec b {
  font-size: 2.1rem;
  font-weight: 600;
  letter-spacing: -0.05em;
}

.typespec em {
  font-family: var(--serif);
  font-size: 1.6rem;
  font-style: normal;
}

.typespec span {
  color: var(--dim);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
}

/* ── 6b. Price ───────────────────────────────────────────────────────────────
 *
 * One product on this site is sold rather than given away, and a price is the
 * one claim on a product page a reader will check against every other claim on
 * it. So none of this is styled as a pricing card: no shadow, no plan column,
 * no highlighted "most popular" tier. There is one price, it is small, and the
 * interesting information is what it covers — which is a ledger, not a badge.
 */

/* The sentence under the hero's action that says the till is shut. It has to be
   read by somebody who has just seen a number and a button, so it is set at
   body size on the dim ink rather than as fine print. */
.hero__note {
  max-width: 40rem;
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--line-soft);
  color: var(--dim);
  font-size: 0.95rem;
  line-height: 1.7;
}

/* The four readings a price actually consists of. Same ruled-column figure as
   .proof, because it is the same kind of statement — a small number of checkable
   facts, side by side, in the mono that this site reserves for readings. */
.pricehead {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}

.pricehead > div {
  padding: var(--s4) var(--s3) var(--s4) 0;
  border-right: 1px solid var(--line-soft);
}

.pricehead > div:last-child {
  border-right: 0;
}

.pricehead > div + div {
  padding-left: var(--s3);
}

.pricehead dt {
  font-family: var(--mono);
  font-size: clamp(1.45rem, 2.6vw, 2.1rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.15;
  color: var(--accent);
  /* Two of the three readings are one word and the third is four. Balanced,
     the long one breaks into even lines instead of leaving a widow; unbalanced
     and at the size the price wants, it out-shouts the price — which is the one
     reading on the page that has to be read first. */
  text-wrap: balance;
}

.pricehead dd {
  margin: 0.6rem 0 0;
  color: var(--dim);
  font-size: 0.95rem;
  line-height: 1.5;
}

/* On the pricing page the same figure carries the page's whole argument, so it
   is given more air. Not much more type: at 3.6rem the four-word reading took
   three lines and the whole figure read as a headline that happened to contain
   a price, rather than a price with two readings beside it. */
.pricehead--large dt {
  font-size: clamp(1.6rem, 3vw, 2.5rem);
}

.pricehead--large > div {
  padding-block: var(--s5);
}

/* The price itself, and only the price. It is the first column because it is
   the fact the page exists to state, and it is the one reading here allowed to
   be display-sized. */
.pricehead--large > div:first-child dt {
  font-size: clamp(2.6rem, 6vw, 4.4rem);
  line-height: 1;
}

/* What a licence covers, and what it does not. A ruled list rather than ticks
   and crosses: a tick is a graphic that carries no information a reader could
   check, and the two columns are already labelled. */
.pricelist {
  display: grid;
  gap: 0;
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
}

.pricelist li {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.35fr);
  gap: var(--s1) var(--s3);
  align-items: start;
  padding-block: var(--s3);
  border-top: 1px solid var(--line-soft);
}

.pricelist li:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.pricelist strong {
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.pricelist span {
  color: var(--dim);
  font-size: 0.97rem;
  line-height: 1.65;
}

/* The excluded column. Its rule is the counter hue rather than the accent, so
   the two columns are distinguishable at a glance without either being marked
   as the bad one — everything on this page is a fact about the same licence. */
.pricelist--not li {
  border-top-color: color-mix(in srgb, var(--counter) 34%, transparent);
}

.pricelist--not li:last-child {
  border-bottom-color: color-mix(in srgb, var(--counter) 34%, transparent);
}

/* The two columns themselves. One column each below the breakpoint, where a
   side-by-side ledger becomes two narrow columns of wrapped words. */
.ledger {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s5);
}

.ledger__head {
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ledger .pricelist {
  margin-top: 0;
}

.ledger .pricelist li {
  grid-template-columns: minmax(0, 1fr);
  gap: 0.4rem;
}

/* The release gates. Numbered like .features, because the count is the point:
   "five things left" is a claim, and a list you can count is what makes it one
   rather than a mood. */
.gates {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: gate;
}

.gate {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) minmax(0, 1.2fr);
  gap: var(--s2) var(--s3);
  align-items: start;
  padding-block: var(--s4);
  border-top: 1px solid var(--line-soft);
  counter-increment: gate;
}

.gate:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.gate h3 {
  font-size: clamp(1.15rem, 1.7vw, 1.45rem);
  letter-spacing: -0.035em;
}

.gate p:last-child {
  color: var(--dim);
  font-size: 1rem;
  line-height: 1.65;
}

/* Outstanding and done are told apart by the word, not by a colour — the state
   is text so it survives a screenshot, a screen reader and a monochrome print.
   The accent is the emphasis on the one that still needs doing. */
.gate__state {
  margin: 0;
  padding-top: 0.3rem;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.11em;
  line-height: 1.5;
  text-transform: uppercase;
}

.gate--done .gate__state {
  color: var(--dim);
}

.gate--done h3 {
  text-decoration: line-through;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
}

/* The "nothing is being collected" paragraph. A ruled panel rather than a
   coloured alert box: this site has no semantic colour scale, and inventing an
   amber one for a single sentence would be inventing a reading. */
.notice {
  max-width: 44rem;
  margin: var(--s4) 0 0;
  padding: var(--s3) 0 var(--s3) var(--s3);
  border-left: 2px solid var(--accent);
  color: var(--dim);
  font-size: 1.02rem;
  line-height: 1.75;
}

/* The price readings inside the closing call to action, which is the one
   surface on the site in full accent — so everything here is drawn in the ink
   that sits on it rather than in the accent itself. */
.pricetag {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: var(--s4) 0 0;
  border-top: 1px solid color-mix(in srgb, var(--on-accent) 28%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--on-accent) 28%, transparent);
}

.pricetag > div {
  padding: var(--s3) var(--s2) var(--s3) 0;
  border-right: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
}

.pricetag > div:last-child {
  border-right: 0;
}

.pricetag > div + div {
  padding-left: var(--s2);
}

.pricetag dt {
  color: color-mix(in srgb, var(--on-accent) 72%, transparent);
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.pricetag dd {
  margin: 0.55rem 0 0;
  color: var(--on-accent);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.4;
}

/* On paper, the price ledger takes the paper rules and ink. */
.paper .pricehead,
.paper .pricehead > div,
.paper .pricelist li,
.paper .pricelist li:last-child,
.paper .gate,
.paper .gate:last-child {
  border-color: var(--paper-line);
}

.paper .pricehead dt,
.paper .ledger__head,
.paper .gate__state {
  color: var(--accent-deep);
}

.paper .pricehead dd,
.paper .pricelist span,
.paper .gate p:last-child {
  color: var(--paper-dim);
}

/* ── 6c. Keys and downloads ──────────────────────────────────────────────────
   The pages a buyer uses after the sale: thank you, resend, My computers,
   download. Same hairline language as the price pages: rules and type, no
   cards with shadows, the accent only where something can be pressed. */

/* The Buy control is a form that posts, so it can work without a script. It
   sits in a row of actions exactly where the link used to. */
.buy {
  display: inline-flex;
  margin: 0;
}

button.btn {
  cursor: pointer;
}

.btn:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
  box-shadow: none;
}

.keypage {
  display: grid;
  gap: var(--s5);
  max-width: 52rem;
}

.keycard {
  padding: var(--s4) 0;
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--line-soft);
}

.keycard__state {
  margin: 0;
  color: var(--dim);
  font-size: 1.05rem;
  line-height: 1.7;
}

.keycard__label {
  margin: 0 0 var(--s1);
  color: var(--dim);
  font: 500 0.78rem var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The key itself: large, mono, and selectable in one drag. */
.keybox {
  margin: 0 0 var(--s3);
  font: 500 clamp(1.3rem, 4.2vw, 2.2rem) / 1.3 var(--mono);
  letter-spacing: 0.06em;
  overflow-wrap: anywhere;
  user-select: all;
}

.keycard__note {
  margin: var(--s2) 0 0;
  color: var(--dim);
  font-size: 0.95rem;
}

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

.keysteps li {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--s1) var(--s2);
  padding-block: var(--s3);
  border-top: 1px solid var(--line-soft);
  counter-increment: keystep;
}

.keysteps li::before {
  content: counter(keystep, decimal-leading-zero);
  grid-row: span 2;
  color: var(--accent);
  font: 500 0.85rem/1.9 var(--mono);
}

.keysteps h2 {
  margin: 0;
  font-size: 1.1rem;
  letter-spacing: -0.01em;
}

.keysteps p {
  margin: 0;
  color: var(--dim);
  line-height: 1.65;
}

.keyform {
  display: grid;
  gap: var(--s1);
}

.keyform label {
  font: 500 0.78rem var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
}

.keyform__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.keyform input {
  flex: 1 1 18rem;
  min-width: 0;
  min-height: 44px;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--sink);
  color: var(--text);
  font: 1rem var(--mono);
  letter-spacing: 0.03em;
}

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

.formnote {
  margin: var(--s1) 0 0;
  color: var(--dim);
  line-height: 1.6;
}

/* Resend's confirmation. Without a script the form posts and comes back to
   #sent, so :target shows it; with one, the script adds .is-shown. */
#sent:not(:target):not(.is-shown) {
  display: none;
}

.formnote--error {
  color: var(--text);
  padding-left: var(--s2);
  border-left: 2px solid var(--counter);
}

.keyaside {
  display: grid;
  gap: var(--s2);
  max-width: 44rem;
  color: var(--dim);
  line-height: 1.65;
}

.keyaside p {
  margin: 0;
}

/* A text link inside a sentence on these pages stays inline. As the usual
   44px inline-flex box it pushed the lines of its paragraph apart; links
   inside running text are exempt from the target-size minimum. */
.keypage p .tlink,
.keyaside .tlink,
.keysteps .tlink {
  display: inline;
  min-height: 0;
}

.seatline {
  margin: 0 0 var(--s2);
  font: 500 0.9rem var(--mono);
}

.devices {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.devices li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s1) var(--s3);
  align-items: center;
  padding-block: var(--s2);
  border-top: 1px solid var(--line-soft);
}

.devices li:last-child {
  border-bottom: 1px solid var(--line-soft);
}

.devices strong {
  font-size: 1.02rem;
}

.devices span {
  grid-column: 1;
  color: var(--dim);
  font: 0.8rem/1.5 var(--mono);
}

.devices button {
  grid-column: 2;
  grid-row: 1 / span 2;
}

.dlcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--s4);
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
}

.dlcard {
  display: grid;
  align-content: start;
  gap: var(--s2);
  padding-top: var(--s3);
  border-top: 2px solid var(--accent);
}

.dlcard h2 {
  margin: 0;
  font-size: 1.4rem;
}

.dlcard p {
  margin: 0;
  color: var(--dim);
  line-height: 1.6;
}

.dlcard__facts {
  display: grid;
  gap: var(--s1);
  margin: 0;
  font-size: 0.85rem;
}

.dlcard__facts div {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: var(--s2);
}

.dlcard__facts dt {
  color: var(--dim);
  font-family: var(--mono);
}

.dlcard__facts dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* ── 7. Responsive ───────────────────────────────────────────────────────── */

@media (max-width: 68rem) {
  /* minmax(0, …) rather than a bare 1fr: an auto minimum lets one long token
     inside the track push the track past the viewport. */
  .hero__inner,
  .section__head,
  .doc {
    grid-template-columns: minmax(0, 1fr);
  }

  .doc__index {
    position: static;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .doc__index h2 {
    flex-basis: 100%;
  }

  .doc__index a {
    padding: 0 0.75rem;
    border-left: 0;
    border: 1px solid var(--line-soft);
    border-radius: 2px;
  }

  .features li {
    /* The counter column is fixed; the content column must be free to shrink,
       or its min-content sets the row's width and the row sets the page's. */
    grid-template-columns: 3rem minmax(0, 1fr);
  }

  /* The licence ledger's two columns become two stacked lists. They keep their
     own headings, so stacking loses the comparison but not the labels. */
  .ledger {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s5);
  }

  .pricelist li {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.4rem;
  }

  /* The gate's state reads as a label above its title rather than a gutter
     beside it — the same move .track makes at its own breakpoint. */
  .gate {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s2);
  }

  .gate__state {
    padding-top: 0;
  }

  /* Four price readings will not sit in a phone's width. Two by two keeps the
     ruled figure; four stacked rows would read as a list of settings. */
  .pricetag {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .pricetag > div:nth-child(2) {
    border-right: 0;
  }

  .pricetag > div:nth-child(3) {
    padding-left: 0;
    border-top: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
  }

  .pricetag > div:nth-child(4) {
    border-top: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
  }

  .features h3 {
    grid-column: 2;
  }

  .features p {
    grid-column: 2;
  }

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

  .docindex a {
    grid-template-columns: 1fr;
  }
}

/* Small-label type on phones. Eleven mono label styles sit between 0.62 and
   0.68rem, which lands at 9.9-10.9px on a handset — under the ~12px that
   secondary text needs to stay comfortably readable at arm's length. Desktop
   keeps the sizes it was drawn at; only the phone gets the floor. */
@media (max-width: 46rem) {
  .eyebrow,
  .shot figcaption,
  .colophon h2,
  .colophon__base,
  .hero__stage figcaption,
  .proof dt,
  .steps h3::before,
  .spec dt,
  .langkey,
  .crumb,
  .doc__index h2,
  .docindex em {
    font-size: 0.75rem;
  }
}

@media (max-width: 46rem) {
  .sitenav {
    /* On a phone the nav becomes a scrollable rail rather than a hamburger:
       five links is not enough to hide behind a menu, and a rail keeps every
       destination one tap away. */
    order: 3;
    flex-basis: 100%;
    gap: var(--s3);
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    overflow-x: auto;
    scrollbar-width: none;
    border-top: 1px solid var(--line-soft);
  }

  .sitenav::-webkit-scrollbar {
    display: none;
  }

  .masthead__inner {
    flex-wrap: wrap;
    padding-top: 0.75rem;
  }

  .proof__grid {
    grid-template-columns: 1fr;
  }

  .proof__grid > div,
  .proof__grid > div + div {
    padding: var(--s3) 0;
    border-right: 0;
    border-top: 1px solid var(--line-soft);
  }

  /* The price figure goes single-column for the same reason .proof does: three
     ruled columns at 46rem gives each one about six characters. */
  .pricehead {
    grid-template-columns: 1fr;
  }

  .pricehead > div,
  .pricehead > div + div {
    padding: var(--s3) 0;
    border-right: 0;
    border-top: 1px solid var(--line-soft);
  }

  .pricehead > div:first-child {
    border-top: 0;
  }

  .paper .pricehead > div {
    border-top-color: var(--paper-line);
  }

  .colophon__grid {
    /* Zero minimum, not a bare 1fr: a single column still has to take the width
       it is given rather than the width of the longest thing in it. */
    grid-template-columns: minmax(0, 1fr);
  }

  .colophon__base .spacer {
    margin-left: 0;
  }

  .swatches i {
    aspect-ratio: 1;
  }
}

/* ── 8. Reduced motion and print ─────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

}

@media print {
  .masthead,
  .skip,
  .cta,
  .demo {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }
}
