/* The one-page site (views/home.njk; services/site.js; docs/design.md, The
   one-page site; drawn over fifteen rounds and frozen as
   docs/design-log/2026-10-16-one-page-site.html). What the app's stylesheets
   don't have: the sections and their halves, the headline and titles at their
   sizes, the marks, the ledger, the reminders' line and the footer. Sizes off
   the app's type table come from its spacing scale (71, 44); the italic is
   Jost's, the site's alone (439). Loaded on that page only. */
/* A section: on a phone and a tablet, the app's reading column, 15 tiles,
   with the margins either side (docs/design.md, Layout: 17 at a phone's
   edges, 44 from 704), the picture under the words. From 924, two halves of
   9 tiles with a tile between, the words in one and the picture in the
   other, taking turns. */
.site { --site-edge: var(--space-s); }
/* Not --edge: that's the app's 4-pixel edge of a banner, a row and a
   pairing (tokens.css), which the site draws too. */
/* The launch post's banner, a line under the header (Ty, October 28, from
   his own try at it): edge to edge, its blue edge along the top where a
   banner's is at its left, its words in line with the mark, the post's
   button after them and the x at the far end, wrapping only where a phone
   runs out of room. It never closes itself (Ty, October 28: "it's there
   for messaging important stuff to users/customers."): it's an info banner
   given no fades, so the partial marks it stays. Closed by its x, it leaves nothing. */
.site-note > .banner { align-items: center; padding: var(--space-xs) var(--space-s); border-left: 0; border-top: var(--edge) solid var(--banner); }
/* The button's label in line with the words when a phone wraps it, as in
   any banner: where they share a line, its box starts 17 after the words
   and its label 27. */
.site-note .banner-body { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--space-m); }
.site-note .banner .btn-text { margin: 0 0 0 calc(-1 * var(--space-xs)); }
@media (min-width: 704px) { .site-note > .banner { padding-inline: var(--space-l); } }
@media (min-width: 704px) { .site { --site-edge: var(--tile); } }
/* No column gap: the app gives a section one (components.css), which would
   add to the halves and the tile between them. */
.sec { position: relative; overflow: clip; display: grid; column-gap: 0; grid-template-columns: [full-start] minmax(var(--site-edge), 1fr) [col-start] minmax(0, calc(15 * var(--tile))) [col-end] minmax(var(--site-edge), 1fr) [full-end]; row-gap: var(--space-l); align-items: center; padding-block: var(--space-xl); }
.words { grid-column: col; display: grid; gap: var(--space-m); align-content: start; min-width: 0; }
.words > * { margin: 0; }
.pic { grid-column: col; justify-self: center; min-width: 0; max-width: 100%; margin: 0; }
.pic.is-text { justify-self: stretch; display: grid; gap: var(--space-s); }
.pic.is-text > * { margin: 0; }
@media (min-width: 924px) {
  .sec { grid-template-columns: [full-start] minmax(var(--site-edge), 1fr) [a-start] calc(9 * var(--tile)) [a-end] var(--tile) [b-start] calc(9 * var(--tile)) [b-end] minmax(var(--site-edge), 1fr) [full-end]; }
  .sec > * { grid-row: 1; }
  .sec:not([data-side]) > .words { grid-column: a-start / b-end; max-width: calc(15 * var(--tile)); }
  [data-side="right"] > .words, [data-side="left"] > .pic { grid-column: a; }
  [data-side="left"] > .words, [data-side="right"] > .pic { grid-column: b; }
}

/* Type, from the top: the headline, a section's title, a question. */
.site-headline { margin: 0; font: 200 2.75rem/1.1 var(--font); letter-spacing: -0.01em; text-wrap: balance; }
.sec-title { margin: 0; font: 600 1.75rem/1.2 var(--font); text-wrap: balance; }
.sec-title em { font-style: italic; }
.q { margin: 0; font: 600 1.25rem/1.3 var(--font); }
@media (min-width: 924px) {
  .site-headline { font-size: 4.4375rem; }
  .sec-title { font-size: 2rem; }
  .q { font-size: 1.5rem; }
}
/* A question is its whole row: the row opens it, and where a pointer can
   hover the row takes its section's ink at 12 percent, as a list's row takes
   its color (round 11: "whole row needs a hover state and clickable."). */
.faq-list { display: grid; border-bottom: 1px solid var(--rule); }
.qa { border-top: 1px solid var(--rule); }
.qa > summary { display: flex; padding: var(--space-s) var(--space-xs); transition: background-color var(--dur-press) var(--ease-standard); }
.qa > .opens-body { padding: 0 var(--space-xs) var(--space-m); }
@media (hover: hover) {
  [data-tone="filled"] .qa > summary:hover { background: color-mix(in srgb, var(--on) 12%, var(--c60)); }
  [data-tone="plain"] .qa > summary:hover { background: color-mix(in srgb, var(--c60) 12%, var(--surface)); }
}
.opens > summary .title, .opens > summary .q { margin: 0; }

/* The first screen's tiles. */
.t { flex: none; aspect-ratio: 1; }
.t > svg, .t > .piece { display: block; width: 100%; height: 100%; --tile-ground: var(--surface); transform-origin: var(--pivot); }
.piece { position: relative; }
.piece > svg { position: absolute; inset: 0; width: 100%; height: 100%; --tile-ground: var(--surface); transform-origin: var(--pivot); }
.piece > .pb { opacity: 0; }
.dia { display: flex; align-items: center; color: var(--on); max-width: 100%; }
.dia .t { width: calc(var(--s) * var(--tile)); }
.arrow-cell { flex: none; width: calc(var(--s) * var(--tile)); display: grid; place-items: center; }
/* The first screen's pair, their names under their tiles (438). */
.dia-pair { display: grid; grid-template-columns: repeat(3, auto); align-items: center; justify-items: center; row-gap: var(--space-xs); }
.dia-pair .who { grid-row: 2; font: 600 var(--text-reading)/1.2 var(--font); }
.dia-pair .who:first-of-type { grid-column: 1; }
.dia-pair .who:last-of-type { grid-column: 3; }
/* White, at Ty's word (round 10: "make the •> white."), 3.8 to 1 on blue. */
.big-arrow { width: 62%; height: auto; color: var(--on-strong-fill); --tile-ground: var(--c60); }
@media (max-width: 703px) {
  [data-s="hero"] .dia .t { width: calc(2 * var(--tile)); }
  [data-s="hero"] .arrow-cell { width: var(--tile); }
}

/* The arrival (412, 396 c): the first screen's two tiles turn in with the
   header's, each at its own moment. Their breath after is the page's own
   <style>, drawn by services/site.js where the browser hasn't pressed Stop
   motion. */
@media (prefers-reduced-motion: no-preference) {
  .site.arriving .first .t > * { animation: band-arrive var(--dur-inhale) var(--ease-inhale) backwards; animation-delay: calc(var(--arrive-after, 0ms) + 4 * var(--dur-arrival-beat) + var(--moment)); }
}

/* A filled section: its lead color, the words in the color's ink. */
[data-tone="filled"] { background: var(--c60); color: var(--on); }
[data-tone="filled"] :is(.hint, .title, .sec-title, label, .choice-row small, .member-meta, .tl-text span, a, .muted) { color: var(--on); }
[data-tone="filled"] .t > svg, [data-tone="filled"] .piece > svg { --tile-ground: var(--c60); }
/* A fill is the same in either mode, so what sits on it is too: the form as
   light mode draws it, a white field with an ink edge and an ink button, in
   dark mode as well (round 9's cream button on yellow was 1.2 to 1). */
[data-tone="filled"] { --surface: var(--on-strong-fill); --surface-3: var(--on-strong-fill); --ink: var(--on-fill); --border: var(--on-fill); --ink-2: color-mix(in srgb, var(--on-fill) 68%, var(--on-strong-fill)); --rule: color-mix(in srgb, var(--on) 50%, var(--c60)); color-scheme: light; }
.sec input::placeholder { color: var(--ink-2); opacity: 1; }
/* The draw's pairs on its fill: the arrows in the block's ink, and lines on a
   fill, the pairs' and the questions', half of it (round 9's were the page's
   gray, 1.7 to 1 and 1.1 to 1 on red-violet: "color contrast issues"). */
[data-tone="filled"] .pairs .arrow { color: var(--on); }
/* The viewer's own pairing marked in the block's ink, where the list's own
   color can be the block's (the example list is green). */
[data-tone="filled"] .pairs li.mine { border-left-color: var(--on); }

/* Dividers in ink, edge to edge, by rank. */
.rule { height: var(--w); background: var(--ink); }

/* The marks: tiles a cell from the section, and each cropped its own way.
   At the section's foot, a tile of it under the edge; at the page's edge,
   two tiles of it past the margin where it sits beside the words, and as
   much as a phone can't hold under them; whole, as it is. */
.pic-mark { display: block; max-width: none; }
.w-mark { display: block; width: calc(3 * var(--s) * var(--tile)); height: auto; }
.is-foot { align-self: end; margin-bottom: calc(-1 * (var(--space-xl) + var(--tile))); }
.is-edge { grid-column: full; }
@media (min-width: 924px) {
  [data-side="left"] > .is-edge { grid-column: full-start / a-end; justify-self: start; margin-left: calc(-2 * var(--tile)); }
  [data-side="right"] > .is-edge { grid-column: b-start / full-end; justify-self: end; margin-right: calc(-2 * var(--tile)); }
}

/* The example list, framed, its label on the frame's top edge (443). */
.example { position: relative; margin: 0; border: 1px solid var(--border); padding: var(--space-m) var(--space-s) var(--space-xs); }
.example-tag { position: absolute; top: 0; left: var(--space-s); translate: 0 -50%; padding: 0 var(--space-xs); background: var(--surface); font: 600 1rem/1.2 var(--font); letter-spacing: 0.05em; text-transform: uppercase; }
/* Bringing in a list as it goes (651 c): five moments of the import's page
   stacked in one place, each the app's own piece, shown one after another on
   a loop of 14 seconds, the file chosen sliding in over the first two. Four
   times round, a minute, and it rests on the list made, since an animation
   that never ends keeps a phone drawing (458; docs/design.md, Ambient motion). Still,
   it's the list made alone. */
.flow { position: relative; display: grid; }
.flow > .flow-step { grid-area: 1 / 1; margin: 0; opacity: 0; }
.flow > .at-made { opacity: 1; align-self: center; }
.flow-file { position: absolute; left: 50%; top: 84%; translate: -50% -50%; padding: var(--space-3xs) var(--space-xs); border: 1px solid var(--border); background: var(--surface); font: 300 var(--text-tertiary)/1.2 var(--font); white-space: nowrap; opacity: 0; }
/* Its loader is a drawing here, not status: it turns only while the picture
   moves, for about its four rounds (4 x 14s over the loader's 1.68s turn), so
   a still or finished picture keeps nothing drawing (458; read of c1d6e9f7). */
.flow .loader-cell { animation-play-state: paused; }
@media (prefers-reduced-motion: no-preference) {
  .flow.moving .loader-cell { animation-play-state: running; animation-iteration-count: 34; }
  .flow.moving > * { animation: 14s linear 4 both; }
  .flow.moving > .at-choose { animation-name: flow-choose; }
  .flow.moving > .at-over { animation-name: flow-over; }
  .flow.moving > .at-busy { animation-name: flow-busy; }
  .flow.moving > .at-read { animation-name: flow-read; }
  .flow.moving > .at-made { animation-name: flow-made; }
  .flow.moving > .flow-file { animation-name: flow-file; animation-timing-function: var(--ease-standard); }
}
@keyframes flow-choose { 0%, 20% { opacity: 1; } 22%, 100% { opacity: 0; } }
@keyframes flow-over { 0%, 20% { opacity: 0; } 22%, 28% { opacity: 1; } 30%, 100% { opacity: 0; } }
@keyframes flow-busy { 0%, 28% { opacity: 0; } 30%, 42% { opacity: 1; } 44%, 100% { opacity: 0; } }
@keyframes flow-read { 0%, 42% { opacity: 0; } 44%, 73% { opacity: 1; } 75%, 100% { opacity: 0; } }
@keyframes flow-made { 0%, 73% { opacity: 0; } 75%, 100% { opacity: 1; } }
@keyframes flow-file { 0%, 6% { opacity: 0; transform: translate(60%, -160%); } 9% { opacity: 1; } 18% { transform: none; } 28% { opacity: 1; transform: none; } 30%, 100% { opacity: 0; transform: none; } }

/* What it costs (557 a; drawn where SITE_PRICING is set, 560 b): from 924
   the two plans in the site's halves under the words, each framed as the
   example list is, and support a line under both; narrower, one under
   another. The price at the years' ledger's size. */
[data-s="price"] > * { grid-column: col; min-width: 0; margin: 0; }
.plan { align-self: stretch; display: grid; gap: var(--space-s); align-content: start; }
.plan > * { margin: 0; }
.price { margin: 0; font: 200 2.25rem/1.1 var(--font); }
.support b { font-weight: 600; }
@media (min-width: 924px) {
  .price { font-size: 2.75rem; }
  [data-s="price"] > .plan:nth-of-type(1) { grid-column: a; grid-row: 2; }
  [data-s="price"] > .plan:nth-of-type(2) { grid-column: b; grid-row: 2; }
  [data-s="price"] > .support { grid-column: a-start / b-end; grid-row: 3; max-width: calc(15 * var(--tile)); }
}
/* The years as a ledger. */
.ledger { list-style: none; margin: 0; padding: 0; display: grid; border-bottom: 1px solid currentColor; }
.ledger li { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 var(--space-m); padding-block: var(--space-s); border-top: 1px solid currentColor; }
.year-num { font: 600 var(--text-secondary)/1.2 var(--font); font-variant-numeric: tabular-nums; }
.year-pair { font: 200 2.25rem/1.1 var(--font); }
@media (min-width: 924px) { .year-pair { font-size: 2.75rem; } }
.year-pair :is(.pair, .to) { gap: 0.2em; }
/* The pair's arrow on the middle of its line, as the app has it in .pairs
   (components.css; round 8 had it at the line's top: "align-items center?"). */
.year-pair .arrow { flex: none; width: 1em; height: 0.5em; margin-top: calc((1lh - 0.5em) / 2); color: currentColor; }

/* The groups' marks. */
/* Two above and one below, a tile of air between (round 13: "groups feel
   too tight. contrasts with the white space from everywhere else..."). */
.groups { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, calc(3 * var(--tile)))); justify-content: center; gap: var(--tile) calc(2 * var(--tile)); }
.groups li:last-child { grid-column: 1 / -1; }
.groups li { display: grid; gap: var(--space-xs); justify-items: center; align-content: start; text-align: center; font-weight: 600; }
/* Two and a half tiles (round 12: "feel like we can have the list icons a
   bit bigger..."; round 11 drew them at two). */
.groups svg.mark { width: calc(2.5 * var(--tile)); height: auto; max-width: 100%; }

/* The reminders as a line, each week a tile and a half tall. */
.pic-tl { list-style: none; padding: 0; position: relative; display: grid; grid-template-rows: repeat(7, calc(1.5 * var(--tile))); width: min(100%, calc(9 * var(--tile))); }
.pic-tl::before { content: ""; position: absolute; left: calc(var(--tile) / 2 - var(--space-3xs) / 2); top: calc(var(--tile) / 2); bottom: calc(var(--tile) / 2); width: var(--space-3xs); background: currentColor; }
.pic-tl li { display: flex; align-items: center; gap: var(--space-s); }
.tl-tile { flex: none; position: relative; width: var(--tile); height: var(--tile); }
.tl-text { display: grid; line-height: 1.3; }
.tl-text b { font-weight: 600; }
.tl-text span { font-size: var(--text-tertiary); font-weight: 300; color: var(--ink-2); }

/* The footer: the icon and the name, the headline again, the links in
   columns, who made it at the foot. */
.foot { --site-edge: var(--space-s); padding: var(--space-2xl) var(--site-edge) var(--space-xl); }
@media (min-width: 704px) { .foot { --site-edge: var(--tile); } }
.foot-in { max-width: calc(19 * var(--tile)); margin-inline: auto; display: grid; gap: var(--space-xl) var(--tile); }
@media (min-width: 924px) { .foot-in { grid-template-columns: calc(6 * var(--tile)) minmax(0, 1fr); } .foot-end { grid-column: 1 / -1; } }
.foot-brand { display: grid; gap: var(--space-m); align-content: start; justify-items: start; }
.foot-logo { display: inline-flex; align-items: center; gap: var(--space-s); color: var(--ink); text-decoration: none; }
.foot-icon { width: calc(2 * var(--tile)); height: calc(2 * var(--tile)); }
.foot-name { font: 600 1.25rem/1 var(--font); letter-spacing: 0.36em; text-transform: uppercase; }
.foot-tag { margin: 0; font: 200 1.75rem/1.2 var(--font); text-wrap: balance; }
.foot-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-l) var(--space-s); align-content: start; }
.foot-cols > :last-child { grid-column: 1 / -1; }
@media (min-width: 704px) { .foot-cols { grid-template-columns: repeat(3, max-content); justify-content: space-between; } .foot-cols > :last-child { grid-column: auto; } }
.foot-cols h2 { margin: 0 0 var(--space-s); font: 600 1rem/1.2 var(--font); letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-2); }
.foot-cols ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-xs); }
.foot-cols a, .foot-cols .motion-button { color: var(--ink); }
/* Stop motion is hidden where the device asks for less motion (header.css),
   and its row with it. */
@media (prefers-reduced-motion: reduce) { .foot-cols li:has(.motion-button) { display: none; } }
.foot-end { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-xs) var(--space-l); padding-top: var(--space-m); border-top: 1px solid var(--rule); color: var(--ink-2); font-size: var(--text-tertiary); font-weight: 300; }
.foot-end p { margin: 0; }
.foot-made { flex: 1 1 calc(9 * var(--tile)); max-width: calc(13 * var(--tile)); }

/* Windows' high contrast (682): the dividers between sections and the reminders' line are
   backgrounds, which it drops, and the hero's arrow is drawn white on a ground it drops too. */
@media (forced-colors: active) {
  .rule, .pic-tl::before { forced-color-adjust: none; background: CanvasText; }
  .big-arrow { color: CanvasText; }
}
