/* Contextual :has() layout recipes are paused while the document editor is built. The page is a
   plain semantic stack until they are reintroduced deliberately. */
/* Navigation between pages is a cross-document view transition: the browser snapshots the old page,
   swaps the document, and cross-fades. Same-origin only, and off when the reader asks for less motion. */
@view-transition {
  navigation: auto;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Smooth scrolling belongs to the published page. In the editor the page is a live document
     and a scroll animation moves the blocks under the pointer, which makes dragging flaky. */
  html:not(.editing) {
    scroll-behavior: smooth;
  }
}

/* The in-page anchor at the top of a section. The nav is sticky, so the scroll margin keeps the
   section heading below it when a one-page site links to the anchor. */
.b-anchor {
  display: block;
  height: 0;
  scroll-margin-top: 4rem;
}

/*
 * The site stylesheet. Hand-written CSS: no Tailwind, no utility classes, no per-block styles.
 * Every value comes from the theme row through a custom property emitted in #theme-root. The
 * structure comes from the renderer: semantic elements and the b-* classes it derives.
 *
 * The rules are written against the parity table in .scratch/website-editor/spec-v2.md.
 */
@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");

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

html {
  /* The page and the editor chrome both follow the device preference. Theme colours use
     light-dark(), and Canvas/CanvasText inherit this declaration. */
  color-scheme: light dark;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-sans);
  font-size: var(--base-size);
  line-height: 1.6;
}

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

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

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

/* ---- skip link: the first focusable element, targeting the main landmark ---- */
.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 100;
  transform: translateY(-200%);
  padding: var(--space-2) var(--space-4);
  background: var(--color-fg);
  color: var(--color-bg);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  text-decoration: none;
}

.skip-link:focus {
  transform: none;
}

/* ---- the document shell ---- */
#main {
  display: block;
}

/* The page container is the width a split has to fit in. The viewport is not: the editor's
   sidebar and its device preview both narrow this element without narrowing the window. */
#page-blocks {
  container-type: inline-size;
  container-name: page;
}

/* A block placed directly in the page container, outside any section, still gets the
   container. The layout wraps the page body in #page-blocks; that wrapper is the one element the
   page shell owns, so a section inside it keeps its own full-width rules. */
#page-blocks > :not(.b-section) {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--page-pad);
}

/* ---- container and section rhythm ---- */
.b-section {
  width: 100%;
  max-width: none;
  margin-inline: 0;
  /* A section is full-bleed so its background can reach the viewport edge. The inline padding
     shrinks to the gutter when the viewport is narrow and grows to centre a container-width
     content column when it is wide. */
  padding-block: 1lh;
  padding-inline: max(var(--page-pad), calc((100% - var(--container)) / 2 + var(--page-pad)));
  display: flex;
  flex-direction: column;
  gap: 1lh;
}

/* Only the layout wrappers are flat. A band section nested in the page keeps its own padding. */
.b-section .b-section--div,
.b-section .b-layout,
.b-section .b-section--details {
  padding: 0;
}

/* A FAQ wrapper holds only disclosures. Their own summary padding sets the rhythm; an extra
   flex gap below each closed summary made the space uneven. */
.b-section:has(> .b-section--details) {
  gap: 0;
}

.b-section > * {
  margin-block: 0;
}

/* The page root is the outline root, not a box: its sections carry the container. */
.b-section--main {
  max-width: none;
  padding: 0;
  display: block;
}

.b-section--div {
  max-width: none;
}

/* A section with a layout recipe is a group. Mobile is the default: a grid collapses and a split
   is one column. The same rules run in the editor, so a group reflows at the editor's width.
   No rule infers a group from content shapes; the recipe is stored on the section. */
.b-layout {
  gap: var(--space-8);
}

.b-layout--stack {
  display: flex;
  flex-direction: column;
}

.b-layout--grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, var(--layout-min, 15rem)), 1fr)
  );
}

.b-layout--split {
  display: grid;
  grid-template-columns: 1fr;
}

/* Two columns and sticky only while the page container is wide enough to hold them. A media
   query would keep them sticky after the split has collapsed inside the editor or under the
   sidebar, which made one column follow the scroll behind the other. */
@container page (min-width: 48rem) {
  .b-layout--split {
    grid-template-columns: 1fr 1fr;
  }
  /* The wrapper is the grid item and stretches to the row height; the block inside it sticks
     while the other column scrolls. Only the shorter column has slack, so only it moves. A split
     is always two columns; a grid is wrapped only when it has exactly two children. The editor
     has no wrappers and is unaffected. */
  .b-layout--split > .b-split-col,
  .b-layout--grid > .b-split-col {
    /* A layout may carry align-items: center; the wrapper still has to fill the row, or the
       column inside has no slack and sticky never engages. */
    align-self: stretch;
    min-width: 0;
  }
  html:not(.continuous) .b-layout--split > .b-split-col > *,
  html:not(.continuous) .b-layout--grid > .b-split-col > * {
    position: sticky;
    top: var(--space-4);
  }
  /* The editor has no wrappers, so the column block itself is the sticky element. It starts
     below the editor bar and stops sticking while a block is being dragged, so a drop target
     never moves under the pointer. */
  html.continuous:not(.cd-dragging) .b-layout--split > *,
  html.continuous:not(.cd-dragging) .b-section.b-layout--grid:has(> :nth-child(2):last-child) > * {
    align-self: start;
    position: sticky;
    /* A fixed start for the editor bar. Measured variables meant the bar and the CSS could drift;
       four rem clears the bar at its ordinary height. */
    top: 4rem;
  }
}

.b-layout--align-start {
  align-items: start;
}

.b-layout--align-center {
  align-items: center;
}

.b-layout--align-stretch {
  align-items: stretch;
}

/* ---- headings and body text ---- */
.b-heading {
  margin: 0;
  color: var(--color-fg);
  text-wrap: balance;
}

.b-heading--1 {
  font-family: var(--font-display);
  /* Tailwind prose scale: h1 2.25rem, h2 1.5rem, h3 1.125rem at a 1rem base. The display face
     keeps the site's character; the sizes stop shouting. */
  font-size: clamp(1.875rem, 1.4rem + 1.2vw, 2.25rem);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.b-heading--2 {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.b-heading--3 {
  font-family: var(--font-sans);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.5;
}

.b-text {
  margin: 0;
  max-width: var(--measure);
  color: var(--color-fg-muted);
  text-wrap: pretty;
}

/* Prose: a text block can hold several paragraphs, a list or a quote once the writer adds them.
   The rules are written for the children so the rendered page and the editor agree. */
.b-text > p,
.b-text > ul,
.b-text > ol,
.b-text > blockquote {
  margin-block: 1lh;
}

.b-text > ul,
.b-text > ol {
  padding-left: 1.35em;
}

.b-text li {
  /* The paragraph inside a list item carries the browser's default block margins. Zero those and
     keep the list rhythm to a quarter line so items read as a list, not as separate paragraphs. */
  margin-block: 0.25lh;
}

.b-text li > p {
  margin-block: 0;
}

/* :first-of-type / :last-of-type rather than :first-child: the editor appends a drag handle
   button inside the block, and child-order selectors must not notice it. */
.b-text > p:first-of-type,
.b-text > ul:first-of-type,
.b-text > ol:first-of-type,
.b-text > blockquote:first-of-type { margin-top: 0; }
.b-text > p:last-of-type,
.b-text > ul:last-of-type,
.b-text > ol:last-of-type,
.b-text > blockquote:last-of-type { margin-bottom: 0; }
/* A single paragraph is the whole block, so it carries no spacing of its own: the block does. */
.b-text > p:only-of-type { margin-block: 0; }
.b-text u { text-underline-offset: 2px; }
.b-text ul ul, .b-text ol ol { margin-block: var(--space-2); }

/* ---- links: a link inside content acts as the section action; nav and footer opt out ---- */
.b-link {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.b-section > .b-link,
.b-list-item > .b-link {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-inverse);
  font-weight: 500;
  text-decoration: none;
}

.b-section > .b-link:hover,
.b-list-item > .b-link:hover {
  filter: brightness(1.12);
}

/* A block inside a link keeps the link's colour: the button is dark, and the body colour would
   render its label dark-on-dark. */
.b-link .b-text,
.b-link .b-heading {
  color: inherit;
  margin: 0;
}

/* ---- media ---- */
.b-image {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.b-image img {
  width: 100%;
  border-radius: var(--radius-lg);
  object-fit: cover;
}

/* A placeholder stands in for a real photo. It keeps the card's shape without pushing the page
   down a screen at desktop widths. */
.b-image--placeholder img {
  max-height: 200px;
  /* A placeholder drawn as an SVG carries its own label. Cover crops that label away as the
     card narrows, so the whole drawing stays visible and is letterboxed instead. */
  object-fit: contain;
}

.b-image figcaption {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* A hero with a figure is the template two-column split.
   The renderer emits no wrapper around the copy, so the figure is taken out of the column flow
   and the section reserves its column with padding. The copy keeps its flex stack. */

/* ---- lists ---- */
.b-list {
  margin: 0;
  padding-left: var(--space-6);
  display: flex;
  flex-direction: column;
  /* A list of plain rows is compact; the block gap below adds the line back when the rows are
     cards with their own heading. */
  gap: var(--space-2);
  color: var(--color-fg-muted);
}

/* A card title marks a set of separate items, so the items keep a full line between them. A
   form's field list has no headings and stays a tight run of rows. */
.b-list:has(> .b-list-item > .b-heading) {
  gap: 1lh;
}

.b-list--ordered {
  list-style: decimal;
}

/* A list recipe arranges its own items, so the grid display wins over the base column and the
   marker inset is dropped. */
.b-list.b-layout--grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, var(--layout-min, 15rem)), 1fr)
  );
  gap: 1lh;
  padding-left: 0;
  /* With the marker padding removed, a hanging marker sits left of the text column and no longer
     lines up with the heading above it. Keeping the marker inside puts it on the content edge. */
  list-style-position: inside;
}

/* A grid of cards is not a bulleted list in the visual sense. Keep numbers for an ordered
   sequence, but drop the dots on an unordered grid where they sit on top of each card. */
.b-list--unordered.b-layout--grid {
  list-style: none;
}

.b-list--ordered > .b-list-item::marker {
  color: var(--color-fg);
  font-variant-numeric: tabular-nums;
}

.b-list-item {
  margin: 0;
  max-width: var(--measure);
}



/* A strong run keeps the card's text colour and weight. It stays inline: an inline mark must
   never split a sentence into blocks when a writer bolds one word. Card titles are headings. */
.b-list > .b-list-item > .b-text strong {
  color: var(--color-fg);
  font-weight: 650;
  line-height: 1.4;
}
/* A card label is a leading strong; its text follows on the next line. A bold word elsewhere
   stays inline, so emphasis inside the sentence never splits it. */
.b-list > .b-list-item > .b-text > p > strong:first-child {
  display: block;
}

.b-list > .b-list-item > .b-heading {
  margin: 0;
  color: var(--color-fg);
}


/* ---- forms ---- */
.b-form {
  display: flex;
  flex-direction: column;
  gap: .25lh;
  margin: 0;
}

.b-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.b-field-label {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-fg);
}

.b-field-help {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

.b-field input:not([type="checkbox"]),
.b-field select,
.b-field textarea {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-fg);
  font: inherit;
}

.b-field textarea {
  min-height: 6lh;
  resize: vertical;
}

.b-field--checkbox {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-2);
}

.b-field--checkbox input {
  margin-top: .3lh;
}

.b-field--checkbox .b-field-label {
  font-weight: 400;
  color: var(--color-fg-muted);
}

.b-input--submit,
.b-form button {
  align-self: flex-start;
  padding: var(--space-2) var(--space-4);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-bg);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

/* ---- quotes ---- */
.b-quote {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  color: var(--color-fg);
}

.b-quote > p {
  margin: 0;
  text-wrap: pretty;
}

.b-quote > p::before {
  content: "\201C";
}

.b-quote > p::after {
  content: "\201D";
}

.b-quote > cite {
  font-style: normal;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* A portrait after a quote is the testimonial avatar. */
.b-list-item > .b-quote + .b-image {
  grid-column: 1;
  width: 3rem;
}

.b-list-item > .b-quote + .b-image img {
  width: 3rem;
  height: 3rem;
  aspect-ratio: 1;
  border-radius: 999px;
  object-fit: cover;
}

/* ---- disclosure list: section as=details, heading rendered as summary ---- */
.b-section--details {
  max-width: none;
  width: 100%;
  padding: 0;
  display: block;
  border-top: 1px solid var(--color-border);
  /* Keyword interpolation lets the browser animate the generated disclosure box between 0 and
     auto, provided ::details-content is supported. The fallback is an instant open. */
  interpolate-size: allow-keywords;
}

@supports (interpolate-size: allow-keywords) {
  .b-section--details::details-content {
    block-size: 0;
    overflow: hidden;
    transition:
      block-size .24s cubic-bezier(.2, .8, .2, 1),
      content-visibility .24s;
    transition-behavior: allow-discrete;
  }

  .b-section--details[open]::details-content {
    block-size: auto;
  }

  @starting-style {
    .b-section--details[open]::details-content {
      block-size: 0;
    }
  }
}

.b-section--details:last-child {
  border-bottom: 1px solid var(--color-border);
}

.b-section--details > summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  padding-block: var(--space-4);
  cursor: pointer;
  list-style: none;
  color: var(--color-fg);
  font-size: var(--text-base);
}

.b-section--details > summary::-webkit-details-marker {
  display: none;
}

/* Tabler's chevron-down (MIT), as a mask so it takes the summary's ink colour. */
.b-section--details > summary::after {
  content: "";
  flex: none;
  width: var(--space-5);
  height: var(--space-5);
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6 -6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6l6 -6'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: rotate .15s;
}

.b-section--details[open] > summary::after {
  rotate: 180deg;
}

@media (prefers-reduced-motion: reduce) {
  .b-section--details > summary::after,
  .b-section--details::details-content {
    transition: none;
  }
}

.b-section--details > :not(summary) {
  margin: 0;
  padding-bottom: var(--space-4);
  max-width: var(--measure);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* ---- table: the pricing comparison matrix ---- */
.b-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

.b-table caption {
  padding-bottom: var(--space-4);
  text-align: left;
  color: var(--color-fg);
  font-weight: 600;
}

.b-table th,
.b-table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--color-border);
}

.b-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--color-bg);
  color: var(--color-fg);
  font-weight: 600;
}

/* ---- nav row and its mobile disclosure ---- */
.b-section--nav {
  max-width: none;
  padding-inline: max(var(--page-pad), calc((100% - var(--container)) / 2 + var(--page-pad)));
  padding-block: var(--space-3);
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--color-bg);
}

.b-section--nav > .b-heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 400;
}

.b-section--nav .b-list {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-6);
  padding-left: 0;
  list-style: none;
}

.b-section--nav .b-list-item {
  max-width: none;
}

.b-section--nav .b-link {
  padding: 0;
  border-radius: 0;
  background: none;
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  text-decoration: none;
}

.b-section--nav .b-link:hover {
  color: var(--color-fg);
}

/* The disclosure the nav uses below 64rem. */
@media (max-width: 63.99rem) {

  .b-section--nav details {
    width: 100%;
    order: 3;
  }

  .b-section--nav details > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding-block: var(--space-2);
    cursor: pointer;
    list-style: none;
    color: var(--color-fg);
    font-size: var(--text-sm);
  }

  .b-section--nav details > summary::-webkit-details-marker {
    display: none;
  }

  .b-section--nav details > summary::after {
    content: "+";
    font-size: var(--text-lg);
  }

  .b-section--nav details[open] > summary::after {
    content: "\2212";
  }

  .b-section--nav details .b-list {
    flex-direction: column;
    gap: var(--space-2);
    padding-block: var(--space-2);
  }
}

/* ---- footer: a full-width band whose categories sit in columns ---- */
.b-section--footer {
  max-width: none;
  width: 100%;
  margin-top: var(--space-16);
  padding-block: var(--space-16);
  padding-inline: max(var(--page-pad), calc((100% - var(--container)) / 2 + var(--page-pad)));
  display: block;
  background: var(--color-surface-soft);
}

/* Each category is a section with a heading and its list. It keeps its own column. */
/* The categories share the container evenly instead of stacking as fixed 12rem blocks at the
   left edge. Flex rather than grid: the fineprint is a full row without forcing empty tracks to
   stay open beside the columns. */
.b-section--footer {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-10) var(--space-6);
}

.b-section--footer > .b-section--nav {
  flex: 1 1 8rem;
  display: block;
  width: auto;
  margin: 0;
  padding: 0;
  position: static;
  /* The editor forces position: relative on every block, which would turn the inherited top
     into a downward shift and overlap the copyright row. */
  top: auto;
  max-width: none;
  background: none;
}

.b-section--footer > .b-section--nav > .b-heading {
  margin: 0 0 var(--space-2);
}

.b-section--footer > .b-section--nav > .b-list {
  margin: 0;
}

/* The fineprint row spans the columns. */
.b-section--footer > .b-text {
  /* A measure-wide max-width would let the fineprint join the column row and squeeze it. */
  flex: 1 0 100%;
  width: 100%;
  max-width: none;
  margin-top: var(--space-8);
}

.b-section--footer .b-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-left: 0;
  list-style: none;
}

/* The template's footer is text-sm/7: 14px on a 28px line, headings at normal weight and only
   the ink colour separating them from the muted links. --text-sm is 0.8rem here, so derive the
   Tailwind size from the theme's base instead. */
.b-section--footer .b-heading {
  font-size: calc(var(--base-size) * 0.875);
  font-weight: 400;
  line-height: 2;
}

.b-section--footer .b-link {
  padding: 0;
  border-radius: 0;
  background: none;
  color: var(--color-fg-muted);
  font-size: calc(var(--base-size) * 0.875);
  font-weight: 400;
  line-height: 2;
  text-decoration: none;
}

.b-section--footer .b-link:hover {
  color: var(--color-fg);
  text-decoration: underline;
}

.b-section--footer > .b-text {
  margin-top: var(--space-10);
  color: var(--color-fg-muted);
  font-size: calc(var(--base-size) * 0.875);
  line-height: 2;
}

/* ---- documents: real prose rules, at the measure ---- */
.b-section > .b-heading--2 + .b-text {
  max-width: var(--measure);
}

/* ---- narrow screens ---- */
@media (max-width: 48rem) {
  .b-section {
    padding-block: 1lh;
    gap: 1lh;
  }

  .b-section--nav {
    position: static;
  }

  .b-section--footer {
    padding-block: var(--space-12);
  }

  /* A lone category on the last row keeps its column width instead of stretching full-width. */
  .b-section--footer > .b-section--nav {
    flex: 0 1 calc(50% - var(--space-3));
  }

  .b-section--nav {
    padding-block: var(--space-3);
  }
}

/* ---- node style tokens ----
   The renderer and the editor both emit these classes from the style layer. A token that is not
   set emits no class, so the node inherits its parent or its role. */

.b-text-align--start { text-align: start; }
.b-text-align--center { text-align: center; }
.b-text-align--end { text-align: end; }

.b-layout--justify-items-start { justify-items: start; }
.b-layout--justify-items-center { justify-items: center; }
.b-layout--justify-items-end { justify-items: end; }
.b-layout--justify-items-stretch { justify-items: stretch; }

.b-layout--align-items-start { align-items: start; }
.b-layout--align-items-center { align-items: center; }
.b-layout--align-items-end { align-items: end; }
.b-layout--align-items-stretch { align-items: stretch; }

.b-self--justify-start { justify-self: start; }
.b-self--justify-center { justify-self: center; }
.b-self--justify-end { justify-self: end; }
.b-self--justify-stretch { justify-self: stretch; }

.b-self--align-start { align-self: start; }
.b-self--align-center { align-self: center; }
.b-self--align-end { align-self: end; }
.b-self--align-stretch { align-self: stretch; }

.b-tone--tint { background: var(--color-surface); }
.b-tone--soft { background: var(--color-surface-soft); }
.b-tone--invert {
  background: var(--color-fg);
  color: var(--color-bg);
}
/* Text rules below the tone rule set their own colour. `:is` raises this selector above a single
   class so the inverted band wins without !important and without touching every component. */
.b-tone--invert :is(h1, h2, h3, h4, h5, h6, p, li, blockquote, figcaption, th, td, label,
  .b-field-label, .b-field-help, cite, small) {
  color: var(--color-bg);
}
.b-tone--invert :is(a) { color: inherit; }
.b-tone--invert .b-field input,
.b-tone--invert .b-field select,
.b-tone--invert .b-field textarea {
  color: var(--color-fg);
}
