/* phil.css — one stylesheet for phil's world.
   White paper, charcoal ink, graphite for pencil, and one red pencil for the register.
   Geist for the interface and figures, EB Garamond for captions and prose,
   Patrick Hand only for Phil's own handwriting on the drawings. */

@font-face { font-family: 'Geist'; font-style: normal; font-weight: 100 900; font-display: swap; src: url(/assets/geist-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Geist'; font-style: normal; font-weight: 100 900; font-display: swap; src: url(/assets/geist-latin-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Geist Mono'; font-style: normal; font-weight: 100 900; font-display: swap; src: url(/assets/geist-mono-latin.woff2) format('woff2'); }
@font-face { font-family: 'EB Garamond'; font-style: normal; font-weight: 400 800; font-display: swap; src: url(/assets/garamond-latin.woff2) format('woff2'); }
@font-face { font-family: 'EB Garamond'; font-style: italic; font-weight: 400 800; font-display: swap; src: url(/assets/garamond-italic-latin.woff2) format('woff2'); }
@font-face { font-family: 'Patrick Hand'; font-style: normal; font-weight: 400; font-display: swap; src: url(/assets/font-4.ttf) format('truetype'); }

:root {
  --paper: #ffffff;
  --ink: #1b1c18;
  --ink-2: #45463f;
  --muted: #74756e;
  --graphite: #9a9a93;
  --faint: #d6d6d0;
  --rule: #e7e7e2;
  --wash: #f5f5f2;
  --red: #bf3b28;
  --focus: #1b1c18; /* ink: the palette is ink, graphite and one red pencil, and red is never focus */

  --sans: 'Geist', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --serif: 'EB Garamond', Georgia, 'Times New Roman', serif;
  --mono: 'Geist Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --hand: 'Patrick Hand', 'Comic Sans MS', cursive;

  --max: 1360px;
  --gutter: clamp(16px, 4vw, 56px);
  --header: 64px;
  --radius: 12px;
  --ease: cubic-bezier(.2, .8, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  /* motion tokens (app.js mirrors them as PW.easing() and PW.T for WAAPI, which cannot read var()) */
  --ease-pen: cubic-bezier(.45, .05, .25, 1);   /* a stroke leaving rest and settling */
  --ease-stamp: cubic-bezier(.3, 1.5, .5, 1);   /* a stamp or a released press */
  --ease-inout: cubic-bezier(.65, 0, .25, 1);   /* travel */
  --t-press: 70ms;
  --t-out: 120ms;
  --t-hover: 200ms;
  --t-stroke: 240ms;
  --t-row: 320ms;
  --t-draw: 700ms;
  --t-scene: 900ms;
  /* nothing a visitor waits on runs longer than 1200ms, except the house scenes */
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 15px/1.55 var(--sans);
  font-feature-settings: 'ss01', 'cv11';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
main { flex: 1 0 auto; width: 100%; }
img, svg, canvas { display: block; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
button:disabled { cursor: not-allowed; opacity: .45; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 6px; }
::selection { background: #1b1c1822; }
.num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); font-size: .92em; letter-spacing: -.01em; }
.hand { font-family: var(--hand); }
.serif { font-family: var(--serif); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 max(var(--gutter), env(safe-area-inset-right)) 0 max(var(--gutter), env(safe-area-inset-left)); }

.skip { position: fixed; left: 12px; top: -80px; z-index: 200; background: var(--ink); color: #fff; padding: 12px 16px; border-radius: 8px; }
.skip:focus { top: 12px; }

/* ---------- header ---------- */

.top {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(1.2) blur(10px);
  -webkit-backdrop-filter: saturate(1.2) blur(10px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
.top.scrolled { border-bottom-color: var(--rule); }
.top .wrap { height: var(--header); display: flex; align-items: center; gap: 28px; }
.mark { display: flex; align-items: center; gap: 8px; white-space: nowrap; margin-right: auto; }
.mark svg { width: 30px; height: 30px; flex: none; overflow: visible; }
.mark b { font: 400 25px/1 var(--hand); letter-spacing: -.5px; }
.mark span { font: 500 13px/1 var(--sans); color: var(--muted); letter-spacing: .01em; }
.mark b + span { margin-left: -6px; }
/* the mark is Phil's head (ink.js PHIL_HEAD). On hover his two hair flicks twitch once: two frames at
   12 fps, each flick turning on its root, then back. Calm's global kill makes it a no-op. */
.mark .mk-f1 { transform-box: view-box; transform-origin: 45px 7px; }
.mark .mk-f2 { transform-box: view-box; transform-origin: 50px 7px; }
@media (hover: hover) {
  .mark:hover .mk-f1 { animation: mk-twitch-1 167ms step-end 1; }
  .mark:hover .mk-f2 { animation: mk-twitch-2 167ms step-end 1; }
}
@keyframes mk-twitch-1 { 0% { transform: rotate(-16deg); } 50% { transform: rotate(7deg); } 100% { transform: rotate(7deg); } }
@keyframes mk-twitch-2 { 0% { transform: rotate(12deg); } 50% { transform: rotate(-6deg); } 100% { transform: rotate(-6deg); } }

.nav { display: flex; align-items: center; gap: 4px; }
.nav a {
  position: relative; padding: 8px 12px; border-radius: 999px;
  font: 500 14px/1 var(--sans); color: var(--ink-2);
  transition: color var(--t-hover), background-color 180ms;
}
.nav a[aria-current='page'] { color: var(--ink); }
/* The current item carries an ink squiggle, a real element so a page change can slide it (S1). Hovering
   any other item draws the same squiggle in graphite, left to right in 200ms; leaving fades it in 120ms.
   No wash pill. */
.nav-mark, .nav a::after {
  position: absolute; left: 12px; right: 12px; bottom: calc(50% - 14px); height: 6px; pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 6' preserveAspectRatio='none'%3E%3Cpath d='M1 4Q15 1 30 3.5T59 2.5' fill='none' stroke='%231b1c18' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}
.nav-mark { display: block; view-transition-name: nav-mark; }
.nav a::after {
  content: '';
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 6' preserveAspectRatio='none'%3E%3Cpath d='M1 4Q15 1 30 3.5T59 2.5' fill='none' stroke='%239a9a93' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  clip-path: inset(0 100% 0 0); opacity: 0;
  transition: clip-path 0s linear var(--t-out), opacity var(--t-out) linear;
}
.nav a[aria-current='page']::after { content: none; }
@media (hover: hover) {
  .nav a:hover { color: var(--ink); }
  .nav a:hover::after { clip-path: inset(0); opacity: 1; transition: clip-path var(--t-hover) var(--ease-pen), opacity 0s; }
}
.nav a:focus-visible::after { clip-path: inset(0); opacity: 1; transition: clip-path var(--t-hover) var(--ease-pen), opacity 0s; }
.nav .nav-extra, .nav .nav-foot { display: none; }
.nav .count { display: inline-grid; place-items: center; min-width: 18px; height: 18px; margin-left: 6px; padding: 0 5px; border-radius: 999px; background: var(--ink); color: #fff; font: 600 10.5px/1 var(--sans); vertical-align: 1px; }
/* The engine's status. Live is ink, rehearsal red, offline hollow. Nothing pulses: the dot beats only
   through PW.beat(), on a read that changed something shown. */
.status-dot { display: inline-flex; align-items: center; gap: 8px; font: 500 12.5px/1 var(--sans); color: var(--muted); white-space: nowrap; }
.status-dot i { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--graphite); box-shadow: 0 0 0 3px #9a9a9322; }
.status-dot.live i { background: var(--ink); box-shadow: 0 0 0 3px #1b1c1814; }
.status-dot.rehearsal i { background: var(--red); box-shadow: 0 0 0 3px #bf3b2822; }
.status-dot.offline i { background: #fff; box-shadow: inset 0 0 0 1.5px var(--graphite); }
.menu-button { display: none; width: 44px; height: 44px; border-radius: 10px; align-items: center; justify-content: center; margin-right: -11px; }
.menu-button svg { width: 22px; height: 22px; overflow: visible; }
/* the two lines turn into a pencil X when the menu is open */
.menu-button path { transform-box: fill-box; transform-origin: center; transition: transform 220ms var(--ease-out); }
.menu-button[aria-expanded='true'] .mb-a { transform: translateY(4px) rotate(45deg); }
.menu-button[aria-expanded='true'] .mb-b { transform: translateY(-4px) rotate(-45deg); }
/* the scrim under an open phone menu (app.js adds it; only shown at phone widths) */
.nav-scrim { display: none; }

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* ---------- footer ---------- */

.foot { border-top: 1px solid var(--rule); margin-top: 96px; }
.foot .wrap { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 32px; padding-top: 40px; padding-bottom: calc(48px + env(safe-area-inset-bottom)); }
.foot h2 { font: 400 26px/1 var(--hand); margin: 0 0 8px; }
.foot p { margin: 0; color: var(--muted); font: 400 16px/1.45 var(--serif); max-width: 34ch; }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; justify-items: start; }
.foot a { color: var(--ink-2); }
.foot .small { font-size: 12.5px; color: var(--muted); display: grid; gap: 6px; align-content: start; justify-items: start; }
.foot button { color: var(--ink-2); text-align: left; font-size: 12.5px; }
@media (hover: hover) {
  .foot a:hover, .foot button:hover { color: var(--ink); }
}

/* ---------- type ---------- */

.kicker { font: 500 11.5px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); text-wrap: balance; }
.kicker b { color: var(--ink); font-weight: 600; }
h1, h2, h3 { margin: 0; font-weight: 500; letter-spacing: -.02em; }
.page-title { font: 500 clamp(40px, 6.2vw, 76px)/.98 var(--sans); letter-spacing: -.045em; margin: 14px 0 0; }
.lede { font: 400 clamp(19px, 2vw, 23px)/1.38 var(--serif); color: var(--ink-2); max-width: 36ch; margin: 18px 0 0; }
.section-title { font: 500 clamp(26px, 3vw, 34px)/1.08 var(--sans); letter-spacing: -.03em; text-wrap: balance; }
.page-title, .more-card b, .card-wallet { text-wrap: balance; }
.prose { font: 400 18px/1.55 var(--serif); color: var(--ink-2); max-width: 62ch; }
.prose p { margin: 0 0 14px; }
.prose strong { color: var(--ink); font-weight: 600; }
.note-hand { font: 400 19px/1.2 var(--hand); color: var(--ink-2); }

/* ---------- buttons and fields ---------- */

/* Buttons carry no shadow (no shadows on chrome). The ink button's hover is a white hairline ruled 3px
   inside it, like a stamp; the ghost's ring inks. A press sinks to .97 in 70ms and comes back in 180ms
   on the stamp curve. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 42px; padding: 0 18px; border-radius: 999px;
  background: var(--ink); color: #fff; font: 500 14px/1 var(--sans); white-space: nowrap;
  transition: transform 180ms var(--ease-stamp), background-color var(--t-hover), box-shadow var(--t-hover);
  box-shadow: none;
}
.btn.ghost { background: #fff; color: var(--ink); box-shadow: inset 0 0 0 1px var(--faint); }
@media (hover: hover) {
  .btn:not(:disabled):hover { background: var(--ink); box-shadow: inset 0 0 0 3px var(--ink), inset 0 0 0 4px #ffffff59; }
  .btn.ghost:not(:disabled):hover { background: #fff; box-shadow: inset 0 0 0 1.5px var(--ink); }
}
.btn:not(:disabled):active { transform: scale(.97); transition: transform var(--t-press) ease-out, background-color var(--t-hover), box-shadow var(--t-hover); }
.btn.small { height: 34px; padding: 0 14px; font-size: 13px; }
.btn svg { width: 16px; height: 16px; }
/* Links: a faint resting rule, and on hover an ink pencil line drawn over it from the left (220ms).
   Footer links have no resting rule. An arrow inside a link (.arr) nudges 3px. */
.link, .foot ul a {
  text-decoration: none; padding-bottom: 1px;
  background: linear-gradient(var(--ink), var(--ink)) 0 100% / 0 1px no-repeat, linear-gradient(var(--faint), var(--faint)) 0 100% / 100% 1px no-repeat;
  transition: background-size 220ms var(--ease-pen), color var(--t-hover);
}
.link { color: var(--ink); }
.foot ul a { background-size: 0 1px, 0 1px; }
@media (hover: hover) {
  .link:hover, .foot ul a:hover { background-size: 100% 1px, 100% 1px; }
}
.link:focus-visible, .foot ul a:focus-visible { background-size: 100% 1px, 100% 1px; }
.link:disabled { background-image: none; }
.arr { display: inline-block; transition: transform 180ms var(--ease-out); }
@media (hover: hover) {
  a:hover .arr, button:hover .arr { transform: translateX(3px); }
}
a:focus-visible .arr, button:focus-visible .arr { transform: translateX(3px); }
.field { display: grid; gap: 6px; }
.field label, .label { font: 500 12.5px/1.2 var(--sans); color: var(--ink-2); }
.input, .field input, .field select, .field textarea {
  width: 100%; height: 42px; padding: 0 14px; border-radius: 10px;
  border: 1px solid var(--faint); background: #fff; font-size: 14.5px;
  transition: border-color .2s, box-shadow .2s;
}
.field textarea { height: auto; min-height: 120px; padding: 12px 14px; line-height: 1.5; resize: vertical; }
.input:focus, .field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px #1b1c1812; }

/* ---------- surfaces ---------- */

.card { background: #fff; border: 1px solid var(--rule); border-radius: var(--radius); }
.panel { background: var(--wash); border-radius: var(--radius); }
.hair { height: 1px; background: var(--rule); border: 0; margin: 0; }
.tag { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 999px; background: var(--wash); font: 500 12px/1 var(--sans); color: var(--ink-2); white-space: nowrap; }
.tag.ink { background: var(--ink); color: #fff; }
.tag.red { background: #bf3b2812; color: var(--red); }
/* Cards that link somewhere do not lift: the border inks (each card's own rule) and an arrow inside
   (.arr) nudges 3px. body raises this above the per-page :hover rules that still carry a -2px lift. */
body :is(.card, .more-card, .rm-next-card, .st-card, .pg-brief, .pg-holders):hover { transform: none; }
@media (hover: hover) {
  :is(.more-card, .rm-next-card, .st-card, .pg-brief, .pg-holders):hover .arr { transform: translateX(3px); }
}

/* ---------- the contract address: one row, front page and garden only ---------- */

.ca { display: flex; align-items: center; gap: 10px; margin: 0; min-width: 0; font: 500 12.5px/1.2 var(--sans); color: var(--muted); }
.ca-k { flex: none; font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; }
.ca-v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-size: 13px; }
.ca-v.is-none { font-family: var(--sans); color: var(--muted); font-size: 12.5px; }
.ca-short { display: none; }
.ca-copy { flex: none; position: relative; height: 26px; padding: 0 10px; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--faint); font: 500 12px/1 var(--sans); color: var(--ink); transition: transform 180ms var(--ease-stamp), box-shadow var(--t-hover); }
@media (hover: hover) { .ca-copy:hover { box-shadow: inset 0 0 0 1px var(--ink); } }
.ca-copy:active { transform: scale(.97); transition: transform var(--t-press) ease-out, box-shadow var(--t-hover); }
/* a finger gets a 44px target; the pill it sees stays 26px (drawn by ::before) */
@media (pointer: coarse) {
  .ca-copy { height: 44px; margin: -9px 0; box-shadow: none; }
  .ca-copy::before { content: ''; position: absolute; inset: 9px 0; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--faint); pointer-events: none; }
  .ca-copy:active::before { background: var(--wash); }
  .ca-copy:hover { box-shadow: none; }
  .ca-copy:hover::before { box-shadow: inset 0 0 0 1px var(--ink); }
}
@media (max-width: 560px) { .ca-long { display: none; } .ca-short { display: inline; } }
/* the smallest phones: the label shortens so the whole short address fits beside the copy button */
.ca-k-short { display: none; }
@media (max-width: 380px) { .ca-k-long { display: none; } .ca-k-short { display: inline; } }

/* copy that depends on a mouse or a finger */
.for-touch { display: none; }
@media (pointer: coarse) { .for-touch { display: inline; } .for-fine { display: none; } }
button.for-touch, .btn.for-touch { display: none; }
@media (pointer: coarse) { button.for-touch, .btn.for-touch { display: inline-flex; } }

/* a sideways scroller says it scrolls: the right edge fades while there is more (app.js sets the class) */
.fade-r { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); }

/* ---------- page head (every page except the roll call) ---------- */

.page-head { padding-top: clamp(40px, 7vw, 88px); padding-bottom: clamp(28px, 4vw, 48px); display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 32px; align-items: end; }
.page-head .art { width: clamp(120px, 16vw, 200px); color: var(--ink); }

/* ---------- toast and dialog ---------- */

.toast {
  position: fixed; left: 50%; bottom: calc(88px + env(safe-area-inset-bottom)); z-index: 300; transform: translate(-50%, 16px);
  background: var(--ink); color: #fff; padding: 11px 16px; border-radius: 999px; font: 500 13.5px/1.2 var(--sans);
  opacity: 0; pointer-events: none; transition: opacity .25s var(--ease), transform .35s var(--ease-out);
  max-width: calc(100vw - 32px); text-align: center;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

dialog.sheet-dialog {
  border: 0; padding: 0; margin: 0; max-width: none; max-height: none;
  position: fixed; inset: 0 0 0 auto; width: min(460px, 100vw); height: 100dvh;
  background: #fff; color: var(--ink); box-shadow: -24px 0 60px -30px #1b1c1860;
  overflow: auto; overscroll-behavior: contain;
}
dialog.sheet-dialog::backdrop { background: #1b1c1826; backdrop-filter: blur(2px); transition: opacity 220ms linear; }
dialog.sheet-dialog[open] { animation: slide-in .38s var(--ease-out); }
/* closing: app.js slides the sheet out (40px and a fade, 220ms) and fades the backdrop, then close() */
dialog.sheet-dialog.closing::backdrop { opacity: 0; }
dialog.sheet-dialog.closing { pointer-events: none; }
dialog.sheet-dialog .x { position: sticky; top: 12px; float: right; margin: 12px 12px 0 0; width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; background: #fff; box-shadow: inset 0 0 0 1px var(--rule); z-index: 2; transition: transform 180ms var(--ease-stamp), box-shadow var(--t-hover); }
@media (hover: hover) { dialog.sheet-dialog .x:hover { box-shadow: inset 0 0 0 1px var(--ink); } }
dialog.sheet-dialog .x:active { transform: scale(.94); transition: transform var(--t-press) ease-out, box-shadow var(--t-hover); }
dialog.sheet-dialog .x svg { width: 14px; height: 14px; }
.dialog-body { padding: 28px 28px calc(40px + env(safe-area-inset-bottom)); }
@keyframes slide-in { from { transform: translateX(40px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes rise-in { from { transform: translateY(40px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---------- specimen / rehearsal banners ---------- */

.specimen-bar { position: sticky; top: var(--header); z-index: 40; background: var(--ink); color: #fff; font: 500 12px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; text-align: center; padding: 9px 12px; }
/* one line on a phone: the bar stays stuck under the header, so a second line was 12px more of every screen */
@media (max-width: 560px) { .specimen-bar .sb-more { display: none; } }

/* ---------- reveal ---------- */

.reveal { opacity: 0; transform: translateY(14px); transition: opacity .7s var(--ease), transform .8s var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }

/* ---------- responsive shell ---------- */

@media (max-width: 1020px) {
  .nav a { padding: 8px 9px; }
  .status-dot span { display: none; }
}
@media (max-width: 860px) {
  :root { --header: 58px; }
  .menu-button { display: inline-flex; }
  /* the status word stays beside the dot on a phone, small: "running", "rehearsal", "offline" */
  .status-dot { gap: 6px; }
  .status-dot span { display: inline; font-size: 11px; letter-spacing: .01em; }
  .nav {
    position: fixed; inset: var(--header) 0 auto 0; flex-direction: column; align-items: stretch; gap: 0;
    background: #fff; border-bottom: 1px solid var(--rule);
    padding: 8px max(var(--gutter), env(safe-area-inset-right)) 16px max(var(--gutter), env(safe-area-inset-left));
    opacity: 0; visibility: hidden; transition: opacity 160ms linear, visibility 0s linear 160ms;
    view-transition-name: none;
  }
  .nav.open { opacity: 1; visibility: visible; transition: opacity 160ms linear, visibility 0s; view-transition-name: nav-open; }
  /* the rows appear 30ms apart, opacity only; closing, they go together */
  .nav > * { opacity: 0; transition: opacity 160ms linear; }
  .nav.open > * { opacity: 1; transition-delay: calc(var(--i, 0) * 30ms); }
  .nav a { padding: 14px 4px; border-radius: 0; border-bottom: 1px solid var(--rule); font-size: 16px; line-height: 1.1; transition: opacity 160ms linear, background-color 180ms, color var(--t-hover); }
  .nav.open a { transition-delay: calc(var(--i, 0) * 30ms), 0s, 0s; }
  .nav-mark, .nav a::after { left: 4px; right: auto; width: 60px; bottom: 5px; }
  .nav .nav-extra { display: block; }
  .nav .nav-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding-top: 14px; }
  .nav .nav-foot .btn { height: 44px; padding: 0 18px; border: 0; border-radius: 999px; font-size: 14px; color: #fff; }
  .nav-status { display: inline-flex; align-items: center; gap: 8px; font: 500 13px/1.2 var(--sans); color: var(--muted); }
  .nav-status::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--graphite); }
  .nav-status.rehearsal::before { background: var(--red); }
  .nav-status.live::before { background: var(--ink); }
  .nav-status.offline::before { background: #fff; box-shadow: inset 0 0 0 1.5px var(--graphite); }
  .nav-scrim {
    display: block; position: fixed; inset: var(--header) 0 0 0; z-index: 45; background: #1b1c1814;
    opacity: 0; visibility: hidden; transition: opacity 160ms linear, visibility 0s linear 160ms;
  }
  .nav-scrim.on { opacity: 1; visibility: visible; transition: opacity 160ms linear, visibility 0s; }
  .foot .wrap { grid-template-columns: 1fr 1fr; }
  .foot .wrap > :first-child { grid-column: 1 / -1; }
  .page-head { grid-template-columns: 1fr; }
  .page-head .art { display: none; }
  dialog.sheet-dialog { inset: auto 0 0 0; width: 100vw; height: auto; max-height: 88dvh; border-radius: 18px 18px 0 0; box-shadow: 0 -24px 60px -30px #1b1c1860; }
  dialog.sheet-dialog[open] { animation: rise-in .38s var(--ease-out); }
}

/* calm: ONE switch. app.js sets body.calm from the OS setting (prefers-reduced-motion) and the footer
   toggle, so "motion: on" really turns motion on. There is no other reduced-motion rule in this sheet. */
body.calm *, body.calm *::before, body.calm *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
body.calm .reveal { opacity: 1; transform: none; }
[hidden] { display: none !important; }
.top-cta { margin-left: 4px; }
@media (min-width: 861px) and (max-width: 1180px) { .top .wrap { gap: 16px; } .nav a { padding: 8px 8px; font-size: 13.5px; } }
@media (max-width: 860px) { .top-cta { display: none; } }
body.calm .nav > *, body.calm .nav a { transition-delay: 0s !important; }

/* ---------- touch: 44px targets, and a press that answers at once ---------- */

@media (pointer: coarse) {
  .mark { min-height: 44px; }
  .btn, .btn.small { min-height: 44px; }
  .foot ul { gap: 0; }
  .foot ul a, .foot button { display: inline-flex; align-items: center; min-height: 44px; }
  .foot ul a { background-position: 0 calc(50% + 11px); }
  dialog.sheet-dialog .x { width: 44px; height: 44px; margin: 10px 10px 0 0; }
}
@media (min-width: 861px) and (pointer: coarse) {
  .nav a { padding-top: 15px; padding-bottom: 15px; }
}
/* no hover on a finger: the wash lands at once and fades over 180ms after the press */
@media (hover: none) {
  .nav a:active, .foot ul a:active, .foot button:active { background-color: var(--wash); transition-duration: 0s; }
  .foot ul a, .foot button { border-radius: 6px; transition: background-color 180ms, color var(--t-hover); }
  .btn.ghost:active { background: var(--wash); }
}

/* ---------- page changes (S1): the header and the house hold still, the sheet comes off ---------- */

/* Cross-document view transitions (Chrome and Edge 126+, Safari 18.2+; elsewhere a normal load). The
   old page lifts off like a sheet torn from a pad (10px up, a third of a degree, 220ms); the new one is
   simply there underneath (a 200ms fade after 80ms). The header, the current nav squiggle and, between
   the front page and the garden, the house keep their own layers, so they hold or slide instead.
   Calm: the OS setting drops the rule below; the footer switch is honoured by app.js (pageswap and
   pagereveal skip the transition), because body.calm does not reach ::view-transition-*. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
.top { view-transition-name: top; }
body[data-page='page'] #rc-scene, body[data-page='garden'] #rc-scene { view-transition-name: phil-house; }
::view-transition-old(root) { animation: 220ms cubic-bezier(.4, 0, 1, 1) both vt-sheet-off; transform-origin: 50% 0; }
::view-transition-new(root) { animation: 200ms linear 80ms both vt-sheet-on; }
::view-transition-group(nav-mark) { animation-duration: 320ms; animation-timing-function: cubic-bezier(.3, .7, .2, 1); }
::view-transition-group(phil-house) { animation-duration: 320ms; animation-timing-function: var(--ease-inout); }
::view-transition-group(top) { animation-duration: 220ms; }
::view-transition-old(nav-open) { animation: 160ms linear both vt-fade-out; }
@keyframes vt-sheet-off { to { opacity: 0; transform: translateY(-10px) rotate(-.35deg); } }
@keyframes vt-sheet-on { from { opacity: 0; } }
@keyframes vt-fade-out { to { opacity: 0; } }

/* ---------- the shared motion contract (app.js) ---------- */

/* PW.drawIn: a drawing waits hidden for exactly one frame, then drawIn takes this off in the same task
   that creates its strokes. If drawIn never runs, the drawing shows itself after 2.5s rather than never. */
.rc-pending { opacity: 1; }
@keyframes rc-unpend { to { opacity: 1; } }

/* PW.beat: the header dot fills with solid ink for 900ms on a read that changed something shown.
   A class swap, no fade. */
.status-dot.beat i { background: var(--ink); box-shadow: 0 0 0 2px var(--ink); animation: none; }
.nav-status.beat::before { background: var(--ink); box-shadow: 0 0 0 2px var(--ink); }

/* PW.rewrite: glyphs rewritten in place. .rw-c is a character being written in; .rw-swap holds one
   changed glyph (or the whole figure when its length changed): the new one in .rw-new, wiped in by
   app.js, and the old one as ::before (data-o), lifted away over it after --rw-o. Keeping the old glyph
   out of the DOM text means el.textContent is always the new figure. */
.rw-c { white-space: pre; }
.rw-swap { position: relative; display: inline-block; white-space: pre; }
.rw-new { display: inline-block; white-space: pre; }
.rw-swap::before {
  content: attr(data-o); content: attr(data-o) / ''; /* the alt text '' keeps it out of the accessibility tree */
  position: absolute; left: 0; top: 0; white-space: pre; pointer-events: none;
  animation: rw-lift 140ms ease-in var(--rw-o, 0ms) both;
}
@keyframes rw-lift { from { transform: none; opacity: 1; } to { transform: translateY(-.35em); opacity: 0; } }
/* the underline under a changed figure: graphite, red for a fall. app.js measures the figure into --rw-x,
   --rw-w and --rw-y (just under its baseline) and starts it --rw-d after the last glyph. */
:where(.rw-ul, .rw-ul-static) { position: relative; }
.rw-ul::after, .rw-ul-static::after {
  content: ''; position: absolute; left: var(--rw-x, 0); top: var(--rw-y, 100%); width: var(--rw-w, 100%); height: 1.5px;
  border-radius: 1px; background: var(--graphite); transform-origin: 0 50%; pointer-events: none;
}
.rw-ul.rw-down::after, .rw-ul-static.rw-down::after { background: var(--red); }
/* 260ms draw (--ease-pen), 600ms held, 1200ms fade = 2060ms */
.rw-ul::after { animation: rw-ul 2060ms linear var(--rw-d, 0ms) both; }
@keyframes rw-ul {
  0% { transform: scaleX(0); opacity: 1; animation-timing-function: cubic-bezier(.45, .05, .25, 1); }
  12.62% { transform: scaleX(1); opacity: 1; animation-timing-function: linear; }
  41.75% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}

/* Stable shells and clear data states. */
html,body{max-width:100%}.wrap{width:min(1240px,calc(100% - 64px));min-width:0}.top .wrap{gap:22px}.nav{min-width:0}.top .top-cta{flex-shrink:0}.data-state{font-size:13px;line-height:1.5;border-left:2px solid var(--graphite);padding:10px 14px;background:var(--wash);color:var(--ink-2)}.data-state .link{min-height:44px}.feed-item[id]{scroll-margin-top:100px}.feed-item:target{outline:1px solid var(--ink);outline-offset:5px}button,a.btn{touch-action:manipulation}body.calm *,body.calm *::before,body.calm *::after{animation:none!important;transition:none!important}
@media(max-width:860px){.wrap{width:calc(100% - 32px)}.top .wrap{gap:12px}.nav a{min-height:44px}.top .status-dot{margin-left:auto}}

.route-loading{min-height:65vh;padding-top:60px}.loading-line{height:32px;background:#f3f3f0;width:65%;margin:28px 0 15px}.loading-line.short{width:42%;height:18px}.loading-art{width:130px;margin:28px 0}.route-loading p{color:var(--muted)}.state-notice{line-height:1.5}.route-loading svg{max-width:100%}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}

/* Whole pages only cross-fade; the header never travels. */
::view-transition-old(root),::view-transition-new(root){animation-duration:160ms;transform:none} @keyframes vt-sheet-off{to{opacity:0;transform:none}} @keyframes vt-sheet-on{from{opacity:0;transform:none}to{opacity:1;transform:none}}

/* Round 15: content is present before any optional entrance accent. */
.reveal,.reveal.in{opacity:1;transform:none;transition:none}
@media(max-width:650px){.link,.rm-switch a,.lh-tabs button,.nav a,.card-actions a,.card-actions button{min-height:44px;display:inline-flex;align-items:center}.step .choice.mini{min-height:44px}.top .brand{min-height:44px}.calm-toggle{min-height:44px}}

/* The complete fallback stays visible; only fresh recorded changes move. */
.h-smoke{animation:none!important}body[data-page='page'] #rc-scene,body[data-page='garden'] #rc-scene{view-transition-name:none}
.rent-jar{width:22px;height:24px;vertical-align:middle;margin:-8px 5px -5px 0}

.ca-v.is-none{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.4}.ca-copy{min-height:44px}

/* Phone targets include the small-looking controls as well as primary buttons. */
@media(max-width:650px){.top .mark,.foot a,.foot button,.tenant-name>a,.lh-roomkey a{min-height:44px;display:inline-flex;align-items:center}.btn,button,input:not([type=radio]):not([type=checkbox]),select,summary{min-height:44px}.chart-index a{display:flex;min-height:44px;align-items:center}.lh-roomkey{row-gap:0}}

.lh-figures dt:has(.rent-jar){position:relative;padding-left:25px}.lh-figures .rent-jar{display:inline-block;position:absolute;left:0;top:-8px;margin:0}

/* Motion repair: the default is readable; JavaScript accents first viewport entry. */
.scene-replay{display:block;margin:2px auto 0;min-height:44px;padding:8px 14px;border:0;border-radius:6px;background:transparent;color:var(--muted);font:500 11px/1.2 var(--sans);letter-spacing:.06em;cursor:pointer;transition:color 160ms,background 160ms}
.scene-replay:hover,.scene-replay:focus-visible{color:var(--ink);background:var(--wash)}
.scene-replay:disabled{opacity:.5;cursor:default}
.scene-fallback{pointer-events:none}
