/*
  15 — Pages · the site's styles, shared by page.html (landing) and
  case.html (a project's page). Started as a copy of 14 — System's page.css.

  Every spacing and type value worth tuning is a custom property in the
  first :root block; redline.html moves them live and hands the changes
  back against these names.

  Layout system
  - Structures 6–8 (round eighteen): Company left (company in a 96px
    column, projects beside it), Ruled (the same with hairlines between
    groups), Index (one even list, company at each row's far end).
  - One left edge. Name, bio, link, section labels, company names, contact,
    and footer all start at x = 0. Projects sit one step in, at 16px; with
    years, everything after the year column starts at 60px (48 + 12).
  - Hover fields extend 8px past the text on both sides, into the gutter,
    so the text itself never moves off the edge.
  - Text runs the full content width (round thirteen) — no measure caps.
  - Vertical scale: 4 · 8 · 12 · 16 · 24 · 32 · 48 · 64 · 96 · 128 (12 and 128
    added from Ben's redline, 2026-10-13; 4 from his list redline the same
    day — row padding and the gap under a company name; 48 in round fifteen).
    Under a company name 4 (round sixteen; was a one-off 6). Paragraphs 12 apart; groups 16;
    sections 64; contact → footer 128; 64 above the name and 64 under the
    header on desktop (48 and 64 on phones). Label to content 12. Content
    column 560; screens' corners 12. A project's page (round twenty-one):
    24 from the name to the paragraph, 32 to the figures, 48 to the first
    screen, 16 between screens.
*/

:root {
  /* page */
  --page-w: 560px;      /* content column — Ben's redline 2026-10-14 (a width, not on the spacing scale) */
  --gutter: 24px;       /* window edge → text, whenever the window is narrower than the column — Ben, 2026-10-14 (was 16) */
  --page-top: 96px;     /* window top → name — Ben's redline 2026-10-20 (was 64) */
  --head-gap: 16px;     /* name → Get in touch, across the name's line */
  --title-gap: 4px;     /* name → title on the line below — Ben's redline 2026-10-20 (was 0) */
  --bio-top: 64px;      /* header → bio — Ben's redline 2026-10-14 (was 48) */
  --para-gap: 12px;     /* bio paragraph → paragraph */
  --section-gap: 64px;  /* between sections — Ben, 2026-10-14 (was 48) */
  --label-gap: 4px;     /* section label → its content — back to 4, Ben's redline 2026-10-21 (12 for a round that day) */
  --cv-label-gap: 12px; /* résumé: Experience label → its first entry — Ben, 2026-10-22 (Education keeps 4) */
  --work-label-gap: 4px;  /* Projects label → its first row: 8 between the line boxes with the row's 4 — Ben, 2026-10-22 (12 earlier that day) */
  --foot-top: 128px;     /* last section (Connect) → footer */
  --foot-gap: 16px;     /* between footer links */
  /* list */
  --row-pad: 4px;       /* above and below each row's text — Ben's redline 2026-10-13; desktop (Ben, 2026-10-22) */
  --row-pad-phone: 6px; /* the same on phones — Ben, 2026-10-22 (off the spacing scale, at his request) */
  --group-gap: 4px;     /* last project → next company: 12 between the line boxes with the rows' 4 + 4 — Ben, 2026-10-22 (was 8) */
  --co-pad-b: 4px;      /* under a company name (its projects' own 4 follows) — Ben's redline 2026-10-14 */
  --indent: 16px;       /* company → project */
  --co-col: 96px;       /* Company left / Ruled: the company column — projects start here */
  --rule-gap: 12px;     /* Ruled: hairline → the rows on either side of it */
  --nd-gap: 8px;        /* project title → description */
  --mk-size: 12px;      /* open / close indicator */
  --mk-x: 0px;          /* Icon left: indicator's inset from the company edge */
  /* a project's page (15 — Pages; round twenty-one: intro → figures → screens) */
  --case-top: 64px;     /* header (Back · Previous / Next) → project name */
  --case-words: 24px;   /* project name and company → paragraph */
  --case-co-gap: 4px;   /* company ↔ project name — 4, like a section label → its text (Ben, 2026-10-22; was 0) */
  --fig-gap: 0px;       /* figure ↔ its label — back to 0, Ben's redline 2026-10-22 (4 for a round that day) */
  --stats-top: 32px;    /* paragraph → figures */
  --stats-gap: 48px;    /* figure → figure, across — Ben's redline 2026-10-20 (was 40) */
  --link-top: 24px;     /* paragraph → a link out (App Store) */
  --detail-gap: 12px;   /* role · team · time on its own line → paragraph, or figures → it — Ben's redline 2026-10-21 (was 24) */
  --gallery-top: 48px;  /* figures (or the paragraph) → the first screen */
  --case-end: 48px;     /* last frame → Close · Previous / Next again — Ben, 2026-10-21 */
  --shot-gap: 16px;     /* frame → frame */
  --shot-radius: 12px;  /* a frame's corners */
  /* inside a frame (Ben, 2026-10-21): 24 above the screens, 24 between
     them and the label, 24 under the label. The screens keep one height
     (what a 4:3 frame left them at 24/12/24) and the frame grows around
     them, so these three move the frame's edges, not the screens. */
  --frame-top: 24px;    /* frame top → screens */
  --frame-side: 24px;   /* frame side → screens, at the least — Ben, 2026-10-21; the screens shrink to keep it */
  --screen-gap: 24px;   /* screen → screen inside a frame — Ben, 2026-10-21 (was 3.5% of the frame) */
  --cap-top: 16px;      /* screens → label — Ben's redline 2026-10-21 (was 24) */
  --cap-bot: 24px;      /* label → frame foot */
  --cap-fs: 11px;       /* label size */
  --cap-lh: 14px;       /* label line */
  --cv-gap: 24px;       /* résumé: entry → entry */
  /* a project opened in place (?po=place — Ben, 2026-10-21, a test) */
  --open-top: 12px;     /* the row → its words */
  --strip-top: 32px;    /* the words (or figures) → the row of screens */
  --strip-gap: 12px;    /* frame → frame, across — Ben's redline 2026-10-21 (was 24); 24 or 8 from the Workbench (?fg) */
  --open-bot: 48px;     /* the screens → the next row */
  /* type styles — size, line height, tracking (% of the size). Font and
     weight sit with the usage map on .pg below, because the Regular weight
     follows the theme (400 light, 350 dark) and has to resolve where the
     theme is set.
     The system (round eighteen, Ben's pick): two weights — Medium only for
     the name and section labels, everything else Regular; one tracking for
     all 14px text, −0.5% (Inter's optical value at 14 is −0.6; the
     redline steps by .5); colour carries importance — Highlight for names
     and links, Ink for reading text and figures, Mute for context. Body
     medium (600) is gone; Label is the one Medium style. */
  --body-fs: 14px;  --body-lh: 1.5;   --body-ls: -.5;  /* Body */
  --label-fs: 14px; --label-lh: 1.5;  --label-ls: -.5; /* Label */
  --mono-fs: 12px;  --mono-lh: 1.4;   --mono-ls: 0;    /* Mono */
}

[data-fg="24"] { --strip-gap: 24px; }
/* row padding from the Workbench (?rp=, Ben 2026-10-21) — rows 8px / 16px
   taller than now (29 → 37 / 45 on desktop, 32 → 40 / 48 on phones) */
:root[data-rp="8"] { --row-pad: 8px; }
:root[data-rp="6"] { --row-pad: 6px; }
[data-fg="8"] { --strip-gap: 8px; }

:root {
  --bg: #FBFAF7; --hi: #121210; --ink: #5D5B54; --mute: #8F8C84; --faint: #C9C6BE;
  --rule: rgba(20,18,10,.12); --line: rgba(20,18,10,.22); --hover: rgba(20,18,10,.035);
  --stage: #EFEDE8; --stage-hover: #E7E5DF; --track: rgba(20,18,10,.10); --sel: rgba(20,18,10,.10);
  --body-w: 400; --mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --inter: "Inter", -apple-system, system-ui, sans-serif;
  color-scheme: light;
}
/* dark: the frames' ground (--stage) a step lighter, #1E1E23 (Ben,
   2026-10-22; was #131316) — Phantom's dark screens had melted into it.
   Everything on that ground follows: frames, row hover, viewer buttons. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #09090B; --hi: #F7F8F8; --ink: rgba(255,255,255,.68); --mute: rgba(255,255,255,.40);
    --faint: rgba(255,255,255,.22); --rule: rgba(255,255,255,.10); --line: rgba(255,255,255,.28); --hover: rgba(255,255,255,.04);
    --stage: #1E1E23; --stage-hover: #25252A; --track: rgba(255,255,255,.12); --sel: rgba(255,255,255,.16); --body-w: 400; color-scheme: dark;
  }
}
:root[data-theme="dark"], .pg.dk {
  --bg: #09090B; --hi: #F7F8F8; --ink: rgba(255,255,255,.68); --mute: rgba(255,255,255,.40);
  --faint: rgba(255,255,255,.22); --rule: rgba(255,255,255,.10); --line: rgba(255,255,255,.28); --hover: rgba(255,255,255,.04);
  --stage: #1E1E23; --stage-hover: #25252A; --track: rgba(255,255,255,.12); --sel: rgba(255,255,255,.16); --body-w: 400; color-scheme: dark;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Type: three shared styles (Figure went in round twenty-one), and every kind of text on the page mapped to
   one of them plus a colour. redline.html rewrites the font / weight and
   the usage map on .pg itself, so these resolve against the theme there. */
.pg {
  --body-ff: var(--inter);  --body-fw: var(--body-w);
  --label-ff: var(--inter); --label-fw: 500;
  --mono-ff: var(--mono);   --mono-fw: 400;
  --body-font:  var(--body-fw)  var(--body-fs)/var(--body-lh)   var(--body-ff);
  --label-font: var(--label-fw) var(--label-fs)/var(--label-lh) var(--label-ff);
  --mono-font:  var(--mono-fw)  var(--mono-fs)/var(--mono-lh)   var(--mono-ff);

  /* usage → style + colour */
  --name-font: var(--label-font);  --name-ls: var(--label-ls);  --name-c: var(--hi);     /* name */
  --title-font: var(--body-font);  --title-ls: var(--body-ls);  --title-c: var(--mute);  /* title beside it — Mute, Ben's redline 2026-10-21 (Ink for a round); also the company over a project's name */
  --summary-font: var(--body-font); --summary-ls: var(--body-ls); --summary-c: var(--ink); /* résumé summary under the name — its own style, Ink (Ben, 2026-10-22; it shared the title's Mute) */
  --detail-font: var(--body-font); --detail-ls: var(--body-ls); --detail-c: var(--mute);  /* a project's year · duration line — its own style, Mute (Ben, 2026-10-22; it shared the title's) */
  --cta-font: var(--body-font);    --cta-ls: var(--body-ls);    --cta-c: var(--ink);     /* Message me, Download — Ink like every text link (Ben, 2026-10-21; was Highlight) */
  --label-u-font: var(--label-font); --label-u-ls: var(--label-ls); --label-u-c: var(--hi);   /* section labels */
  --text-font: var(--body-font);   --text-ls: var(--body-ls);   --text-c: var(--ink);    /* bio, row paragraph, contact */
  --co-font: var(--body-font);     --co-ls: var(--body-ls);     --co-c: var(--mute);     /* company name */
  --proj-font: var(--body-font);   --proj-ls: var(--body-ls);   --proj-c: var(--hi);     /* project name */
  --desc-font: var(--body-font);   --desc-ls: var(--body-ls);   --desc-c: var(--mute);   /* project description */
  --fig-u-font: var(--body-font);  --fig-u-ls: var(--body-ls);  --fig-u-c: var(--hi);    /* figure — Body in Highlight (Ben's redline 2026-10-20; was Label) */
  --cap-font: var(--body-font);    --cap-ls: var(--body-ls);    --cap-c: var(--mute);    /* figure caption */
  --email-font: var(--body-font);  --email-ls: var(--body-ls);  --email-c: var(--ink);   /* contact email — Ben's redline 2026-10-21 (was Highlight) */
  --foot-font: var(--body-font);   --foot-ls: var(--body-ls);   --foot-c: var(--mute);   /* footer */
  --yr-font: var(--body-font);     --yr-ls: var(--body-ls);     --yr-c: var(--mute);     /* years */
  --cvco-font: var(--body-font);   --cvco-ls: var(--body-ls);   --cvco-c: var(--hi);     /* résumé company */
  --cvrole-font: var(--body-font); --cvrole-ls: var(--body-ls); --cvrole-c: var(--mute); /* résumé job title, and the dot before it — Mute, Ben 2026-10-21 (was Ink) */
  /* one line of a project title — centres the indicator and ends the guide line */
  --proj-line: calc(var(--body-fs) * var(--body-lh));

  background: var(--bg); color: var(--text-c);
  font: var(--body-font); letter-spacing: calc(var(--body-ls) * .01em);
  -webkit-font-smoothing: antialiased; font-feature-settings: "cv11", "ss01";
  transition: background-color .3s, color .3s;
}
/* the page's own background reaches the window's foot on short pages (a
   project page with no screens yet) — body only, so the redline's drawing
   keeps the device's height */
body.pg { min-height: 100vh; }
.pg ::selection { background: var(--sel); color: var(--hi); }
.pg a { color: inherit; text-decoration: none; }
.pg button { font: inherit; color: inherit; }

.page { width: min(100% - 2 * var(--gutter), var(--page-w)); margin: 0 auto; padding: var(--page-top) 0 40px; }

/* the name on its own line, the title beneath it, Get in touch at the far
   end of the name's line (15 — Pages; the title used to sit beside the name) */
.page header.site-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--head-gap); row-gap: var(--title-gap); align-items: baseline; }
.site-head .name { grid-area: 1 / 1; }
.site-head .role { grid-area: 2 / 1; }
.site-head .cta { grid-area: 1 / 2; }
.name { margin: 0; font: var(--name-font); color: var(--name-c); letter-spacing: calc(var(--name-ls) * .01em); }
/* the landing page's name one weight up, Semibold (Ben, 2026-10-22) — the
   name only; project names, the résumé's name and section labels stay Medium */
.site-head .name { font-weight: 600; }
.role { margin: 0; font: var(--title-font); color: var(--title-c); letter-spacing: calc(var(--title-ls) * .01em); }

/* project pages and the résumé: 12 less above the Close · Previous / Next
   row, so the icons (16 in a 40 target) top-align with the landing page's
   name (Ben, 2026-10-22); 36 on phones */
.page:has(> header.case-head:first-child) { padding-top: calc(var(--page-top) - 12px); }

.page section.about { margin-top: var(--bio-top); }
.bio p, .words, .contact p { font: var(--text-font); color: var(--text-c); letter-spacing: calc(var(--text-ls) * .01em); }
.bio p { margin: 0; text-wrap: wrap; }   /* plain wrapping (Ben, 2026-10-21): Safari's "pretty" evened out every line, pulling words down that fit */
.bio a.co { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; text-decoration-color: var(--line); transition: color .2s, text-decoration-color .2s; }
/* every text link — Message me, the companies, the email, the App Store
   links, Download — rests in Ink over a hairline and comes up to
   Highlight, underline and all, on hover (Ben, 2026-10-21) */
.pg .cta:hover, .pg a.ul:hover, .bio a.co:hover { color: var(--hi); text-decoration-color: currentColor; }
.bio p + p { margin-top: var(--para-gap); }

/* Get in touch — an underlined text link at the far end of the name's
   line (round fourteen; it was a section below About) */
.pg .cta {
  font: var(--cta-font); color: var(--cta-c); letter-spacing: calc(var(--cta-ls) * .01em);
  text-decoration: underline; text-decoration-color: var(--line);
  text-decoration-thickness: 1px; text-underline-offset: 4px;
  transition: color .2s, text-decoration-color .2s;
}

.page section { margin-top: var(--section-gap); }
.page h2 { margin: 0 0 var(--label-gap); font: var(--label-u-font); color: var(--label-u-c); letter-spacing: calc(var(--label-u-ls) * .01em); }
.page section.work > h2 { margin-bottom: var(--work-label-gap); }
.page section.cv-lead > h2 { margin-bottom: var(--cv-label-gap); }

/* ---------------------------------------------------------------- */
/* rows                                                              */

.row { display: grid; grid-template-columns: 48px minmax(0, 1fr); column-gap: 12px; transition: opacity .3s; }
.yr { font: var(--yr-font); color: var(--yr-c); letter-spacing: calc(var(--yr-ls) * .01em); font-variant-numeric: tabular-nums; padding-top: var(--row-pad); }
.yr.blank { visibility: hidden; }
.cell { min-width: 0; position: relative; }
.head {
  position: relative; isolation: isolate;
  display: flex; align-items: baseline; gap: var(--nd-gap); width: 100%; padding: var(--row-pad) 0; margin: 0;
  background: none; border: 0; text-align: left; min-width: 0;
}
a.head, button.head { cursor: pointer; }
a.head:focus-visible, button.head:focus-visible { outline: 1px solid var(--mute); outline-offset: 2px; border-radius: 2px; }
.n { white-space: nowrap; }
/* descriptions hidden — Ben, 2026-10-13; the words stay in content.js */
.d { display: none; font: var(--desc-font); color: var(--desc-c); letter-spacing: calc(var(--desc-ls) * .01em); flex: 1; min-width: 0; text-wrap: pretty; transition: color .2s; }

/* hover — a faint field behind the row, and the words come up a step */
a.head::after, button.head::after {
  content: ""; position: absolute; z-index: -1; inset: 0 -8px; border-radius: 6px;
  background: var(--stage); opacity: 0; transition: opacity .2s;   /* the frames' ground (Ben, 2026-10-21; was the fainter --hover) */
}
a.head:hover::after, button.head:hover::after { opacity: 1; }
a.head:hover .d, button.head:hover .d { color: var(--ink); }

/* the open / close indicator — see ICONS in content.js. .mk is the box
   (and the mask for the masked entrance); .mki inside it is what moves. */
.mk {
  flex: none; order: 3; margin-left: auto; align-self: center;
  width: var(--mk-size); height: var(--mk-size); color: var(--mute); transition: color .2s;
}
.mki { display: block; width: 100%; height: 100%; }
.mk svg { display: block; width: 100%; height: 100%; overflow: visible; }
a.head:hover .mk, button.head:hover .mk { color: var(--hi); }

/* Nested — company is a name; projects beneath it on a guide line */
.row.co-row { padding-top: var(--group-gap); }
.list > .row.co-row:first-child { padding-top: 0; }
.co-row .head { padding-bottom: var(--co-pad-b); }
.co-row .n { font: var(--co-font); color: var(--co-c); letter-spacing: calc(var(--co-ls) * .01em); }  /* company Body in mute, project Body in highlight — round eighteen */
.row.proj .cell { padding-left: var(--indent); }
/* the line sits on the company's left edge and runs through opened rows;
   the last one stops at the middle of its project's first line */
.row.proj .cell::before { content: ""; position: absolute; left: 1px; top: 0; bottom: 0; width: 1px; background: var(--rule); }
.row.proj.last .cell::before { bottom: auto; height: calc(var(--row-pad) + var(--proj-line) / 2); }
.row.proj .n { font: var(--proj-font); color: var(--proj-c); letter-spacing: calc(var(--proj-ls) * .01em); }
/* the company name repeated on each project row — Index only */
.c { display: none; flex: none; white-space: nowrap; font: var(--co-font); color: var(--co-c); letter-spacing: calc(var(--co-ls) * .01em); }

/* no years */
[data-v="2"] .row, [data-v="3"] .row, [data-v="5"] .row { grid-template-columns: minmax(0, 1fr); }
[data-v="2"] .yr, [data-v="3"] .yr, [data-v="5"] .yr { display: none; }
/* no lines — the indent alone carries the hierarchy */
[data-v="3"] .row.proj .cell::before, [data-v="5"] .row.proj .cell::before { display: none; }
/* flush — no lines and no indent: company and project share one edge;
   weight and tone alone tell them apart */
[data-v="4"] .row { grid-template-columns: minmax(0, 1fr); }
[data-v="4"] .yr, [data-v="4"] .row.proj .cell::before { display: none; }
[data-v="4"] .row.proj .cell { padding-left: 0; }
/* icon left — No lines, with the indicator hanging in the indent, on the
   company's edge, centred on the title's first line */
[data-v="5"] .mk {
  position: absolute; margin: 0;
  left: calc(var(--mk-x) - var(--indent));
  top: calc(var(--row-pad) + var(--proj-line) / 2 - var(--mk-size) / 2);
}
[data-v="5"] a.head::after, [data-v="5"] button.head::after { left: calc(var(--mk-x) - var(--indent) - 8px); }

/* round eighteen — three structures, all with no years and no guide lines */
[data-v="6"] .row, [data-v="7"] .row, [data-v="8"] .row { grid-template-columns: minmax(0, 1fr); }
[data-v="6"] .yr, [data-v="7"] .yr, [data-v="8"] .yr,
[data-v="6"] .row.proj .cell::before, [data-v="7"] .row.proj .cell::before, [data-v="8"] .row.proj .cell::before { display: none; }
/* company left — the company sits in a left column, level with its first
   project; projects run down the column beside it. The company row keeps
   only its gap above (no height), so the name hangs into the first
   project's line. */
[data-v="6"] .row.co-row, [data-v="7"] .row.co-row { height: 0; }
[data-v="6"] .co-row .head, [data-v="7"] .co-row .head { width: calc(var(--co-col) - 12px); padding-bottom: 0; }
[data-v="6"] .co-row .n, [data-v="7"] .co-row .n { white-space: normal; }
[data-v="6"] .row.proj .cell, [data-v="7"] .row.proj .cell { padding-left: var(--co-col); }
/* ruled — Company left, with a hairline across the column above each group
   and under the list */
[data-v="7"] .row.co-row { border-top: 1px solid var(--rule); padding-top: var(--rule-gap); margin-top: var(--rule-gap); }
[data-v="7"] .list > .row.co-row:first-child { padding-top: var(--rule-gap); margin-top: 0; }
[data-v="7"] .list { border-bottom: 1px solid var(--rule); padding-bottom: var(--rule-gap); }
/* index — one list of projects; a company's name sits at the far end of
   its first row only (Ben: no repeats), the indicator after it, and the
   usual gap opens between companies */
[data-v="8"] .row.co-row { display: none; }
[data-v="8"] .row.proj .cell { padding-left: 0; }
[data-v="8"] .row.proj.first { padding-top: var(--group-gap); }
[data-v="8"] .list > .row.co-row:first-child + .row.proj { padding-top: 0; }
[data-v="8"] .c { display: block; order: 2; margin-left: auto; }
[data-v="8"] .row.proj:not(.first) .c { visibility: hidden; }
[data-v="8"] .mk { order: 3; margin-left: 12px; }

/* ---------------------------------------------------------------- */
/* a project's page (15 — Pages)                                     */
/* The landing page's column and type: a header with Home on the left and
   Previous / Next at the far end, then the project name over its company —
   the same pair, in the same styles, as the name over the title. */

.case-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--head-gap); }
/* Home, Previous and Next share one style (Ben, 2026-10-20): the word in
   Highlight, its icon in Mute until hovered. Each icon sits on the side it
   points to. */
/* 2026-10-21 (Ben): the word rests in Ink (it had been meant as
   Highlight, but `.pg a` won and left it Ink) and comes up to Highlight
   with its icon on hover. Home is now Close, a text link with no mark. */
.pg .nav { display: inline-flex; align-items: center; gap: 4px; color: var(--ink); font: var(--body-font); letter-spacing: calc(var(--body-ls) * .01em); transition: color .2s; }
.nav .mk { order: 0; margin: 0; color: var(--mute); align-self: center; }   /* centred on the word, phones too (the list's phone rule had pulled it to the top) */
.pg .nav:hover, .nav:hover .mk { color: var(--hi); }
.step { display: flex; gap: var(--head-gap); margin-left: auto; }
.step .next { margin-right: -2px; }
.nav:focus-visible { outline: 1px solid var(--mute); outline-offset: 2px; border-radius: 2px; }
.page section.case-title { margin-top: var(--case-top); }
/* the résumé's summary under the name (Ben, 2026-10-22) */
.role.cv-summary { margin-top: var(--title-gap); font: var(--summary-font); color: var(--summary-c); letter-spacing: calc(var(--summary-ls) * .01em); }   /* 4 under the name, like the landing page's title (Ben, 2026-10-22) */
/* the company in mute over the project's name (Ben, 2026-10-21) */
.case-title .co-over { color: var(--mute); }
.case-title > * + * { margin-top: var(--case-co-gap); }
.stat > * + * { margin-top: var(--fig-gap); }
.page section.case-body { margin-top: var(--case-words); }
/* icons instead of words (Ben, 2026-10-21) — 16px icons in a 40px
   target. Bare icons hang into the margin so the icon itself keeps the
   column's edge; circles, rings and the pill sit on the edge. */
.case-head:has(.nav.ic) { align-items: center; }
.pg .nav.ic { width: 40px; height: 40px; display: inline-grid; place-items: center; gap: 0; border-radius: 999px; color: var(--ink); transition: color .2s, background-color .2s, box-shadow .2s; }
.nav.ic .nb { display: block; width: 16px; height: 16px; }
.nav.ic .nb svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pg .nav.ic:hover { color: var(--hi); }
.step.icons { gap: 8px; }
.step.icons .next { margin-right: 0; }
[data-nv="icon"] .back.ic { margin-left: -12px; }
[data-nv="icon"] .step.icons { gap: 0; margin-right: -12px; }
[data-nv="circle"] .nav.ic, [data-nv="pill"] .back.ic, [data-nv="pill"] .step.icons { background: var(--stage); }
[data-nv="circle"] .nav.ic:hover, [data-nv="pill"] .nav.ic:hover { background: var(--stage-hover); }
[data-nv="ring"] .nav.ic { box-shadow: inset 0 0 0 1px var(--line); }
[data-nv="ring"] .nav.ic:hover { box-shadow: inset 0 0 0 1px var(--mute); }
[data-nv="pill"] .step.icons { gap: 0; border-radius: 999px; }
[data-nv="pill"] .step.icons .nav.ic { width: 44px; }
/* the same row again under the last frame (Ben, 2026-10-21) */
.page .case-head.case-end { margin-top: var(--case-end); }

.words { margin: 0; text-wrap: wrap; }
/* role · team · time as its own line (Ben, 2026-10-20): above the
   paragraph, or at the bottom in the figures' place */
.detail { margin: 0; font: var(--detail-font); color: var(--detail-c); letter-spacing: calc(var(--detail-ls) * .01em); }
.detail.lead { margin-bottom: var(--detail-gap); }
.words + .detail.tail { margin-top: var(--stats-top); }
.stats + .detail.tail { margin-top: var(--detail-gap); }
/* where the line sits on a project's page (data-pd, Ben 2026-10-22) —
   under the name, 4 below it like the landing page's title; across from
   the name on its baseline; or under the paragraph, 12 below it as it
   now sits 12 above */
.detail.under { margin-top: var(--title-gap); }
.name-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--head-gap); }
.name-row .name { min-width: 0; }
.detail.beside { flex: none; }
[data-pd="tail"] .words + .detail.tail { margin-top: var(--detail-gap); }
[data-pd="tail"] .detail.tail + .stats { margin-top: var(--stats-top); }

/* figures — the same 14px as the words, the value in Medium and Highlight,
   its caption in Mute, value over caption, side by side; space alone sets
   them apart (round twenty-one; Columns, Ben's pick over Rows) */
.stats { display: flex; flex-wrap: wrap; gap: 16px var(--stats-gap); margin-top: var(--stats-top); }
.stat b { display: block; font: var(--fig-u-font); color: var(--fig-u-c); letter-spacing: calc(var(--fig-u-ls) * .01em); font-variant-numeric: tabular-nums; white-space: nowrap; }
.stat > span { display: block; font: var(--cap-font); color: var(--cap-c); letter-spacing: calc(var(--cap-ls) * .01em); max-width: 24ch; text-wrap: pretty; }

/* screens — frames one after another, the full column wide. 16 (Ben,
   2026-10-17): every frame is the same size and every screen in it the
   same height, whether it holds one, two or three (three at most). The
   screens' height is fixed against the frame's width — 3/4 of it less
   74, what a 4:3 frame with the old 24/12/24 spacing left them (Ben,
   2026-10-21: keep the screens as they are) — and the frame is that plus
   its spacing. A click anywhere on a frame opens the whole frame in the
   viewer (below). */
.gallery { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--shot-gap); margin-top: var(--gallery-top); }
/* the frame's width: the gallery's (a container here), or the column's in
   a row opened in place (--col, below) */
.gallery:not(.strip) { container-type: inline-size; }
.frame { --fw: 100cqw; }
.strip .frame { --fw: var(--col); }
.frame {
  position: relative; width: 100%; border: 0; font: inherit; color: inherit;
  /* the screens' height (--sh): as before, unless three phone screens
     (about .46 of their height wide) with 24 between them would come
     within 24 of the frame's sides — then they shrink until they don't
     (Ben, 2026-10-21). One height for every frame, so the frames stay one
     size. */
  --sh: min(var(--fw) * .75 - 74px, (var(--fw) - 2 * var(--frame-side) - 2 * var(--screen-gap)) * .72);
  padding: var(--frame-top) var(--frame-side) calc(var(--cap-top) + var(--cap-lh) + var(--cap-bot));
  display: flex; align-items: center; justify-content: center; gap: var(--screen-gap);
  height: calc(var(--sh) + var(--frame-top) + var(--cap-top) + var(--cap-lh) + var(--cap-bot));
  background: var(--stage); border-radius: var(--shot-radius); overflow: hidden;
  cursor: zoom-in; -webkit-tap-highlight-color: transparent;
}
.frame:focus-visible { outline: 1px solid var(--mute); outline-offset: 3px; }
.shot { display: block; height: 100%; flex: none; }
/* one corner for every screen: 11.5% of its width, as a true circle (the
   vertical radius is the same length expressed against a phone screen's
   height). Larger than the corners some exports have baked in (≤7%), so
   none of their backing shows. 11.5% (Ben, 2026-10-20; was 9%) because iOS’s
   keyboard in the recordings runs to the screen's edges with its own
   corner of about 11.3% — at 9% a sliver of the app showed round its
   bottom corners; at 11.5% the screen's corner fully covers it.
   ?rc=cur brings back 9% for comparison. */
.shot img, .shot video, .lb-stage img, .lb-stage video {
  display: block; height: 100%; width: auto;
  border-radius: 11.5% / 5.31%;
  box-shadow: 0 0 0 1px rgba(0,0,0,.06), 0 10px 30px -12px rgba(0,0,0,.25);
}
[data-rc="cur"] .shot img, [data-rc="cur"] .shot video, [data-rc="cur"] .lb-stage img, [data-rc="cur"] .lb-stage video { border-radius: 9% / 4.15%; }
/* smoothed corners (Ben, 2026-10-21: match Figma's 60% / iOS smoothing).
   Figma's 60% keeps the circle's depth at the diagonal but starts the
   curve 1.6× the radius along each edge. A CSS superellipse that does
   both: the radius × 1.6 with exponent 2^1.8 ≈ 3.5 (superellipse(2) at
   the same 1.6× would run about 15% shallower at the diagonal). Browsers
   without corner-shape (Safari, Firefox as of 2026-10) keep the plain
   circular corners above. */
@supports (corner-shape: superellipse(2)) {
  .frame { border-radius: calc(var(--shot-radius) * 1.6); corner-shape: superellipse(1.8); }
  .shot img, .shot video, .lb-stage img, .lb-stage video { border-radius: 18.4% / 8.5%; corner-shape: superellipse(1.8); }
  [data-rc="cur"] .shot img, [data-rc="cur"] .shot video, [data-rc="cur"] .lb-stage img, [data-rc="cur"] .lb-stage video { border-radius: 14.4% / 6.64%; }
}
/* hover — 2026-10-21 (Ben: the zoom read oddly; try treatments that leave
   the screens' size and the frame's shape alone). Decided: Ground — the
   frame's ground deepens a step. ?fh= still shows the others. Recordings take the same hover as stills.
   Pointer devices only — a tap goes straight to the viewer. */
/* Ben, 2026-10-21 (round two): slower and gentler, and the rest of the
   page steps back a little while a frame is pointed at. The settled
   selector outranks the entrance's opacity-only transition (motion.css),
   which had been making the ground change snap. */
/* the hover ground is a theme token (Ben, 2026-10-21: in dark mode the
   settled frame's light value had been winning, so it lit up) */
.frame, html .frame[data-a].settled { transition: background-color .5s cubic-bezier(.25,.1,.25,1), box-shadow .5s cubic-bezier(.25,.1,.25,1), opacity .5s cubic-bezier(.25,.1,.25,1); }
.frame .flabel, .frame .cap { transition: color .5s cubic-bezier(.25,.1,.25,1); }
/* everything that doesn't hold the frame under the pointer — the largest
   such blocks, so nothing dims twice */
.page > :not(:has(.frame:hover)), .page :has(.frame:hover) > :not(:has(.frame:hover)):not(.frame:hover) { transition: opacity .5s cubic-bezier(.25,.1,.25,1); }
.frame::after {
  content: ''; position: absolute; right: 16px; bottom: calc(var(--cap-bot) + (var(--cap-lh) - 12px) / 2); width: 12px; height: 12px; display: none;
  background: var(--mute); opacity: 0; transition: opacity .25s ease, background-color .25s ease;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='black' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8.5 1.5h4v4M12.5 1.5 8 6M5.5 12.5h-4v-4M1.5 12.5 6 8'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='black' stroke-width='1.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8.5 1.5h4v4M12.5 1.5 8 6M5.5 12.5h-4v-4M1.5 12.5 6 8'/%3E%3C/svg%3E") center / contain no-repeat;
}
[data-fh="icon"] .frame::after { display: block; }
.frame .shot img, .frame .shot video { transition: transform .4s cubic-bezier(.2,.7,.2,1); }
@media (hover: hover) {
  /* Ground — the frame's ground deepens a step and its labels come up */
  [data-fh="tint"] .frame:hover { background-color: var(--stage-hover); }
  [data-fh="tint"] .frame:hover .flabel, [data-fh="tint"] .frame:hover .cap { color: var(--ink); }
  [data-fh="tint"] .page:has(.frame:hover) > :not(:has(.frame:hover)),
  [data-fh="tint"] .page :has(.frame:hover) > :not(:has(.frame:hover)):not(.frame:hover) { opacity: .7; }
  /* Outline — a hairline traces the frame's edge */
  [data-fh="ring"] .frame:hover { box-shadow: inset 0 0 0 1px var(--line); }
  /* Dim the others — the frame under the pointer stays, the rest step back */
  [data-fh="dim"] .gallery:has(.frame:hover) .frame:not(:hover) { opacity: .45; }
  /* Expand icon — a small expand mark in the frame's corner, on the labels' line */
  [data-fh="icon"] .frame:hover::after { opacity: 1; background-color: var(--hi); }
  /* Zoom — the earlier hover, for comparison */
  [data-fh="zoom"] .frame:hover .shot img, [data-fh="zoom"] .frame:hover .shot video { transform: scale(1.01); }
}
html.lb-open .frame { opacity: 1 !important; }
/* while a frame is open full screen its screens step aside (the frame and
   its labels stay under the ground), and nothing on the page scales */
.frame.lb-src .shot img, .frame.lb-src .shot video { visibility: hidden; }
html.lb-open .frame .shot img, html.lb-open .frame .shot video { transform: none; }

/* labels (Ben, 2026-10-19; every frame 2026-10-21) — inside the frame:
   one under each screen (.cap), or one for the whole frame (.flabel),
   24 under the screens and 24 above the frame's foot; 11px, mute, normal
   tracking. Placed absolutely, so every frame's screens sit alike. */
.shot { position: relative; }
.shot .cap, .frame .flabel { position: absolute; text-align: center; white-space: nowrap; font: 400 var(--cap-fs)/var(--cap-lh) var(--body-ff); letter-spacing: 0; color: var(--mute); }
.shot .cap { top: calc(100% + var(--cap-top)); left: -40%; right: -40%; }
.frame .flabel { left: 0; right: 0; bottom: var(--cap-bot); }

.words + .words { margin-top: 12px; }
/* a link out under a project's words (the App Store links, Ben
   2026-10-20) — its own line, 24 below the words, in the figures' place;
   set like the email: highlight, hairline underline that goes solid on
   hover, the arrow after it in mute */
.out { margin: var(--link-top) 0 0; font: var(--text-font); letter-spacing: calc(var(--text-ls) * .01em); }
.out a { color: var(--email-c); }
.out .em-i { display: inline-block; width: 12px; height: 12px; vertical-align: -1px; margin-left: 8px; color: var(--mute); transition: color .2s; }
.out .em-i svg { display: block; width: 100%; height: 100%; overflow: visible; }
.out a:hover .em-i { color: var(--hi); }
.out + .stats { margin-top: var(--link-top); }

/* the underlined links — the email and the App Store links */
a.ul { text-decoration: underline; text-decoration-color: var(--line); text-decoration-thickness: 1px; text-underline-offset: 4px; transition: color .2s, text-decoration-color .2s; }

/* ---------------------------------------------------------------- */
/* a project opened in place (?po=place — Ben, 2026-10-21; a test, it may
   not stay). The row opens and closes like round 14's; the chevron turns
   down while it is open. Its words keep the project name's edge; its
   screens are one row of frames, each the full width of the column, 24
   apart, that you swipe or scroll across — the row runs out to the
   window's edges so the next frame shows past the column where there is
   room. Opened and closed by page.html. */
.mk .r { transform-box: view-box; transform-origin: 6px 6px; transition: transform .3s cubic-bezier(.2,.7,.2,1); }
.row.open .mk .r { transform: rotate(90deg); }
.row.open .mk { color: var(--hi); }
.more { grid-column: 1 / -1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 0fr; transition: grid-template-rows .45s cubic-bezier(.2,.7,.2,1); }
.more.on { grid-template-rows: 1fr; }
/* clipped top and bottom only, so the screens can run past the column */
.more-in { min-height: 0; min-width: 0; overflow-x: visible; overflow-y: clip; opacity: 0; transition: opacity .3s; }
.more.on .more-in { opacity: 1; transition-delay: .08s; }
.more-pad { padding: var(--open-top) 0 var(--open-bot); }
/* the words start where the project's name does, in every structure */
.page { --open-in: 0px; }
.page[data-v="1"] { --open-in: calc(60px + var(--indent)); }
.page[data-v="2"], .page[data-v="3"], .page[data-v="5"] { --open-in: var(--indent); }
.page[data-v="6"], .page[data-v="7"] { --open-in: var(--co-col); }
.more-words { padding-left: var(--open-in); }
.gallery.strip {
  --col: min(100cqw - 2 * var(--gutter), var(--page-w));
  --side: calc((100cqw - var(--col)) / 2);
  display: flex; gap: var(--strip-gap);
  margin: var(--strip-top) calc(0px - var(--side)) 0;
  padding: 0 var(--side);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--side);
  scrollbar-width: none;
}
.gallery.strip::-webkit-scrollbar { display: none; }
.strip .frame { flex: none; width: var(--col); scroll-snap-align: start; }

/* the viewer — the whole frame, its screens side by side as large as the
   window allows (never past their own size), on the page's ground.
   ‹ › move between frames; Escape, × or a click on the ground closes it.
   Built by site.js. */
.lb { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; cursor: zoom-out; }
.lb[hidden] { display: none; }
.lb-ground { position: absolute; inset: 0; background: var(--bg); opacity: 0; transition: opacity .28s ease; }
.lb.on .lb-ground { opacity: .97; }
.lb-stage { position: relative; display: flex; align-items: center; cursor: default; transform-origin: 0 0; }
.lb-stage > * { flex: none; }
.lb-btn { position: absolute; z-index: 1; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%; background: none; color: var(--mute); cursor: pointer; opacity: 0; transition: opacity .28s ease, color .2s, background-color .2s; }
.lb.on .lb-btn { opacity: 1; }
.lb-btn:hover { color: var(--hi); background: var(--stage); }
.lb-btn:focus-visible { outline: 1px solid var(--mute); outline-offset: -4px; }
.lb-x { top: 12px; right: 12px; }
.lb-prev, .lb-next { top: 50%; margin-top: -22px; background: var(--stage); color: var(--ink); }
.lb-prev:hover, .lb-next:hover { color: var(--hi); }
.lb-prev { left: 16px; }
.lb-next { right: 16px; }
.lb.one .lb-prev, .lb.one .lb-next { display: none; }
html.lb-open { overflow: hidden; }

/* the résumé (resume.html, Ben 2026-10-19) — the PDF's layout in this
   page's type: each entry is "Company · Role" with its years at the far
   end, over a line of copy. Company and role each have their own usage
   (the redline's Résumé companies / Résumé job titles); years are Years. Download PDF is the header's underlined link, at the far end. */
.cv-item + .cv-item { margin-top: var(--cv-gap); }
.cv-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: 16px; }
.cv-what { font: var(--cvrole-font); color: var(--cvrole-c); letter-spacing: calc(var(--cvrole-ls) * .01em); }
.cv-co { font: var(--cvco-font); color: var(--cvco-c); letter-spacing: calc(var(--cvco-ls) * .01em); }
.cv-yr { color: var(--yr-c); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* contact + footer */
.contact p { margin: 0; text-wrap: wrap; }   /* lines run the full width — Ben, 2026-10-14 (pretty wrapped early) */
.pg .contact a { font: var(--email-font); color: var(--email-c); letter-spacing: calc(var(--email-ls) * .01em); }
/* the email's icon — 12px, mute, 8 from the address; an inline-block, so
   the underline stays under the words (Ben, 2026-10-20) */
.contact .em-i { display: inline-block; width: 12px; height: 12px; vertical-align: -1px; color: var(--mute); transition: color .2s; }
.contact .em-b { margin-right: 8px; }
.contact .em-a { margin-left: 8px; }
.contact .em-i svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pg .contact a:hover .em-i { color: var(--hi); }
.page footer { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: var(--foot-top); font: var(--foot-font); color: var(--foot-c); letter-spacing: calc(var(--foot-ls) * .01em); }
.foot-l { display: flex; align-items: center; gap: var(--foot-gap); flex-wrap: wrap; }
.foot-l a { transition: color .2s; }
.foot-l a:hover { color: var(--hi); }
.theme { position: relative; display: inline-flex; padding: 2px; border: 0; cursor: pointer; border-radius: 999px; background: var(--track); }
.theme:focus-visible { outline: 1px solid var(--mute); outline-offset: 2px; }
.theme::before { content: ""; position: absolute; top: 2px; left: 2px; width: 26px; height: 22px; border-radius: 999px; background: var(--bg); box-shadow: 0 1px 2px rgba(0,0,0,.12); transition: transform .3s cubic-bezier(.2,.7,.2,1), background-color .3s; }
.theme[aria-checked="true"]::before { transform: translateX(26px); }
.theme span { position: relative; width: 26px; height: 22px; display: grid; place-items: center; color: var(--mute); transition: color .2s; }
.theme[aria-checked="false"] span.sun, .theme[aria-checked="true"] span.moon { color: var(--hi); }

/* ---------------------------------------------------------------- */

/* Phones (Ben, 2026-10-21): 16px text, 12px frame labels. A media query,
   not the container query below — the type tokens resolve on .pg itself,
   which its own container query can't reach. */
@media (max-width: 560px) {
  :root { --body-fs: 16px; --label-fs: 16px; --cap-fs: 12px; --cap-lh: 16px; }
  /* one screen to a frame (case.html splits the frames), drawn large: the
     screen as tall as 1.25× the frame's width */
  .gallery:not(.strip) .frame[data-n="1"] { --sh: calc(var(--fw) * 1.25); }
}

/* Small screens. A container query on .pg (the page's body, or the redline's
   drawing) rather than a media query, so the redline's phone-sized drawing
   gets the phone layout too — the window there is desktop-sized. */
.pg { container-type: inline-size; }
@container (max-width: 560px) {
  .page { padding-top: 48px; --row-pad: var(--row-pad-phone); }
  /* the landing page keeps its full top space on phones (Ben, 2026-10-22);
     project pages and the résumé stay at 48 */
  .page:has(> header.site-head) { padding-top: var(--page-top); }
  .page:has(> header.case-head:first-child) { padding-top: 36px; }
  .page section.about { margin-top: 64px; }
  .row { grid-template-columns: 40px minmax(0, 1fr); }
  [data-v="2"] .row, [data-v="3"] .row, [data-v="4"] .row, [data-v="5"] .row,
  [data-v="6"] .row, [data-v="7"] .row, [data-v="8"] .row { grid-template-columns: minmax(0, 1fr); }
  .head { flex-wrap: wrap; row-gap: 0; }
  .n { white-space: normal; }
  .d { flex-basis: 100%; order: 4; }
  .mk { order: 2; align-self: flex-start; margin-top: calc(var(--proj-line) / 2 - var(--mk-size) / 2); }
  [data-v="5"] .mk { margin: 0; }
  /* the list's indicators at 16 on phones (Ben, 2026-10-21; 12 on desktop),
     their lines kept at the desktop weight */
  .row .mk { --mk-size: 16px; }
  .row .mk svg { stroke-width: .9; }
  /* every other icon at 16 on phones too (Ben, 2026-10-22): the arrows by
     the email and the App Store links, and the theme switch's sun and moon */
  .contact .em-i, .out .em-i { width: 16px; height: 16px; vertical-align: -3px; }
  .contact .em-i svg, .out .em-i svg { stroke-width: .9; }
  .theme svg { width: 16px; height: 16px; }
  .theme .sun svg { stroke-width: 1.14; }   /* lines kept at their desktop weight */
  .theme .moon svg { stroke-width: 1.05; }
  [data-v="8"] .c { align-self: flex-start; }
  .lb-prev, .lb-next { top: auto; bottom: 12px; margin: 0; }
  .stats { gap: 14px 28px; }
  .cv-head { flex-direction: column; }
  .page[data-v] { --open-in: 0px; }   /* opened words take the whole column on phones */   /* years under the role on every entry, not just the long ones */
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; }
}
