/* Sempera theme layer.
   Loaded last in <head>, on top of the site's own compiled stylesheet.

   TYPOGRAPHY ONLY. The colour system is deliberately left exactly as the
   bland.ai mirror ships it: same grounds, same ink, same amber accent, same
   eleven-step neutral ramp, same semantic and illustration colours. Nothing
   here declares a --color-* value, so every one of them resolves to the
   origin's. See git history for the warm-paper recolour if it is ever wanted
   back; it was removed on request, not lost.

   Everything below is a token override rather than a rewrite. The site
   resolves all of its typography through var(--font-soehne), so retargeting
   that variable restyles all 861 pages without touching a component.

   Selectors use html:root (specificity 0,1,1) rather than :root (0,1,0) so the
   overrides win regardless of where React injects its own <style> blocks at
   hydration time. Source order is not guaranteed; specificity is. */

@font-face {
  font-family: "Sempera Serif";
  src: url("/sempera/fonts/sempera-serif.woff2") format("woff2-variations");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Sempera Sans";
  src: url("/sempera/fonts/sempera-sans.woff2") format("woff2-variations");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Sempera Mono";
  src: url("/sempera/fonts/sempera-mono.woff2") format("woff2-variations");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}

html:root {
  --sempera-serif: "Sempera Serif", Georgia, "Times New Roman", serif;
  --sempera-sans: "Sempera Sans", Inter, system-ui, -apple-system, sans-serif;
  --sempera-mono: "Sempera Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* The site's stacks are built from these two, so overriding them moves the
     whole of the body copy across. */
  --font-soehne: "Sempera Sans";
  --font-soehne-aux: "Sempera Sans";
  --font-body: var(--sempera-sans);
  --font-soehne-stack: var(--sempera-sans);
  --font-display: var(--sempera-serif);
  --font-mono: var(--sempera-mono);

  /* -.04em was tuned for a grotesk at display sizes. A serif needs air. */
  --heading-ls: -0.02em;
  --body-ls: -0.003em;
  --heading-lh: 1.04;
}

body {
  font-family: var(--sempera-sans);
  font-optical-sizing: auto;
}

/* Headings to the serif. The site labels display type three ways: a
   font-display utility, text-h1/h2/h3 size classes, and hand-written hpv5-*
   classes on the homepage sections. All of them mean "heading". */
h1,
h2,
h3,
.font-display,
.text-display,
.text-h1,
.text-h2,
.text-h3,
[class*="hpv5-halbfett"],
[class*="__heading"],
[class*="-title"],
blockquote {
  font-family: var(--sempera-serif) !important;
  font-optical-sizing: auto;
  letter-spacing: var(--heading-ls);
}

/* Display sizes read heavy at soehne's 600-700. The serif carries the same
   authority at 500 and looks like a wordmark rather than a headline. */
h1,
.text-display,
.text-h1 {
  font-weight: 500 !important;
}

code,
pre,
kbd,
samp,
.font-mono,
[class*="text-mono"] {
  font-family: var(--sempera-mono) !important;
}

/* The wordmark is drawn as vector paths, so the brand rename cannot reach it.
   Swap the artwork for set type rather than editing path data on 861 pages. */
a[aria-label="Sempera home"] {
  align-items: center;
}
a[aria-label="Sempera home"] svg {
  display: none !important;
}
/* The mark, set beside the word rather than replacing it. Drawn as a MASK, not
   an <img> or a background-image, so it takes its colour from currentColor and
   is therefore correct on the white nav and the bg-fog footer alike, and in dark
   mode, without shipping a second file. The bare glyph is used rather than
   logos/sempera-icon.svg: that one wraps the glyph in a filled rounded square,
   which beside set type reads as a favicon dropped into the nav. */
a[aria-label="Sempera home"]::before {
  content: "";
  flex: none;
  width: 26px;
  height: 26px;
  margin-right: 9px;
  background-color: currentColor;
  -webkit-mask: url("/sempera/mark.svg") center / contain no-repeat;
  mask: url("/sempera/mark.svg") center / contain no-repeat;
}
a[aria-label="Sempera home"]::after {
  content: "Sempera";
  font-family: var(--sempera-serif);
  font-size: 25px;
  font-weight: 500;
  letter-spacing: -0.022em;
  line-height: 1;
  color: currentColor;
  white-space: nowrap;
}

/* copy.py credits the sector-card figures to the platform by PREPENDING the
   sentence onto this link's label, and the label lives in a .whitespace-nowrap
   span. The origin's label was "See all customer stories", short enough to never
   break; ours is that plus a full sentence, 493px of unbreakable text inside a
   390px viewport, running off the right edge on six pages. Desktop is unaffected
   because the line still fits on one row when wrapping is allowed.

   This is a value-level fix on purpose. The sentence wants to be a footnote
   BESIDE the link rather than inside its label, but moving it means adding an
   element to the server markup and the flight payload in agreement, which is the
   change that breaks hydration. Left for the rebuild, where the footnote can be
   authored in the right place to begin with. */
a[href="/customers/"] .whitespace-nowrap {
  white-space: normal;
}

/* THE FOOTER'S EMPTY HALF.
   Bland runs an SEO footer: sixteen links under Solutions against four, five and
   seven under the others. Because those groups are cells of one CSS grid, the row
   is as tall as its tallest cell, so the origin's own footer already ends in
   288-384px of nothing under four of its five columns. Measured at 1280px:
   column bottoms at 188 / 540 / 156 / 188 / 252 inside a 540px row.

   Ours inherits the shape and makes it worse, because prune.py deleted most of
   the routes the short columns pointed at: 3 / 16 / 3 / 1 / 2 items, so four
   columns end within 130px of the top of a 540px row. That is the white band at
   the bottom of every page.

   Fixed by giving the long list the width it needs instead of letting it set the
   height for everyone. The group that has a seventh item is the Solutions one,
   and saying so in the selector is the point: it earns two grid columns and
   flows its own items across them, which halves its height and brings it into
   range of its neighbours. On phones the same problem has a simpler answer,
   since there is only room for one column anyway.

   This is the one place the mirror deliberately does NOT match the origin
   pixel for pixel. The origin's version of this row is a defect, and copying a
   defect faithfully is still shipping a defect. */
@media (max-width: 639px) {
  footer > div > div.grid {
    grid-template-columns: 1fr;
  }
}
@media (min-width: 640px) {
  footer > div > div.grid > div:has(> ul > li:nth-child(7)) {
    grid-column: span 2;
  }
  /* display:block because multi-column layout has no effect on a flex
     container, and the site sets these lists to flex-col. The items carry
     their own 32px rhythm on the anchor, so nothing else changes. */
  footer > div > div.grid > div:has(> ul > li:nth-child(7)) > ul {
    display: block;
    columns: 2;
    column-gap: var(--card-gap);
  }
}
/* Six tracks rather than five, because the wide Solutions cell now occupies two
   of them and five groups need six slots. Scoped to the link grid: the logo row
   above it reads the same --footer-cols and must stay at five. */
@media (min-width: 1024px) {
  footer > div > div.grid:has(> div > ul) {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* The call panel offers a text-chat fallback, which exists because the live
   agent could also be typed at. These cards play a fixed recording, so there is
   nothing to type to and the control would only mislead. */
.tta-dock-switch {
  display: none !important;
}

/* The nav sign-up buttons and the links to deleted routes used to be hidden
   here, because editing a shared client component on 853 pages looked like 853
   chances to break hydration. tools/strip.py now does it properly, cutting the
   element from the markup, the flight stream, and the chunk together, so the
   anchors are gone from the DOM rather than merely invisible. Those rules are
   deliberately not replaced: if strip.py ever misses one, the resulting 404
   should be loud. */

/* The plan comparison table. Bland's rows price a developer platform: talk-time
   and transfer-time rates per minute, daily and hourly call caps, voice-clone
   and knowledge-base limits, JWT signatures, forward-deployed engineers. Sempera
   sells four flat monthly plans with minutes included, so the table contradicts
   the cards directly above it, and its column headers are client-rendered from
   the bundle, so they still read Start / Build / Scale / Enterprise.

   Filling the cells in would mean inventing daily caps and concurrency limits
   that pricing.ts does not set, which is a worse failure than having no table.
   Hidden until those numbers are real product decisions. */
section:has(#pricing-compare-table) {
  display: none !important;
}

/* Field Notes tables.

   The origin never used a table inside a post, so the compiled stylesheet has
   no rule for one and .blog-content table inherits browser defaults: no
   borders, no padding, cells butted against each other so "What you'd need" and
   "What it actually requires" read as one run-on sentence. Our articles carry
   about 120 table rows between them, so this is not an edge case.

   Styled from the same tokens the surrounding prose uses rather than with new
   values, so a table reads as part of the article and not as something pasted
   into it. Wrapped in its own scroll container because a three-column table at
   390px cannot shrink to fit and would otherwise widen the whole page. */
.blog-content table {
  width: 100%;
  border-collapse: collapse;
  margin: 32px 0;
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  line-height: 1.55;
  display: block;
  overflow-x: auto;
}
.blog-content thead th {
  font-weight: 600;
  color: var(--color-dark);
  text-align: left;
  vertical-align: bottom;
  border-bottom: 1px solid var(--color-border-emphasis);
  padding: 0 20px 10px 0;
  white-space: nowrap;
}
.blog-content tbody td {
  color: var(--color-text-secondary);
  vertical-align: top;
  border-bottom: 1px solid var(--color-border-soft);
  padding: 12px 20px 12px 0;
}
.blog-content tbody tr:last-child td {
  border-bottom: 0;
}
.blog-content th:last-child,
.blog-content td:last-child {
  padding-right: 0;
}
