/* ==========================================================================
   My Day Suite — holding page + legal template
   Values come from contracts/design/tokens.json. Do not invent colours here:
   if a value is missing, add it to the contract first.
   ========================================================================== */

/* --- typeface -------------------------------------------------------------
   SF Pro is NOT embedded: Apple's licence covers apps and UI for Apple
   platforms, not websites. Apple devices pick up SF Pro from the system stack;
   everywhere else falls to IBM Plex Sans, which is OFL and is already the
   suite's Android typeface. Note the stack order in --font-sans: `system-ui`
   sits AFTER IBM Plex Sans on purpose — it resolves on every platform (Segoe
   UI on Windows, Roboto on Android) and would otherwise shadow our webfont. */
@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/IBMPlexSans-var.woff2") format("woff2");
  font-weight: 100 700;
  font-stretch: 75% 100%;
  font-style: normal;
  font-display: swap;
}

:root {
  /* surfaces */
  --ground: #0B0905;
  --surface: #14110C;
  --raised: #1D1A14;
  --hairline: rgba(76, 74, 66, 0.62);
  --card-border: rgba(76, 74, 66, 0.55);

  /* ink */
  --ink: #F1EEE7;
  --ink-muted: #A19E96;
  --ink-faint: #6B6962;

  /* the whole chromatic budget of this site: the Works signature */
  --accent: #CAE923;
  --on-accent: #0B0905;

  /* type */
  --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "IBM Plex Sans", system-ui, "Segoe UI", Roboto, sans-serif;

  /* the lockup, as the app builds it (SplashView.swift:120-130). The app's
     0.78 leading is for a SINGLE line; stacked over two, the "y" descender of
     Day runs down past the "it" of suite. Measured at 144px in IBM Plex Sans
     (longer descenders than SF Pro, so it is the worst case): at 0.85 the two
     lines clear each other by 14.3px, with zero colliding columns.
     --lockup-word restores the word gap the negative tracking eats, so
     "My Day" still reads as two words. */
  --lockup-tracking: -0.065em;
  --lockup-word: 0.06em;
  --lockup-leading: 0.85;
  /* the heavy word carries its own size so the two lines can be balanced
     independently of the leading. MUST have a unit — a bare number is an
     invalid font-size and the whole declaration is dropped. */
  --lockup-heavy-scale: 0.95em;
  --lockup-light: 300;
  --lockup-heavy: 800;
  --lockup-heavy-transform: lowercase;

  /* space — base-4 grid from the contract */
  --s-xs: 4px;
  --s-sm: 8px;
  --s-md: 12px;
  --s-lg: 16px;
  --s-xl: 20px;
  --s-2xl: 24px;
  --s-3xl: 32px;

  /* radii */
  --r-tile: 12px;
  --r-control: 14px;
  --r-full: 9999px;

  /* motion — one curve, no bounce */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 180ms;

  /* page gutter */
  --gutter: clamp(20px, 5vw, 56px);

  /* Every band of the page (top bar, document, footer) is full-bleed for its
     rules and background, but its CONTENT stops at --shell. --edge is the side
     padding that produces that: the gutter until the viewport outgrows the
     shell, half the overflow after. Because the bar and the document share it,
     the logo and the contents rail sit on the same left margin at every width —
     which is the whole point. */
  --shell: 1440px;
  --edge: max(var(--gutter), (100% - var(--shell)) / 2);
}

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

html {
  -webkit-text-size-adjust: 100%;
}

/* jumping from the contents should read as movement through one document, not
   as a new page. Cancelled under Reduce Motion at the bottom of this file. */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  min-height: 100svh;
  /* scale() does not affect layout, so the 105% end of the swell animation can
     paint past the viewport. The guard belongs on the horizontal axis and on the
     page -- `overflow: clip` on the lockup itself clips BOTH axes, and what it
     clipped was the descender of the "y" in "Day". `clip` is the one overflow
     value that lets the other axis stay visible, which is what those tails need. */
  overflow-x: clip;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: grid;
  grid-template-rows: auto 1fr auto;
}

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* skip link — visible only once focused */
.skip {
  position: absolute;
  left: var(--edge);
  top: var(--s-sm);
  z-index: 10;
  padding: var(--s-sm) var(--s-md);
  border-radius: var(--r-tile);
  background: var(--raised);
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
}

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

/* --- top bar -------------------------------------------------------------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-lg);
  padding: var(--s-xl) var(--edge);
}

/* the holding page has nothing on the left, so the selector sits alone right */
.topbar--bare {
  justify-content: flex-end;
}

/* --- language selector ---------------------------------------------------- */

.lang {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-full);
  background: var(--raised);
  border: 1px solid var(--card-border);
  flex: none;
}

/* Links, not buttons: each language is its own URL, so switching is navigation
   and must behave like it (middle-click, open in new tab, copy link). */
.lang__btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 7px 14px;
  min-height: 32px;
  border-radius: var(--r-full);
  color: var(--ink-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease);
}

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

.lang__btn[aria-current="page"] {
  background: rgba(241, 238, 231, 0.10);
  color: var(--ink);
}

/* site.js marks the language the browser asked for, when the visitor is not
   already on it. A dot — never a redirect. */
.lang__btn--suggested::after {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: var(--r-full);
  background: var(--accent);
}

/* --- the lockup ----------------------------------------------------------- */
/* Two weights of one typeface, tight tracking, the heavy word lowercased —
   the same construction the app uses for "My Day works". */

.lockup {
  margin: 0;
  font-weight: var(--lockup-light);
  letter-spacing: var(--lockup-tracking);
  word-spacing: var(--lockup-word);
  line-height: var(--lockup-leading);
  color: var(--accent);
}

.lockup__heavy {
  display: block;
  /* Pulls the heavy word up against the light one. The pair was measured at
     144px with IBM Plex Sans forced (longer descenders than SF Pro, so the
     worst case) -- if you change this, redo that measurement, because the
     descender of "y" in Day is what it is trading against. */
  margin-top: -15px;
  font-size: var(--lockup-heavy-scale);
  font-weight: var(--lockup-heavy);
  text-transform: var(--lockup-heavy-transform);
}

/* --- holding page --------------------------------------------------------- */

.stage {
  /* The lockup IS the page, so it scales with the viewport instead of
     stopping at a fixed ceiling and floating small on a large screen. ONE
     formula for every width -- no separate mobile floor -- so the whole
     composition (this, and the padding/gap below, which are fractions of
     it) reads as the same picture resized, not a different layout under a
     breakpoint. It answers to BOTH dimensions: 24vw is the size law that
     actually governs on phones and tablets (roughly a quarter of the
     width), and 26svh stops it from outgrowing a short landscape window;
     on desktop the 9rem cap is what actually governs past ~600px, so
     24vw only ever touches screens narrower than that. The 3.5rem floor is
     just a legibility backstop for a device narrower than ~233px -- it
     shouldn't engage on any phone actually in use. */
  --lockup-size: clamp(3.5rem, min(24vw, 26svh), 9rem);
  display: grid;
  place-content: center;
  justify-items: center;
  text-align: center;
  /* Padding and gap are fractions of --lockup-size, not the fixed --s-*
     tokens: on a phone the lockup is much smaller than on desktop, and a
     fixed gap would read proportionally wider around it than the desktop
     layout ever shows. Ratios are desktop's own 32px/20px against its
     ~144px mid-range lockup (9rem). */
  padding: calc(var(--lockup-size) * 0.22) var(--gutter);
  gap: calc(var(--lockup-size) * 0.14);
}

.stage .lockup {
  font-size: var(--lockup-size);
  /* At line-height 0.85 the box is SHORTER than the glyphs: the descenders of
     the heavy word overflow it by roughly 0.18em. Anything spaced from that box
     -- the note below it, the grid gap -- lands inside the tails of "pp". This
     gives the box back the height the leading took, so a 20px margin below
     means 20px of visible air. Re-measure if --lockup-leading changes. */
  padding-bottom: 0.18em;
}

.stage__note {
  margin: calc(var(--lockup-size) * 0.14);
  color: var(--ink-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}

/* one discreet entrance, disabled under Reduce Motion (see bottom of file) */
.stage > * {
  animation: rise 620ms var(--ease) both;
}

.stage__note {
  animation-delay: 140ms;
}

/* The lockup and the note move differently, on purpose.

   The note keeps `rise` from `.stage > *`: it is the only thing that lifts.
   The lockup gets `swell` instead -- the shorthand replaces `rise` on this
   element, which is what keeps the lift off it. No fade: the lockup is
   visible from frame one and just zooms, slowly and barely, for the whole
   duration. */
.stage .lockup {
  animation: swell 14s cubic-bezier(0.33, 0, 0.15, 1) both;
}

@keyframes swell {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(1.06);
  }
}

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

/* --- footer --------------------------------------------------------------- */

.footer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-md) var(--s-2xl);
  padding: var(--s-xl) var(--edge) var(--s-2xl);
  border-top: 1px solid var(--hairline);
  font-size: 13px;
}

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-sm) var(--s-md);
}

/* decorative separator: outside the anchors so it is neither clickable nor
   announced, and it wraps with the links instead of dangling on a new line */
.footer__sep {
  color: var(--ink-faint);
  user-select: none;
}

.footer__legal a {
  color: var(--ink-muted);
  text-decoration: none;
  padding: var(--s-xs) 0;
  transition: color var(--dur-fast) var(--ease);
}

.footer__legal a:hover,
.footer__legal a[aria-current="page"] {
  color: var(--ink);
}

.footer__legal a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ink-faint would land at 3.6:1 on the ground — below AA for body text, so the
   copyright uses ink-muted (7.4:1) even though it is the quietest thing here */
.footer__copy {
  margin: 0;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .footer {
    flex-direction: column;
    align-items: flex-start;
  }
  .footer__legal {
    flex-direction: column;
    gap: var(--s-xs);
  }
  /* stacked links separate themselves; a lone "|" on its own row does not */
  .footer__sep {
    display: none;
  }
  /* -15px was measured against the 144px reference size (see .lockup__heavy);
     at the smaller mobile lockup it pulls "app" in too far. */
  .stage .lockup__heavy {
    margin-top: -5px;
  }
  /* Overriding the custom property, not .stage .lockup's font-size directly,
     keeps the padding/gap calc()s (both keyed off --lockup-size) in the same
     proportion to the logo as everywhere else. */
  .stage {
    --lockup-size: 5rem;
  }
  .stage__note {
    margin: 5px;
  }
}

/* --- legal pages ---------------------------------------------------------- */

.docbar {
  border-bottom: 1px solid var(--hairline);
}

/* fluid so it never crowds the language selector on a 320px phone */
.docbar .lockup {
  font-size: clamp(19px, 5vw, 26px);
  text-decoration: none;
  display: inline-flex;
  align-items: baseline;
  gap: 0.22em;
  line-height: 1.1;
  white-space: nowrap;
}

/* reduced lockup: one line, the two weights kept side by side */
.docbar .lockup__heavy {
  display: inline;
}

/* The text block is CENTRED on the page at every width, with the text itself
   left-aligned inside it. The document is full-bleed and padded by --edge, the
   same padding the top bar uses: that is what puts the contents rail on the
   logo's margin. The centre column is capped at the measure, so the two side
   columns are equal by construction and the text can never be pushed off
   centre by the rail. */
.doc {
  --measure: 36rem;
  --rail: 13rem;
  --rail-gap: 2.5rem;
  --doc-pad-block: 20px;

  width: 100%;
  padding: var(--doc-pad-block) var(--edge);
  display: grid;
  /* minmax(0,…) so a wide table inside can scroll itself instead of pushing
     the whole page sideways */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: var(--s-3xl);
}

/* fluid up to the measure, centred below it — no fixed widths anywhere */
.doc > * {
  min-width: 0;
  width: 100%;
  max-width: var(--measure);
}

/* Only once the viewport fits the measure PLUS a rail on each side does the
   contents appear at all. Below that the page is nothing but the running text:
   on a phone a table of contents is a screenful of links between the reader
   and the first sentence, and the browser's own find-in-page does the job. */
.toc {
  display: none;
}

@media (min-width: 74rem) {
  .doc {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--measure)) minmax(0, 1fr);
    column-gap: var(--rail-gap);
    row-gap: var(--s-2xl);
    justify-items: stretch;
    align-items: start;
  }
  .doc__head,
  .doc__body {
    grid-column: 2;
    max-width: none;
  }
  /* Spans BOTH rows of the right-hand column — the title and the body. Pinned
     to the first row alone, a contents list taller than the title would stretch
     that row and push the copy down by its whole height. */
  .toc {
    display: block;
    grid-column: 1;
    grid-row: 1 / span 2;
    justify-self: start;
    align-self: start;
    width: 100%;
    max-width: var(--rail);
  }
}

.doc__head h1 {
  margin: 0;
  color: var(--ink);
  font-size: clamp(1.9rem, 5vw, 2.6rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.kicker {
  margin: 0 0 var(--s-md);
  color: var(--ink-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}

/* the "Effective / Version / Applies to" block each legal document opens with */
.doc__frontmatter {
  margin: 0 0 var(--s-2xl);
  color: var(--ink-muted);
  font-size: 14px;
  line-height: 1.5;
}

/* scoped under .doc__body so it outranks the generic paragraph spacing below;
   these three metadata lines belong together as one block */
.doc__body .doc__frontmatter p {
  margin: 0;
}

.doc__frontmatter strong {
  color: var(--ink);
  font-weight: 600;
}

/* an unfilled {{PLACEHOLDER}} that reached the page — loud on purpose */
mark.todo {
  background: rgba(245, 190, 63, 0.16);
  color: #F5BE3F;
  padding: 0.05em 0.3em;
  border-radius: 3px;
  font-size: 0.92em;
  font-weight: 600;
}

/* table of contents — generated by tools/build.py, so it is in the HTML and
   works with JavaScript off. Desktop only (see the layout block above). */
@media (min-width: 74rem) {
  .toc {
    position: sticky;
    /* level with the document's own top padding on first paint, then pinned */
    top: var(--doc-pad-block, 20px);
    border-left: 1px solid var(--hairline);
    padding: 2px 0 2px var(--s-lg);
    /* long policies have long tables of contents: scroll the rail, not the page */
    max-height: calc(100svh - var(--s-xl) * 2);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}

.toc__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-sm);
}

.toc__list a {
  position: relative;
  color: var(--ink-muted);
  text-decoration: none;
  font-size: 13.5px;
  line-height: 1.35;
  display: block;
  transition: color var(--dur-fast) var(--ease);
}

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

/* the section being read — set by assets/js/toc.js, so with JavaScript off the
   list is exactly what it was before: a plain, working set of links. The marker
   sits on the rail's own hairline rather than beside the text, so nothing in
   the list shifts when it moves. */
.toc__list a[aria-current] {
  color: var(--ink);
  font-weight: 600;
}

.toc__list a[aria-current]::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--s-lg) - 1px);
  top: -1px;
  bottom: -1px;
  width: 2px;
  background: var(--accent);
}

/* --- long-form legal copy -------------------------------------------------
   Styles the HTML that tools/build.py renders from content/*.md. */

/* the measure comes from the grid (--measure), not from a width here */
.doc__body {
  font-size: clamp(15.5px, 0.9rem + 0.25vw, 17px);
  line-height: 1.65;
  color: var(--ink-muted);
  overflow-wrap: break-word;
}

.doc__body :is(h1, h2, h3) {
  color: var(--ink);
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.doc__body h1 {
  font-size: clamp(1.9rem, 5vw, 2.6rem);
  font-weight: 700;
  line-height: 1.12;
  margin: 0 0 var(--s-lg);
}

.doc__body h2 {
  font-size: 1.32rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 2.4em 0 var(--s-md);
  scroll-margin-top: var(--s-3xl);
}

/* the first section already has the heading block above it */
.doc__body > *:first-child > h2:first-child,
.doc__body h2:first-child {
  margin-top: 0;
}

.doc__body h3 {
  font-size: 1.06rem;
  font-weight: 600;
  margin: 1.9em 0 var(--s-sm);
  scroll-margin-top: var(--s-3xl);
}

.doc__body :is(p, ul, ol) {
  margin: 0 0 1.15em;
}

.doc__body :is(ul, ol) {
  padding-left: 1.35em;
}

.doc__body li {
  margin-bottom: 0.5em;
}

.doc__body li::marker {
  color: var(--ink-faint);
}

.doc__body strong {
  color: var(--ink);
  font-weight: 600;
}

.doc__body a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent);
}

.doc__body hr {
  border: 0;
  border-top: 1px solid var(--hairline);
  margin: var(--s-3xl) 0;
}

.doc__body code {
  font-family: ui-monospace, "SF Mono", "IBM Plex Mono", Menlo, monospace;
  font-size: 0.88em;
  padding: 0.12em 0.36em;
  border-radius: 4px;
  background: var(--raised);
  color: var(--ink);
}

.doc__body blockquote {
  margin: 0 0 1.15em;
  padding-left: var(--s-lg);
  border-left: 2px solid var(--hairline);
  color: var(--ink-muted);
}

/* tables in a policy get wide; scroll the table, never the page. The rounded
   frame is the affordance: it shows where the scrollable region begins and
   ends, since CSS alone cannot signal "this scrolls". */
.doc__table {
  overflow-x: auto;
  margin: 0 0 1.5em;
  border: 1px solid var(--card-border);
  border-radius: var(--r-control);
  padding: 0 var(--s-md);
  -webkit-overflow-scrolling: touch;
}

/* the last row's rule would double up with the container border */
.doc__table tr:last-child :is(td, th) {
  border-bottom: 0;
}

.doc__body table {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
  margin: 0 0 1.5em;
}

.doc__table table {
  margin: 0;
}

/* No table stays a grid on a phone. A four-column table of prose (what data,
   from where, what for, on what legal basis) sliced into a 390px viewport is
   four words per line in every column — scrolling it sideways only spreads the
   problem out. Stacked, one block per row, each value keeps the heading of the
   column it came from and the row reads top to bottom. */
@media (max-width: 640px) {
  .doc__table--pairs :is(table, tbody, tr, td) {
    display: block;
    width: 100%;
  }

  .doc__table--pairs thead {
    display: none;
  }

  .doc__table--pairs tr {
    padding: var(--s-md) 0;
    border-bottom: 1px solid var(--hairline);
  }

  /* scoped under .doc__body to outrank the generic cell rule, which would
     otherwise draw a second divider between the label and its value */
  .doc__body .doc__table--pairs td {
    padding: 0;
    border: 0;
  }

  .doc__table--pairs td:first-child {
    color: var(--ink);
    font-weight: 600;
    margin-bottom: var(--s-xs);
  }

  .doc__table--pairs tr:last-child {
    border-bottom: 0;
  }

  /* three columns or more: the same stacking, but each row becomes a card and
     every value is announced by the heading of its column. The container's own
     frame goes — with nothing left to scroll it would be a box around boxes. */
  .doc__table--stack {
    overflow-x: visible;
    border: 0;
    border-radius: 0;
    padding: 0;
  }

  .doc__table--stack :is(table, tbody, tr, td) {
    display: block;
    width: 100%;
  }

  .doc__table--stack thead {
    display: none;
  }

  .doc__table--stack tr {
    padding: var(--s-lg);
    margin-bottom: var(--s-md);
    border: 1px solid var(--card-border);
    border-radius: var(--r-control);
  }

  .doc__table--stack tr:last-child {
    margin-bottom: 0;
  }

  .doc__body .doc__table--stack td {
    padding: 0;
    border: 0;
  }

  .doc__body .doc__table--stack td + td {
    margin-top: var(--s-md);
  }

  /* the first column is the row's subject: it titles the card */
  .doc__table--stack td:first-child {
    color: var(--ink);
    font-weight: 600;
  }

  .doc__table--stack td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 2px;
    color: var(--ink-faint);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.1px;
    text-transform: uppercase;
  }

  /* a blank cell stacked is a label answering nothing */
  .doc__table--stack td:empty {
    display: none;
  }

  /* A matrix (subject per row, verdict per column) stacks like the others, but
     its values are two characters wide — "✅", "—". Given a heading line of
     their own they would be four near-empty lines per card, so label and
     verdict share a line: question left, answer right, the way the eye reads a
     checklist. Longer answers ("Passes through AI providers") wrap in place. */
  .doc__table--matrix td[data-label] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    align-items: baseline;
    gap: var(--s-md);
    padding: var(--s-sm) 0;
    border-top: 1px solid var(--hairline);
  }

  .doc__body .doc__table--matrix td + td {
    margin-top: 0;
  }

  .doc__table--matrix td[data-label]::before {
    margin-bottom: 0;
  }

  .doc__table--matrix .cell {
    color: var(--ink);
    text-align: right;
  }

  .doc__table--matrix td:first-child {
    padding-bottom: var(--s-sm);
  }
}

/* the source centres these columns (`|---|:---:|`); at desk width the verdicts
   line up under their heading instead of hugging the prose to their left */
@media (min-width: 641px) {
  .doc__body .doc__table--matrix :is(th, td):not(:first-child) {
    text-align: center;
  }
}

/* Once the contents moves into its own rail, the column mirroring it on the
   right is empty by construction — it exists to keep the text centred. A
   five-column table is the one thing on the page that needs more room than the
   measure, so it borrows exactly that width. The measure is a rule about
   READING PROSE; a table is scanned, not read in lines. */
@media (min-width: 74rem) {
  .doc__body :is(.doc__table--stack, .doc__table--matrix) {
    margin-right: calc(-1 * (var(--rail) + var(--rail-gap)));
  }
}

.doc__body :is(th, td) {
  text-align: left;
  padding: var(--s-md);
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}

.doc__body th {
  color: var(--ink);
  font-weight: 600;
}

.doc__body address {
  font-style: normal;
}

/* --- masked contact details ----------------------------------------------
   tools/build.py breaks every address, company number and e-mail with decoy
   spans so a scraper reading the source finds junk where the pattern should
   be. `display: none` is what makes them invisible to the reader, to screen
   readers and to the clipboard — do not swap it for opacity, a zero size or an
   off-screen position, all of which leave the junk in the copied text and in
   what a screen reader announces. */
.mask__x {
  display: none;
}

/* mask.js turns a legible address into a working link; without it the address
   is still there and still correct, just not clickable */
.mask--mail a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent);
}

/* placeholder shown while the legal copy has not been written yet — delete the
   element and this rule stops applying to anything */
.doc__placeholder {
  border: 1px dashed var(--card-border);
  border-radius: var(--r-control);
  padding: var(--s-xl);
  color: var(--ink-faint);
  font-size: 14px;
}

/* --- reduced motion ------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* `animation: none` rather than a near-zero duration: with a duration hack
     plus fill-mode both, the element can settle on the keyframe's FROM state
     and the lockup renders invisible. Cancelling the animation outright leaves
     every element at its natural, painted state. */
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
