/* ===========================================================================
   hired.tools — the page and the product both in the app's light theme.

   Every token below is lifted verbatim from the light `:root` block of the
   product's globals.css, so the mocks further down are the app's own light
   theme rather than an approximation of it. `--page` is the one value with no
   counterpart in the app: it is a step deeper than `--background` so a product
   frame, which is the app's near-white, reads as a lit object on it.

   Screenshots dropped into the slots therefore have to be captured in light
   mode — see site/media/README.md. The app defaults to dark, so that means
   switching its theme before you shoot.

   Three things this file will not do, because the product doesn't:
   - use colour that isn't carrying information (the one exception is the stage
     rotation, which globals.css already licenses for marketing);
   - loop an animation (everything plays once, on entry, and then holds);
   - move at all for anyone who has asked their system to calm down.
   =========================================================================== */

:root {
  /* --- Surfaces. A stack, not a set of greys: page -> canvas -> card -> popover. */
  --page: oklch(0.955 0.002 265);
  --background: oklch(0.979 0.001 265);
  --canvas: oklch(0.962 0.002 265);
  --card: oklch(1 0 0);
  --popover: oklch(1 0 0);
  --inset: oklch(0.968 0.002 265);
  --rail-bg: oklch(0.968 0.002 265);

  /* --- Ink. Three levels: what you came to read, its label, its metadata. */
  --foreground: oklch(0.18 0.006 265);
  --muted: oklch(0.505 0.008 265);
  --faint: oklch(0.665 0.008 265);

  /* --- The one accent. */
  --primary: oklch(0.55 0.17 254);
  --primary-tint: oklch(0.96 0.019 253);
  --on-primary: oklch(1 0 0);

  /* Shifu Labs' signal orange, from shifulab.com. It belongs to the studio and
     not to Hired, so it is only ever worn by the studio's mark in the footer. */
  --signal: #ff4d00;

  --success: oklch(0.6 0.13 152);
  --warning: oklch(0.72 0.14 70);
  --destructive: oklch(0.58 0.21 25);

  /* --- The stage rotation. Hue turns one way as an application advances, so
         two chips read as "further along" without knowing the labels. */
  --stage-wishlist: oklch(0.6 0.012 265);
  --stage-applied: oklch(0.55 0.13 235);
  --stage-screen: oklch(0.53 0.15 268);
  --stage-interview: oklch(0.52 0.17 300);
  --stage-final: oklch(0.55 0.18 340);
  --stage-offer: oklch(0.58 0.14 68);
  --stage-accepted: oklch(0.55 0.13 152);
  --stage-rejected: oklch(0.55 0.19 25);
  --stage-wash: 12%;

  /* --- Overlays. Named rather than written inline, because "a bit of white on
         top" only works on a dark ground and this page now has both. */
  --wash: oklch(0 0 0 / 0.04);
  --rim-strong: oklch(0.8 0.004 265);
  --dot: oklch(0.86 0.004 265);
  --grid-line: oklch(0 0 0 / 0.05);

  /* --- The mark has no colour of its own: the tile is the page's ink and the
         three bars are cut out of it, so it inverts with the surface. */
  --brand-tile: var(--foreground);
  --brand-cut: var(--background);

  /* --- Elevation. The rim does the separating; the shadow says how far off
         the page. Many small stops read as light falling on an edge. */
  --rim: oklch(0.905 0.003 265);
  --shadow-hairline: 0 0 0 1px var(--rim);
  --shadow-card:
    0 0 0 1px var(--rim),
    0 1px 1.5px oklch(0 0 0 / 0.028),
    0 3px 6px oklch(0 0 0 / 0.022),
    0 8px 18px oklch(0 0 0 / 0.018);
  --shadow-raised:
    0 0 0 1px var(--rim),
    0 1px 2px oklch(0 0 0 / 0.04),
    0 4px 10px oklch(0 0 0 / 0.035),
    0 12px 26px oklch(0 0 0 / 0.03);
  --shadow-overlay:
    0 0 0 1px var(--rim),
    0 2px 4px oklch(0 0 0 / 0.05),
    0 8px 20px oklch(0 0 0 / 0.06),
    0 24px 56px oklch(0 0 0 / 0.09);
  --shadow-lift:
    0 0 0 1px oklch(0.885 0.003 265),
    0 2px 6px oklch(0 0 0 / 0.06),
    0 14px 32px oklch(0 0 0 / 0.08),
    0 38px 80px oklch(0 0 0 / 0.09);

  /* --- Radius by the size of the thing. */
  --r-chip: 6px;
  --r-control: 8px;
  --r-card: 10px;
  --r-panel: 14px;
  --r-frame: 18px;

  --sans: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* Two curves. Both decelerate hard and then coast, which is what makes a
     transition feel like an object settling rather than a value animating. */
  --settle: cubic-bezier(0.23, 1, 0.32, 1);
  --enter: cubic-bezier(0.16, 1, 0.3, 1);

  --gutter: 24px;
  --measure: 1280px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: 78px;
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--page);
  color: var(--foreground);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
[hidden] { display: none !important; }
img, svg, video { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: color-mix(in oklch, var(--primary) 26%, transparent); }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: color-mix(in oklch, var(--muted) 22%, transparent);
  border-radius: 999px;
  border: 4px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
  background: color-mix(in oklch, var(--muted) 38%, transparent);
  background-clip: content-box;
}

/* ---------------------------------------------------------------------------
   Type
   --------------------------------------------------------------------------- */

h1, h2, h3, h4 { font-weight: 600; letter-spacing: -0.018em; text-wrap: balance; }
h1 { letter-spacing: -0.03em; }

.eyebrow {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

.meta { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.nums { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }

.lede a { text-decoration: underline; text-decoration-color: color-mix(in oklch, currentColor 35%, transparent); text-underline-offset: 3px; transition: text-decoration-color 0.15s var(--settle); }
.lede a:hover { text-decoration-color: currentColor; }

.lede {
  color: var(--muted);
  font-size: 16.5px;
  line-height: 1.62;
  max-width: 58ch;
  text-wrap: pretty;
}

.h-display {
  font-size: clamp(34px, 6.4vw, 62px);
  line-height: 1.04;
  letter-spacing: -0.035em;
  font-weight: 600;
}

.h-section {
  font-size: clamp(25px, 3.4vw, 36px);
  line-height: 1.14;
  letter-spacing: -0.028em;
}

/* A phrase set in the accent, used at most once per section. */
.accent { color: var(--primary); }
.dim { color: var(--muted); }
.faint { color: var(--faint); }

/* ---------------------------------------------------------------------------
   Layout
   --------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap-narrow { max-width: 880px; }

section { position: relative; }

.band { padding-block: clamp(72px, 9vw, 128px); }
.band-tight { padding-block: clamp(52px, 6vw, 84px); }

/* The hairline that separates one band from the next: brightest in the middle,
   gone at the edges, so it reads as a fold rather than a border. */
.fold {
  height: 1px;
  border: 0;
  background: linear-gradient(90deg, transparent, var(--rim) 18%, var(--rim) 82%, transparent);
}

.section-head { max-width: 62ch; }
/* Long evidence beside a short argument: pin the argument so it is still
   there when the reader reaches the bottom of the evidence. */
@media (min-width: 900px) {
  .sticky-head { position: sticky; top: 108px; }
}
.section-head .eyebrow { margin-bottom: 14px; }
.section-head p { margin-top: 14px; }

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 10px 17px;
  border-radius: var(--r-control);
  font-size: 13.5px;
  font-weight: 500;
  white-space: nowrap;
  transition:
    background-color 0.16s var(--settle),
    box-shadow 0.16s var(--settle),
    transform 0.16s var(--settle),
    color 0.16s var(--settle);
}
.btn svg { width: 15px; height: 15px; flex-shrink: 0; }
.btn:active { transform: translateY(0.5px); }

.btn-primary {
  background: var(--primary);
  color: var(--on-primary);
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--primary) 70%, black),
    0 1px 2px oklch(0 0 0 / 0.3),
    0 6px 20px color-mix(in oklch, var(--primary) 24%, transparent);
}
.btn-primary:hover {
  background: color-mix(in oklch, var(--primary) 88%, white);
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--primary) 70%, black),
    0 1px 2px oklch(0 0 0 / 0.3),
    0 8px 28px color-mix(in oklch, var(--primary) 34%, transparent);
}

.btn-ghost { box-shadow: var(--shadow-hairline); color: var(--foreground); }
.btn-ghost:hover { background: var(--wash); box-shadow: 0 0 0 1px var(--rim-strong); }

.btn-quiet { color: var(--muted); padding-inline: 10px; }
.btn-quiet:hover { color: var(--foreground); }

.btn-sm { padding: 7px 13px; font-size: 13px; }

/* ---------------------------------------------------------------------------
   Chips, pills, code
   --------------------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: var(--r-chip);
  font-size: 11.5px;
  font-weight: 500;
  box-shadow: var(--shadow-hairline);
  color: var(--muted);
}

/* A stage, wearing its colour. Set --tone and this handles the rest — exactly
   the same one-declaration trick the app uses. */
.stage-chip {
  color: var(--tone);
  background-color: color-mix(in oklch, var(--tone) var(--stage-wash), transparent);
}

.mono-tag {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--muted);
  padding: 4px 8px;
  border-radius: var(--r-chip);
  background: var(--inset);
  box-shadow: var(--shadow-hairline);
  white-space: nowrap;
}

pre, code { font-family: var(--mono); }

.code {
  background: var(--inset);
  border-radius: var(--r-control);
  box-shadow: var(--shadow-hairline);
  padding: 13px 15px;
  overflow-x: auto;
  font-size: 12px;
  line-height: 1.75;
  color: var(--foreground);
  tab-size: 2;
}
.code .c { color: var(--faint); }
.code .k { color: var(--stage-screen); }
.code .s { color: var(--success); }

/* ---------------------------------------------------------------------------
   Motion primitives

   One observer adds .in when an element first crosses into view; everything
   else is a transition off that class. Nothing loops, nothing replays, and the
   media query at the bottom of this file turns all of it off.
   --------------------------------------------------------------------------- */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.62s var(--enter),
    transform 0.62s var(--enter);
  transition-delay: calc(var(--i, 0) * 65ms);
}
.js [data-reveal].in { opacity: 1; transform: none; }

.js [data-reveal="scale"] { transform: translateY(20px) scale(0.985); }
.js [data-reveal="scale"].in { transform: none; }

.js [data-reveal="left"] { transform: translateX(-16px); }
.js [data-reveal="left"].in { transform: none; }

.js [data-reveal="right"] { transform: translateX(16px); }
.js [data-reveal="right"].in { transform: none; }

/* A rule that draws itself. Used under section headings and inside mocks. */
.js [data-reveal="rule"] {
  opacity: 1;
  transform: none;
  transform-origin: left;
  scale: 0 1;
  transition: scale 0.85s var(--enter);
  transition-delay: calc(var(--i, 0) * 65ms);
}
.js [data-reveal="rule"].in { scale: 1 1; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  .js [data-reveal] { opacity: 1 !important; transform: none !important; scale: none !important; }
}

/* ===========================================================================
   THE APP FRAME

   Everything below draws the product rather than describing it. The rule for
   this whole block: if a number here disagrees with src/app/globals.css or a
   component in src/components/, globals.css wins and this is the bug.
   =========================================================================== */

.frame {
  position: relative;
  border-radius: var(--r-frame);
  background: var(--background);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
  isolation: isolate;
}

/* Window chrome. Enough of a browser to say "this is the app", not so much
   that it becomes a drawing of Chrome. */
.frame-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 40px;
  background: var(--canvas);
  box-shadow: inset 0 -1px 0 var(--rim);
}
.frame-dots { display: flex; gap: 6px; }
.frame-dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--dot);
}
.frame-url {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: center;
}
.frame-url span {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
  background: var(--inset);
  border-radius: 999px;
  padding: 3px 14px;
  box-shadow: var(--shadow-hairline);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.frame-body { display: flex; min-height: 0; min-width: 0; }

/* The host clips; motion.js sets its height to the scaled height of the
   drawing inside it. Without scripting the drawing is simply fluid. */
.fit-host { position: relative; overflow: hidden; }

/* When the drawing is wider than the frame — a phone looking at a 1440px
   screen — the frame scrolls rather than shrinking the type into a smudge. */
.fit-host.pannable {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.fit-host.pannable::-webkit-scrollbar { display: none; }
.frame:has(.pannable) .frame-bar::after {
  content: "drag to look around";
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--faint);
  white-space: nowrap;
}
.js [data-fit] { transform-origin: top left; }

/* The rail. Five destinations, in the app's order. */
.rail {
  width: 240px;
  flex-shrink: 0;
  background: var(--rail-bg);
  box-shadow: inset -1px 0 0 var(--rim);
  padding: 12px 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.rail-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px 6px;
  font-size: 13.5px;
  font-weight: 600;
}
.rail-tagline { padding: 0 6px 12px; font-size: 11px; color: var(--faint); }
.rail-search {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: var(--r-control);
  background: var(--inset);
  box-shadow: var(--shadow-hairline);
  font-size: 12px;
  color: var(--faint);
}
.rail-search svg { width: 13px; height: 13px; }
.rail-search .k { margin-left: auto; font-family: var(--mono); font-size: 10px; }
.rail .rail-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 8px;
  border-radius: var(--r-control);
  font-size: 12.5px;
  color: var(--muted);
  transition: background-color 0.15s var(--settle), color 0.15s var(--settle);
}
.rail .rail-item.on { background: var(--wash); color: var(--foreground); font-weight: 500; }
.rail-item svg { width: 14px; height: 14px; opacity: 0.85; }
.rail-spacer { flex: 1; }

.pane {
  flex: 1;
  min-width: 0;
  padding: 20px 24px 24px;
  background: var(--background);
}

.pane-head { display: flex; align-items: flex-end; gap: 12px; margin-bottom: 16px; }
.pane-head .pane-title { font-size: 19px; font-weight: 600; letter-spacing: -0.02em; }
.pane-head .eyebrow { margin-bottom: 3px; }

/* --- Cards inside the app ------------------------------------------------- */

.app-card {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
}

.stat {
  padding: 12px 14px 13px;
}
.stat-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 500;
  color: var(--muted);
}
.stat-label svg { width: 12px; height: 12px; color: var(--faint); }
.stat-value {
  margin-top: 6px;
  font-size: 26px;
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.stat-hint { margin-top: 6px; font-size: 11.5px; color: var(--faint); }

.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

/* --- The pipeline board --------------------------------------------------- */

.board-wrap { position: relative; }
.board-wrap::after {
  content: "";
  position: absolute;
  inset-block: 0;
  right: 0;
  width: 104px;
  pointer-events: none;
  background: linear-gradient(to left, var(--background) 34%, transparent);
}

.board {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 6px;
  scrollbar-width: none;
}
.board::-webkit-scrollbar { display: none; }

.col { display: flex; flex-direction: column; width: 256px; flex-shrink: 0; }
.col-head { display: flex; align-items: center; gap: 7px; padding: 0 4px; margin-bottom: 8px; }
.col-head .stage-chip {
  padding: 2px 6px;
  border-radius: var(--r-chip);
  font-size: 12px;
  font-weight: 600;
}
.col-head .count { font-family: var(--mono); font-size: 12px; color: var(--faint); }
.col-body {
  background: var(--canvas);
  border-radius: 12px;
  box-shadow: var(--shadow-hairline);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 176px;
  flex: 1;
  transition: background-color 0.2s var(--settle), box-shadow 0.2s var(--settle);
}
.col-body.hot {
  background: var(--primary-tint);
  box-shadow: 0 0 0 1px var(--primary);
}
.col-empty {
  flex: 1;
  display: grid;
  place-items: center;
  font-size: 11.5px;
  color: var(--faint);
}

/* A stripe of the stage's colour down the edge, so a column reads as one thing
   at a glance and a mis-dropped card is obvious. */
.app-row {
  position: relative;
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  padding: 12px 12px 12px 14px;
  overflow: hidden;
}
.app-row::before {
  content: "";
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 3px;
  background: var(--tone);
}
.app-row-top { display: flex; align-items: flex-start; gap: 8px; }
.app-row .co { font-size: 13px; font-weight: 600; }
.app-row .role { font-size: 12px; color: var(--faint); }
.app-row-meta {
  margin-top: 8px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  font-size: 11px;
  color: var(--muted);
}
.app-row-meta span { display: inline-flex; align-items: center; gap: 4px; }
.app-row-meta svg { width: 10px; height: 10px; }
.app-row-foot {
  margin-top: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--muted);
}
.app-row-foot .right { margin-left: auto; display: flex; align-items: center; gap: 7px; }
.app-row-foot .overdue { color: var(--destructive); font-weight: 500; }

/* The company monogram, with a stable hue per name — decoration under a chip
   that is doing the actual work. */
.mono-av {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: var(--r-chip);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: oklch(0.5 0.075 var(--hue));
  background: oklch(0.945 0.028 var(--hue));
  user-select: none;
}
.mono-av.lg { width: 28px; height: 28px; font-size: 11px; }

/* A company that has a mark wears it; one that doesn't keeps the initials
   tile. That is what the product itself does, so the mocks show both — the
   invented companies in this data have no favicon to fetch, and neither does a
   real one the user has only just typed in. The tinted ground is dropped for a
   logo: the marks bring their own, and two grounds fight. */
.mono-av.logo { background: var(--inset); padding: 3px; }
.mono-av.logo img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* A hairline table. Column gaps would break the rules into dashes, so the
   spacing is padding on the cells and the rule runs the width of the row. */
.tbl { display: grid; font-size: 12.5px; }
.tbl > * {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 11px 16px 11px 0;
  box-shadow: inset 0 1px 0 var(--rim);
}
.tbl > .th { padding: 0 16px 9px 0; box-shadow: none; }
.tbl .num { justify-content: flex-end; font-variant-numeric: tabular-nums; padding-right: 0; }
.tbl .dim { color: var(--muted); }
.tbl .none { color: var(--faint); }

/* Highlight strength, as the app draws it: five marks, the lit ones in amber. */
.stars { flex-shrink: 0; letter-spacing: 0.06em; font-size: 11px; line-height: 1.55; color: var(--warning); }
.stars i { font-style: normal; color: var(--faint); }

/* --- The funnel and the diagnosis ---------------------------------------- */

.funnel-row { display: flex; align-items: center; gap: 10px; padding: 5px 7px; border-radius: var(--r-control); }
.funnel-row .step { width: 168px; flex-shrink: 0; font-size: 12.5px; color: var(--muted); }
.funnel-row .of { width: 62px; flex-shrink: 0; font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.funnel-row .rate { width: 40px; flex-shrink: 0; text-align: right; font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.funnel-row.weak .rate { font-weight: 600; color: var(--tone); }
.funnel-row .track {
  position: relative;
  flex: 1;
  min-width: 0;
  height: 6px;
  border-radius: 999px;
  background: var(--inset);
  overflow: hidden;
}
.funnel-row .track i {
  position: absolute;
  inset-block: 0;
  left: 0;
  border-radius: 999px;
  background: var(--tone);
  width: var(--w, 0%);
  transform-origin: left;
  transition: scale 0.9s var(--enter);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.js [data-grow] .funnel-row .track i { scale: 0 1; }
.js [data-grow].in .funnel-row .track i { scale: 1 1; }
.funnel-row .median { width: 78px; flex-shrink: 0; text-align: right; font-size: 11.5px; color: var(--faint); font-variant-numeric: tabular-nums; }

/* Six weeks of volume, this week on the right. */
.velocity { display: flex; align-items: flex-end; gap: 6px; height: 46px; max-width: 240px; }
.velocity div { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; justify-content: flex-end; }
.velocity span.n { font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }
.velocity i {
  width: 100%;
  border-radius: 3px 3px 0 0;
  background: var(--stage-screen);
  height: var(--h, 4px);
  transform-origin: bottom;
  transition: scale 0.7s var(--enter);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.velocity i.now { background: var(--primary); }
.js [data-grow] .velocity i { scale: 1 0; }
.js [data-grow].in .velocity i { scale: 1 1; }

/* Highlight strength, as the app draws it: five marks, the lit ones in amber. */
.stars { flex-shrink: 0; letter-spacing: 0.06em; font-size: 11px; line-height: 1.5; color: var(--warning); }
.stars i { font-style: normal; color: var(--faint); }

/* --- The resume paper ----------------------------------------------------- */

/* Deliberately untouched by the theme. This is a printed document, and it is
   white with black text wherever it is rendered. */
.sheet { container-type: inline-size; width: 100%; }

/* A sheet cropped to a band, fading out rather than being cut — the page
   plainly continues, which is truer than pretending it ends there. */
.sheet-crop {
  max-height: 430px;
  overflow: hidden;
  mask-image: linear-gradient(to bottom, black 74%, transparent);
  -webkit-mask-image: linear-gradient(to bottom, black 74%, transparent);
}

.paper {
  background: #ffffff;
  color: #16181d;
  font-family: Tinos, "Times New Roman", "Liberation Serif", "Nimbus Roman", Times, serif;
  --paper-accent: #16181d;
  aspect-ratio: 8.5 / 11;
  overflow: hidden;
  box-shadow: var(--shadow-lift);
  border-radius: 3px;
  padding: 5.6cqw;
  /* True scale would be 1.63cqw — 10pt on an 8.5in page. Nudged up because a
     preview nobody can read is a grey rectangle, and this one is meant to be
     recognisable as a document. */
  font-size: 1.94cqw;
  line-height: 1.35;
}
.paper .rp-name { font-size: 1.1em; font-weight: 700; line-height: 1.2; }
.paper .rp-sec { font-size: 1.1em; font-weight: 700; line-height: 1.25; text-align: center; }
.paper .rule { border-bottom: 1px solid var(--paper-accent); margin-top: 0.1em; }
.paper .center { text-align: center; }
.paper .entry { display: flex; justify-content: space-between; gap: 1em; }
.paper .entry b { font-weight: 700; }
.paper .entry span:last-child { white-space: nowrap; }
.paper ul { list-style: disc; margin-left: 0.25in; padding-left: 0.25in; }
.paper li { margin: 0; }
.paper section { margin-top: 0.85em; }
.paper .contacts { margin-top: 0.55em; display: flex; flex-wrap: wrap; justify-content: center; column-gap: 0.42em; }

/* --- The transcript ------------------------------------------------------- */

.tape { display: flex; flex-direction: column; gap: 14px; }

.turn { display: flex; gap: 11px; }
.turn .who {
  flex-shrink: 0;
  width: 46px;
  padding-top: 2px;
  text-align: right;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}
.turn .said { min-width: 0; flex: 1; font-size: 13.5px; color: var(--muted); }
.turn.you .said { color: var(--foreground); }

/* Tool calls, as they appear: name, then a tick when it returns. */
.calls { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.call {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--muted);
  background: var(--inset);
  box-shadow: var(--shadow-hairline);
  border-radius: var(--r-chip);
  padding: 3px 8px;
  transition: opacity 0.4s var(--enter), transform 0.4s var(--enter), color 0.3s linear;
}
.js .call { opacity: 0; transform: translateY(4px); }
.js .call.in { opacity: 1; transform: none; }
.call i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--faint);
  transition: background-color 0.3s linear;
}
.call.done i { background: var(--success); }

/* A call that came back with nothing. The dot goes amber rather than green,
   because "no evidence" is a real answer and the page should say so. */
.call.empty.done { color: var(--warning); }
.call.empty.done i { background: var(--warning); }

/* The caret that trails typed text. It is the one thing on the page that
   blinks, and it stops when the line finishes. */
.caret {
  display: inline-block;
  width: 1px;
  height: 1.05em;
  vertical-align: -0.16em;
  margin-left: 1px;
  background: var(--primary);
  animation: blink 1.05s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---------------------------------------------------------------------------
   Screenshot and video slots

   Every mock on this page is a real, rendered fallback. Drop a file into
   site/media/ named after the slot and motion.js swaps it in on load — so an
   empty media/ folder is a complete page, not a page full of grey boxes.
   See site/media/README.md.
   --------------------------------------------------------------------------- */

.shot { position: relative; margin: 0; }
.shot > img, .shot > video { width: 100%; height: auto; border-radius: inherit; }

/* Only visible when you add ?slots to the URL — the guide to where art goes. */
.shot::after {
  content: attr(data-shot);
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 3;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--primary);
  background: color-mix(in oklch, var(--background) 88%, transparent);
  box-shadow: 0 0 0 1px var(--primary);
  border-radius: var(--r-chip);
  padding: 2px 7px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s linear;
}
body.show-slots .shot::after { opacity: 1; }
body.show-slots .shot { outline: 1px dashed color-mix(in oklch, var(--primary) 55%, transparent); outline-offset: 3px; }

/* ===========================================================================
   PAGE CHROME
   =========================================================================== */

/* The header is a floating capsule, not an edge-to-edge bar. Full width put
   the links six hundred pixels from the brand and left 42% of the row empty at
   1440; a contained pill has no void to leave. It stays sticky rather than
   fixed so it keeps its space in the flow and the hero needs no offset. */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  padding-block: 12px;
  transition: padding-block 0.25s var(--settle);
}
.nav-rail { position: relative; padding-inline: var(--gutter); }

/* A floating pill leaves a see-through strip above it, and scrolled content
   was appearing in that strip clipped by the top of the viewport. This is the
   ground the page dissolves into before it gets there: opaque at the very top,
   gone by just below the pill. Only once scrolled — at rest there is nothing
   behind it to hide. */
.nav::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  /* Opaque down to roughly the bottom of the pill, then a long fade. A gradient
     that starts thinning immediately leaves a legible ghost of the heading
     scrolling past above the pill, which reads as a bug rather than an effect. */
  height: calc(100% + 40px);
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    var(--page) 0%,
    var(--page) 55%,
    transparent 100%
  );
  opacity: 0;
  transition: opacity 0.25s var(--settle);
}
.nav.stuck::before { opacity: 1; }

/* Three tracks, not a flex row: 1fr auto 1fr puts the links on the true centre
   of the pill however wide the brand and the actions grow. margin-left:auto
   would only ever push them up against the right-hand group. */
.nav-inner {
  max-width: 1080px;
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
  height: 56px;
  /* Asymmetric on purpose. A 999px radius curves in about five pixels at the
     height of the button's corners, so the right side needs more clearance
     than the left, where only text sits. */
  padding-inline: 20px 14px;
  border-radius: 999px;
  background: color-mix(in oklch, var(--card) 72%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  box-shadow: var(--shadow-hairline);
  transition:
    height 0.25s var(--settle),
    background-color 0.25s var(--settle),
    box-shadow 0.25s var(--settle);
}

/* Scrolled: the pill tightens, settles onto the page and stops being see-through. */
.nav.stuck { padding-block: 8px; }
.nav.stuck .nav-inner {
  height: 50px;
  background: color-mix(in oklch, var(--card) 92%, transparent);
  box-shadow: var(--shadow-card);
}

/* justify-self, or the brand stretches across its whole 1fr track and half the
   pill becomes a link to the home page. */
.brand { display: flex; align-items: center; justify-self: start; gap: 9px; font-size: 15px; font-weight: 600; letter-spacing: -0.015em; }
.brand svg { border-radius: 6px; }

.nav-links { display: flex; align-items: center; gap: 2px; }
.nav-acts { display: flex; align-items: center; justify-self: end; gap: 6px; }
.nav-login { white-space: nowrap; }

/* Scoped to the header rather than to .nav-links, because the same link style
   is wanted on "Log in" over in the actions group. */
.nav-inner a.link {
  padding: 7px 11px;
  border-radius: var(--r-control);
  font-size: 13.5px;
  color: var(--muted);
  transition: color 0.15s var(--settle), background-color 0.15s var(--settle);
}
.nav-inner a.link:hover { color: var(--foreground); background: var(--wash); }
/* Which section you are actually in — aria-current="true" set by motion.js as you
   scroll, aria-current="page" written into the markup on a subpage. Either way
   the marker is announced rather than only drawn. */
.nav-inner a.link[aria-current],
.nav-sheet a[aria-current] { color: var(--foreground); background: var(--wash); }

/* ---------------------------------------------------------------------------
   The small-screen menu
   A <details>, so it opens and closes and takes keyboard focus without a line
   of JavaScript. Below 720px it replaces both link rows; above, it is not
   rendered at all.
   --------------------------------------------------------------------------- */

.nav-menu { display: none; position: relative; }
.nav-menu summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-control);
  color: var(--muted);
  cursor: pointer;
}
.nav-menu summary::-webkit-details-marker { display: none; }
.nav-menu summary:hover { color: var(--foreground); background: var(--wash); }
.nav-menu[open] summary { color: var(--foreground); background: var(--wash); }

.nav-sheet {
  position: absolute;
  /* Pulled out to the pill's own edge rather than the button's, so the sheet
     hangs flush under the capsule instead of nine pixels inside it. */
  right: -9px;
  top: calc(100% + 8px);
  min-width: 208px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-overlay);
}
.nav-sheet a {
  padding: 9px 11px;
  border-radius: var(--r-control);
  font-size: 14px;
  color: var(--muted);
}
.nav-sheet a:hover { color: var(--foreground); background: var(--wash); }
.nav-sheet .fold { margin: 6px 0; }
.nav-sheet .btn { margin-top: 2px; justify-content: center; color: var(--on-primary); }
.nav-sheet .btn:hover { color: var(--on-primary); }

/* Icon only in the pill. The word "GitHub" beside a mono star count made it a
   third button competing with the two that matter; the count moved to the
   footer, where a live number is a nice detail rather than a distraction. */
.gh {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--r-control);
  color: var(--muted);
  transition: color 0.15s var(--settle), background-color 0.15s var(--settle);
}
.gh:hover { color: var(--foreground); background: var(--wash); }
.gh svg { width: 15px; height: 15px; fill: currentColor; }

/* The star count, beside the footer's GitHub link. Ships hidden; motion.js
   reveals it only if the number actually arrives. */
.stars {
  display: inline-block;
  margin-left: 5px;
  padding: 1px 6px;
  border-radius: var(--r-chip);
  box-shadow: var(--shadow-hairline);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
}

/* The scroll progress line, wearing the stage rotation. It is the only place
   on the page where all six hues appear at once, and it doubles as the motif. */
.progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 60;
  background: linear-gradient(
    90deg,
    var(--stage-wishlist),
    var(--stage-applied) 20%,
    var(--stage-screen) 40%,
    var(--stage-interview) 60%,
    var(--stage-final) 80%,
    var(--stage-offer)
  );
  transform-origin: left;
  scale: var(--p, 0) 1;
  pointer-events: none;
}

/* Where the browser can drive an animation from the scroll position itself,
   let it: the bar stops depending on a scroll listener writing a custom
   property every frame, and runs off the main thread. motion.js checks the
   same support and skips its own version, so only one of the two ever runs.
   Everything else falls back to the JS, which is unchanged. */
@supports (animation-timeline: scroll()) {
  .progress {
    scale: 0 1;
    animation-name: progress-fill;
    animation-duration: auto;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }
  @keyframes progress-fill {
    from { scale: 0 1; }
    to { scale: 1 1; }
  }
}

.motif { display: flex; height: 3px; border-radius: 2px; overflow: hidden; }
.motif i { flex: 1; }

/* ===========================================================================
   HERO
   =========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(52px, 7vw, 92px) clamp(48px, 6vw, 80px);
}

/* A single soft light behind the headline, masked to nothing at the edges.
   Not a gradient mesh — one source, one direction, the way the app's rim
   highlight implies light coming from above. */
.hero-glow {
  position: absolute;
  inset: -70px 0 auto;
  height: 860px;
  z-index: -1;
  pointer-events: none;
  /* On a light ground the same light source has to be much weaker: a colour
     that reads as a glow against near-black reads as a stain against paper. */
  background:
    radial-gradient(50% 46% at 34% 28%, color-mix(in oklch, var(--primary) 13%, transparent), transparent 72%),
    radial-gradient(46% 46% at 68% 12%, color-mix(in oklch, var(--stage-interview) 11%, transparent), transparent 74%),
    radial-gradient(34% 36% at 96% 40%, color-mix(in oklch, var(--stage-final) 8%, transparent), transparent 76%);
  mask-image: linear-gradient(to bottom, black, black 42%, transparent 94%);
  -webkit-mask-image: linear-gradient(to bottom, black, black 42%, transparent 94%);
}

/* The grid it sits on. Faint enough to read as texture rather than as a chart. */
.hero-grid {
  position: absolute;
  inset: 0 0 auto;
  height: 620px;
  z-index: -2;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(82% 66% at 46% 18%, black, transparent 76%);
  -webkit-mask-image: radial-gradient(82% 66% at 46% 18%, black, transparent 76%);
}

/* The copy block is centred and the product shots below it are not: the text
   is one column of statement, the shots are two columns of evidence. Centring
   the statement is what stops a wide screen reading as a left-hand margin with
   a lot of nothing to the right of it. */
.hero-lead { text-align: center; display: flex; flex-direction: column; align-items: center; }

.hero-copy { max-width: 22ch; }
.hero .lede { margin-top: 18px; max-width: 54ch; }
.hero-ctas { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }
.hero-note { margin-top: 16px; font-size: 12.5px; color: var(--faint); display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 12px; }
.hero-note .sep { color: var(--rim); }
.hero-note .works { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.hero-note .works .c {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px 3px 6px;
  border-radius: 999px;
  background: var(--card);
  box-shadow: var(--shadow-hairline);
  color: var(--muted);
  font-size: 12px;
}
.hero-note .works .mark { width: 16px; height: 16px; border-radius: 3px; }
.hero-note b { color: var(--muted); font-weight: 500; }
.hero-note a { text-decoration: underline; text-decoration-color: var(--rim); text-underline-offset: 3px; transition: color 0.15s var(--settle); }
.hero-note a:hover { color: var(--muted); text-decoration-color: currentColor; }

/* The badge above the headline — a real link to the thing it names. */

/* The two-up: the conversation on the left, what it did on the right. */
/* The hero's two shots lean back on one plane, so they read as a surface
   receding into the page rather than two flat cards pasted on it. Perspective
   sits on the wrap and the transform on the stage, so both panels share a
   single vanishing point — tilting each child on its own origin makes them
   diverge. Desktop only: at phone widths the shots are already the whole
   screen and a tilt just eats legibility.

   The angles are deliberately gentler than the reference this came from. That
   one tilts a single static screenshot; the left panel here is a transcript
   that types itself out and is meant to be read. --tilt-x / --tilt-skew are
   here to be argued with. */
@media (min-width: 900px) {
  .hero .wrap { perspective: 1600px; }
  .hero .stage {
    --tilt-x: 13deg;
    --tilt-skew: 0.1rad;
    transform: rotateX(var(--tilt-x)) skewX(var(--tilt-skew));
    transform-origin: 50% 0%;
    -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);
  }

  /* Scrubbed by scroll position, not played on a timer: the shots lean back
     when you land and stand up as you scroll past them, so the tilt reads as
     something the page is doing rather than a static flourish. Driven from the
     document's own scroll rather than view(), because the stage is already
     partly on screen at load and a view() range would start mid-animation.

     This is the page's third kind of motion. The other two are "plays once on
     entry and holds" and "does not move at all"; this one has no duration and
     no direction of its own — it only ever reflects where the scrollbar is,
     and it reverses exactly as faithfully when you scroll back up. It is
     behind prefers-reduced-motion, so the calm path keeps the static tilt. */
  @supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
      .hero .stage {
        animation-name: stage-settle;
        animation-duration: auto;
        animation-timing-function: linear;
        animation-fill-mode: both;
        animation-timeline: scroll(root block);
        animation-range: 0 65vh;
      }
      @keyframes stage-settle {
        from { transform: rotateX(var(--tilt-x)) skewX(var(--tilt-skew)); }
        to { transform: rotateX(0deg) skewX(0rad); }
      }
    }
  }
}

.stage {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 16px;
  margin-top: clamp(40px, 5vw, 64px);
  align-items: stretch;
}

.panel {
  background: var(--canvas);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  padding: 18px;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 14px;
  margin-bottom: 14px;
  box-shadow: inset 0 -1px 0 var(--rim);
}
.panel-head .eyebrow { margin-right: auto; }
.panel-head .dotline { display: flex; gap: 5px; }
.panel-head .dotline i { width: 6px; height: 6px; border-radius: 50%; background: var(--dot); }

/* ===========================================================================
   CLIENT STRIP
   =========================================================================== */


/* Each client's own mark, at its own ground. Rounded to one radius so icons
   drawn to different shapes read as a row rather than as loose stickers.
   Shared by the hero's chips and the connect section's tabs. */
.mark {
  width: 18px;
  height: 18px;
  border-radius: 5px;
  flex-shrink: 0;
  object-fit: contain;
}

/* ===========================================================================
   BENTO — the four parts
   =========================================================================== */

.bento {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
}
.cell {
  position: relative;
  grid-column: span 3;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  padding: 20px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.25s var(--settle);
}
.cell:hover { box-shadow: var(--shadow-raised); }
.cell.wide { grid-column: span 6; }
.cell.third { grid-column: span 2; }

.cell-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--tone); margin-bottom: 11px; }
.cell h3 { font-size: 15px; margin-bottom: 6px; }
.cell p { font-size: 13.5px; color: var(--muted); }
.cell .art { margin-top: 16px; }

/* ===========================================================================
   THE TOUR — sticky chapters
   =========================================================================== */

/* One measure for the whole page, so every section starts at the same left
   edge. The chapter list is a sticky bar rather than a rail for the same
   reason: a 210px rail would have pushed the product shots into a column too
   narrow to be shots of anything. */
.tour { display: block; }

.chapters {
  position: sticky;
  top: 54px;
  z-index: 20;
  display: flex;
  gap: 4px;
  margin-bottom: 40px;
  padding: 8px 0;
  background: color-mix(in oklch, var(--page) 93%, transparent);
  backdrop-filter: saturate(180%) blur(22px);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  box-shadow: inset 0 -1px 0 var(--rim);
  overflow-x: auto;
  scrollbar-width: none;
}
.chapters::-webkit-scrollbar { display: none; }

.chapter {
  position: relative;
  flex: 1 1 0;
  min-width: 168px;
  text-align: left;
  padding: 11px 14px 13px;
  border-radius: var(--r-card) var(--r-card) 0 0;
  transition: background-color 0.25s var(--settle);
}
.chapter::before {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 0;
  height: 2px;
  border-radius: 999px;
  background: var(--tone);
  scale: 0 1;
  opacity: 0;
  transform-origin: left;
  transition: scale 0.4s var(--enter), opacity 0.25s linear;
}
.chapter.on { background: var(--wash); }
.chapter.on::before { scale: 1 1; opacity: 1; }
.chapter .ct { display: block; font-size: 14px; font-weight: 600; letter-spacing: -0.012em; color: var(--muted); transition: color 0.25s var(--settle); }
.chapter.on .ct { color: var(--foreground); }
.chapter p { font-size: 12.5px; color: var(--faint); margin-top: 3px; line-height: 1.45; }

.scenes { display: flex; flex-direction: column; gap: clamp(56px, 8vw, 104px); min-width: 0; }
.scene { scroll-margin-top: 46px; min-width: 0; }
.scene-note {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* ===========================================================================
   WHAT YOU SAY

   The tool catalogue is the proof, not the pitch. This is the pitch: six
   sentences a person would actually say, and what exists afterwards.
   =========================================================================== */

.says {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
  gap: 12px;
}

.say {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  padding: 20px 22px;
  transition: box-shadow 0.25s var(--settle);
}
.say:hover { box-shadow: var(--shadow-raised); }

.say .q {
  font-size: 16.5px;
  line-height: 1.45;
  letter-spacing: -0.012em;
  text-wrap: pretty;
}
.say .q::before { content: "\201C"; color: var(--faint); }
.say .q::after { content: "\201D"; color: var(--faint); }

.say .then {
  display: flex;
  gap: 9px;
  margin-top: 12px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
  flex: 1;
}
.say .then svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 3px; color: var(--tone); }

.say .via {
  margin-top: 16px;
  padding-top: 12px;
  box-shadow: inset 0 1px 0 var(--rim);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--faint);
}

/* The catalogue, folded away. It is for the person who wants to check, and it
   should not be the first thing anybody has to read. */
.under { margin-top: 36px; }
.under > summary {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
  list-style: none;
  padding: 9px 15px;
  border-radius: var(--r-control);
  box-shadow: var(--shadow-hairline);
  font-size: 13.5px;
  color: var(--muted);
  transition: color 0.15s var(--settle), box-shadow 0.15s var(--settle);
}
.under > summary::-webkit-details-marker { display: none; }
.under > summary:hover { color: var(--foreground); box-shadow: 0 0 0 1px var(--rim-strong); }
.under > summary svg { width: 13px; height: 13px; transition: transform 0.25s var(--settle); }
.under[open] > summary svg { transform: rotate(90deg); }
.under .inner { margin-top: 26px; }

/* ===========================================================================
   THE TOOL CATALOGUE
   =========================================================================== */

.tools-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 18px; }

.filter {
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12.5px;
  color: var(--muted);
  box-shadow: var(--shadow-hairline);
  transition: color 0.15s var(--settle), box-shadow 0.15s var(--settle), background-color 0.15s var(--settle);
}
.filter:hover { color: var(--foreground); }
.filter.on {
  color: var(--tone, var(--foreground));
  background: color-mix(in oklch, var(--tone, var(--primary)) 15%, transparent);
  box-shadow: 0 0 0 1px color-mix(in oklch, var(--tone, var(--primary)) 45%, transparent);
}

.search {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--inset);
  box-shadow: var(--shadow-hairline);
  min-width: 210px;
}
.search svg { width: 13px; height: 13px; color: var(--faint); flex-shrink: 0; }
.search input {
  flex: 1;
  min-width: 0;
  background: none;
  border: 0;
  outline: 0;
  color: var(--foreground);
  font-family: var(--mono);
  font-size: 12px;
}
.search input::placeholder { color: var(--faint); }

.tool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
  gap: 8px;
}
.tool {
  --tone: var(--faint);
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-hairline);
  padding: 11px 13px;
  transition: box-shadow 0.18s var(--settle), background-color 0.18s var(--settle);
}
.tool:hover { box-shadow: var(--shadow-card); background: var(--popover); }
.tool.gone { display: none; }
.tool .n {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--foreground);
}
.tool .n i { width: 5px; height: 5px; border-radius: 50%; background: var(--tone); flex-shrink: 0; }
.tool .d { margin-top: 5px; font-size: 12px; line-height: 1.5; color: var(--faint); }
.tool.flow { background: var(--canvas); box-shadow: 0 0 0 1px color-mix(in oklch, var(--tone) 30%, transparent); }

.tools-count { font-family: var(--mono); font-size: 12px; color: var(--faint); margin-top: 14px; }
.tools-empty { display: none; padding: 26px 0; font-size: 13.5px; color: var(--muted); }
.tools-empty.on { display: block; }

/* ===========================================================================
   DOORS, FAQ, FOOTER
   =========================================================================== */

/* ---------------------------------------------------------------------------
   REQUEST ACCESS
   Hosting is invite-only, so the primary action on this page is an email
   address rather than a sign-up. One form, used twice — hero and close — and
   posted to the instance by motion.js without leaving the page.
   --------------------------------------------------------------------------- */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.joinform { width: 100%; max-width: 480px; }
.joinform-row { display: flex; flex-wrap: wrap; gap: 8px; }
.joinform input[type="email"] {
  flex: 1 1 210px;
  min-width: 0;
  padding: 11px 14px;
  font: inherit;
  font-size: 14px;
  color: var(--foreground);
  background: var(--card);
  border: 1px solid var(--rim);
  border-radius: var(--r-control);
  transition: border-color 0.16s var(--settle), box-shadow 0.16s var(--settle);
}
.joinform input[type="email"]::placeholder { color: var(--faint); }
.joinform input[type="email"]:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}
.joinform button[type="submit"] { flex: 0 0 auto; }
.joinform button[disabled] { opacity: 0.6; pointer-events: none; }

/* The honeypot. Moved off-screen rather than display:none, because a bot that
   skips hidden inputs will still fill a positioned one. */
.joinform .hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.joinform-note { margin-top: 11px; font-size: 12.5px; color: var(--faint); text-wrap: balance; }
.joinform-said { margin-top: 11px; font-size: 13px; color: var(--muted); }
.joinform-said:empty { display: none; }
.joinform-said.bad { color: var(--destructive); }

/* Once it has gone through, the form is replaced by its own answer rather than
   cleared — there is nothing useful left to do with it. */
.joinform.done .joinform-row,
.joinform.done .joinform-note { display: none; }
.joinform.done .joinform-said {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  margin-top: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--foreground);
}
.joinform.done .joinform-said svg { flex-shrink: 0; margin-top: 3px; color: var(--success); }

/* Centred variant, for the close. */
.joinform.mid { margin-inline: auto; }
.joinform.mid .joinform-row { justify-content: center; }
.joinform.mid .joinform-note,
.joinform.mid .joinform-said { text-align: center; }
.joinform.mid.done .joinform-said { justify-content: center; text-align: left; }

/* ---------------------------------------------------------------------------
   PRICING
   Three columns, one of them real. Self-host is available now; the two hosted
   tiers are marked and their CTAs go to the form rather than to a checkout.
   --------------------------------------------------------------------------- */

.tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); gap: 14px; }
/* auto-fit would stretch one or two cards across the whole measure, which reads
   as a banner rather than a price. Pin them and centre the group; the section
   heading centres with it, since a left-aligned heading over centred cards
   lines up with nothing. */
.tiers.one { grid-template-columns: minmax(0, 380px); justify-content: center; }
.tiers.pair { grid-template-columns: repeat(2, minmax(0, 340px)); justify-content: center; }

/* The free card carries one line that is a condition rather than a feature.
   It gets the same row, in the colour of a caveat instead of a tick. */
.tier li.caveat { color: var(--faint); }
.tier li.caveat svg { color: var(--faint); }
#pricing .section-head { text-align: center; margin-inline: auto; }
#pricing .section-head .lede { margin-inline: auto; }
.tier {
  display: flex;
  flex-direction: column;
  padding: 22px;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
}
.tier.lit { box-shadow: var(--shadow-raised), 0 0 0 1px var(--primary); }
.tier h3 { font-size: 15px; }
.tier .price { display: flex; align-items: baseline; gap: 6px; margin: 14px 0 0; }
.tier .price b {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
.tier .price span { font-size: 13px; color: var(--faint); }
.tier .terms { font-family: var(--mono); font-size: 11.5px; color: var(--faint); margin: 6px 0 16px; }
.tier ul { list-style: none; margin: 0 0 18px; display: flex; flex-direction: column; gap: 8px; }
.tier li { display: flex; gap: 9px; font-size: 13px; line-height: 1.5; color: var(--muted); }
.tier li svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 3px; color: var(--success); }
.tier .fill { flex: 1; }
.tier .btn { align-self: stretch; justify-content: center; }

/* "Not yet" said once, in the same place on every card that needs it. */
.soon {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: var(--r-chip);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warning);
  background: color-mix(in oklch, var(--warning) 12%, transparent);
}
.tier-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

.checks { list-style: none; margin: 16px 0 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.checks li { display: flex; gap: 9px; font-size: 13px; line-height: 1.5; color: var(--muted); }
.checks li svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 3px; color: var(--success); }

/* Feature lists inside the bento cells. */
.cell ul { list-style: none; margin: 14px 0 0; display: flex; flex-direction: column; gap: 8px; }
.cell li { display: flex; gap: 9px; font-size: 13px; line-height: 1.5; color: var(--muted); }
.cell li svg { width: 13px; height: 13px; flex-shrink: 0; margin-top: 3.5px; color: var(--tone, var(--primary)); }

.doors { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; }
.door {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  padding: 24px;
}
.door.lit {
  background: var(--canvas);
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--primary) 40%, transparent),
    0 2px 10px oklch(0 0 0 / 0.28),
    0 0 60px color-mix(in oklch, var(--primary) 10%, transparent);
}
.door h3 { font-size: 17px; }
.door .terms { font-family: var(--mono); font-size: 11.5px; color: var(--faint); margin: 4px 0 14px; }
.door p { font-size: 13.5px; color: var(--muted); }
.door ul { list-style: none; margin: 16px 0; display: flex; flex-direction: column; gap: 8px; }
.door li { display: flex; gap: 9px; font-size: 13px; color: var(--muted); }
.door li svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 3px; color: var(--success); }
.door .fill { flex: 1; }
.door .code { margin: 16px 0; }
.door .btn { align-self: flex-start; }

.faq { display: flex; flex-direction: column; }
details.q {
  border-top: 1px solid var(--rim);
  padding: 2px 0;
}
details.q:last-of-type { border-bottom: 1px solid var(--rim); }
details.q summary {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 17px 2px;
  cursor: pointer;
  font-size: 15px;
  font-weight: 500;
  list-style: none;
  transition: color 0.15s var(--settle);
}
details.q summary::-webkit-details-marker { display: none; }
details.q summary:hover { color: var(--primary); }
details.q summary .plus {
  margin-left: auto;
  position: relative;
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
details.q summary .plus::before,
details.q summary .plus::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: 1.5px;
  background: var(--muted);
  border-radius: 2px;
  transition: transform 0.25s var(--settle);
}
details.q summary .plus::after { transform: rotate(90deg); }
details.q[open] summary .plus::after { transform: rotate(0deg); }
details.q .a { padding: 0 40px 18px 2px; font-size: 13.5px; color: var(--muted); max-width: 72ch; }
details.q .a p + p { margin-top: 10px; }

/* The receipt: what this actually is, in one line, for whoever reads that
   before they read anything else. */
.spec {
  max-width: 74ch;
  margin: 26px auto 0;
  font-size: 11.5px;
  line-height: 1.9;
  color: var(--faint);
  text-wrap: pretty;
}

/* ---------------------------------------------------------------------------
   FOOTER
   Hired is one of several Shifu Labs tools, and this is where that gets said.
   The mark, the signal orange and the social set are the studio's, taken from
   shifulab.com; the layout, the type and the restraint are this page's. The
   studio's mark spins on its own site — here it doesn't, because nothing on
   this page loops. It turns a quarter when you point at it instead.
   --------------------------------------------------------------------------- */

footer { position: relative; isolation: isolate; overflow: hidden; padding-block: 44px 40px; }

.foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 40px 56px;
  align-items: start;
}

.foot-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; max-width: 36ch; }
.foot-line { margin: -3px 0 0; font-size: 13px; line-height: 1.6; color: var(--muted); }

.shifu-tag { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); transition: color 0.15s var(--settle); }
.shifu-tag b { font-weight: 600; color: var(--foreground); }
.shifu-tag svg { color: var(--signal); transition: rotate 0.45s var(--settle); }
.shifu-tag:hover { color: var(--foreground); }
.shifu-tag:hover svg { rotate: 90deg; }

.socials { display: flex; align-items: center; gap: 8px; }
.socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid var(--rim);
  background: var(--card);
  color: var(--muted);
  transition: color 0.15s var(--settle), border-color 0.15s var(--settle), background 0.15s var(--settle);
}
.socials a:hover { color: var(--foreground); border-color: var(--rim-strong); background: var(--inset); }

.foot-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 150px)); gap: 28px 56px; }
.foot-h {
  margin: 0 0 11px;
  font-family: var(--mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--faint);
}
.foot-cols ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.foot-cols a { font-size: 13px; color: var(--muted); transition: color 0.15s var(--settle); }
.foot-cols a:hover { color: var(--foreground); }

.foot-base {
  margin-top: 40px;
  padding-top: 18px;
  border-top: 1px solid var(--rim);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 20px;
  font-size: 11.5px;
  color: var(--faint);
}
.foot-base .fill { flex: 1; }

/* The studio mark, large and almost gone, behind the last line of the page. */
.foot-mark {
  position: absolute;
  right: -72px;
  bottom: -84px;
  z-index: -1;
  width: clamp(180px, 21vw, 270px);
  height: auto;
  color: var(--signal);
  opacity: 0.05;
  pointer-events: none;
}


/* Transcript turns arrive one at a time as the tape plays. */
.js [data-tape] [data-step] { opacity: 0; transform: translateY(6px); transition: opacity 0.35s var(--enter), transform 0.35s var(--enter); }
.js [data-tape] [data-step].in { opacity: 1; transform: none; }

/* ---------------------------------------------------------------------------
   Tabs — the connection recipes
   --------------------------------------------------------------------------- */

.tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: var(--r-control);
  font-size: 13px;
  color: var(--muted);
  box-shadow: var(--shadow-hairline);
  transition: color 0.15s var(--settle), background-color 0.15s var(--settle), box-shadow 0.15s var(--settle);
}
.tab svg { width: 15px; height: 15px; }
.tab .mark { width: 17px; height: 17px; border-radius: 4px; }
.tab:hover { color: var(--foreground); }
.tab.on {
  color: var(--foreground);
  background: var(--card);
  box-shadow: var(--shadow-card);
}
.tab .tagline { color: var(--faint); font-family: var(--mono); font-size: 10.5px; }

.recipe { display: flex; flex-direction: column; gap: 14px; }
.recipe ol { list-style: none; counter-reset: step; display: flex; flex-direction: column; gap: 14px; }
.recipe li { counter-increment: step; display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 6px 12px; }
.recipe li > * { grid-column: 2; }
.recipe li::before {
  content: counter(step);
  grid-column: 1;
  grid-row: 1;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--inset);
  box-shadow: var(--shadow-hairline);
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
}
.recipe li p { font-size: 13.5px; color: var(--muted); }
.recipe li .code { margin-top: 9px; }

.code-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 7px;
}
.code-head .label { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); }
.copy {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--faint);
  padding: 3px 8px;
  border-radius: var(--r-chip);
  box-shadow: var(--shadow-hairline);
  transition: color 0.15s var(--settle), box-shadow 0.15s var(--settle);
}
.copy:hover { color: var(--foreground); box-shadow: 0 0 0 1px var(--rim-strong); }

/* ---------------------------------------------------------------------------
   The no-fabrication panel
   --------------------------------------------------------------------------- */

.refusal {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 10px;
  margin-top: 20px;
}
.req {
  display: flex;
  gap: 10px;
  padding: 13px 14px;
  border-radius: var(--r-card);
  background: var(--card);
  box-shadow: var(--shadow-hairline);
}
.req svg { width: 15px; height: 15px; flex-shrink: 0; margin-top: 2px; }
.req .t { font-size: 13px; }
.req .s { font-size: 12px; color: var(--faint); margin-top: 3px; }
.req.yes svg { color: var(--success); }
.req.no { background: var(--inset); }
.req.no svg { color: var(--faint); }
.req.no .t { color: var(--muted); }

/* ---------------------------------------------------------------------------
   Numbers row
   --------------------------------------------------------------------------- */

.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px 20px; }
.figure .n {
  font-size: clamp(30px, 4vw, 42px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.figure .l { margin-top: 8px; font-size: 13px; color: var(--muted); }
.figure .h { margin-top: 3px; font-size: 12px; color: var(--faint); }

/* ===========================================================================
   RESPONSIVE

   The mocks are the hard part: they are drawn at a fixed internal scale so
   that type inside them keeps its real proportions, and then the whole frame
   is scaled down rather than reflowed. A reflowed screenshot is not a
   screenshot of anything.
   =========================================================================== */

@media (max-width: 860px) {
  .chapters {
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
  }
  .chapter { flex: 0 0 auto; min-width: 0; }
  .chapter p { display: none; }
}

@media (max-width: 900px) {
  .stage { grid-template-columns: minmax(0, 1fr); }
  .hero-copy { max-width: 100%; }
  .cell, .cell.third { grid-column: span 6; }
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot { grid-template-columns: 1fr; gap: 36px; }
  .foot-brand { max-width: 52ch; }
}

@media (max-width: 560px) {
  .joinform-row { flex-direction: column; }
  .joinform input[type="email"] { flex: 1 1 auto; width: 100%; }
  .joinform button[type="submit"] { width: 100%; justify-content: center; }
}

@media (max-width: 720px) {
  :root { --gutter: 18px; }
  .tiers.pair { grid-template-columns: minmax(0, 1fr); }
  .bento { grid-template-columns: minmax(0, 1fr); }
  .cell, .cell.wide, .cell.third { grid-column: span 1; }
  .foot-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot-base .fill { flex: 0 0 100%; }
  .foot-mark { right: -104px; bottom: -104px; }
  .hero-note { display: block; }
  .hero-note .sep { display: none; }
  .hero-note span { display: block; }
  /* `span { display: block }` above would flatten the client chips into a
     stack; keep that one a wrapping, centred row. */
  .hero-note .works { display: flex; flex-wrap: wrap; justify-content: center; gap: 7px 8px; margin-bottom: 4px; }
  .frame-url span { max-width: 62vw; }
  body { font-size: 14.5px; }
  .rail { display: none; }
  .nav-links, .nav-acts { display: none; }
  .nav-menu { display: block; justify-self: end; }
  .nav-inner { grid-template-columns: 1fr auto; height: 52px; padding-inline: 18px 9px; }
  .nav.stuck .nav-inner { height: 48px; }
  .search { margin-left: 0; width: 100%; }
  .funnel-row .step { width: 118px; font-size: 11.5px; }
  .funnel-row .median, .funnel-row .of { display: none; }
  .pane { padding: 14px 14px 18px; }
}

/* A frame narrower than its contents scales rather than reflows, so the
   product mock stays a mock of the product. */
@media (max-width: 640px) {
  .scale-out {
    transform: scale(0.86);
    transform-origin: top left;
    width: 116.3%;
  }
}


/* ---------------------------------------------------------------------------
   RESOURCES
   Long-form pages, generated from Markdown by tools/build-resources.mjs. They
   wear the same stylesheet as the landing page — one set of tokens, one set of
   type — so an article never looks like it was bolted on afterwards.
   --------------------------------------------------------------------------- */

.crumbs { font-size: 12.5px; color: var(--faint); margin-bottom: 18px; }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--foreground); }

.post-title { max-width: 26ch; margin-bottom: 12px; }
.post-meta {
  align-items: center;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--faint);
  display: flex;
  gap: 8px;
  margin-bottom: 34px;
}

.prose { max-width: 68ch; }
.prose p { margin-bottom: 20px; font-size: 16px; line-height: 1.72; color: var(--muted); }
.prose h2 {
  margin: 44px 0 14px;
  font-size: clamp(19px, 2.2vw, 23px);
  letter-spacing: -0.02em;
  color: var(--foreground);
  scroll-margin-top: 90px;
}
.prose h3 { margin: 30px 0 10px; font-size: 16.5px; color: var(--foreground); }
.prose strong { color: var(--foreground); font-weight: 600; }
.prose a {
  color: var(--primary);
  text-decoration: underline;
  text-decoration-color: color-mix(in oklch, var(--primary) 32%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s var(--settle);
}
.prose a:hover { text-decoration-color: currentColor; }
.prose ul, .prose ol { margin: 0 0 20px 20px; display: flex; flex-direction: column; gap: 9px; }
.prose li { font-size: 16px; line-height: 1.65; color: var(--muted); }
.prose blockquote {
  margin: 0 0 20px;
  padding: 14px 18px;
  border-left: 2px solid var(--primary);
  background: var(--inset);
  border-radius: 0 var(--r-control) var(--r-control) 0;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--foreground);
}
.prose .code { margin-bottom: 20px; white-space: pre-wrap; }
.prose > .fold { margin: 32px 0; }

/* The contents list, printed only when a post has enough sections to need it. */
.toc {
  margin-bottom: 34px;
  padding: 16px 18px;
  background: var(--canvas);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-hairline);
}
.toc .eyebrow { margin-bottom: 9px; }
.toc ul { list-style: none; margin: 0; gap: 7px; }
.toc li { font-size: 13.5px; }
.toc a { color: var(--muted); text-decoration: none; }
.toc a:hover { color: var(--foreground); }

.post-cta {
  margin: 48px 0 0;
  padding: 24px;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
}
.post-cta p { font-size: 15px; line-height: 1.6; color: var(--muted); margin: 0; }
.post-cta .btn { align-self: flex-start; }
.post-cta { flex-wrap: wrap; }

.post-author { margin-top: 34px; font-size: 13.5px; color: var(--faint); }
.post-author .eyebrow { margin-bottom: 7px; }
.post-author strong { color: var(--foreground); }

.post-more { margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--rim); }
.post-more .eyebrow { margin-bottom: 12px; }
.post-more ul { list-style: none; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.post-more a { font-size: 15px; font-weight: 500; color: var(--foreground); }
.post-more a:hover { color: var(--primary); }
.post-more span { display: block; font-size: 13.5px; color: var(--faint); font-weight: 400; margin-top: 3px; }

.post-link { margin: 0 0 30px; }

/* Not everything here is an article. The badge says which, in the colour the
   stage rotation already assigns to that kind. */
.kind {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--r-chip);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--tone);
  background: color-mix(in oklch, var(--tone) var(--stage-wash), transparent);
}

/* The filter bar. Revealed by the hub's own script — it is hidden in the
   markup, so with scripting off the page is the full list and nothing that
   does not work. */
.res-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 30px;
}
.res-bar .search { margin-left: auto; }
.res-empty { margin-top: 22px; font-size: 14px; color: var(--muted); }
.linkish {
  font: inherit;
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
}
.res[hidden] { display: none; }

/* The hub. */
.post-list { list-style: none; margin: 36px 0 0; display: flex; flex-direction: column; gap: 14px; }
.post-list a {
  display: block;
  padding: 22px;
  background: var(--card);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-card);
  transition: box-shadow 0.25s var(--settle);
}
.post-list a:hover { box-shadow: var(--shadow-raised); }
.post-list .kind { margin-bottom: 10px; }
.post-list h2 { font-size: 17px; letter-spacing: -0.02em; margin-bottom: 7px; }
.post-list p { font-size: 14px; line-height: 1.6; color: var(--muted); margin-bottom: 11px; }
.post-list .meta { font-family: var(--mono); font-size: 11.5px; color: var(--faint); }
