/* Parallax Studio shared chrome: base, header and nav, the phone menu, the footer
   title block, and the reveal system. Page composition stays in each page's own
   <style>; identity tokens come from /assets/identity/tokens.css. */

* { box-sizing: border-box; }
body { margin: 0; }
main a:not(.btn):not(.hint):not(.piece):not(.mail) {
  color: var(--ps-accent); font-weight: 500; text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--ps-accent) 35%, transparent);
}
main a:not(.btn):not(.hint):not(.piece):not(.mail):hover { text-decoration-color: var(--ps-accent); }
.wrap { max-width: 1140px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 48px); }
.grid-bg {
  background-image: linear-gradient(var(--ps-grid) 1px, transparent 1px), linear-gradient(90deg, var(--ps-grid) 1px, transparent 1px);
  background-size: 48px 48px;
}
.eyebrow { font-family: var(--ps-font-mono); font-weight: 400; font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--ps-text-label); }
.btn { display: inline-block; font-family: var(--ps-font-body); font-weight: 500; font-size: 15px; text-decoration: none; padding: 13px 24px; border: 0; background: none; cursor: pointer; color: var(--ps-text-body); }
.btn-primary { background: var(--ps-accent); color: var(--ps-on-accent); }
.btn-ghost { border: 1px solid var(--ps-text-label); color: var(--ps-text-body); font-weight: 400; }
/* Buttons answer the hand: a tint on hover where a pointer exists, a 1px press
   everywhere, and a drawn focus ring for the keyboard. Hover sits behind a
   (hover: hover) guard so touch screens never hold a stuck hover state. */
.btn { transition: background-color 120ms ease, border-color 120ms ease; }
@media (hover: hover) {
  .btn-primary:hover { background: color-mix(in srgb, var(--ps-ink) 12%, var(--ps-accent)); }
  .btn-ghost:hover { border-color: var(--ps-text-body); background: color-mix(in srgb, var(--ps-accent) 5%, transparent); }
  .menu-btn:hover, .menu-close:hover { border-color: var(--ps-text-body); color: var(--ps-text-display); }
}
.btn:active, .menu-btn:active, .menu-close:active { transform: translateY(1px); }
.btn:focus-visible, .menu-btn:focus-visible, .menu-close:focus-visible { outline: 2px solid var(--ps-accent); outline-offset: 2px; }

/* The head (Scott, 1 Sep 2026): wordmark on the left, the drawn Get in touch cell
   and the Menu cell on the right, no table hairlines at desk size. The nav itself
   lives behind Menu and opens as the blind, defined with the menus further down.
   The bar is pinned and its controls never move between states. */
header.site { position: sticky; top: 0; z-index: 30; background: var(--ps-paper); }
header.site .wrap { display: flex; justify-content: flex-start; align-items: stretch; padding-top: 0; padding-bottom: 0; }
.wordmark { display: flex; align-items: center; gap: 12px; text-decoration: none; padding: 16px 0; }
.wordmark span { font-family: var(--ps-font-display); font-weight: 600; font-size: 17px; letter-spacing: -0.01em; color: var(--ps-text-display); }
/* Get in touch is drawn, not filled: vertical accent lines only, no horizontals,
   so the cell never bleeds into a blue block sitting under the bar. */
a.bar-cta {
  margin-inline-start: auto; display: flex; align-items: center;
  font-family: var(--ps-font-mono); font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; padding: 0 22px;
  background: var(--ps-paper); color: var(--ps-accent);
  box-shadow: inset 1px 0 0 var(--ps-accent), inset -1px 0 0 var(--ps-accent);
}
a.bar-cta:focus-visible { outline: 2px solid var(--ps-accent); outline-offset: -4px; }
/* A fixed-width centred cell so Menu and Close occupy the same spot. */
.menu-btn {
  display: flex; align-items: center; justify-content: center; width: 84px;
  font-family: var(--ps-font-mono); font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--ps-text-body);
  background: none; border: 0; padding: 0; cursor: pointer;
}
@media (hover: hover) {
  a.bar-cta:hover, .menu-btn:hover { background: color-mix(in srgb, var(--ps-accent) 6%, var(--ps-paper)); }
}
/* Closed, the nav is nowhere: it is the blind at desk size and the sheet on the
   phone, both only while the menu is open. */
nav.site { display: none; }
nav.site a { text-decoration: none; }
.menu-close { display: none; }

section.band { padding: clamp(44px, 7vh, 80px) 0; border-top: 1px solid var(--ps-hairline); }
section.band h2 { font-size: clamp(26px, 3.2vw, 34px); letter-spacing: -0.02em; margin: 10px 0 0; }
.rule { height: 1px; background: var(--ps-hairline); transform-origin: left center; }

/* Interior-page grammar: the sheet's title line, numbered clauses with a mono label rail,
   and the closing action row. First drawn for About; every interior page reuses it. */
.title-line { display: flex; align-items: center; gap: 16px; font-family: var(--ps-font-mono); font-size: 10px; letter-spacing: 0.16em; color: var(--ps-text-label); }
.title-line .rule { flex: 1; }
section.clause { padding: clamp(44px, 7vh, 80px) 0; border-top: 1px solid var(--ps-hairline); }
.clause .wrap { display: grid; grid-template-columns: minmax(180px, 240px) minmax(0, 1fr); gap: clamp(28px, 6vw, 72px); align-items: center; }
.clause h2 { font-size: clamp(22px, 2.6vw, 28px); letter-spacing: -0.02em; margin: 0; }
/* Scott's rail ruling: the title centres on the body text; the number rides above it and
   plays no part in the alignment. On the phone the rail stacks and the number returns to flow. */
.clause .rail { position: relative; }
.clause .rail .eyebrow { position: absolute; bottom: calc(100% + 10px); left: 0; }
.clause .prose p { font-size: 16px; line-height: 1.7; color: var(--ps-text-muted); max-width: 36em; margin: 0 0 18px; }
.clause .prose p:last-of-type { margin-bottom: 0; }
.actions { margin-top: 26px; }
@media (max-width: 860px) {
  .clause .wrap { grid-template-columns: 1fr; gap: 18px; }
  .clause .rail .eyebrow { position: static; }
  .clause h2 { margin-top: 12px; }
}
.sheet-head { padding: clamp(36px, 7vh, 72px) 0 clamp(40px, 7vh, 76px); }
.sheet-head .title-line { margin-bottom: clamp(40px, 8vh, 80px); }
.sheet-head h1 { margin: 0; font-weight: 400; }
/* A plate that develops: hover crossfades a drawing into the real screenshot and clicks
   through; on touch (wired in site.js) the first tap reveals, the second follows. */
.shot-wrap { display: block; position: relative; }
.shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; opacity: 0; transition: opacity 320ms ease; }
.has-shot:hover .shot, .has-shot.reveal .shot, .shot-wrap:focus-visible .shot { opacity: 1; }
.fig .stamp { z-index: 2; background: var(--ps-paper); }
/* The stamp hides while the screenshot is showing. !important because each page's
   inline stamp entrance rules are more specific than anything sane written here. */
.has-shot:hover .stamp, .has-shot.reveal .stamp, .shot-wrap:focus-visible .stamp, .shot-wrap:focus-visible ~ .stamp {
  opacity: 0 !important;
  transition: opacity 200ms ease !important;
}
@media (prefers-reduced-motion: reduce) {
  .shot { transition: none; }
  .has-shot:hover .stamp, .has-shot.reveal .stamp, .shot-wrap:focus-visible .stamp, .shot-wrap:focus-visible ~ .stamp { transition: none !important; }
}

/* A disclosure: a drawn line the reader can open. Work's thinking passages and the FAQ. */
details.disc { border-top: 1px solid var(--ps-hairline); }
details.disc:last-of-type { border-bottom: 1px solid var(--ps-hairline); }
details.disc summary {
  list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px; padding: 14px 0;
}
details.disc summary::-webkit-details-marker { display: none; }
details.disc summary::after {
  content: "+"; font-family: var(--ps-font-mono); font-size: 14px; color: var(--ps-accent); flex: none;
}
details.disc[open] summary::after { content: "\2212"; }
details.disc .disc-body { padding: 2px 0 18px; }
details.disc .disc-body p { font-size: 15px; line-height: 1.7; color: var(--ps-text-muted); max-width: 36em; margin: 0 0 12px; }
details.disc .disc-body p:last-child { margin-bottom: 0; }

/* The one cyanotype statement a page may carry. Always gridded: add .grid-bg. */
.strip { padding: clamp(56px, 10vh, 104px) 0; position: relative; }
.strip .line { font-family: var(--ps-font-display); font-weight: 600; font-size: clamp(24px, 3.4vw, 38px); line-height: 1.3; letter-spacing: -0.01em; color: var(--ps-text-display); max-width: 21em; margin: 0; }
.strip .mark { position: absolute; right: clamp(20px, 5vw, 48px); bottom: 24px; width: 30px; height: 30px; opacity: 0.85; }

/* Below the fold, content inks in as it arrives. */
[data-ink] { opacity: 0; }
html.d1 [data-ink].inked-el { opacity: 1; transition: opacity 480ms ease var(--d, 0ms); }
[data-ink="rise"] { transform: translateY(12px); }
html.d1 [data-ink="rise"].inked-el { transform: none; transition: opacity 520ms ease var(--d, 0ms), transform 560ms cubic-bezier(0.2, 0, 0, 1) var(--d, 0ms); }
html:not(.d1) [data-ink] { opacity: 1; transform: none; filter: none; }

/* Device 1: line-work draws in. */
html.d1 .draw-stroke path, html.d1 .draw-stroke line, html.d1 .draw-stroke rect, html.d1 .draw-stroke polygon, html.d1 .draw-stroke circle {
  stroke-dasharray: var(--len, 600); stroke-dashoffset: var(--len, 600);
  fill-opacity: 0; transition: none;
}
html.d1 .draw-stroke.drawn path, html.d1 .draw-stroke.drawn line, html.d1 .draw-stroke.drawn rect, html.d1 .draw-stroke.drawn polygon, html.d1 .draw-stroke.drawn circle {
  stroke-dashoffset: 0; fill-opacity: 1;
  transition: stroke-dashoffset 1100ms cubic-bezier(0.2, 0, 0, 1) var(--d, 0ms), fill-opacity 500ms ease var(--fd, 900ms);
}
html.d1 .draw-stroke text { opacity: 0; }
html.d1 .draw-stroke.drawn text { opacity: 1; transition: opacity 500ms ease var(--fd, 900ms); }
html.d1 .rule { transform: scaleX(0); }
html.d1 .rule.drawn { transform: scaleX(1); transition: transform 900ms cubic-bezier(0.2, 0, 0, 1); }
@media (prefers-reduced-motion: reduce) {
  [data-ink] { opacity: 1; transform: none; }
  html.d1 .draw-stroke path, html.d1 .draw-stroke line, html.d1 .draw-stroke rect, html.d1 .draw-stroke polygon, html.d1 .draw-stroke circle { stroke-dashoffset: 0; fill-opacity: 1; }
  html.d1 .draw-stroke text { opacity: 1; }
  html.d1 .rule { transform: scaleX(1); }
}

/* The footer is the sheet's title block. */
footer.site .wrap { display: grid; grid-template-columns: auto 1fr auto; gap: 0; padding-top: 0; padding-bottom: 0; }
footer.site .cell { padding: 20px 22px; border-inline-start: 1px solid var(--ps-hairline); align-self: stretch; display: flex; align-items: center; }
footer.site .cell:first-child { border-inline-start: 0; padding-inline-start: 0; }
footer.site .cell:last-child { border-inline-end: 0; justify-content: flex-end; }
footer.site { border-top: 1px solid var(--ps-hairline); background: var(--ps-paper); position: relative; z-index: 1; }
footer.site .wrap { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-top: 22px; padding-bottom: 26px; }
footer.site div { font-family: var(--ps-font-mono); font-size: 10px; letter-spacing: 0.16em; color: var(--ps-text-label); }
footer.site a { color: var(--ps-text-label); }
footer.site .cell .sep { margin: 0 12px; }

/* The phone menu: the same blind as the desk (Scott, 1 Sep 2026), the index
   right-aligned within thumb reach and printed on the sheet, no row rules, with
   the sheet's own Close and Get in touch at the bottom. Opens at 00 Home. */
@keyframes nav-rise { to { opacity: 1; transform: none; } }
@keyframes sheet-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes sheet-out { to { opacity: 0; } }
nav.site a.btn-primary:focus-visible { outline-color: var(--ps-on-accent); }
@media (max-width: 860px) {
  .menu-close {
    font-family: var(--ps-font-mono); font-size: 11px; letter-spacing: 0.2em;
    text-transform: uppercase; color: var(--ps-text-body); background: none;
    border: 1px solid var(--ps-text-label); padding: 11px 16px; cursor: pointer;
  }
  /* The phone bar keeps its settled ruled cells. */
  .menu-btn {
    width: auto; justify-content: flex-start; font-size: 11px; letter-spacing: 0.2em;
    border-inline-start: 1px solid var(--ps-hairline);
    padding: 0 0 0 18px; margin-inline-start: auto;
  }
  .wordmark { padding: 14px 18px 14px 0; border-inline-end: 1px solid var(--ps-hairline); }
  header.site { z-index: 9; border-bottom: 1px solid var(--ps-hairline); }
  a.bar-cta { display: none; }
  body.menu-open { overflow: hidden; }
  body.menu-open nav.site {
    display: flex; position: fixed; inset: 0; z-index: 10; background: var(--ps-paper);
    flex-direction: column; justify-content: flex-end; align-items: stretch; gap: 0;
    padding: 96px clamp(20px, 5vw, 48px) calc(24px + env(safe-area-inset-bottom));
    counter-reset: sheet-nav -1;
    animation: sheet-blind-in 1400ms cubic-bezier(0.2, 0, 0, 1) both;
  }
  body.menu-closing nav.site { animation: sheet-blind-out 900ms cubic-bezier(0.2, 0, 0, 1) both; }
  /* The way out lives in the sheet itself, where the Menu button was. */
  body.menu-open .menu-close { display: inline-block; position: absolute; top: 21px; right: clamp(20px, 5vw, 48px); }
  body.menu-open nav.site a:not(.btn) {
    counter-increment: sheet-nav;
    display: flex; align-items: baseline; gap: 14px; justify-content: flex-end;
    font-family: var(--ps-font-display); font-weight: 600; font-size: clamp(28px, 7.5vw, 34px);
    letter-spacing: -0.02em; color: var(--ps-text-display);
    padding: 16px 0;
  }
  body.menu-open nav.site a:not(.btn)::before {
    content: "0" counter(sheet-nav);
    font-family: var(--ps-font-mono); font-weight: 400; font-size: 10px;
    letter-spacing: 0.16em; color: var(--ps-text-label);
  }
  body.menu-open nav.site a.btn-primary {
    margin-top: 24px; width: 100%; text-align: center; font-size: 15px; padding: 15px 24px;
    font-family: var(--ps-font-mono); letter-spacing: 0.16em; text-transform: uppercase;
  }
}

/* The desk menu: a blind pulled down (Scott's construction, 1 Sep 2026). The bar
   stays the topmost layer with its controls fixed in place; the sheet slides down
   from above with the index already printed on it, riding as one object. The rows
   carry no rules; the highlight arrives on hover. Menu reads Close while it is
   down (site.js swaps the label) and shares Get in touch's vertical line. */
@media (min-width: 861px) {
  body.menu-open { overflow: hidden; }
  body.menu-open .wordmark, body.menu-open a.bar-cta, body.menu-open .menu-btn { position: relative; z-index: 40; }
  /* The nav is markup-inside the header, so the blind shares the header's stacking
     context: an opaque cover over the bar area, above the sheet and below the
     controls, makes the blind emerge from the bar's underside. */
  body.menu-open header.site::before { content: ""; position: absolute; inset: 0; background: var(--ps-paper); z-index: 35; }
  body.menu-open .menu-btn { color: var(--ps-text-display); box-shadow: inset -1px 0 0 var(--ps-accent); }
  body.menu-open nav.site {
    display: flex; position: fixed; inset: 0; z-index: 20; background: var(--ps-paper);
    flex-direction: column; justify-content: flex-end; align-items: stretch; gap: 0;
    padding: 96px calc(max((100% - 1140px) / 2, 0px) + clamp(20px, 5vw, 48px)) 36px;
    counter-reset: sheet-nav -1;
    animation: sheet-blind-in 1400ms cubic-bezier(0.2, 0, 0, 1) both;
  }
  body.menu-closing nav.site { animation: sheet-blind-out 900ms cubic-bezier(0.2, 0, 0, 1) both; }
  body.menu-open nav.site a:not(.btn) {
    counter-increment: sheet-nav;
    display: flex; align-items: baseline; gap: 16px; justify-content: flex-end;
    font-family: var(--ps-font-display); font-weight: 600;
    font-size: clamp(30px, 3.6vw, 52px); letter-spacing: -0.02em;
    color: var(--ps-text-display); padding: 18px 0;
  }
  body.menu-open nav.site a:not(.btn)::before {
    content: "0" counter(sheet-nav);
    font-family: var(--ps-font-mono); font-weight: 400; font-size: 10px;
    letter-spacing: 0.16em; color: var(--ps-text-label);
  }
  /* Get in touch lives in the bar at desk size, not on the blind. */
  body.menu-open nav.site a.btn-primary { display: none; }
}
@media (min-width: 861px) and (hover: hover) {
  body.menu-open nav.site a:not(.btn):hover {
    background: color-mix(in srgb, var(--ps-accent) 5%, transparent);
    color: var(--ps-accent);
  }
}
@keyframes sheet-blind-in { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes sheet-blind-out { from { transform: translateY(0); } to { transform: translateY(-100%); } }

@media (prefers-reduced-motion: reduce) {
  body.menu-open nav.site, body.menu-closing nav.site { animation: none; transform: none; }
  body.menu-open nav.site a { animation: none; opacity: 1; transform: none; }
}

/* A picked menu item leaves the blind down, and on browsers with cross-document
   view transitions the old page crossfades into the new one. Elsewhere it is a
   plain navigation. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* Phone footer: the title block stacks, keeping its dividing lines. */
@media (max-width: 860px) {
  footer.site .wrap { flex-direction: column; align-items: stretch; gap: 0; }
  footer.site .cell { border-inline-start: 0; border-top: 1px solid var(--ps-hairline); padding: 12px 0; }
  footer.site .cell:first-child { border-top: 0; }
  footer.site .cell:last-child { justify-content: flex-start; }
  footer.site .cell:last-child { flex-wrap: wrap; gap: 8px 16px; }
  /* Each footer link is a real tap target on the phone: 24px tall, with room around it. */
  footer.site .cell a { display: inline-block; padding: 7px 0; line-height: 1; }
  footer.site .cell .sep { display: none; }
}
