/*
 * Kutumb — site styles.
 *
 * The palette and the three typographic voices are lifted directly from the app
 * (ui/theme/Color.kt, ui/theme/Type.kt) so the site and the product read as the same
 * object. Brass keeps the single job it has in the app: marking what is not known.
 *
 * Both palettes are the app's own — bone and forest ink by day, the app's night ground and
 * sage by night — so the site, the viewer (playground/playground.css, playground/chart.js)
 * and the product are recognisably one thing in either mode.
 *
 * Roles, not just colours. A handful of tokens below name a *job* rather than a hue
 * (--on-forest, --on-sage, --forest-hover, --deep) because those jobs do not map onto the
 * same colour in both modes: forest is a dark green carrying white text by day, and sage is
 * a pale green carrying dark green text by night. Rules further down ask for the role, so
 * they never need to know which mode they are in.
 */

:root {
  color-scheme: light;

  --bone: #f7f6f1;
  --bone-raised: #fffffe;
  --bone-dim: #efeee7;
  --bone-sunk: #e9e8e1;

  --ink: #1a1c1a;
  --ink-soft: #414942;
  --ink-faint: #656d65;   /* 4.6:1 on the sunk band, the lowest-contrast ground it lands on */

  --forest: #2a5138;
  --forest-deep: #0c2417;
  --sage: #cde6d5;
  --sage-line: #5e8c6d;

  --brass: #8a6420;
  --brass-surface: #f7eedc;

  --rule: #c1c9c0;
  --rule-strong: #9aa69b;

  /* Roles. See the note above. */
  --forest-hover: var(--forest-deep);   /* the pressed/hover shade of the accent */
  --on-forest: #fff;                    /* ink on a forest ground: the CTA, the primary button */
  --on-sage: var(--forest-deep);        /* ink on a sage ground: a named card, a step number */

  /* The wordmark tile. A launcher icon, so it holds its colour across both modes. */
  --mark-tile: #2a5138;
  --mark-line: #cde6d5;
  --mark-dash: #e3c38c;

  /* The "local first" slab is a dark green panel in both modes; only its ground shifts. */
  --deep: var(--forest-deep);
  --deep-ink: #dfe7e0;
  --deep-ink-soft: #b3c4b8;
  --deep-faint: #8fa694;
  --deep-rule: rgba(179, 196, 184, .22);
  --deep-hair: #c1c9c0;    /* the rule-label's hairline; --rule is tuned for the page, not this band */
  --deep-brass: #f7eedc;   /* the "no" prefix; --brass-surface goes dark and would vanish here */
  --deep-btn-line: #4a6a55;
  --deep-btn-ink: #cde6d5;

  /* The install page's one warning box. */
  --notice-line: #e3c38c;
  --notice-ink: #4a3810;
  --notice-strong: #2c1d00;

  --shadow-soft: 0 1px 2px rgba(12, 36, 23, .04);
  --shadow-cast: 0 12px 32px -18px rgba(12, 36, 23, .22);
  --shadow-disc: 0 6px 20px rgba(12, 36, 23, .28);

  --serif: "Literata", Georgia, "Times New Roman", serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --gutter: clamp(20px, 5vw, 64px);
  --measure: 1220px;

  /* The toggle offers the mode you are not in, so the glyph is the opposite of the ground. */
  --glyph-moon: block;
  --glyph-sun: none;
}

/*
 * Night.
 *
 * Two entry points, one palette, so the block is written twice and the two copies must be
 * kept identical — edit one, edit the other. The media query is what a reader with a dark
 * system and no stored choice gets (it is also the whole of dark mode with JavaScript off);
 * the attribute is what the masthead toggle sets. `:not([data-theme="light"])` is what lets
 * an explicit "light" win over a dark system.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bone: #10150f;
    --bone-raised: #1a211a;
    --bone-dim: #181d17;
    --bone-sunk: #0b100a;

    --ink: #e0e4dd;
    --ink-soft: #c1c9c0;
    --ink-faint: #8b938a;   /* 5.4:1 on the dim band, the lowest-contrast ground it lands on */

    --forest: #8fc7a1;
    --forest-deep: #0c2417;
    --sage: #24402e;
    --sage-line: #8fc7a1;

    --brass: #e3c38c;
    --brass-surface: #2c2618;

    --rule: #333c33;
    --rule-strong: #5c665c;

    --forest-hover: #b6dbc3;
    --on-forest: #06371c;
    --on-sage: #abe4bc;

    --mark-tile: #2f5c3f;

    --deep: #132b1c;

    --notice-line: #5e4100;
    --notice-ink: #e8dcc4;
    --notice-strong: #ffdea8;

    --shadow-soft: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow-cast: 0 14px 34px -18px rgba(0, 0, 0, .75);
    --shadow-disc: 0 6px 20px rgba(0, 0, 0, .55);

    --glyph-moon: none;
    --glyph-sun: block;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bone: #10150f;
  --bone-raised: #1a211a;
  --bone-dim: #181d17;
  --bone-sunk: #0b100a;

  --ink: #e0e4dd;
  --ink-soft: #c1c9c0;
  --ink-faint: #8b938a;   /* 5.4:1 on the dim band, the lowest-contrast ground it lands on */

  --forest: #8fc7a1;
  --forest-deep: #0c2417;
  --sage: #24402e;
  --sage-line: #8fc7a1;

  --brass: #e3c38c;
  --brass-surface: #2c2618;

  --rule: #333c33;
  --rule-strong: #5c665c;

  --forest-hover: #b6dbc3;
  --on-forest: #06371c;
  --on-sage: #abe4bc;

  --mark-tile: #2f5c3f;

  --deep: #132b1c;

  --notice-line: #5e4100;
  --notice-ink: #e8dcc4;
  --notice-strong: #ffdea8;

  --shadow-soft: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow-cast: 0 14px 34px -18px rgba(0, 0, 0, .75);
  --shadow-disc: 0 6px 20px rgba(0, 0, 0, .55);

  --glyph-moon: none;
  --glyph-sun: block;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.65;
  font-variant-numeric: oldstyle-nums;
  -webkit-font-smoothing: antialiased;
}

.shell {
  max-width: var(--measure);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

a { color: var(--forest); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 2px solid var(--forest);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------------------------------------------------------------- masthead */

.masthead {
  border-bottom: 1px solid var(--rule);
  background: var(--bone);
  position: sticky;
  top: 0;
  z-index: 20;
}
.masthead .shell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 62px;
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-decoration: none;
}
.wordmark svg { display: block; }

.masthead nav {
  display: flex;
  align-items: center;
  gap: 26px;
  font-family: var(--sans);
  font-size: 14px;
}
.masthead nav a {
  color: var(--ink-soft);
  text-decoration: none;
}
.masthead nav a:hover { color: var(--forest); text-decoration: underline; }
.masthead .nav-cta {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  color: var(--on-forest);
  background: var(--forest);
  padding: 8px 16px;
  border-radius: 999px;
  text-decoration: none;
}
.masthead .nav-cta:hover { background: var(--forest-hover); text-decoration: none; }
@media (max-width: 620px) {
  .masthead nav .nav-link { display: none; }
}

/* -------------------------------------------------------- the download menu */
/*
 * Download names the systems before it starts anything. The button is a scripted control, so
 * like the theme toggle it only appears once the head script has marked the page as scripted;
 * until then — or for good, with JavaScript off — the plain link to #get stands in for it.
 */

.dl-menu { position: relative; display: flex; }
.dl-toggle { display: none; }
:root[data-js] .dl-fallback { display: none; }
:root[data-js] .dl-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 0;
  cursor: pointer;
  line-height: 1.3;
}
.dl-chevron { display: block; transition: transform .15s ease; }
.dl-toggle[aria-expanded="true"] .dl-chevron { transform: rotate(180deg); }
.masthead .dl-toggle[aria-expanded="true"] { background: var(--forest-hover); }

.dl-panel {
  position: absolute;
  top: calc(100% + 12px);
  right: 0;
  width: min(360px, calc(100vw - 2 * var(--gutter)));
  line-height: 1.4;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 16px;
  background: var(--bone-raised);
  box-shadow: var(--shadow-cast), var(--shadow-soft);
}
/* On a phone the button sits against the right gutter, so the panel takes the width between both. */
@media (max-width: 620px) {
  .dl-panel { position: fixed; top: 70px; left: 16px; right: 16px; width: auto; }
}
@media (prefers-reduced-motion: no-preference) {
  .dl-panel:not([hidden]) { animation: dl-open .14s ease-out; }
}
@keyframes dl-open {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

/*
 * A row per system: the mark, the name with its version and size across from it, and a line
 * saying which file it is. The line gets the whole width, so none of them wraps at 400px.
 */
.masthead .dl-option {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: 14px;
  row-gap: 1px;
  padding: 11px 12px;
  border-radius: 10px;
  color: var(--ink);
  line-height: 1.4;
  text-decoration: none;
}
.masthead .dl-option:hover,
.masthead .dl-option:focus-visible { background: var(--bone-dim); color: var(--ink); text-decoration: none; }
.masthead .dl-option:focus-visible { outline-offset: -2px; }
.dl-option > svg { grid-row: 1 / 3; align-self: center; color: var(--forest); }
.dl-text { display: contents; }
.dl-name {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 14.5px;
}
.dl-sub { grid-column: 2 / 4; grid-row: 2; font-size: 13px; color: var(--ink-soft); }
.dl-sub code { font-family: var(--mono); font-size: 12px; }
.dl-meta {
  grid-column: 3;
  grid-row: 1;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  white-space: nowrap;
}
.dl-yours {
  font-size: 11px;
  font-weight: 500;
  color: var(--forest);
  border: 1px solid var(--forest);
  border-radius: 999px;
  padding: 0 7px;
  line-height: 1.5;
  white-space: nowrap;
}

.dl-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  margin: 6px 4px 0;
  padding: 10px 8px 4px;
  border-top: 1px solid var(--rule);
  font-size: 13px;
}
.masthead .dl-foot a { color: var(--forest); }
.masthead .dl-foot a:hover { color: var(--forest); }


/* ---------------------------------------------------------- light and dark */
/*
 * The toggle is a JavaScript control, so it is hidden until the inline script in the head has
 * marked the document as scripted — the same bargain the demo's play button makes. With
 * JavaScript off the page still follows prefers-color-scheme; it just cannot be overridden,
 * and no dead button is offered.
 *
 * It sits outside .nav-link, so unlike the section links it survives on a phone: on a small
 * screen the nav is the wordmark, this, and the download button.
 */

.theme-toggle { display: none; }
:root[data-js] .theme-toggle {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, background-color .15s ease;
}
.theme-toggle:hover {
  border-color: var(--forest);
  color: var(--forest);
  background: var(--bone-dim);
}
.theme-toggle svg { display: block; }
.theme-toggle .i-moon { display: var(--glyph-moon); }
.theme-toggle .i-sun { display: var(--glyph-sun); }

/*
 * Repainting the whole page on a click is the one place this site animates a colour, and it is
 * worth it: without it the swap reads as a flicker rather than as the lights being turned down.
 * Only the two grounds and the body text are transitioned — transitioning everything would drag
 * the hairlines and the chart along with it and cost more than it buys.
 */
@media (prefers-reduced-motion: no-preference) {
  :root[data-js] body,
  :root[data-js] .masthead,
  :root[data-js] .band-sunk,
  :root[data-js] .slab,
  :root[data-js] .chart-frame {
    transition: background-color .2s ease, color .2s ease, border-color .2s ease;
  }
}

/* ------------------------------------------------------- register headings */
/*
 * The letterspaced mono label with a hairline running off to the right is the
 * section heading from the app's person screen. Reusing it here is the page's
 * main structural device.
 */

.rule-label {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 28px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.rule-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

/*
 * Where a section has no display heading of its own, the rule label is the heading and
 * is marked up as an h2. This must out-specify `.band h2`, which sets the display size.
 */
h2.rule-label,
.band h2.rule-label {
  font-size: 11px;
  line-height: 1.5;
  font-weight: 500;
  letter-spacing: 0.16em;
  margin: 0 0 28px;
}

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

.hero {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  /* padding-block, not the `padding` shorthand: .hero sits on the same element as
     .shell, and the shorthand would reset .shell's padding-inline to zero. */
  padding-block: clamp(48px, 7vw, 92px) clamp(40px, 6vw, 76px);
}
@media (max-width: 900px) {
  /* minmax(0,…) not 1fr: a bare 1fr takes its minimum from the column's max-content, so a
     single long unbreakable run inside can widen the page rather than being clipped. */
  .hero { grid-template-columns: minmax(0, 1fr); gap: 40px; }
}

.eyebrow {
  margin: 0 0 22px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass);
}

.hero h1 {
  margin: 0 0 22px;
  font-size: clamp(34px, 4.3vw, 52px);
  line-height: 1.08;
  font-weight: 600;
  letter-spacing: -0.022em;
  text-wrap: balance;
}
.hero h1 em {
  font-style: normal;
  color: var(--brass);
}

.lede {
  margin: 0 0 32px;
  font-size: clamp(17px, 1.5vw, 19px);
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 30em;
}

/* ------------------------------------------------------------------ button */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  line-height: 1;
  padding: 17px 27px;
  border-radius: 999px;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, transform .15s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--forest); color: var(--on-forest); }
.btn-primary:hover { background: var(--forest-hover); }

.btn-quiet {
  background: transparent;
  color: var(--forest);
  border-color: var(--rule-strong);
}
.btn-quiet:hover { border-color: var(--forest); background: var(--bone-dim); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
}

/* Spec line + live download counter, both in the records voice. */
/*
 * The spec line's spans are butted together with no whitespace between them, so that the
 * separators sit tight against the words. That leaves the browser no break opportunity at
 * all, and an unbreakable 360px run sets the min-content width of whatever grid column it
 * sits in — which is what used to push the whole page sideways on a phone. Flex items are
 * break opportunities, so laying it out as a wrapping flex row keeps the tight separators
 * and lets the line fold.
 */
.spec {
  margin: 18px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-faint);
  letter-spacing: 0.01em;
}
.spec span { white-space: nowrap; }
.spec .sep { color: var(--rule-strong); padding: 0 3px; }

.counter {
  margin: 26px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-faint);
  max-width: 34em;
}
.counter b {
  display: inline-block;
  margin-bottom: 2px;
  font-weight: 500;
  font-size: 33px;
  color: var(--forest);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.counter[data-state="loading"] b { color: var(--rule-strong); }

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

.chart-frame {
  background: var(--bone-raised);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 10px 10px 0;
  box-shadow: var(--shadow-soft), var(--shadow-cast);
}
.chart-stage { position: relative; }
.chart-stage svg { display: block; width: 100%; height: auto; }

.chart-caption {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0;
  padding: 12px 12px 14px;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-faint);
}
.chart-caption .marker { color: var(--brass); flex: none; }
.chart-caption button {
  font: inherit;
  color: var(--forest);
  background: none;
  border: 0;
  padding: 0;
  margin-left: 6px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Chart node notation, matching the app's chart. */
.node-card { fill: var(--bone-raised); stroke: var(--rule-strong); stroke-width: 1.25; }
.node-name { font-family: var(--serif); font-size: 15px; font-weight: 600; fill: var(--ink); }
.node-years {
  font-family: var(--mono);
  font-size: 11.5px;
  fill: var(--ink-faint);
  font-variant-numeric: tabular-nums lining-nums;
}
.link-line { stroke: var(--sage-line); stroke-width: 1.5; fill: none; }

.node-unknown .node-card {
  fill: var(--brass-surface);
  stroke: var(--brass);
  stroke-dasharray: 7 5;
}
.node-unknown .node-name { fill: var(--brass); font-style: italic; }

/* The one interactive node. */
.node-slot { cursor: pointer; }
.node-slot:hover .node-card { stroke-width: 2; }
.node-slot:focus-visible { outline: none; }
.node-slot:focus-visible .node-card { stroke-width: 2.5; stroke-dasharray: none; }

.node-named .node-card { fill: var(--sage); stroke: var(--forest); stroke-dasharray: none; }
.node-named .node-name { fill: var(--on-sage); font-style: normal; }

.name-input {
  position: absolute;
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  color: var(--on-sage);
  background: var(--bone-raised);
  border: 2px solid var(--forest);
  border-radius: 8px;
  padding: 0 8px;
}

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

.band { padding: clamp(52px, 7vw, 92px) 0; }
.band-sunk { background: var(--bone-dim); border-block: 1px solid var(--rule); }
.band-deep { background: var(--deep); color: var(--deep-ink); }

/* Note: h2.rule-label deliberately out-specifies this — see the rule above the hero. */
.band h2 {
  margin: 0 0 18px;
  font-size: clamp(27px, 3.4vw, 38px);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.018em;
  text-wrap: balance;
}
.band p { margin: 0 0 18px; color: var(--ink-soft); max-width: 34em; }
.band-deep p { color: var(--deep-ink-soft); }
/*
 * The deep band brings its own ground with it, so its label, its rule and its one button are
 * set from the band's own tokens rather than the page's — they must read on dark green in
 * either mode, not on whatever the page happens to be.
 */
.band-deep .rule-label { color: var(--deep-faint); }
.band-deep .rule-label::after { background: var(--deep-hair); }
.band-deep .btn-quiet { border-color: var(--deep-btn-line); color: var(--deep-btn-ink); }
.band-deep .btn-quiet:hover { border-color: var(--deep-btn-ink); background: rgba(223, 231, 224, .07); }
.band-deep a:focus-visible,
.band-deep button:focus-visible { outline-color: var(--deep-btn-ink); }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
@media (max-width: 860px) { .split { grid-template-columns: minmax(0, 1fr); } }

/* The viewer shot is a landscape screen, so it earns more of the row than a phone screenshot. */
.split-wide { grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr); }
@media (max-width: 860px) { .split-wide { grid-template-columns: minmax(0, 1fr); } }

.shot-wide { max-width: 100%; }
.shot-link { display: block; border-radius: 18px; }
.shot-link:focus-visible { outline: 2px solid var(--forest); outline-offset: 4px; }
.shot-link .shot { transition: border-color .15s, transform .15s; }
.shot-link:hover .shot { border-color: var(--rule-strong); }
@media (prefers-reduced-motion: no-preference) {
  .shot-link:hover .shot { transform: translateY(-2px); }
}

/* Feature entries, set as register rows rather than a card grid. */
.entries { display: grid; gap: 0; }
.entry {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  gap: 28px;
  padding: 26px 0;
  border-top: 1px solid var(--rule);
}
.entry:last-child { border-bottom: 1px solid var(--rule); }
.entry h3 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.entry p { margin: 0; color: var(--ink-soft); font-size: 16px; }
@media (max-width: 700px) {
  .entry { grid-template-columns: 1fr; gap: 8px; }
}

/* Negative-space list: what the app deliberately does not do. */
.nots { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.nots li {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 13px 0;
  border-bottom: 1px solid var(--deep-rule);
  font-family: var(--mono);
  font-size: 14px;
  color: var(--deep-ink);
}
.nots li::before {
  content: "no";
  flex: none;
  color: var(--deep-brass);
  opacity: .8;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 18px;
  border: 1px solid var(--rule);
  background: var(--bone-raised);
}
.shot-narrow { max-width: 360px; }
.shot-card { max-width: 400px; }

/* Three sample book pages, side by side; two, then one alone, once a phone can't fit three. */
.book-pages {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
.book-pages figure { margin: 0; }
.book-pages figcaption {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  text-align: center;
}
@media (max-width: 520px) {
  .book-pages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------- the demo */
/*
 * A screen recording of the shipped app, framed exactly like a screenshot so the section
 * reads as one object. It is click-to-play with preload="none": the poster frame already
 * carries the whole answer, so nobody pays for the video until they ask for it, and there
 * is no autoplay for prefers-reduced-motion to have to suppress.
 */
.demo-figure { margin: 0; max-width: 360px; }
.demo-stage { position: relative; }
.demo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 18px;
  border: 1px solid var(--rule);
  background: var(--bone-raised);
}
.demo-figure figcaption {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-faint);
}

/*
 * The play control. The video ships with native `controls` so it works with JavaScript off;
 * app.js takes them away and puts this in front instead, then hands them back the moment the
 * video is playing. The native bar is a black slab with a gradient scrim, which sits badly on
 * a bone poster and covers the very rows the poster exists to show.
 */
.demo-play {
  position: absolute;
  inset: 0;
  width: 100%;
  display: grid;
  place-items: center;
  gap: 0;
  border: 0;
  border-radius: 18px;
  background: transparent;
  cursor: pointer;
  font: inherit;
  /* Sat at the bottom rather than the middle: the poster's centre is the sentence the whole
     section is about, and a disc placed over "…first cousin once removed" hides the answer
     from anybody who never presses play. */
  align-items: end;
  padding: 0 0 26px;
}
.demo-play .disc {
  display: grid;
  place-items: center;
  width: 66px;
  height: 66px;
  border-radius: 999px;
  background: var(--forest);
  color: var(--on-forest);   /* the triangle inside is filled with currentColor */
  box-shadow: var(--shadow-disc);
  transition: background-color .15s ease, transform .15s ease;
}
.demo-play .disc svg { margin-left: 3px; }   /* a triangle looks off-centre when it is centred */
.demo-play:hover .disc { background: var(--forest-hover); }
.demo-play:focus-visible { outline: 2px solid var(--forest); outline-offset: 3px; }
@media (prefers-reduced-motion: no-preference) {
  .demo-play:hover .disc { transform: scale(1.05); }
}
/* The demo and the card are portrait, so they sit to the right of their text rather than
   taking an equal half of a very wide row. */
.split-demo { grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr); }
@media (max-width: 860px) { .split-demo { grid-template-columns: minmax(0, 1fr); } }

/* Two stacked splits in one band need a rule between them, not just more air. */
.split-hindi {
  margin-top: clamp(48px, 6vw, 84px);
  padding-top: clamp(48px, 6vw, 84px);
  border-top: 1px solid var(--rule);
}

.gallery {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 250px;
  gap: 22px;
  overflow-x: auto;
  padding-bottom: 14px;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}
.gallery figure { margin: 0; scroll-snap-align: start; }
.gallery figcaption {
  margin-top: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------ download slab */

.slab {
  background: var(--bone-raised);
  border: 1px solid var(--rule);
  border-radius: 16px;
  padding: clamp(26px, 4vw, 44px);
}
.facts {
  margin: 26px 0 0;
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 13px;
}
.facts div {
  display: grid;
  grid-template-columns: 118px minmax(0, 1fr);
  gap: 18px;
  padding: 11px 0;
  border-bottom: 1px solid var(--rule);
}
.facts dt { color: var(--ink-faint); letter-spacing: .04em; overflow-wrap: anywhere; }
.facts dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
@media (max-width: 560px) {
  .facts div { grid-template-columns: 1fr; gap: 2px; }
}

/* The phone and the laptop, side by side, and each a complete answer on its own. */
.get-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  gap: 20px;
}
.get-grid .slab { display: flex; flex-direction: column; }
.get-grid .slab > p:first-of-type { max-width: 34em; }
/* The facts sit on the floor of each slab, so the two lists start level whatever is above them. */
.get-grid .facts { margin-top: auto; }
.get-grid .cta-row { margin: 0 0 26px; }
.get-title { font-size: clamp(24px, 2.4vw, 30px); margin: 0 0 12px; }
.btn-kind { font-family: var(--mono); font-size: 14px; background: none; border: 0; padding: 0; }
.get-shared { margin-top: 20px; border-top: 0; }
.get-shared div:first-child { border-top: 1px solid var(--rule); }

/*
 * A checksum and the file it belongs to.
 *
 * Not a `.facts` row: a filename and a 64-character hash are both too long for a label column,
 * and side by side they collide. The name goes above its hash, each with the whole width.
 */
.hash-row {
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 13px;
}
.hash-row:first-child { border-top: 1px solid var(--rule); }
.hash-row p { margin: 0; font-family: var(--mono); font-size: 13px; line-height: 1.5; }
.hash-row .hash-name { color: var(--ink-faint); letter-spacing: .04em; margin-bottom: 5px; }
.hash-row .hash { color: var(--ink); overflow-wrap: anywhere; }

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

.footer {
  border-top: 1px solid var(--rule);
  padding: 40px 0 56px;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink-faint);
}
.footer .shell {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 32px;
  align-items: center;
  justify-content: space-between;
}
.footer nav { display: flex; flex-wrap: wrap; gap: 22px; }
.footer a { color: var(--ink-soft); text-decoration: none; }
.footer a:hover { color: var(--forest); text-decoration: underline; }

/* ------------------------------------------------------------- thanks page */

.steps { list-style: none; counter-reset: step; margin: 0; padding: 0; }
.steps > li {
  counter-increment: step;
  position: relative;
  padding: 0 0 30px 62px;
  border-left: 1px solid var(--rule);
  margin-left: 17px;
}
.steps > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps > li::before {
  content: counter(step);
  position: absolute;
  left: -18px;
  top: -2px;
  width: 35px;
  height: 35px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--sage);
  color: var(--on-sage);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 500;
}
.steps h3 {
  margin: 4px 0 8px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.steps p { margin: 0 0 10px; color: var(--ink-soft); max-width: 36em; }

.quote {
  margin: 12px 0 0;
  padding: 12px 16px;
  background: var(--bone-dim);
  border-left: 2px solid var(--rule-strong);
  border-radius: 0 6px 6px 0;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-soft);
}
.quote b { font-weight: 500; color: var(--ink); }

.notice {
  display: flex;
  gap: 14px;
  padding: 18px 20px;
  background: var(--brass-surface);
  border: 1px solid var(--notice-line);
  border-radius: 12px;
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--notice-ink);
}
.notice strong { color: var(--notice-strong); }

.hash {
  font-family: var(--mono);
  font-size: 12.5px;
  overflow-wrap: anywhere;
  color: var(--ink);
}

.status-line {
  margin: 22px 0 0;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink-faint);
}

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

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* The numbered rail costs too much of a phone's width at its desktop indent. */
@media (max-width: 620px) {
  .steps > li { padding-left: 46px; margin-left: 14px; }
  .steps > li::before { left: -15px; width: 29px; height: 29px; font-size: 12px; }
}


/* ------------------------------------------------- the download cards

   One card per system, every file in it as its own row with its own size, so nothing about
   choosing depends on the page having guessed the reader's machine correctly. Detection only
   marks a recommendation; it never hides the other half.
*/

.platforms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
  gap: 20px;
  margin: 30px 0 0;
}
.platform {
  border: 1px solid var(--rule);
  border-radius: 16px;
  padding: 22px 22px 18px;
  background: var(--bone-raised);
}
.platform.is-yours { border-color: var(--forest); box-shadow: 0 0 0 1px var(--forest); }
.platform h3 {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 6px;
  font-size: 19px;
  font-weight: 600;
}
.platform h3 .tag {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--forest);
  border: 1px solid var(--forest);
  border-radius: 999px;
  padding: 3px 9px;
}
.platform > p { margin: 0 0 16px; font-size: 14.5px; color: var(--ink-soft); }

.file {
  display: flex;
  align-items: baseline;
  gap: 12px;
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: 11px;
  padding: 13px 15px;
  margin-bottom: 9px;
  text-decoration: none;
  color: var(--ink);
  background: var(--bone);
  transition: border-color .15s, background .15s;
}
.file:hover { border-color: var(--forest); background: var(--bone-raised); }
.file .what { font-weight: 600; font-size: 15px; }
.file .meta { margin-left: auto; font-family: var(--mono); font-size: 12px; color: var(--ink-faint); }
.file.primary { border-color: var(--forest); background: var(--sage); }
.file.primary .what { color: var(--on-sage); }
.file.primary .meta { color: var(--on-sage); }
.platform .caution {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-faint);
  line-height: 1.55;
}

/* A single fact bar under the cards. */
.band .assurance {
  margin: 22px 0 0;
  font-size: 14px;
  color: var(--ink-faint);
  text-align: center;
}

/* "What to expect", set apart by a rule rather than a box within a box. */
.expect {
  margin: 34px 0 0;
  border-left: 3px solid var(--brass);
  padding: 4px 0 4px 18px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink-soft);
}
.expect strong { color: var(--ink); }

/* The long-form steps, folded away until wanted. */
details.folded {
  border-top: 1px solid var(--rule);
  padding: 16px 0;
}
details.folded > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 16px;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
}
details.folded > summary::-webkit-details-marker { display: none; }
details.folded > summary::after {
  content: "+";
  margin-left: auto;
  font-family: var(--mono);
  color: var(--ink-faint);
  font-size: 18px;
}
details.folded[open] > summary::after { content: "\2013"; }
details.folded > summary:hover { color: var(--forest); }


/* A command you are meant to run, with a button that saves retyping it. */
.copyline {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin: 10px 0 0;
  border: 1px solid var(--rule);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bone);
}
.copyline code {
  flex: 1;
  padding: 11px 13px;
  font-family: var(--mono);
  font-size: 13px;
  overflow-x: auto;
  white-space: nowrap;
  background: none;
  border: 0;
}
.copyline .copy {
  flex: none;
  border: 0;
  border-left: 1px solid var(--rule);
  background: var(--bone-raised);
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: 13px;
  padding: 0 15px;
  cursor: pointer;
}
.copyline .copy:hover { background: var(--forest); color: var(--on-forest); }
