/*
 * pages.css: every page but the front page (inc/site.php enqueues it everywhere else,
 * after site.css and before case.css). The inner pages' blocks, moved here from site.css
 * in its own order on 2026-10-25: they were two fifths of site.css, which every page
 * waits for before its first paint, so the front page waited on 110 KB of rules it could
 * never use.
 *
 * What may come here: a rule that can never match on the front page, in any state,
 * including the classes site.js adds as it runs (a page's own section class, say). A
 * rule the front page can match stays in site.css, even inside one of these blocks:
 * P5's face rules and the front page's About arrow did. site.css's header, motion
 * patterns and tokens apply here as there.
 *
 * Order: this file prints after site.css, so a rule here beats a rule in site.css of the
 * same specificity wherever both match. When the blocks moved, every such pair that
 * could meet on one element was checked, and none changes what wins. A new rule here
 * that must lose to a site.css rule needs that rule to be the more specific.
 */

/* ==== The services page, "What we do" (D-24). Light page, the care band ink ======= */
/* A jargon-buster (page-services.php): the head with every word the page explains as a
   pill, then a kit window per part, headed by the trade's word for it in the magenta
   (4.42:1 on white, 3.98:1 on paper: display size only) and its plain name. Each window
   is set out for what its part has to say (D-74, Sam 2026-10-27: the windows all
   looked and did the same thing): split, promise, checklist, picture, statement,
   compare, before-after, pair and key, below, each written phone first. Building your
   site and Yours to keep are calm; Looking after it is the ink band and the page's one
   standout ("line"). */
.svc-head{--scene:44.5%;--top-copy:34rem;padding-block:0 var(--space-4)}
.svc-head h1{margin:0;font-family:var(--font-display);font-weight:400;font-size:var(--fs-poster);line-height:.95;letter-spacing:-.03em;text-wrap:balance}
.svc-head__lead{display:grid;gap:var(--gap-text);max-inline-size:36ch;margin-block-start:var(--gap-text);font-size:clamp(1.25rem, 1rem + 1.1vw, 2rem);font-weight:500;line-height:1.38;letter-spacing:-.01em;color:var(--ink)}
.svc-head__lead p+p{color:var(--ink-soft)}
/* Balanced, not only pretty (.section p): pretty still ended a line on the next
   sentence's "It" at 1366 and 1440 wide (look-2). The lead is four lines at most, within
   what balance covers. */
.svc-head__lead p{text-wrap:balance}
.svc-index{display:grid;gap:var(--space-2);margin-block-start:var(--space-3)}
.svc-index__label{font-weight:700}
.svc-index__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.625rem}
/* The kit's pill at link size: white, the ink outline, the display face, a magenta arrow
   down (4.42:1 on white). The ground swaps at once on a hover; only a press moves. 46px,
   not 44, as the contact page's pills are. */
.svc-index__pill{display:inline-flex;align-items:center;gap:.45em;box-sizing:border-box;min-block-size:46px;padding:.5em .9em .5em 1.1em;font-family:var(--font-display);font-size:var(--fs-body);line-height:1.1;color:var(--ink);text-decoration:none;background:var(--white);border:var(--line) solid var(--ink);border-radius:999px;-webkit-tap-highlight-color:transparent;transition:transform var(--t-feedback) var(--ease-out)}
.svc-index__down{flex:none;inline-size:.95em;block-size:.95em;color:var(--accent)}
/* At most 8vw (device pass, 2026-10-27): at 200% text "Responsive" and its arrow made a
   333px pill, which widened the index and its line past a 320 or 360 screen. Never at
   100% text, where 8vw is over the body size from 320. */
.svc-index__pill{font-size:min(var(--fs-body), 8vw)}
@media (hover:hover){
  .svc-index__pill:hover{background:var(--lit)}
}
.svc-index__pill:active{transform:translateY(1px)}
.svc-index__pill:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
/* From 64em, and on a phone held sideways, the h1 and the lead stand in the page-top
   picture's empty half (the page-tops block below), the h1 sized by that column so
   "What we do" keeps one line. */
@media (min-width: 64em), (orientation: landscape) and (max-height: 35em){
  .svc-head h1{font-size:clamp(3rem, 16cqi, 7rem)}
}
/* The picture's paper is the page's (2026-10-27, Sam's front page item 5 applied here:
   a picture whose ground differs from the page's paper must match it, no seam and no
   tint). The studio in all three files was regraded from its own #F2EEE6 to the page's
   #FBFAF7, keeping 65% of the ground's shading so its soft shadows stay: each pixel
   moved to #FBFAF7 less 0.65 of its difference from #F2EEE6, in full from 88% lightness
   and not at all below 62%, nor where its colour passes 16% (from 7%), so the navy and
   magenta clay are untouched. The head's ground is the page's paper, so the band no
   longer stands on a beige of its own that faded out below it.
   Past 1920 the picture's right edge, regraded, is #F7F5F1 (its last 2%), so the
   ground darkens to that, as the page-tops block does for the beige. */
.svc-head.page-top{--top-ground:var(--page)}
@media (min-width: 120.0625em){
  .svc-head.page-top{background:linear-gradient(transparent calc(100% - var(--space-4)), var(--page)),linear-gradient(90deg, var(--top-ground) 50%, #F7F5F1 calc(50% + 60rem))}
}

.svc-group{padding-block:var(--pad-m)}
/* The groups' headings never past 18vw (device pass, 2026-10-27): at 200% text the 80px
   floor ran "Building" and "Looking" 10px past the frame at 390 and 80px past it at 320.
   Never at 100% text, where --fs-h2 is under 18vw from 320. */
.svc-group > .s-head > h2{font-size:min(var(--fs-h2), 18vw)}
/* The windows' padding is held to its size at the usual 16px text (px, the same figures
   then): with a reader's text at 200% at 390 it doubled to 40px a side and left the
   words 230px (2026-10-27, device pass; How it works' road does the same). */
.svc-parts{--win-pad:clamp(20px, 12.8px + 2vw, 48px);list-style:none;margin-block:var(--gap-head) 0;padding:0;display:grid;row-gap:clamp(2rem, 1.25rem + 3vw, 3.5rem)}
.part{min-inline-size:0}
/* ---- What every window shares (D-74: a different window for each part). Each window
   is the container its words are sized against (cqi), so a long word always fits its
   own column; every piece is a grid item a layout below places by name, and spaced by
   its own top margin, as the layouts differ in what follows what. */
.part__window{container-type:inline-size;display:grid;grid-template-columns:minmax(0,1fr);align-items:start;column-gap:clamp(1.5rem, 4cqi, 4rem)}
.part__window > *,.part__half > *{min-inline-size:0}
/* The trade's word in the magenta (4.42:1 on white, 3.98:1 on paper: display size
   only). 12.5cqi keeps "Responsive" inside a phone's window down to 320px, with a
   reader's own text spacing too (WCAG 1.4.12, a11y-5); past that, a larger text size
   breaks the word rather than run it out of its window. Each layout sets its own size:
   huge where the word is the point, a tag where the promise is. Each floor is the
   smaller of its rem and a share of the window (cqi) the longest word fits: at the
   usual text size the rem always wins from 320 up, so nothing changes there, and at
   200% text the word stays whole instead of breaking "SE/O", "Respo/nsive" and
   "Domai/n" (2026-10-27, device pass). The display promises below do the same. */
.part__term{grid-area:term;display:grid;justify-items:start;margin:0;font-family:var(--font-display);font-size:clamp(min(1.875rem, 16cqi), 12.5cqi, 6.5rem);line-height:1;letter-spacing:-.03em;color:var(--accent);overflow-wrap:anywhere}
.svc-parts .part__name{grid-area:name;font-size:clamp(1.5rem, 1.15rem + 1.5vw, 2.25rem);line-height:1.1;letter-spacing:-.02em;margin-block-start:var(--space-1)}
.part__pic{grid-area:pic;display:block;margin-block-start:var(--space-3)}
.part__pic img{display:block;inline-size:100%;block-size:100%;object-fit:contain}
.part__window .part__lead{grid-area:lead;margin-block-start:var(--space-3);max-inline-size:36ch;font-size:var(--fs-lead);font-weight:500;line-height:1.4;letter-spacing:-.01em;color:var(--ink)}
.part__window .part__soft{grid-area:soft;margin-block-start:var(--space-2);max-inline-size:48ch;line-height:1.55;color:var(--ink-soft)}
.part__window .part__strong{grid-area:strong;margin-block-start:var(--space-2);max-inline-size:44ch;font-weight:700;line-height:1.45;color:var(--ink)}
.part__window .part__def{grid-area:def;margin-block-start:var(--space-2);max-inline-size:46ch;line-height:1.55;color:var(--ink-soft)}
.part__window .part__label{grid-area:label;margin-block-start:var(--space-3);font-weight:700;color:var(--ink)}
/* Each line keeps its own top margin over .section p's margin:0 (site.css), which
   out-ranks a lone class: hence .part__window before each. */
/* A promise, set as the window's statement in the display face. */
.part__window .part__promise{grid-area:promise;margin-block-start:var(--space-3);font-family:var(--font-display);font-size:clamp(1.875rem, 9cqi, 6rem);line-height:1;letter-spacing:-.03em;color:var(--ink);text-wrap:balance}
/* The beats, labelled, under ink rules: the page's old stamp, now in the few windows that
   set two or three short lines side by side. */
.part__beats{grid-area:beats;display:grid;gap:var(--space-3);margin:var(--space-3) 0 0}
.part__beat{display:grid;align-content:start;gap:var(--space-1);padding-block-start:var(--space-2);border-block-start:var(--line) solid var(--ink)}
.part__beat dt{font-weight:700;color:var(--ink)}
.part__beat dd{margin:0;max-inline-size:46ch;line-height:1.55;color:var(--ink-soft)}
@media (min-width: 48em){
  .part__beats{grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),1fr));column-gap:var(--gutter)}
}
/* The tick, a mask over the magenta so its colour stays the token's: the pills', the
   list's and the comparison's. */
.part__chips li::before,.part__ticks li::before,.compare__us::before{content:"";flex:none;background:var(--accent);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5 6.5 12.5 13.5 3.5' fill='none' stroke='%23000' stroke-width='2.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50% 50% / contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5 6.5 12.5 13.5 3.5' fill='none' stroke='%23000' stroke-width='2.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50% 50% / contain no-repeat}

/* ---- split: The build. The scene large, beside the words from 64em (the window
   reflowing into a phone is what "responsive" means, so it leads), and what every build
   comes with as the kit's pills, one thing each, in place of a sentence of six. */
.pw--split{grid-template-areas:"term" "name" "pic" "lead" "soft" "get"}
/* The scene ends as a phone in the middle of its frame, so it stands on a paper stage
   that fills its side of the window: the space round the phone reads as the stage, not
   as a gap. */
.pw--split .part__pic{display:grid;grid-template-columns:minmax(0,1fr);align-content:center;box-sizing:border-box;padding:clamp(.75rem, 3cqi, 2.5rem) clamp(.5rem, 2cqi, 2rem);border-radius:var(--radius-sm);background:var(--paper)}
.pw--split .part__lead{max-inline-size:32ch}
.part__get{grid-area:get;margin-block-start:var(--space-3)}
.part__window .part__get .part__label{margin:0}
.part__chips{list-style:none;margin:.75rem 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem}
.part__chips li{display:inline-flex;align-items:center;gap:.4em;box-sizing:border-box;min-block-size:2.25rem;padding:.3em .8em .3em .6em;border:var(--line) solid var(--ink);border-radius:999px;background:var(--white);font-size:clamp(.9375rem, .9rem + .2vw, 1.0625rem);font-weight:600;line-height:1.2;color:var(--ink)}
.part__chips li::before{inline-size:1em;block-size:1em}
@media (max-width: 63.99em){
  .pw--split .part__pic > .demo{max-inline-size:26rem;margin-inline:auto}
}
@media (min-width: 48em) and (max-width: 63.99em){
  .pw--split{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-areas:"term term" "name name" "pic pic" "lead soft" "get get"}
  .pw--split .part__soft{margin-block-start:var(--space-3)}
}
@media (min-width: 64em){
  /* Rows above and below the words take the spare height, so the words sit centred
     beside the scene however their lengths change. 7cqi keeps "Responsive" inside its
     column at 1024 (362px of 403) and at 1440 (468 of 600). */
  .pw--split{grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);grid-template-rows:1fr repeat(5,auto) 1fr;grid-template-areas:"pic ." "pic term" "pic name" "pic lead" "pic soft" "pic get" "pic .";column-gap:clamp(2rem, 5cqi, 5rem)}
  .pw--split .part__term{font-size:clamp(2.5rem, 7cqi, 6rem)}
  .pw--split .part__pic{align-self:stretch;margin:0;max-inline-size:none}
  /* The scene drawn a quarter larger than its stage, so the phone it ends on fills more
     of it: its empty sides spill over the stage's padding, unseen, and the wide window
     it starts as (72% of the scene) still sits inside the stage. Not clipped: a clip
     would hide a fifth of the scene from bootPartDemos' "all of it on screen" test, and
     it would never play. */
  .pw--split .part__pic > .demo{inline-size:125%;margin-inline:-12.5%}
}

/* ---- promise: Your words. The build group's one ink window (the closing pair's ink
   card's colours), the word a small tag on its plate, and the promise as a quote across
   the window. The clay sheet sits on a white disc on the window's corner, a sticker:
   its navy outline fades on ink (decision D-3's reason for paper windows on the ink
   band). Left-aligned on a phone, the words clear of the disc; centred from 48em. */
.part--promise .window{background:var(--ink);color:var(--text-primary)}
.part--promise .window::before{border-block-end-color:var(--text-primary)}
.part--promise .window::after{background:var(--text-primary)}
.pw--promise{grid-template-areas:"term" "name" "def" "promise" "beats";position:relative}
.pw--promise .part__pic{grid-area:auto;position:absolute;top:calc(var(--tab) + var(--space-2));right:var(--space-2);inline-size:clamp(72px, 48px + 5vw, 120px);aspect-ratio:1;margin:0;box-sizing:border-box;padding:.6rem;border:var(--line) solid var(--text-primary);border-radius:50%;background:var(--white);box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent);transform:rotate(8deg)}
.pw--promise .part__term{justify-self:start;font-size:var(--fs-body);letter-spacing:0}
.pw--promise .part__term > span{display:inline-block;padding:.4em 1em;border-radius:999px;background:var(--white);color:var(--ink);box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
/* Only the name sits beside the disc: the definition starts below it at every phone
   width (17px clear at 320 and 390), so it takes the window's width. Disc and room in
   px, the same as before at 16px text: at 200% they had doubled with it, and the
   definition ran a word a line, 900px tall (2026-10-27, device pass). */
.pw--promise .part__name{padding-inline-end:clamp(80px, 56px + 5vw, 128px)}
.pw--promise .part__name{margin-block-start:var(--space-2);color:var(--text-primary)}
.pw--promise .part__def{color:var(--text-secondary)}
/* The floor comes down with the window below 390 (14cqi), so the quote is two lines
   at 320 and 360, not "You / approve / every / word." a word a line (it was four at
   320, at 40px); unchanged from 390. */
.pw--promise .part__promise{margin-block-start:var(--space-4);font-size:clamp(min(2.5rem, 14cqi), 10.5cqi, 7rem);line-height:.98;color:var(--text-primary)}
.pw--promise .part__promise::before,.pw--promise .part__promise::after{color:var(--accent)}
.pw--promise .part__promise::before{content:"\201C"}
.pw--promise .part__promise::after{content:"\201D"}
.pw--promise .part__beats{margin-block-start:var(--space-4)}
.pw--promise .part__beat{border-block-start-color:var(--rule-ink)}
.pw--promise .part__beat dt{color:var(--text-primary)}
.pw--promise .part__beat dd{color:var(--text-secondary)}
@media (min-width: 48em){
  .pw--promise{justify-items:center;text-align:center}
  .pw--promise .part__term{justify-self:center}
  .pw--promise .part__name,.pw--promise .part__def{padding-inline:0}
  .pw--promise .part__def{max-inline-size:40ch}
  .pw--promise .part__promise{max-inline-size:14ch}
  .pw--promise .part__beats{inline-size:min(100%,52rem);text-align:start}
  .pw--promise .part__pic{top:calc(var(--tab) + var(--win-pad) * .75);right:var(--win-pad)}
}

/* ---- checklist: Found on Google. SEO is three letters, so it can be the biggest word
   on the page; then the basics every site has as ticks across the window, each under
   its rule like a line in a list of jobs done, and the honest line on ranking. */
.pw--checklist{grid-template-areas:"term" "name" "pic" "lead" "soft" "label" "ticks" "note"}
.pw--checklist .part__term{font-size:clamp(min(4rem, 40cqi), 26cqi, 12rem);line-height:.85}
.pw--checklist .part__label{margin-block-start:var(--space-4);font-family:var(--font-display);font-weight:400;font-size:var(--fs-step);line-height:1.15;letter-spacing:-.01em}
.part__ticks{grid-area:ticks;list-style:none;margin:var(--space-2) 0 0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,16rem),1fr));column-gap:var(--gutter)}
.part__ticks li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:.75rem;padding-block:.75rem;border-block-start:var(--line) solid var(--ink);font-weight:600;line-height:1.4;color:var(--ink);text-wrap:pretty}
.part__ticks li::before{inline-size:1.4rem;block-size:1.4rem;margin-block-start:.05em}
/* At most 7.5vw (device pass, 2026-10-27): at 200% text on a 320 phone the words beside
   their ticks had 131px, and "description" (175px) ran past the window's edge. Never at
   100% text, where 7.5vw is over the body size from 320. */
.part__ticks li{font-size:min(var(--fs-body), 7.5vw)}
/* The honest line on ranking and the search work sold separately: the glow's pink as a
   flat strip, ink words (12.7:1), kept to a reading measure across a wide window. */
.svc-parts .part__note{grid-area:note;justify-self:start;max-inline-size:60ch;margin-block-start:var(--space-3);padding:var(--space-2) clamp(1rem, .7rem + 1.2vw, 1.5rem);border-radius:var(--radius-sm);background:var(--lit);color:var(--ink);font-weight:600;line-height:1.5}
/* "Ask us" (P1-26): on the pink the faint line other text links rest on read as no line
   at all, so here it is the full ink. */
.svc-parts .part__note .text-link::before{opacity:1}
/* Its press area 46px tall (it was 26 at 390), the line it sits in unmoved: the extra is
   padding, taken back by a negative margin, and the underline is placed from the
   middle of the box, so it stays under the words (2026-10-27, device pass). 46, not
   44, as How it works' .stop__more is: the window sinks to .96 as the next comes over
   it, and the link is still 44px while it does. */
.svc-parts .part__note .text-link{padding-block:max(0px, (46px - 1lh) / 2);margin-block:min(0px, (1lh - 46px) / 2)}
@media (min-width: 48em){
  .pw--checklist{grid-template-columns:minmax(0,1fr) minmax(0,40%);grid-template-areas:"term pic" "name pic" "lead pic" "soft pic" "label label" "ticks ticks" "note note"}
  .pw--checklist .part__term{font-size:clamp(4.5rem, 12cqi, 9rem)}
  .pw--checklist .part__pic{align-self:center;margin:0}
}
@media (min-width: 64em){
  .part__ticks{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* ---- picture: Motion and film. The window is the film panel's picture, edge to edge
   under its tab, and its film plays over it (bootFilms): a part about movement shows
   movement before it says anything. The clay symbol keeps to the right of the frame
   all through the film, so from 64em the words stand in the empty paper on its left,
   ink and magenta on the light ground (15:1 and 3.9:1, the word at display size). On a
   phone and an upright tablet the frame is too narrow to share: the words go under it. */
.pw--picture{padding:var(--tab) 0 0;overflow:hidden;overflow:clip;grid-template-areas:"pic" "term" "name" "lead" "soft"}
.pw--picture > :not(.part__pic){padding-inline:var(--win-pad)}
.pw--picture > :last-child{padding-block-end:var(--win-pad)}
.pw--picture .part__pic{position:relative;margin:0;aspect-ratio:16 / 9;overflow:hidden;overflow:clip;background:var(--slot);border-block-end:var(--line) solid var(--ink)}
.pw--picture .part__pic img{object-fit:cover;object-position:62% 50%}
.pw--picture .part__pic > .icon-film{top:0;left:0;inline-size:100%;block-size:100%;object-fit:cover;object-position:62% 50%;mix-blend-mode:normal}
.pw--picture .part__term{margin-block-start:var(--space-3)}
.pw--picture .part__lead{grid-area:lead;max-inline-size:30ch}
@media (min-width: 64em){
  .pw--picture{grid-template-columns:minmax(0,46%) minmax(0,1fr);grid-template-rows:1fr repeat(4,auto) 1fr;grid-template-areas:"." "term" "name" "lead" "soft" "."}
  .pw--picture .part__pic{grid-column:1 / -1;grid-row:1 / -1;border:0}
  .pw--picture > :not(.part__pic){position:relative;grid-column:1;padding-inline:var(--win-pad) 0}
  .pw--picture > :last-child{padding-block-end:0}
  .pw--picture .part__term{margin:0;font-size:clamp(2.5rem, 7.5cqi, 6rem)}
  .pw--picture .part__lead{max-inline-size:24ch}
  .pw--picture .part__soft{max-inline-size:34ch}
}

/* ---- statement: We run your site. A poster: the word and its pulse, then "If it ever
   breaks, one of us fixes it." across the window, the promise a visitor most needs to
   hear (a designer who vanishes after launch is on the ICP card's list of worries), then
   the day and night scene beside the two short beats. */
.pw--statement{grid-template-areas:"term" "name" "promise" "pic" "beats"}
.pw--statement .part__promise{margin-block-start:var(--space-3);font-size:clamp(min(2rem, 14cqi), 10cqi, 6.25rem)}
@media (min-width: 48em){
  .pw--statement{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);grid-template-areas:"term term" "name name" "promise pic" "beats beats"}
  .pw--statement .part__term{font-size:clamp(3rem, 7.5cqi, 6.5rem)}
  .pw--statement .part__promise{align-self:center;margin-block-start:var(--space-3);max-inline-size:13ch;font-size:clamp(2.75rem, 6cqi, 5.25rem)}
  .pw--statement .part__pic{align-self:center;margin-block-start:var(--space-3);max-inline-size:none}
  .pw--statement .part__beats{grid-template-columns:repeat(2,minmax(0,1fr));margin-block-start:var(--space-4)}
}

/* ---- compare: Safe from hackers. On your own, or with us, three rows and no prices:
   the scene and the reason first, then the rows. Each row says both, so a screen reader
   hears every row whole (its labels shown on a phone, hidden from 48em where the column
   heads, for the eye only, take over). "With us" is the kit's white card on its plate,
   one card down its column; "On your own" is plain, in the soft ink, never crossed out:
   doing it yourself is a fair choice, it is just more to do. */
.pw--compare{grid-template-areas:"term" "name" "pic" "soft" "lead" "compare"}
.pw--compare .part__lead{max-inline-size:40ch}
.compare{grid-area:compare;margin-block-start:var(--space-4)}
.compare__heads{display:none}
.compare__rows{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3)}
/* One column, the row's own width: at 200% text "With us"'s card, wider than the window
   at its longest word, had spread the row's column and run every line past the
   window's edge. Its sides in px, the same at 16px text, so the words keep room. */
.compare__row{display:grid;grid-template-columns:minmax(0,1fr);gap:.5rem}
.compare__aspect{font-family:var(--font-display);font-size:var(--fs-step);line-height:1.15;color:var(--ink)}
.compare__self{line-height:1.5;color:var(--ink-soft)}
.compare__who{font-weight:700;color:var(--ink)}
.compare .compare__us{position:relative;margin-inline-end:var(--plate-sm);padding:.75rem 16px .75rem 40px;border:var(--line) solid var(--ink);border-radius:var(--radius-sm);background:var(--white);box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent);font-weight:600;line-height:1.45;color:var(--ink)}
.compare__us::before{position:absolute;left:16px;top:1.05rem;inline-size:min(1.1rem, 17.6px);block-size:min(1.1rem, 17.6px)}
@media (min-width: 48em){
  .compare{--card:minmax(0,1.2fr)}
  /* The row's name takes a narrow column on an upright tablet, so "With us" keeps a
     measure that reads (it ran to seven lines at 768 beside a 200px column). */
  .compare{--aspect:minmax(0,8rem)}
  .compare__heads,.compare__row{display:grid;grid-template-columns:var(--aspect) minmax(0,1fr) var(--card);column-gap:var(--gutter)}
  .compare .compare__heads{align-items:end;margin:0}
  .compare__head{font-weight:700;color:var(--ink);padding-block-end:.75rem}
  .compare__head--self{grid-column:2}
  .compare__head--us{grid-column:3;padding:.85rem 1.25rem .5rem;border:var(--line) solid var(--ink);border-block-end:0;border-radius:var(--radius-sm) var(--radius-sm) 0 0;background:var(--white);box-shadow:var(--plate) var(--plate) 0 var(--accent)}
  .compare__rows{gap:0}
  .compare__row{row-gap:0}
  .compare__aspect,.compare__self{padding-block:1rem;border-block-start:var(--line) solid var(--ink)}
  .compare__aspect{font-size:clamp(1.0625rem, .95rem + .45vw, 1.25rem)}
  /* One card down the column: each row's line a slice of it, its plate a strip on the
     right that each later slice covers the foot of, so the plate reads whole. */
  .compare .compare__us{margin:0;padding:1rem 1.25rem 1rem 2.75rem;border-block:0;border-radius:0;box-shadow:var(--plate) var(--plate) 0 var(--accent)}
  .compare__us::before{left:1.25rem;top:1.3rem}
  .compare__row + .compare__row .compare__us{border-block-start:1px solid var(--rule)}
  .compare__row:last-child .compare__us{border-block-end:var(--line) solid var(--ink);border-radius:0 0 var(--radius-sm) var(--radius-sm)}
  .compare__who{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
}
@media (min-width: 48em){
  .pw--compare{grid-template-columns:minmax(0,38%) minmax(0,1fr);grid-template-rows:auto auto auto 1fr auto;grid-template-areas:"pic term" "pic name" "pic soft" "pic lead" "compare compare"}
  .pw--compare .part__term{font-size:clamp(2.5rem, 6.5cqi, 5rem)}
  .pw--compare .part__pic{align-self:center;margin:0}
}
@media (min-width: 64em){
  .compare{--aspect:minmax(0,12.5rem)}
}

/* ---- before-after: Backed up. The site knocked over by a bad update or a break-in, then
   put back from the copy: the same drawn scene twice, the first a still in its knocked
   pose (services-demo.php, pose broken), the second playing from that pose to the site
   put back once it is in view. Plain on the left; the after lifted on its plate, the
   outcome. An arrow from one to the other, down on a phone, across from 48em. */
.pw--before-after{grid-template-areas:"term" "name" "lead" "ba" "strong"}
.part__ba{grid-area:ba;list-style:none;margin:var(--space-4) 0 0;padding:0;display:grid;gap:3.25rem}
.part__ba-step{position:relative;display:grid;gap:.75rem;align-content:start}
.part__ba-step > .part__pic{grid-area:auto;margin:0;padding:clamp(.5rem, 2cqi, 1rem);box-sizing:border-box;border:var(--line) solid var(--ink);border-radius:var(--radius-sm);background:var(--white)}
.part__ba-step--after > .part__pic{box-shadow:var(--plate) var(--plate) 0 var(--accent)}
/* Balanced: at 320 the before's caption ended on "break-in." alone (2026-10-27, device
   pass); one line from 360 up, so nothing else moves. */
.part__ba-step p{font-weight:700;line-height:1.35;color:var(--ink);text-wrap:balance}
.part__ba-step--before p{color:var(--ink-soft)}
.part__ba-step--before::after{content:"";position:absolute;left:50%;top:100%;inline-size:2.25rem;block-size:3.25rem;margin-inline-start:-1.125rem;background:var(--accent);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 34'%3E%3Cpath d='M12 4v24M4 20l8 8 8-8' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50% 50% / contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 34'%3E%3Cpath d='M12 4v24M4 20l8 8 8-8' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 50% 50% / contain no-repeat}
/* What you get, said once under the two panels in the display face, as the page's
   other promises are. */
.pw--before-after .part__strong{margin-block-start:var(--space-3);font-family:var(--font-display);font-weight:400;font-size:var(--fs-step);line-height:1.15;letter-spacing:-.01em}
/* The before pose: each block where the scene knocks it (its --fy and --fr), the bar
   greyed, no tick. Drawn, never played (no data-demo, so bootPartDemos never arms it). */
.demo--broken .bk-blk{transform:translateY(calc(var(--fy) * var(--u))) rotate(var(--fr))}
.demo--broken .bk-bar{background-color:var(--rule)}
.demo--broken .bk-done{display:none}
@media (min-width: 48em){
  .part__ba{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:4.5rem}
  .part__ba-step--before::after{left:100%;top:calc(25% + 1rem);inline-size:4.5rem;block-size:2.25rem;margin:0;-webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 24'%3E%3Cpath d='M8 12h24M24 4l8 8-8 8' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 24'%3E%3Cpath d='M8 12h24M24 4l8 8-8 8' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
}
@media (min-width: 64em){
  .pw--before-after{grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-areas:"term lead" "name lead" "ba ba" "strong strong"}
  .pw--before-after .part__term{font-size:clamp(3rem, 8cqi, 6.5rem)}
  .pw--before-after .part__lead{align-self:end;margin:0}
  .part__ba{column-gap:6rem}
  .part__ba-step--before::after{inline-size:6rem}
}

/* ---- pair: Kept up to date and Small changes in one window, the software changing and
   the business changing, each half its own article and anchor, the container its word
   is sized against. One under the other on a phone, side by side from 48em, an ink rule
   between. */
.pw--pair{grid-template-columns:minmax(0,1fr)}
.part__half{container-type:inline-size;display:grid;grid-template-columns:minmax(0,1fr);grid-template-areas:"term" "name" "pic" "soft" "strong";align-content:start}
.part__half + .part__half{margin-block-start:var(--space-4);padding-block-start:var(--space-4);border-block-start:var(--line) solid var(--ink)}
.part__half .part__term{font-size:clamp(min(1.875rem, 20cqi), 15cqi, 5.5rem)}
@media (min-width: 48em){
  .pw--pair{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:0}
  .part__half{padding-inline-end:clamp(1.25rem, 3.5cqi, 3.5rem)}
  .part__half + .part__half{margin:0;padding:0 0 0 clamp(1.25rem, 3.5cqi, 3.5rem);border-block-start:0;border-inline-start:var(--line) solid var(--ink)}
}

/* ---- key: Yours to keep. The key on a paper disc, its plate on it, and "It's yours,
   not ours." to close the page: beside the key from 48em, under it on a phone. */
.pw--key{grid-template-areas:"pic" "term" "name" "def" "promise" "beats"}
.pw--key .part__pic{margin:0 0 var(--space-3);inline-size:clamp(7rem, 30cqi, 16rem);aspect-ratio:1;box-sizing:border-box;padding:6%;border:var(--line) solid var(--ink);border-radius:50%;background:var(--paper);box-shadow:var(--plate) var(--plate) 0 var(--accent)}
.pw--key .part__promise{font-size:clamp(min(2.25rem, 16cqi), 10cqi, 5.5rem)}
@media (min-width: 48em){
  .pw--key{grid-template-columns:auto minmax(0,1fr);grid-template-areas:"pic term" "pic name" "pic def" "pic promise" "pic beats";align-items:start}
  .pw--key .part__pic{grid-row:1 / -1;align-self:center;margin:0}
  .pw--key .part__term{font-size:clamp(2.5rem, 8cqi, 5.5rem)}
}
/* The two demos only this page shows (template-parts/services-demo.php, restore and
   change), in What you get's drawn kit: ink lines at one weight, white faces on magenta
   plates, magenta for what is new. Each piece is drawn at its finished place (no script,
   reduced motion: T-052) and plays from its start once site.js arms it, held there until
   its window has arrived (bootPartDemos, through site.css's --play). Under 3s, once.
   Backed up: the site goes wrong, then the copy from the box puts it back. */
.demo .bk-win{overflow:hidden;overflow:clip}
.bk-blk{border-radius:calc(1.5 * var(--u));transform-origin:50% 0}
.bk-bar{background:var(--accent)}
.bk-pic,.bk-card{background:var(--slot)}
.bk-ln{border-radius:999px;background:var(--ink)}
.bk-ln--soft{background:var(--rule)}
.demo .bk-copy{opacity:0;border:var(--dl) solid var(--ink);border-radius:calc(4 * var(--u));background:linear-gradient(var(--accent) 0 0) calc(5 * var(--u)) calc(6 * var(--u)) / calc(28 * var(--u)) calc(4 * var(--u)) no-repeat,linear-gradient(var(--ink) 0 0) calc(5 * var(--u)) calc(15 * var(--u)) / calc(18 * var(--u)) calc(3 * var(--u)) no-repeat,linear-gradient(var(--slot) 0 0) calc(5 * var(--u)) calc(23 * var(--u)) / calc(28 * var(--u)) calc(15 * var(--u)) no-repeat,var(--white)}
.demo .bk-box{border:var(--dl) solid var(--ink);border-radius:0 0 calc(5 * var(--u)) calc(5 * var(--u));background:var(--white);box-shadow:calc(4 * var(--u)) calc(4 * var(--u)) 0 var(--accent)}
.demo .bk-box::after{content:"";position:absolute;left:25%;right:25%;top:30%;block-size:calc(5 * var(--u));border-radius:999px;background:var(--accent)}
.demo .bk-lid{border:var(--dl) solid var(--ink);border-radius:calc(3 * var(--u));background:var(--white);transform-origin:0 100%}
.bk-done,.ed-done{border-radius:50%;background:var(--accent)}
.bk-done path,.ed-done path{stroke:var(--white);stroke-width:var(--sw);stroke-dasharray:1}
@keyframes bk-knock{0%{transform:none;animation-timing-function:cubic-bezier(.5,0,.75,0)}25%{transform:translateY(calc(var(--fy) * var(--u))) rotate(var(--fr));animation-timing-function:var(--ease-out)}28%{transform:translateY(calc(var(--fy) * var(--u) - 2 * var(--u))) rotate(var(--fr))}31%,77.5%{transform:translateY(calc(var(--fy) * var(--u))) rotate(var(--fr));animation-timing-function:var(--ease-arrive)}100%{transform:none}}
@keyframes bk-dim{0%,100%{background-color:var(--accent)}25%,77.5%{background-color:var(--rule)}}
@keyframes bk-lid{0%,100%{transform:none}18%,82%{transform:rotate(-32deg)}}
@keyframes bk-copy{0%{opacity:1;transform:translate(calc(176 * var(--u)),calc(56 * var(--u))) scale(.8)}28%{opacity:1;transform:translate(calc(176 * var(--u)),calc(6 * var(--u))) scale(.8);animation-timing-function:var(--ease-in-out)}72%{opacity:1;transform:none}100%{opacity:0;transform:scale(2.4)}}
/* Small changes: a message arrives, and one line of the site's opening hours and its
   picture are changed; the message gets its tick. */
.ed-msg{background:var(--white);border:var(--dl) solid var(--ink);border-radius:calc(14 * var(--u));box-shadow:calc(4 * var(--u)) calc(4 * var(--u)) 0 var(--accent);transform-origin:0 100%}
.ed-msg::after{content:"";position:absolute;left:calc(16 * var(--u));bottom:calc(-6.5 * var(--u));inline-size:calc(11 * var(--u));aspect-ratio:1;box-sizing:border-box;background:var(--white);border:solid var(--ink);border-width:0 var(--dl) var(--dl) 0;transform:rotate(45deg)}
.ed-say,.ed-ln,.ed-row,.ed-old,.ed-new{border-radius:999px;background:var(--ink);transform-origin:0 50%}
.ed-say--soft,.ed-ln--soft,.ed-row{background:var(--rule)}
.demo .ed-old{opacity:0}
.ed-new{background:var(--accent)}
.ed-pic{border-radius:calc(3 * var(--u));background:radial-gradient(circle at 30% 46%, var(--slot) 0 13%, transparent 13.5%),var(--rule)}
.ed-pic--new{background:radial-gradient(circle at 74% 34%, var(--accent) 0 10%, transparent 10.5%),radial-gradient(ellipse 46% 58% at 28% 112%, var(--ink) 0 98%, transparent 100%),radial-gradient(ellipse 40% 44% at 70% 118%, var(--ink-soft) 0 98%, transparent 100%),var(--slot)}
.ed-send path{stroke:var(--accent);stroke-width:calc(var(--sw) * 1.1)}
@keyframes ed-out{from{opacity:1;transform:none}to{opacity:0;transform:translateX(calc(12 * var(--u)))}}
@keyframes ed-wipe{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}
@media (prefers-reduced-motion: no-preference){
  .demo.is-armed .bk-blk{animation:bk-knock 2s linear calc(.15s + var(--t, 0s)) both var(--play)}
  .demo.is-armed .bk-bar{animation:bk-knock 2s linear .15s both var(--play),bk-dim 2s linear .15s both var(--play)}
  .demo.is-armed .bk-lid{animation:bk-lid 1.65s var(--ease-in-out) .75s both var(--play)}
  .demo.is-armed .bk-copy{animation:bk-copy 1s linear .95s both var(--play)}
  .demo.is-armed .bk-done{animation:d-from .35s var(--ease-arrive) 2.4s both var(--play)}
  .demo.is-armed .bk-done path{animation:d-draw .3s var(--ease-out) 2.55s both var(--play)}
  .demo.is-armed .ed-msg{animation:d-from .45s var(--ease-arrive) .1s both var(--play),d-fade .25s var(--ease-out) .1s both var(--play)}
  .demo.is-armed .ed-say{animation:d-from .3s var(--ease-out) var(--t) both var(--play)}
  .demo.is-armed .ed-send{animation:d-from .3s var(--ease-arrive) .85s both var(--play)}
  .demo.is-armed .ed-old{animation:ed-out .35s var(--ease-in-out) 1.1s both var(--play)}
  .demo.is-armed .ed-new{animation:d-from .4s var(--ease-arrive) 1.35s both var(--play)}
  .demo.is-armed .ed-pic--new{animation:ed-wipe .55s var(--ease-in-out) 1.7s both var(--play)}
  .demo.is-armed .ed-done{animation:d-from .35s var(--ease-arrive) 2.3s both var(--play)}
  .demo.is-armed .ed-done path{animation:d-draw .3s var(--ease-out) 2.45s both var(--play)}
}

/* Looking after it: THE ink band of this page, paper windows on it (the self-check's
   way, decision D-3), the windows' magenta plates bright on the ink. */
.svc-group--care{padding-block:var(--pad-l);background:var(--ink);color:var(--text-primary)}
.svc-group--care .s-intro{color:var(--text-secondary)}
.svc-group--care .window{background:var(--paper)}

/* The standout's line: a pulse drawn under each word as its window lands, the monitor's
   heartbeat (the site is running), then its end dot. The window itself rises and lifts
   off its plate (P3, data-reveal). It draws once and settles, and never beats again
   (a11y-7, option A, Stanley 2026-10-21): a transition, not an animation, on .in, which
   is never taken away, so no pulse runs on while the band is on screen. Drawn at once
   without the script and under reduced motion (T-052). */
[data-standout] .part__pulse{display:block;inline-size:min(100%,15rem);block-size:auto;aspect-ratio:240/40;margin-block-start:.5rem;overflow:visible}
[data-standout] .part__pulse path{fill:none;stroke:var(--accent);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1;stroke-dashoffset:0}
[data-standout] .part__pulse circle{fill:var(--ink)}
.js [data-standout] .part:not(.in) .part__pulse path{stroke-dashoffset:1}
.js [data-standout] .part:not(.in) .part__pulse circle{opacity:0}
.js [data-standout] .part .part__pulse path{transition:stroke-dashoffset 1s var(--ease-arrive) .45s}
.js [data-standout] .part .part__pulse circle{transition:opacity .3s var(--ease-out) 1.25s}

/* Yours to keep, and the way on (the closing pair, its own block below): the paper band
   before the ink footer. */
.svc-close{padding-block:var(--pad-m) var(--pad-l);background:var(--paper)}
@media (prefers-reduced-motion: reduce){
  .js [data-standout] .part .part__pulse path{stroke-dashoffset:0;transition:none}
  .js [data-standout] .part .part__pulse circle{opacity:1;transition:none}
  .svc-index__pill{transition:none}
}

/* ---- What we do: the windows slide up and stack (Stanley, 2026-10-22; D-42) ---- */
/* The reference picture: big cards slide up from below, each over the last, the earlier
   one's top edge still showing above it, the new one tilted a touch as it comes and
   settling flat. The pattern only: each card here is the window it already is, in both
   groups (Building your site, Looking after it), each its own stack, phones included;
   Yours to keep stays on its own. Our work's case study cards are a stack too (its own
   block says so), and every list marked [data-stack] is one. site.js (bootStack)
   measures and marks; this block reads what it writes (.is-stacking, .is-stacked,
   .is-landed, .is-passed, .is-pinned, .is-over, .is-under, --stick, --land, --sink-from,
   --sink, --pin, --stack-self, --stack-next; bootStack says what each is). Nothing here
   applies without .is-stacking or .is-pinned, so without the script, under reduced
   motion, on a phone held sideways, and in a list with fewer than two layers that fit
   the screen, the windows are the plain list above, every one finished (T-052).
   The words under the windows (Stanley, 2026-10-22, from Huge's "Working with us.":
   the cards go over the words, "it adds layers"): a group's heading and intro, marked
   [data-stack-words], stay put just under the pill (.is-pinned, at --pin) while the
   windows slide up over them, so the windows cover "Building your site" and "Looking
   after it" rather than pushing them away. They are positioned, so they paint over the
   section's ground and under every window, which comes later in the page. The first
   window comes up over them already lifted off its plate (.is-over), as the build
   windows always are: a care window lies on its plate until it lands, a plate right of
   the words' column and a plate lower, so a strip of letters stood beside it and the
   tops of Looking after it above it, and went at once as the words were hidden. Once
   that window's top is a corner's radius above their first line they are hidden
   (.is-under): covered whole there, corner and all, and never seen again from under the
   deck's foot as it leaves. Not a fade: the window is over them as it happens. Hidden,
   they are let go to their place in the page, which the scroll has taken up past them,
   and take no pointer: Our work's head, a section of its own, stayed pinned unseen to
   the page's end, over Your site next?, whose words could not be selected through it.
   Opacity, not visibility, so a screen reader still has them.
   No window in a stacking group is ever the browser's scroll anchor: a window let go or
   held again (.is-passed) moves while the list does not, and the browser, keeping its
   anchor still, scrolled the page by the difference (196px after a link's jump, at 768
   wide).
   Every window in a stacking group is positioned, so they paint in reading order, each
   over the one before, and opaque from its first pixel: a window sliding over another
   must hide the words under it, so P3's fade and rise give way to the slide itself. A
   window that sticks does so at --stick, which keeps it from sticking before its foot is
   on screen. The care band's windows (the standout's) still lie on their plates while
   they come, and lift off and draw their pulse as they land (.is-landed, once); the
   first, over the pinned words, comes lifted and only draws its pulse. */
@media (prefers-reduced-motion: no-preference){
  [data-stack-words].is-pinned{overflow-anchor:none}
  [data-stack-words].is-pinned:not(.is-under){position:sticky;top:var(--pin, 0px)}
  [data-stack-words].is-pinned.is-under{opacity:0;pointer-events:none}
  [data-stack].is-stacking > *{position:relative;overflow-anchor:none}
  [data-stack].is-stacking > .is-stacked{position:sticky;top:var(--stick, 0px)}
  [data-stack].is-stacking > .is-stacked.is-passed{position:relative;top:auto}
  /* A sticky window stays inside its list's content box, and the last window is the
     last box in it, so it had no room to stick: it scrolled on past its line, over the
     edges above it, and the finished deck never held at all (Small changes went level
     with Backups at 1440 by 900). This room after it, a grid row, so with a row's gap
     before it, lets it stick on its line and the deck hold. Not padding on the list:
     sticky stops at the content edge. bootStack sizes it (--hold), and only where the
     last window ends a deck of two or more. */
  [data-stack].is-stacking.is-holding::after{content:"";block-size:var(--hold, 0px)}
  .js [data-stack].is-stacking > [data-reveal] > .lift{opacity:1;transform:none;transition:none}
  /* A list that arrives as a list (P2, Our work's cards) does not fade in once it stacks. */
  .js [data-list] [data-stack].is-stacking > *{opacity:1;animation:none}
  .js [data-stack].is-stacking > .is-stacked[data-reveal]:not(.is-landed):not(.is-over) > .lift > .window{transform:none}
  .js [data-stack].is-stacking > .is-over[data-reveal] > .lift > .window{transform:translate(calc(var(--plate) * -1),calc(var(--plate) * -1))}
  .js [data-stack].is-stacking > .is-stacked[data-reveal].is-landed > .lift > .window{transform:translate(calc(var(--plate) * -1),calc(var(--plate) * -1));transition-delay:.1s}
  .js [data-standout] [data-stack].is-stacking > .is-stacked:not(.is-landed) .part__pulse path{stroke-dashoffset:1}
  .js [data-standout] [data-stack].is-stacking > .is-stacked:not(.is-landed) .part__pulse circle{opacity:0}
}
/* The tilt and the sink, tied to the scroll where the browser can (elsewhere the stack
   alone). A window comes up turned a degree, its right side high, the reference's, and
   is flat as it lands (--land is that run); the window it covers sinks back as the next
   comes over its head (--sink-from to --sink): a little smaller from its top edge, so
   the deck's edges stay where they were, and a shade darker, more on the ink band. Only
   over its head, its word, name and picture: until then the next window is covering
   words still being read, and they neither shrink nor dim. Transform and opacity only,
   run by the compositor; nothing loops (a11y-7, D-31). Each window names its own view
   timeline (--stack-self) and the group shares them, so a window can follow the next
   one's (--stack-next): six names, one more than the longer group. The shade lies over
   the window wherever it is: lifted off its plate, or still on it (a care window
   covered before it landed). */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    [data-stack].is-stacking{timeline-scope:--stack-1,--stack-2,--stack-3,--stack-4,--stack-5,--stack-6}
    [data-stack].is-stacking > *{view-timeline-name:var(--stack-self)}
    /* .js and the list's attribute: over P2's fade-in, which the rule above has stopped. */
    .js [data-stack].is-stacking > .is-stacked{transform-origin:50% 0;animation:stack-tilt linear both;animation-timeline:view();animation-range:cover 0px cover var(--land)}
    [data-stack].is-stacking > .is-stacked:not(:last-child) > .lift{transform-origin:50% 0;animation:stack-sink linear both;animation-timeline:var(--stack-next);animation-range:cover var(--sink-from, 0px) cover var(--sink)}
    [data-stack].is-stacking > .is-stacked:not(:last-child) > .lift::after{content:"";position:absolute;inset:calc(var(--plate) * -1) var(--plate) var(--plate) calc(var(--plate) * -1);border-radius:inherit;background:var(--ink);opacity:0;pointer-events:none;animation:stack-shade linear both;animation-timeline:var(--stack-next);animation-range:cover var(--sink-from, 0px) cover var(--sink)}
    .js [data-stack].is-stacking > .is-stacked[data-reveal]:not(.is-landed):not(.is-over) > .lift::after{inset:0}
  }
}
@keyframes stack-tilt{from{transform:rotate(-1deg)}to{transform:none}}
@keyframes stack-sink{to{transform:scale(.96)}}
@keyframes stack-shade{to{opacity:var(--shade, .1)}}
.svc-group--care{--shade:.25}

/* ---- The contact page (decision D-18): its hero, then the form's section, then the FAQ
   (in its own block below). */

/* The hero (contact-hero.php): the clay film, played once as the page opens (site.js,
   bootContactFilm), and the page's words. Its ground is the page's own paper, --page,
   the ground of the form's section under it, so nothing changes tone at the hero's foot
   (item 5, Sam, 2026-10-25, as the front page's hero). Until 2026-10-27 it was the film's
   floor (#F2ECE5), 5 to 6 colour-difference units off --page: a line across the screen
   where the form's section began, and the film's top right ran 9 to 10 units darker.
   The films and stills are now graded so their floor and wall are --page (within about
   1 unit on average at every edge), the clay untouched, and their foot fades into it at
   every size. Ink on it 17.0:1, --ink-soft 8.0:1. Two layouts, chosen by the screen, at
   the same 48em the script and the still's <source> use to choose the cut:
     side     from 48em on a screen at least 4:3: the film covers the box, its right edge
              kept so the symbol stays right, and the words sit over its paper on the
              left, vertically centred. Behind them the film is paper on every frame
              (contact-hero.php has the measures): ink 15.6:1, --ink-soft 7.3:1.
     stacked  everywhere else: the film full width at the top (the 4:5 cut on a phone, the
              16:9 cut on an upright tablet), its foot fading into the ground, the words
              below it. On a phone the box is capped at 48svh: the symbol (its clay and
              shadow 65% of the 4:5 frame's height) then clears the top edge from 320 by
              640 up; at 42svh its top was cut at 320. The fade is the box's last 1rem:
              it was its last 12% while the floor drifted a few levels off the ground,
              and at 375x667 that faded the symbol's foot (it ends 14px above the box's,
              the 12% began 38px above); graded, the floor's bottom row is within about
              1.4 units of --page, which 1rem hides.
   Shorter than a screen, so the form's window shows under it: this page's work is the
   form. Only transform and opacity move; every start state is under .js and only with
   motion allowed (T-052), so without the script, or with reduced motion, the end frame
   and the words are simply there. */
.contact-hero{--ch-ground:var(--page);--ch-rise:16px;position:relative;isolation:isolate;box-sizing:border-box;background:var(--ch-ground);color:var(--ink);overflow:hidden;overflow:clip}
.contact-hero__media{position:relative;inline-size:100%;aspect-ratio:4/5;max-block-size:48svh;overflow:hidden;
  -webkit-mask-image:linear-gradient(#000 calc(100% - 1rem),transparent);mask-image:linear-gradient(#000 calc(100% - 1rem),transparent)}
.contact-hero__still{position:absolute;inset:0;display:block}
.contact-hero__still img,.contact-hero__film{position:absolute;inset:0;display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 50%}
.contact-hero__film{z-index:1;visibility:hidden}
.contact-hero.is-film .contact-hero__film{visibility:visible}
.contact-hero.is-still .contact-hero__film{display:none}
.contact-hero__copy{position:relative;z-index:2;box-sizing:border-box;padding:var(--space-3) var(--frame-inline) var(--space-5);container-type:inline-size}
/* Stacked, the words' last line sits one section spacer (--pad-m) above the form's
   window, as one section sits above the next: with 5rem here, the form section's 3rem
   top it was 128px at 390 (167 at 768), a dead band of paper between the growth
   check's link and the form. */
.contact-hero__copy{padding-block-end:calc(var(--pad-m) - var(--space-4))}
/* The heading in the display face, sized to its column (cqi) so its longest word fits,
   each word in its own clipped line box, padded so the clip never cuts the comma. */
.contact-hero__title{margin:0;font-family:var(--font-display);font-weight:400;font-size:clamp(2.5rem, 14cqi, 4.5rem);line-height:.95;letter-spacing:-.03em;text-wrap:balance}
.contact-hero__word{display:inline-block;overflow:hidden;overflow:clip;padding-block:.1em .16em;margin-block:-.1em -.16em;vertical-align:top}
.contact-hero__in{display:inline-block}
.contact-hero__intro{margin:var(--gap-text) 0 0;max-inline-size:34ch;font-size:var(--fs-lead);font-weight:450;line-height:1.45;color:var(--ink-soft);text-wrap:pretty}
.contact-hero__facts{display:grid;gap:var(--space-1);justify-items:start;margin-block-start:var(--space-3)}
.contact-hero__facts p{margin:0}
/* The email as big as its column allows: two lines broken after the @ on a phone
   ("remasterstudio.co.uk" is 11.27em, footer's measure), one line (14.56em) from 48em. */
.contact-hero .cta__mail{font-size:clamp(1.5rem, 8.2cqi, 2.75rem)}
/* The number, and "Text us" beside it once the number takes texts (P1-17); printed only
   once the number is real (D-30). */
.contact-hero__tel{display:flex;flex-wrap:wrap;column-gap:1.25em;font-weight:700;font-size:var(--fs-lead);font-variant-numeric:tabular-nums}
.contact-hero__tel .text-link{display:inline-flex;align-items:center;min-block-size:44px}
/* "Questions first? Read them." (P1-38): quieter than the email and the phone, in the
   line's soft ink, its link in ink and 44px tall like the number's. */
.contact-hero__ask{font-size:var(--fs-body);font-weight:500;color:var(--ink-soft)}
.contact-hero__ask .text-link{display:inline-flex;align-items:center;min-block-size:44px;font-weight:700;color:var(--ink)}
.contact-hero .text-link::before{block-size:1px;background:currentColor;opacity:.4}
/* "Not ready to write? Try the one-minute growth check." (Sam's round 2, item d): the
   same quiet line as the FAQ's jump; on a phone its link moves whole to a line of its
   own, and "one-minute" is never broken at its hyphen. */
.contact-hero__keep{white-space:nowrap}

/* Stacked from 48em (an upright tablet): the 16:9 cut, full width. */
@media (min-width: 48em){
  .contact-hero__media{aspect-ratio:16/9;max-block-size:56svh}
  .contact-hero__still img,.contact-hero__film{object-position:100% 50%}
  .contact-hero__title{font-size:clamp(2.75rem, 11cqi, 4.5rem)}
  .contact-hero .cta__mail{font-size:clamp(1.5rem, 6.6cqi, 2.75rem)}
}
/* A phone held sideways (667 by 375, 568 by 320: under 48em, so the 4:5 phone cut): the
   words on the left and the film beside them on the right, the screen's height under the
   bar. Stacked, the 4:5 box ran the screen's width and was capped at 48svh, 180px on a
   375 screen, so the frame showed a band across the middle of the symbol, its top cut
   off, and the heading began below the screen's foot. The film starts level with the
   words; no fade, since nothing runs under it. */
@media (max-width: 47.99em) and (min-aspect-ratio: 4/3){
  .contact-hero{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center}
  .contact-hero__media{grid-column:2;grid-row:1;align-self:start;inline-size:auto;block-size:calc(100svh - var(--nav-h));max-block-size:none;-webkit-mask-image:none;mask-image:none}
  .contact-hero__copy{grid-column:1;grid-row:1;padding:var(--space-3) var(--space-2) var(--space-3) var(--frame-inline)}
}
/* Side by side, from 48em on a screen at least 4:3. The box is a screen less the nav and
   9rem, so the window's top comes into view under it (and arrives: core.js's reveal
   waits for 8% above the screen's foot), between 30 and 50rem; but never wider than
   2.4:1 (42vw tall at least), or the film, cropped top and bottom to cover it, cut the
   symbol's top off (2560 by 1440, and 1366 by 657; up to 2.48:1 its top keeps 2% of
   the frame clear). At 2.22:1 the window's top missed its arrival at 1600 by 900. The film covers it
   with its right edge kept, so the frame's middle (the symbol starts at 53%) sits at
   min(50vw, 100vw - 0.889 x the box's height), and the words' column stops 3vw short of
   it, starting on the nav's frame line. The film's foot fades into the form's section, as
   the front page's hero does (hero.css): the symbol's contact shadow ends at frame y 900
   on every frame, which sits --ch-h / 2 - 0.1875 x the frame's width above the box's foot
   (the frame is max(100vw, 16/9 of the box's height) wide), so the fade is that gap less
   half a rem, between 1.5rem and 10rem, and never reaches the shadow. */
@media (min-width: 48em) and (min-aspect-ratio: 4/3){
  .contact-hero{--ch-h:clamp(max(30rem, 42vw), 100svh - var(--nav-h) - 9rem, max(50rem, 42vw));--ch-x:max(var(--margin), (100vw - 82rem) / 2);
    display:grid;align-items:center;min-block-size:var(--ch-h);padding-block:var(--space-4)}
  .contact-hero__media{--ch-fade:clamp(1.5rem, var(--ch-h) / 2 - .1875 * max(100vw, var(--ch-h) * 16 / 9) - .5rem, 10rem);position:absolute;inset:0;max-block-size:none;aspect-ratio:auto;
    -webkit-mask-image:linear-gradient(to top,transparent,#000 var(--ch-fade));mask-image:linear-gradient(to top,transparent,#000 var(--ch-fade))}
  .contact-hero__copy{inline-size:min(40rem, calc(min(50vw, 100vw - .889 * var(--ch-h)) - var(--ch-x) - 3vw));margin-inline-start:var(--ch-x);padding:0}
  .contact-hero__title{font-size:clamp(2.5rem, min(13cqi, 10svh), 5.5rem)}
}

/* The arrival. Until site.js decides (.is-film or .is-still) the studio is empty and the
   words wait below their lines; once the film moves (.is-on) the heading rises word by
   word out of its line (P1's rise, 60ms apart), then the line and the email and phone,
   on the long expo tail with no overshoot. */
@media (prefers-reduced-motion: no-preference){
  .js .contact-hero:not(.is-still):not(.is-done) .contact-hero__still{opacity:0}
  .js .contact-hero:not(.is-on):not(.is-still) .contact-hero__in{transform:translateY(calc(100% + .3em))}
  .js .contact-hero:not(.is-on):not(.is-still) :is(.contact-hero__intro,.contact-hero__facts){opacity:0;transform:translateY(var(--ch-rise))}
  /* The failsafe (T-052): if site.js never runs (blocked, failed, a browser too old), the
     end frame and the words appear at 4 s. It stands down the moment the script marks
     the hero .is-armed, and the script takes over from there. */
  .js .contact-hero:not(.is-armed) :is(.contact-hero__still,.contact-hero__in,.contact-hero__intro,.contact-hero__facts){animation:contact-failsafe 0s 4s forwards}
  .js .contact-hero.is-on:not(.is-still) .contact-hero__in{animation:rise-word .72s var(--ease-arrive) calc(var(--i, 0) * 60ms) both}
  .js .contact-hero.is-on:not(.is-still) .contact-hero__intro{animation:contact-up .7s var(--ease-arrive) .2s both}
  .js .contact-hero.is-on:not(.is-still) .contact-hero__facts{animation:contact-up .7s var(--ease-arrive) .32s both}
}
@keyframes contact-failsafe{to{opacity:1;transform:none}}
@keyframes contact-up{from{opacity:0;transform:translateY(var(--ch-rise))}to{opacity:1;transform:none}}

/* The form's section: the window (its heading, the pills, the form), then the column
   (the faces, what happens next, the review); from 64em the window on columns 1 to 7
   and the column on 9 to 12 beside it, held in view under the nav's pill (which comes
   on this page now: layout-4) while the form scrolls past, on a screen tall enough to
   hold them. Phone: the source order. */
/* A short top, so the window's top edge shows under the hero on a desktop screen. */
.cta.is-page{padding-block:var(--space-4) var(--pad-m)}
.cta__inner{row-gap:var(--gap-head)}
/* Full width until the split at 64em: .grid has 12 columns from 48em, and anything not
   placed would take one each. */
.cta__inner > *{grid-column:1 / -1;min-inline-size:0}
.cta__action{position:relative;isolation:isolate;min-inline-size:0}
.cta.is-page .cta__title{font-size:var(--fs-h3);line-height:1;margin-block-end:var(--space-3)}
/* The sent card's "Message sent." never wider than its window: "Message" is 4.7em as
   set, and at 200% text the heading was 56px and ran 30px into the window's side at 390,
   and 54px out of it, past the screen's edge, at 320. The window is its size container;
   the cap binds only at large text (28 to 52px at 100%, 320 to 2000). */
.cta.is-page .cta__window{container-type:inline-size}
.cta.is-page .cta__title{font-size:min(var(--fs-h3), 100cqi / 4.9)}
/* The sent card (P1-18; page-contact.php marks the window .is-sent only for the status
   the engine shows its thanks for): the heading, the thanks on its ink panel, and the
   contact film's end frame in a small ink-ringed frame, square, the envelope in the
   pocket kept in its middle. Under them on a phone; beside them from 48em, where the
   window is wide enough. Still: nothing here moves but the window's own arrival. */
.cta__window.is-sent{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-3);align-items:center}
.cta.is-page .cta__window.is-sent .cta__title,.cta__window.is-sent [data-enquiry-result]{margin:0}
/* The thanks on its ink panel keeps inside the panel at large text: at 200% on a 320
   phone the window left it 100px for 38px words, and "arrived." ran 56px out of the ink.
   Its inset comes down to half (never under the window's own 8% of width) and a word
   breaks anywhere only as the last resort; at 100% text both are as before. */
.cta.is-page .cta__window.is-sent [data-enquiry-result]{padding:clamp(.5rem, 8cqi, var(--space-2));overflow-wrap:anywhere}
/* The handler's jump lands on #enquiry, the thanks; here it stops short by the window's
   tab, its padding and the heading's line, so the whole card shows under the nav's pill
   with its heading, not the thanks alone at the top of the screen. core.js then focuses
   the thanks itself, which scrolls again wherever the thanks is not wholly on screen
   (at 200% text it is taller than the room under the pill): it carries the same margin,
   or that second scroll put "Message sent." 193px up, under the pill. */
.cta__window.is-sent :is([data-enquiry],[data-enquiry-result]){scroll-margin-block-start:calc(var(--tab) + var(--win-pad) + var(--fs-h3) + var(--space-3) + 3.5rem)}
.sent__pic{justify-self:center;inline-size:min(100%,15rem);aspect-ratio:1;overflow:hidden;box-sizing:border-box;border:var(--line) solid var(--ink);border-radius:var(--radius-sm);background:var(--ch-ground, #F2ECE5)}
.sent__img{display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 47%}
@media (min-width: 48em){
  .cta__window.is-sent{grid-template-columns:minmax(0,1fr) clamp(9rem, 4rem + 9vw, 14rem);column-gap:var(--gutter)}
  .cta__window.is-sent > :not(.sent__pic){grid-column:1}
  .sent__pic{grid-column:2;grid-row:1 / span 3;inline-size:100%}
}
/* While they wait (D-51): a case study under the thanks, so the card
   is never the end of the road. A plain line, its link inline as the FAQ's are, so it
   wraps with its sentence: as the kit's inline-block text link, its one drawn line fell
   through the second line of words wherever the link wrapped (320 to 356px, 1024 to
   1048px; review, 2026-10-25). The padding gives a 44px tap height without moving the
   lines. */
.sent__more{margin:0;font-size:var(--fs-body);line-height:1.5}
.sent__link{padding-block:.65em;color:var(--ink);font-weight:700;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em;text-decoration-color:color-mix(in srgb, currentColor 40%, transparent)}
@media (hover:hover){
  .sent__link:hover{text-decoration-color:var(--accent);text-decoration-thickness:2px}
}
.sent__link:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:2px}
/* The window's column ends with the window (align-self:start): stretched to the row,
   it took the height of what happens next once the thank-you had replaced the form,
   and the glow (inset 6% of it) outlined an empty card below the window (review
   finding wordpress-10). */
/* An upright tablet, or a phone held sideways from 48em: under the window, who you will
   deal with on the left and what happens next on the right, rather than the phone's one
   column at 28rem with the screen's right half empty under a full-width window. */
@media (min-width: 48em) and (max-width: 63.99em){
  .cta.is-page .cta__next:has(> .cta__faces){grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--gutter)}
  .cta.is-page .cta__next:has(> .cta__faces) > *{grid-column:2}
  .cta.is-page .cta__next > .cta__faces{grid-column:1;grid-row:1 / span 3;align-self:start}
  .cta.is-page .cta__next:has(> .cta__faces) > .reviews{grid-column:1 / -1}
}
@media (min-width: 64em){
  .cta.is-page .cta__action{grid-column:1 / 8;grid-row:1;align-self:start}
  .cta.is-page .cta__next{grid-column:9 / -1;grid-row:1}
}
@media (min-width: 64em) and (min-height: 40em){
  .cta.is-page .cta__next{position:sticky;top:calc(var(--nav-h) + 2.5rem)}
}

/* "I'm interested in" (page-contact.php; site.js, bootInterest): toggle pills in the kit's
   pill, paper with an ink outline; pressed, ink with paper words (15.98:1 either way,
   never magenta words) and the plus turned to a tick, so the state is never colour
   alone. The colours swap at once; only the mark's opacity and a 1px press move. Hidden
   without the script ([hidden], which display:grid would otherwise undo). 46px tall, not
   44: the window scales from .96 as it arrives, and the pills must still be 44px while
   it does (browser-check measured 42px), as the services cards' links are. */
.interest{display:grid;gap:var(--space-2);margin-block-end:var(--space-4)}
.interest[hidden]{display:none}
.interest__label{font-weight:700;color:var(--ink)}
.interest__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.625rem}
.interest__pill{display:inline-flex;align-items:center;gap:.5em;box-sizing:border-box;min-block-size:46px;padding:.55em 1.1em .55em .85em;font-family:var(--font-body);font-weight:700;font-size:var(--fs-body);line-height:1.2;text-align:start;color:var(--ink);background:var(--paper);border:2px solid var(--ink);border-radius:999px;cursor:pointer;-webkit-tap-highlight-color:transparent;transition:transform var(--t-feedback) var(--ease-out)}
.interest__pill[aria-pressed="true"]{color:var(--paper);background:var(--ink)}
/* At 320 "Looking after my site" needed 235px of a 232px row and broke onto two lines;
   "Looking after the site" (P1-39) takes 229px of it with these tighter insides. */
@media (max-width: 22.49em){
  .interest__pill{gap:.4em;padding:.5em .85em .5em .7em}
}
/* At the reader's own large text on a phone (narrower than 20em of it: never at 100%,
   where 320px is 20em): the form's window keeps to 6.5vw a side, and the words and pills
   to 15% of it (its size container, above). At 200% on a 320 its 40px sides left the
   form 160px, where "interested" (194px) and "+ website" (227px) ran past its edge
   (device pass, 2026-10-27). */
@media (max-width: 19.99em){
  .cta.is-page .cta__window{--win-pad:min(clamp(1.25rem, .8rem + 2vw, 3rem), 6.5vw)}
  .cta.is-page :is(.interest__label,.interest__pill){font-size:min(var(--fs-body), 15cqi)}
}
@media (hover:hover){
  .interest__pill[aria-pressed="false"]:hover{background:var(--slot)}
}
.interest__pill:active{transform:translateY(1px)}
.interest__pill:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.interest__mark{flex:none;inline-size:.9em;block-size:.9em}
.interest__plus,.interest__tick{transition:opacity var(--t-state) var(--ease-out)}
.interest__pill[aria-pressed="true"] .interest__plus,.interest__pill:not([aria-pressed="true"]) .interest__tick{opacity:0}

/* What happens next, two lines and a link since P1-18 (page-contact.php): each line in
   ink at the lead size, marked with the kit's dot in the magenta, ink-ringed (the dot is
   decoration; the words carry it all), then "See every step", 44px tall. Calm. */
.cta__next{display:grid;gap:var(--space-3);align-content:start;align-self:start}
/* The faces at the column's head (P1-30; their pills are the shared part's, in How it
   works' block): the line over them in ink, bold, then the two pills, with the column's
   own gap before "What happens next". The line says who does what in two sentences (Sam's
   round 2, item c), balanced so neither ends on a stray "to date." */
.cta__faces{display:grid;gap:var(--space-2);justify-items:start}
.cta__faces .faces__lead{max-inline-size:28rem;font-weight:700;line-height:1.3;color:var(--ink);text-wrap:balance}
.cta.is-page .cta__next h2{font-size:clamp(1.75rem, 1.2rem + 1.4vw, 2.5rem);line-height:1}
.next__list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-2);max-inline-size:28rem}
.next__line{display:grid;grid-template-columns:.875rem minmax(0,1fr);column-gap:var(--space-2);align-items:start;font-size:var(--fs-lead);font-weight:600;line-height:1.4;color:var(--ink)}
.next__line::before{content:"";box-sizing:border-box;inline-size:.875rem;block-size:.875rem;margin-block-start:calc((1lh - .875rem) / 2);border:2px solid var(--ink);border-radius:50%;background:var(--accent)}
.next__more{margin:0}
.next__more .text-link{display:inline-flex;align-items:center;min-block-size:44px;font-weight:700}
/* A client's words at the column's foot (P1-35; reviews.php inside the column, printed
   only with a real quote and name): a small white card in the kit's ink outline on a
   magenta offset, the quote in ink a size up, the name under it. Still. */
.cta__next .reviews{display:grid;gap:var(--space-2);margin-block-start:var(--space-2);max-inline-size:28rem}
.cta__next .reviews h3{font-size:var(--fs-step);line-height:1.1}
.cta__next .review{display:grid;gap:var(--space-2);margin:0;padding:var(--space-3);background:var(--white);border:var(--line) solid var(--ink);border-radius:var(--radius-sm);box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.cta__next .review blockquote{margin:0}
.cta__next .review blockquote p{font-size:var(--fs-lead);font-weight:500;line-height:1.4;color:var(--ink);text-wrap:pretty}
.cta__next .review cite{font-style:normal;font-weight:700;color:var(--ink-soft)}

/* The glow: full strength on a pseudo-element behind the window; only its opacity
   moves. --lit on the light page. Never on the button. As the window arrives (.in) the
   light comes on, dims once and comes back, then stays lit: one pulse, over in under
   three seconds, as the We run it glow does (services-lit). It no longer cycles every
   6s while on screen (a11y-7, option A, Stanley 2026-10-21, for the whole site): an
   endless pulse with no way to pause it fails WCAG 2.2.2. .in is never taken away, so
   the pulse never starts again. Lit at once, and still, without the script (no .js) and
   under reduced motion (T-052). Since 2026-10-27 the pulse waits for the window to be
   properly on screen, not just its top edge (.glow-wait below). */
[data-standout] .cta__action::before{content:"";position:absolute;z-index:-1;inset:6%;border-radius:var(--radius-win);box-shadow:0 0 5rem 2rem var(--lit);opacity:.9;pointer-events:none}
.js [data-standout]:not(.in) .cta__action::before{opacity:0}
/* Held off until the window is properly on screen (site.js, bootContactGlow: half of it,
   or 60% of the screen; Sam's round 2, item f), then the pulse below plays from there. */
.js [data-standout].glow-wait .cta__action::before{opacity:0}
@keyframes cta-lit{0%{opacity:0}30%{opacity:1}62%{opacity:.5}100%{opacity:.9}}
@media (prefers-reduced-motion: no-preference){
  .js [data-standout].in:not(.glow-wait) .cta__action::before{animation:cta-lit 2.4s var(--ease-in-out) .2s both}
}
@media (prefers-reduced-motion: reduce){
  .js [data-standout] .cta__action::before{opacity:.9;animation:none}
}
@media (max-width: 63.99em){
  [data-standout] .cta__action::before{box-shadow:0 0 2.5rem 1rem var(--lit)}
}

/* The form, in the window: labels above, helper text, errors in words below. */
.cta [data-enquiry]{scroll-margin-block-start:2rem}
.cta [data-enquiry] form{display:grid;gap:clamp(1.25rem, 1rem + 1vw, 1.75rem)}
.cta [data-field]{display:grid;gap:.4rem;min-inline-size:0}
.cta [data-field] label{font-weight:700;color:var(--ink)}
.cta [data-field] > p:not([data-error]){margin:0;font-size:var(--fs-small);line-height:1.45;color:var(--ink-soft);max-inline-size:56ch}
.cta [data-field] input,.cta [data-field] select,.cta [data-field] textarea{box-sizing:border-box;inline-size:100%;min-block-size:3.25rem;padding:.7em .9em;font-family:var(--font-body);font-size:var(--fs-body);line-height:1.4;color:var(--ink);background:var(--white);border:var(--line) solid var(--ink);border-radius:12px}
.cta [data-field] textarea{min-block-size:9rem;resize:vertical}
.cta [data-field] select{appearance:none;-webkit-appearance:none;padding-inline-end:2.75rem;background:var(--white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 10'%3E%3Cpath d='M1.5 1.5 8 8l6.5-6.5' fill='none' stroke='%23111827' stroke-width='2.5'/%3E%3C/svg%3E") right 1rem center / 1rem auto no-repeat}
/* Focus: the kit's magenta hard offset, set at once (no transition). */
.cta [data-field] input:focus-visible,.cta [data-field] select:focus-visible,.cta [data-field] textarea:focus-visible{outline:none;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.cta [data-field] [aria-invalid="true"]{box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--ink)}
.cta [data-error]:not([hidden]){justify-self:start;margin:0;padding:.3em .75em;font-size:var(--fs-small);font-weight:700;color:var(--error);background:var(--ink);border-radius:8px}
.cta [data-enquiry-status]{margin:0;font-weight:700;color:var(--ink-soft)}
/* Empty, it takes no room but stays in the accessibility tree: a live region has to be
   there before its words change to be announced (review finding a11y-6). */
.cta [data-enquiry-status]:empty{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.cta [data-enquiry-failed]:not([hidden]),.cta [data-enquiry-result],.cta .cta__either{margin:0 0 var(--space-3);padding:var(--space-2);font-weight:700;color:var(--paper);background:var(--ink);border-radius:12px;outline-offset:3px}
.cta [data-enquiry-failed] a,.cta [data-enquiry-result] a{color:var(--paper)}

/* Send. Without the script, a plain pill with a still plate (no shadow transition);
   site.js gives it the face and plate of every other button, and on fine pointers P5. */
.cta [data-enquiry] button[type="submit"]:not(.btn){justify-self:start;display:inline-flex;align-items:center;gap:.6em;min-block-size:3.25rem;padding:.8em 1.6em;font-family:var(--font-body);font-weight:700;font-size:var(--fs-body);line-height:1.2;color:var(--ink);background:var(--paper);border:var(--line) solid var(--ink);border-radius:999px;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent);cursor:pointer;transition:transform var(--t-state) var(--ease-out)}
@media (hover:hover){ .cta [data-enquiry] button[type="submit"]:not(.btn):hover{transform:translate(-2px,-2px)} }
.cta [data-enquiry] button[type="submit"]:not(.btn):active{transform:translate(2px,2px)}
.cta [data-enquiry] button[type="submit"].btn{justify-self:start}
.cta .magnet{justify-self:start;display:inline-block}
.cta [data-enquiry] form[aria-busy="true"] button[type="submit"]{cursor:progress;opacity:.8}
.cta [data-enquiry] form[aria-busy="true"] button[type="submit"]:not(.btn)::after,.cta [data-enquiry] form[aria-busy="true"] .btn__face::after{content:"";inline-size:1em;block-size:1em;box-sizing:border-box;border:2px solid currentColor;border-inline-end-color:transparent;border-radius:50%;animation:sending .8s linear infinite}
@keyframes sending{to{transform:rotate(1turn)}}
@media (min-width: 48em){
  .cta [data-enquiry] form{grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--gutter)}
  .cta [data-field]:nth-of-type(n+5),.cta [data-enquiry-status],.cta [data-enquiry] button[type="submit"],.cta .magnet{grid-column:1 / -1}
  .cta [data-field]:has(select) select{inline-size:min(100%,20rem)}
  /* The paired fields' contents sit at the foot of their row, so each input keeps its
     3.25rem and the two inputs line up whether a label takes one line or two ("Your
     phone number (optional)" wraps at 1024 and up): stretched, the shorter label's
     input grew by the difference (review finding layout-2). */
  .cta [data-field]:nth-of-type(-n+4){align-content:end}
}

/* The hint for the number (P1-19; fields.php gives the reply a helper, which
   enquiry-form.php, an engine file, prints between the label and the choice as
   #enquiry-reply-helper). It answers a choice ("Picked a call or a text?"), so it reads
   under the choice, after it, as the field's own helper style; [data-error] after both,
   though the two never show together (an empty choice has no hint). With the script it
   appears only once a call or a text is chosen with no number (site.js, bootNumberHint):
   under the choice, so the box just chosen in never moves, and with a short fade, under
   .js alone (T-052). It goes at once, faster than it came. Still under reduced motion. */
.cta [data-field] > #enquiry-reply-helper{order:1}
.cta [data-field]:has(> #enquiry-reply-helper) > [data-error]{order:2}
@keyframes hint-in{from{opacity:0;transform:translateY(-.25rem)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: no-preference){
  .js .cta [data-field] > #enquiry-reply-helper:not([hidden]){animation:hint-in var(--t-state) var(--ease-arrive) both}
}

/* "What happens to what you send" (P1-03; page-contact.php), straight under Send, printed
   only while the privacy page is published: small and calm, in ink, with the section's
   resting underline. 46px tall, as the pills are: the window scales from .96 as it
   arrives, and the link must still be 44px while it does. Those 46px are its only space
   from Send (.section p has no margin), which keeps it read as Send's own footnote.
   Still: only the underline's hover moves. */
.cta__privacy .text-link{display:inline-flex;align-items:center;min-block-size:46px;font-size:var(--fs-small);font-weight:700;color:var(--ink)}

/* P5 (Huge's call to action), Send only, on fine pointers with motion: the button leans
   toward the pointer (site.js sets --mx and --my in a frame), a magenta circle fills the
   face from where the pointer came in, and the label rolls letter by letter. Exits are
   faster than entrances. The face keeps its P3 lift underneath. The face's own two rules
   are in site.css: the front page's closing band button matches them too. */
.cta .btn__fill{position:absolute;z-index:-1;left:var(--cx, 50%);top:var(--cy, 50%);inline-size:240%;aspect-ratio:1;border-radius:50%;background:var(--accent);transform:translate(-50%,-50%) scale(0);transition:transform .2s var(--ease-roll);pointer-events:none}
.cta .btn__label{position:relative;display:inline-flex;block-size:1lh;overflow:hidden;overflow:clip}
.cta .btn__ch{display:inline-block;white-space:pre;text-shadow:0 1lh currentColor;transition:transform .2s var(--ease-roll)}
@media (hover:hover) and (pointer:fine){
  .cta .btn:hover .btn__fill{transform:translate(-50%,-50%) scale(1);transition-duration:var(--t-hover)}
}
@media (hover:hover) and (pointer:fine) and (prefers-reduced-motion: no-preference){
  .cta .magnet{transform:translate(var(--mx, 0px),var(--my, 0px));transition:transform .5s var(--ease-arrive)}
  .cta .magnet.is-tracking{transition-duration:.15s}
  .cta .btn:hover .btn__ch{transform:translateY(-1lh);transition:transform .28s var(--ease-roll) calc(var(--i, 0) * 8ms)}
}

/* ==== page.php (the privacy page) in Read mode, and the not-found page ============ */
/* The light page between the ink nav and the ink footer: one calm column at reading
   measure, no film, no standout. The not-found page has its film (D-18), below. */
.page-read,.not-found{box-sizing:border-box;padding:var(--pad-m) var(--frame-inline) var(--pad-l);background:var(--page);color:var(--ink);font-size:var(--fs-body)}
.page-read article{max-inline-size:60ch}
.page-read h1,.not-found h1{margin:0 0 var(--gap-text);font-family:var(--font-display);font-weight:400;font-size:var(--fs-h2);line-height:.95;letter-spacing:-.03em;text-wrap:balance}
.page-read h2,.page-read h3{margin:var(--space-4) 0 var(--space-2);font-family:var(--font-display);font-weight:400;line-height:1.05;letter-spacing:-.02em}
.page-read h2{font-size:var(--fs-step)}
.page-read h3{font-size:var(--fs-body)}
.page-read p,.page-read li{max-inline-size:60ch;color:var(--ink-soft)}
.page-read p{margin:0 0 var(--space-2)}
.page-read a{color:var(--ink);text-decoration-color:var(--accent);text-decoration-thickness:2px;text-underline-offset:.25em}
.page-read table{inline-size:100%;margin-block:var(--space-4);border-collapse:collapse;font-size:var(--fs-small)}
.page-read caption{text-align:start;margin-block-end:var(--space-2);font-weight:700;font-size:var(--fs-body);color:var(--ink)}
.page-read th,.page-read td{padding:.75em 1em .75em 0;text-align:start;vertical-align:top;border-block-end:1px solid var(--rule)}
.page-read thead th{border-block-end:var(--line) solid var(--ink)}
.page-read tbody th{color:var(--ink)}
.page-read td{color:var(--ink-soft)}

/* The not-found page and its film (decision D-18; 404.php says why a film here): the
   front page's clay drop, landing upside down. Laid out as the front page's intro is, so
   the joke reads, in two layouts chosen by the screen, and the same 48em that site.js
   and the still's <source> use to choose the cut:
     side     from 48em on a screen at least 4:3: the film fills the first screen below
              the nav, and the words sit in its calm left half, vertically centred.
     stacked  everywhere else: the film full width at the top (the 4:5 cut on a phone,
              the 16:9 cut on an upright tablet), the words under it.
   Under 4:3 the 16:9 film, cropped to fill, would put the symbol behind the words. The
   ground is the page's own paper, --page, as the privacy page's is: until 2026-10-27 it
   was the film's floor (#F2EEE4), a beige the rest of the site does not use, with the
   film's top right 10 units darker still. The films and stills are now graded so their
   floor and wall are --page (within about 1 unit on average at every edge), the clay
   untouched (item 5, Sam, 2026-10-25, as the front page's hero): ink on it 17.0:1,
   --ink-soft 8.0:1. Behind the words in the side layout (the frame's left 45%, where the
   symbol never goes), the darkest 4px block of any frame of the 16:9 cut is #EFEBE3:
   ink 15.0:1, --ink-soft 7.0:1. */
.not-found{--nf-ground:var(--page);position:relative;isolation:isolate;display:block;padding:0;background:var(--nf-ground);overflow:hidden;overflow:clip}

/* The film and its end frame share one box; the film sits on top. object-fit applies to
   the poster too, so the start frame crops exactly as the film will. Stacked, the box is
   capped so the heading still reaches the first screen, and its last 1rem fades into the
   ground. It was the last tenth while the floor drifted a few levels off the ground, and
   at 375x667 that took the symbol's foot and shadow (they end 24px above the box's, the
   tenth began 35px above); graded, the floor's bottom row is within about 1.4 units of
   --page, which 1rem hides. */
.not-found__media{position:relative;inline-size:100%;aspect-ratio:4/5;max-block-size:52svh;overflow:hidden;
  -webkit-mask-image:linear-gradient(#000 calc(100% - 1rem),transparent);mask-image:linear-gradient(#000 calc(100% - 1rem),transparent)}
/* On a short phone the cap leaves the words and the way home their room on the first
   screen (they need about 18rem under the film): at 320x568 and 375x667, and on a 390
   phone with Safari's bars showing (390x664), Back to the start was below the screen's
   foot. Capped harder, the box narrows with it and is centred, so the frame is never
   cropped by more than 15% of its height (the symbol and its shadow fill 19 to 83% of
   it). Binds only on screens under about 740px tall; never under 13rem. */
.not-found__media{--nf-cap:max(13rem, min(52svh, 100svh - var(--nav-h) - 18rem));max-block-size:var(--nf-cap);inline-size:min(100%, var(--nf-cap) * .94);margin-inline:auto}
/* Its sides fade into the ground as its foot does, so a narrowed frame's grain (within 3
   levels of --page) never draws an edge; over the paper at a full-width box's edges the
   fade is unseen. */
@media (max-width: 47.99em){
  .not-found__media{-webkit-mask-image:linear-gradient(#000 calc(100% - 1rem),transparent),linear-gradient(to right,transparent,#000 1rem,#000 calc(100% - 1rem),transparent);mask-image:linear-gradient(#000 calc(100% - 1rem),transparent),linear-gradient(to right,transparent,#000 1rem,#000 calc(100% - 1rem),transparent);-webkit-mask-composite:source-in;mask-composite:intersect}
}
.not-found__still{position:absolute;inset:0;display:block}
.not-found__still img,.not-found__film{position:absolute;inset:0;display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 50%}
.not-found__film{z-index:1;visibility:hidden}
.not-found.is-film .not-found__film{visibility:visible}
.not-found.is-still .not-found__film{display:none}

/* The words: the heading set to its column (cqi), so its longest word always fits. */
.not-found__copy{position:relative;z-index:2;display:grid;gap:var(--gap-text);justify-items:start;box-sizing:border-box;padding:var(--space-3) var(--frame-inline) var(--pad-m);container-type:inline-size}
.not-found h1{margin:0;font-size:clamp(2.25rem, 13.5cqi, 4.5rem)}
.not-found p{margin:0;max-inline-size:44ch;font-size:var(--fs-lead);line-height:1.45;color:var(--ink-soft);text-wrap:pretty}
.not-found__tel{font-weight:700;font-variant-numeric:tabular-nums}
.not-found__tel a{color:var(--ink)}

/* ==== The About page: "meet Sam and Stanley" (D-17). Light page ================== */
/* Stanley's reference, in our kit: the heading centred in two lines, then a portrait
   card each, the second set lower, the stories under them, the pill at the end
   (page-about.php). Spacing by margins, not the grid's gap, so a closed story leaves no
   gap where it was. */
.team{
  padding-block:var(--pad-s) var(--pad-l);
  /* The portrait window's shape, on a 400 by 500 box (4:5): rounded corners, and the
     bottom-left corner notched out (59% by 18.4%) to hold the name and role, its inner
     corner rounded the other way. --frame-line is that shape's outline, 4px inside it
     (an 8px stroke cut by the shape, its width kept whatever the card's size). Both are
     masks, so the photograph, the ink outline and the magenta plate share one shape. */
  --frame-shape:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500' preserveAspectRatio='none'%3E%3Cpath d='M0 20A20 20 0 0 1 20 0H380A20 20 0 0 1 400 20V480A20 20 0 0 1 380 500H256A20 20 0 0 1 236 480V436A28 28 0 0 0 208 408H20A20 20 0 0 1 0 388Z'/%3E%3C/svg%3E");
  --frame-line:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500' preserveAspectRatio='none'%3E%3CclipPath id='c'%3E%3Cpath d='M0 20A20 20 0 0 1 20 0H380A20 20 0 0 1 400 20V480A20 20 0 0 1 380 500H256A20 20 0 0 1 236 480V436A28 28 0 0 0 208 408H20A20 20 0 0 1 0 388Z'/%3E%3C/clipPath%3E%3Cpath d='M0 20A20 20 0 0 1 20 0H380A20 20 0 0 1 400 20V480A20 20 0 0 1 380 500H256A20 20 0 0 1 236 480V436A28 28 0 0 0 208 408H20A20 20 0 0 1 0 388Z' fill='none' stroke='%23000' stroke-width='8' vector-effect='non-scaling-stroke' clip-path='url(%23c)'/%3E%3C/svg%3E");
}
.team__inner{display:grid}
/* The column is the frame's whatever is in it (device pass, 2026-10-27): as an auto
   track it took the widest word on the page, so at 200% text on a 320 phone the heading,
   the lead, the cards, the facts and the closing pair all sat in a 368px box. */
.team__inner{grid-template-columns:minmax(0,1fr)}
.team__head{display:grid;justify-items:center;gap:var(--gap-text);text-align:center}
.team h1{margin:0;font-family:var(--font-display);font-weight:400;font-size:clamp(2.5rem, .9rem + 4.9vw, 5.25rem);line-height:1.05;letter-spacing:-.03em}
.team__line{display:block;text-wrap:balance}
/* The lead: Stanley's big paragraph, set large for easy reading, left-aligned in a
   short measure under the centred heading (a centred block of this size reads badly). */
.team__lead{display:grid;gap:var(--gap-text);max-inline-size:min(100%,36ch);text-align:start;font-size:clamp(1.25rem, 1rem + 1.1vw, 2rem);font-weight:500;line-height:1.38;letter-spacing:-.01em;color:var(--ink);text-wrap:pretty}
.team__lead p+p{color:var(--ink-soft)}

/* The cards: Sam then Stanley. Phone: one under the other, Stanley's set to the other
   side, the reference's stagger turned sideways. From 48em: side by side and centred,
   Stanley's set lower; from 64em narrower (30vw), so the hover fan has room beside each
   card without leaving the screen. */
.team__people{list-style:none;margin:var(--gap-head) 0 0;padding:0;display:grid;row-gap:clamp(3rem, 2rem + 4vw, 5rem)}
.person{inline-size:min(86%, 22rem)}
.person:nth-child(even){justify-self:end}
@media (min-width: 48em){
  .team__people{grid-template-columns:repeat(2, minmax(0, min(26rem, 40vw)));justify-content:center;column-gap:clamp(3rem, 12vw, 11rem)}
  .person{inline-size:auto}
  .person:nth-child(even){justify-self:stretch;margin-block-start:clamp(3rem, 1rem + 5vw, 6rem)}
}
@media (min-width: 64em){
  .team__people{grid-template-columns:repeat(2, minmax(0, min(26rem, 30vw)))}
}

/* A card: the portrait window, its notch and its "+". Without mask support (an old
   browser) it is a plain kit window with the name under it. The margin keeps the
   plate inside the column, so on a phone it never crosses the page's gutter. Until the
   portrait has arrived the window is ink, as the initials' card beside it is, never the
   pale slot: on a slow phone that showed as an empty frame waiting for a face (Sam's
   round 2, a: never show something half loaded; D-30). */
.person__card{position:relative;isolation:isolate;margin:0 var(--plate) var(--plate) 0}
.person__frame{position:relative;z-index:1;display:grid;margin:0}
.person__photo{position:relative;display:block;aspect-ratio:4/5;overflow:hidden;background:var(--ink);border:var(--line-heavy) solid var(--ink);border-radius:var(--radius-win);box-shadow:var(--plate) var(--plate) 0 var(--accent)}
.person__photo img{display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 22%}
.person__tag{display:grid;align-content:center;padding-block-start:var(--space-2);line-height:1.15}
.person__name{font-family:var(--font-display);font-size:clamp(1.25rem, 1rem + 1vw, 1.75rem);letter-spacing:-.02em;color:var(--ink)}
.person__role{font-size:clamp(.875rem, .82rem + .2vw, 1rem);font-weight:500;color:var(--ink-soft)}
/* Each role in two lines, "Co-founder," over what that person does (inc/about.php,
   smwd_about_role), so the two cards match whatever the width. */
.person__role-line{display:block}
/* Room between the name and its role, and between the role's two lines (Sam,
   2026-10-29: "subtitles look squashed"). */
.person__tag .person__link{gap:.25rem}
.person__tag .person__role{line-height:1.3}
/* The name and role as the link to that person's own page (D-72): laid out as the tag
   was, the name underlined as the site's text links are at rest (40% ink, 1px), the
   magenta drawn in under a mouse anywhere on the card, since a click there follows the
   link too (site.js, bootTeam; never on the "+"). */
.person__link{display:grid;color:inherit;text-decoration:none;border-radius:4px;-webkit-tap-highlight-color:transparent}
.person__badge .person__link{gap:.35rem}
.person__link .person__name{text-decoration-line:underline;text-decoration-color:rgb(17 24 39 / .4);text-decoration-thickness:1px;text-underline-offset:.14em;transition:text-decoration-color var(--t-hover) var(--ease-out)}
.person__link:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.js .person__card.has-link{cursor:pointer}
@media (hover:hover){
  .person__card:hover .person__link .person__name,.person__link:hover .person__name{text-decoration-color:var(--accent);text-decoration-thickness:3px}
}
/* The narrowest phones: the notch is narrowest there (at 320 about 146px wide), so the
   role steps down to 13px and each of its two lines stays one line. */
@media (max-width: 20.99em){
  .person__role{font-size:.8125rem}
}
@supports ((mask-size: 100% 100%) or (-webkit-mask-size: 100% 100%)){
  .person__frame{aspect-ratio:4/5}
  .person__photo{position:absolute;inset:0;border:0;border-radius:0;box-shadow:none;-webkit-mask:var(--frame-shape) 0 0 / 100% 100% no-repeat;mask:var(--frame-shape) 0 0 / 100% 100% no-repeat}
  /* The plate (the kit's hard shadow, the window's own shape set 8px down and right)
     and the outline over the photograph. In the notch the plate shows as a band under
     the ledge, as a hard shadow of this shape would fall. */
  .person__frame::before,.person__frame::after{content:"";position:absolute;inset:0;pointer-events:none}
  .person__frame::before{z-index:-1;background:var(--accent);transform:translate(var(--plate),var(--plate));-webkit-mask:var(--frame-shape) 0 0 / 100% 100% no-repeat;mask:var(--frame-shape) 0 0 / 100% 100% no-repeat}
  .person__frame::after{background:var(--ink);-webkit-mask:var(--frame-line) 0 0 / 100% 100% no-repeat;mask:var(--frame-line) 0 0 / 100% 100% no-repeat}
  /* The name and role in the notch, on the page itself, below the plate's band. */
  .person__tag{position:absolute;left:0;bottom:0;box-sizing:border-box;inline-size:59%;block-size:18.4%;padding:calc(var(--plate) / 4) .5rem 0 0}
}
/* The name card, while the portrait is not a real photograph (D-30: no empty frame and
   no marker): the kit window on its plate, the name big at its foot in the display face
   and the role under it, the "+" in the top corner under the tab line. The name is sized
   by the card (a size container), so "Stanley" fills the same share of its card as "Sam"
   is sized to, one line at every width. A name card is shorter than a portrait, so the
   pair still reads as two cards side by side with Stanley's set lower, not two empty
   frames. */
.person__badge{display:grid;align-content:end;gap:.35rem;container-type:inline-size;min-block-size:clamp(12.5rem, 8rem + 9vw, 17rem);margin:0;box-shadow:var(--plate) var(--plate) 0 var(--accent);line-height:1.15}
.person__badge .person__name{font-size:min(5.5rem, 19cqi);line-height:.95;letter-spacing:-.03em}
.person__badge .person__role{font-size:var(--fs-body)}
.person__card.is-name .person__open{top:calc(var(--tab) + clamp(.75rem, 3%, 1.25rem))}
/* Initials in a portrait's frame (page-about.php): the card of the one whose photograph
   has not come while the other's has (Sam, 2026-10-26: his now, Stanley's later). The
   same window, notch, outline and plate as the portrait beside it, filled with ink and
   the initials in paper, as the front page's thread and the faces set Stanley's, so the
   pair matches in shape and weight (Sam's photograph is on a dark ground). Not a frame
   waiting for a face (D-30): the initials are what it shows, sized by the card and
   centred over the notch's ledge. Since Sam's round 2 (2026-10-26) it is the short name
   the thread shows, "Stan", where one is written: --chars (page-about.php) is its length,
   and 118cqi shared by it keeps a four-letter name at about 70% of the frame's width,
   as two letters stay at 38cqi. */
.person__frame.is-initials{container-type:inline-size}
.person__initials{display:grid;place-items:center;box-sizing:border-box;padding-block-end:18.4%;font-family:var(--font-display);font-size:min(38cqi, 118cqi / var(--chars, 2));line-height:1;letter-spacing:-.04em;color:var(--paper);background:var(--ink)}

/* The "+": the site's button at a round size, a paper face on a magenta plate; it turns
   to a cross while its story is open (two bars rotating, transform only). */
.person__open{position:absolute;z-index:2;top:clamp(.75rem, 3%, 1.25rem);right:clamp(.75rem, 3.5%, 1.5rem);display:block;inline-size:3.25rem;block-size:3.25rem;margin:0;padding:0;color:var(--ink);background:var(--accent);border:0;border-radius:50%;cursor:pointer;-webkit-tap-highlight-color:transparent}
.person__open[hidden]{display:none}
.person__plus{position:absolute;inset:0;box-sizing:border-box;background:var(--paper);border:var(--line) solid var(--ink);border-radius:50%;transform:translate(calc(var(--plate-sm) * -1),calc(var(--plate-sm) * -1));transition:transform var(--t-state) var(--ease-out)}
.person__plus::before,.person__plus::after{content:"";position:absolute;top:50%;left:50%;inline-size:44%;block-size:var(--line);margin:calc(var(--line) / -2) 0 0 -22%;background:currentColor;border-radius:2px;transition:transform var(--t-state) var(--ease-out)}
.person__plus::after{transform:rotate(90deg)}
.person__open[aria-expanded="true"] .person__plus::before{transform:rotate(45deg)}
.person__open[aria-expanded="true"] .person__plus::after{transform:rotate(135deg)}
@media (hover:hover){
  .person__open:hover .person__plus{transform:translate(calc(var(--plate-sm) * -1 - 2px),calc(var(--plate-sm) * -1 - 2px))}
}
.person__open:active .person__plus{transform:translate(-1px,-1px);transition-duration:.1s}
.person__open:focus-visible{outline:none}
.person__open:focus-visible .person__plus{outline:3px solid var(--focus);outline-offset:3px}

/* A snapshot, in the fan and in the story: a white print with a thin ink edge and a
   small magenta hard shadow, its caption written along the bottom. */
.team .snap{box-sizing:border-box;display:grid;gap:.4rem;margin:0;padding:.375rem .375rem .5rem;background:var(--white);border:2px solid var(--ink);border-radius:4px;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.snap__photo{position:relative;display:block;aspect-ratio:1;overflow:hidden;background:var(--slot)}
.snap__photo img{display:block;inline-size:100%;block-size:100%;object-fit:cover}
.team .snap figcaption{font-size:.8125rem;font-weight:600;line-height:1.3;text-align:center;color:var(--ink);text-wrap:balance}

/* The hover fan (Stanley: "when you hover over their mugshots, it shows some pictures
   of what they do"): the everyday pictures with a file pop out from behind the
   portrait, fanned and turned like snapshots, two each side, clear of the "+" (top
   right, inside the window) and the notch (bottom left). Only on a desktop-width screen
   with a mouse or trackpad and motion allowed, and only with the script's .js (T-052);
   everywhere else, and while there are no pictures, there is no fan and the pictures
   are in the story. The card's own hover or keyboard focus drives it: 320ms out with a
   45ms stagger on the arrival curve, 200ms back, transform and opacity only. At rest
   each print waits part-way toward the card's middle, behind the window, unseen; --x
   and --y are where it lands (as a share of the card), --rx and --ry its way back (as
   a share of itself), --r its turn. */
.person__snaps{display:none}
@media (min-width: 64em) and (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference){
  .js .person__snaps{display:block;position:absolute;inset:0;z-index:0;pointer-events:none}
  .js .person__snaps .snap{position:absolute;left:var(--x);top:var(--y);inline-size:42%;opacity:0;transform:translate(var(--rx),var(--ry)) scale(.72);transition:transform .2s var(--ease-out),opacity .12s var(--ease-out)}
  .js .person__card:is(:hover,:focus-within){z-index:2}
  .js .person__card:is(:hover,:focus-within) .person__snaps .snap{opacity:1;pointer-events:auto;transform:rotate(var(--r));transition:transform .32s var(--ease-arrive) calc(var(--i) * 45ms),opacity .2s var(--ease-arrive) calc(var(--i) * 45ms + 40ms)}
  /* Each print's caption sits on the part of it out beside the card, two lines at
     most here (the story shows it whole), so a print never grows down into the notch.
     The upper print of each side lies on the lower one, its caption on top. */
  .js .person__snaps .snap figcaption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
  .js .person__snaps .snap:nth-child(-n+2) figcaption{padding-inline-end:12%}
  .js .person__snaps .snap:nth-child(n+3) figcaption{padding-inline-start:12%}
  .js .person__snaps .snap:nth-child(odd){z-index:1}
  .js .person__snaps .snap:nth-child(1){--i:0;--x:-38%;--y:-10%;--r:-8deg;--rx:125%;--ry:70%}
  /* The lower left print is held by its foot, above the notch's top (81.6%), however
     tall its caption makes it. */
  .js .person__snaps .snap:nth-child(2){--i:1;--x:-35%;--r:-3deg;--rx:120%;--ry:-20%;top:auto;bottom:23%}
  .js .person__snaps .snap:nth-child(3){--i:2;--x:96%;--y:10%;--r:7deg;--rx:-125%;--ry:30%}
  .js .person__snaps .snap:nth-child(4){--i:3;--x:96%;--y:54%;--r:-5deg;--rx:-125%;--ry:-42%}
  /* Behind a name card (D-30), about half a portrait's height, the prints are smaller and
     spread further up and down, one over the card's top edge and one under its foot each
     side: placed as for a portrait, the two each side lay one on top of the other. */
  .js .person__card.is-name .person__snaps .snap{inline-size:34%}
  .js .person__card.is-name .person__snaps .snap:nth-child(1){--x:-30%;--y:-24%;--ry:60%}
  .js .person__card.is-name .person__snaps .snap:nth-child(2){--x:-27%;bottom:-28%;--ry:-60%}
  .js .person__card.is-name .person__snaps .snap:nth-child(3){--x:96%;--y:-16%;--ry:50%}
  .js .person__card.is-name .person__snaps .snap:nth-child(4){--x:93%;top:auto;bottom:-34%;--ry:-60%}
}

/* The stories: a kit window each under the cards, on its plate. With the script one is
   open at a time (site.js, bootTeam), arriving in 400ms; closing is instant. Without it
   both are open, one after the other. The same short shape for both (P1-48), each part
   only once real (D-30). Phone: one column in the page's order. From 64em their own
   words on the left (the h2, the role and town, the answers, their line set large), the
   rest on the right (what they do on your project, three things, the pictures two by
   two), and the way on under both. With only the h2 and the role on the left, as today,
   the way on moves up under them, beside the list (below). */
/* As wide as the pair of cards above, not the whole page. */
.team__stories{justify-self:center;inline-size:min(100%, 64rem)}
.story{margin-block-start:var(--gap-head);scroll-margin-block:var(--space-3)}
.story[hidden]{display:none}
.story:focus,.story h2:focus{outline:none}
.story__window{display:grid;row-gap:var(--gap-text)}
.team .story h2{font-size:clamp(2rem, 1.3rem + 2.6vw, 3.75rem);line-height:1.05}
.team .story h3{margin-block:var(--gap-text) var(--space-2);font-size:var(--fs-step)}
/* Each question with its answer, and each part of the side with its heading, is one
   block; the heading's margins fall through it, so the spacing is the heading's own. */
.team .story__side > :first-child > h3{margin-block-start:0}
/* The role, then the town once known: under the h2, quieter than it. */
.team .story__place{margin:.6rem 0 0;font-size:var(--fs-step);font-weight:600;line-height:1.3;color:var(--ink-soft)}
.story__answer{display:grid;gap:var(--space-2)}
.story__answer p{max-inline-size:60ch;font-size:var(--fs-lead);font-weight:450;line-height:1.5;color:var(--ink-soft)}
/* Their own line, set large in the display face (P1-48): ink, in a short measure, the
   opening mark in the magenta at display size only. */
.team .story__pull{margin:var(--gap-text) 0 0;max-inline-size:20ch;font-family:var(--font-display);font-size:var(--fs-quote);line-height:1.1;letter-spacing:-.02em;color:var(--ink);text-wrap:balance}
.story__pull::before{content:"\201C";color:var(--accent)}
.story__pull::after{content:"\201D"}
/* What they do on your project (D-005), a short list, each line after a magenta dot with
   the kit's ink edge, the line's first-line middle. */
.story__does{list-style:none;margin:0;padding:0;display:grid;gap:.65rem}
.story__does li{display:grid;grid-template-columns:.875rem minmax(0,1fr);column-gap:.75rem;max-inline-size:40ch;font-weight:500;line-height:1.4}
.story__does li::before{content:"";box-sizing:border-box;inline-size:.875rem;block-size:.875rem;margin-block-start:calc(.5lh - .4375rem);background:var(--accent);border:2px solid var(--ink);border-radius:50%}
/* With its clay icon (inc/about.php: the one How it works gives that step), the icon takes
   the dot's place, a small sticker turned a little either way, the line level with its
   middle. Still: the story's own arrival is the only motion (the facts below set their
   icons down; two strips doing the same would be the repeat Sam cut on the front page). */
.story__does:has(.has-icon){gap:var(--space-2)}
.story__does li.has-icon{grid-template-columns:3.25rem minmax(0,1fr);align-items:center;column-gap:.875rem}
.story__does li.has-icon::before{content:none}
.story__icon{display:block;transform:rotate(-5deg)}
.story__does li:nth-child(even) .story__icon{transform:rotate(4deg)}
.story__img{display:block;inline-size:100%;block-size:auto}
/* Three true things, numbered in the magenta (numbers may take it; 24px and up). */
.story__things{list-style:none;margin:0;padding:0;counter-reset:thing;display:grid;gap:var(--space-2)}
.story__things li{counter-increment:thing;display:grid;grid-template-columns:2rem minmax(0,1fr);align-items:baseline;column-gap:.75rem;max-inline-size:52ch;line-height:1.45}
.story__things li::before{content:counter(thing);font-family:var(--font-display);font-size:1.75rem;line-height:1;color:var(--accent)}
.story__snaps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-3) var(--space-2)}
.story__snaps li:last-child:nth-child(odd){grid-column:1 / -1;justify-self:center;inline-size:calc(50% - var(--space-2) / 2)}
/* Turned a little either way, like prints put down on a table. */
.story__snaps li:nth-child(odd) .snap{transform:rotate(-2deg)}
.story__snaps li:nth-child(even) .snap{transform:rotate(1.5deg)}
/* The way on: the link to the other story, in the display face, then Close, close under
   it. Each at least 44px tall. */
.story__end{display:grid;justify-items:start;gap:.25rem;margin-block-start:var(--space-1)}
.team .story__next,.team .story__foot{margin:0}
.story__go{display:inline-flex;align-items:center;gap:.5em;min-block-size:44px;font-family:var(--font-display);font-size:var(--fs-step);letter-spacing:-.01em}
.story__arrow{flex:none;inline-size:1em;block-size:1em;transition:transform var(--t-hover) var(--ease-out)}
@media (hover:hover){
  .story__go:hover .story__arrow{transform:translateX(3px)}
}
.story__foot[hidden]{display:none}
.story__close{min-block-size:44px;padding:0;font:inherit;font-weight:700;color:var(--ink);background:none;border:0;cursor:pointer}
@media (min-width: 64em){
  .story__window{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--gutter)}
  .story__words{grid-column:1 / 8}
  .story__side{grid-column:9 / -1;align-self:start}
  .story__end{grid-column:1 / -1}
  /* While the words are only the heading and the role (D-30: no answer prints until it
     is given), the way on moves up into their column, at the foot of the list beside it,
     so the window closes up round what is there instead of holding a hole the height of
     the list under the role (final review, looks-3). Once an answer prints, the layout
     above applies again. */
  .story__window:not(:has(.story__words > :nth-child(3))) .story__side{grid-row:1 / span 2}
  .story__window:not(:has(.story__words > :nth-child(3))) .story__end{grid-column:1 / 8;grid-row:2;align-self:end}
  /* And while it has no answers, what they do takes the wider share, two to a row with
     their icons, so the window is as tall as the heading and the way on beside it rather
     than a column of five over a hole (Sam's item 9: "boring, just text"). */
  .story__does li.has-icon{grid-template-columns:3.75rem minmax(0,1fr)}
  .story__window:not(:has(.story__words > :nth-child(3))) .story__words{grid-column:1 / 6}
  .story__window:not(:has(.story__words > :nth-child(3))) .story__end{grid-column:1 / 6}
  .story__window:not(:has(.story__words > :nth-child(3))) .story__side{grid-column:6 / -1}
  .story__window:not(:has(.story__words > :nth-child(3))) .story__does{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--gutter)}
}
/* An upright tablet, or a phone held sideways (48 to 64em, one column): while a story has
   no answers, what they do runs two to a row, as it does beside the words from 64em. One
   to a row, the lines (the longest 380px) left the window's right half empty and the
   window 694px tall at 768 by 1024; two to a row it is 558 (device pass, 2026-10-27). */
@media (min-width: 48em) and (max-width: 63.99em){
  .story__window:not(:has(.story__words > :nth-child(3))) .story__does{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--gutter)}
}
/* Two to a row the lines are short, so none ends on one word alone ("sort out access and
   photos with / you" at 844 by 390). */
.story__do{text-wrap:pretty}
@keyframes story-in{from{opacity:0;transform:translateY(var(--list-y))}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: no-preference){
  .js .story.is-opening{animation:story-in .4s var(--ease-arrive) both}
}

/* The page ends on the closing pair (P1-49), styled in its own block below. Under reduced
   motion the "+" and the arrows change state at once. */
@media (prefers-reduced-motion: reduce){
  .person__plus,.person__plus::before,.person__plus::after,.story__arrow{transition:none}
}

/* Stacked from 48em (an upright tablet): the 16:9 cut, full width, its right edge kept. */
@media (min-width: 48em){
  .not-found__media{inline-size:100%;aspect-ratio:16/9;max-block-size:60svh}
  .not-found__still img,.not-found__film{object-position:100% 50%}
  .not-found h1{font-size:clamp(2.75rem, 11cqi, 4.5rem)}
}

/* A phone held sideways (667 by 375, 568 by 320: under 48em, so the 4:5 phone cut): the
   words on the left and the film on the right, the screen's height under the bar, as the
   contact page's hero does. Stacked, the 4:5 box ran the screen's width capped at 52svh,
   so the frame showed a band across the symbol's middle and the heading began below the
   screen's foot, the way home further down still. */
@media (max-width: 47.99em) and (min-aspect-ratio: 4/3){
  .not-found{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;min-block-size:calc(100svh - var(--nav-h))}
  .not-found__media{grid-column:2;grid-row:1;align-self:start;inline-size:auto;block-size:calc(100svh - var(--nav-h));max-block-size:none;-webkit-mask-image:none;mask-image:none}
  .not-found__copy{grid-column:1;grid-row:1;padding:var(--space-2) var(--space-2) var(--space-2) var(--frame-inline)}
  /* Held to the screen's height as well as its column, as the side layout's is, so the
     way home is on the first screen at 568 by 320. */
  .not-found h1{font-size:clamp(2.25rem, min(13.5cqi, 11svh), 4.5rem)}
}

/* Side by side, from 48em on a screen at least 4:3: the first screen below the nav. The
   film covers the box with its right edge kept, so the symbol stays right. Its left edge,
   at its widest (the squash as it lands, 47.7% of the frame's width, measured on every
   frame), then sits at min(47.7vw, 100vw - 0.93 x the box's height), and the words'
   column stops 3vw short of it, starting on the nav's frame line. */
@media (min-width: 48em) and (min-aspect-ratio: 4/3){
  .not-found{--nf-h:calc(100svh - var(--nav-h));--nf-x:max(var(--margin),(100vw - 82rem) / 2);display:grid;align-items:center;box-sizing:border-box;min-block-size:var(--nf-h);padding-block:var(--space-4)}
  .not-found__media{position:absolute;inset:0;max-block-size:none;aspect-ratio:auto;-webkit-mask-image:none;mask-image:none}
  .not-found__copy{inline-size:min(40rem,calc(min(47.7vw,100vw - .93 * var(--nf-h)) - var(--nf-x) - 3vw));margin-inline-start:var(--nf-x);padding:0}
  .not-found h1{font-size:clamp(2.25rem, min(15cqi, 11svh), 6rem)}
}

/* The film's start state: only under .js and with motion allowed. Until site.js decides
   (.is-film or .is-still), the studio is empty, as the film's first frame is; once the
   film has ended the end frame under it shows again. The failsafe (T-052): if site.js
   never runs (blocked, failed, a browser too old), the end frame appears at 4 s; it
   stands down the moment the script marks the page .is-armed. */
@media (prefers-reduced-motion: no-preference){
  .js .not-found:not(.is-still):not(.is-done) .not-found__still{opacity:0}
  .js .not-found:not(.is-armed) .not-found__still{animation:not-found-failsafe 0s 4s forwards}
}
@keyframes not-found-failsafe{to{opacity:1}}

/* ==== The How it works page (D-23). Light page; the journey is its standout ("line") */
/* page-how-it-works.php says what is where. Two sections: the head, calm, then the
   journey, a road down the page with the three parts on it as stations and every step a
   kit window along it. The road and the windows sit on the light page; the clay icons
   and the symbol suit it (their navy outline fades on ink). Finished states first;
   every start state only under .js (T-052); only transform and opacity move. */

/* The head: the page-top picture (the page-tops block below), then the <h1> in two
   lines (the second in the magenta, large text only: at least 3.69:1 on the picture's
   paper, its darkest spot behind the line from 1366 up; 3.82:1 on a phone's ground)
   sized to its column (cqi) so "How it works." fits a 320px phone on one line, then the
   lead, large for easy reading as the About page's is. From 64em the h1 and the lead
   stand in the picture's empty half. */
.how-head{--scene:47%;--top-copy:29.5rem;padding-block:0 var(--space-4)}
.how-head h1{margin:0;font-family:var(--font-display);font-weight:400;font-size:clamp(2.25rem, 12.5cqi, 6.75rem);line-height:.95;letter-spacing:-.03em}
.how-head__line{display:block;text-wrap:balance}
.how-head__line + .how-head__line{color:var(--accent)}
.how-head .how-head__lead{max-inline-size:34ch;margin-block-start:var(--gap-text);font-size:clamp(1.25rem, 1rem + 1.1vw, 2rem);font-weight:500;line-height:1.38;letter-spacing:-.01em;color:var(--ink);text-wrap:pretty}
@media (min-width: 48em){
  .how-head h1{font-size:clamp(2.25rem, 7.2cqi, 6rem)}
}
@media (min-width: 64em), (orientation: landscape) and (max-height: 35em){
  .how-head h1{font-size:clamp(2.25rem, 13cqi, 6rem)}
}
/* The picture's paper is the page's (2026-10-27, Sam's front page item 5 applied here,
   as What we do's picture was the same day: a picture whose ground differs from the
   page's paper must match it, no seam and no tint). The studio in all three how-top
   files was regraded from its own #F2EEE6 to the page's #FBFAF7 by What we do's method,
   keeping 65% of the ground's shading so its soft shadows stay: each pixel moved to
   #FBFAF7 less 0.65 of its difference from #F2EEE6, in full from 88% lightness and not
   at all below 62%, nor where its colour passes 16% (from 7%), so the navy and magenta
   clay are untouched. The head's ground is the page's paper, so the band no longer
   stands on a beige of its own that faded out over the road's first room.
   Past 1920 the picture's right edge, regraded, is #F7F6F3 (its last 2%), so the
   ground darkens to that, as the page-tops block does for the beige. */
.how-head.page-top{--top-ground:var(--page)}
@media (min-width: 120.0625em){
  .how-head.page-top{background:linear-gradient(transparent calc(100% - var(--space-4)), var(--page)),linear-gradient(90deg, var(--top-ground) 50%, #F7F6F3 calc(50% + 60rem))}
}

/* The short version (D-75; Sam, 2026-10-27: "How it works is a long scroll, I think it
   needs a summary of all the steps at the top"). Every step by its own name, under its
   part, each a link to the step (#step-<n>), so the page can be skimmed here or used as
   a map. The page's one ink band, so the map reads as a map and the journey's first pill
   below is never taken for an echo of its own. The route is the front page's piped line
   (D-60) in miniature, not a copy of it: one magenta stroke through the three parts,
   each part's steps on stations along a thinner one, no portholes, no swags.
   - Phone, below 48em: the route runs down a lane on the left, as the road does below,
     the parts' pills and the steps' stations on it; each step one tap target, 44px tall
     at least (T-035), so thirteen fit on about one screen.
   - From 48em (an upright tablet): the three parts side by side, the stroke across from
     pill to pill, each part's steps hanging down under its pill.
   Each stroke is drawn a row at a time, each row's segment from its top to its foot, so
   a name that wraps can never break the line or carry it past the last station.
   Calm: nothing moves on its own. Under a mouse, a press or keyboard focus a station
   fills magenta, as the road's stations do when it reaches them. Paper on ink 15.98:1,
   the numbers and the hint (--text-secondary) 10.39:1; the stroke and the focus ring,
   magenta on ink, 4.02:1, past the 3:1 a graphic needs. */
.how-map{--lane:1.5rem;--dot:1rem;--stroke:4px;--twig:4px;padding-block:var(--pad-s);background:var(--canvas);color:var(--text-primary)}
.how-map__inner{display:grid;gap:var(--gap-head)}
.how-map__head{display:grid;gap:var(--space-2)}
.how-map h2{font-size:var(--fs-h3);color:var(--text-primary)}
.how-map .how-map__hint{max-inline-size:34ch;font-size:var(--fs-lead);font-weight:450;line-height:1.45;color:var(--text-secondary)}
.how-map__acts,.how-map__stops{list-style:none;margin:0;padding:0}
.how-map__acts{counter-reset:map}
.how-map__part,.how-map__stop{position:relative;font-size:var(--fs-body)}
/* A step's row at most 9vw, its station with it (it is placed in the row's em): at 200%
   text on a 320 phone the names had 112px beside the lane and number, and "yourself"
   and "change," ran 12px past the frame (device pass, 2026-10-27). Never at 100% text,
   where 9vw is over the body size from 320. */
.how-map__stop{font-size:min(var(--fs-body), 9vw)}
/* The part: its name on the kit's button, a paper face on its magenta plate, which on
   ink is the kit's "press me" (the nav's Get in touch), so it is one: a link to the part
   on the road (#part-<n>). In the display face, as the road's own pills, at 44px. */
.how-map__part{display:flex;padding-block:1.5rem .375rem}
.how-map__act:first-child .how-map__part{padding-block-start:0}
.how-map .how-map__pill{z-index:2;max-inline-size:calc(100% - var(--plate-sm))}
.how-map .how-map__pill .btn__face{min-block-size:44px;padding:.36em .95em .42em;font-family:var(--font-display);font-weight:400;font-size:clamp(1.125rem, 1rem + .55vw, 1.5rem);line-height:1.05;letter-spacing:-.01em;text-align:start}
/* The stroke: each row's segment down the middle of the lane, under its pill and its
   station; the first starts at the first pill's middle, the last stops at the last
   station's. A station's middle is the first line's: the link's top padding (.7rem) and
   half the name's 1.3 line (.65em), the name's size being the row's (--fs-body). */
.how-map__part::before,.how-map__stop::before{content:"";position:absolute;inset-block:0;inset-inline-start:calc(var(--lane) / 2 - var(--twig) / 2);inline-size:var(--twig);background:var(--accent)}
.how-map__act:first-child .how-map__part::before{inset-block-start:50%}
.how-map__act:last-child .how-map__stop:last-child::before{inset-block-end:auto;block-size:calc(.7rem + .65em)}
/* A step: the whole row is the link, at least 44px tall, its station in the lane, then
   its number (the one counter, from the CSS, never the copy: the journey's numbers, so a
   removed step renumbers both) and its name. */
.how-map__stop{counter-increment:map}
.how-map__link{display:grid;grid-template-columns:var(--lane) 1.5rem minmax(0,1fr);column-gap:.75rem;align-items:baseline;box-sizing:border-box;min-block-size:44px;padding-block:.7rem;line-height:1.3;color:inherit;text-decoration:none;-webkit-tap-highlight-color:transparent}
.how-map__dot{position:relative;z-index:1;align-self:start;justify-self:center;box-sizing:border-box;inline-size:var(--dot);block-size:var(--dot);margin-block-start:calc(.65em - var(--dot) / 2);background:var(--canvas);border:var(--line) solid var(--text-primary);border-radius:50%}
.how-map__dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--accent);transform:scale(0);transition:transform var(--t-state) var(--ease-arrive)}
.how-map__num{font-family:var(--font-display);font-size:.875rem;letter-spacing:-.01em;color:var(--text-secondary);font-variant-numeric:tabular-nums}
.how-map__num::before{content:counter(map, decimal-leading-zero)}
.how-map__name{font-weight:600;text-wrap:pretty;text-decoration:underline 2px transparent;text-underline-offset:.22em;transition:text-decoration-color var(--t-state) var(--ease-out)}
@media (hover:hover){
  .how-map__link:hover .how-map__dot::after{transform:scale(1)}
  .how-map__link:hover .how-map__name{text-decoration-color:var(--accent)}
}
.how-map__link:active .how-map__dot::after,.how-map__link:focus-visible .how-map__dot::after{transform:scale(1)}
.how-map__link:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:var(--radius-sm)}
.how-map + .journey{padding-block-start:var(--pad-s)}

@media (min-width: 48em){
  .how-map{--stroke:6px;--twig:3px}
  .how-map__acts{display:grid;grid-template-columns:repeat(3, minmax(0,1fr));column-gap:var(--gutter)}
  .how-map__part,.how-map__act:first-child .how-map__part{padding-block:0 .5rem}
  /* The stroke across, from inside each pill to inside the next, under both, through
     the middle of the paper face: the row's box is the button's plate margin above it,
     the button, and the .5rem below, and the face sits a plate up from the button, so
     its middle is half the margin and the .5rem above the row's. */
  .how-map__act:not(:last-child) .how-map__part::after{content:"";position:absolute;z-index:1;inset-inline:1rem calc(-1 * var(--gutter) - 1rem);inset-block-start:calc(50% - (var(--plate-sm) + .5rem) / 2 - var(--stroke) / 2);block-size:var(--stroke);background:var(--accent)}
  .how-map__part::before{inset-block-start:50%}
  .how-map__stop:last-child::before{inset-block-end:auto;block-size:calc(.7rem + .65em)}
}
/* On paper the band turns white (most print no backgrounds, and one that does would
   print the page's ink canvas behind it), its words ink, and the route keeps its
   magenta: the short version prints as a one-page list. */
@media print{
  .how-map{background:var(--white);color:var(--ink)}
  .how-map h2{color:var(--ink)}
  .how-map .how-map__hint,.how-map__num{color:var(--ink-soft)}
  .how-map__dot{background:var(--white);border-color:var(--ink)}
  .how-map__part::before,.how-map__part::after,.how-map__stop::before{-webkit-print-color-adjust:exact;print-color-adjust:exact}
}
/* An upright tablet's three columns are about 215px: the pill's name a size down so
   "Before the price" stays on one line (at 20px it wrapped, the pill grew and the first
   part's stations sat lower than the others'), and the lane and gaps a little tighter
   for the names. */
@media (min-width: 48em) and (max-width: 63.99em){
  .how-map{--lane:1.25rem}
  .how-map .how-map__pill .btn__face{padding-inline:.8em;font-size:1rem}
  .how-map__link{column-gap:.625rem}
}

/* The journey. --rail is the road's lane: down the left on a phone (the stations in it,
   the windows beside it), down the middle from 64em (the windows on alternate sides).
   The one counter runs down the whole road, so the numbers go on from part to part.
   The lane and the windows' padding are held to their sizes at the usual 16px text
   (min() and px, the same figures then): with a reader's text at 200% at 390 wide they
   doubled with it, the lane to 88px and each side of a window to 40px, and left the
   words 142px, a word or two a line, and step 03's faces, wider than that, spread
   every window's grid, so the words of all thirteen ran off the screen's edge
   (2026-10-27, device pass). Each window's one column is its own width, whatever is
   in it. */
.journey{--rail:min(2.75rem, 44px);--dot:1.25rem;--road:4px;--win-pad:clamp(20px, 12.8px + 2vw, 48px);padding-block:var(--space-3) var(--pad-l)}
.journey__inner{display:grid}
.track{position:relative;display:grid;row-gap:var(--pad-s);padding-block-end:var(--space-4);counter-reset:stop}

/* The road: a dashed ink line down the middle of the lane, under everything on it, and
   the magenta drawn over it (below). */
.track__road{position:absolute;inset-block:0;inset-inline-start:calc(var(--rail) / 2 - var(--road) / 2);inline-size:var(--road);border-radius:var(--road);background:repeating-linear-gradient(to bottom, var(--ink) 0 12px, transparent 12px 22px)}
.track__fill{position:absolute;inset:0;border-radius:inherit;background:var(--accent);transform-origin:50% 0}

/* A part: its name in an ink pill laid over the road (paper on ink, 15.98:1, on its
   magenta plate), and what the part is for, beside the lane. The pill's corner is in em,
   not 999px, so a name that wraps on a narrow phone still reads as a pill. */
.act{position:relative;display:grid;row-gap:var(--gap-head);scroll-margin-block-start:1rem}
.act__head{display:grid;justify-items:start;gap:var(--space-3)}
.journey .act__name{position:relative;display:inline-block;max-inline-size:100%;box-sizing:border-box;padding:.3em .7em .36em;font-size:clamp(1.5rem, 1.05rem + 2.4vw, 3.5rem);line-height:1;color:var(--paper);background:var(--ink);border-radius:.9em;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.act__text{max-inline-size:34ch;padding-inline-start:var(--rail);font-size:var(--fs-lead);font-weight:450;line-height:1.45;color:var(--ink-soft)}

/* A step: the station in the lane, level with its window's tab line; the window beside
   it; the clay icon a sticker on the window's top corner, tilting the other way step by
   step (decorative, so nothing under it needs a pointer). The name sits nearer its words
   than the number above it, so it reads as their heading (browser-check item 18).
   Each step has an address, #step-<n>, and each part #part-<n> (the short version's
   links, a link someone shares; D-75): a jump lands its top html's 88px under the
   pill, and a step's scroll margin adds room for the sticker that stands up to 2rem
   above the window's corner (1.5rem on a phone, turned 7deg), so a jump never leaves
   the sticker under the pill; a part's, 1rem, for its pill's plate. */
.stops{list-style:none;margin:0;padding:0;display:grid;row-gap:clamp(2.75rem, 2rem + 3vw, 4.5rem)}
.stop{--tilt:7deg;counter-increment:stop;position:relative;display:grid;grid-template-columns:var(--rail) minmax(0,1fr);align-items:start;scroll-margin-block-start:2rem}
.stop--flip{--tilt:-7deg}
.stop > .lift{grid-column:2;grid-row:1;align-self:start}
.stop__dot{position:relative;grid-column:1;grid-row:1;justify-self:center;box-sizing:border-box;inline-size:var(--dot);block-size:var(--dot);margin-block-start:calc(var(--tab) / 2 - var(--dot) / 2);background:var(--paper);border:var(--line-heavy) solid var(--ink);border-radius:50%}
.stop__dot::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--accent)}
.stop__window{display:grid;grid-template-columns:minmax(0,1fr);align-content:start}
.stop__num{font-family:var(--font-display);font-size:clamp(3rem, 2rem + 4.2vw, 6rem);line-height:.85;letter-spacing:-.03em;color:var(--accent);font-variant-numeric:tabular-nums}
.stop__num::before{content:counter(stop, decimal-leading-zero)}
.journey .stop__name{margin-block-start:var(--space-3);font-size:clamp(1.5rem, 1.1rem + 1.7vw, 2.75rem);line-height:1.02}
.journey .stop__text{max-inline-size:38ch;margin-block-start:.75rem;font-size:clamp(1.0625rem, .98rem + .4vw, 1.3125rem);line-height:1.5;color:var(--ink-soft)}
/* Never past 12vw and 10vw (device pass, 2026-10-27): at 200% text on a 320 phone a
   window leaves its words 169px, and "yourself" (203px at the name's 48px) and
   "screenshot." (171px) ran past the window's edge. Neither binds at 100% text, where
   both sizes are under them from 320. */
.journey .stop__name{font-size:min(clamp(1.5rem, 1.1rem + 1.7vw, 2.75rem), 12vw)}
.journey .stop__text{font-size:min(clamp(1.0625rem, .98rem + .4vw, 1.3125rem), 10vw)}
/* A line's last two words stay together (inc/how-it-works.php, smwd_how_keep_last), but
   at the reader's own large text on a phone (narrower than 20em of it: never at 100%)
   they may part: tied, "your enquiries." (230px at 200%) ran 36px past a 320 phone's
   window, past its edge (device pass, 2026-10-27). */
.journey .keep-last{white-space:nowrap}
@media (max-width: 19.99em){
  .journey .keep-last{white-space:normal}
}
.stop__icon{position:relative;z-index:2;grid-column:2;grid-row:1;justify-self:end;align-self:start;inline-size:5.5rem;margin-block-start:-1.5rem;margin-inline-end:-.25rem;pointer-events:none;transform:rotate(var(--tilt))}
.stop__img{display:block;inline-size:100%;block-size:auto}

/* What the monthly care covers: the kit's chunky pills, real words set as text (never
   buttons), then the link on to the services page while it is live. Flat, with no
   magenta plate: a paper pill on its plate is the kit's "press me" (the buttons, the
   FAQ's pills, the pair's arrows), and these are labels, so they sit like Our work's
   "Enquiry form" (final review, looks-6). */
.stop__covers{list-style:none;margin:var(--space-3) 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.625rem}
.stop__covers > li{padding:.4em .95em .45em;font-weight:700;font-size:1rem;line-height:1.2;color:var(--ink);background:var(--paper);border:2px solid var(--ink);border-radius:999px}
.journey .stop__more{margin-block-start:var(--space-3);font-size:1rem;font-weight:700}
/* One line from 320px up at 16px ("The monthly care in full" is 183px of the 188 a
   320px phone leaves it), so the text link's underline stays under it. 46px tall, not
   44, as .stack__link's and .cta__privacy's are: the window scales from .96 as it
   arrives, and the link must still be 44px while it does (hiw-tap-17). */
.stop__more .text-link{display:inline-flex;align-items:center;min-block-size:46px}

/* The faces (template-parts/faces.php): step 03's here (P1-50), and the contact page's
   beside the form (P1-30), which places them in its own block. Each the kit's pill
   (paper on its magenta plate, lifting 2px under a mouse), a round face at its start
   (that person's square cut, else their portrait cropped high, where the face is, else
   their initials) and the first name after it; side by side, wrapping on a narrow
   phone; 52px tall. */
.faces__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem 1rem}
.faces .face{font-size:1.0625rem}
.faces .face .btn__face{gap:.6em;min-block-size:3.25rem;padding:.25rem 1.15rem .25rem .25rem}
.face__photo{flex:none;inline-size:2.5rem;block-size:2.5rem;box-sizing:border-box;overflow:hidden;background:var(--page);border:2px solid var(--ink);border-radius:50%}
.face__img{display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 20%}
/* Initials in the same circle until that person's photograph comes (Sam, 2026-10-26:
   his now, Stanley's later), set as the front page's thread sets them: Sam on white,
   Stanley on ink, so a photograph and a set of initials still read as a pair. */
.face__photo.is-initials{display:grid;place-items:center;font-family:var(--font-display);font-size:.9375rem;line-height:1;letter-spacing:-.02em;color:var(--ink);background:var(--white)}
.face__photo.is-initials.is-alt{color:var(--paper);background:var(--ink)}
/* A short name ("Stan") in place of the initials, smaller to sit inside the ring, as the
   thread's .is-word does. */
.face__photo.is-initials.is-word{font-size:.6875rem;letter-spacing:-.03em}
.stop__faces{margin-block-start:var(--space-3)}
/* Step 03's pills at 200% text (the lane's note above): the face and the padding keep
   their 16px-text sizes, so "Stanley" fits the window's column. */
.stop__faces .face{max-inline-size:100%}
.stop__faces .face .btn__face{padding-inline-end:min(1.15rem, 18.4px)}
.stop__faces .face__photo{inline-size:min(2.5rem, 40px);block-size:min(2.5rem, 40px)}

/* The end of the road: a big station and the question, then the closing pair (P1-49,
   its own block below) across the frame, the two cards as on What we do. The station
   fills as the stations on the road do (its magenta an ::after, the arrivals below). */
.journey__end{display:grid;justify-items:start;gap:var(--space-3)}
.journey__stop{position:relative;box-sizing:border-box;inline-size:min(var(--rail), 4rem);aspect-ratio:1;background:var(--paper);border:var(--line-heavy) solid var(--ink);border-radius:50%}
/* The question centred at every width, as Our work's is, over the pair (looks-1); the
   station stays on the road. */
.journey__end h2{justify-self:center;margin-block-start:var(--space-2);text-align:center}

@media (min-width: 48em){
  .journey{--rail:min(3.5rem, 56px)}
  .stop{scroll-margin-block-start:2.5rem}
  .stop__icon{inline-size:7rem;margin-block-start:-2rem}
}
/* From 48em to 64em (an upright tablet, a phone held sideways) a window runs the width
   of the page, and its words, held to a reading measure, left its right third empty
   under a 7rem sticker on the corner: a phone's window stretched (2026-10-27, device
   pass; 247px of 651 bare at 768). Here the clay icon stands inside the window's right
   side, large, beside the words and in the middle of them top to bottom, as What we
   do's windows set their pictures, and the words keep clear of it. Still turned a
   touch, still settling as the road reaches its station; still decorative, so a press
   goes through it. From 64em it stands free beside the road (below). */
@media (min-width: 48em) and (max-width: 63.99em){
  .stop{--icon:clamp(8rem, 2rem + 10vw, 9.5rem)}
  .stop__icon{align-self:center;inline-size:var(--icon);margin:0 calc(var(--win-pad) + var(--plate)) 0 0}
  .stop__window{padding-inline-end:calc(2 * var(--win-pad) + var(--icon))}
}

/* From 64em the road runs down the middle: each window on one side, its icon large on
   the other, swapping sides step by step, a short spur from the station to the window.
   The parts' names and lines sit centred on the road, the line on the page's own ground
   so the road passes behind it. */
@media (min-width: 64em){
  .journey{--rail:7rem;--dot:1.75rem}
  .track__road{inset-inline-start:calc(50% - var(--road) / 2)}
  .act__head{justify-items:center;text-align:center}
  .act__text{position:relative;padding:var(--space-1) var(--space-2);background:var(--page)}
  .stop{grid-template-columns:minmax(0,1fr) var(--rail) minmax(0,1fr);align-items:center;scroll-margin-block-start:1.25rem}
  .stop > .lift{grid-column:1}
  .stop--flip > .lift{grid-column:3}
  .stop__dot{grid-column:2;align-self:start}
  /* The spur runs from the station to the window's edge, 2px under it: on the left the
     window sits a plate in from its column's end (the lift's own offset), on the right
     its edge is the column's start. */
  .stop__dot::before{content:"";position:absolute;top:calc(50% - var(--line) / 2);right:100%;inline-size:calc(var(--rail) / 2 - var(--dot) / 2 + var(--plate) + 2px);block-size:var(--line);background:var(--ink)}
  .stop--flip .stop__dot::before{right:auto;left:100%;inline-size:calc(var(--rail) / 2 - var(--dot) / 2 + 2px)}
  .stop__icon{grid-column:3;justify-self:start;align-self:center;inline-size:clamp(9rem, 1rem + 12vw, 15rem);margin:0 0 0 clamp(1rem, 4vw, 4rem)}
  .stop--flip .stop__icon{grid-column:1;justify-self:end;margin:0 clamp(1rem, 4vw, 4rem) 0 0}
  .journey__end{justify-items:center;text-align:center}
  .journey__end h2{font-size:var(--fs-h2)}
}

/* The arrivals. The road's magenta follows the reader down: its tip held at the middle
   of the screen as the road passes it, a CSS scroll-driven animation (page-design.md,
   section 4: no scroll listener). Its insets are 0, so the tip stays on that line all
   the way down: left to html's scroll-padding (the nav pill's 88px), the timeline's
   view began below the pill and the tip slid from the middle to 88px under it by the
   road's end. Each window still rises as it comes on screen (P3, the .lift reveal, on
   core.js's .in); its station fills, and its icon settles in a beat after, from a
   little above and turned further, on --ease-arrive (no overshoot), only as the tip
   reaches the station's dot (.is-reached, site.js bootRoad, watching that same middle
   line), and the big station at the end fills as the road ends in it. Scrolled back up,
   the road goes back and each station it leaves empties again, so nothing is ever lit
   ahead of the road (Sam's round 2, item f: they filled 300 to 390px ahead of it, on
   .in at 92% of the screen). Where the browser has no view timeline the magenta runs to
   the last station reached instead (--reach, from site.js), and only there, since a
   transition on the same transform would override the scroll's animation while it ran.
   With reduced motion, or without the script, the road is simply drawn and every
   station full. Nothing here loops while on screen (a11y-7, page-how-it-works.php says
   what was checked): each moves only with the reader's scroll. */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .track{view-timeline:--road block;view-timeline-inset:0}
    .js .track__fill{animation:road-draw linear both;animation-timeline:--road;animation-range:cover 50vh cover calc(100% - 50vh)}
  }
}
@supports not (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .js .track__fill{transform:scaleY(var(--reach, 1));transition:transform .9s var(--ease-arrive)}
  }
}
@keyframes road-draw{from{transform:scaleY(0)}to{transform:scaleY(1)}}
.journey__stop::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--accent)}
.js [data-standout] .stop:not(.is-reached) .stop__dot::after,
.js [data-standout] .journey__end:not(.is-reached) .journey__stop::after{transform:scale(0)}
.js [data-standout] .stop__dot::after,.js [data-standout] .journey__stop::after{transition:transform .4s var(--ease-arrive)}
/* An icon still waiting for the road takes no pointer, so the bubble (inc/cursor.php)
   never shows over the empty room where it will settle, and no click plays it there. */
.js [data-standout] .stop:not(.is-reached) .stop__icon{opacity:0;transform:translateY(-14%) rotate(calc(var(--tilt) - 14deg)) scale(.88);pointer-events:none}
.js [data-standout] .stop__icon{transition:transform .7s var(--ease-arrive) .15s,opacity .4s var(--ease-arrive) .15s}
@media (prefers-reduced-motion: reduce){
  .js [data-standout] .stop__dot::after,.js [data-standout] .journey__stop::after{transform:none;transition:none}
  .js [data-standout] .stop__icon{opacity:1;transform:rotate(var(--tilt));transition:none}
}

/* Focus after a jump from the short version (site.js, bootMap): the step's name, or the
   part's, takes focus with no ring for a mouse or a finger, and the kit's magenta ring
   for the keyboard, which needs to see where it landed. */
.journey :is(.stop__name,.act__name):focus{outline:none}
.journey .stop__name:focus-visible{outline:3px solid var(--focus);outline-offset:6px;border-radius:4px}
.journey .act__name:focus-visible{outline:3px solid var(--focus);outline-offset:calc(var(--plate-sm) + 4px)}

/* Where you are (D-75; site.js, bootWhere): from 48em, while the road is being read, the
   kit's button at the foot of the screen, at the frame's right edge: the route in
   miniature (a dot a step, the parts apart, filled magenta up to the step the road has
   reached, that one a size up) and "All steps", back to the short version. Printed
   hidden, so without the script it never shows. It fades and rises 8px in and out; it
   takes no pointer and no focus while out (visibility). On a phone it never shows: the
   screen is the road's. While it shows, html keeps what the browser scrolls to (a
   focused link) clear of it, as it does of the pill (WCAG 2.4.11, a11y-2). Under the
   nav (its z-index 40), so an open menu is never covered by it. Nor on a phone held
   sideways (landscape, 35em tall or less, as the page-tops block says): at 844x390 the
   nav's pill and this one took 128px of the 390, and this one lay over the words of
   every window as it passed the foot of the screen (2026-10-27, device pass). */
.section .how-where{display:none}
@media (min-width: 48em) and (orientation: portrait), (min-width: 48em) and (min-height: 35.0625em){
  .section .how-where:not([hidden]){position:fixed;z-index:30;right:var(--frame-inline);bottom:calc(env(safe-area-inset-bottom, 0px) + 1.25rem);display:inline-flex;margin:0;visibility:hidden;opacity:0;transform:translateY(8px);transition:opacity var(--t-state) var(--ease-out),transform var(--t-state) var(--ease-out),visibility 0s linear var(--t-state)}
  .section .how-where.is-shown{visibility:visible;opacity:1;transform:none;transition-delay:0s}
  .section .how-where .btn__face{gap:.75rem;min-block-size:2.875rem;padding:.5em 1.1em .5em 1em;font-size:1rem}
  .how-where__route{display:flex;align-items:center;gap:.5rem}
  .how-where__part{display:flex;align-items:center;gap:.1875rem}
  .how-where__dot{box-sizing:border-box;inline-size:.5rem;block-size:.5rem;border:2px solid var(--ink);border-radius:50%;background:var(--paper);transition:background-color var(--t-state) var(--ease-out),transform var(--t-state) var(--ease-out)}
  .how-where__dot.is-on{background:var(--accent);border-color:var(--accent)}
  .how-where__dot.is-here{transform:scale(1.5)}
  .how-where__arrow{flex:none;margin-inline-start:-.25rem}
  html:has(.how-where.is-shown){scroll-padding-block-end:5rem}
}
@media (min-width: 48em) and (prefers-reduced-motion: reduce){
  .section .how-where:not([hidden]),.how-where__dot{transition:none}
}
/* Never on paper: fixed, it would print at the foot of every sheet. */
@media print{
  .section .how-where:not([hidden]){display:none}
}

/* ==== The clay icons' films on the two new pages (2026-10-20, inc/icon-films.php) ==== */
/* Each film is framed so its first frame lies exactly over the still: 130% of the
   still's box, with the still's box centred in it. Its studio's paper is white, and
   multiply lets the window or the page show through it, so only the clay and its soft
   shadow show, and the icon stands free as the stills do. The <video> shows only with
   motion allowed and once it has a frame (site.js marks the box .is-ready), and the
   still goes then, or the film's white would show it through the moving clay; a film
   still loading, or one that fails, leaves the still, and so do reduced motion, no
   script and Save-Data. On the services page the blend reaches the window (the window
   is the stacking context). On the How it works page the icon is turned by its tilt,
   which makes it a stacking context of its own, so it blends as a whole, and only from
   64em, where it stands free beside the road: below that it is a sticker on its
   window's corner and keeps the still (page-how-it-works.php). */
.has-film{position:relative}
.icon-film{position:absolute;top:-15%;left:-15%;display:none;inline-size:130%;block-size:130%;mix-blend-mode:multiply;pointer-events:none}
@media (prefers-reduced-motion: no-preference){
  .part__pic.has-film > .icon-film{display:block;visibility:hidden}
  .part__pic.has-film.is-ready > .icon-film{visibility:visible}
  .part__pic.has-film.is-ready > img{visibility:hidden}
}
/* The icons beside the road answer a mouse from 64em (the film plays again, and the
   pointer's bubble shows); below it they are stickers over their windows' corners, and
   a press goes through them to the window. */
@media (min-width: 64em){
  .stop__icon{pointer-events:auto}
}
@media (min-width: 64em) and (prefers-reduced-motion: no-preference){
  .stop__icon.has-film{mix-blend-mode:multiply}
  .stop__icon.has-film > .icon-film{display:block;visibility:hidden;mix-blend-mode:normal}
  .stop__icon.has-film.is-ready > .icon-film{visibility:visible}
  .stop__icon.has-film.is-ready > img{visibility:hidden}
}

/* ==== The new pages' first screens: the page-top pictures (2026-10-20) ============= */
/* inc/page-tops.php: the front page's clay studio with the page's own clay things round
   the symbol, its left half empty paper for the words, as on the front page's first
   screen. The head takes the picture's own paper as its ground (sampled from its left
   half and its edges, #F2EEE6 between the two pictures: ink 15.4:1, --ink-soft 7.2:1),
   so the picture's edges disappear into it; the faded edges below take the last few
   levels of difference. Calm: nothing moves.
   - Phone, below 48em: the square crop first, the whole scene, full width and at most
     46% of the screen's height so the h1 follows it on the first screen, its foot
     fading into the ground; then the words.
   - From 48em: the wide picture, full width at its own shape, its right edge kept;
     then the words.
   - From 64em: the picture fills the band at its own shape, and the h1 and the lead
     stand in its empty left half, in the middle top to bottom (from a set top, below):
     the column runs from the page's frame line to two gutters short of where the clay
     begins (--scene, set per page: the scene starts 44.5% across the services picture
     and 47% across How it works's).
     The picture is never scaled by the band's height, so words that run taller than it
     push the band down with the picture centred in it and the ground above and below,
     and never slide the clay under the words.
   The ground fades into the page's paper over the head's empty foot (its last
   --space-4), so the band never stops on a hard line, and How it works's road starts a
   small section's room below it rather than 28px under the cut (review
   how-top-seam-cramped). */
.page-top{--top-ground:#F2EEE6;background:linear-gradient(var(--top-ground) calc(100% - var(--space-4)), var(--page))}
.page-top + .journey{padding-block-start:var(--pad-s)}
.section > .page-top__band{inline-size:auto;margin-inline:0}
.page-top__pic{position:relative;display:block;inline-size:100%;aspect-ratio:1;max-block-size:46svh;overflow:hidden;overflow:clip;-webkit-mask-image:linear-gradient(#000 86%,transparent);mask-image:linear-gradient(#000 86%,transparent)}
.page-top__pic img{display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 50%}
.page-top__copy{box-sizing:border-box;inline-size:var(--container);margin-inline:auto;padding-block-start:var(--space-2);container-type:inline-size}
@media (min-width: 48em){
  .page-top__pic{aspect-ratio:1920 / 1086;max-block-size:none}
  .page-top__pic img{object-position:100% 50%}
  .page-top__copy{padding-block-start:var(--space-3)}
}
/* A phone held sideways (landscape, 35em tall or less: the hero's own gate for it,
   engine.css) takes the desktop's first screen, the words in the picture's empty half,
   whatever its width (2026-10-27, device pass). Stacked, the wide picture alone filled
   the first screen at 844x390 and 932x430 with the h1 under the fold, and below 48em
   the square crop, held to 46svh, was a slice through the clay (172px of 667 at
   667x375, the symbol's top and foot cut off). inc/page-tops.php serves it the wide
   picture for the same reason. The words start a smaller step down: the screen is
   short. */
@media (orientation: landscape) and (max-height: 35em){
  .page-top__pic{aspect-ratio:1920 / 1086;max-block-size:none}
  .page-top__pic img{object-position:100% 50%}
}
@media (min-width: 64em), (orientation: landscape) and (max-height: 35em){
  .page-top__band{position:relative;display:grid;align-items:start;aspect-ratio:1920 / 1086}
  .page-top__pic{position:absolute;inset:50% 0 auto 0;transform:translateY(-50%);-webkit-mask-image:linear-gradient(transparent,#000 6%,#000 94%,transparent);mask-image:linear-gradient(transparent,#000 6%,#000 94%,transparent)}
  .page-top__copy{position:relative;inline-size:calc(var(--scene, 44%) - var(--frame-inline) - 2 * var(--gutter));margin-inline:var(--frame-inline) 0;padding-block:var(--space-4)}
  /* The words hang from a set top rather than centring on their own height: on a cold
     visit the lead's face (DM Sans) can land after the first paint, and as the lead
     rewrapped, centred words jumped 22px (review services-top-load-jump). The top is
     where the copy's usual height (--top-copy, set per page beside --scene: 34rem for
     the services page's 515 to 560px, 29.5rem for How it works's 422 to 483px) would be
     centred in the band, whose height is 56.5625% of its width, so the words still
     stand in the middle and a face arriving moves nothing above the lead's last line. */
  .page-top__copy{margin-block-start:max(0px, (56.5625% - var(--top-copy, 34rem)) / 2)}
  /* No wider than 1920 (120rem), centred on the ground. Wider, the column (the scene's
     start less a frame line that grows with the screen) narrowed as the clay grew, so
     the words shrank: at 2560 the h1 was 72px against 82 at 1440, the lead 25
     characters a line, the picture taller than the screen (review page-top-scale-wide).
     Inside a capped band --frame-inline is measured on the band and still lands on the
     page's frame line, so the words hold their 1920 sizes and stay in line with the
     page below. */
  .section > .page-top__band{max-inline-size:120rem;margin-inline:auto}
}
@media (max-width: 63.99em) and (orientation: landscape) and (max-height: 35em){
  .page-top__copy{padding-block:var(--space-3)}
}
/* Past 1920 the picture's sides stand on the ground too. Its left edge is the ground's
   paper; its right edge is a shade darker (#EBE6DE, sampled from both pictures' last
   2%), so the ground darkens to it from the middle, behind the picture, and right of
   the picture it carries on in that shade. Its sides fade into the ground, the left
   over 8% (empty paper) and the right over 2%, which the clay stays clear of (it ends
   at most 97.1% across). */
@media (min-width: 120.0625em){
  .page-top{background:linear-gradient(transparent calc(100% - var(--space-4)), var(--page)),linear-gradient(90deg, var(--top-ground) 50%, #EBE6DE calc(50% + 60rem))}
  .page-top__pic{-webkit-mask-image:linear-gradient(transparent,#000 6%,#000 94%,transparent),linear-gradient(90deg,transparent,#000 8%,#000 98%,transparent);-webkit-mask-composite:source-in;mask-image:linear-gradient(transparent,#000 6%,#000 94%,transparent),linear-gradient(90deg,transparent,#000 8%,#000 98%,transparent);mask-composite:intersect}
}

/* ==== The About page's fun facts (Stanley, 2026-10-20). Light page, calm ========== */
/* "A fun fact type thing, just to keep it playful", after Shaped by You's "burritos
   eaten" (page-about.php and inc/about.php say why it sits in the team section, under
   the stories and before the pill). Five stickers: a white tile with the kit's ink
   outline on its magenta plate, its clay icon (on the light tile only: the icons' navy
   outline fades on ink), a big magenta number (display size only, 4.42:1 on the white
   tile, never small text) and a short label in ink. Phone: one column, the tiles set to
   alternate sides as the cards above are once the screen is wider than a tile; from
   48em upright, three and two; from 80em five in a row, every other one set lower (in
   a row of five below 80em, at 1024 a number was 25px: no longer big). Never wider
   than the page: the tiles shrink and the numbers with them. */
.facts{display:grid;gap:var(--gap-head);margin-block-start:var(--pad-s)}
/* Greedy wrapping in a measure the heading never fits on one line, so it breaks after
   its comma at every size: balanced, it broke after "By the" on a phone. */
.team .facts h2{justify-self:center;max-inline-size:18ch;text-align:center;font-size:clamp(2rem, 1.3rem + 2.6vw, 3.75rem);line-height:1.05;text-wrap:wrap}
/* Its 2rem floor gives way to 13vw at large text: at 200% "numbers," (4.85em) at 64px was
   310px, past a 320 phone's 256px column. 13vw is over 2rem from 246px, so never at 100%. */
.team .facts h2{font-size:clamp(min(2rem, 13vw), 1.3rem + 2.6vw, 3.75rem)}
.facts__list{list-style:none;margin:0;padding:0;display:grid;row-gap:var(--space-3)}
/* The plate stays inside the column (as the cards' does), so at 375 a tile set to the
   right never crosses the page's gutter. --tilt turns each tile's icon its own way. */
.fact{box-sizing:border-box;display:grid;grid-template-columns:5.5rem minmax(0,1fr);align-items:center;column-gap:var(--space-2);inline-size:min(100% - var(--plate), 22rem);margin:0 var(--plate) var(--plate) 0;padding:var(--space-2) 1.25rem;background:var(--white);color:var(--ink);border:var(--line-heavy) solid var(--ink);border-radius:var(--radius-win);box-shadow:var(--plate) var(--plate) 0 var(--accent);transform:rotate(var(--turn, 0deg))}
.fact:nth-child(1){--tilt:-8deg;--turn:-1deg}
.fact:nth-child(2){--tilt:6deg;--turn:1.25deg}
.fact:nth-child(3){--tilt:-4deg;--turn:-.75deg}
.fact:nth-child(4){--tilt:7deg;--turn:1deg}
.fact:nth-child(5){--tilt:-6deg;--turn:-1.25deg}
.fact:nth-child(even){justify-self:end}
.fact__icon{display:block;grid-column:1;transform:rotate(var(--tilt, 0deg))}
.fact__img{display:block;inline-size:100%;block-size:auto}
/* The "nearly done" bar is a wide, low toy in a square file, the clear room above and
   below it two thirds of the square: cropped to its own shape, so its tile has no empty
   band over the number (and from 48em the bar rests on the tile's edge). */
.fact--nearly .fact__img{aspect-ratio:5 / 2;object-fit:cover}
/* The words are the container the number is sized against: --n is the widest number's
   width in figures (inc/about.php: a comma half a figure, the smaller "+" .6), and a
   figure is .657em wide with the tracking, so at 100cqi / (--n x .66) the widest always
   fits on one line and every tile's number is the same size. Counted by length, a comma
   and the "+" as whole figures, the numbers were 41.6px in a row of five at 1440 and
   up: smaller than the heading over them. The figures are tabular (Archivo Black's are
   by default; asked for anyway), so the count never changes a number's width. */
.fact__words{grid-column:2;container-type:inline-size;margin:0}
/* A fact whose icon is not in the theme (a new one, say): its words take the whole tile. */
.fact__words:only-child{grid-column:1 / -1}
.fact__num{display:grid;font-family:var(--font-display);font-size:min(4.25rem, 100cqi / (var(--n, 7) * .66));line-height:1;letter-spacing:-.01em;white-space:nowrap;color:var(--accent);font-variant-numeric:tabular-nums}
/* The "+" smaller and raised, as a stat's "+" often is: the figures are the number. */
.fact__tail{font-size:.6em;vertical-align:.5em}
/* The count (site.js, bootFacts): its copy sits in the same cell as the real number,
   which keeps its room and stays in the page for a screen reader, unseen until the
   count lands on it. */
.fact__value,.fact__tick{grid-area:1 / 1}
.fact__num.is-counting .fact__value{opacity:0}
.fact__label{display:block;margin-block-start:.4rem;font-size:var(--fs-body);font-weight:600;line-height:1.3;text-wrap:balance}
/* A list narrow for its text size (a phone with a larger default text, or a 320 screen):
   the icon over the words, which then have the tile's whole width. Beside a 5.5rem icon,
   the words were left so little room that at 375 with 24px text the number (20.6px) was
   smaller than its label, and at 32px it was 12.6px magenta: small text at 4.42:1. In
   rem, so the turn comes earlier the larger the text: 320px at 16px, 480px at 24px. */
.facts__list{container:facts / inline-size}
@container facts (max-width: 20rem){
  .fact{grid-template-columns:minmax(0,1fr);row-gap:var(--space-1)}
  .fact__icon{inline-size:5.5rem}
  .fact__words{grid-column:1}
}

/* Tablets and small laptops: three and two, centred, the icon over the words. Every
   tile in a row is as tall as the tallest, its words at its foot, and every other one is
   set lower by a transform, which keeps its height (set lower by a margin and sized to
   its own icon, the "nearly done" tile was 35 to 40% shorter than the rest, the bottoms
   wandered and the lower row was lopsided). A transform takes no room, so the rows'
   gap and the list's foot make room for the lower ones. */
@media (min-width: 48em){
  .facts__list{display:flex;flex-wrap:wrap;justify-content:center;align-items:stretch;gap:calc(clamp(4.5rem, 3rem + 3vw, 5.5rem) + 2.5rem) var(--gutter);padding-block:2.5rem}
  .fact{flex:0 1 calc((100% - 2 * var(--gutter)) / 3 - var(--plate));inline-size:auto;grid-template-columns:minmax(0,1fr);grid-template-rows:auto 1fr;row-gap:var(--space-1);padding:0 1.25rem 1.25rem}
  .fact:nth-child(even){transform:translateY(2.5rem) rotate(var(--turn, 0deg))}
  /* The icon stands on the tile's top edge, half out of it, like a toy put down on it. */
  .fact__icon{inline-size:min(8.5rem, 78%);margin-block-start:-2.75rem}
  .fact__words{grid-column:1;grid-row:2;align-self:end}
  .fact__words:only-child{padding-block-start:1.25rem}
}
/* From 80em: all in one row (five as built, three since the So What test), closer and
   wider than the page's column (up to 96rem, never past the page's margins), so each
   number stays big: in the 82rem column with
   the wider gaps they were the smallest on the biggest screens. The heading's track is
   the column's (minmax), so the wider row is centred on it rather than stretching it.
   No tile grows past 22rem: with three (the So What test, 2026-10-24, cut two) each
   stretched to about 440px at 1440, its words lost on the left of an empty card; five
   never reach the cap, so their row is as it was. */
@media (min-width: 80em){
  .facts{grid-template-columns:minmax(0,1fr)}
  .facts__list{flex-wrap:nowrap;column-gap:var(--space-2);justify-self:center;inline-size:min(100vw - 2 * var(--margin), 96rem)}
  .fact{flex-basis:0;flex-grow:1;max-inline-size:22rem;padding-inline:.75rem}
}

/* The arrival: once each tile has come into view (core.js's .in) and its picture is
   decoded (site.js's .is-set: settling on a picture still loading, the icon popped in
   after the motion had played), its icon is put down on it: from a little above, turned
   further and smaller, settling to rest, 700ms on the arrival curve with no overshoot.
   Transform and opacity only, on the picture, so the hop below (on its frame) never
   waits on it. Tiles that arrive together are staggered by --d, 70ms a step (P2's
   rhythm): on a phone each tile arrives alone. The start state is under .js only, from
   the first paint until .in as every reveal's is, and after .in it waits for the picture
   only while .facts is .is-ready, which site.js adds (T-052): without site.js the icons
   show on arrival. The motion is on .is-set only, so being put back to the start state
   when site.js boots is never seen as a fade. .in and .is-set are only ever added, so
   each icon is set down once and stays (a11y-7, option A: nothing loops on screen). */
.js .fact:not(.in) .fact__img,
.js .facts.is-ready .fact:not(.is-set) .fact__img{opacity:0;transform:translateY(-1.25rem) rotate(-12deg) scale(.85)}
.js .fact.is-set .fact__img{transition:transform .7s var(--ease-arrive) calc(var(--d, 0) * 70ms),opacity .4s var(--ease-arrive) calc(var(--d, 0) * 70ms)}
@media (min-width: 48em){
  .fact:nth-child(2),.fact:nth-child(5){--d:1}
  .fact:nth-child(3){--d:2}
}
@media (min-width: 80em){
  .fact:nth-child(4){--d:3}
  .fact:nth-child(5){--d:4}
}
/* A small hop of the icon under a mouse or trackpad (the tile itself never moves, so it
   never reads as a button): up 6px and a little further round in 300ms, back in 200ms. */
@media (hover:hover) and (pointer:fine) and (prefers-reduced-motion: no-preference){
  .fact__icon{transition:transform .2s var(--ease-out)}
  .fact:hover .fact__icon{transform:translateY(-6px) rotate(calc(var(--tilt, 0deg) + 5deg));transition-duration:var(--t-hover)}
}
@media (prefers-reduced-motion: reduce){
  .js .fact .fact__img,.js .fact:not(.in) .fact__img,.js .facts.is-ready .fact:not(.is-set) .fact__img{opacity:1;transform:none;transition:none}
}
/* On paper the strip is finished whether or not it was scrolled to: every real number
   and every icon, never a count's copy (a page printed before the strip arrived read
   "0+" under blank icons). */
@media print{
  .fact__tick{display:none}
  .fact__num.is-counting .fact__value{opacity:1}
  .js .fact .fact__img,.js .fact:not(.in) .fact__img,.js .facts.is-ready .fact:not(.is-set) .fact__img{opacity:1;transform:none;transition:none}
}

/* ==== About's "All two of us." (P1-54, page-about.php). Light page, calm ========== */
/* The two of them on the partnership, from Huge's two-person interviews: printed only
   once a question has both answers (D-30). As wide as the stories and centred with
   them; the heading on the left at the facts heading's size, rising as every heading
   does (D-2) and nothing else moving; the photograph of the two of them, wide, in the
   kit's ink outline on its magenta plate (only once it is real); then the talk in a
   reading column of 65 to 75 characters, set in two of twelve columns from the left from
   64em and full width on a phone. Each answer opens with the name in bold, in ink. */
.together{justify-self:center;display:grid;justify-items:start;inline-size:min(100%, 64rem);margin-block-start:var(--pad-s)}
.team .together h2{margin:0;font-size:clamp(2rem, 1.3rem + 2.6vw, 3.75rem);line-height:1.05}
.team .together__photo{box-sizing:border-box;inline-size:calc(100% - var(--plate));margin:var(--gap-text) var(--plate) var(--plate) 0;overflow:hidden;background:var(--slot);border:var(--line-heavy) solid var(--ink);border-radius:var(--radius-win);box-shadow:var(--plate) var(--plate) 0 var(--accent)}
.together__photo img{display:block;inline-size:100%;block-size:auto;aspect-ratio:16/9;object-fit:cover;object-position:50% 35%}
/* 47ch of this face at this size is about 70 characters a line (measured: 58ch gave
   87). One answer's paragraphs sit closer than the two answers do, so each reads as one
   person's turn. */
.together__talk{display:grid;gap:var(--space-2);max-inline-size:47ch}
.team .together h3{margin-block:var(--gap-text) calc(var(--space-1) - var(--space-2));font-size:var(--fs-step)}
.together__answer{display:grid;gap:.6rem}
.team .together__answer p{margin:0;font-size:var(--fs-body);line-height:1.6;color:var(--ink-soft)}
.together__answer strong{font-weight:700;color:var(--ink)}
@media (min-width: 64em){
  .together__talk{margin-inline-start:calc(2 / 12 * 100%)}
}

/* ==== Sam's and Stanley's own pages (Sam, 2026-10-27; page-profile.php). Light, calm == */
/* The reference's shape in our kit (D-72): a square portrait in the kit's window (the
   ink outline, the magenta plate), the name very large in the display face with the
   curtain's magenta full stop, the role, then the line; "About Sam" under it, then the
   closing pair. Phone: one column, the portrait not full width, so the name and the line
   are on the first screen with it. From 48em the portrait takes four of twelve columns
   and the words the rest, set in by a gutter so the huge name never touches the frame;
   "About Sam" sits in the same column as the words, one axis down the page, and from
   64em its heading hangs on the left under the portrait, as the FAQ's does. */
.profile{padding-block:var(--pad-s) var(--pad-l)}
.profile__inner{row-gap:var(--pad-s)}
.profile__head{display:grid;gap:var(--gap-text);align-items:center}
/* The window: square, ink while the photograph loads (never the pale slot, D-30), its
   plate kept inside the column so on a phone it never crosses the gutter. */
.profile__portrait{position:relative;box-sizing:border-box;inline-size:min(100% - var(--plate), 17rem);aspect-ratio:1;margin:0 var(--plate) var(--plate) 0;overflow:hidden;background:var(--ink);border:var(--line-heavy) solid var(--ink);border-radius:var(--radius-win);box-shadow:var(--plate) var(--plate) 0 var(--accent)}
/* The 4:5 portrait cropped square, high, as the About card crops it: the whole head in. */
.profile__img{display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 22%}
/* No photograph yet: the short name in paper on the ink, sized by the square as the About
   card sizes it (118cqi shared by its letters, two letters at most 38cqi). */
.profile__portrait.is-initials{display:grid;place-items:center;container-type:inline-size}
.profile__initials{font-family:var(--font-display);font-size:min(38cqi, 118cqi / var(--chars, 2));line-height:1;letter-spacing:-.04em;color:var(--paper)}
/* The words are the container the name is sized against, so its longest word always
   fits its column: 16cqi keeps "Mileham" or "Stanley" (Archivo Black, about 4.9em) inside
   at every width, up to 7.5rem. A full name breaks onto two lines, balanced. Its floor
   gives way to 20cqi ("Mileham." is 4.36em, so 87% of the column) where a reader has
   set larger text: a fixed 2.75rem was 88px at 200%, "Mileham." 384px in a 326px
   column, and it pushed the role and the line off the screen with it (device pass,
   2026-10-27, 390 and 320). At the usual text size nothing changes. */
.profile__intro{display:grid;justify-items:start;container-type:inline-size}
.profile__name{margin:0;font-family:var(--font-display);font-weight:400;font-size:clamp(min(2.75rem, 20cqi), 16cqi, 7.5rem);line-height:.92;letter-spacing:-.035em;color:var(--ink);text-wrap:balance}
/* The stop is decoration: empty alternative text, so a screen reader reads the name only;
   a browser without that syntax drops the rule and shows no stop. */
.profile__name::after{content:"." / "";color:var(--accent)}
.section .profile__role{margin-block-start:var(--space-2);font-size:var(--fs-step);font-weight:600;line-height:1.3;color:var(--ink-soft)}
.section .profile__line{margin-block-start:var(--gap-text);max-inline-size:30ch;font-size:var(--fs-lead);font-weight:500;line-height:1.4;color:var(--ink);text-wrap:balance}
.section .profile__links{margin-block-start:var(--space-2)}
/* The way on (and LinkedIn's link): the kit's text link with its arrow, 44px tall. */
.profile__go{display:inline-flex;align-items:center;gap:.5em;min-block-size:44px;font-weight:700;color:var(--ink)}
.profile__arrow{flex:none;inline-size:1em;block-size:1em;transition:transform var(--t-hover) var(--ease-out)}
@media (hover:hover){
  .profile__go:hover .profile__arrow{transform:translateX(3px)}
}
.profile__about{display:grid;justify-items:start;gap:var(--gap-text)}
.profile .profile__about h2{font-size:var(--fs-h3);line-height:1.05}
/* A reading column: about 60 characters a line at the lead size, the first paragraph in
   ink and the rest softer, as the About page's lead is. */
.profile__bio{display:grid;gap:var(--space-2);max-inline-size:34em}
.section .profile__bio p{font-size:var(--fs-lead);font-weight:450;line-height:1.5;color:var(--ink-soft)}
.section .profile__bio p:first-child{color:var(--ink)}
.section .profile__next{margin-block-start:var(--space-1)}
.profile__next .profile__go{font-family:var(--font-display);font-weight:400;font-size:var(--fs-step);letter-spacing:-.01em}
@media (min-width: 48em){
  .profile__head{grid-column:1 / -1;grid-template-columns:subgrid;gap:var(--gutter)}
  .profile__portrait{grid-column:1 / 5;inline-size:calc(100% - var(--plate))}
  .profile__intro,.profile__about{grid-column:5 / -1;padding-inline-start:var(--gutter)}
}
@media (min-width: 64em){
  .profile__portrait{max-inline-size:26rem}
  .profile__about{grid-column:1 / -1;grid-template-columns:subgrid;align-items:start;padding-inline-start:0}
  .profile .profile__about h2{grid-column:1 / 5}
  .profile__bio,.profile__next{grid-column:5 / -1;padding-inline-start:var(--gutter)}
}
@media (prefers-reduced-motion: reduce){
  .profile__arrow{transition:none}
}

/* ==== The Our work page (Stanley, 2026-10-21). Light page, calm =================== */
/* page-our-work.php says what is where: the head, a big card per client with a case
   study (Stanley, 2026-10-22; each job in full is its own page now, assets/css/case.css),
   then Your site next? on the paper. Calm throughout (page-design.md, section 4): no
   standout. The cards arrive as a list (P2), their names rise as every heading does
   (P1), and they answer only a pointer, a press and focus. The cards slide up over the
   head (Stanley, 2026-10-22, "the cards go over the text"): the head is the list's
   words and the cards its stack (data-stack-words, data-stack; the stack's block, What
   we do's, does it all), so "Our work" and its lead stay put under the pill while each
   card comes up over them, tilted a touch and settling; the head is a section of its
   own, hidden and let go once the first card is over it.
   Finished states first; start states only under .js (T-052); only transform and
   opacity move. */

/* The head: the <h1> large in the display face, then the lead in the offset reading
   column, as a section head is laid out (never a split header). No picture: the
   client's site is this page's picture, so the first case study starts on the first
   screen at 1440 by 900. */
.work-head{padding-block:var(--pad-s) var(--space-4)}
/* Pinned (the stack's block), the head is drawn lower than its place in the page, which
   the scroll takes on up, and hidden it leaves that place empty: there the body's ink
   showed, a strip between the bar and the head behind the pill at 375 to 768 wide, and
   a band over the cases that came at once as the head was hidden, at every width. So
   <main> carries the head's paper under it while it is pinned. */
main:has(> .work-head.is-pinned){background:var(--page)}
.work-head__inner{row-gap:var(--gap-text)}
.work-head h1{margin:0;font-family:var(--font-display);font-weight:400;font-size:var(--fs-poster);line-height:.95;letter-spacing:-.03em;text-wrap:balance}
.work-head__last{color:var(--accent)}
.work-head__lead{display:grid;gap:var(--space-2);max-inline-size:36ch;font-size:clamp(1.25rem, 1rem + 1.1vw, 2rem);font-weight:500;line-height:1.38;letter-spacing:-.01em;color:var(--ink)}
.work-head__lead p{text-wrap:balance}
.work-head__lead p+p{color:var(--ink-soft)}
@media (min-width: 48em){
  .work-head h1{grid-column:1 / 11}
  .work-head__lead{grid-column:3 / -1}
}
@media (min-width: 64em){
  .work-head h1{grid-column:1 / 9}
  .work-head__lead{grid-column:5 / 12}
}

/* The index: a big card per client, the first a small spacer's room under the head, not
   a section's (the head has just said what the page is). Each card is the kit's window
   on its magenta plate, the whole of it one link to the case study, as the closing
   pair's cards are: the top of their site straight under the tab line and edge to edge
   as a browser shows a page (the phone's capture at 4:5 below 48em, the desktop's 16:10
   from 48em, both from the top of the page, as the front page's card shows them), then
   the name in the display face, their line in the soft ink, and the way on with the
   kit's round arrow on its magenta plate (the pair's). From 64em the picture takes
   eight columns and the words stand beside it at its foot, the picture's own edge the
   only line between them (an ink rule down its side read as a coloured side stripe,
   page-design.md section 11, check-site's css-tells). A card without a capture is
   its words alone, across the window. Under a mouse the window lifts 2px further off its
   plate and the arrow steps on 3px, a press pushes it almost home, out again faster than
   in; the focus ring is the window's. Under reduced motion the states simply change. */
.work-head + .work-index{padding-block-start:var(--space-4)}
.work-index{padding-block-end:var(--pad-m)}
.work-index__list{list-style:none;margin:0;padding:0;display:grid;gap:var(--gap-head)}
.work-card{display:block;color:inherit;text-decoration:none;-webkit-tap-highlight-color:transparent}
.work-card__window{display:grid;padding:calc(var(--tab) + var(--line)) 0 0;overflow:hidden;overflow:clip;transition:transform .15s var(--ease-out)}
.work-card__screen{position:relative;aspect-ratio:4/5;overflow:hidden;overflow:clip;background:var(--slot);border-block-end:var(--line) solid var(--ink)}
.work-card__img{position:absolute;inset:0;display:block;inline-size:100%;block-size:100%;object-fit:cover;object-position:50% 0}
/* A capture still arriving (site.js marks it .is-loading, so only with the script) is
   hidden on the screen's pale ground until it is whole and decoded, as the front page's
   window is (Sam's item a, 2026-10-26): never painted in strips, or dark and blurred
   first, as its card comes up. It then comes in over 300ms where motion is allowed;
   going out it goes at once, so a capture marked mid-paint never fades out on screen. */
.work-card__img.is-loading{opacity:0}
@media (prefers-reduced-motion: no-preference){
  .work-card__img:not(.is-loading){transition:opacity .3s var(--ease-out)}
}
.work-card__about{display:grid;gap:var(--space-2);align-content:end;justify-items:start;padding:var(--win-pad)}
.work-index .work-card__name{font-size:var(--fs-h3);line-height:1;text-wrap:balance}
.work-card__line{max-inline-size:38ch;font-size:var(--fs-lead);font-weight:450;line-height:1.45;color:var(--ink-soft);text-wrap:pretty}
.work-card__go{display:inline-flex;align-items:center;gap:var(--space-2);margin-block-start:var(--space-1);font-weight:700;font-size:var(--fs-lead);line-height:1.2;color:var(--ink)}
/* Where the way on cannot keep one line beside its button (a 320 phone, 232px for its
   249), it breaks in two even halves, never "See the case / study" (device pass,
   2026-10-27). */
.work-card__go > span:first-child{text-wrap:balance}
/* At large text (device pass, 2026-10-27): at 200% on a 320 phone the card ran 51px off
   the screen, widened by "Mandy's" at the h3's 56px floor (260px), the window's 40px
   sides and the way on with its 112px button beside it (243px). The name is never past
   12vw; narrower than 20em of the reader's text the words' sides keep to 6.5vw and the
   button may drop under its words. None of it binds at 100% text. */
.work-index .work-card__name{font-size:min(var(--fs-h3), 12vw)}
@media (max-width: 19.99em){
  .work-card__about{padding-inline:min(var(--win-pad), 6.5vw)}
  .work-card__go{flex-wrap:wrap}
}
.work-card__btn{display:grid;place-items:center;box-sizing:border-box;inline-size:3.5rem;block-size:3.5rem;flex:none;color:var(--ink);background:var(--paper);border:var(--line) solid var(--ink);border-radius:50%;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.work-card__arrow{inline-size:1.25rem;block-size:1.25rem;transition:transform .15s var(--ease-out)}
@media (min-width: 48em){
  .work-card__screen{aspect-ratio:16/10}
}
@media (min-width: 64em){
  .work-card__window{grid-template-columns:repeat(12,minmax(0,1fr))}
  .work-card__screen{grid-column:1 / 9;border-block-end:0}
  .work-card__about{grid-column:9 / -1}
  .work-card--words .work-card__about{grid-column:1 / -1}
}
/* Until 80em the words take five columns and the picture seven: in four, from 1024 to
   1279 (an iPad held sideways, a small laptop), "See the case study" broke onto two
   lines beside its button ("study" alone at 1024) and the line ran to three (device
   pass, 2026-10-27). From 80em the eight and four above have room for both. */
@media (min-width: 64em) and (max-width: 79.99em){
  .work-card__screen{grid-column:1 / 8}
  .work-card__about{grid-column:8 / -1}
}
/* A phone held sideways (844 by 390, 926 by 428): stacked, the 16:10 picture alone was
   485px tall on 310 of screen under the pill, so the card was never seen whole and its
   name and way on came a screen later (device pass, 2026-10-27). There the words stand
   beside the picture, half each, and the whole card fits the screen with its way on in
   one line. Below 48em too (568 by 320, 667 by 375, 740 by 360), with the desktop's
   16:10 capture (page-our-work.php's <source>): stacked, the phone's 4:5 capture was 640
   to 845px tall there, the card 884 to 1101px on a 320 to 375px screen. */
@media (max-width: 63.99em) and (orientation: landscape) and (max-height: 40em){
  .work-card__screen{aspect-ratio:16/10}
  .work-card__window{grid-template-columns:repeat(12,minmax(0,1fr))}
  .work-card__screen{grid-column:1 / 7;border-block-end:0}
  .work-card__about{grid-column:7 / -1}
  .work-card--words .work-card__about{grid-column:1 / -1}
}
@media (hover:hover){
  .work-card:hover > .window{transform:translate(calc(var(--plate) * -1 - 2px),calc(var(--plate) * -1 - 2px));transition-duration:var(--t-state)}
  .work-card:hover .work-card__arrow{transform:translateX(3px);transition-duration:var(--t-state)}
}
.work-card:active > .window{transform:translate(-2px,-2px);transition-duration:.1s}
.work-card:focus-visible{outline:none}
.work-card:focus-visible > .window{outline:3px solid var(--focus);outline-offset:3px}
@media (prefers-reduced-motion: reduce){
  .work-card__window,.work-card__arrow{transition:none}
}

/* Your site next?: the paper band before the ink footer, the question centred over the
   closing pair (P1-49, its own block below) across the frame, as How it works ends. Two
   classes, to outrank .section h2, which zeroes the frame's auto margins too. */
.work-close{padding-block:var(--pad-m) var(--pad-l);background:var(--paper)}
.work-close .work-close__title{margin-inline:auto;text-align:center}

/* ==== The closing pair (P1-49, template-parts/closing-pair.php). Calm =============== */
/* Huge's closing pair in our kit: two windows on their magenta plates, Get in touch the
   ink one (paper words 15.98:1; its tab line and dot in paper, as the reversed symbol
   draws them, and as Our work's card backs do), the next page the white one, as every
   window on the light page is (D-3). Phone: one under the other. From 48em: side by
   side, half the frame each, as tall as each other. The label is the nav's word in the
   display face, sized by its card (a size container) so "Get in touch" keeps one line
   in any card; a card's line under it never ends on one word alone (text-wrap:pretty;
   "Meet the two you'll talk / to." at 768px without it); the arrow button sits at the
   card's foot, the kit's pill in small: paper, the ink outline, a solid magenta plate.
   The whole card is the link. Under a mouse the window lifts 2px further off its plate
   and the arrow steps on 3px, as the pills do; a press pushes it almost home; out again
   faster than in. Nothing moves on arrival, and under reduced motion the states simply
   change.
   One card alone (its partner's page not published, the part says why) keeps a column's
   width but sits in the middle of the frame, under the centred question, so the band
   never ends on half a pair with an empty right half (the polish round's skeptic,
   pair-one-card-lopsided).
   Every pair opens the same way (final review, looks-1): a question in the display face
   at a section heading's size, centred at every width, the cards a heading's gap under
   it. How it works and Our work ask theirs as the section's own h2 (.journey__end h2,
   .work-close__title); What we do and About through the pair's line, styled here to
   match, so a visitor going round the ring (D-34, D-40) meets one ending, not four. */
.pair{display:grid;gap:var(--gap-head);margin-block-start:var(--gap-head)}
/* Large text on a phone (device pass, 2026-10-27): at 200% the line's longest word at
   the heading's 80px floor ("business?" 414px on a 390 screen) widened the pair's auto
   column, and About's own column with it, so the line and both cards ran past the
   frame (to 446px at 390, 368 at 320). The column is now the frame's whatever is in it,
   and the pair is the size container that holds the line to 18% of the frame, which
   keeps "business?" (5.2em) inside it from a 320 at 200%. It never binds at 100% text:
   at 320, the narrowest frame, 18cqi is 52px, over the heading's 40. */
.pair{container-type:inline-size;grid-template-columns:minmax(0,1fr)}
.section .pair__line{font-family:var(--font-display);font-size:min(var(--fs-h2), 18cqi);line-height:.95;letter-spacing:-.03em;text-align:center;text-wrap:balance}
.pair__cards{--pair-gap:clamp(1.5rem, 1rem + 2vw, 2.5rem);list-style:none;margin:0;padding:0;display:grid;gap:var(--pair-gap)}
@media (min-width: 48em){
  .pair__cards{grid-template-columns:repeat(2,minmax(0,1fr))}
  .pair__item:only-child{grid-column:1 / -1;justify-self:center;inline-size:calc((100% - var(--pair-gap)) / 2)}
}
.pair__item{display:grid;min-inline-size:0}
.pair__card{display:block;color:inherit;text-decoration:none;-webkit-tap-highlight-color:transparent}
.pair__window{container-type:inline-size;display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"label label" "more go";align-content:space-between;column-gap:var(--space-2);row-gap:var(--space-3);block-size:100%;min-block-size:clamp(11rem, 5rem + 14vw, 20rem);transition:transform .15s var(--ease-out)}
/* The label's 1.75rem floor gives way to 28% of the card at large text (device pass,
   2026-10-27): at 200% on a 320 phone "How it" (3.2em) at 56px ran 19px past the card's
   160px of words. Never at 100% text, where 28cqi is over 1.75rem in any card wider
   than 100px. */
.pair__label{grid-area:label;font-family:var(--font-display);font-size:clamp(min(1.75rem, 28cqi), 12cqi, 4.5rem);line-height:1;letter-spacing:-.03em;text-wrap:balance}
.pair__more{grid-area:more;align-self:end;max-inline-size:32ch;font-weight:500;line-height:1.45;color:var(--ink-soft);text-wrap:pretty}
.pair__go{grid-area:go;justify-self:end;align-self:end;display:grid;place-items:center;box-sizing:border-box;inline-size:3.5rem;block-size:3.5rem;color:var(--ink);background:var(--paper);border:var(--line) solid var(--ink);border-radius:50%;box-shadow:var(--plate-sm) var(--plate-sm) 0 var(--accent)}
.pair__go svg{inline-size:1.25rem;block-size:1.25rem;transition:transform .15s var(--ease-out)}
/* Large text on a phone (device pass, 2026-10-27): beside the 3.5rem button the card's
   line had 86px at 200% on a 390 and 16px on a 320, a word a line ("Every / part, /
   in / plain / English."). With under 12rem of card, the line takes the card's width
   and the button drops to its own row under it. Never at 100% text, where the
   narrowest card (320) has 15.5rem. */
@container (inline-size < 12rem){
  .pair__more{grid-column:1 / -1}
  .pair__go{grid-row:3}
}
.pair__card--ink > .window{background:var(--ink);color:var(--text-primary)}
.pair__card--ink > .window::before{border-block-end-color:var(--text-primary)}
.pair__card--ink > .window::after{background:var(--text-primary)}
.pair__card--ink .pair__more{color:var(--text-secondary)}
@media (hover:hover){
  .pair__card:hover > .window{transform:translate(calc(var(--plate) * -1 - 2px),calc(var(--plate) * -1 - 2px));transition-duration:var(--t-state)}
  .pair__card:hover .pair__go svg{transform:translateX(3px);transition-duration:var(--t-state)}
}
.pair__card:active > .window{transform:translate(-2px,-2px);transition-duration:.1s}
.pair__card:focus-visible{outline:none}
.pair__card:focus-visible > .window{outline:3px solid var(--focus);outline-offset:3px}
@media (prefers-reduced-motion: reduce){
  .pair__window,.pair__go svg{transition:none}
}
