/* ============================================================
   The Rowan Agency · v2
   ------------------------------------------------------------
   The Atelier system, inherited from therowan.studio, spoken
   louder. Same paper, same ink, same one blue. Fraunces carries
   the statement, the roster names, the step numerals and the
   closing address. Everything else is the sans, including the
   engraved label voice at 11px.

   v2, same day as v1: the long roster records became a lateral
   scroller of portrait cards, How it works went lateral, the
   vertical rhythm tightened everywhere, and the theme became a
   three-state switch (auto / light / dark) instead of following
   the system silently.

   The portrait treatment is lifted verbatim from Iván's
   photography site (ivanlizarde.com): rest under
   grayscale(1) contrast(1.06) brightness(.97), then color and a
   3.5% scale on hover, inside an overflow-hidden frame. Keep the
   numbers identical across both sites; the shared gesture is the
   point.
   ============================================================ */

/* ---------- fonts (self-hosted, variable, latin) ---------- */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/fraunces.woff2') format('woff2');
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/fraunces-italic.woff2') format('woff2');
}

/* ---------- tokens ----------
   Three-state theme. Light lives in :root. The dark block exists
   TWICE below and the two copies must stay identical: once under
   the media query for auto mode, once under [data-theme="dark"]
   for the explicit switch. html[data-theme="light"] wins over the
   media query by never matching it. */
:root {
  /* --err has to be a token, not a literal. The one literal #A03A2E was fine on
     paper and measured 2.72:1 on the dark background, which is a failure on the
     one message a person most needs to be able to read. */
  --err: #A03A2E;
  --paper: #FAF7F0;
  --ink: #1B1916;
  --whisper: #716B5C;
  --faded: #C9C2B2;
  --hair: #DDD5C4;
  --blue: #0000EE;
  --plate: #F1ECE1;
  --display: 'Fraunces', ui-serif, Georgia, serif;
  --sans: system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --wrap: 1200px;
  --gutter: clamp(20px, 5vw, 64px);
  /* the photography-site portrait filter, verbatim */
  --mono: grayscale(1) contrast(1.06) brightness(0.97);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --err: #E8887A;
    --paper: #161513;
    --ink: #E8E4DB;
    --whisper: #8A857A;
    --faded: #4A463F;
    --hair: #2E2C28;
    --blue: #7B7BFF;
    --plate: #1E1C19;
  }
}
:root[data-theme="dark"] {
  --err: #E8887A;
  --paper: #161513;
  --ink: #E8E4DB;
  --whisper: #8A857A;
  --faded: #4A463F;
  --hair: #2E2C28;
  --blue: #7B7BFF;
  --plate: #1E1C19;
}

/* ---------- reset, base ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* The canvas colour lives on html, not body. That stops body's background
   propagating to the canvas, which is what lets the wash below paint over
   the whole viewport instead of being hidden underneath it. */
html { background: var(--paper); }
body {
  background: transparent;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ============================================================
   THE WASH · one gradient, behind the entire page
   ------------------------------------------------------------
   Every section used to inherit the same flat --paper, so the page read
   as one beige column from top to bottom. The fix is not a gradient per
   section: that produces a seam at every boundary and reads as the same
   image tiled, which is precisely what Ivan asked to avoid.

   Instead there is exactly ONE gradient, on a fixed viewport-sized layer
   behind everything. Sections are transparent by default and slide over
   it, so continuity is structural rather than something to maintain: no
   section boundary can show a seam, because there is only one image and
   no section owns any part of it.

   Fixed rather than a document-height layer for two reasons. A gradient
   stretched down a 6000px page smears its glows into bands. And
   background-attachment: fixed has a long history of misbehaving on iOS
   Safari, so this is a real fixed-position element instead.

   Still built only from palette tokens, so it flips with the theme and
   cannot drift off-brand. The blue stays under 10 percent: above that it
   stops reading as paper with light in it and starts reading as a SaaS
   hero, which is the failure Ivan named at the beginning.
   ============================================================ */
/* --wash-deep is the whole trick. --paper and --plate sit about 4% apart in
   luminance, which is right for panels inside a page but far too close to make
   a paper plate read as floating ON the wash: both just looked beige. Mixing a
   little --ink into --plate opens that gap without introducing a colour the
   palette does not already own, so figure and ground finally separate. */
:root {
  --wash-deep: color-mix(in srgb, var(--plate) 89%, var(--ink) 11%);
  --wash-mid: color-mix(in srgb, var(--plate) 96%, var(--ink) 4%);
}
.wash {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(125% 80% at 86% 2%, color-mix(in srgb, var(--blue) 9%, transparent) 0%, transparent 52%),
    radial-gradient(85% 65% at 4% 26%, color-mix(in srgb, var(--paper) 70%, transparent) 0%, transparent 58%),
    radial-gradient(100% 75% at 96% 92%, color-mix(in srgb, var(--wash-deep) 88%, transparent) 0%, transparent 55%),
    linear-gradient(162deg, var(--wash-mid) 0%, var(--wash-deep) 48%, var(--wash-mid) 100%);
}

/* ---------- plates: the sections that float above the wash ----------
   A plate is opaque, inset from the window, and rounded, so it reads as
   an object sitting ON the gradient rather than a band cut out of it.
   The shadow is doing the lifting; the hairline keeps the edge legible in
   dark mode, where a shadow alone disappears. */
.plate-section {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: clamp(16px, 2.2vw, 28px);
  margin-inline: clamp(12px, var(--gutter), 64px);
  box-shadow: 0 24px 60px -28px rgba(10, 10, 9, 0.34);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .plate-section {
    box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.6);
  }
}
:root[data-theme="dark"] .plate-section {
  box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.6);
}
/* A plate already insets from the window, so its inner .wrap would inset a
   second time and squeeze the column. Give the padding back. */
.plate-section > .wrap { padding-inline: clamp(16px, 3vw, 40px); }
@media (max-width: 620px) {
  .plate-section { margin-inline: 10px; border-radius: 14px; }
}
img { max-width: 100%; display: block; }
a { color: inherit; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }

::selection { background: var(--blue); color: #FFFFFF; }

a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 1px;
}

.label {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--whisper);
}

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--paper);
  padding: 10px 18px; font-family: var(--sans); font-size: 13px; z-index: 99;
}
.skip:focus { left: 0; }

/* Placeholder pills: visible on purpose, everywhere content awaits a
   real asset or a person's approval. Removed piece by piece as the
   real thing arrives, never all at once. */
.draft-pill {
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--whisper);
  border: 1px solid var(--hair);
  padding: 3px 8px;
  /* Never nowrap. A nowrap pill sets the min-content width of whatever
     cell contains it, and one long pill inside a 1fr grid pushed the
     whole quote grid ~400px past the wrap. Found by Ivan in Safari,
     2026-07-30; the same overflow was in Chrome and got waved off as
     screenshot cropping. Pills wrap, and grids use minmax(0, 1fr). */
}

/* ---------- reveal motion, once, gently ---------- */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.8s ease, transform 0.8s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* ---------- header ---------- */
header.site {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hair);
}
/* The wordmark and the station clock read as one unit: the agency and where it
   is. They sit together on the left with the nav pushed to the far right, rather
   than the clock floating in the middle of the bar unattached to anything. */
.site-bar {
  display: flex; align-items: baseline; gap: clamp(12px, 2vw, 22px);
  padding: 16px var(--gutter);
  max-width: var(--wrap); margin: 0 auto;
}
.wordmark {
  font-family: var(--display); font-weight: 600; font-size: clamp(21px, 1.9vw, 25px);
  letter-spacing: -0.014em; text-decoration: none; white-space: nowrap;
}
.station {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--whisper); white-space: nowrap;
}
/* The gap that used to be space-between. Everything before it hugs the
   wordmark; the nav takes the rest. */
nav.primary { margin-left: auto; }
nav.primary { display: flex; gap: clamp(14px, 2.2vw, 26px); align-items: baseline; }
nav.primary a {
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
  text-decoration: none; color: var(--ink);
  padding: 6px 0;
}
nav.primary a:hover { color: var(--blue); }

/* Inquire is the only solid thing on the page's furniture, because it is the
   only action the page is for. Everything else in the bar is a link. */
nav.primary a.cta {
  background: var(--blue); color: #FFFFFF;
  padding: 8px 16px;
  border: 1px solid var(--blue);
  transition: opacity 0.25s ease;
}
nav.primary a.cta:hover { color: #FFFFFF; opacity: 0.86; }
/* Dark mode lightens --blue to #7B7BFF for legibility on a dark page, which makes
   white-on-blue 3.43:1. The button keeps the blue and flips the label instead. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) nav.primary a.cta,
  :root:not([data-theme="light"]) nav.primary a.cta:hover { color: #14120F; }
}
:root[data-theme="dark"] nav.primary a.cta,
:root[data-theme="dark"] nav.primary a.cta:hover { color: #14120F; }

/* Subscribe: the cheaper yes, for someone not ready to book. Outlined rather
   than filled, so the eye still lands on Inquire first. Two solid buttons
   would be no button at all. */
nav.primary a.cta-ghost {
  border: 1px solid var(--hair);
  color: var(--whisper);
  padding: 8px 14px;
  transition: color 0.25s ease, border-color 0.25s ease;
}
nav.primary a.cta-ghost:hover { color: var(--blue); border-color: var(--blue); }

/* ---------- the theme pill, floating lower right ----------
   Out of the nav entirely: it is a preference, not a destination, and it was
   taking a slot in the bar that the two real actions needed. The thumb is a
   single element that slides, so the movement reads as one control with three
   positions rather than three buttons that light up. */
.theme-pill {
  position: fixed; right: clamp(14px, 3vw, 28px); bottom: clamp(14px, 3vw, 28px);
  z-index: 60;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  align-items: center;
  padding: 4px;
  border: 1px solid var(--hair);
  border-radius: 999px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px) saturate(1.1);
  box-shadow: 0 6px 22px rgba(10, 10, 9, 0.13);
}
.theme-thumb {
  position: absolute; left: 4px; top: 4px;
  width: 34px; height: 34px;
  border-radius: 999px;
  background: var(--plate);
  border: 1px solid var(--hair);
  transform: translateX(calc(var(--i, 0) * 34px));
  transition: transform 0.34s cubic-bezier(0.22, 0.7, 0.24, 1);
}
.theme-opt {
  position: relative; z-index: 1;
  appearance: none; background: none; border: none; cursor: pointer;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  color: var(--whisper);
  border-radius: 999px;
  transition: color 0.25s ease;
}
.theme-opt svg {
  width: 16px; height: 16px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.theme-opt:hover { color: var(--ink); }
.theme-opt[aria-checked="true"] { color: var(--blue); }
@media (prefers-reduced-motion: reduce) { .theme-thumb { transition: none; } }
/* On a phone the pill sits where a thumb rests, so it is pulled in from the
   corner rather than out of reach. */
@media (max-width: 620px) {
  .theme-pill { right: 12px; bottom: 12px; }
}

@media (max-width: 900px) { .station { display: none; } }
@media (max-width: 620px) {
  nav.primary a:not(.cta):not(.keep) { display: none; }
  .nav-the { display: none; }
  .site-bar { gap: 14px; }
}

/* ---------- the opening ----------
   Statement and provenance together fill the first screen. A peek at the
   roster underneath read as sloppy; a full opening reads as composed, and it
   makes the roster a deliberate second beat rather than an accident.
   min-height uses svh so mobile browser chrome cannot shrink it into a lie. */
.opening {
  min-height: calc(100svh - 61px);   /* 61px is the sticky header */
  display: flex; flex-direction: column;
}
.opening .statement { flex: 1 1 auto; display: flex; align-items: center; }
.opening .statement .wrap { width: 100%; }
/* No rule here. A full-width hairline reads as a band edge, and the whole
   point of the wash is that the opening and the provenance strip are one
   continuous surface. Spacing does the separating. */
.opening .provenance { flex: 0 0 auto; }
@media (max-width: 700px) {
  /* On a phone the two together cannot fit without squeezing the headline,
     so the opening stops claiming a full screen and simply flows. */
  .opening { min-height: 0; }
  .opening .statement { display: block; }
}

/* ---------- the statement, over the hero video ----------
   The section is full-bleed media behind a text column. Until the
   real file arrives, .hero-media is a labeled placeholder; when it
   lands it becomes <video autoplay muted loop playsinline> under
   the same scrim. The scrim is not decoration: it is what keeps a
   Klein-blue headline readable over unknown footage, so it ships
   with the placeholder and never gets removed separately. */
.statement {
  position: relative;
  padding: clamp(52px, 9vh, 104px) 0 clamp(32px, 5vh, 52px);
  overflow: hidden;
}
/* Deliberately transparent. This used to carry its own copy of the gradient,
   which is why the hero looked lit and everything below it looked flat: the
   gradient stopped where this element stopped. The wash now runs behind the
   whole page, so this is purely the mount point for the hero video, and the
   gradient "starting in the hero" simply never ends. */
.hero-media {
  position: absolute; inset: 0;
  background: transparent;
}
.media-tag {
  position: absolute; top: 14px; right: max(14px, var(--gutter));
  z-index: 2;
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--whisper);
  border: 1px solid var(--hair);
  background: color-mix(in srgb, var(--paper) 70%, transparent);
  padding: 3px 8px;
}
.statement-inner { position: relative; z-index: 1; }
.statement h1 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(38px, 5.6vw, 84px);
  line-height: 1.04;
  letter-spacing: -0.022em;
  /* 26ch, not 22: the first sentence is meant to hold one line on a desktop
     screen. Ivan asked for that specifically, and for any forced break to
     fall before "in an hour" rather than inside it. */
  max-width: 26ch;
}
/* The phrase that must never split. With it kept whole, the only place the
   line CAN break is in front of it, which is exactly the break Ivan wants. */
.statement h1 .keep { white-space: nowrap; }
.statement h1 .turn { color: var(--blue); }
.statement h1 em { font-style: italic; font-weight: 440; }
.statement .sub {
  margin-top: 20px; max-width: 52ch;
  font-size: clamp(16px, 1.7vw, 20px); line-height: 1.5; color: var(--whisper);
}
.statement .acts { margin-top: 30px; display: flex; gap: 32px; align-items: baseline; flex-wrap: wrap; }
.act {
  font-family: var(--sans); font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase;
  text-decoration: none;
  display: inline-block;
  padding-top: 6px;
}
.act.primary { color: var(--blue); border-bottom: 1px solid var(--blue); padding-bottom: 3px; }
.act.quiet { color: var(--whisper); }
.act.quiet:hover { color: var(--ink); }

/* Three beats, engraved. The cadence is the point: it echoes the label voice
   used everywhere else on the page, so it reads as the agency's own texture
   rather than as a tagline bolted on. Middots are aria-hidden so a screen
   reader hears three phrases, not punctuation. */
.intent {
  margin-top: clamp(28px, 4.5vh, 44px);
  padding-top: 20px;
  border-top: 1px solid var(--hair);
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px 14px;
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--whisper);
}
.intent span[aria-hidden] { opacity: 0.5; }
@media (max-width: 560px) {
  /* Stack rather than wrap mid-phrase; a broken beat loses the cadence. */
  .intent { flex-direction: column; gap: 7px; }
  .intent span[aria-hidden] { display: none; }
}

/* ---------- where the work has been ----------
   Typographic, never logos. See the note in index.html. Set in the display
   face at a restrained size so it reads as provenance rather than as a
   badge wall. */
.provenance { padding: clamp(22px, 3.5vh, 34px) 0 clamp(22px, 3.2vh, 32px); }
.provenance .orgs {
  margin-top: 16px;
  display: flex; align-items: center; flex-wrap: wrap;
  gap: clamp(20px, 3.4vw, 44px);
}
.provenance .orgs img {
  height: 26px; width: auto;
  filter: grayscale(1) contrast(1.15);
  opacity: 0.55;
  transition: opacity 0.4s ease;
}
.provenance .orgs:hover img { opacity: 0.30; }
.provenance .orgs img:hover { opacity: 0.75; }
/* Optical balance: a tall mark at the same pixel height reads larger than a
   wide one, so the two tallest are trimmed by eye rather than by maths. */
.provenance .orgs img[alt="NFL"] { height: 30px; }
.provenance .orgs img[alt="NWSL"] { height: 22px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .provenance .orgs img {
    filter: grayscale(1) contrast(1.15) invert(1);
    opacity: 0.62;
  }
  :root:not([data-theme="light"]) .provenance .orgs:hover img { opacity: 0.34; }
  :root:not([data-theme="light"]) .provenance .orgs img:hover { opacity: 0.85; }
}
:root[data-theme="dark"] .provenance .orgs img {
  filter: grayscale(1) contrast(1.15) invert(1);
  opacity: 0.62;
}
:root[data-theme="dark"] .provenance .orgs:hover img { opacity: 0.34; }
:root[data-theme="dark"] .provenance .orgs img:hover { opacity: 0.85; }
@media (prefers-reduced-motion: reduce) {
  .provenance .orgs img { transition: none; }
}
/* The typeset credits row: same register as the marks above it — quiet,
   grayscale, waking slightly on hover — so the two rows read as one wall.
   Display face, spaced caps, no separators; the gap is the separator. */
.provenance .orgs-names {
  margin-top: 18px;
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 10px clamp(20px, 3.4vw, 44px);
  font-family: var(--display); font-weight: 500;
  font-size: clamp(14px, 1.4vw, 17px);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink);
}
.provenance .orgs-names span { opacity: 0.55; transition: opacity 0.4s ease; }
.provenance .orgs-names:hover span { opacity: 0.30; }
.provenance .orgs-names span:hover { opacity: 0.75; }

.provenance .orgs-note {
  margin-top: 14px; max-width: 62ch;
  font-size: 14px; line-height: 1.5; color: var(--whisper);
}

/* ---------- the roster: a lateral scroll of portraits ----------
   Headshot, name, title, one line. The full bios wait for each
   person's approval; the card is what an organizer actually scans.
   Scrolls sideways with snap, scrollbar kept thin but visible so
   the affordance is discoverable. */
.roster { padding: clamp(36px, 5vh, 56px) 0 clamp(32px, 5vh, 52px); }
.roster .head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px;
}
.roster-nav { display: flex; align-items: baseline; gap: 16px; }
.arrow {
  appearance: none; background: none; cursor: pointer;
  border: 1px solid var(--hair);
  color: var(--whisper);
  font-size: 15px; line-height: 1;
  padding: 7px 13px;
  transition: color 0.3s ease, border-color 0.3s ease;
}
.arrow:hover { color: var(--blue); border-color: var(--blue); }
.people {
  margin-top: clamp(20px, 3vh, 32px);
  display: flex; gap: clamp(16px, 2.2vw, 28px);
  overflow-x: auto;
  padding: 4px 4px 16px;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  cursor: grab;
}
.people.dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
.person {
  flex: 0 0 auto;
  width: clamp(230px, 24vw, 300px);
  scroll-snap-align: start;
}
/* The rail: the scroller escapes the wrap on the right so a card cut
   by the window edge reads as an invitation to scroll, not a bug. Left
   edge stays aligned with the wrap's content. */
/* The rail spans the full window and the FIRST CARD is pushed to the content
   edge by padding, not by a margin on the track.
   The difference matters: a margin moves the scroll container's left edge
   inward, so a card scrolled past it is clipped at the text column and
   vanishes against an invisible wall. Padding leaves the container full
   width, so cards travel out of view at the window edge in both directions,
   the way a rail should. Card one still lands exactly under the headline on
   first load. scroll-padding makes the arrows respect the same line. */
.rail { width: 100%; }
.people {
  --railpad: max(var(--gutter), calc((100vw - var(--wrap)) / 2 + var(--gutter)));
  padding-left: var(--railpad);
  padding-right: var(--railpad);
  scroll-padding-left: var(--railpad);
}
/* Four cards and a peek. The 2026-08-03 call set five-and-a-peek (Jo's
   spec); on 2026-09-08 Ivan asked for larger portraits as the real
   headshots started arriving, so the same derivation now divides the
   visible run by 4.25 instead of 5.25 — four full cards, four gaps, a
   quarter of card five, peek still pushed into the margin. If Jo asks
   where his five went, this is the decision, and reverting is one number.
   The max() floor keeps cards from collapsing on narrow desktops. */
@media (min-width: 1100px) {
  .person {
    width: max(184px, calc((100vw - var(--railpad, 64px) - 4 * clamp(16px, 2.2vw, 28px)) / 4.25));
  }
}

/* The closed card is photo, name, one line — the title subheading came off
   on Ivan's 2026-09-08 take-it-live pass. The element stays in the markup
   because build.mjs scrapes it for the profile pages and the dialog still
   shows it; only the closed card hides it. Restore by deleting this rule. */
.person > .person-title { display: none; }

/* The take-it-live switch: anything carrying `hidden` is genuinely gone,
   even where an author rule sets a display. Lesson borrowed from Oxcart,
   where an author flex beat the UA hidden rule and an empty alert bar
   rendered every day. */
[hidden] { display: none !important; }

/* the portrait is a real button: click opens the full card */
.person-open {
  appearance: none; background: none; border: none; padding: 0;
  display: block; width: 100%; cursor: pointer;
}
.person figure {
  margin: 0; position: relative; overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--plate);
  border: 1px solid var(--hair);
}
/* the photography-site gesture, verbatim numbers */
.person figure img {
  width: 100%; height: 100%; object-fit: cover;
  filter: var(--mono);
  transition: filter 0.55s ease, transform 1.1s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.person:hover figure img,
.person:focus-within figure img {
  filter: grayscale(0);
  transform: scale(1.035);
}
.person-name {
  margin-top: 14px;
  font-family: var(--display); font-weight: 540;
  font-size: clamp(19px, 1.9vw, 24px); line-height: 1.12; letter-spacing: -0.014em;
}
.person-title {
  margin-top: 6px;
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--whisper);
  line-height: 1.6;
}
.person-line {
  margin-top: 8px;
  font-size: 14px; line-height: 1.5; color: var(--whisper);
}
.person .draft-pill { display: inline-block; margin-top: 10px; }
@media (hover: none) {
  .person figure img { transition: none; }
  .person:hover figure img { filter: var(--mono); transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .person figure img { transition: filter 0.55s ease; }
  .person:hover figure img { transform: none; }
}

/* ---------- the full card: one dialog, every speaker ---------- */
/* The dialog sat top-left because the global `* { margin: 0 }` reset wiped
   the UA's `margin: auto` on <dialog>, which is what centres a modal. Putting
   it back is the whole fix; everything below is the entrance. */
.person-dialog {
  margin: auto;
  border: 1px solid var(--hair);
  background: var(--paper);
  color: var(--ink);
  padding: 0;
  width: min(760px, calc(100vw - 32px));
  max-height: min(84vh, 720px);
  box-shadow: 0 40px 90px rgba(10, 10, 9, 0.45);

  /* Entrance: rise and settle, no bounce. @starting-style gives the open
     state something to animate FROM, and allow-discrete lets display and
     overlay participate so the card animates out as well as in. */
  opacity: 0;
  transform: translateY(14px) scale(0.985);
  transition:
    opacity 0.34s cubic-bezier(0.22, 0.7, 0.24, 1),
    transform 0.34s cubic-bezier(0.22, 0.7, 0.24, 1),
    overlay 0.34s allow-discrete,
    display 0.34s allow-discrete;
}
/* Flex column so the footer nav stays put while .dialog-grid scrolls. It has
   to hang off [open] rather than the bare selector: writing `display: flex`
   unconditionally overrides the UA's `dialog:not([open]) { display: none }`
   and the card is then visible on a closed dialog. */
.person-dialog[open] {
  opacity: 1; transform: none;
  display: flex; flex-direction: column;
}
@starting-style {
  .person-dialog[open] { opacity: 0; transform: translateY(14px) scale(0.985); }
}

/* The page stays visible behind, darkened rather than hidden, so the roster
   still reads as the context the card came out of. */
.person-dialog::backdrop {
  background: color-mix(in srgb, #0A0A09 70%, transparent);
  backdrop-filter: blur(2px) saturate(0.8);
  opacity: 0;
  transition:
    opacity 0.34s ease,
    overlay 0.34s allow-discrete,
    display 0.34s allow-discrete;
}
.person-dialog[open]::backdrop { opacity: 1; }
@starting-style {
  .person-dialog[open]::backdrop { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .person-dialog, .person-dialog::backdrop { transition: opacity 0.15s ease; }
  .person-dialog { transform: none; }
  @starting-style { .person-dialog[open] { transform: none; } }
}
.dialog-close {
  position: absolute; top: 8px; right: 12px; z-index: 2;
  appearance: none; background: none; border: none; cursor: pointer;
  color: var(--whisper); font-size: 26px; line-height: 1; padding: 6px;
}
.dialog-close:hover { color: var(--blue); }
.dialog-grid {
  display: grid; grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
  gap: 0;
  /* `min-height: 0` is what lets a flex child actually shrink below its
     content and scroll. Without it the grid pushes the nav off the card. */
  flex: 1 1 auto; min-height: 0; overflow: auto;
}
.dialog-figure {
  margin: 0; overflow: hidden; background: var(--plate);
  border-right: 1px solid var(--hair);
}
.dialog-figure img {
  width: 100%; height: 100%; object-fit: cover;
  /* the card shows the person in color: the reveal the hover promised */
  filter: none;
}
.dialog-body { padding: clamp(20px, 3vw, 32px); }
.dialog-body .person-name { margin-top: 0; font-size: clamp(22px, 2.4vw, 30px); }
.dialog-bio { margin-top: 14px; font-size: 15px; line-height: 1.6; }
.dialog-bio p + p { margin-top: 10px; }
.dialog-bio strong {
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--whisper);
  display: block; margin-bottom: 4px;
}
.dialog-trailer {
  position: relative; margin-top: 18px;
  aspect-ratio: 16 / 9;
  background: var(--plate);
  border: 1px solid var(--hair);
  display: grid; place-items: center;
}
.dialog-trailer .play {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--whisper);
  display: grid; place-items: center;
  color: var(--whisper); font-size: 14px;
}
.dialog-trailer .reel-tag {
  position: absolute; left: 12px; bottom: 10px;
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--whisper);
}
.dialog-body .draft-pill { display: inline-block; margin-top: 16px; }

/* ---------- moving through the roster without leaving the card ----------
   Same .arrow vocabulary as the rail, so the gesture is learned once. The
   count is the reason this beats a bare pair of chevrons: on a roster this
   short, knowing you are on 3 of 7 is most of the navigation. */
.dialog-nav {
  flex: none;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px clamp(20px, 3vw, 32px);
  border-top: 1px solid var(--hair);
  background: var(--plate);
}
.dialog-count {
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--whisper);
}
/* Stops at the ends rather than wrapping. Seven records is a list, not a
   carousel, and a dimmed arrow answers "have I seen everyone" for free.
   aria-disabled rather than [disabled] because disabling a focused button
   blurs it out of the dialog and kills the arrow keys — see main.js. */
.dialog-nav .arrow[aria-disabled="true"] { opacity: 0.3; cursor: default; }
.dialog-nav .arrow[aria-disabled="true"]:hover {
  color: var(--whisper); border-color: var(--hair);
}

@media (max-width: 640px) {
  /* The row has to be a definite 300px, not `max-height: 300px` on the figure.
     Once .dialog-grid became a flex child with a resolved height, an auto row
     whose only content is an img at height:100% contributes nothing intrinsic,
     so the portrait collapsed to zero and the card opened on the name. Caught
     in a 420px render, not in the code — it looked correct on desktop. */
  .dialog-grid { grid-template-columns: 1fr; grid-template-rows: 300px auto; }
  .dialog-figure { border-right: none; border-bottom: 1px solid var(--hair); }
}

/* ---------- speaker profile pages ----------
   One URL per person, so a speaker can be sent as a link rather than
   described. The dialog stays for browsing; this is for sharing. */
.profile { padding: clamp(32px, 5vh, 56px) 0 clamp(48px, 8vh, 88px); }
.profile-grid {
  display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 64px); align-items: start;
}
.profile-figure {
  margin: 0; overflow: hidden; aspect-ratio: 4 / 5;
  background: var(--plate); border: 1px solid var(--hair);
}
.profile-figure img {
  width: 100%; height: 100%; object-fit: cover;
  filter: var(--mono);
  transition: filter 0.55s ease;
}
.profile-figure:hover img { filter: grayscale(0); }
.profile-body h1 {
  font-family: var(--display); font-weight: 520;
  font-size: clamp(32px, 4.6vw, 56px); line-height: 1.05; letter-spacing: -0.02em;
  margin-top: 10px;
}
.profile-body .person-title { margin-top: 10px; }
.profile-bio { margin-top: 20px; font-size: clamp(16px, 1.6vw, 18px); line-height: 1.65; max-width: 58ch; }
.profile-bio p + p { margin-top: 12px; }
.profile-bio strong {
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--whisper);
  display: block; margin-bottom: 4px;
}
.profile-trailer {
  position: relative; margin-top: 26px; max-width: 560px;
  aspect-ratio: 16 / 9; background: var(--plate); border: 1px solid var(--hair);
  display: grid; place-items: center;
}
.profile-trailer .play {
  width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid var(--whisper); display: grid; place-items: center;
  color: var(--whisper); font-size: 15px;
}
.profile-trailer .reel-tag {
  position: absolute; left: 12px; bottom: 10px;
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--whisper);
}
/* A real reel or a staged still replaces the placeholder's centred grid. */
.profile-trailer.has-reel, .profile-trailer.has-still { display: block; }
.profile-trailer.has-reel iframe,
.profile-trailer.has-reel video,
.profile-trailer.has-still img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border: 0; display: block;
}
/* The stand-in pill must survive whatever image sits behind it — it is the
   condition Ivan set for using generated stills at all. */
.profile-trailer.has-still .reel-tag {
  color: var(--ink);
  background: color-mix(in srgb, var(--paper) 84%, transparent);
  padding: 4px 10px; border-radius: 999px;
}

/* Social links, icon-only, data-driven: a network shows up on the card
   solely because the speaker gave us a handle for it. */
.person-links { display: flex; gap: 15px; margin-top: 20px; align-items: center; }
.person-links a {
  color: var(--whisper); display: inline-grid; place-items: center;
  transition: color 0.3s ease;
}
.person-links a:hover, .person-links a:focus-visible { color: var(--blue); }
.person-links svg { display: block; }

.profile-body .draft-pill { display: inline-block; margin-top: 18px; }
.profile-acts { margin-top: 26px; display: flex; gap: 28px; align-items: baseline; flex-wrap: wrap; }
@media (max-width: 760px) { .profile-grid { grid-template-columns: 1fr; } .profile-figure { max-width: 320px; } }

/* the quiet link from a roster card to its page */
.person-more {
  display: inline-block; margin-top: 10px;
  font-family: var(--sans); font-size: 11px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--blue); text-decoration: none;
  border-bottom: 1px solid transparent;
}
.person-more:hover { border-bottom-color: var(--blue); }

/* ---------- after the applause ----------
   Not a testimonial wall. Three voices, gathered after real rooms,
   and visibly empty until those rooms have happened. */
.afterward { padding: clamp(36px, 5vh, 56px) 0; margin-block: clamp(28px, 4.5vh, 56px); }
.afterward .head { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; flex-wrap: wrap; }
/* The boxes are gone. Inside a plate, a grid of bordered cells was a box in a
   box: two competing containers arguing about which one was the object. The
   quotes now sit on the plate itself with air around them, and the rail lets
   the section grow past three without becoming a testimonial wall. */
.quote-rail { position: relative; margin-top: clamp(22px, 3.4vh, 36px); }
/* The fades are the affordance. They sit inside the plate's rounded corner and
   say "more this way" without a scrollbar having to. Pointer-events off, or
   they would eat clicks on the first and last quote. */
.quote-rail::before, .quote-rail::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: clamp(28px, 5vw, 72px);
  pointer-events: none; z-index: 2;
}
.quote-rail::before { left: -1px; background: linear-gradient(to right, var(--paper), transparent); }
.quote-rail::after { right: -1px; background: linear-gradient(to left, var(--paper), transparent); }
/* A fade over nothing is just a smudge on the first quote. Each one appears
   only when there is actually content hidden on that side, which is the same
   state the arrows use. */
.quote-rail::before, .quote-rail::after { opacity: 1; transition: opacity 0.3s ease; }
.quote-rail[data-start="true"]::before { opacity: 0; }
.quote-rail[data-end="true"]::after { opacity: 0; }
.quote-track {
  display: flex; gap: clamp(26px, 4vw, 56px);
  overflow-x: auto; scroll-snap-type: x proximity;
  padding: 4px 2px 18px;
  scrollbar-width: none;
}
.quote-track::-webkit-scrollbar { display: none; }
.quote-track.dragging { scroll-snap-type: none; }
.quote {
  margin: 0; background: none; padding: 0;
  flex: 0 0 clamp(260px, 30vw, 360px);
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 16px;
}
.quote blockquote {
  font-family: var(--display); font-style: italic; font-weight: 420;
  font-size: clamp(17px, 1.7vw, 20px); line-height: 1.5; letter-spacing: -0.008em;
  color: var(--whisper);
}
.quote figcaption { display: grid; gap: 3px; }
.quote .q-name { font-weight: 600; font-size: 14px; color: var(--ink); }
.quote .q-org {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--whisper);
}
.quote .draft-pill { align-self: start; margin-top: auto; }

/* ---------- why this agency ---------- */
.why { padding: clamp(52px, 7vh, 84px) 0; }
.why-grid {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 72px); align-items: start;
}
.why h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(26px, 3.6vw, 46px); letter-spacing: -0.018em; line-height: 1.12;
  margin-top: 12px; max-width: 24ch;
}
.why .body { margin-top: 18px; max-width: 60ch; font-size: clamp(16px, 1.6vw, 18px); line-height: 1.6; }
.why .body p + p { margin-top: 12px; }
.why .body em { font-style: italic; }
.why-figure {
  margin: 0; position: relative;
  aspect-ratio: 4 / 5;
  background:
    radial-gradient(120% 80% at 75% 12%, color-mix(in srgb, var(--blue) 7%, transparent) 0%, transparent 60%),
    linear-gradient(158deg, var(--plate) 0%, var(--paper) 78%);
  border: 1px solid var(--hair);
  align-self: stretch;
  max-width: 420px; justify-self: end; width: 100%;
}
.why-figure .media-tag { top: auto; bottom: 12px; right: 12px; }
@media (max-width: 820px) {
  .why-grid { grid-template-columns: 1fr; }
  .why-figure { justify-self: start; max-width: 340px; }
}

/* ---------- journal (Substack, once it exists) ---------- */
.journal { padding: clamp(36px, 5vh, 56px) 0; margin-block: clamp(28px, 4.5vh, 56px); }
.journal .head { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; flex-wrap: wrap; }
.jgrid { margin-top: clamp(20px, 3vh, 32px); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.jcard {
  border: 1px solid var(--hair); padding: 20px;
  display: flex; flex-direction: column; gap: 8px;
}
.jcard .jdate { font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--whisper); }
.jcard h3 { font-weight: 600; font-size: 18px; line-height: 1.25; }
.jcard p { color: var(--whisper); font-size: 14px; }
@media (max-width: 820px) { .jgrid { grid-template-columns: 1fr; } }
.journal .subline { margin-top: 20px; font-size: 15px; color: var(--whisper); max-width: 60ch; }

/* ---------- subscribe: the secondary action ----------
   Quiet by design. It sits at the end of the journal, where someone who has
   just read three headlines is closest to wanting the fourth. */
.subscribe { margin-top: 4px; }
.subscribe-row {
  margin-top: 14px;
  display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch;
  max-width: 620px;
}
.subscribe-row input {
  flex: 1 1 190px; min-width: 0;   /* min-width:0 or a flex input refuses to shrink */
  appearance: none;
  background: none;
  border: 1px solid var(--hair);
  color: var(--ink);
  font-family: var(--sans); font-size: 14px;
  padding: 11px 13px;
  transition: border-color 0.25s ease;
}
.subscribe-row input::placeholder { color: var(--faded); }
.subscribe-row input:focus { border-color: var(--blue); outline: none; }
.subscribe-row button {
  flex: 0 0 auto;
  appearance: none; cursor: pointer;
  background: var(--ink); color: var(--paper);
  border: 1px solid var(--ink);
  font-family: var(--sans); font-size: 12px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
  padding: 11px 20px;
  transition: opacity 0.25s ease;
}
.subscribe-row button:hover { opacity: 0.85; }
.subscribe-row button[disabled] { opacity: 0.45; cursor: default; }
.subscribe .form-feedback { margin-top: 10px; }

/* Present to a screen reader, invisible on screen. The inputs carry
   placeholders, and a placeholder is not a label: it disappears the moment
   someone types, which is exactly when a label matters most. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* ---------- inquire ----------
   Compressed in v3: intro left, form right, so the section reads as
   one composed spread instead of a long scroll. The form borrows the
   hairline-cell language the steps and quotes already use, which is
   what ties it back into the design scheme. */
.inquire { padding: clamp(32px, 5vh, 52px) 0; margin-block: clamp(28px, 4.5vh, 56px); }
.inquire-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  gap: clamp(28px, 5vw, 72px); align-items: start;
}
.inquire h2 {
  font-family: var(--display); font-weight: 480;
  font-size: clamp(28px, 3.4vw, 44px); letter-spacing: -0.018em; line-height: 1.08;
  margin-top: 10px;
}
.inquire .lede {
  margin-top: 14px; max-width: 40ch;
  font-size: clamp(15px, 1.4vw, 17px); line-height: 1.5; color: var(--whisper);
}
.inquire form {
  display: grid; gap: 14px;
  border: 1px solid var(--hair);
  padding: clamp(18px, 2.4vw, 28px);
  background: color-mix(in srgb, var(--plate) 45%, var(--paper));
}
.inquire .frow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; }
@media (max-width: 560px) { .inquire .frow { grid-template-columns: 1fr; } }
.inquire label {
  font-family: var(--sans); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--whisper); display: grid; gap: 5px;
}
.inquire input, .inquire textarea, .inquire select {
  font-family: var(--sans); font-size: 15px; color: var(--ink);
  background: transparent; border: none; border-bottom: 1px solid var(--hair);
  padding: 6px 2px; border-radius: 0;
  width: 100%;
}
.inquire select { appearance: none; -webkit-appearance: none; cursor: pointer; }
.inquire textarea { min-height: 56px; resize: vertical; }
.inquire input:focus-visible, .inquire textarea:focus-visible, .inquire select:focus-visible {
  border-bottom-color: var(--blue);
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}
.inquire button {
  justify-self: start; margin-top: 2px;
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
  background: var(--ink); color: var(--paper); border: 1px solid var(--ink);
  padding: 12px 26px; cursor: pointer;
}
.inquire button:hover { background: var(--blue); border-color: var(--blue); color: #FFFFFF; }
.inquire button:disabled { opacity: 0.5; cursor: wait; }
.inquire .promise { margin-top: 18px; font-size: 14px; color: var(--whisper); }
.form-feedback { font-family: var(--sans); font-size: 13px; min-height: 18px; }
.form-feedback.ok { color: var(--blue); }
.form-feedback.err { color: var(--err); }
@media (max-width: 860px) { .inquire-grid { grid-template-columns: 1fr; gap: 24px; } }

/* ---------- the address ----------
   Rescaled in v3 against the Apple measurements in the Oxcart type
   scale: a 34px-class display line with 1.08 leading and slightly
   negative tracking, and the address one step below it rather than
   shouting at 54px. The section carries the same weight in a third
   of the height. */
.write { padding: clamp(40px, 5.5vh, 60px) 0; }
.write h2 {
  font-family: var(--display); font-weight: 500;
  font-size: clamp(26px, 3vw, 38px); letter-spacing: -0.012em; line-height: 1.08;
}
.write .address {
  display: inline-block; margin-top: 10px;
  font-family: var(--display); font-weight: 440;
  font-size: clamp(19px, 2.2vw, 27px); letter-spacing: -0.01em; line-height: 1.2;
  color: var(--blue); text-decoration: none;
  border-bottom: 1px solid var(--blue); padding-bottom: 2px;
  overflow-wrap: anywhere;
}
/* Underlined at rest, not only on hover. Colour alone measured 1.77:1 against
   the surrounding text in light and 1.07:1 in dark, so anyone who cannot separate
   those two hues cannot see that this is a link at all. */
.quiet-link { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
.quiet-link:hover { text-decoration-thickness: 2px; }

/* ---------- the quiet door for speakers ---------- */
.door { padding: clamp(24px, 4vh, 40px) 0; }
.door p { color: var(--whisper); font-size: 15px; max-width: 60ch; }
.door p a { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
.door p a:hover { text-decoration-thickness: 2px; }

/* ---------- footer ---------- */
footer.site { padding: 40px 0 48px; }
.foot-bar {
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px; flex-wrap: wrap;
}
.foot-nav { display: flex; gap: 20px; flex-wrap: wrap; align-items: center; }
.foot-nav a {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--whisper); text-decoration: none;
  padding: 5px 0;
}
.foot-nav a:hover { color: var(--blue); }
.colophon { margin-top: 16px; font-size: 14px; color: var(--whisper); }

/* ============================================================
   ROUNDED CORNERS · every framed image on the site
   ------------------------------------------------------------
   Once the sections became plates with soft corners, every square
   photograph read as a leftover from the previous system. One radius
   token so the whole site agrees, and it is deliberately smaller than
   the plate radius: a plate is a surface, an image is an object on it,
   and an object with the same corner as its container reads as a hole
   cut in the container rather than a thing sitting on it.

   overflow:hidden on each frame is what actually clips the portraits,
   because .person figure scales its img by 3.5% on hover and a radius
   on the img alone would let the corners escape the frame mid-transition.
   ============================================================ */
:root { --radius: clamp(10px, 1.1vw, 16px); --radius-sm: 8px; }

.person figure,
.dialog-figure,
.why-figure,
.dialog-trailer,
.shot-frame,
.profile-figure,
.profile-trailer,
.jcard {
  border-radius: var(--radius);
  overflow: hidden;
}
/* The image inside a clipped frame inherits the shape, but a bare image with
   no frame around it still needs its own. */
.person figure img,
.dialog-figure img,
.profile-figure img { border-radius: inherit; }

/* On a single-column dialog the figure sits flush against the body, so only
   the top corners should round or the seam reappears. */
@media (max-width: 640px) {
  .dialog-figure { border-radius: var(--radius) var(--radius) 0 0; }
}
/* Left column on desktop: round the outer edge, leave the inner one square
   where it meets the body. */
@media (min-width: 641px) {
  .dialog-figure { border-radius: var(--radius) 0 0 var(--radius); }
}

/* Matches the dialog nav: a dimmed arrow says "you are at the end" for free. */
.afterward .arrow[aria-disabled="true"] { opacity: 0.3; cursor: default; }
.afterward .arrow[aria-disabled="true"]:hover { color: var(--whisper); border-color: var(--hair); }

/* The alternative to the form, moved up beside the promise on 2026-08-01 so
   the other door sits where the decision is being made rather than in its
   own section further down. Quieter than the old standalone treatment: the
   form is the primary path and this must not compete with it. */
.inquire .or-write {
  margin-top: 14px;
  font-size: 15px;
  color: var(--whisper);
}
.inquire .or-write .address {
  font-family: var(--display);
  font-size: 17px;
  color: var(--blue);
  text-decoration: none;
  border-bottom: 1px solid var(--blue);
  padding-bottom: 1px;
  overflow-wrap: anywhere;
}

/* Formats and the outcome line, added 2026-08-01 when the offering widened
   past speaking. The label column is already set by .person-full p strong;
   these two only need to sit quieter than the topics line above them, since
   an organizer scans them rather than reads them. */
.person-full p + p,
.profile-bio p + p { margin-top: 10px; }


/* The honeypot: invisible to people, irresistible to bots. Positioned off
   canvas rather than display:none because some scripts skip hidden fields. */
.hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }


/* The journal's waiting state: one card, full width, quiet. It is replaced
   by real posts the moment the feed has any. */
.jcard-waiting { grid-column: 1 / -1; max-width: 62ch; }
