/* 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: cool and quiet, with one warm light. The neutrals were a blush wall and oxblood ink - every
     one of them on the same warm hue as her coral, which made the whole page read as beige (her word,
     9 Nov: less beige, more cool tones, off-white shades). They are off-white and cool-grey now, a
     breath of blue in them rather than a breath of orange, and the coral is left exactly where it was:
     against a cool ground it is the one warm thing on the page, which is what an accent is for.

     The paper is #f5f6f8 rather than white: white is a surface, off-white is a sheet. */
  --paper: #f5f6f8;
  --raised: #fcfcfd;
  --fill: #eaecf0;
  --fill-2: #e1e5ea;
  --line: #e3e6eb;
  --line-2: #ccd2da;
  --ink: #1e2430;
  --body: #46505f;
  /* 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. Measured
     against the new paper, not inherited from the old one: the same greys on a lighter, cooler sheet
     come out thinner, so both went a step down to hold the ratios they are here for. */
  --muted: #646d7a;
  --faint: #878f9d;
  /* Her coral, turned a little off the orange side of red and onto the magenta side (her word, 9 Nov:
     a tiny tiny bit more into magenta, not fully, not obvious, but aligned with the background of my
     photo). The portrait's backdrop runs from a coral at hue 6 to a magenta at 340; the accent sat at 8,
     on the far edge of that range, and now sits at 358 - over the line, a tenth of the way across.
     Rotated in oklch at the lightness and chroma it already had (0.631 / 0.172), so it carries exactly
     the same weight on the page and only its hue has moved. It is the focus ring, the caret that writes
     About out, and the underline under a marked phrase. */
  --accent: #de555a;

  /* ----- glass -----
     One material for every panel that floats over the page - the tabs, the bar that names where you are,
     the reading progress (her word, 9 Nov: glassy, like Apple). Four panels had four recipes between
     them, each a little different and none of them deliberate; this is the recipe, and they all read it.

     What makes it read as glass rather than as a translucent box is the pair at the top of the shadow:
     the hairline is lighter than the paper behind it, and an inset white line sits just under it, so the
     top edge catches light the way a real pane does. The saturation lift is what keeps whatever is
     sliding underneath from going grey as it blurs. */
  /* Every colour in this block is mixed in sRGB, not in oklch. Chrome drops the hue of a pale, low-chroma
     grey when it carries it through oklch towards transparent - it writes the hue out as `none` and then
     paints `none` as zero, which is pink - so the cool rim was landing at rgb(219 209 212) and the fill
     with it: a warm ring and a warm wash sitting on a cool sheet (her word, 9 Nov: the selection gray is
     not matching other gray tones). Mixed in sRGB the same rim is rgb(207 213 220) and the hue holds.
     The ink and the coral keep their oklch mixes; they have enough chroma to survive it.

     The fill is flat (her word, 9 Nov: remove the weird fill gradient). It was a wash running from white
     at the top to the page's own grey at the bottom - the falloff a curved pane puts on the light - and
     over anything with a tone of its own it read as a gradient painted on the panel rather than as
     glass. So the pane is one translucent white, and what makes it a pane is the rim, the lit top edge
     and the fall underneath it.

     And it is properly translucent, though less so than it was: 66 per cent, having gone 78 to 58 and
     back a little (her word, 9 Nov: make it a tiny tiny bit less translucent). At 78 the card came out
     at rgb(252 252 252) over the Miro board - which is white, and no trick makes a panel look like glass
     while letting almost nothing through it. At 58 it let enough through to read as glass and a little
     more than the words wanted behind them. Sixty-six keeps the shapes behind it legible as shapes and
     gives the ink a steadier ground. */
  --glass-bg: rgb(255 255 255 / 0.66);
  /* The edge is a line catching light, not a border. A uniform ring at full strength is what reads as a
     box with a stroke drawn round it (her word, 9 Nov: all glassy effect things have very strong
     outline), so the ring is halved and the edge is left to the pair of insets below: lit along the top,
     shaded along the bottom, the two edges of a pane under a light from above. */
  --glass-line: color-mix(in srgb, var(--line-2) 48%, transparent);
  /* And the blur is halved. Twenty-two pixels is a wash: over low-contrast content - a light board with
     thin lines on it - it smears every edge into one flat tone, which is the other half of why the card
     read as opaque. Eleven keeps the shapes behind it as shapes, soft and unreadable but plainly there,
     which is what a reader recognises as glass. The saturation lift stays: it is what stops whatever is
     behind from going grey as it blurs. */
  --glass-blur: saturate(1.8) blur(11px);
  --glass-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.92),
    inset 0 -1px 0 rgb(30 36 48 / 0.1),
    0 1px 2px rgb(30 36 48 / 0.05),
    0 6px 16px -10px rgb(30 36 48 / 0.16),
    0 24px 48px -30px rgb(30 36 48 / 0.2);
  /* The same colour, said again at a fraction - so it has to move with it. It was still the old coral
     in figures, which is how a token drifts from the thing it is a soft version of. */
  --accent-soft: rgb(222 85 90 / 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: #1e2430;
  --island-2: #343c4b;
  --island-ink: #f5f6f8;
  --island-muted: #aab2c0;
  --hatch: rgb(30 36 48 / 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;

  /* One face, everywhere. Hierarchy is size and colour first and weight only where a line has to be
     told from the one under it, which is the most restrained reading of what she asked for and the one
     that leaves the fewest decisions lying about. Inter is a variable file, so Regular and Medium both
     come out of the single download and nothing is synthesised. */
  /* The one measure every page reads at: her words, her timeline, her stories, her Approach page - and
     the line at the foot of all of them, which sits outside the page's own box and so could not see
     this while it was declared on that box. */
  --measure: 41rem;

  --font: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: var(--font);
  /* No role is set in it; it is here for a code span, should one ever be written. */
  --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-22: 1.375rem;
  --t-24: 1.5rem;
  --t-16: 1rem;
  --t-32: 2rem;
  /* The ranged steps. Restrained, at her word (9 Nov: the font sizes are too large) - the hero ran to 48
     and reads at 38 now - and a little above what the monospaced face needed, because a proportional
     one puts the same sentence in less room. */
  --t-sec: clamp(1.3125rem, 1.1rem + 0.8vw, 1.625rem);
  --t-proj: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  /* The introduction: 26 on a phone to 38 on a desktop. */
  --t-48: clamp(1.625rem, 1.25rem + 1.5vw, 2.375rem);

  /* ---------- the type system ----------
     One face, two weights, eight pairs for eleven roles: the introduction, two heading bands, one
     reading size, and the four small ones. Hierarchy is size and colour first and weight only where a
     line has to be told from the line under it - Regular and Medium, nothing heavier. */
  /* HERO / INTRODUCTION. */
  --h1-font: 400 var(--t-48) / 1.2 var(--font-display);
  /* A touch of negative tracking on the two display bands, which is what a grotesque wants at size and
     nothing below them needs. */
  --h1-track: -0.018em;
  /* SECTION HEADINGS. */
  --h2-font: 500 var(--t-sec) / 1.3 var(--font-display);
  --h2-track: -0.012em;
  /* The hero's own line is the introduction role, not a tighter copy of the section heading. */
  --hero-font: var(--h1-font);
  /* PROJECT HEADINGS. */
  --h3-font: 500 var(--t-proj) / 1.35 var(--font-display);
  --h3-track: -0.008em;
  /* BODY - one reading size, at sixteen. */
  /* b1 and b2 were the same number - 16 over 1.6, twice - which meant the system had eleven roles and
     only ten meanings. b1 is the reading size now, 18 over 1.62: it is what About is set in, and what a
     standfirst over an article is set in, both of which are prose somebody sits down to read rather than
     words beside a picture (her word, 9 Nov: in the About it kinda is too small). b2 stays at 16 and
     keeps the rest - a case's body, an essay's paragraphs, a row's title - so an article's opening line
     is now a step above its paragraphs, which is what a standfirst is for. */
  /* Twenty-two, the largest body on the site. It has gone 16 to 18 to 20 and now here (her word, 9 Nov:
     I meant too small, I want bigger font) - About is the page that is nothing but prose, read sitting
     still, and it carries the size that suits that rather than the size the rest of the site is set in.
     In its 36rem column that is about 49 characters a line, which is the tight end of the reading range
     and where a larger size has to sit unless the column grows with it.
     The leading comes in as the size goes up: 1.45, where 16px sits at 1.6 (her word, 9 Nov: bigger font
     so it looks better with a bit smaller line height). It is the rule rather than a preference - leading
     goes with the measure, and a 49-character line needs far less help finding the next one than a
     71-character line does. A standfirst over an article wears this too, a clear step above the 16 its
     paragraphs are set in, and it is the line that most wanted the tightening. */
  --b1-font: 400 var(--t-22) / 1.45 var(--font);
  --b2-font: 400 var(--t-16) / 1.6 var(--font);
  /* SHORT DESCRIPTIONS - what people say, the line under a clip, the note on a piece of work. */
  --b3-font: 400 var(--t-15) / 1.58 var(--font);
  /* NAVIGATION AND METADATA - the tabs, the buttons, the years, the roles. */
  --l1-font: 500 var(--t-13) / 1.45 var(--font);
  /* CAPTIONS. */
  --l2-font: 400 var(--t-13) / 1.5 var(--font);
  /* MARKS - twelve, with the tracking that tells a tag from a label. */
  --l3-font: 500 var(--t-12) / 1.45 var(--font);
  /* PROJECT HEADING, on a card - tied to the card's own measure so a sentence written across a picture
     grows with the picture rather than with the window. */
  --card-type: clamp(24px, 2.2vw, 30px);
  --c1-font: 500 calc(var(--card-type) * 0.66) / 1.3 var(--font-display);
  --c1-track: -0.008em;
  --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. */
/* Emphasis inside a sentence is Medium, not Bold. A browser's own idea of <b> and <strong> is 700, which
   on this scale is a shout in the middle of a paragraph and the one weight the system does not own. */
b, strong { font-weight: 500; }
.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(--h1-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. */
/* Inter, which carries the whole site. Her word, 9 Nov, was to use the face x.com is set in: that one
   is Chirp, which is X Corp's own and is not licensed to anybody else, and Inter is the open grotesque
   it is routinely stood in for - the same neutral, slightly narrow, screen-first drawing. One variable
   file, latin only, 47 KB, 100 to 900, so every weight the page asks for comes out of a single
   download. SIL Open Font License 1.1.

   This is not the 352 KB inter-var.woff2 below it: that one is the full family, claimed only by her
   Miro brand study, which is a page about somebody else's type system and needs the whole of it. */
@font-face {
  font-family: "Inter";
  src: url('/assets/fonts/inter-latin-var.woff2') format('woff2');
  font-weight: 100 900;
  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 srgb, 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 srgb, 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: 500; 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: 500; 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: 500;
}

.mf-post { display: flex; flex-direction: column; gap: 8px; }
.mf-post-title { font: var(--b2-font); font-weight: 500; 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: #f5f6f8;
}
: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: #f5f6f8; }
  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: #f5f6f8; }
}
/* 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); }
/* Only for a reader with no JavaScript. The shell replaces the whole of the page it stands in, so with
   scripts on these two are a flash of something nobody meant to show and nothing else. The mark is set
   in the head of the document, before the first paint. */
html[data-js] :is(.mf-pre-nav, .mf-pre-foot) { display: none; }
.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: 500; }
/* 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: 500; }
.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; }
