/* sadisa.app — the page.
 *
 * Everything is authored with CSS logical properties (margin-inline,
 * border-inline-start, padding-block) rather than left/right, so the Arabic
 * build mirrors correctly from dir="rtl" alone. There is no second stylesheet.
 *
 * No animation exists that prefers-reduced-motion would need to strip except the
 * two below, and both are removed wholesale at the end of this file. No parallax,
 * no scroll-jacking, no autoplay: the brief forbids them and they are a real
 * accessibility problem for this audience, not a style preference.
 */

@import url('./fonts.css');

/* ------------------------------------------------------------------ reset */

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

html {
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
  /* Anchor links land below the sticky header instead of under it. */
  scroll-padding-block-start: 5rem;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: 'Source Sans 3', 'Noto Sans Arabic', 'Noto Sans Devanagari',
               /* CJK is served from the reader's own system fonts: a self-hosted
                  CJK face is several megabytes, and every device that reads these
                  scripts already ships a good one. */
               'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Yu Gothic',
               'Microsoft YaHei', 'PingFang SC', 'Malgun Gothic',
               system-ui, sans-serif;
  font-size: 1.0625rem;          /* 17px — the brief's floor */
  line-height: 1.6;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
}

@media (min-width: 40rem) { body { font-size: 1.125rem; } }  /* 18px */

img { max-width: 100%; height: auto; }

/* --------------------------------------------------------------- headings */

h1, h2, h3 {
  font-family: 'Fraunces', 'Source Serif 4', Georgia, serif;
  /* Fraunces is variable on optical size and weight. A low SOFT/WONK keeps it
     warm without turning novelty — the brief asks for character, not costume. */
  font-variation-settings: 'SOFT' 30, 'WONK' 0;
  font-weight: 600;
  line-height: 1.15;
  text-wrap: balance;
  margin: 0;
  letter-spacing: -0.011em;
}

h1 {
  /* Trimmed 2026-09-13 from a 4.9rem ceiling. At 4.9rem the headline set in
     FOUR lines inside a 35rem column, so the reader met a wall of type and the
     conversation — the one piece of proof on the page — was pushed to the
     margin. 3.35rem holds the same sentence in three. The ceiling is doing the
     work here, not the max-inline-size: the wrap is capped at 72rem, so a
     22ch guard would never fire. */
  font-size: clamp(2.15rem, 1.55rem + 3.1vw, 3.35rem);
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  letter-spacing: -0.021em;
}

/* h2 was 3rem against 18px body — a top-heavy scale where every section
   shouted and everything inside it whispered. 2.35rem keeps the mastheads
   clearly above their content without drowning the copy they introduce. */
h2 { font-size: clamp(1.65rem, 1.3rem + 1.5vw, 2.35rem); }
h3 { font-size: 1.4rem; line-height: 1.25; }

p { margin: 0; }

/* Latin-only display face. For Greek, Cyrillic and every other script Fraunces
   does not cover, the @font-face unicode-ranges in fonts.css hand off to
   Source Serif 4 automatically — hence its position in the stack above. */

/* --------------------------------------------------------------- measure */

.wrap {
  width: min(100% - 3rem, 72rem);
  margin-inline: auto;
}

/* The measure constrains PARAGRAPHS, not the page. Applying it to layout was
   what left two-thirds of a desktop screen empty and made the whole thing read
   as unfinished rather than airy. */
.section__lead, .does__item p, .claims p, .facts dd, .demo__caption,
.hero__sub, .close__body p { max-width: var(--measure); }

/* Body text never exceeds ~68 characters. Long reading with a tired brain is
   the actual use case; measure is doing more work here than it usually does. */
:root { --measure: 27em; }   /* measured: worst rendered line is 68 characters */
.measure { max-width: var(--measure); }

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 10;
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
  backdrop-filter: blur(10px);
  border-block-end: 1px solid var(--divider);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: 0.7rem;
}

.wordmark {
  font-family: 'Fraunces', 'Source Serif 4', Georgia, serif;
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-weight: 600;
  font-size: 1.15rem;
  letter-spacing: -0.015em;
  color: var(--text);
  text-decoration: none;
  margin-inline-end: auto;
}

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

/* The mark, when assets/logo.* is present. alt="" because the adjacent word
   "Sadisa" already names the link — announcing it twice is noise to a screen
   reader, not extra information. */
.wordmark__mark {
  width: 1.75rem;
  height: 1.75rem;
  margin-inline-end: 0.55rem;
  flex: none;
  color: var(--accent);   /* the SVG draws in currentColor, so it follows the theme */
}

/* ------------------------------------------------------------------ hero */

.hero {
  /* 6.5rem of top padding put the first line of the page 104px below a sticky
     header that already eats 60px. This is a page someone reads on a bad day;
     the headline should start near the top of it. */
  padding-block: clamp(2.25rem, 1.5rem + 3.4vw, 4.5rem) clamp(2.75rem, 2rem + 3vw, 4.5rem);
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  align-items: start;
}

/* Asymmetric on purpose: the argument gets more room than the evidence, and the
   two columns are deliberately unequal so the page does not read as a template. */
@media (min-width: 62rem) {
  .hero { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); align-items: center; }
}

.hero h1 { margin-block-end: 1.5rem; }

.hero__sub {
  font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem);
  line-height: 1.5;
  color: var(--muted);
  max-width: 26em;
}

/* The one place `warm` appears on the page. The brief allows one element per
   screen; spending it on the eyebrow gives the greens something to be green
   against without raising the overall volume. */
.eyebrow {
  display: block;
  font-size: 0.83rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--warm);
  margin-block-end: 1.4rem;
}

.hero__cta { margin-block-start: 2.5rem; display: flex; flex-wrap: wrap; gap: 0.9rem 1.4rem; align-items: center; }

/* --------------------------------------------------------------- buttons */

/* Every interactive target is at least 44px on its smaller axis.
   WCAG 2.2 AA only asks for 24px, but the brief is explicit that accessibility
   here is the audience rather than a compliance exercise, and motor-coordination
   differences co-occur heavily with ADHD and autism. 44px is the honest floor. */
.btn, .theme-toggle, .lang > summary, .wordmark, .site-footer nav a {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font: inherit;
  font-weight: 600;
  padding: 0.72rem 1.35rem;
  border-radius: 0.6rem;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.btn--primary { background: var(--accent); color: var(--accentInk); }
.btn--primary:hover { background: color-mix(in srgb, var(--accent) 86%, var(--text)); }
.btn--primary:active { background: color-mix(in srgb, var(--accent) 74%, var(--text)); }

/* `--inputBorder` is calibrated against `--input` (3.23:1 light / 3.06 dark), NOT
   against `--canvas` — on canvas it is 2.86:1 and fails WCAG 1.4.11. A quiet
   button has a transparent fill, so canvas IS its adjacent colour and its border
   is the only thing identifying it as a control. It therefore uses `--muted`
   (5.15:1 light / 7.59:1 dark on canvas). Using inputBorder here was a misuse of
   the token, not a flaw in it. */
.btn--quiet {
  background: transparent;
  color: var(--text);
  border-color: var(--muted);
}
.btn--quiet:hover { background: var(--chrome); border-color: var(--text); }
.btn--quiet:active { background: var(--divider); }

/* Disabled is distinguishable without colour: the dashed edge and the
   not-allowed cursor both survive greyscale and both survive a colour
   deficiency. Opacity alone would not. */
.btn:disabled, .btn[aria-disabled='true'] {
  background: transparent;
  color: var(--muted);
  border-style: dashed;
  border-color: var(--inputBorder);
  cursor: not-allowed;
}

/* --------------------------------------------------------------- focus */

/* One visible ring everywhere, in `accent` — verified 4.70:1 light,
   9.50:1 dark. The offset keeps it legible against a filled button. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 0.35rem;
}

/* --------------------------------------------------------------- links */

a { color: var(--accent); text-underline-offset: 0.18em; text-decoration-thickness: 0.06em; }
a:hover { text-decoration-thickness: 0.12em; }

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

/* -------------------------------------------------------------- sections */

.section { padding-block: clamp(3.5rem, 2rem + 5vw, 6.5rem); }
.section + .section:not(.band) { border-block-start: 1px solid var(--divider); }

/* Heading and lead sit side by side on wide screens — an editorial masthead
   rather than another centred stack. */
.section__head { display: grid; gap: 0.9rem; margin-block-end: clamp(2.25rem, 4vw, 3.25rem); }
@media (min-width: 62rem) {
  .section__head { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 2.5rem; align-items: end; }
  .section__head h2 { margin-block-end: 0; }
}
.section__lead { color: var(--muted); margin: 0; }

/* ------------------------------------------------------------- does-list */

.does { margin-block-start: 2.75rem; display: grid; gap: 1.6rem; }
@media (min-width: 48rem) { .does { grid-template-columns: repeat(3, 1fr); gap: 1.4rem; } }

.does__item {
  background: var(--chrome);
  border: 1px solid var(--divider);
  border-radius: 0.85rem;
  padding: 1.4rem 1.35rem;
}

.does__item h3 { margin-block-end: 0.55rem; }
.does__item p { color: var(--muted); font-size: 0.98rem; max-width: var(--measure); }

/* ------------------------------------------------------------ claim list */

/* The not-punishing claims. A hanging rule instead of bullets — this is the
   part a sceptic actually reads, and it should look like statements, not
   features. */
.claims { margin-block-start: 2.5rem; display: grid; gap: 1.9rem; list-style: none; padding: 0; }

.claims li {
  border-inline-start: 2px solid var(--accent);
  padding-inline-start: 1.25rem;
  /* The brief asks for a measure under 70 characters and means it: this is long
     reading with a tired brain. .wrap alone is 46rem, which runs to ~100. */
  max-width: var(--measure);
}

.claims strong {
  display: block;
  font-family: 'Fraunces', 'Source Serif 4', Georgia, serif;
  font-variation-settings: 'SOFT' 30, 'WONK' 0;
  font-size: 1.2rem;
  font-weight: 600;
  line-height: 1.3;
  margin-block-end: 0.4rem;
}

.claims p { color: var(--muted); }

/* ---------------------------------------------------------- conversation */

/* The palette applied to real elements — deliverable 3. These are the app's
   own bubble tokens at the app's own separation (1.61:1 light), not swatches. */

.demo {
  margin-block-start: 2.5rem;
  background: var(--chrome);
  border: 1px solid var(--divider);
  border-radius: 1rem;
  padding: 1.35rem 1.2rem;
}

.demo__caption {
  max-width: var(--measure);
  font-size: 0.85rem;
  color: var(--muted);
  margin-block-end: 1.1rem;
  padding-inline-start: 0.15rem;
}

.thread { display: grid; gap: 0.7rem; }

.bubble {
  /* The one text block the measure pass missed: these ran to 81 characters
     (84 in German), well over the brief's 70. */
  max-width: min(82%, var(--measure));
  padding: 0.7rem 0.95rem;
  border-radius: 1.05rem;
  border: 1px solid;
  font-size: 1rem;
  line-height: 1.5;
}

.bubble--agent {
  background: var(--agentBubble);
  border-color: var(--agentBorder);
  border-end-start-radius: 0.3rem;
  justify-self: start;
}

.bubble--user {
  background: var(--userBubble);
  border-color: var(--userBorder);
  border-end-end-radius: 0.3rem;
  justify-self: end;
}

/* The quiet empty state. The brief is explicit that an all-tasks-complete
   screenshot is the productivity-app lie in visual form; this is what the app
   shows when there is nothing, and it says nothing about it. */
.empty {
  margin-block-start: 1.5rem;
  border: 1px dashed var(--inputBorder);
  border-radius: 0.85rem;
  padding: 2rem 1.25rem;
  text-align: center;
  color: var(--muted);
  background: var(--canvas);
}

.empty p { font-size: 0.98rem; }

/* A real input, in its real states — the third deliverable asks for the palette
   on interface, and a field with no visible edge was the bug the token set fixes. */
.field {
  margin-block-start: 1.1rem;
  display: flex;
  gap: 0.6rem;
}

.field input {
  flex: 1;
  font: inherit;
  font-size: 1rem;
  padding: 0.65rem 0.85rem;
  color: var(--text);
  background: var(--input);
  border: 1px solid var(--inputBorder);   /* 3.23:1 / 3.06:1 — the whole point */
  border-radius: 0.6rem;
  min-width: 0;
}

.field input::placeholder { color: var(--muted); opacity: 1; }

/* ---------------------------------------------------------------- panels */

.panel {
  margin-block-start: 2.25rem;
  background: var(--chrome);
  border: 1px solid var(--divider);
  border-radius: 0.9rem;
  padding: 1.5rem 1.4rem;
}

.panel h3 { margin-block-end: 0.6rem; }

/* Used only where something is genuinely unresolved and must not read as a
   settled claim. Warm carries text at 5.23:1 light / 8.04:1 dark, and the
   dashed edge means it is distinguishable without colour. */
.panel--open {
  background: var(--warmSoft);
  border: 1px dashed var(--warm);
}
.panel--open h3 { color: var(--warm); }

.facts { margin: 0; display: grid; gap: 1.1rem; }
.facts > div { max-width: var(--measure); }
.facts dt { font-weight: 600; margin-block-end: 0.2rem; }
.facts dd { margin: 0; color: var(--muted); }

/* ----------------------------------------------------------------- prose */

.prose { max-width: var(--measure); }
.prose > * + * { margin-block-start: 1.15rem; }
.prose h2 { margin-block-start: 2.75rem; }
.prose h3 { margin-block-start: 2rem; }
.prose ul { padding-inline-start: 1.25rem; }
.prose li + li { margin-block-start: 0.5rem; }
.prose table { border-collapse: collapse; width: 100%; font-size: 0.97rem; }
.prose th, .prose td {
  text-align: start;
  padding: 0.6rem 0.7rem;
  border-block-end: 1px solid var(--divider);
  vertical-align: top;
}
.prose th { font-weight: 600; }

/* Wide content scrolls inside its own box; the page body never scrolls sideways. */
.scroll-x {
  overflow-x: auto;
  inline-size: 100%;
  max-inline-size: 100%;
  contain: inline-size;
}

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

.site-footer {
  border-block-start: 1px solid var(--divider);
  padding-block: 2.75rem 3.5rem;
  color: var(--muted);
  /* 0.95rem made the operator and the two legal routes the smallest text on the
     page. The company that makes the thing should not be the footnote. */
  font-size: 1rem;
}

.site-footer nav { display: flex; flex-wrap: wrap; gap: 0.6rem 1.4rem; margin-block-end: 1.5rem; }
.site-footer a { color: var(--text); }
.site-footer a:hover { color: var(--accent); }

/* ------------------------------------------------------- language picker */

.lang { position: relative; }




/* The theme toggle is the only script on the page. Without JS it is absent
   rather than broken, and the OS preference still drives the palette. */
.theme-toggle {
  font: inherit;
  font-size: 0.88rem;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  /* --muted, not --inputBorder: this sits on the canvas-tinted header, where
     inputBorder is 2.86:1 and fails WCAG 1.4.11. Set on the SHORTHAND, because
     a border-color declaration earlier in the file was silently overridden by
     this rule and the fix did nothing. */
  border: 1px solid var(--muted);
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.theme-toggle:hover { border-color: var(--text); }

/* ------------------------------------------------------------ skip link */

.skip {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.skip:focus {
  width: auto;
  height: auto;
  margin: 0;
  clip: auto;
  overflow: visible;
  inset-inline-start: 0;
  top: 0;
  background: var(--accent);
  color: var(--accentInk);
  padding: 0.7rem 1.1rem;
  border-radius: 0 0 0.5rem 0;
  z-index: 20;
}

@media (max-width: 30rem) {
  .prose h1 { overflow-wrap: anywhere; }
  .scroll-x table { table-layout: fixed; min-width: 0; }
  .scroll-x th, .scroll-x td { overflow-wrap: anywhere; }
}

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

/* Respected fully, per the brief — not softened. The only two transitions on
   the page are the button colour fades above; both go to zero. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------- forced colors */

@media (forced-colors: active) {
  .btn, .field input, .panel, .does__item, .bubble { border: 1px solid; }
  :where(a, button):focus-visible { outline: 3px solid; }
}

/* ------------------------------------------------- language menu (links) */

/* Replaces a <select> that navigated on change — a WCAG 3.2.2 (On Input)
   violation which also fired on every option a keyboard user arrowed past,
   needed JavaScript, and could not mark each option's own language. */

.lang { position: relative; }

.lang > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--muted);
  /* Transparent, not --input. A filled, field-coloured box beside a serif
     wordmark reads as an unstyled form control, which is what the header
     looked like. The pill stays recognisable as something pressable while
     sitting quieter than the page behind it. */
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font-size: 0.88rem;
  white-space: nowrap;
}

.lang > summary::-webkit-details-marker { display: none; }
.lang > summary::after { content: '▾'; font-size: 0.8em; opacity: 0.8; }
.lang > summary:hover { border-color: var(--text); }

.lang__menu {
  position: absolute;
  inset-inline-end: 0;
  inset-block-start: calc(100% + 0.4rem);
  z-index: 30;
  margin: 0;
  padding: 0.4rem;
  list-style: none;
  background: var(--chrome);
  border: 1px solid var(--divider);
  border-radius: 0.7rem;
  box-shadow: 0 8px 28px rgb(0 0 0 / 0.14);
  max-height: min(70vh, 30rem);
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.1rem;
  width: max-content;
  max-width: min(90vw, 34rem);
}

.lang__menu a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.3rem 0.7rem;
  border-radius: 0.4rem;
  color: var(--text);
  text-decoration: none;
  font-size: 0.95rem;
}

.lang__menu a:hover { background: var(--canvas); }
.lang__menu a[aria-current='true'] { font-weight: 600; color: var(--accent); }
/* Current language is marked by weight AND a leading rule, never colour alone. */
.lang__menu a[aria-current='true']::before {
  content: '';
  inline-size: 2px;
  block-size: 1.1em;
  background: var(--accent);
  margin-inline-end: 0.5rem;
}

/* ------------------------------------------------------- draft artefacts */

/* Classes rather than inline style attributes: the generated CSP sets
   style-src 'self', which blocks every inline style attribute — so the spacing
   they used to set was being silently dropped in production. */

.draft-banner {
  background: var(--warmSoft);
  border-block-end: 2px dashed var(--warm);
  color: var(--text);
  padding: 1rem 1.25rem;
  font-size: 0.92rem;
}
.draft-banner > .wrap > strong { color: var(--warm); }
.draft-banner ul { margin: 0.6rem 0 0; padding-inline-start: 1.1rem; }

mark {
  background: var(--warmSoft);
  color: var(--warm);
  border: 1px dashed var(--warm);
  padding: 0 0.3em;
  font-weight: 600;
}

.facts { margin-block-start: 2.25rem; }
.cta-row { margin-block-start: 1.75rem; }

/* The language menu lists all 36 endonyms on every page, which pulled the
   self-hosted Arabic and Devanagari faces (~287 KB) into every single page load
   just to draw two menu labels. Those two labels fall back to the reader's own
   system fonts instead — any device that can display Arabic or Devanagari
   already ships a face for it. The self-hosted files still serve the /ar/ and
   /hi/ pages themselves, where the whole document is in that script. */
.lang__menu a:lang(ar),
.lang__menu a:lang(hi) {
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
}

/* On a narrow screen the menu is wider than the space between its anchor and the
   edge, so anchoring it to the summary pushed its left edge off-screen (measured
   -32px at 375px) and part of the list became unreachable. Below 30rem it
   detaches from the anchor and spans the viewport instead. */
@media (max-width: 30rem) {
  .lang__menu {
    position: fixed;
    inset-inline: 0.75rem;
    inset-block-start: 4.6rem;
    width: auto;
    max-width: none;
    max-height: min(60vh, 24rem);
  }
}

/* ============================================================ composition */

/* --- the three things: numbered, editorial --- */

.does {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.75rem, 3vw, 2.75rem);
}
@media (min-width: 44rem) { .does { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 66rem) { .does { grid-template-columns: repeat(3, 1fr); } }

.does__item {
  /* The editorial row this was always meant to be. The component default above
     sets `border: 1px solid` as a SHORTHAND; overriding only `border-block-start`
     here left the other three edges standing, so every row still rendered as a
     rounded card — the composition layer was drawing boxes and its own comment
     said rules. Reset the box, then draw the one hairline. */
  border: 0;
  border-block-start: 1px solid var(--divider);
  padding: 0;
  padding-block-start: 1.25rem;
  background: none;
  border-radius: 0;
}

/* The numeral is the largest thing in the card and sets the row's rhythm. */
.does__n {
  display: block;
  font-family: 'Fraunces', 'Source Serif 4', Georgia, serif;
  font-variation-settings: 'SOFT' 40, 'WONK' 1;
  font-size: 2.6rem;
  line-height: 1;
  color: var(--accent);
  margin-block-end: 0.6rem;
  font-feature-settings: 'tnum';
}

.does__item h3 { margin-block-end: 0.5rem; }
.does__item p { color: var(--muted); font-size: 1rem; }

/* --- the conversation, promoted to hero evidence --- */

.demo {
  margin: 0;
  background: var(--chrome);
  border: 1px solid var(--divider);
  border-radius: 1.1rem;
  padding: clamp(1.1rem, 2.5vw, 1.6rem);
}

.thread { display: grid; gap: 0.75rem; }

.demo__caption {
  margin-block-start: 1.1rem;
  padding-block-start: 0.9rem;
  border-block-start: 1px solid var(--divider);
  /* Provenance, not small print: this label is what keeps the drawing from
     reading as a captured screenshot, so it has to be legible rather than
     apologetic and tiny. */
  font-size: 0.95rem;
  color: var(--muted);
}

/* --- the one inverted, full-bleed band --- */

/* Full-bleed without a wrapper element, and RTL-safe. */
.band {
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
  background: var(--canvas);
  color: var(--text);
}

/* Applies the OPPOSITE theme's tokens locally. Same palette, inverted ground —
   the page's single moment of contrast, and the only thing that breaks the
   rhythm. In dark mode it flips back to light so it stays a contrast moment
   rather than disappearing into the surrounding page. */
.band {
  --canvas: #0F1412;
  --chrome: #151B18;
  --text: #F1F4F2;
  --muted: #9AA9A2;
  /* Aligned with tokens.css 2026-09-13. This block still carried #4FD08A, the
     dark accent the palette moved OFF: it sat 6.4° from WhatsApp's brand green
     at the same lightness. Nothing in the band uses --accent today, which is
     exactly how a rejected value survives in a stylesheet — the next element
     someone drops in there would have inherited it. */
  --accent: #7FC9A4;
  --accentInk: #08160E;
  --warm: #E8985C;
  --divider: #29312E;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .band {
    --canvas: #F4F1EA;
    --chrome: #FCFAF5;
    --text: #1B2420;
    --muted: #5C6862;
    --accent: #1F7A52;
    --accentInk: #FFFFFF;
    --warm: #A8461B;
    --divider: #DAD6CB;
  }
}
:root[data-theme='dark'] .band {
  --canvas: #F4F1EA;
  --chrome: #FCFAF5;
  --text: #1B2420;
  --muted: #5C6862;
  --accent: #1F7A52;
  --accentInk: #FFFFFF;
  --warm: #A8461B;
  --divider: #DAD6CB;
}

/* --- the claims: big typographic statements, not a bulleted list --- */

.claims {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 55rem) { .claims { grid-template-columns: repeat(2, 1fr); gap: 3rem 4rem; } }
.claims { max-width: 62rem; }

.claims li { border: 0; padding: 0; }

.claims h3 {
  font-size: clamp(1.35rem, 1.1rem + 0.9vw, 1.75rem);
  margin-block-end: 0.6rem;
  text-wrap: balance;
}

.claims p { color: var(--muted); }

/* --- section mastheads share their section's own column axis --- */

/* A section lead is an introduction to the grid underneath it, so it has to sit
   ON that grid. It did not. The masthead split the wrap 0.9fr / 1.1fr with a
   2.5rem gap, putting the lead's left edge at 46.9% of the wrap, while `.facts`
   splits it 1fr / 1fr with a 4rem gap and starts its second column at 52.8%.
   Nearly-aligned is worse than plainly unaligned: 4.2rem of offset reads as a
   mistake rather than as a decision, and the page's whole argument is that
   somebody thought carefully about it.

   So each section declares the axis its own content uses, and the head inherits
   it. The default stays the editorial 0.9 / 1.1 for sections whose content is a
   single column, where there is no content axis to agree with. */
.section {
  --head-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  --head-column-gap: 2.5rem;
  --head-lead-column: 2;
  --head-lead-end: -1;
}

@media (min-width: 62rem) {
  .section__head {
    grid-template-columns: var(--head-columns);
    column-gap: var(--head-column-gap);
    /* Box-bottom alignment left the lead floating below the heading's last
       line by the heading's descender space. Aligning the LAST baselines puts
       the lead exactly on the heading's final baseline, which is what a
       masthead is meant to do. `end` stays as the fallback for engines without
       last-baseline support — the layout it produces is the one shipped until
       now, so the fallback is not a regression. */
    align-items: end;
    align-items: last baseline;
  }
  .section__head .section__lead {
    grid-column: var(--head-lead-column) / var(--head-lead-end);
  }
}

/* `.facts` is two equal columns from 55rem; the head follows at the same
   breakpoint so the two axes are never briefly different. */
@media (min-width: 55rem) {
  .section--data {
    --head-columns: repeat(2, 1fr);
    --head-column-gap: 4rem;
  }
  .section--data .section__head {
    grid-template-columns: var(--head-columns);
    column-gap: var(--head-column-gap);
  }
  .section--data .section__head .section__lead { grid-column: 2 / -1; }
}

/* `.does` is two columns from 44rem and three from 66rem, with its own gap. The
   lead spans from the second column to the end in both cases, so it starts on a
   real column edge instead of near one. */
@media (min-width: 44rem) {
  .section--does {
    --head-columns: repeat(2, 1fr);
    --head-column-gap: clamp(1.75rem, 3vw, 2.75rem);
  }
  .section--does .section__head {
    grid-template-columns: var(--head-columns);
    column-gap: var(--head-column-gap);
  }
  .section--does .section__head .section__lead { grid-column: 2 / -1; }
}
@media (min-width: 66rem) {
  .section--does { --head-columns: repeat(3, 1fr); }
}

/* --- price + data --- */

.facts { margin: 0; display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }
@media (min-width: 55rem) { .facts { grid-template-columns: repeat(2, 1fr); gap: 2.5rem 4rem; } }
.facts dt { font-weight: 600; margin-block-end: 0.35rem; font-size: 1.06rem; }
.facts dd { margin: 0; color: var(--muted); }

/* The price is the one fact a visitor came for, and it was set at 1.06rem in a
   list of four sentences of equal weight — findable only by reading. It gets the
   display face at masthead scale, and it keeps its sentence: the figure alone
   does not say monthly, including VAT, billed in euro. This costs no new
   translation, because the string it promotes already said all three. */
.facts__item--price dt {
  font-family: 'Fraunces', 'Source Serif 4', Georgia, serif;
  font-variation-settings: 'SOFT' 30, 'WONK' 0;
  font-size: clamp(1.8rem, 1.35rem + 1.6vw, 2.4rem);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin-block-end: 0.6rem;
}
/* No size on the price's explanation. It had 1.05rem, which was meant as "5%
   larger than its neighbours" and rendered as 7% SMALLER: rem is relative to the
   root (16px), while every other `dd` in this row inherits the body's 18px. Two
   definitions standing side by side at 16.8px and 18px read as an accident,
   because they were one. The price's sentence is the commercial qualifier
   (monthly, VAT included, billed in euro), so it is the last text on the page
   that should have been the smallest. */

/* --- closing section --- */

.close { display: grid; gap: 1.25rem; }
@media (min-width: 62rem) {
  .close { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 2.5rem; align-items: start; }
}
.close__body > * + * { margin-block-start: 1.1rem; }
.section--close { padding-block-end: clamp(4rem, 7vw, 7rem); }

/* The line under the call to action. The only ask on a page that spends 600
   words promising there is nothing to fill in should say what happens next —
   otherwise the reader supplies a silent waiting list of their own. */
.hero__note {
  margin-block-start: 1rem;
  font-size: 1rem;
  color: var(--muted);
  max-width: var(--measure);
}

/* The page used to stop rather than close. */
.close__sign {
  margin-block-start: 1.75rem;
  padding-block-start: 1.25rem;
  border-block-start: 1px solid var(--divider);
  color: var(--muted);
  font-size: 1rem;
  max-width: var(--measure);
}

/* The ask, repeated at the foot of the page. The hero carries the only call to
   action, 600 words above the point where a reader who was convinced reaches
   it — so a convinced reader had to scroll back up to act. Same intent and the
   same label as the hero (a second wording for one intent is its own defect),
   reusing the string rather than minting a 37th translation. */
.close__ask {
  margin-block-start: 2rem;
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--divider);
}
