/* monika.fyi · theme
   ---------------------------------------------------------------------------
   The shared half of the concept gallery's stylesheet (~/monika-fyi/concepts/shell.css, lines
   56-120, 122-547 and 691-705), with the "Her" palette inlined as the only theme: blush paper,
   oxblood ink, one coral light. Everything about the gallery itself is gone. Each concept's own
   CSS is bundled separately by build.mjs. */

:root {
  color-scheme: light;

  /* Her: warm and close. A blush wall, oxblood ink, coral as the one light. */
  --paper: #fbf4f1;
  --raised: #fffaf8;
  --fill: #f5e9e4;
  --fill-2: #efdfd8;
  --line: #efdcd5;
  --line-2: #e2c8bf;
  --ink: #3b1f1c;
  --body: #6b4640;
  /* muted and faint are darker than the brand board's, so small type clears WCAG AA on paper:
     muted 4.6:1 at any size, faint 3:1 and reserved for separators and decorative numbers */
  --muted: #8a6159;
  --faint: #a8887f;
  --accent: #e2543f;
  --accent-soft: rgb(226 84 63 / 0.14);
  /* her coral taken most of the way into the blush paper: the pastel pink a marked phrase is underlined in.
     It is the one accent lightened, not a second brand colour, so Approach stays in the same palette. */
  --accent-blush: color-mix(in oklch, var(--accent) 40%, var(--paper));
  --island: #3b1f1c;
  --island-2: #52302b;
  --island-ink: #fbf4f1;
  --island-muted: #c9a9a2;
  --hatch: rgb(59 31 28 / 0.05);

  /* Two borrowed registers, used nowhere but the hero crowd: a message rebuilt as it arrived, and a merged
     pull request. They are the real products' own colours rather than hers, because the point of both is
     that you recognise where they came from, so they sit apart from the palette above and are never used
     for anything of hers. */
  --slack: #1a1d21;
  --slack-ink: #f4f5f6;
  --slack-body: #d5d8dc;
  --merged: #8250df;

  --font: "Manrope", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: "Manrope", -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --brand-annotate: ui-serif, "New York", Georgia, serif;

  /* The scale. The type system below reaches for eight of these ten steps; 12 and 32 are the two the nine roles
     do not use any more — 12 went to 13 and 32 to 24 — and they stay here because the scale is hers, not the
     system's. 14 is hers too: she asked for the metadata on the timeline at 14px, so l2 — the quiet label, which
     is what every one of those properties is — moved onto this step rather than a tenth role being invented. */
  --t-11: 0.6875rem;
  --t-12: 0.75rem;
  --t-13: 0.8125rem;
  --t-14: 0.875rem;
  --t-15: 0.9375rem;
  --t-17: 1.0625rem;
  --t-18: 1.125rem;
  --t-20: 1.25rem;
  --t-24: 1.5rem;
  --t-32: 2rem;
  --t-48: clamp(2.25rem, 1.5rem + 2.8vw, 3.5rem);

  /* ---------- the type system ----------
     Nine roles and no more: three headings, three body, three labels. Everything on the site — Home, the
     timeline row, the case folded out on it, the case page, Approach, Ideas, Not here, the nav and the footer —
     is one of these. A role fixes size, weight and line-height together; only the ink changes with the place
     (--ink, --body, --muted), and an inline <b> may add weight without leaving the role. Every size is one of
     the --t-* steps above: nothing here invents a new one.

       h1  the one title on a page            a case title, Not here
       h2  a section, an era, a figure        an era's name, a section heading, an outcome number, a lede set large
       h3  a lead-in or a small heading       a design point, a post title, the opening line on Home
       b1  reading prose, set large           her Approach, a case lede
       b2  reading prose                      a case paragraph, an essay
       b3  secondary prose                    her line on the timeline, a caption that is a sentence
       l1  a label you can act on             the nav, a button, a name, a pill
       l2  a quiet label                      years, a role, a team, an outcome, a figure's caption
       l3  a mark, in the one mono face       a media tag, a column head, "case study soon"  */
  --h1-font: 600 var(--t-48) / 1.04 var(--font-display);
  --h1-track: -0.03em;
  --h2-font: 600 var(--t-32) / 1.6 var(--font-display);
  /* The hero's own line: the h2 size set tight, at her word (26 Oct). Published as a role of its own
     rather than left as a raw line-height, so the page stays inside its own type system. */
  --hero-font: 600 var(--t-32) / 1.12 var(--font-display);
  --h2-track: -0.02em;
  --h3-font: 600 var(--t-24) / 1.58 var(--font-display);
  --h3-track: -0.015em;
  --b1-font: 400 var(--t-20) / 1.5 var(--font);
  --b2-font: 400 var(--t-18) / 1.55 var(--font);
  --b3-font: 400 var(--t-15) / 1.55 var(--font);
  --l1-font: 500 var(--t-13) / 1.45 var(--font);
  --l2-font: 400 var(--t-14) / 1.45 var(--font);
  --l3-font: 500 var(--t-11) / 1.4 var(--mono);
  /* A tenth role, added deliberately (19 Oct): the sentence a work card carries over its picture. It is the
     measure the vision deck she is working against uses on its own cards — a card type of
     clamp(24px, 2.2vw, 30px) set at 0.74 of itself, 600, 1.15, -0.01em — and it is here rather than inline
     so it is one of the roles the type check knows about instead of a stray on every page that shows work. */
  --card-type: clamp(24px, 2.2vw, 30px);
  --c1-font: 600 calc(var(--card-type) * 0.74) / 1.15 var(--font-display);
  --c1-track: -0.01em;
  --l3-track: 0.02em;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --spring: var(--ease-out);
  --d-press: 140ms;
  --d-state: 240ms;
  --d-layout: 380ms;
  --d-enter: 460ms;

  --r-s: 6px;
  --r-m: 10px;
  --r-l: 14px;
  --dock-space: 96px;
}
@supports (transition-timing-function: linear(0, 1)) {
  :root {
    --spring: linear(0, 0.06, 0.22 6%, 0.62 14%, 0.86 21%, 0.97 28%, 1.015 35%, 1.025 42%, 1.018 52%, 1.005 66%, 1);
  }
}

/* Reduced motion: movement collapses to short fades. The shell sets this for the OS preference too. */
:root[data-motion="reduced"] {
  --d-press: 0ms;
  --d-state: 120ms;
  --d-layout: 120ms;
  --d-enter: 150ms;
}
:root[data-motion="reduced"] *,
:root[data-motion="reduced"] *::before,
:root[data-motion="reduced"] *::after {
  animation-duration: 1ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 120ms !important;
  transition-delay: 0ms !important;
  scroll-behavior: auto !important;
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: var(--b3-font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
body.mf-lock { overflow: hidden; }
h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
h1, h2, h3, h4 { text-wrap: balance; }
p { text-wrap: pretty; }
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
a { color: inherit; }
img, svg { display: block; max-width: 100%; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
[hidden] { display: none !important; }
.mf-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* The nine, as classes: for markup that reaches for one directly, and so the check can read the system off the
   page itself rather than off a list it keeps separately. */
.t-h1 { font: var(--h1-font); letter-spacing: var(--h1-track); color: var(--ink); }
.t-h2 { font: var(--h2-font); letter-spacing: var(--h2-track); color: var(--ink); }
.t-hero { font: var(--hero-font); letter-spacing: var(--h2-track); color: var(--ink); }
.t-h3 { font: var(--h3-font); letter-spacing: var(--h3-track); color: var(--ink); }
.t-b1 { font: var(--b1-font); color: var(--body); }
.t-b2 { font: var(--b2-font); color: var(--body); }
.t-b3 { font: var(--b3-font); color: var(--body); }
.t-l1 { font: var(--l1-font); color: var(--ink); }
.t-l2 { font: var(--l2-font); color: var(--muted); }
.t-l3 { font: var(--l3-font); letter-spacing: var(--l3-track); color: var(--muted); }
.t-c1 { font: var(--c1-font); letter-spacing: var(--c1-track); color: var(--ink); }

/* Press feedback. Zero specificity so concept styles always win; include `scale` if you set your own transition. */
:where(.mf-press, .mf-stage-root button, .mf-stage-root [role="button"], .mf-dock button, .mf-demo-press) {
  transition: scale var(--d-press) var(--ease-out);
}
:where(.mf-press, .mf-stage-root button, .mf-stage-root [role="button"], .mf-dock button, .mf-demo-press):active { scale: 0.97; }

/* Hovering a list dims the siblings. */
@media (hover: hover) and (pointer: fine) {
  :where(.mf-dim) > * { transition: opacity 150ms var(--ease-out); }
  :where(.mf-dim):has(> :hover) > :not(:hover) { opacity: 0.45; }
}
/* ---------- shared components ---------- */
.mf-link {
  color: var(--ink);
  text-decoration: none;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0% 1px no-repeat;
  transition: background-size var(--d-state) var(--ease-out);
}
@media (hover: hover) { .mf-link:hover { background-size: 100% 1px; } }

.mf-avatar {
  display: inline-block;
  flex: none;
  width: var(--s, 32px);
  height: var(--s, 32px);
  border-radius: 50%;
  border: 1px solid var(--line);
  background:
    radial-gradient(circle at 50% 38%, var(--line-2) 0 17%, transparent 18%),
    radial-gradient(ellipse 60% 44% at 50% 100%, var(--line-2) 0 99%, transparent 100%),
    var(--fill-2);
}

.mf-media {
  position: relative;
  display: grid;
  place-items: end start;
  aspect-ratio: var(--ratio, 16 / 10);
  border-radius: var(--r-m);
  border: 1px solid var(--line);
  background: repeating-linear-gradient(135deg, transparent 0 9px, var(--hatch) 9px 10px), var(--fill);
  overflow: hidden;
}
.mf-media-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 10px;
  padding: 5px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--raised);
  color: var(--muted);
  font: var(--l3-font); letter-spacing: var(--l3-track);
  white-space: nowrap;
}
.mf-play {
  width: 0;
  height: 0;
  border-left: 6px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}
.mf-media[data-media="clip"]::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--line-2);
  transform-origin: 0 50%;
  transform: scaleX(0);
  animation: mf-clip 7s linear infinite;
}
@keyframes mf-clip { to { transform: scaleX(1); } }

.mf-clock { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mf-clock-t { display: inline-block; color: var(--ink); }
.mf-clock-t.is-tick { animation: mf-tick 460ms var(--ease-out); }
.mf-colon { transition: opacity 300ms var(--ease-out); }
.mf-clock.is-blink .mf-colon { opacity: 0.35; }
@keyframes mf-tick { from { opacity: 0.25; filter: blur(2px); translate: 0 -2px; } }

.mf-copy {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ink);
  font-weight: 500;
  border-radius: 6px;
}
.mf-copy-text { display: inline-grid; }
.mf-copy-text > span {
  grid-area: 1 / 1;
  transition: opacity 200ms var(--ease-out), filter 200ms var(--ease-out), translate 200ms var(--ease-out);
}
.mf-copy-text > span:last-child { opacity: 0; filter: blur(2px); translate: 0 3px; }
.mf-copy.is-copied .mf-copy-text > span:first-child { opacity: 0; filter: blur(2px); translate: 0 -3px; }
.mf-copy.is-copied .mf-copy-text > span:last-child { opacity: 1; filter: none; translate: 0 0; }
.mf-copy-icon { position: relative; width: 14px; height: 14px; color: var(--muted); }
.mf-copy-icon svg {
  position: absolute;
  inset: 0;
  width: 14px;
  height: 14px;
  transition: opacity 200ms var(--ease-out), scale 200ms var(--ease-out), filter 200ms var(--ease-out);
}
.mf-copy .i-check { opacity: 0; scale: 0.5; filter: blur(2px); color: var(--ink); }
.mf-copy .i-check path { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 250ms var(--ease-out) 60ms; }
.mf-copy.is-copied .i-copy { opacity: 0; scale: 0.5; filter: blur(2px); }
.mf-copy.is-copied .i-check { opacity: 1; scale: 1; filter: none; }
.mf-copy.is-copied .i-check path { stroke-dashoffset: 0; }

.mf-time {
  position: relative;
  color: var(--muted);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.mf-time::after {
  content: attr(data-exact);
  position: absolute;
  left: 0;
  bottom: calc(100% + 6px);
  z-index: 5;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--island);
  color: var(--island-ink);
  font: var(--l3-font); letter-spacing: var(--l3-track);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  translate: 0 4px;
  transition: opacity 150ms var(--ease-out), translate 150ms var(--ease-out);
}
@media (hover: hover) { .mf-time:hover { color: var(--ink); } .mf-time:hover::after { opacity: 1; translate: 0 0; } }
.mf-time:focus-visible::after { opacity: 1; translate: 0 0; }

.mf-filters,
.mf-seg {
  position: relative;
  display: inline-flex;
  isolation: isolate;
  padding: 3px;
  gap: 2px;
  border-radius: 999px;
}
.mf-filters { background: var(--fill); }
.mf-filters button,
.mf-seg button {
  position: relative;
  z-index: 1;
  padding: 6px 12px;
  border-radius: 999px;
  font: var(--l2-font);
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--d-state) var(--ease-out), scale var(--d-press) var(--ease-out);
}
.mf-filters button { color: var(--muted); }
.mf-filters button[aria-pressed="true"] { color: var(--ink); }
.mf-filters-pill,
.mf-seg-pill {
  position: absolute;
  z-index: 0;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: var(--w, 0px);
  translate: var(--x, 3px) 0;
  border-radius: 999px;
  /* only the slide animates: a width transition would lay the dock out on every frame */
  transition: translate 380ms var(--spring);
}
.mf-filters-pill { background: var(--raised); border: 1px solid var(--line); }
:is(.mf-filters, .mf-seg):not(.is-ready) :is(.mf-filters-pill, .mf-seg-pill) { transition: none; }

.mf-in { animation: mf-in 320ms var(--ease-out) both; animation-delay: calc(var(--i, 0) * 35ms); }
@keyframes mf-in { from { opacity: 0; translate: 0 6px; filter: blur(2px); } }

.mf-compose {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 14px 14px 16px;
  border: 1px dashed var(--line-2);
  border-radius: var(--r-l);
  color: var(--faint);
}
.mf-compose-face { display: block; flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; object-position: 40% 30%; background: var(--fill-2); }
.mf-compose-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.mf-compose-field { font: var(--b3-font); }
.mf-compose-tag { font: var(--l3-font); letter-spacing: var(--l3-track); color: var(--muted); }
.mf-compose-btn {
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--fill-2);
  color: var(--muted);
  font: var(--l2-font);
  font-weight: 500;
}

.mf-sample {
  display: inline-block;
  padding: 2px 7px;
  border: 1px dashed var(--line-2);
  border-radius: 999px;
  color: var(--muted);
  font: var(--l3-font); letter-spacing: var(--l3-track);
  vertical-align: 1px;
}

/* A company's mark: a small rounded chip, the mark filling it. --s sets its size where a place wants another. */
.mf-face { flex: none; display: block; width: var(--s, 28px); height: var(--s, 28px); overflow: hidden; border-radius: 50%; background: var(--fill); }
.mf-face img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* ---------- the two faces of Miro's AI brand study ----------
   Her field notes for the Miro AI vision are set in the faces the study is actually about: Apris, Miro's display
   serif, and Inter, its working sans, both lifted from her own field-notes file. Nothing else on this site uses
   them, so a browser downloads them only when that one graphic is on the page. */
/* Manrope carries the whole site now, at her word (19 Oct). One variable file, latin only, 24 KB: every
   weight the page asks for comes out of it, so there is nothing else to load and nothing to go stale. */
@font-face {
  font-family: "Manrope";
  src: url('/assets/fonts/manrope-var.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Apris";
  src: url('/assets/fonts/apris.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter Var";
  src: url('/assets/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
/* ----- the product's own face -----
   The pieces of her Miro work rebuilt on the timeline are set in the face the product is set in, because a
   component in the wrong face is wrong in a way no amount of correct geometry hides. Two weights, not the
   four the product has: Noto carries every script there is, so each face is a quarter of a megabyte, and the
   650 and 700 the product uses are both answered by 600 here rather than paid for twice.

   Nothing claims this family until a rebuilt piece is near the window — see .qi-gen.is-near in quiet-index —
   so the browser has no text to lay out in it, and asks for nothing, until someone scrolls to that work. */
@font-face {
  font-family: "Noto Sans Product";
  src: url('/assets/fonts/noto-sans-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Noto Sans Product";
  src: url('/assets/fonts/noto-sans-600.woff2') format('woff2');
  font-weight: 500 1000;
  font-style: normal;
  font-display: swap;
}
:root { --font-product: "Noto Sans Product", OpenSans, system-ui, sans-serif; }

.mf-logo { flex: none; align-self: center; width: var(--s, 28px); height: var(--s, 28px); overflow: hidden; border-radius: calc(var(--s, 28px) / 4); background: var(--island); }
.mf-logo img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
/* The corner is on the drawing and not only on the box it stands in. Every one of these marks is a
   square picture that sits INSIDE its box rather than filling it, so the box's own corner never reached
   them: McKinsey and Google X were sharp black squares in a rounded holder, and only Miro looked round
   because its asset was drawn that way (her word, 27 Oct). The holder's own corner, taken by the
   picture, so a mark that already filled its box - the 42px one at the head of a row - keeps exactly
   the corner it had, and the small ones that sit inside their box finally get one. */

.mf-work {
  position: relative;
  margin: 0;
  aspect-ratio: var(--ratio, 16 / 10);
  border-radius: var(--r-m);
  background: var(--fill);
  overflow: hidden;
}
.mf-work img { width: 100%; height: 100%; object-fit: cover; user-select: none; }
.mf-work.is-video video { display: block; width: 100%; height: 100%; object-fit: cover; background: transparent; }
/* How media meets its frame (MF.ui.work picks from the asset):
   framed: plain UI floats on a soft gradient card with a drop shadow.
   matte:  the asset already sits on a flat colour, so the card is that colour and the asset fills it.
   bleed:  a photo or filmed scene is its own background and fills the card edge to edge.
   Framed and matte media are fitted with the asset's ratio (--mr) against the card's own size, so they
   centre exactly whatever size a layout gives the card. Tones mix into the brand's paper. */
.mf-work:is(.is-framed, .is-matte, .is-bleed) { border-radius: calc(var(--r-l) + 4px); }
.mf-work:is(.is-framed, .is-matte) {
  display: grid;
  place-items: center;
  container-type: size;
}
.mf-work:is(.is-framed, .is-matte) > :is(img, video) {
  --pad: clamp(10px, 7cqmin, 56px);
  display: block;
  width: min(100cqw - 2 * var(--pad), (100cqh - 2 * var(--pad)) * var(--mr));
  height: auto;
  aspect-ratio: var(--mr);
  object-fit: cover;
}
.mf-work.is-matte,
.mf-work.is-matte > :is(img, video) { background: var(--matte); }
.mf-work.is-matte > :is(img, video) { --pad: 0px; }
/* A matte asset normally fills its card, because the card is the colour the asset
   already sits on and the two are meant to be one surface. That assumes the asset
   carries its own margin — most of these were filmed with the ground around them.
   One that was filmed edge to edge has none, so it runs the full width of the card
   and reads far larger than its neighbours. `inset` on the asset gives it the
   margin the footage does not have, at the same size a framed asset floats by. */
.mf-work.is-matte.is-inset > :is(img, video) { --pad: clamp(10px, 7cqmin, 56px); }
/* A picture standing inside a card is an object on a surface, so it turns a corner
   the way the card does. One step tighter than the card's own, which is what keeps
   the two radii from reading as the same line drawn twice. */
.mf-work.is-inset > :is(img, video) { border-radius: var(--r-m); }
/* ----- a card that says what it is -----
   The title in the card's own top left, the way the Miro cards set it. There is no
   scrim: the card reserves a band of its own colour for the words and the picture
   stands under it, so nothing is written over the footage and nothing is hidden by
   being written on. The band is part of the card's height, so the picture gives up
   exactly as much room as the words take. */
/* The words take their room out of the picture's own margin, not out of the card
   above it. Reserving a band with padding pushed the picture to the bottom of what
   was left, so it sat low in the card instead of in the middle of it. A capped card
   stands its picture a little further in and leaves the title the ground that makes,
   while the picture stays centred — which is the whole of what a card does with it.
   Written past .is-matte.is-inset on purpose: that rule is three classes deep and
   would otherwise set the margin back to the uncaptioned one. */
.mf-work.is-matte.is-inset.is-capped > :is(img, video) { --pad: clamp(18px, 11cqmin, 80px); }
.mf-cap {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0;
  /* The Miro card's own inset, 28 and 30 at the size these stand in the row. */
  padding: clamp(14px, 5.1cqmin, 30px) clamp(16px, 5.5cqmin, 32px) 0;
  /* The Miro shelf's own title, to the letter: same face, same size, same measure.
     These cards stand in the same strip as those, so a second heading style would
     make two systems out of one row. */
  font: var(--c1-font);
  letter-spacing: var(--c1-track);
  color: var(--ink);
  text-wrap: balance;
  pointer-events: none;
  /* The picture is centred in the card, so the words and its top edge share a little
     ground. A scrim of the card's own colour is what lets them — the same answer the
     Miro shelf gives, and for the same reason: the title is IN the card, not on a
     band stuck above it. It is made of the card's colour, so there is no second
     surface, and it is gone before it reaches anything worth seeing. */
  right: 0;
  padding-bottom: clamp(14px, 4cqmin, 30px);
  background: linear-gradient(to bottom,
    var(--matte, transparent) 58%,
    color-mix(in oklch, var(--matte, transparent) 66%, transparent) 82%,
    transparent);
}
.mf-cap > span { display: block; max-width: 24ch; }
.mf-work.is-framed {
  --frame-a: oklch(0.9 0.05 245);
  --frame-b: oklch(0.94 0.03 285);
  background:
    radial-gradient(95% 85% at 12% 0%, color-mix(in oklch, var(--frame-a) 80%, var(--paper)) 0%, transparent 72%),
    radial-gradient(85% 75% at 100% 100%, color-mix(in oklch, var(--frame-b) 75%, var(--paper)) 0%, transparent 72%),
    color-mix(in oklch, var(--frame-a) 28%, var(--paper));
}
.mf-work.is-framed[data-tone="lilac"] { --frame-a: oklch(0.89 0.06 300); --frame-b: oklch(0.93 0.04 250); }
.mf-work.is-framed[data-tone="mint"] { --frame-a: oklch(0.9 0.06 165); --frame-b: oklch(0.94 0.04 215); }
.mf-work.is-framed[data-tone="sand"] { --frame-a: oklch(0.91 0.05 80); --frame-b: oklch(0.94 0.035 40); }
.mf-work.is-framed[data-tone="peach"] { --frame-a: oklch(0.9 0.055 40); --frame-b: oklch(0.94 0.04 350); }
/* No shadow under a clip, at her word (2026-10-18): a drop shadow is what makes a screen recording read as
   something pasted onto a card rather than as the card's own surface. The frame's colour is the colour the
   footage is already on — `fill` on the asset says which — so the two meet without a seam, and nothing is
   drawn to separate them. The radius stays, because the corner is the frame's, not the shadow's.
   The media keeps no background of its own either: a clip that has not arrived yet shows the frame it is in
   rather than a second, warmer colour inside it. */
.mf-work.is-framed > :is(img, video) {
  border-radius: clamp(4px, 1.5cqmin, 12px);
  background: transparent;
}
:root[data-motion="reduced"] .mf-work.is-video { cursor: pointer; }

/* Intro bubble: her face in a circle, looping silently, with a small play badge. */
.mf-intro {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex: none;
  border-radius: 999px;
  color: var(--ink);
  font: var(--l2-font);
  font-weight: 500;
  pointer-events: auto;
  transition: scale var(--d-press) var(--ease-out);
}
.mf-intro:active { scale: 0.96; }
.mf-intro-disc { position: relative; display: block; flex: none; width: var(--s); height: var(--s); border-radius: 50%; }
.mf-intro-disc video {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  object-position: 40% 30%;
  background: var(--fill-2);
  transition: scale 320ms var(--ease-out);
}
.mf-intro-disc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  outline: 2px solid transparent;
  animation: mf-intro-ring 2.8s var(--ease-out) infinite;
}
@keyframes mf-intro-ring {
  0% { outline-color: var(--accent); outline-offset: 0; }
  60%, 100% { outline-color: transparent; outline-offset: 9px; }
}
.mf-intro-play {
  position: absolute;
  right: -2px;
  bottom: -2px;
  display: grid;
  place-items: center;
  width: max(20px, calc(var(--s) * 0.32));
  height: max(20px, calc(var(--s) * 0.32));
  border-radius: 50%;
  border: 2px solid var(--paper);
  background: var(--island);
  color: var(--island-ink);
}
.mf-intro-play svg { width: 45%; height: 45%; margin-left: 8%; }
.mf-intro-label { white-space: nowrap; }
@media (hover: hover) and (pointer: fine) { .mf-intro:hover .mf-intro-disc video { scale: 1.05; } }

.mf-intro-player { position: fixed; inset: 0; z-index: 70; display: grid; place-items: center; padding: 24px; }
.mf-intro-backdrop { position: absolute; inset: 0; background: color-mix(in oklch, var(--paper) 94%, transparent); }
.mf-intro-frame { position: relative; width: min(900px, 100%); aspect-ratio: 16 / 9; margin: 0; overflow: hidden; border-radius: 20px; background: var(--island); }
.mf-intro-frame video { display: block; width: 100%; height: 100%; object-fit: cover; cursor: pointer; }
.mf-intro-bar {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 6px 6px 14px;
  border-radius: 999px;
  background: var(--island);
  color: var(--island-ink);
  font: var(--l2-font);
  font-weight: 500;
}
.mf-intro-progress { flex: 1; height: 3px; border-radius: 3px; background: var(--island-2); overflow: hidden; }
.mf-intro-progress i { display: block; height: 100%; background: var(--island-ink); transform-origin: 0 50%; transform: scaleX(var(--p, 0)); transition: transform 250ms linear; }
.mf-intro-close { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; color: var(--island-muted); transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out); }
@media (hover: hover) { .mf-intro-close:hover { background: var(--island-2); color: var(--island-ink); } }

/* Testimonials: words first, then a small grey portrait beside name and role. */
.mf-said { display: flex; flex-direction: column; gap: 36px; }
.mf-said-k { font: var(--l2-font); font-weight: 600; color: var(--muted); }
.mf-quote { margin: 0; display: flex; flex-direction: column; gap: 14px; }
.mf-quote blockquote { margin: 0; }
.mf-quote p { color: var(--ink); font-size: inherit; text-wrap: pretty; }
.mf-quote figcaption { display: flex; align-items: center; gap: 12px; min-width: 0; }
.mf-quote-face { flex: none; width: 40px; height: 40px; overflow: hidden; border-radius: 50%; background: var(--fill-2); }
.mf-quote-face img { display: block; width: 100%; height: 100%; object-fit: cover; filter: grayscale(1); user-select: none; }
.mf-quote-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.35; }
.mf-quote-name { font: var(--l2-font); font-weight: 600; color: var(--ink); }
.mf-quote-role { font: var(--l2-font); color: var(--muted); }
.mf-initials {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--fill-2);
  color: var(--body);
  font: var(--l3-font); letter-spacing: var(--l3-track);
  font-weight: 600;
}

.mf-post { display: flex; flex-direction: column; gap: 8px; }
.mf-post-title { font: var(--b2-font); font-weight: 600; color: var(--ink); }
.mf-post-text { font: var(--b3-font); color: var(--ink); }
.mf-post-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; font: var(--l2-font); color: var(--muted); }
.mf-dot { color: var(--faint); }
.mf-bsky { color: var(--muted); text-decoration: none; white-space: nowrap; }
.mf-older {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  color: var(--ink);
  font-weight: 500;
  text-decoration: none;
}
.mf-older span { transition: translate var(--d-state) var(--ease-out); }
@media (hover: hover) {
  .mf-bsky:hover { color: var(--ink); }
  .mf-older:hover span { translate: 3px 0; }
}

.mf-pulse { animation: mf-pulse 1100ms var(--ease-out) 2; }
@keyframes mf-pulse {
  from { outline: 2px solid var(--accent); outline-offset: 0; }
  to { outline: 2px solid oklch(0.6 0.165 256 / 0); outline-offset: 10px; }
}

.mf-toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  z-index: 60;
  padding: 8px 12px;
  border-radius: 999px;
  background: var(--island);
  color: var(--island-ink);
  font: var(--l2-font);
  pointer-events: none;
  opacity: 0;
  translate: -50% 8px;
  transition: opacity 200ms var(--ease-out), translate 200ms var(--ease-out);
}
.mf-toast.is-on { opacity: 1; translate: -50% 0; }

.mf-spec { font: var(--l3-font); letter-spacing: var(--l3-track); color: var(--muted); }

kbd {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  margin: 0 1px;
  border: 1px solid var(--line-2);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--raised);
  color: var(--body);
  font: var(--l3-font); letter-spacing: var(--l3-track);
}

/* ---------- stage + dock ---------- */
.mf-stage {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--paper);
}
.mf-stage-root {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-padding-bottom: var(--dock-space);
}
.mf-stage-root:focus { outline: none; }

/* one faint warm light at the top of the page, nothing more */
body, .mf-stage {
  background-image: radial-gradient(90% 50% at 50% -14%, rgb(233 116 98 / 0.12), transparent 70%);
}

/* ---------- the page breathing, on Writing ----------
   Her reference (interconnected.org) runs a ten-minute keyframe over the body colour, which you never
   catch moving and always notice having moved. This is the same idea in her palette and slower: eight
   tints within about two per cent of the paper, fourteen minutes end to end, so the page is never a
   different colour — only never quite the same one.

   A custom property has to be registered before it can be animated at all; an unregistered one flips
   from stop to stop instead of easing between them. Registering it also lets the selection colour be
   mixed from the same value, so what you highlight shifts with the page under it.

   Scoped by :has to the tab she asked for it on, which needs no script: the drift is on while the
   Writing page is the one showing and nowhere else. */
@property --mf-drift {
  syntax: '<color>';
  inherits: true;
  initial-value: #fbf4f1;
}
:root:has(.c-anatomy-lpage[data-list="writing"].is-on) {
  animation: mf-drift 840s linear infinite;
}
:root:has(.c-anatomy-lpage[data-list="writing"].is-on) :is(body, .mf-stage) {
  background-color: var(--mf-drift);
}
/* What you highlight is mixed from the same colour, so it moves with the page rather than against it. */
:root:has(.c-anatomy-lpage[data-list="writing"].is-on) ::selection {
  background: color-mix(in oklch, var(--mf-drift) 58%, var(--accent) 42%);
  color: var(--ink);
}
@keyframes mf-drift {
  0%   { --mf-drift: #fbf4f1; }
  12%  { --mf-drift: #faf5ef; }
  25%  { --mf-drift: #f7f6f0; }
  37%  { --mf-drift: #f4f6f2; }
  50%  { --mf-drift: #f3f6f6; }
  62%  { --mf-drift: #f4f5f9; }
  75%  { --mf-drift: #f7f4f8; }
  87%  { --mf-drift: #faf4f4; }
  100% { --mf-drift: #fbf4f1; }
}
/* A page that must not move does not move. */
:root[data-motion="reduced"]:has(.c-anatomy-lpage[data-list="writing"].is-on) { animation: none; }

/* the page before JavaScript arrives, or without it: a way around, then the list, then the small print */
.mf-pre-nav, .mf-pre-foot { display: flex; flex-wrap: wrap; gap: 6px 18px; max-width: 620px; margin: 0 auto; padding: 20px 24px; font: var(--l2-font); }
.mf-pre-nav a, .mf-pre-foot a { color: var(--body); text-decoration: none; }
.mf-pre-nav a[aria-current] { color: var(--ink); font-weight: 600; }
/* The small print sits right under whatever the page ends with — on Home that is the band of her
   drawings, and 48px of air under it plus the page's own padding read as a hole rather than a margin. */
.mf-pre-foot { padding-top: 6px; padding-bottom: 22px; color: var(--muted); }
.mf-pre-foot a { color: var(--muted); }

/* the two legal pages: a plain document, the same paper and type */
.mf-legal-page { min-height: 100vh; background-color: var(--paper); }
.mf-legal { max-width: 620px; margin: 0 auto; padding: 24px 24px 16px; color: var(--body); font: var(--b3-font); }
.mf-legal h1 { margin: 24px 0 28px; color: var(--ink); font: var(--h2-font); letter-spacing: var(--h2-track); font-weight: 650; }
.mf-legal h2 { margin: 36px 0 10px; color: var(--ink); font: var(--b2-font); font-weight: 600; }
.mf-legal p { margin: 0 0 14px; max-width: 64ch; }
.mf-legal a { color: var(--ink); }
.mf-legal mark { padding: 1px 4px; border-radius: 4px; background: var(--accent-soft); color: var(--ink); }
.mf-legal-draft { display: inline-block; padding: 6px 12px; border-radius: 999px; background: var(--island); color: var(--island-ink); font: var(--l2-font); font-weight: 500; }
