/* Bonney's site — one sheet for every page. The palette, type, surfaces and measures are the settings page's
   (bonney-app/settings_page.html), resolved to plain values: light is the app's web theme, dark its Night mode. WHICH ONE
   PAINTS is <html data-theme> — theme.js's, from the reader's pin or the device (2.0.30); without it, light.
   index.html and 404.html load this file as /site.css?v=<first 8 hex of its sha256>; stamps.py keeps that stamp current on
   every push to main (2.0.35), so no cache serves a new page with an old sheet — never edit it by hand. */

@font-face { font-family: Inter; src: url("/fonts/inter.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }
@font-face { font-family: "Roboto Served"; src: url("/fonts/roboto.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }

:root {
  color-scheme: light;
  --flip: -1;                                                /* THE POLARITY, the app's (2.0.86, settings_page.html): -1 light, +1 Night
     mode — the laws below read it, so each is declared once and Night mode states only its palette */
  --bg: #f2edf0; --surface: #fffdff; --text: #44373e;
  --body: rgb(68 55 62 / 0.85);                              /* ordinary text: --text at 85% — titles, headings and the lead keep --text */
  --muted: rgb(68 55 62 / 0.73);                             /* muted: 0.65 fails AA on this ground — 0.73 is the least that passes (4.61) */
  --accent: #007aff; --accent-text: #fff; --chip: rgb(0 122 255 / 0.14);
  --btn-lift: rgb(255 255 255 / 0.1);                         /* the capsule's hover: white over the accent, never grey */
  /* THE LAWS — the app's, verbatim (settings_page.html), each read against the polarity: */
  --light: calc((1 - var(--flip)) / 2);                      /* 1 on light, 0 in Night mode */
  --lift: color-mix(in srgb, #fff calc(50% + var(--flip) * 50%), #000);   /* which way a surface lifts: black on light, white in Night */
  --title: oklch(from var(--text) calc(l + var(--flip) * 0.036) c h);     /* the lockup's ink, pushed further from the ground */
  --hairline: color-mix(in srgb, var(--lift) 6.5%, transparent);
  --panel-inset: color-mix(in srgb, var(--lift) 4.8%, transparent);   /* a panel: read and copied, never typed into (the app's) */
  --rim-hint: calc(50% - var(--flip) * 16.7%);               /* where the ring's lit edge fades: 66.7% on light, 33.3% in Night */
  --btn-rim: inset 0 1px 0 color-mix(in srgb, #fff 22%, var(--accent)), inset 0 -1px 0 oklch(from var(--accent) calc(l - 0.092) c h);
  --cast-hue: oklch(from var(--bg) 0 0 h / calc(0.061 / max(l, 0.18)));   /* black at Δ / the ground's lightness */
  --toggles: rgb(0 0 0 / 0.11); --positive: #34c759;         /* the switch: its unset track and its on — the app's */
  --column: 27rem; --gutter: 0.85rem; --air: 1.2rem; --logo: 96px; --reach: 22rem;
  --band: 85px;                                              /* A SHUT FOLD'S BLUR AND FADE, from its foot up — one length on every card (owner-ruled 2.0.137) */
  --peek: 10.65rem;                                          /* A SHUT FOLD'S HEIGHT, every one (owner-ruled 2.0.104: "same height for
     all") — the homepage's Security as 2.0.103 sized it, its head and first paragraph: 170.3px */
  --card-inset: 28px; --rhythm: 0.9rem; --step: 1.2rem; --step-gap: 0.55rem;   /* a step's numbered chip, and the air after it */
}
/* THE CARD'S WIDTH IS THE APP'S (bonney-app/settings_page.html, the operate page): 27rem clears every phone, so there the window
   less a gutter each side wins; from 30rem up the column is the thumb's reach plus a gutter each side — 23.7rem. */
@media (min-width: 30rem) { :root { --column: calc(var(--reach) + 2 * var(--gutter)); } }
/* NIGHT MODE — one block, keyed on the one fact: the pin, else the device (theme.js). */
:root[data-theme="dark"] {
  color-scheme: dark;
  --flip: 1;
  --bg: #18222d; --surface: #21303f; --text: #fff;
  --body: rgb(255 255 255 / 0.85);
  --muted: rgb(255 255 255 / 0.65);
  --accent: #2ea6ff; --chip: rgb(46 166 255 / 0.14);
  --toggles: rgb(255 255 255 / 0.11);
}
/* THE CARD'S RING, the app's law (2.0.85–2.0.86): white over the card's OWN ground — all of it on light, 2.55% in Night mode —
   fading out by --rim-hint into that ground. Declared on each wearer — a card and the mark (2.0.91: "exactly as the cards have it")
   — since a custom property's var()s resolve where it is declared: a wearer that changes --surface gets a ring of its own. */
.card, h1 i {
  --rim-top: color-mix(in srgb, #fff max(var(--light) * 100%, 2.55%), var(--surface));
  --rim: linear-gradient(var(--rim-top), var(--rim-hint), var(--surface));   /* a card's 1px ring: lit above, nothing below */
}

html { background: var(--bg); -webkit-tap-highlight-color: transparent; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { max-width: var(--column); margin: 0 auto; padding: calc(var(--air) / 2) var(--gutter) 2rem; overflow-x: hidden;
       font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", Inter, Roboto, "Roboto Served", system-ui, sans-serif;
       font-size: 0.95rem; line-height: 1.45; color: var(--body); }
b, h2, .lead { color: var(--text); }                         /* a title reads at full strength over the ordinary text beneath it */
/* TWO LANES WHERE TWO FIT: two cards of the column, the page's air between them, a gutter each side — 2 × 23.7 + 1.2 + 2 × 0.85
   = 50.3rem (a media query takes no custom property; lanes.js reads the same figure). lanes.js chooses each card's lane, every fold
   counted shut (the folds are shut on every device until the reader opens one, 2.0.36) — the shorter one when it is placed, a tie
   left — and places it whole: its lane and its rows (a start and a span in 1px rows), stacked from the heights on screen, so
   no lane waits on the other and a fold grows only its own. A PAIR (2.0.77) is nothing of its own in the layout (2.0.96): its
   lead — a card always open (2.0.98) — takes the left lane and its partner — a fold — the right, level only while the partner is
   open; in one column, its cards one under the other. The air is inside each span, so the
   cards' margins go and the last span's air is taken back below. Without the script — or on a page of one card — main is one
   column. */
.pair { display: contents; }
@media (min-width: 50.3rem) {
  body:has(main.lanes) { max-width: calc(2 * var(--column) + var(--air)); }
  main.lanes { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-auto-rows: 1px; column-gap: var(--air);
               align-items: start; margin-block: var(--air) calc(-1 * var(--air)); }
  main.lanes > .card, main.lanes > .pair > .card { margin: 0; grid-column: var(--lane); grid-row: var(--row); }
  :root[data-lanes="pending"] main { visibility: hidden; }   /* lanes.js marks it before the first paint and clears it once the
                                                             lanes are chosen: no frame of the one-column page where two fit */
}
a { color: var(--accent); text-underline-offset: 2px; }
/* AN OUTSIDE LINK — every link that leaves the site — in its sentence's own size and ink, no underline —
   and after it outside.svg, an arrow leaving a box: a mask filled with the link's own colour, so it follows the link in either
   theme. It is a box, not text: a screen reader never names it. */
a.out { color: inherit; text-decoration: none; }
a.out::after { content: ""; display: inline-block; width: 0.8em; height: 0.8em; margin-left: 0.3em; vertical-align: -0.06em;
               background: currentColor; -webkit-mask: center/contain no-repeat url("/outside.svg"); mask: center/contain no-repeat url("/outside.svg"); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* THE LOCKUP: the mark on its squircle plate, ringed as a card is, beside the three-line name — the h1's text is the visible name */
/* THE LOCKUP HANGS ON THE PAGE'S CENTRE LINE: two equal halves meet there — the mark ends half the lanes' gap before it, the
   name begins on it. Where two lanes stand, that is the left card's right edge exactly; in one column the lockup sits a
   hair left of centre. The name's width never moves the mark; its lines are the markup's own breaks, never wrapped. */
h1 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; height: var(--logo); margin: 3.5vh 0 1.1rem;
     font-size: 23px; font-weight: 200; line-height: 1.16; color: var(--title); }
h1 span { white-space: nowrap; }
h1 small { font-size: 0.82em; }                             /* a lockup's aside (docs' "(work in progress)"): measured, as long as "Documentation" above it */
h1 i { justify-self: end; margin-right: calc(var(--air) / 2); position: relative; width: var(--logo); height: var(--logo);
       filter: drop-shadow(0 2px 5px var(--cast-hue)); }
h1 i::before, h1 i::after { content: ""; position: absolute; inset: 0; }
h1 i::before { background: center/98% no-repeat url("/mark.svg"); background-color: var(--surface);
               -webkit-mask: center/contain no-repeat url("/squircle.svg"); mask: center/contain no-repeat url("/squircle.svg"); }
h1 i::after { background: var(--rim);                        /* the card's ring, on the squircle: a 1px band of the same --rim */
              -webkit-mask: url("/squircle.svg") center/contain no-repeat,
                            url("/squircle.svg") center/calc(100% - 2px) calc(100% - 2px) no-repeat;
              -webkit-mask-composite: xor;
                      mask: url("/squircle.svg") center/contain no-repeat,
                            url("/squircle.svg") center/calc(100% - 2px) calc(100% - 2px) no-repeat;
                      mask-composite: exclude; }

/* THE CARD: the surface, its cast, and its rim as an overlay masked to a 1px ring (a border would move layout). ONE INSET on
   all four sides, and it IS the gap the eye reads: the card's first CHILD is trimmed to its cap height and its last CHILD to
   its baseline, so no font size, line height or element at an edge adds leading of its own. The trims sit on the children,
   never on the card: asked to find the card's own "last line", WebKit walked back past the fold and the button to the
   door's last point and trimmed under it (the button rose 6px, owner's screenshot 2026-09-27). A child with no lines of
   its own (the button, the QR's fold) takes no trim — a box has no leading. Where text-box is
   unsupported the lines keep their leading — the inset still holds, a few pixels wider. */
.card { position: relative; box-sizing: border-box; margin: var(--air) 0; padding: var(--card-inset); scroll-margin-top: var(--air);
        background: var(--surface); border-radius: 22px; box-shadow: 0 2px 10px var(--cast-hue); text-box-edge: cap alphabetic; }
.card > :first-child { text-box-trim: trim-start; }
.card > :last-child { text-box-trim: trim-end; }
.card::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
                padding: 1px; background: var(--rim);
                -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
                        mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude; }
.card p { margin: var(--rhythm) 0 0; }
.card > :first-child { margin-top: 0; }
.lead { text-wrap: balance; }
.card .lead { margin-bottom: 0; padding-block: 0.68rem 0.42rem; font-size: 1.3rem; font-weight: 400; line-height: 1.325; }   /* the door's tagline: a step above the body, regular weight */
.lead + .rows { margin-top: 0.1rem; }   /* the air under the tagline is the list's own margin — the two collapse into one, so it is set here */
h2 { margin: 0; font-size: 1rem; font-weight: 600; line-height: 1.45; }
.card > h2 { margin-top: calc(1.5 * var(--rhythm)); }

/* ROWS — the door's points and What you need: a bold label over its line, a hairline between peers and none above the first */
.rows { list-style: none; margin: 0.35rem 0 0; padding: 0; }
.rows li { padding: 0.7rem 0; }
.rows li + li { border-top: 1px solid var(--hairline); }
.rows b { display: block; margin-bottom: 0.25rem; font-weight: 600; }   /* a little air under the label */
.card > .rows:last-child > li:last-child { padding-bottom: 0; }   /* a list that ends its card ends at its last line, not below it */

/* THE CAPSULE: full width, 50px, the accent under a faint sheen, 1px rims top and bottom — no outer shadow */
.capsule { display: flex; align-items: center; justify-content: center; box-sizing: border-box; min-height: 50px;
           margin: 0.75rem 0 0; padding: 0.65rem 1.3rem; border-radius: 999px;
           background: var(--accent) linear-gradient(180deg, rgb(255 255 255 / 0.04), rgb(0 0 0 / 0.026));
           box-shadow: var(--btn-rim); color: var(--accent-text); font-size: 17px; font-weight: 600; text-align: center;
           text-decoration: none; }
@media (hover: hover) {
  .capsule:hover { background-image: linear-gradient(var(--btn-lift), var(--btn-lift)); }
  a.out:hover { opacity: 0.7; }                                  /* an outside link and its glyph, as one */
}
button.capsule { width: 100%; border: 0; font-family: inherit; cursor: pointer; }   /* a capsule that acts in place (Copy) */
/* THE COPYABLE (2.0.106): the settings page's — a monospace box on the panel inset, read and copied, never typed into, scrolling
   sideways rather than wrapping code, and its Copy capsule under it (copy.js) */
.code { margin: var(--rhythm) 0 0; padding: 0.6rem; background: var(--panel-inset); border-radius: 5px; color: var(--text);
        font: 0.8rem/1.45 ui-monospace, Menlo, monospace; white-space: pre; overflow-x: auto; user-select: all; }
   /* (its code never widens a card: the lanes and a step's text column are minmax(0, 1fr), so a long line scrolls in its box) */
.note, small { font-size: 0.8rem; }                            /* small print: the note's size, in whatever colour its text is */
.note { line-height: 1.3; }
.note, .muted { color: var(--muted); }                        /* the note's colour, alone where a block keeps its size */
.card .note { margin-top: 0.5rem; }
.door .note { margin-top: 22px; text-align: center; text-wrap: balance; }                        /* the button's lines, centred under it — its note and the scan's line alike */

/* THE SCAN: the same door as a code, on every device (owner-ruled: one website for all devices). The button's note IS the fold's
   summary — one element, one style — and "Or scan the QR" continues its last line, the chevron after it turning when open. A
   summary is the only thing that can open a fold without script, so the whole note is its tap target. The code is dark on
   white in both themes, the icon at its centre. */
.scan { display: flow-root; }   /* THE FOLD IS ITS OWN FORMATTING CONTEXT, so the card's trims never reach inside it: WebKit trimmed the
   note's first line to its cap height only while the fold was open (the note jumped 3.7px, owner's recording 2026-09-27) */
.scan > summary { text-box: trim-both cap alphabetic; }   /* the note's own trims, both edges: the button's inset above its cap height
   equals the card's below its baseline (owner-asked, 2.0.20); its own property in both fold states, so opening moves nothing */
.scan summary::after { margin-left: 0.25em; line-height: 0; }   /* the 1rem chevron adds no height: the line keeps the note's own step */
.cue { white-space: nowrap; }                                    /* "Or scan the QR" moves as one piece when a narrow line must wrap */
.qr { margin: 1rem auto 0; position: relative; width: 176px; padding: 10px; box-sizing: border-box; background: #fff; border-radius: 22px; }
.qr svg { display: block; width: 100%; height: auto; }   /* its viewBox keeps 2.7 of the code's 4-unit quiet modules: with the box's
                                                            10px padding, the white around the code is half what the full zone gave */
.qr i { position: absolute; inset: 50% auto auto 50%; transform: translate(-50%, -50%); width: 38px; height: 38px;
        background: center/contain no-repeat url("/icon.svg");
        -webkit-mask: center/contain no-repeat url("/squircle.svg"); mask: center/contain no-repeat url("/squircle.svg"); }

/* EVERY SUMMARY: no marker, and a chevron that turns when open */
summary { list-style: none; cursor: pointer; }
summary::-webkit-details-marker { display: none; }
summary::after { content: "›"; display: inline-block; color: var(--muted); opacity: 0.5; font-size: 1rem; transition: transform 0.15s; }
details[open] > summary::after { transform: rotate(90deg); }
summary:focus-visible { border-radius: 6px; }

/* A FOLD (details.card) PREVIEWS WHAT OPENING IT GIVES (2.0.104: every fold is what 2.0.99–2.0.103 called a peek). ITS HEAD IS AN
   ORDINARY CARD'S: the card's inset above the heading, the heading trimmed at its top only, what it opens taking its own margin —
   title and body line for line as a card that does not fold; the chevron at the far edge on the cap's middle, a box that nets to
   no height. SHUT, it is --peek tall (a pair's partner: its lead's height, --shut, written by lanes.js), its text shown (::details-
   content; a browser without it shows the head alone), clipped at the card's edge, blurring and fading into the card's own ground
   toward its foot — and the whole card is its head (below). */
details.card { padding-block: 0; }
details.card[open] { padding-bottom: var(--card-inset); }
details.card > summary { position: relative; display: flex; align-items: center; gap: 0.8rem; padding-top: var(--card-inset); }
details.card > summary > h2 { text-box: trim-start cap alphabetic; }
details.card > summary::before { content: ""; position: absolute; inset: 0 calc(-1 * var(--card-inset)); }
details.card > summary::after, .pair > section.card > h2::after {
   content: ""; display: inline-block; color: var(--muted); opacity: 0.5; font-size: 1rem; transition: transform 0.15s;
   margin-left: auto; width: 0.8em; height: 0.8em; align-self: flex-start;
   margin-block: calc(0.5cap - 0.4em) -0.4em;   /* the chevron's middle on the cap's middle */
   background: currentColor; -webkit-mask: center/contain no-repeat url("/chevron.svg"); mask: center/contain no-repeat url("/chevron.svg"); }
   /* chevron.svg (2.0.87–2.0.88; every other fold keeps "›"): outside.svg's pen — a 24-unit box, a 2.6 stroke, round ends */
details.card > summary:focus-visible { outline-offset: 0; }
/* A PAIR'S CHEVRON IS ITS LEAD'S (2.0.112): the left card's heading wears it and turns it while its partner is open (:has), and a
   tap anywhere on that heading's area — the card's inset above it and at its sides, down to the air under it, the area a shut
   fold's head covers — opens or shuts the partner (lanes.js). The partner keeps its own tap, and no chevron of its own. */
.pair > section.card > h2 { position: relative; padding-right: calc(0.8em + 0.8rem); cursor: pointer; }   /* a block, so its top
   trim holds (a flex heading lost it and grew 5.4px): the chevron is laid at its right edge instead of flowing */
.pair > section.card > h2::after { position: absolute; top: 0; right: 0; }
.pair > section.card > h2::before { content: ""; position: absolute;
   inset: calc(-1 * var(--card-inset)) calc(-1 * var(--card-inset)) calc(-1 * var(--rhythm)); }
.pair:has(> details[open]) > section.card > h2::after { transform: rotate(90deg); }
.pair > details.card > summary::after { display: none; }
details.card:not([open]) { height: var(--peek); overflow: hidden; }
.pair > details.card:not([open]) { height: var(--shut, var(--peek)); }
details.card:not([open])::details-content { content-visibility: visible; }
/* NO TEXT AT THE FOOT (2.0.133): a shut fold's text stops an inset above the card's foot — the head and the text are the fold's two
   rows (grid), the text's row clipped, the inset below it empty — so it ends where the veil (below) is already solid. It ran on
   under the veil to the card's clip, and at the foot's fractional device pixel the clip's antialiased edge let that text through
   the veil above it — two layers each clipped to a partial pixel, the lower one showing: a strip of the next line's glyphs along
   the card's edge (owner's iPad, zoomed; Chromium at 1.5×/2.25×, 174 of 624 shut cards). Now nothing lies under that edge to show. */
details.card:not([open]) { display: grid; grid-template-rows: auto minmax(0, 1fr); padding-bottom: var(--card-inset); }
details.card:not([open])::details-content { overflow: clip; }
/* ONE LANE, ONE CARD (2.0.101): where the lanes do not stand, a pair is one card — the lead its top, the partner its foot, one
   box. The join has no corners, no gap, no ring and no cast: each card's cast is clipped at the join, the partner's ring goes,
   and the partner overlaps the lead by 1px, so no sub-pixel edge lets the page or a shadow through. The lead keeps its inset
   below — the air from its last line (descenders and all) to the partner's title, which takes none above. The partner is still
   its fold — its preview, its tap, its one-open group. */
main:not(.lanes) > .pair > .card:first-child { margin: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0;
                                               clip-path: inset(-2rem -2rem 0); }
main:not(.lanes) > .pair > .card:last-child { margin: -1px 0 0; border-top-left-radius: 0; border-top-right-radius: 0;
                                              clip-path: inset(0 -2rem -2rem); }
main:not(.lanes) > .pair > .card:last-child::before { display: none; }
main:not(.lanes) > .pair > details > summary { padding-top: 0; }
/* …AND ITS SHUT SIZE IS THE STYLESHEET'S, NOT A SCRIPT'S (2.0.113): the pair is a grid of rows 10fr and 7fr, and a shut partner
   contributes no size of its own (contain: size), so the lead's height sets the fr and the partner's row is --part of it (owner-
   ruled 2.0.128: 65%; 2.0.129: 67%; 2.0.130: 63%; 2.0.131: 64%; 2.0.132: 65%; 2.0.135: 66%; 2.0.138: 75%; 2.0.139: 85%; 2.0.140: 100%; 2.0.141: 60%; 2.0.142: 70%) — less --part of the lead's inset (its bottom margin, handed back below the pair), since its head took none
   above (2.0.102): what shows is --part of the lead-less-inset 2.0.113 showed. The page's
   first paint is therefore its final one: 2.0.101–2.0.112 painted a fallback height until lanes.js measured the lead (owner's
   recording, a phone refresh: 142.4px, then 120.3px). Open, the rows are each card's own. */
main:not(.lanes) > .pair { --part: 0.7; display: grid; grid-template-rows: 10fr 7fr;   /* 7 / 10 = --part (a fr takes no calc) */
                           margin-block: var(--air) calc(-1 * (var(--part) * var(--card-inset) + 1px)); }
main:not(.lanes) > .pair > details.card:last-child:not([open]) { height: auto; contain: size; margin-bottom: calc(var(--part) * var(--card-inset) + 1px); }
main:not(.lanes) > .pair:has(> details[open]) { grid-template-rows: auto; margin-bottom: var(--air); }
/* THE WHOLE SHUT CARD IS ITS HEAD (2.0.100): the head's own hit area (summary::before) is laid over the card entire — the head
   un-positioned, so the area takes the card's box — and a tap anywhere lands on the head, which opens the fold natively. The
   links beneath it take no tap until the card is open. Nothing is hidden or removed: the text and the links stay in the page,
   in the markup, for any reader or crawler. */
details.card:not([open]) > summary { position: static; }
details.card:not([open]) > summary::before { inset: 0;   /* …AND IT BLURS AS IT FADES (2.0.102; the app's nav-bar veil, what suits
   a card): a Gaussian blur of what lies under it, over the same band the veil fades — none at the fade's top, full at the
   foot, the mask's curve rising slowly first as the veil's own blur ladder does; the veil's tint then lays over it. A second
   mask layer keeps it to the text's column — half the card's inset clear at each side — so the card's edge and ring stay sharp.
   ONE LENGTH ON EVERY CARD (owner-ruled 2.0.136: "a blur and fade that is of equal length on every card that has it — no matter
   the size"): both are LENGTHS from the foot up — --band, 85px (owner-ruled 2.0.137; 2.0.136 took 60% of --peek, 102px) — the
   blur's curve the shares it was of that band — so a shorter card (a pair's partner, one lane's 66%) wears the same band, and a card shorter than the band shows
   its upper part cut off at its head, never a smaller one. */
   -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
   --column-mask: linear-gradient(90deg, transparent calc(var(--card-inset) / 2), #000 var(--card-inset),
                                         #000 calc(100% - var(--card-inset)), transparent calc(100% - var(--card-inset) / 2));
   --ramp: linear-gradient(transparent calc(100% - var(--band)), rgb(0 0 0 / 0.25) calc(100% - 19 / 30 * var(--band)),
                           #000 calc(100% - 0.25 * var(--band)));   /* the ramp's curve as 2.0.136 drew it on a --peek card */
   -webkit-mask-image: var(--ramp), var(--column-mask);
   -webkit-mask-composite: source-in;
           mask-image: var(--ramp), var(--column-mask);
           mask-composite: intersect; }
details.card:not([open])::after { content: ""; position: absolute; inset: auto 0 0; height: var(--band); pointer-events: none;
                                     background: linear-gradient(transparent, var(--surface) calc(100% - var(--card-inset))); }

/* THE STEPS: the card's own text — no panel (owner-asked, 2.0.37) — and a numbered chip beside each line, centred on its first */
.steps { margin: var(--rhythm) 0 0; padding: 0; list-style: none; counter-reset: step; }   /* the rhythm above, as a card's paragraph */
.steps li { counter-increment: step; display: grid; grid-template-columns: var(--step) minmax(0, 1fr); column-gap: var(--step-gap); }
.steps li + li { margin-top: calc(1.5 * var(--rhythm)); }   /* steps part by the air a card's title takes */
.card > .steps:last-child > li:last-child > :last-child { text-box-trim: trim-end; }   /* the card's bottom trim, carried into the grid row it
                                                                                  cannot reach: the last line ends on its baseline */
.steps li::before { content: counter(step); display: grid; place-items: center; width: var(--step); height: var(--step); margin-top: calc((1.45 * 0.95rem - var(--step)) / 2);
                    border-radius: 50%; background: var(--chip); color: var(--accent); font-size: 0.7rem; font-weight: 650; }
/* EVERY STEP IS A NUMBERED TITLE (docs 2.0.107; the rule for every list of steps, 2.0.108) — the chip beside it, in the ordinary
   text's weight and ink — and everything the step says under it at the card's full width, not indented from the number. */
.steps h3 { margin: 0; font: inherit; color: inherit; }
.steps li > :not(h3) { grid-column: 1 / -1; }

/* THE SWITCH CARD (Night mode): the app's row and toggle (settings_page.html) — a title and a 51 × 31 switch. The row is one cap
   tall, its title trimmed to that cap and the switch centred on it, so the card is a shut fold's height: the inset, a cap, the
   inset. The whole card taps it, as a fold's head does. */
.row { position: relative; display: flex; align-items: center; gap: 0.8rem; height: 1cap; font-size: 1rem; cursor: pointer; }
.row::before { content: ""; position: absolute; inset: calc(-1 * var(--card-inset)); }
.row .lab { flex: 1 1 auto; font-weight: 600; color: var(--text); text-box: trim-both cap alphabetic; }
input[type=checkbox][data-kind="toggle"] { position: relative; flex: none; width: 51px; height: 31px; margin: 0;
  appearance: none; -webkit-appearance: none; border-radius: 16px; background: var(--toggles); cursor: pointer; transition: background 0.2s; }
input[type=checkbox][data-kind="toggle"]::after { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px;
  border-radius: 50%; background: var(--accent-text); transition: left 0.2s; }
/* ON IS THE PAINTED THEME, not the box's `checked` (2.0.113): <html data-theme> is set in the <head> before the first paint, where
   `checked` is set at DOMContentLoaded — after a paint the browser was free to make, so in Night mode the switch painted off and
   then slid on, on every refresh (owner's recording). The switch is the theme's, and shows it; `checked` still carries it for a
   screen reader and the tap. */
:root[data-theme="dark"] #themePin { background: var(--positive); }
:root[data-theme="dark"] #themePin::after { left: 22px; }

footer { margin: 2rem 0 0; padding: 0 0.5rem; text-align: center; }
footer p { margin: 0; }

@media (prefers-reduced-motion: reduce) { summary::after, .pair > section.card > h2::after, input[data-kind="toggle"], input[data-kind="toggle"]::after { transition: none; } }
