/* ============================================================
   FOUNDATION: DEVICES
   Created 2026-08-08.

   Where a PROMOTED device lives. A device arrives here when a page
   rebuild designed something for itself that there could be more than
   one of, per step 4b of the redesign skill. `foundation.css` stays
   the base layer (tokens, paint, type, buttons, sections, surfaces)
   and is already at its size ceiling; appending every promoted device
   to it is how a shared file becomes unreadable.

   Loaded immediately AFTER `foundation.css` and BEFORE
   `foundation-members.css`, so the cascade order of everything that
   existed before this file is unchanged. The breadcrumb moved here whole when it was redesigned, which was
   safe to do because no other file in the layer targets `.fnd-crumbs`
   (checked, not assumed). Everything else here is new. A move is only
   ever allowed when nothing later in the cascade can be reordered by
   it; otherwise write the new rules here and leave the old ones where
   they are.

   Same rules as the rest of the layer: every selector carries the
   `fnd-` prefix or a `.fnd` ancestor, element rules go in `:where()`,
   and a device sits ON a surface rather than becoming one.
   ============================================================ */

/* ------------------------------------------------------------------
   RECIPE: the opening summary  (added 2026-08-08)

   One question-shaped heading and one dense paragraph that answers the
   whole page, with the date it was last checked. It exists because
   search engines and AI answer engines lift it, and on five of our
   public pages it had been sitting there looking exactly like that:
   the founder called it an eyesore, and he was describing something
   real rather than a taste.

   THE FIX IS MOSTLY SUBTRACTION, and the ranked research says so
   plainly: delete the container. A card with a border, a fill and a
   radius announces "this is a separate thing that was added", which is
   precisely the impression to avoid. What is left is a standfirst: two
   hairlines, a generous measure, a step up in size, and air. That is
   how a newspaper marks its opening paragraph and how Wikipedia marks
   a lead section, and neither of them reaches for a box.

   Four decisions worth keeping:

   - HAIRLINES, NOT A BOX. A rule above and below says "read this
     first" without claiming to be a separate object. It also keeps the
     section auditable: only `.fnd-sec--tint` and `.fnd-ink-surface`
     paint a full-width field, and a device must never become a
     surface.
   - ONE STEP UP, NOT TWO. Lede size with loose leading. The summary is
     the standfirst; it should read as the opening of the page, not as
     a pull quote competing with the hero.
   - THE DATE IS A BYLINE, NOT A BADGE, and it sits UNDER the question
     where a byline goes. Above the heading it was the first thing on
     the block, which is metadata furniture, which is the SEO-slab tell
     again.
   - EMPHASIS IS APPLIED AT RENDER, never written into the source
     text. Three to five load-bearing terms in bold break the slab and
     give a scanner something to land on, and doing it at render means
     the same string can still be handed to structured data without
     shipping markup inside it. Same rule as the FAQ answers.

   Deliberately NOT done here, because both are copy and copy on a page
   that already ranks is the founder's call, not a stylesheet's: adding
   a 40 to 55 word direct answer above the prose, and moving surplus
   inline links out into a "Related" line. Both are the highest-rated
   recommendations in the research and both are waiting on him.
   ------------------------------------------------------------------ */
/* THE QUESTION IS ONE COLUMN, THE ANSWER IS THE OTHER. Second pass,
   2026-08-08, after the founder looked at the first one and said do
   better. Deleting the card was right and not enough: what was left
   was still a heading with 150 words of grey text under it, which is a
   slab whether or not it has a box round it.
   The heading is a QUESTION and the paragraph is its ANSWER, and
   nothing on the page said so. Setting them side by side, with a rule
   between, makes the pair visible before a word is read: this is the
   thing you wanted to know, and this is the answer. It is the same
   move the questions block makes further down the page, which is the
   point. A page should have a small number of ideas used consistently.
   The date moved UNDER the question, where a byline goes, instead of
   floating above the heading as the first thing on the block. */
.fnd-summary {
  max-width: none;
  padding: var(--fnd-s6) 0;
  border-top: 1px solid var(--fnd-rule);
  border-bottom: 1px solid var(--fnd-rule);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--fnd-s5);
}
@media (min-width: 900px) {
  .fnd-summary {
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
    gap: var(--fnd-s8);
    padding: var(--fnd-s7) 0;
    align-items: start;
  }
  .fnd-summary-a { border-left: 1px solid var(--fnd-rule); padding-left: var(--fnd-s8); }
  .fnd-ink-surface .fnd-summary-a { border-left-color: var(--fnd-on-ink-rule); }
}
/* The `.fnd ` prefix is not decoration. `.fnd :is(h1, h2, h3)` in the
   base block scores (0,1,1) and would beat a bare component class at
   (0,1,0), taking this margin with it. Six other rules in this layer
   carry the same prefix for the same reason. */
.fnd .fnd-summary h2 { max-width: 20ch; margin: 0; }
.fnd-summary-when {
  font-size: var(--fnd-t-micro);
  color: var(--fnd-text-faint);
  margin: var(--fnd-s3) 0 0;
}
.fnd-summary-a {
  font-size: var(--fnd-t-lede);
  line-height: 1.75;
  color: var(--fnd-text-soft);
  margin: 0;
  max-width: 62ch;
}
/* The bolded terms. Full ink against the softer prose, so the eye lands
   on them without the paragraph turning into a row of shouting
   fragments. Weight 600, not 700: at 700 five of them in one paragraph
   read as five separate headings. */
.fnd-summary-a b, .fnd-summary-a strong { color: var(--fnd-text); font-weight: 600; }
.fnd-ink-surface .fnd-summary-a { color: var(--fnd-on-ink-soft); }
.fnd-ink-surface .fnd-summary-a b, .fnd-ink-surface .fnd-summary-a strong { color: #fff; }
.fnd-ink-surface .fnd-summary { border-color: var(--fnd-on-ink-rule); }
.fnd-ink-surface .fnd-summary-when { color: var(--fnd-on-ink-faint); }


/* ------------------------------------------------------------------
   THE MICRO LABEL  (promoted 2026-08-08)

   The quietest line the system has: a small, plain, faint line sitting
   under something louder. The sub-line under a pinned bar's button, the
   caption under a rail heading, the unit under a figure.

   It arrives here because the devices gate caught the same five
   declarations written out longhand on a page under a page-private
   name, byte for byte identical to `.fnd-rail-head-l` in the member
   layer. That class is the same treatment scoped to one component, and
   reaching into a rail's namespace from a public page would be worse
   than the duplicate. **`.fnd-rail-head-l` should fold into this next
   time the member layer is touched**; it is left alone here because
   renaming a live class is a change of its own, not a footnote to a
   page rebuild.
   ------------------------------------------------------------------ */
.fnd-microlabel {
  display: block;
  font-family: var(--fnd-body-font); font-weight: 500;
  font-size: var(--fnd-t-micro); color: var(--fnd-text-faint);
}
.fnd-ink-surface .fnd-microlabel { color: var(--fnd-on-ink-faint); }

/* ------------------------------------------------------------------
   BREADCRUMB  (rebuilt 2026-08-08)

   The way out, and nothing more. The H1 directly below already says
   where you are, so the trail's only unique value is the link to the
   parent. Everything here follows from that one sentence.

   THREE FAULTS, in the founder's words, each with a different cause.

   1. REAL ESTATE. It spent a 78px band (a 44px link plus a 34px gap)
      above the first thing anyone came to read; it now spends ~46px.
      Nothing was made smaller: the type stays at --fnd-t-meta, because
      shrinking a trail below 14px is the mobile failure Nielsen Norman
      names, and the height came out of the PADDING instead. The 44px
      hit area survives in full, bought with vertical padding on an
      INLINE anchor: that padding is inside the border box but outside
      the line box, so a pointer and a checker measure 44px while the
      layout measures 20px. Hence `display: inline`, and hence the list
      item must NOT be a flex container, because a flex child is
      blockified and the padding would push the row open again. (WCAG
      2.5.8 asks 24px, so this over-delivers. It replaces the old
      `min-height: 44px`, which had been declared on a duplicated
      selector, a trap of its own.)

   2. STANDING OUT. The loudest item was the CURRENT page, at full ink
      and weight 600: the one crumb with no destination, in the
      strongest colour on the line. It now recedes and the ANCESTORS
      carry the weight, which is the way round every reference
      implementation does it.

   3. ALIGNMENT was never a breadcrumb bug. See --fnd-shell-w.

   It also no longer wraps: a trail on two lines stops reading as a
   trail, so it truncates from the end instead, which is the item worth
   losing. Below 600px it collapses to the parent alone with the
   chevron flipped, reading as one back link. The markup and the
   BreadcrumbList data are untouched by that, because Google's guidance
   is not to mark up content that is not visible: shortened, never
   deleted.
   ------------------------------------------------------------------ */
.fnd-crumbs {
  font-size: var(--fnd-t-meta);
  line-height: 1.45;
  color: var(--fnd-text-faint);
  margin: 0 0 var(--fnd-s5);
}

/* THE TRAIL AS A BAR, and this is the version a page should reach for
   when the trail opens the page rather than sitting inside a column of
   content. Added 2026-08-08 on the founder's second look: the trail was
   correct in every measurement and still looked wrong, because a short
   left-aligned line floating in the top-left of a large field, above a
   CENTRED headline, has no relationship to anything on the screen. It
   was not too big or too loud by then. It had nowhere to live.

   So it gets a bar: tight vertical padding, a hairline under it, and
   the page's content starting cleanly below. The rule is what does the
   work. It gives the line an edge to sit on, separates the trail from
   the hero instead of leaving it adrift in it, and reads as a masthead
   rather than as a stray link somebody left at the top.

   The persistent underline goes with it. Inside a bar, under a rule,
   in a labelled `<nav>`, with chevrons between the items, the
   affordance is carried by the structure; the underline was simply the
   loudest thing on the line and made the first crumb look like an
   orphaned link rather than the start of a trail. It returns on hover
   and on focus, so it is never colour alone at the moment of use. */
.fnd-crumbs--bar {
  margin: 0;
  padding: var(--fnd-s3) 0;
  border-bottom: 1px solid var(--fnd-rule);
}
.fnd-ink-surface .fnd-crumbs--bar { border-bottom-color: var(--fnd-on-ink-rule); }
/* IT HAS TO LIFT ITSELF OFF THE SURFACE. `.fnd-ink-surface` paints its light
   source in `::before` and its grain in `::after`, both `position: absolute;
   inset: 0` with no z-index, so anything inside it that is not positioned gets
   painted OVER. `.fnd-ink-in` solves this for the hero's content by being
   `position: relative`, and the trail sits OUTSIDE that wrapper on purpose, so
   it has to solve it for itself. Without this the trail renders and measures
   perfectly and is invisible on screen, which cost a full look to spot: every
   computed style said white at 80% opacity, visible, in the right box. */
.fnd-ink-surface .fnd-crumbs { position: relative; }
.fnd .fnd-crumbs--bar a:not(.fnd-btn) { text-decoration-color: transparent; }
.fnd .fnd-crumbs--bar a:not(.fnd-btn):hover,
.fnd .fnd-crumbs--bar a:not(.fnd-btn):focus-visible { text-decoration-color: currentColor; }
/* One line, truncated at the end rather than wrapped. `display: block`
   and not flex, so the anchors below stay genuine inline boxes. */
.fnd-crumbs ol {
  list-style: none; margin: 0; padding: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fnd-crumbs li { display: inline; }
/* The hit area. `padding` gives 44px inside the border box at no cost
   to the line box; the negative inline margin gives back the sideways
   space, which DOES apply to an inline element.

   THE `.fnd ` PREFIX AND THE `:not()` ARE LOad-BEARING, not decoration.
   The base block carries
     `.fnd :is(p, li, summary, em, span) > a:not(.fnd-btn) { color: inherit }`
   at (0,2,2), which is the highest-specificity element rule in the
   layer. A breadcrumb anchor is an `li > a`, so that rule caught it and
   forced `color: inherit`, and the trail's links rendered in the same
   faint ink as the separator: measured .55 white on ink when the rule
   below says .80. A component losing to a base rule is the exact trap
   section 11 of the spec describes; this is the same failure in a
   different costume, because the guard clauses in that selector push it
   ABOVE a plain component class.
   The clean fix is to lower that base rule with `:where()`, but it is
   shared by every foundation page including an unapproved homepage
   rebuild, so it is recorded as a known trap rather than changed under
   a page's deadline. Here the component simply wins on its own terms:
   (0,3,1) beats (0,2,2). */
.fnd .fnd-crumbs a:not(.fnd-btn) {
  display: inline;
  color: var(--fnd-text-soft);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  /* TRANSPARENT AT REST, not the hairline colour it used to be. The founder's
     rule is that colour and weight say link and an underline appears on hover
     only; he has now said it twice. A faint standing underline is still a
     standing underline, and this device is the most visible place it survived
     (the public /collaborations category pages).

     The underline itself is kept and only its colour is animated, because
     switching `text-decoration` on and off at hover reflows the line box and
     makes the trail twitch. The transition on the line below was already
     written for exactly this. */
  text-decoration-color: transparent;
  /* 13, not 12: the line box measures 18px here, so 12 lands at 42 and
     misses the floor by two. Measured, not assumed. */
  padding: 13px 6px;
  margin-inline: -6px;
  transition: color 140ms ease, text-decoration-color 140ms ease;
}
.fnd .fnd-crumbs a:not(.fnd-btn):hover {
  color: var(--fnd-accent-deep);
  text-decoration-color: currentColor;
}
/* The separator is drawn on the item, so it never appears before the
   first crumb and never needs a spacer element. It is decorative and
   invisible to assistive technology by being a pseudo-element. */
.fnd-crumbs li + li::before {
  content: ""; display: inline-block;
  width: 5px; height: 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  margin: 0 var(--fnd-s3) 0 var(--fnd-s2);
  vertical-align: 1px;
  opacity: .55;
}
/* You are here. Quiet on purpose: it is the only item you cannot go to. */
.fnd-crumbs [aria-current] { color: var(--fnd-text-faint); font-weight: 400; }

/* Below 600px only the parent survives and its chevron turns into a
   back arrow, which is what both HubSpot and Asana ship. On a two
   level trail that leaves "Home"; on a three level one it leaves the
   hub, which is the more useful link of the two either way. The
   hidden items stay in the DOM and in the structured data. */
@media (max-width: 599px) {
  .fnd-crumbs li:not(:nth-last-child(2)) { display: none; }
  .fnd-crumbs li:nth-last-child(2)::before {
    content: ""; display: inline-block;
    width: 5px; height: 5px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(135deg);
    margin: 0 var(--fnd-s2) 0 0;
    vertical-align: 1px;
    opacity: .55;
  }
}

/* THE SAME TRAIL, ON INK. The SEO landing pages open on an ink hero and
   the trail has to sit inside it, where every colour above is an
   ink-on-ink value. Measured on #16141A: .80 white is 12.1:1, .55 is
   6.0:1, and the accent #8F87FF is 7.4:1, so all three clear AA and the
   hover stays the same gesture it is on paper. Only the colours move:
   the geometry above is shared, which is what stops the two surfaces
   drifting apart. */
.fnd-ink-surface .fnd-crumbs { color: var(--fnd-on-ink-faint); }
.fnd .fnd-ink-surface .fnd-crumbs a:not(.fnd-btn) {
  color: var(--fnd-on-ink-soft);
  text-decoration-color: var(--fnd-on-ink-rule);
}
.fnd .fnd-ink-surface .fnd-crumbs a:not(.fnd-btn):hover {
  color: var(--fnd-accent);
  text-decoration-color: currentColor;
}
.fnd-ink-surface .fnd-crumbs [aria-current] { color: var(--fnd-on-ink-faint); }
/* The bar's no-underline rule has to live AFTER the ink block, not with the
   rest of `--bar` above it. Both selectors score (0,3,1), so the tie goes to
   whichever is written last, and written first the ink rule put the underline
   straight back on. Ties are decided by source order and source order is easy
   to get wrong from twenty lines away. */
.fnd .fnd-crumbs--bar a:not(.fnd-btn),
.fnd .fnd-ink-surface .fnd-crumbs--bar a:not(.fnd-btn) { text-decoration-color: transparent; }
.fnd .fnd-crumbs--bar a:not(.fnd-btn):hover,
.fnd .fnd-crumbs--bar a:not(.fnd-btn):focus-visible,
.fnd .fnd-ink-surface .fnd-crumbs--bar a:not(.fnd-btn):hover,
.fnd .fnd-ink-surface .fnd-crumbs--bar a:not(.fnd-btn):focus-visible { text-decoration-color: currentColor; }

/* ==================================================================
   THE LANDING-PAGE KIT  (promoted 2026-08-09)

   Six devices the free-youtube-* family and the first migrated tool
   page each built privately, caught by the devices gate the moment a
   second page entered the ledger: identical blocks under fywh-, fyl-,
   fyc-, fys-, fyv- and slg2- prefixes. A device invented twice is a
   design system that is quietly not one; five copies was the proof.

   Every rule here is the fywh original verbatim (the founder-reviewed
   page), renamed. The pages keep only what genuinely differs on them:
   grid column counts, one-off margins, and the JavaScript state
   classes their scripts toggle.

   Spec + gallery rows for these are handed over in
   .claude/plans/public-devices-handover.md, because the spec file and
   /dev/design-system belong to the parallel member-area session.
   ================================================================== */

/* ------------------------------------------------------------------
   The landing hero copy group. Chip, headline, standfirst, actions,
   reassurance, as two groups: what the page is (tight), what to do
   about it (tight), a real break between. The headline uses the
   SECOND display rung because these H1s carry the exact search phrase
   and cannot be shortened; the top rung strands a word per line.
   ------------------------------------------------------------------ */
.fnd-lp-hero { text-align: center; }
.fnd-lp-hero .fnd-chip { margin-bottom: var(--fnd-s4); }
.fnd .fnd-lp-title {
  font-size: var(--fnd-t-display-2);
  max-width: 20ch;
  margin: 0 auto var(--fnd-s4);
  text-wrap: balance;
}
.fnd-lp-sub {
  max-width: 56ch;
  margin: 0 auto var(--fnd-s7);
  font-size: var(--fnd-t-lede);
  line-height: 1.7;
}
/* The group break grows with the screen: 62px is right on a desktop
   and most of a phone screen; at 34 both buttons stay on the first
   screen and the break still reads against 20px inside the groups. */
@media (min-width: 768px) { .fnd-lp-sub { margin-bottom: var(--fnd-s8); } }
@media (max-width: 767px) { .fnd-lp-sub { margin-bottom: var(--fnd-s6); } }
.fnd-lp-go {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--fnd-s3);
}

/* ------------------------------------------------------------------
   The dot line. Short reassurances as ONE quiet line with middots
   drawn by CSS, never typed (a typed middot counts as a word against
   a locked page) and never three accent ticks (three bright discs
   under a button out-shout the button).
   ------------------------------------------------------------------ */
.fnd-dotline {
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center;
  gap: 0;
  margin: var(--fnd-s4) 0 0;
  font-size: var(--fnd-t-meta);
  color: var(--fnd-text-faint);
}
.fnd-ink-surface .fnd-dotline { color: var(--fnd-on-ink-faint); }
.fnd-dotline--left { justify-content: flex-start; }
.fnd-dotline span + span::before {
  content: "\00b7";
  margin: 0 10px;
  opacity: .6;
}

/* ------------------------------------------------------------------
   The flagged card set. One quiet accent rule above each card title
   in a warning set: a mark, not a red disc, because error styling
   stays off anything that is not an error the reader just caused.
   Sits on the card ROW wrapper beside .fnd-cards--3.
   ------------------------------------------------------------------ */
.fnd-cards--flagged .fnd-card-t::before {
  content: ""; display: block; width: 26px; height: 2px; border-radius: 2px;
  background: var(--fnd-accent); margin-bottom: var(--fnd-s3);
}
/* The ink card's paragraph colour, which every warning set needs and
   each page had re-declared. Completion of .fnd-card--ink, written
   here because foundation.css is at its size ceiling. */
.fnd-card--ink .fnd-card-sub { color: var(--fnd-on-ink-soft); }

/* ------------------------------------------------------------------
   The step number. A numeral that leads an ordered cell, in display
   weight, accent-deep so it reads as structure rather than decoration.
   Shared by the step grid below and any numbered card list.
   ------------------------------------------------------------------ */
.fnd-stepnum {
  display: block;
  font-family: var(--fnd-display-font); font-weight: 800;
  font-size: 34px; line-height: 1; letter-spacing: -.04em;
  color: var(--fnd-accent-deep);
  margin-bottom: var(--fnd-s3);
  font-variant-numeric: tabular-nums;
}
.fnd-ink-surface .fnd-stepnum, .fnd-card--ink .fnd-stepnum { color: var(--fnd-accent); }

/* ------------------------------------------------------------------
   THE NUMBERED SECTION HEAD                                  .fnd-numhead
   A dark ink circle carrying a step number, set beside a title. The circle
   matches collab-board's .cb-how-step__n (ink fill, on-ink glyph); the
   number is a CSS counter, NOT hardcoded, so a list of conditionally-shown
   sections never leaves a gap in the sequence (a display:none head does not
   increment). Reset the counter on the list container with .fnd-numlist.
   Promoted 2026-08-24 from the Studio Package rebuild.
   ------------------------------------------------------------------ */
.fnd .fnd-numlist { counter-reset: fnd-num; }
.fnd .fnd-numhead { display: flex; align-items: center; gap: var(--fnd-s3); }
.fnd .fnd-numhead__n {
  counter-increment: fnd-num;
  flex: 0 0 auto;
  width: 32px; height: 32px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--fnd-ink); color: var(--fnd-on-ink);
  font-family: var(--fnd-display-font); font-weight: 700; font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.fnd .fnd-numhead__n::before { content: counter(fnd-num); }
.fnd .fnd-numhead__t {
  margin: 0;
  font-family: var(--fnd-display-font); font-weight: 700; font-size: 20px;
  line-height: 1.2; color: var(--fnd-text);
}
.fnd-ink-surface .fnd-numhead__n, .fnd-card--ink .fnd-numhead__n { background: var(--fnd-on-ink); color: var(--fnd-ink); }

/* ------------------------------------------------------------------
   The step grid. Hairline cells in one, two, then four columns, the
   numeral leading each. NOT .fnd-steps: that is the member progress
   bar and answers a different question.
   ------------------------------------------------------------------ */
.fnd-stepgrid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 0;
  border-top: 1px solid var(--fnd-rule);
}
@media (min-width: 700px)  { .fnd-stepgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .fnd-stepgrid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.fnd-stepcell { padding: var(--fnd-s5) 0; border-bottom: 1px solid var(--fnd-rule); }
@media (min-width: 700px) {
  .fnd-stepcell { padding-right: var(--fnd-s5); }
  .fnd-stepcell:nth-child(2n) { padding-left: var(--fnd-s5); border-left: 1px solid var(--fnd-rule); }
}
@media (min-width: 1000px) {
  .fnd-stepcell { padding-left: var(--fnd-s5); border-left: 1px solid var(--fnd-rule); }
  .fnd-stepcell:nth-child(2n) { padding-left: var(--fnd-s5); }
  .fnd-stepcell:first-child { padding-left: 0; border-left: 0; }
}
.fnd .fnd-stepcell .fnd-card-t { margin: 0 0 var(--fnd-s2); }
.fnd .fnd-stepcell .fnd-card-sub { margin-top: var(--fnd-s2); }
.fnd-stepcell .fnd-card-sub strong { color: var(--fnd-text); font-weight: 600; }

/* ------------------------------------------------------------------
   The supporting figures. The two smaller true numbers beside the one
   hero figure on an ink band. One hero number per band: these take a
   clamped size a full step below .fnd-fig-n so the strong figure
   never borrows their doubt.
   ------------------------------------------------------------------ */
.fnd-figside { display: grid; gap: var(--fnd-s5); }
.fnd-subfig {
  padding-top: var(--fnd-s4);
  border-top: 1px solid var(--fnd-on-ink-rule);
}
.fnd-subfig strong {
  display: block;
  font-family: var(--fnd-display-font); font-weight: 800;
  font-size: clamp(1.8rem, 5vw, 2.4rem); line-height: 1; letter-spacing: -.03em;
  color: var(--fnd-on-ink); font-variant-numeric: tabular-nums;
}
.fnd-subfig span {
  display: block; margin-top: 7px;
  font-size: var(--fnd-t-meta); color: var(--fnd-on-ink-faint);
}
.fnd-figside .fnd-note { margin-top: 0; max-width: 46ch; }

/* ------------------------------------------------------------------
   The offer panel. One card, one price, one button: the paid route at
   the bottom of a free page. The price takes display size because it
   is the only number in the section and "how much" is the whole
   question the section answers.
   ------------------------------------------------------------------ */
.fnd-offer {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--fnd-s6);
  padding: var(--fnd-s6);
}
@media (min-width: 768px) {
  .fnd-offer { grid-template-columns: minmax(0, 1fr) auto; gap: var(--fnd-s8); align-items: center; padding: var(--fnd-s7); }
}
.fnd-offer-copy .fnd-chip { margin-bottom: var(--fnd-s3); }
.fnd .fnd-offer-copy .fnd-h2 { max-width: 22ch; }
.fnd-offer-copy .fnd-lede { margin-bottom: 0; }
.fnd-offer-act { display: flex; flex-direction: column; align-items: flex-start; gap: var(--fnd-s3); }
@media (min-width: 768px) { .fnd-offer-act { align-items: center; } }
.fnd-offer-price {
  margin: 0;
  font-size: var(--fnd-t-meta); color: var(--fnd-text-faint);
}
.fnd-offer-price strong {
  font-family: var(--fnd-display-font); font-weight: 800;
  font-size: 32px; letter-spacing: -.03em; color: var(--fnd-text);
  margin-left: 4px;
}

/* ------------------------------------------------------------------
   The pinned bar. Phones only: on a desktop the hero button is still
   on screen for most of the fold and a fixed bar would eat the page.
   Pages keep their own id, their legacy class and their own
   `--visible` state class, because the scroll script that drives it
   is shared with each OLD page so both versions are measured on the
   same ruler. The state class flips only transform and pointer-events.
   RELATED, for the merge pass: .fnd-actionbar (member) and this bar
   still disagree on breakpoint and z-index; that reconciliation is
   recorded in the handover, not hidden here.
   ------------------------------------------------------------------ */
.fnd-pinbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
  background: rgba(22, 20, 26, .94);
  backdrop-filter: blur(10px);
  border-top: 1px solid rgba(255, 255, 255, .12);
  transform: translateY(110%);
  transition: transform 240ms cubic-bezier(.22, 1, .36, 1);
  pointer-events: none;
}
.fnd-pinbar-link {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 54px; padding: 8px 20px;
  border-radius: 999px; background: #fff; color: var(--fnd-ink);
  font-family: var(--fnd-display-font); font-weight: 700; font-size: 16px;
  text-decoration: none; text-align: center;
}
/* The Google mark sits beside a label, not above a two-line stack, so
   the mark is hidden here rather than mis-stacked. */
.fnd-pinbar-link svg { display: none; }
.fnd-pinbar-link .fnd-microlabel { margin-top: 2px; }
@media (min-width: 900px) { .fnd-pinbar { display: none; } }

/* ------------------------------------------------------------------
   The quiet link list, when its rows are headings. .fnd-links draws
   a span and an em; a ranking page whose link rows are h3 + p cannot
   swap its tags without dropping headings from its outline, so the
   same drawing applies to those tags here. Extension of a
   foundation.css component, written here because that file is frozen
   this session; fold it into .fnd-links proper on the merge pass.
   ------------------------------------------------------------------ */
.fnd .fnd-links a h3 {
  font-family: var(--fnd-display-font); font-weight: 700; font-size: 17.5px;
  letter-spacing: -.015em; color: var(--fnd-text); margin: 0;
  transition: color 140ms ease;
}
.fnd-links a p { font-style: normal; font-size: var(--fnd-t-meta); color: var(--fnd-text-soft); margin: 2px 0 0; }
.fnd .fnd-links a:hover h3 { color: var(--fnd-accent-deep); }


/* ---------------------------------------------------------------------
   PAGE HEADER, INK   .fnd-pagehead--ink
   Promoted from /collab-board, 2026-08-10.

   WHY THIS IS A DEVICE AND NOT ONE PAGE'S CSS. Section 9 of the spec
   requires exactly one dark anchor at every width on a member page, and
   /studio put it on that page's identity CARD. A page with no identity
   card (a board, a list, a feed) has nowhere to put it, so the anchor
   goes on the one block every member page already has: its header.
   /collab-board was the first to need it; /activity, /community/watch
   and /collaborations all have the same shape, so this is the second
   copy waiting to happen and it belongs here.

   USE IT ON THE HEADER, NOT ON A HERO. The component's own rule still
   stands: the aside is a FIGURE, not a call to action. This paints the
   figure, it does not turn the header into a banner. Exactly one block
   per page carries this.

   BOTH CLASSES ARE REQUIRED, per anti-pattern one:
       <header class="fnd-pagehead fnd-pagehead--ink fnd-ink-surface">
   .fnd-ink-surface supplies the gradients, the grain, and the repaint
   of every chip, badge and quiet button standing on it. This modifier
   supplies the box and repaints what .fnd-pagehead owns, which the ink
   surface cannot know about.

   The number rises to 38px here. It is the one figure the member came
   to read and it is now standing on the page's only dark field; at the
   paper header's 30px it read as a caption on a poster. */
/* ---------------------------------------------------------------------
   THE BREADCRUMB INSIDE THE DARK MEMBER HEADER
   Added 2026-08-10, founder caught it by eye on /collab-board.

   `.fnd-crumbs` colours itself with --fnd-text-faint, which is correct on
   paper and invisible on the member header, because that bar is nearly
   black. Measured: rgb(110,104,120) on the dark bar, about 2:1, where the
   page it replaced used rgba(255,255,255,.8). The page name in the top bar
   is how a member knows where they are, so this is not a nicety.

   The device file already repaints crumbs standing on `.fnd-ink-surface`.
   The member header is NOT that class, so nothing reached it. Scoped to
   `.member-header` so every member page migrated after this one inherits
   the fix rather than rediscovering it.

   Also zero the bottom margin: `.fnd-crumbs` carries 26px of it to sit
   above a page heading, which inside a flex header bar just pushes the
   name off centre. */
.fnd .member-header .fnd-crumbs {
  margin: 0;
  color: rgba(255, 255, 255, .8);
  font-weight: 500;
}
.fnd .member-header .fnd-crumbs a { color: rgba(255, 255, 255, .8); }
.fnd .member-header .fnd-crumbs a:hover { color: #fff; }
.fnd .member-header .fnd-crumbs [aria-current="page"] { color: rgba(255, 255, 255, .8); }

/* .fnd prefix is REQUIRED, not decoration. `.fnd-pagehead` sets padding 0
   and a margin in foundation-members.css, which the bundle concatenates
   AFTER this file, so a bare `.fnd-pagehead--ink` (0,1,0) is in the file,
   reads correctly and does nothing at all. Measured: padding computed to
   0px and the header rendered as an unpadded black band. */
.fnd .fnd-pagehead--ink {
  padding: var(--fnd-s5) var(--fnd-s5);
  border-radius: var(--fnd-r);
  margin-bottom: var(--fnd-s6);
  align-items: center;
}
@media (min-width: 768px) {
  .fnd .fnd-pagehead--ink { padding: var(--fnd-s5) var(--fnd-s6); }
}

/* The header's own children. .fnd-ink-surface repaints what the SYSTEM
   owns and cannot reach these, exactly as the ink card could not reach
   /studio's channel name. z-index because ::before paints over content. */
.fnd .fnd-pagehead--ink > * { position: relative; z-index: 1; }
.fnd .fnd-pagehead--ink .fnd-pagehead-t { color: var(--fnd-on-ink); }
.fnd .fnd-pagehead--ink .fnd-pagehead-sub { color: var(--fnd-on-ink-soft); }
.fnd .fnd-pagehead--ink .fnd-pagehead-n { color: var(--fnd-on-ink); font-size: 38px; }
/* --fnd-text-faint measures 2.1:1 on ink. This is the same fault the
   Studio hero paid for with .fnd-help, in the other direction. */
.fnd .fnd-pagehead--ink .fnd-pagehead-l { color: var(--fnd-on-ink-faint); }
.fnd .fnd-pagehead--ink .fnd-pagehead-link { color: var(--fnd-on-ink); }
.fnd .fnd-pagehead--ink .fnd-pagehead-link:hover { color: var(--fnd-on-ink-soft); }
.fnd .fnd-pagehead--ink .fnd-pagehead-eyebrow { color: var(--fnd-accent); }

/* On a phone the aside comes first and sits ABOVE the title, so the
   figure and the title need to read as one block rather than two. */
@media (max-width: 767px) {
  .fnd .fnd-pagehead--ink { gap: var(--fnd-s2); }

  /* .fnd-pagehead-aside is one baseline-aligned flex line, which is right
     on a wide screen and breaks at 375px once the slot carries a link as
     well as the figure: "237 jobs for / you    How does this / work?",
     three ragged lines reading as two collided elements. Let the slot
     wrap and give the link its own full line. Scoped to --ink so the ten
     other pages using .fnd-pagehead are untouched. */
  .fnd .fnd-pagehead--ink .fnd-pagehead-aside { flex-wrap: wrap; align-items: baseline; }
  .fnd .fnd-pagehead--ink .fnd-pagehead-link { flex: 1 0 100%; margin-top: 2px; }
}

/* ---------------------------------------------------------------------
   GROUP LABEL   .fnd-group-label
   Promoted from /collab-board, 2026-08-11.

   A band across a list card that names the run of rows under it. The board
   needed it the moment two different kinds of item shared one surface: brand
   briefs above, shoutout jobs below. Without a name on each run, the rule
   between them reads as the END of the card rather than the start of a second
   group.

   It passes the counting test easily. /activity has three runs (live
   campaigns, collaboration offers, history), /collaborations and
   /community/watch both group their lists, and any list that ever shows two
   kinds of thing needs exactly this. It was written twice on ONE page before
   being promoted, under two class names with two different icon spacings,
   which is how the founder noticed: one title sat closer to its icon than the
   other because one used a literal space character and the other a flex gap.

   Use it INSIDE the card, not above it, so the band spans the full surface:

       <div class="the-card">
         <p class="fnd-group-label fnd-group-label--first">
           <i class="fas fa-file-alt"></i> Brands looking for creators
           <span class="fnd-group-label-n">2</span>
         </p>
         ...rows...
         <p class="fnd-group-label"><i class="fas fa-list"></i> Jobs</p>
         ...rows...
       </div>

   `--first` drops the top rule, because the card's own border is already
   there and two lines 1px apart is the seam this system's anti-pattern list
   names. The count sits right with `margin-left: auto` and stays quiet: it is
   an aside to the label, never a badge (a badge with no icon draws the dot,
   which reads as a stray bullet beside two words). */
.fnd-group-label {
  display: flex; align-items: center; gap: var(--fnd-s2);
  margin: 0;
  padding: var(--fnd-s3) var(--fnd-s4);
  background: var(--fnd-paper);
  border-top: 1px solid var(--fnd-rule);
  border-bottom: 1px solid var(--fnd-rule);
  font-family: var(--fnd-display-font); font-weight: 700;
  font-size: var(--fnd-t-sm);
  color: var(--fnd-text);
}
/* THE CARD'S OWN ROUNDED CORNER, GIVEN BACK. A band is a full-bleed
   rectangle with an opaque ground, so when it sits flush at the top of a
   card it paints square into the curve and the corner reads as if the
   outline stops there. Founder, 2026-08-16, on the onboarding form: "the
   rounded parts are missing the outline. The bottom edges seem fine" —
   and the bottom was fine because nothing full-bleed sits there.
   Measured: card radius 14px, band radius 0, band inset 1px from each
   edge, container overflow visible. Matching the container's radius on
   the two corners the band actually touches is the fix that needs no
   overflow clip, which a card cannot have while it holds a picker whose
   list escapes its bounds. */
.fnd-group-label--first {
  border-top: 0;
  border-top-left-radius: var(--fnd-r);
  border-top-right-radius: var(--fnd-r);
}
/* Fixed box on the glyph so two labels with DIFFERENT icons start their text
   at the same x. Without it a wide icon and a narrow one indent differently
   and the bands look misaligned, which is the fault that earned this device. */
.fnd .fnd-group-label i {
  flex: 0 0 auto; width: 16px; text-align: center;
  color: var(--fnd-accent-deep); font-size: 14px;
}
.fnd-group-label-n {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-size: var(--fnd-t-meta);
  color: var(--fnd-text-faint);
}

/* ---------------------------------------------------------------------
   THE PAGE-HEADER LINK NEEDS A GAP
   Added 2026-08-11, caught by eye on /activity: "Browse the marketplace→"
   with the arrow against the final letter.

   `.fnd-pagehead-link` is `display: inline-flex` in foundation-members.css,
   and inline-flex discards the whitespace between the label and a trailing
   icon, so every use of it renders that way. Fixed here rather than in the
   component's own file only because that file is carrying another session's
   in-progress work today; fold it into the component's block when it is next
   clean. Two classes, so it lands whichever way the bundle orders them. */
.fnd .fnd-pagehead-link { gap: 6px; }

/* ==================================================================
   THE ASK BAND: .fnd-ask
   Added 2026-08-12, rebuilding the Video Ideas step of the Create
   workspace.

   Every step of a multi-step tool is the same three parts: the step's
   NAME, ONE question with ONE box and ONE button, and then the
   ANSWERS. This is the middle part. It is promoted rather than left on
   the page because there are eight steps in that workspace alone and
   the next one to be rebuilt is Title, which 9,044 members used in 30
   days against this step's 372. A device built once for the quiet step
   and re-derived for the loud one is how a design system stops being
   one.

   It is INK because a working screen still needs one dark anchor
   (section 9 of the spec) and on a step the box IS the thing that must
   be noticed. Because it is identical on every step, the workspace
   gains a spine: a member who has learned one step has learned all of
   them.

   NOT .fnd-ink-in. That companion exists to lift content above the
   surface's two absolutely positioned overlays, which it does, but it
   also pads 76px top and bottom because it was written for a landing
   page hero. On a step that left 170px of dead air and the band stood
   313px tall for 140px of content. `.fnd-ask > *` does the lift alone.
   ================================================================== */
.fnd-ask { border-radius: var(--fnd-r); padding: 20px 22px 18px; overflow: hidden; }
.fnd-ask > * { position: relative; }
.fnd-ask-q { display: block; font-family: var(--fnd-display-font); font-weight: 700;
             font-size: var(--fnd-t-h3); line-height: 1.3; color: var(--fnd-on-ink);
             margin: 0 0 12px; }
.fnd-ask-in { display: flex; gap: 10px; align-items: stretch; }
.fnd-ask-f { flex: 1 1 auto; min-width: 0; min-height: 46px;
             border-radius: 10px; border: 1px solid var(--fnd-on-ink-rule);
             background: rgba(255, 255, 255, .08); color: var(--fnd-on-ink);
             font-family: var(--fnd-body-font); font-size: var(--fnd-t-body);
             line-height: 1.4; padding: 12px 14px; resize: none; }
.fnd-ask-f::placeholder { color: var(--fnd-on-ink-faint); }
.fnd-ask-f:focus { outline: 0; border-color: rgba(255, 255, 255, .55);
                   background: rgba(255, 255, 255, .12); }
.fnd-ask-go { flex: 0 0 auto; white-space: nowrap; }
.fnd-ask-hint { margin: 9px 0 0; font-size: var(--fnd-t-sm); line-height: 1.45;
                color: var(--fnd-on-ink-soft); }
/* On a phone the button cannot share the line with the box: a 44px
   control beside a 46px field leaves the field about 150px, which is
   not a box anyone types a sentence into. */
@media (max-width: 640px) {
  .fnd-ask { padding: 16px; }
  .fnd-ask-in { flex-direction: column; }
  .fnd-ask-go { width: 100%; justify-content: center; }
}

/* ==================================================================
   THE IDEA ROW: .fnd-idearow
   Added 2026-08-12, same rebuild.

   Three columns, every row, always in the same order: the SIGNAL that
   lets you judge it (a picture that proves it, or a meter that
   measures it), the THING itself, and the ONE action. Section 15 of
   the spec: a member reads a list DOWN a column, so a row that puts
   its facts wherever they fit has to be read one at a time.

   The action is quiet on every row on purpose. The screen's one filled
   button is the ask band's, which is a different action (it asks a
   question) rather than a louder version of the same one. Before this,
   the step carried three filled black buttons, which is the same as
   carrying none.

   Below 640px the three columns become one stack: three columns beside
   a picture do not fit in 375px, and the wrapping version is right
   there.
   ================================================================== */
.fnd-idearow { display: grid; grid-template-columns: 168px minmax(0, 1fr) auto;
               gap: var(--fnd-s2) var(--fnd-s4); align-items: center;
               padding: 13px 18px; border-top: 1px solid var(--fnd-rule); }
.fnd-idearow-sig  { grid-column: 1; grid-row: 1; }
.fnd-idearow-main { grid-column: 2; grid-row: 1; min-width: 0; }
.fnd-idearow-end  { grid-column: 3; grid-row: 1; }
.fnd-idearow-t { font-family: var(--fnd-display-font); font-weight: 700;
                 font-size: var(--fnd-t-body); line-height: 1.38; color: var(--fnd-text);
                 margin: 0 0 4px;
                 display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                 overflow: hidden; }
.fnd-idearow-m { margin: 0; font-size: var(--fnd-t-sm); line-height: 1.5;
                 color: var(--fnd-text-soft); }
.fnd-idearow-m b { color: var(--fnd-text); font-weight: 600; }
/* The picture that proves it. Bigger than a list thumbnail usually is,
   because on this step the picture IS the argument: 667 members a month
   press the row it belongs to, more than any other control here. */
.fnd-idearow-media { position: relative; border-radius: 8px; overflow: hidden;
                     aspect-ratio: 16 / 9; background: var(--fnd-ink-3); }
.fnd-idearow-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fnd-idearow-mult { position: absolute; left: 8px; bottom: 8px;
                    background: var(--fnd-ink); color: var(--fnd-on-ink);
                    border-radius: 7px; padding: 4px 9px;
                    font-family: var(--fnd-display-font); font-weight: 800;
                    font-size: 1rem; line-height: 1; letter-spacing: -.01em; }
.fnd-idearow-mult span { font-size: .75rem; font-weight: 600; letter-spacing: 0;
                         color: var(--fnd-on-ink-soft); margin-left: 4px; }
@media (max-width: 640px) {
  .fnd-idearow { grid-template-columns: minmax(0, 1fr); padding: 12px 14px; gap: 9px; }
  .fnd-idearow-sig, .fnd-idearow-main, .fnd-idearow-end { grid-column: 1; grid-row: auto; }
  .fnd-idearow-end .fnd-btn { width: 100%; justify-content: center; }
}

/* ==================================================================
   THE LIST  .fnd-list  (promoted 2026-08-12)

   THREE PAGES HAD GROWN THREE OF THESE. /studio wrapped its videos in a
   card and put a fixed-width score cell beside the title; /collab-board
   laid its 53 jobs straight onto the paper with a task column; /activity
   built a card with a heading band and four aligned cells. Same device,
   three times, differing in exactly the ways a member feels rather than
   notices: row height, picture box, whether the list had a card at all.

   /activity's is promoted here because it is the only one that makes the
   facts line up into COLUMNS down the whole list, which is the property
   that makes a list of twelve things readable without reading twelve
   things. Its own comments record that it was copied from
   .collabs-list-container on /collab-board and then fixed against the
   founder's reading of it, so this is the mastered version of a device
   that has already been round the houses twice.

   Everything below is that CSS, moved rather than rewritten, with its
   reasoning intact. The page-scoped names it used (.act-list,
   .act-group-head, .act-c-*) are gone; the pages now use these.
   ================================================================== */

/* A LIST IS A CARD. Founder, 2026-08-10: "I also dont like how the table of
   jobs doesnt have a background". A run of rows sitting straight on the paper
   reads as loose text, not as a table of things you can act on. */
.fnd-list {
  background: var(--fnd-card);
  border: 1px solid var(--fnd-rule);
  border-radius: var(--fnd-r);
  overflow: hidden;
}
.fnd-list + .fnd-list { margin-top: var(--fnd-s4); }

/* A LIST THAT IS NOT THE CARD. Some lists sit inside a card that already holds
   something else above them: a toolbar, a search box, a row of filters. That
   card is the surface, so the list gives up the surface, the border, the radius
   and the phone bleed, and keeps the parts that are actually the list: the rows,
   the cells, the picture box and the action column.

   Without this a list inside a card either draws a second box 1px inside the
   first, or has to opt out of the device entirely and re-invent the cells, which
   is what /studio was doing. */
.fnd-list--inset {
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
@media (max-width: 767px) {
  .fnd-list--inset { margin-left: 0; margin-right: 0; }
}

/* The runs of rows inside stop being surfaces of their own. .fnd-rows ships a
   border-top, which would otherwise draw a second line 1px inside the card's
   own border. */
.fnd-list .fnd-rows {
  background: none;
  border: 0;
  border-radius: 0;
  margin-bottom: 0;
}
/* The last row's divider would double up with the card's bottom border. */
.fnd-list .fnd-rows:last-child > .fnd-row:last-child { border-bottom: 0; }
.fnd-list > .fnd-row:last-child { border-bottom: 0; }

/* A group heading is a band INSIDE the card, not a floating label above it. */
.fnd-list-group {
  margin: 0;
  padding: var(--fnd-s3) var(--fnd-s4) var(--fnd-s2);
  border-top: 1px solid var(--fnd-rule);
  background: var(--fnd-paper-2);
}
.fnd-list > .fnd-list-group:first-child { border-top: 0; }

/* The card has no padding of its own, so the rows carry it. */
.fnd-list .fnd-row { padding-left: var(--fnd-s4); padding-right: var(--fnd-s4); }

/* THE THREE THINGS A LIST DECLARES FOR ITSELF, and nothing else. The picture
   box, the width of the action column, and the column template of the facts.
   Every list on the product varies on those three and on nothing else; the
   notes further down say why each one has to. What a list must NEVER redeclare
   is which cell means what, or the columns stop being comparable page to page. */
.fnd-list {
  --fnd-list-media-w: 84px;
  --fnd-list-media-h: 47px;
}
.fnd-list .fnd-row { grid-template-columns: var(--fnd-list-media-w) minmax(0, 1fr) auto; }

/* ------------------------------------------------------------------
   THE ROWS LINE UP INTO COLUMNS.  Founder, 2026-08-11: "Do you truly think we
   have optimized the table appearances? When I review the current live
   versions, they are far better."

   He was right about the mechanism, not just the look. The LIVE page is a
   TABLE: every row puts its facts in the same places, so twelve rows can be
   read DOWN a column ("which of these is in review", "which cost the most")
   without reading any of them across. A rebuild that crams the same facts into
   one wrapping line of chips lines nothing up with anything and forces every
   row to be read on its own. That is a feed, not a table, and it is why a
   scannable page can feel worse after being made prettier.

   What a real table pays for it is repeating the column label inside every
   single row (MY REQUEST, CREATOR SIZE, STATUS, ESCROWED, twelve times over).
   The cells here say what they are in their own words ("250 - 500
   subscribers", "2 escrowed"), so the alignment is kept and the repetition is
   not.

   display: contents on the meta paragraph is what lets its spans become cells
   of the row's own grid without another wrapper. Every cell is placed by an
   explicit grid-column, never by auto-flow: rows carry different numbers of
   facts (a Community Watch row has no size, a gift row has no money) and
   auto-flow would slide the survivors left and destroy the alignment this
   whole block exists to create.

   THE FOUR COLUMNS, in reading order:
     1  .fnd-row-t          what it is           (+ .fnd-cell--tag under it)
     2  .fnd-cell--detail   who, how big, how far along
     3  .fnd-cell--state    where it has got to
     4  .fnd-cell--value    what it is worth

   Below 900px there is not room for four columns beside a picture, so the
   whole thing reverts to the wrapping line it was, which is right on a phone.
   ------------------------------------------------------------------ */
@media (min-width: 900px) {
  .fnd-list .fnd-row-main {
    display: grid;
    /* THE WIDTHS ARE PER LIST, THE CELLS ARE NOT. A list of videos, a list of
       jobs and a list of campaigns hold different numbers of facts, so a single
       hardcoded template would leave one of them with an empty 146px column and
       squeeze another. The default is the four-fact case; a list that carries
       three declares its own. What must NOT vary is which cell means what, or
       the columns stop being comparable between pages. */
    grid-template-columns: var(--fnd-list-cols,
      minmax(0, 1.55fr)   /* what it is */
      minmax(0, 1fr)      /* who, or how big, or how far along */
      118px               /* status */
      146px);             /* money */
    grid-template-rows: auto auto;
    align-items: center;
    column-gap: var(--fnd-s3);
  }
  .fnd-list .fnd-row-main > .fnd-row-t {
    grid-column: 1; grid-row: 1; margin: 0; align-self: end;
    /* One line here. A title that wraps to two pushes the line under it a
       whole row away from the title it belongs to. */
    -webkit-line-clamp: 1;
  }
  .fnd-list .fnd-row-main > .fnd-row-meta { display: contents; }

  /* The kind chip belongs with the title, under it, in column one. */
  .fnd-list .fnd-row-meta > .fnd-cell--tag {
    grid-column: 1; grid-row: 2; justify-self: start; align-self: start; margin-top: 4px;
  }

  /* EVERY CELL STARTS ON THE SAME LINE, not in the middle of its own row.
     Founder: "the verbiage doesnt align vertically as I look down the table."
     He was reading a column, and centring each cell inside ITS OWN row box
     floats the detail, status and money of a two-line row 10px lower than the
     row above. These SPAN both grid rows instead, so row one is sized by the
     title alone and row two by the line under it: a detail that runs long
     grows downwards instead of shoving the chip away from its title. */
  .fnd-list .fnd-row-meta > .fnd-cell--detail,
  .fnd-list .fnd-row-meta > .fnd-cell--state,
  .fnd-list .fnd-row-meta > .fnd-cell--value { grid-row: 1 / span 2; align-self: center; line-height: 21px; }
  .fnd-list .fnd-row-meta > .fnd-cell--detail {
    grid-column: 2;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .fnd-list .fnd-row-meta > .fnd-cell--state { grid-column: 3; justify-self: start; }
  .fnd-list .fnd-row-meta > .fnd-cell--value { grid-column: 4; justify-self: start; white-space: nowrap; }
  /* A badge is a pill, so its own box height decides where its text sits. Pin
     it to the same line as the plain text either side of it. */
  .fnd-list .fnd-row-meta > .fnd-badge.fnd-cell--state { line-height: normal; margin-top: -1px; }

  /* THE ACTION COLUMN HAS TO BE A FIXED WIDTH, and this is the whole alignment
     story. .fnd-row is 104px minmax(0,1fr) auto, so the end column sizes
     itself to whatever that row happens to hold. One row carries a button and
     a switch, its neighbour carries only the switch; the end column is
     therefore ~160px wider on one than the other, the main column absorbs the
     difference, and all four cells inside it slide sideways. Measured in the
     founder's own screenshot: "5 escrowed" landed at two different x positions
     two rows apart.

     Everything before this fixed the VERTICAL rhythm, which is why it kept
     looking half-solved: the remaining fault was horizontal and lived in a
     column nobody had touched.

     SIZED PER LIST, not once for the whole product. A list whose rows carry
     three controls needs 280px; a list carrying one small "See proof" needs
     168px, and forcing the wider number on it leaves a band of empty air down
     its right side and crushes the content columns leftwards. Each list
     declares its own --fnd-list-actions; the width is still FIXED within a
     list, which is the part that keeps every row aligned. */
  .fnd-list .fnd-row { grid-template-columns: var(--fnd-list-media-w) minmax(0, 1fr) var(--fnd-list-actions, 168px); }
  .fnd-list .fnd-row-end {
    width: var(--fnd-list-actions, 168px);
    justify-content: flex-end;
    /* Wrapping is the honest answer when a rare row carries three controls:
       the column keeps its fixed width so every other row stays aligned, and
       that row grows a second line instead of trampling its neighbour. */
    flex-wrap: wrap;
    row-gap: 6px;
  }
  /* ONE WIDTH FOR THE REPEATED ROW ACTION. "See proof" and "View results" are
     the same act in the same column, and a button that changes width every few
     rows makes the right edge of the list ragged, which is the loudest kind of
     untidiness on a list. Only the repeated action, never a one-off. */
  .fnd-list .fnd-row-end > .fnd-btn { min-width: 132px; justify-content: center; }

  /* A row that dropped its picture keeps the same four columns, so those rows
     line up with each other even though they line up with nothing else. */
  .fnd-list .fnd-row--nomedia .fnd-row-main { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) 118px 146px; }
}

/* Anything a row adds that has no column of its own joins the cell it sits in
   rather than claiming a fifth column and pushing the money out of line. */
.fnd-cell-note { display: block; margin-top: 2px; color: var(--fnd-text-faint); }

/* THE KIND LABEL IS NOT A PILL ON A PHONE. As a full chip it stands 32px tall
   and, at 93px wide beside a 142px detail, it cannot share a line, so the four
   facts take THREE lines and the row reaches 194px against the live page's
   161px. Stripped to plain text it shares the line with the detail, the status
   and the money share the next, and the row comes back to about 155px. It also
   stops three pills sitting in a stack of rows, which is the "count the heavy
   elements in a row" note in the spec.

   Spelling "subscribers" in full is what pushes it over in the first place, and
   that is not negotiable: our own rule bans the abbreviation. So the space is
   found here instead. */
@media (max-width: 640px) {
  .fnd-list .fnd-row-meta > .fnd-cell--tag {
    background: none;
    border: 0;
    padding: 0;
    min-height: 0;
    height: auto;
    color: var(--fnd-text-faint);
    font-weight: 600;
  }
  .fnd-list .fnd-row-meta > .fnd-cell-note { display: block; margin-top: 2px; }
}

/* A date is not a headline. It was a filled chip once, the loudest thing in a
   finished row after the title, for the least consequential fact on the page. */
.fnd-cell--date { color: var(--fnd-text-faint); font-weight: 500; }

/* ------------------------------------------------------------------
   THE PICTURE COLUMN IS ONE COLUMN, so everything in it sits in the same box.
   Founder: "the avatar beside Collaborator Spot isnt nicely centered in the
   space. Its off to the side."

   Measured: a video thumbnail rendered 84x47 and an avatar 40x40, and the
   small one was pinned to the left of an 84px cell, so a list mixing the two
   had pictures starting at two different x positions and floating at two
   different heights. The columns of TEXT were aligned the whole time, which is
   why this survived a pass: the ragged thing was the artwork.

   A video is a rectangle and a person is a circle, and that difference is
   honest, but they share a centre line either way.

   THE BOX SIZE IS PER LIST for the same reason the columns are: a list of
   videos wants a 16:9 frame, and a list whose every row IS a channel wants a
   bigger circle, because on that page the face is the thing being identified.
   What does not vary is that ONE box holds whatever the row shows.
   ------------------------------------------------------------------ */
.fnd-list .fnd-row-media {
  width: var(--fnd-list-media-w); height: var(--fnd-list-media-h);
  display: flex; align-items: center; justify-content: center;
}
.fnd-list .fnd-row-media > .fnd-avatar {
  width: var(--fnd-list-media-h); height: var(--fnd-list-media-h); flex: 0 0 var(--fnd-list-media-h);
  border: 1px solid var(--fnd-rule);
}
.fnd-list .fnd-row-media > .fnd-media {
  width: var(--fnd-list-media-w); height: var(--fnd-list-media-h);
  border: 1px solid var(--fnd-rule);
}

/* A ROW WITH NOTHING TO SHOW DOES NOT KEEP THE PICTURE COLUMN. Five identical
   grey placeholder tiles down one card is the "lone glyph reads as unfinished"
   note in the spec, five times over, and it costs the title 104px of width.
   Keep the column when the picture says WHICH one; drop it when every row
   would draw the same thing. */
.fnd-list .fnd-row--nomedia { grid-template-columns: minmax(0, 1fr) auto; }
.fnd-list .fnd-row--nomedia > .fnd-row-media { display: none; }
.fnd-list .fnd-row--nomedia > .fnd-row-main { grid-column: 1; }
.fnd-list .fnd-row--nomedia > .fnd-row-end { grid-column: 2; }

/* THE CARD IS WHAT BLEEDS, and only the outermost box may do it: a child
   pulled outside a clipping parent is cut, not bled. Boxing the list inside
   the page's 16px gutters and then padding the rows again would take 32px off
   a 375px text column for nothing. */
@media (max-width: 767px) {
  .fnd-list {
    /* The bleed has to equal the gutter its own page actually uses, and that
       is not one number across the product: `.page-container` gutters at 16px,
       and a page whose board sits inside a wider wrapper needs its own. A list
       that bleeds by more than its gutter pushes the card past the screen edge
       and puts a horizontal scrollbar on a phone, which is a P0 here. */
    margin-left: calc(var(--fnd-list-bleed, var(--page-gutter-mobile, 16px)) * -1);
    margin-right: calc(var(--fnd-list-bleed, var(--page-gutter-mobile, 16px)) * -1);
    border-left: 0;
    border-right: 0;
    border-radius: 0;
  }
  .fnd-list .fnd-row { padding-left: var(--fnd-s3); padding-right: var(--fnd-s3); }
  .fnd-list .fnd-list-group { padding-left: var(--fnd-s3); padding-right: var(--fnd-s3); }
}

/* ==================================================================
   TIDY CARD ROW  .fnd-cards--tidy          (promoted 2026-08-12)

   A row of cards whose bands line up ACROSS the row: every title on
   one line, every button on one line, every list starting on one
   line, however much or little each individual card carries.

   WHY THIS IS A COMPONENT AND NOT A PAGE FIX. Measured on the
   /dashboard destination cards, whose buttons sat at 207, 251, 295,
   159 and 203px within their own cards. Every card in a row was
   already the same height and every description already STARTED at
   the same 97px, so the heights were never the fault. The five link
   lists carry 4, 3, 2, 2 and 1 rows; the cards are stretched to a
   common height; and the one element allowed to grow sat ABOVE the
   button. So each missing 44px link row landed in the description
   and pushed that card's button down by exactly 44px. Lists of
   176/132/88px against buttons at 207/251/295px, to the pixel.

   Two earlier attempts moved the slack between the description and
   the button's own margin, and neither could have worked: any slack
   that lands above the button moves the button. Slack cannot be
   redistributed into alignment. The bands have to be MEASURED ACROSS
   THE ROW, which is what subgrid does and nothing else can. The row
   owns four tracks and each card borrows them.

   SHAPE THE ROW REQUIRES. Every child is either
     (a) a .fnd-card holding .fnd-card-head plus a .fnd-card-body of
         at most three parts (fewer is fine: the spare band is empty
         in that card and collapses), or
     (b) anything carrying .fnd-cards__whole, which keeps the row's
         footprint and gutter and lays its own interior out. Use it
         for a card whose content is a genuinely different kind of
         thing, as /dashboard's Mailbox card is.
   A body with FOUR or more parts spills into implicit rows and
   breaks the row. Split it, or opt it out.

   GUTTERS. A subgrid inherits its parent's gutters, so without the
   `row-gap: 0` below, the row's 20px gap is redrawn between every
   band inside every card. The gap between the two card ROWS is not
   spanned by any single card, so it keeps the parent's value. That
   is the whole reason no margin hack is needed here.
   ------------------------------------------------------------------ */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 720px) {
    .fnd .fnd-cards--tidy > .fnd-card:not(.fnd-cards__whole) {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 4;
      row-gap: 0;
    }
    .fnd .fnd-cards--tidy > .fnd-card:not(.fnd-cards__whole) > .fnd-card-body {
      display: grid;
      grid-template-rows: subgrid;
      grid-row: span 3;
      row-gap: 0;
      /* Bands are sized by the tallest card, so a card with less in
         one holds its content at the top of that band rather than
         floating it in the middle of space it did not ask for. */
      align-content: start;
    }
    /* AND EVERY BAND HOLDS ITS CONTENT AT THE TOP OF ITSELF.
       The founder caught this the moment it shipped: "the links below the
       buttons now get spread out vertically." A band is as tall as the tallest
       card's version of it, so the link band is sized by the card carrying four
       links. Without this, a card with two links stretches ITS list to fill the
       whole 176px and its own rows go from 44px to 88, so the alignment across
       the row is bought by wrecking the rhythm inside each card. Measured in
       one row: four rows at 44px, three at 58.7, two at 88, all in the same
       176px band.

       `align-self: start` on every band's content is what makes the leftover
       height show up as ONE quiet gap under a shorter card, which is what a row
       of cards is meant to look like, instead of as padding injected between
       somebody's links. */
    .fnd .fnd-cards--tidy > .fnd-card:not(.fnd-cards__whole) > .fnd-card-body > * {
      align-self: start;
    }

    /* A button must not take the band's full width. In a flex column
       `align-self` did that job; in a grid that axis is vertical, so
       it is said again on the axis that now matters. */
    .fnd .fnd-cards--tidy > .fnd-card > .fnd-card-body > .fnd-btn {
      justify-self: start;
      align-self: start;
    }
    /* The opt-out: same footprint, own interior. */
    .fnd .fnd-cards--tidy > .fnd-cards__whole {
      grid-row: span 4;
      display: flex;
      flex-direction: column;
    }
  }
}

/* ==================================================================
   THE CHAT BUBBLE  .fnd-bubble          (built 2026-08-12, founder)

   A speech bubble: a said thing, framed so it reads as speech before
   a word of it is read. Three surfaces want this and all three were
   drawing their own: the Concierge message on /dashboard, the same
   message inside the dock, and a thread in /mailbox.

   WHY A BUBBLE AND NOT A CARD. A card says "here is a block of
   content". A bubble says "somebody said this to you", which is a
   different claim and the whole reason the Concierge works at all:
   its message is advice from a character, not a panel of copy. The
   tail is what carries that, and it is the one part a page cannot
   fake with a border-radius.

   HOW TO USE IT

     <div class="fnd-bubble-row">
       <img class="fnd-bubble-face" src="..." alt="">
       <div class="fnd-bubble">
         <p>Your last three videos all lost people in the first
            fifteen seconds.</p>
       </div>
     </div>

   `.fnd-bubble-row` is the pairing of a face and a bubble, because
   both consumers need it and the alignment (face to the TOP of the
   bubble, not the middle) is the part every hand-built version gets
   wrong once the message runs to three lines.

   VARIANTS
     (default)        somebody else speaking. Paper, hairline, tail
                      on the left.
     --me             the member speaking. Accent-soft ground, tail
                      on the right, and the row reverses.
     --lead           the same bubble one size up, for the single
                      message a page is built around, as the
                      Concierge's is.

   ON INK it repaints itself: a bubble is a device and a device sits
   ON a surface rather than becoming one.

   THE TAIL is a rotated square keeping only the two borders that end
   up on the outside. See the note below it, which is the one thing on
   this component that has already been got wrong once.
   ------------------------------------------------------------------ */
.fnd-bubble {
  position: relative;
  display: block;
  max-width: 62ch;
  padding: var(--fnd-s3) var(--fnd-s4);
  background: var(--fnd-card);
  border: 1px solid var(--fnd-rule);
  /* Softer than the system card's radius on purpose. A card is an
     object with corners; speech does not have corners. */
  border-radius: 16px;
  color: var(--fnd-text);
  font-size: var(--fnd-t-body);
  line-height: 1.55;
}
/* A bubble holds prose, and prose brings its own top and bottom
   margins. Left alone they show up as uneven padding inside the
   frame, which is the single most common way a hand-built bubble
   looks slightly wrong without anyone being able to say why. */
.fnd-bubble > :first-child { margin-top: 0; }
.fnd-bubble > :last-child  { margin-bottom: 0; }

/* THE TAIL KEEPS THE TWO OUTER BORDERS, AND ONLY THOSE. This is the
   whole of it, and getting it wrong is what made the founder say the
   mailbox boxes "don't look like properly shaped message boxes... the
   diamond part looks weird", then ask the question that found the
   answer: "why can't it just be shaped like the one on /dashboard?"

   Because /dashboard was already drawing it correctly and this was not.
   `.cncg-strip__body` uses the identical technique, the identical 12px
   square, the identical -7px offset: the ONLY difference is which two
   of the four borders it keeps.

   A square rotated 45 degrees puts its `top` and `left` edges on the
   INSIDE, buried under the bubble, and its `bottom` and `left`... no:
   after the rotation the two edges that stick OUT are `bottom` and
   `left`. This kept `top` and `left` instead, so one visible outer edge
   was drawn and one was not, and the hairline that should have run
   around the point stopped halfway. That is why it read as a bent flag
   or a scratch rather than as speech, and why no amount of moving it,
   shrinking it or flattening it helped: the shape was never the fault.

   Measured off the working one rather than re-derived, which is the
   whole point of having a design system and is the step that was
   skipped. */

/* THE TAIL. 12px, tucked 7px under the bubble's own edge so the two
   hairlines meet rather than crossing. `border-width: 0 0 1px 1px` is
   the load-bearing line: after the 45 degree rotation those are the two
   edges that stick out, and they are the only two that may be drawn.
   A clip-path triangle is the other way to make this shape and cannot
   carry a border at all, which would leave the bubble outlined
   everywhere except at the one point that makes it a bubble. */
.fnd-bubble::before {
  content: "";
  position: absolute;
  /* 14, so the point lands on the MIDDLE OF THE FACE. `.fnd-bubble-face` is
     36px with a 2px top margin, so its centre sits 20px down the row; the
     tail is 12px square, so its own centre is `top + 6`. Founder, 2026-08-13:
     "could the avatar be aligned to the knub that sticks out of the message
     box? Right now it is not nicely aligned on both sides." Measured before
     changing anything: 12px out on a one-line message and 60px out on a
     three-line one, on both sides. A tail that points past somebody's head is
     worse than no tail, because it reads as a mistake rather than as speech. */
  top: 14px;
  left: -7px;
  width: 12px;
  height: 12px;
  background: inherit;
  border: 0 solid var(--fnd-rule);
  border-width: 0 0 1px 1px;
  transform: rotate(45deg);
}

.fnd-bubble--me {
  margin-left: auto;
  background: var(--fnd-accent-soft);
  border-color: var(--fnd-accent-soft);
}
/* Mirrored: the point flips to the member's own side, so a pair reads as
   two people facing each other rather than one column of boxes. The
   opposite two borders, for the same reason. */
.fnd-bubble--me::before {
  left: auto;
  right: -7px;
  border-color: var(--fnd-accent-soft);
  border-width: 1px 1px 0 0;
}

/* The one message a page is built around. */
.fnd-bubble--lead {
  padding: var(--fnd-s4) var(--fnd-s5);
  font-size: var(--fnd-t-lede);
  line-height: 1.6;
  border-radius: 20px;
}
/* The lead row's face is 48px, so its centre is 26px down and the tail's
   own centre has to be too. */
.fnd-bubble--lead::before { top: 20px; }

/* ON INK. */
.fnd-ink-surface .fnd-bubble,
.fnd-card--ink .fnd-bubble {
  background: rgba(255, 255, 255, .07);
  border-color: var(--fnd-on-ink-rule);
  color: var(--fnd-on-ink);
}
.fnd-ink-surface .fnd-bubble::before,
.fnd-card--ink .fnd-bubble::before { border-color: var(--fnd-on-ink-rule); }
.fnd-ink-surface .fnd-bubble--me,
.fnd-card--ink .fnd-bubble--me {
  background: var(--fnd-accent);
  border-color: var(--fnd-accent);
  color: var(--fnd-accent-glyph);
}
.fnd-ink-surface .fnd-bubble--me::before,
.fnd-card--ink .fnd-bubble--me::before { border-color: var(--fnd-accent); }

/* NO FACE, NO TAIL. A run of messages from one person shows the face once,
   at the top, because three copies of the same face is a column of noise
   rather than information. The tail has to follow it: left alone, the second
   and third message in a run each kept a point aimed at empty space beside
   them, which reads as a rendering fault.

   This is what every messaging product does, and the reason it is safe here is
   that nothing about ownership changes inside a run. The side the bubble sits
   on and the ground behind it both hold for every message in it, and the face
   still marks where the run begins. Founder's question, 2026-08-13: "is it
   best practice to keep showing the avatar beside each message box even if
   they write 3x in a row? And if not, should we remove the knub on the 2nd and
   3rd messages?" No, and yes.

   `:has()` reaches a face nested in a page's own wrapper as well as one that
   is a direct child, which matters because a list that has to reserve the
   face's width when it is absent will wrap it. */
.fnd-bubble-row:not(:has(.fnd-bubble-face)) .fnd-bubble::before { content: none; }

/* THE ROW: a face and what it said. */
.fnd-bubble-row {
  display: flex;
  align-items: flex-start;
  /* THE GAP HAS TO PAY FOR THE TAIL. The tail hangs 7px outside the bubble's
     own left edge, so a plain `gap: var(--fnd-s2)` leaves 10px between the face
     and the BUBBLE and only 3px between the face and the point that is actually
     nearest it. Measured in the Concierge dock, where an older 8px gap made it
     1px: "the concierge avatar is touching the blip".

     Published as a custom property as well as applied, so a surface whose own
     older rules set a gap on this same element can line itself back up by
     referring to it rather than by copying the number. */
  --fnd-bubble-gap: calc(var(--fnd-s2) + 7px);
  gap: var(--fnd-bubble-gap);
}
.fnd-bubble-row + .fnd-bubble-row { margin-top: var(--fnd-s3); }
.fnd-bubble-row:has(> .fnd-bubble--me) { flex-direction: row-reverse; }
.fnd-bubble-row > .fnd-bubble { min-width: 0; }

.fnd-bubble-face {
  /* NOT decoration. `.fnd-ink-surface::before` and `::after` are
     `position: absolute; inset: 0` with no z-index, so they paint over
     every child that is not itself positioned. The bubble is already
     `position: relative` and so survives; the face was
     static and vanished completely on ink while reporting a correct
     36x36 box and a correct light background. Measured, because
     nothing about the computed style says it is invisible. */
  position: relative;
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--fnd-accent-soft);
  /* Beside the FIRST line of what was said, not floating level with
     the middle of a four-line message. */
  margin-top: 2px;
}
.fnd-bubble-row--lead .fnd-bubble-face {
  flex-basis: 48px;
  width: 48px;
  height: 48px;
}

/* ==================================================================
   THE DESTRUCTIVE CONFIRM
   Promoted from /mailbox, 2026-08-12. The block-this-creator popup
   needed a button that says "this one takes something away", and the
   foundation shipped --ink, --light and --quiet and nothing else. The
   old library had `.button--danger`, so every migrated page that ever
   confirms a destructive act would otherwise either keep an old-library
   button on a foundation popup or invent its own red.

   There will be more than one: block a creator, delete a listing, cancel
   a campaign, remove a payout method, close an account. That is the
   counting test, so it is a device rather than a page's own rule.

   IT IS NOT A FILLED RED BUTTON. The foundation has exactly one filled
   shape, --ink, and it means "this is the way forward". A second filled
   shape competing with it in the same popup makes neither one the
   answer, and a solid red block is louder than blocking one person on a
   creator network deserves. So: the quiet button's hairline shell, in
   the danger ink, which fills only on hover, at the moment the pointer
   is actually on it and the warning is worth its volume.
   ================================================================== */
.fnd .fnd-btn--danger {
  background: transparent;
  color: var(--fnd-danger);
  box-shadow: inset 0 0 0 1px var(--fnd-danger);
  transition: transform 150ms ease, background-color 140ms ease, color 140ms ease;
}
.fnd .fnd-btn--danger:hover {
  background: var(--fnd-danger);
  color: #fff;
}
.fnd .fnd-btn--danger:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--fnd-danger), 0 0 0 3px var(--fnd-danger-soft);
}

/* ==================================================================
   THE TEXT ACTION
   Promoted from /mailbox, 2026-08-12. A control that is a WORD: the
   "Translate" under an incoming message, an "Undo", a "Show more". The
   foundation shipped three button shapes and all three are pills with a
   presence, which is right for something you are being asked to do and
   wrong for something that is simply available if you want it. Put
   .fnd-btn--quiet under every message in a conversation and the page
   reads as a column of buttons with some text between them.

   Two pages had already built this privately by the time it was
   promoted: this one, and the Thumbnail Maker's `.tmk-linkbtn`. That is
   the counting test twice over.

   NOT a link. A link goes somewhere; this does something on the page,
   so it is a <button> and it is not underlined. The signal that it is
   pressable is the hover ground, which is why the ground is not
   optional.

   IT DOES NOT RESERVE 44px, deliberately: the rows it belongs in are
   exactly the ones with no vertical room. Pair it with .fnd-hit, which
   buys the tap target back without spending layout.
   ================================================================== */
.fnd .fnd-textbtn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 8px;
  background: none; border: 0; cursor: pointer;
  border-radius: var(--fnd-r-xs);
  font-family: var(--fnd-body-font); font-weight: 600;
  font-size: var(--fnd-t-micro); line-height: 1.2;
  color: var(--fnd-text-faint);
  transition: background-color 140ms ease, color 140ms ease;
}
.fnd .fnd-textbtn:hover { color: var(--fnd-text); background: var(--fnd-paper-2); }
.fnd .fnd-textbtn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--fnd-accent-soft); }
.fnd .fnd-textbtn:active { transform: translateY(1px); }
/* On ink the paper ground disappears, so the hover is carried by the ink
   surface's own translucent white instead. */
.fnd .fnd-ink-surface .fnd-textbtn,
.fnd .fnd-card--ink .fnd-textbtn { color: var(--fnd-on-ink-faint); }
.fnd .fnd-ink-surface .fnd-textbtn:hover,
.fnd .fnd-card--ink .fnd-textbtn:hover { color: var(--fnd-on-ink); background: rgba(255,255,255,.10); }

/* A UTILITY, SO IT COMES LAST. .fnd-hit sets `padding`, and so does
   .fnd-textbtn; both score (0,2,0), so the one written later wins. With this
   block above the text button, .fnd-hit lost its own padding and the control it
   was applied to still measured 32px tall while every rule in it looked
   correct. Anything that MODIFIES a component has to sit below every component
   it can be put on. */
/* ==================================================================
   THE HIT AREA
   Promoted from /mailbox, 2026-08-12, where four separate controls
   failed the 44px floor for the same reason: a small inline control in
   a dense row cannot simply be made bigger, because bigger is exactly
   what the row does not have room for.

   The answer is the one `.fnd-crumbs` already worked out privately:
   PADDING grows the border box, which is what the browser and every
   checker measure as the tap target, and an equal NEGATIVE MARGIN gives
   the space straight back to the layout. Net visual change: none. Net
   tap target: 44.

   `::after` overlays are the other way to do this and they are worse
   here for a measurable reason: a pseudo-element does not change
   getBoundingClientRect, so the control still reports its old size, and
   an audit cannot tell a fixed control from a broken one.

   USE IT: add .fnd-hit and set how much to grow by, per side.
     <a class="fnd-hit" style="--fnd-hit-y: 9px">   in a stylesheet, not inline
   Set only the axis that is short. A control already 44 wide needs
   --fnd-hit-y alone; growing both when only one is short pulls the
   neighbours in for no reason.

   NOT for a control that can simply be 44px (use .fnd-iconbtn, or give
   the button its own padding). This is for the case where the ROW is
   the constraint.
   ================================================================== */
.fnd .fnd-hit {
  padding: var(--fnd-hit-y, 0px) var(--fnd-hit-x, 0px);
  margin: calc(var(--fnd-hit-y, 0px) * -1) calc(var(--fnd-hit-x, 0px) * -1);
  /* Padding on an INLINE element does not grow its line box, so an inline
     control keeps reporting its old height however much padding it has.
     inline-flex is the smallest change that makes the padding real while
     still letting the control sit in a line of text. */
  display: inline-flex;
  align-items: center;
}

/* ==================================================================
   VISUALLY HIDDEN
   Promoted from /mailbox, 2026-08-12, after the device gate matched
   the mailbox's own live-region rule against `.fnd-switch input` at
   0.8 declaration similarity and was right to: they are the same
   thing written twice, once inside a component and once on a page.

   There will be many more. Every live region, every icon button's
   real label, every "skip to content", every table caption a sighted
   reader does not need. A product without one named answer for this
   grows a different almost-correct copy per page, and the ones that
   get it wrong get it wrong in the way that matters: `display: none`
   and `visibility: hidden` remove the element from the accessibility
   tree entirely, which is the opposite of the intent.

   CLIPPED, never hidden. 1px box, negative margin, inset clip-path
   with the legacy `clip` beside it for older engines, and
   `white-space: nowrap` so a long announcement cannot be collapsed
   into a single wrapped character by the 1px width.
   ================================================================== */
/* NO `.fnd` PREFIX, and that is deliberate. Every other rule in this file is
   scoped to the foundation because it PAINTS something, and a page that has
   not migrated must not be repainted. This one paints nothing: it removes an
   element from sight while keeping it in the accessibility tree. Scoped to
   `.fnd` it would have left the mailbox's live region fully visible on the
   old branch of the switch, which is a regression on the page members are
   actually looking at. */
.fnd-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* ==================================================================
   .fnd-chips--scroll — a chip set that runs off the edge on purpose
   ------------------------------------------------------------------
   `.fnd-chips` wraps, which is right when the set is short. A filter
   set of ten categories wrapping on a phone pushes the first result
   below the fold, so a browse page keeps them on one line and scrolls
   them sideways instead.

   The reason this is a component and not a page rule: /collaborations
   built it privately as `.mpv2-chips`, and any browse or filter
   surface with more chips than fit has the same problem. Measured on
   /collaborations at 375px, the set is 1,395px inside a 221px window,
   so nine of the ten filters sit off-screen with nothing on the page
   saying so. A sideways scroller with no edge treatment reads as a
   truncated list rather than a scrollable one.

   CONTRACT: use this ONLY when the set is known to overflow its rail.
   The right-edge fade is unconditional, so on a set that fits it would
   fade the last chip for no reason. A short set uses plain
   `.fnd-chips`.
   ================================================================== */
.fnd .fnd-chips--scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  min-width: 0;
  /* The fade is drawn with a mask so it works over any ground the rail
     sits on (paper, tint, or a sticky bar) without hardcoding a colour
     that would show as a pale smear on the wrong background. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), rgba(0, 0, 0, 0.15));
  mask-image: linear-gradient(to right, #000 calc(100% - 34px), rgba(0, 0, 0, 0.15));
}
.fnd .fnd-chips--scroll::-webkit-scrollbar { display: none; }
.fnd .fnd-chips--scroll > * { flex: 0 0 auto; }
/* A TRAILING SPACER EXACTLY AS WIDE AS THE FADE, and it is the whole reason
   this device is honest rather than merely pretty.

   The mask is fixed to the scroller's viewport, not to its content, so it
   keeps dimming the right-hand 34px however far the member has scrolled.
   Without this rule, arriving at the end of the set leaves the LAST chip
   sitting under the fade permanently, and a washed-out chip beside solid ones
   does not read as "there is more", it reads as "this one is disabled". The
   sweep caught exactly that on /collaborations: at the end of the scroll,
   "Other" looked unavailable.

   The spacer adds 34px of empty track after the last chip, so at full scroll
   the faded band contains nothing but blank space and every chip is solid.
   Chosen over a scroll-driven timeline because that needs Chrome 115+ or
   Safari 26 and would leave older phones with the original defect, and over a
   scroll listener because a component in this file must not need script to be
   correct. */
.fnd .fnd-chips--scroll::after {
  content: '';
  flex: 0 0 34px;
  align-self: stretch;
}

/* ---------------------------------------------------------------------
   A run of rows that carry no picture          .fnd-rows--nomedia

   .fnd-row always reserves its first column for .fnd-row-media at 104px,
   which is right for the case it was promoted from (a list of videos) and
   wrong for every list whose rows are a fact and its state. Without this
   the labels sit in a 104px stripe of nothing and read as indented.

   Promoted 2026-08-13 from the brand brief's profile-readiness list, which
   is four rows of "here is what the brand asked for, here is whether you
   match". It is deliberately a modifier on the row device rather than a
   second row device, because everything else about these rows (the
   hairlines, the padding, the title, the meta line, the end slot) is
   already correct and only the picture column is not.
   --------------------------------------------------------------------- */
.fnd .fnd-rows--nomedia .fnd-row { grid-template-columns: minmax(0, 1fr) auto; }
.fnd .fnd-rows--nomedia .fnd-row-main { grid-column: 1; }
.fnd .fnd-rows--nomedia .fnd-row-end  { grid-column: 2; }

@media (max-width: 767px) {
  /* On a phone the end slot drops under the words it grades rather than
     competing with them for a 343px row. */
  .fnd .fnd-rows--nomedia .fnd-row { grid-template-columns: minmax(0, 1fr); }
  .fnd .fnd-rows--nomedia .fnd-row-end { grid-column: 1; margin-top: 4px; }
}

/* ==========================================================================
   TASK LIST  .fnd-tasklist          (promoted 2026-08-13 from /collab-job-accepted)

   A list of steps a member is WORKING THROUGH right now, where each row is in
   one of three states: done, doing it now, or still ahead. It is not
   `.fnd-stepgrid` (a static "how it works" explainer on a public page) and it
   is not `.fnd-steps` (a thin progress bar that states position and carries no
   content). Those two already existed and neither can hold a live task.

   PROMOTED BECAUSE SEVEN PAGES HAD ALREADY BUILT IT PRIVATELY, each with its
   own name and its own idea of what "done" looks like: `.pd-step--done`
   (brand-post-deal), `.coach-checklist-item--done` and
   `.coach-task-card--complete` (coach-core, twice in one file),
   `.mks-check-circle--done` (media-kit-setup), `.mk-check--done` (media-kit),
   `.ob-welcome-step-preview--done` (studio-onboarding), `.proj-step-card--done`
   (studio-workspace) and `.src-step--active` (shorts-remix-checker). The job
   screen would have been the eighth. Nothing caught it, because every check we
   own grades a page on its own.

   THE ONE RULE THAT MAKES IT WORK: exactly one row is `--now` at a time, and
   only that row shows its body. A list where every step is equally loud is the
   thing this replaces, and it is why the old job screen could not tell a member
   on their first job which of five numbered steps they were actually on.

   Done rows collapse to their title and a tick. Upcoming rows collapse to their
   title in faint ink. Neither is hidden: the member can always see the whole
   shape of the job and how much is left, which is what a bare "step 2 of 5"
   never tells them.

   The marker is a NUMBER that becomes a TICK, in the same box, so the row does
   not reflow when it completes. Sizing the tick to the numeral's own box is
   what stops the list jumping as a member works down it.
   ========================================================================== */
.fnd-tasklist {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--fnd-rule);
}

.fnd-task {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  column-gap: var(--fnd-s3);
  align-items: start;
  padding: var(--fnd-s3) 0;
  border-bottom: 1px solid var(--fnd-rule);
}

/* The live row earns the air. Done and upcoming rows stay tight so the page
   does not grow a screen of padding around steps nobody is looking at. */
.fnd-task--now { padding: var(--fnd-s4) 0 var(--fnd-s5); }

.fnd-task-mark {
  grid-column: 1;
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  border-radius: 999px;
  border: 1px solid var(--fnd-rule);
  background: var(--fnd-card);
  font-family: var(--fnd-display-font);
  font-weight: 800; font-size: 14px; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--fnd-text-faint);
  /* Never let the marker shrink when the title beside it wraps to two lines.
     A flex/grid child with only width set still shrinks; this is the trap the
     migration notes call out and it cost a 0px tick on a phone once already. */
  flex: 0 0 30px;
}

.fnd-task-t {
  grid-column: 2;
  margin: 0;
  align-self: center;
  min-height: 30px;
  display: flex; align-items: center;
  font-family: var(--fnd-display-font);
  font-weight: 700;
  font-size: var(--fnd-t-sm);
  letter-spacing: -.01em;
  color: var(--fnd-text-faint);
}

/* The body only ever exists on the live row. Written as a rule on the row
   rather than a hidden/shown class so a page cannot accidentally open two. */
.fnd-task-body { display: none; }
.fnd-task--now > .fnd-task-body {
  display: block;
  grid-column: 2;
  margin-top: var(--fnd-s3);
  font-size: var(--fnd-t-body);
  color: var(--fnd-text-soft);
}
.fnd-task--now > .fnd-task-body > :first-child { margin-top: 0; }
.fnd-task--now > .fnd-task-body > :last-child  { margin-bottom: 0; }

/* --- now: the only row with full-strength ink and an accent marker --- */
.fnd-task--now > .fnd-task-mark {
  background: var(--fnd-ink);
  border-color: var(--fnd-ink);
  color: var(--fnd-on-ink);
}
.fnd-task--now > .fnd-task-t {
  color: var(--fnd-text);
  font-size: var(--fnd-t-h3);
}

/* --- done: the tick replaces the numeral in the same box --- */
.fnd-task--done > .fnd-task-mark {
  background: var(--fnd-ok-soft);
  border-color: var(--fnd-ok-soft);
  color: var(--fnd-ok);
  font-size: 13px;
}
.fnd-task--done > .fnd-task-t { color: var(--fnd-text-soft); }

/* Nothing on an upcoming row is pressable, and it must not read as disabled
   either: it is simply later. Faint ink says that without a lock or a grey
   fill, both of which members read as "you cannot have this". */
.fnd-task--todo > .fnd-task-t { color: var(--fnd-text-faint); }

/* An optional right-hand note on any row: a time, a count, a state word. Sits
   on the title's own line so it never pushes the body around. */
.fnd-task-note {
  margin-left: auto;
  padding-left: var(--fnd-s3);
  flex: 0 0 auto;
  font-family: var(--fnd-body-font);
  font-weight: 500;
  font-size: var(--fnd-t-micro);
  color: var(--fnd-text-faint);
  font-variant-numeric: tabular-nums;
}

/* On ink, the same list with the palette flipped. Used by the finish screen,
   where the steps are all done and the list is a summary of what happened. */
.fnd-ink-surface .fnd-tasklist,
.fnd-card--ink .fnd-tasklist { border-top-color: var(--fnd-on-ink-rule); }
.fnd-ink-surface .fnd-task,
.fnd-card--ink .fnd-task { border-bottom-color: var(--fnd-on-ink-rule); }
.fnd-ink-surface .fnd-task-t,
.fnd-card--ink .fnd-task-t { color: var(--fnd-on-ink-soft); }
.fnd-ink-surface .fnd-task-mark,
.fnd-card--ink .fnd-task-mark {
  background: rgba(255,255,255,.08);
  border-color: var(--fnd-on-ink-rule);
  color: var(--fnd-on-ink-faint);
}

/* ------------------------------------------------------------------
   THE EYEBROW ON INK  (system fix, 2026-08-13, from /collab-job-accepted)

   `.fnd-card-eyebrow` is `--fnd-accent-deep` (#443CC4). On paper that is
   correct and readable. Inside `.fnd-card--ink` or `.fnd-ink-surface` it lands
   on #16141A at about 1.9:1 and is effectively invisible, which is the exact
   failure foundation.css already documents for link hovers on ink and fixes
   there with the light accent. The eyebrow was simply never given the same
   treatment, so EVERY ink card with an eyebrow has carried it.

   Fixed in the system rather than on the page that found it, because the next
   ink card to use an eyebrow would meet the identical fault.
   ------------------------------------------------------------------ */
.fnd .fnd-card--ink .fnd-card-eyebrow,
.fnd .fnd-ink-surface .fnd-card-eyebrow { color: var(--fnd-accent); }

/* ------------------------------------------------------------------
   CLOSING ACTIONS  .fnd-actions   (promoted 2026-08-13)

   The row of one or two buttons that ENDS a screen: a finish screen, an empty
   state, a confirmation. Centred, and stacked full width on a phone so neither
   button becomes a thumb-sized target in the middle of a wide row.

   Not `.fnd-offer-act`, which is the action COLUMN inside an offer card and
   sits beside copy. This is the page's own last row.

   Promoted because two pages had built it: `.studio-v2-empty__actions`
   (studio-v2.css:559) and the job screen's finish row, found by the device
   gate on declaration similarity rather than by anyone noticing.
   ------------------------------------------------------------------ */
.fnd-actions { display: flex; flex-wrap: wrap; gap: var(--fnd-s2); justify-content: center; }
@media (max-width: 479px) {
  .fnd-actions { flex-direction: column; }
  .fnd .fnd-actions > .fnd-btn { display: flex; width: 100%; justify-content: center; }
}

/* ====================================================================
   THE DAY MARKER                                    .fnd-bubble-day
   Belongs to .fnd-bubble (above): a conversation that spans more than
   one day needs to say where the break is.

   A LABEL, NOT A RULE. Drawn as a line across the panel it sat
   directly under the Concierge dock's own header rule, two full-width
   lines with nothing between them, which the founder read as wrong
   before anyone measured it. A centred label separates the days and
   draws nothing.
   ==================================================================== */
.fnd-bubble-day {
  align-self: center;
  display: table;
  margin: var(--fnd-s2) auto var(--fnd-s1);
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--fnd-paper-2);
  font-family: var(--fnd-body-font); font-weight: 600;
  font-size: 12.5px; line-height: 1.3;
  color: var(--fnd-text-soft);
  white-space: nowrap;
}

/* THE ACTION ATTACHED TO A SPOKEN MESSAGE.
   A reply frequently ends in one thing to go and do, and it belongs
   inside the bubble rather than under it, so the sentence and its
   action read as one object. .fnd-btn is 52px and its fill lives on
   `.fnd .fnd-btn--ink`, which needs an ancestor a floating overlay
   cannot be given without also turning on the prose-link rules. */
.fnd-bubble .fnd-btn {
  min-height: 44px;
  padding: 0 16px;
  font-size: 15px;
  background: var(--fnd-ink);
  color: var(--fnd-on-ink);
  margin-top: 10px;
}
.fnd-bubble .fnd-btn:hover { transform: translateY(-1px); }

/* THE FILLED ICON BUTTON.
   .fnd-iconbtn is quiet by design and correct for a control that must
   not compete. A send button is the opposite: it is the one action in
   its row. Unprefixed for the same reason as the ask row below, and it
   is the only filled icon control in the system, so it cannot start
   meaning two things. */
.fnd-iconbtn--ink {
  background: var(--fnd-ink);
  color: var(--fnd-on-ink);
}
.fnd-iconbtn--ink:hover {
  background: var(--fnd-ink);
  color: var(--fnd-on-ink);
  transform: translateY(-1px);
}
.fnd-iconbtn--ink:disabled { opacity: .45; transform: none; cursor: default; }

/* THE ACTION ATTACHED TO A MESSAGE.
   A reply frequently ends in one thing to go and do, and it belongs inside the
   bubble rather than under it, so the sentence and its action read as one
   object. .fnd-btn is 52px and its fill lives on `.fnd .fnd-btn--ink`, which
   needs an ancestor a floating overlay cannot be given without also turning on
   the prose-link rules. Inside a message bubble the fill is unambiguous, so it
   is stated here and nowhere else. */


/* ====================================================================
   THE ASK ROW                     .fnd-askrow / -f, with .fnd-iconbtn--ink
   Promoted 2026-08-13, after the founder put the two side by side:
   "The 'How do I get more views?' ask message input box is different
   from the 'Ask me anything' box on the dashboard. They are supposed to
   be the same design, same button!"

   He was right, and both were wrong in different ways. The dock used a
   bare .fnd-input, which is a FORM field: a rectangle with its own
   border, correct on a settings page and wrong here, where it drew a
   second outline inside the panel ("the dock one has a weird outline").
   The dashboard strip had the right shape and no name, so it could not
   be reused and drifted on its own.

   ONE PILL, holding a borderless field and one round filled button.
   The button is the paper plane, his pick over the arrow, and it is
   .fnd-iconbtn--ink so there is one filled icon control in the system
   rather than two that resemble each other.

   Unprefixed, like the rest of the chat device above: the dock floats
   over member pages that have not migrated.
   ==================================================================== */
.fnd-askrow {
  display: flex; align-items: center; gap: 4px;
  min-height: 52px;
  padding: 3px 3px 3px 8px;
  background: var(--fnd-card);
  border: 1px solid var(--fnd-rule);
  border-radius: 999px;
}
/* The focus ring belongs to the PILL, not to the field inside it. A ring
   drawn around a borderless field inside a bordered pill is the second
   outline all over again. */
.fnd-askrow:focus-within { border-color: var(--fnd-text-faint); }

.fnd-askrow-f {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; outline: 0; box-shadow: none;
  padding: 8px 10px;
  font-family: var(--fnd-body-font);
  /* 15.5px, matching the strip this was taken from and comfortably over
     the 14px body floor. */
  font-size: 15.5px; line-height: 1.4;
  color: var(--fnd-text);
  resize: none;
  /* 44px, the same floor every other touch surface in the system has. It was
     38 before this line, which is a thin target to hit with a thumb on the one
     control the whole row exists for. The pill's own min-height of 52 with 3px
     of padding leaves 46, so this fits without changing the row. */
  min-height: 44px;
  /* About four lines, then it scrolls rather than growing without limit
     inside a dock whose height is the scarce thing. */
  max-height: 92px;
}
.fnd-askrow-f::placeholder { color: var(--fnd-text-faint); }
/* A BARE `textarea:focus` RULE IN THE OLD LIBRARY PAINTS A 3px RING IN THE OLD
   INDIGO, and it reaches any textarea on any page. It is why the dashboard's
   ask row looked right and the dock's did not: one is an <input> and the other
   a <textarea>, and only the textarea was hit. The founder saw it as "a light
   indigo rectangular highlight ... its ugly and the other one doesnt have this".

   Killed here rather than on the page, because the field type is the caller's
   choice and every future ask row would meet the same rule. The pill shows the
   focus with its own border, which is the honest place for it: a ring drawn
   around a borderless field inside a bordered pill is a second outline. */
.fnd-askrow-f:focus { outline: 0; box-shadow: none; border-color: transparent; }

/* ------------------------------------------------------------------
   FOUNDATION POPUP, DRIVEN BY THE SHARED OVERLAY HELPER   (2026-08-13)

   `.fnd-modal` paints the popup; `CPOverlay` (js/cp-overlay.js) owns opening
   and closing, because hand-toggling style.display skips the transition,
   leaves the page behind it scrolling, traps no focus and ignores Escape.
   The helper reveals by removing [hidden] and adding `.is-visible`, and looks
   for the exact class `modal-overlay` when it walks up from a click to find
   the root. So a foundation popup that wants the helper carries BOTH classes,
   and this is the one rule that makes the two conventions agree.

   Promoted from /collab-job-accepted rather than left on the page: the next
   foundation popup to use the helper needs exactly this and nothing else.
   ------------------------------------------------------------------ */
.fnd-modal.modal-overlay {
  /* The old library's .modal-overlay brings its OWN full overlay treatment:
     display none, 100px of top padding, a different scrim and z-index 11000.
     Carrying both classes therefore hands the element two complete and
     conflicting overlays, and the old one wins several of them on source
     order. This restates the foundation's, at three classes, so the bridge is
     a bridge and not a merge. */
  z-index: 10050;
  align-items: center;
  padding: var(--fnd-s4);
  background: rgba(16, 14, 20, .62);
  animation: none;
  overflow-y: auto;
}
.fnd-modal.modal-overlay.is-visible { display: flex; }
.fnd-modal.modal-overlay[hidden] { display: none; }

/* ------------------------------------------------------------------
   A POPUP THAT SUBMITS SOMETHING                       .fnd-modal-form
   (2026-08-13, promoted out of the Contact Us migration)

   .fnd-modal-panel is a flex column holding a head, a body that scrolls and
   a foot that does not. The moment the popup contains a FORM, the form has to
   wrap the body and the foot, or the send button is outside the form it
   submits. That extra element breaks the column: the panel's only flexing
   child is now the form, and the body inside it is no longer a flex item of
   the panel at all, so it stops shrinking and the panel grows past the
   viewport with the send button somewhere below the bottom of the screen.

   This is not particular to support. Any popup that asks for something and
   sends it has exactly this shape, so it is a component rather than that
   page's CSS.

   min-height:0 is the load-bearing half, and for the same reason it is
   load-bearing on .fnd-modal--app: a flex child defaults to min-height:auto
   and refuses to shrink below its content.
   ------------------------------------------------------------------ */
.fnd-modal-form {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
}
.fnd-modal-form > .fnd-modal-body { flex: 1 1 auto; min-height: 0; }
.fnd-modal-form > .fnd-modal-foot { flex: 0 0 auto; position: relative; }

/* THE SCROLL IS INVISIBLE OTHERWISE, and on a form that is expensive. The body
   clips whatever is below it against the foot's hard top edge, which reads as
   the end of the form rather than the middle of it. On the support popup that
   hid the reply-to address entirely: a member could send us a message without
   ever seeing which address our answer was going to.

   Deliberately hung off .fnd-modal-form rather than .fnd-modal-body, so it
   reaches only popups that opt into this device. Every popup in the product has
   a scrolling body and every one of them would inherit a look nobody has
   reviewed; that is a sweep of its own, not a side effect of one migration.

   `to top` from the panel's own card colour, so the last line of content dies
   into the panel rather than into a grey band. */
.fnd-modal-form > .fnd-modal-foot::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%;
  height: 22px; pointer-events: none;
  background: linear-gradient(to top, var(--fnd-card), rgba(255, 255, 255, 0));
}

/* ------------------------------------------------------------------
   THE SAME POPUP AS A PHONE SHEET                     .fnd-modal--sheet
   (2026-08-13, promoted out of the Contact Us migration)

   OPT-IN, AND A NO-OP ABOVE 480px. On a desktop this changes nothing: the
   popup stays the centred 560px panel every other popup is.

   Why a phone needs its own answer. .fnd-modal pays var(--fnd-s4) of overlay
   padding on every edge, which is right when a popup is a short question in the
   middle of a large screen. On a 375px phone it spends 27px a side, so a panel
   that could be 375 wide comes out 320, and the 55px it gave away is dimmed
   background. On a long form that is the difference between a topic row of two
   columns and one of three, and between a placeholder on two lines and three.

   The old support popup already knew this and drew its own sheet
   (`.modal-overlay--sheet` in the pre-foundation library). This carries that
   decision into the system rather than leaving it to be re-invented by the next
   long form: full width, pinned to the bottom edge where the thumb is, rounded
   only at the top so it reads as having come up from the bottom.

   The foot pays the safe-area inset, because a sheet sitting on the bottom edge
   is exactly where an iPhone draws its home indicator over the top of a button.
   ------------------------------------------------------------------ */
@media (max-width: 479px) {
  /* TWO CLASSES, because the bridge rule above is `.fnd-modal.modal-overlay`
     at (0,2,0) and restates the overlay's padding and alignment. A single-class
     variant loses to it and the sheet comes out centred with a 27px moat, which
     is the exact geometry this variant exists to remove. */
  .fnd-modal.fnd-modal--sheet { padding: 0; align-items: flex-end; }
  .fnd-modal--sheet .fnd-modal-panel {
    width: 100%; max-width: none;
    /* 92vh, not 88: the sheet has no padding to give back, and the extra 4%
       is another line of the form rather than more dimmed page. */
    max-height: 92vh;
    border-radius: var(--fnd-r) var(--fnd-r) 0 0;
  }
  /* The foot carried the panel's bottom corners; on a sheet there are none. */
  .fnd-modal--sheet .fnd-modal-foot {
    border-radius: 0;
    padding-bottom: calc(var(--fnd-s4) + env(safe-area-inset-bottom, 0px));
  }
}

/* ------------------------------------------------------------------
   THE POINT LIST                                            .fnd-bullets
   Two or three short reassurance points, each one a fact the reader
   needs before they commit: what happens after you press the button,
   what we will never do, what it costs.

   Promoted from /collaborations/new, which needed the same list twice on
   one page (the channel-gate trust lines and "After you publish"). Two
   copies on ONE page is the system telling you it is missing something.
   Before this, every page wrote its own: the homepage and the
   watch-hours page had independently built a tick bullet under two
   different names.

   Prose runs as sentences; this is for facts a reader SCANS. The marker
   is what makes them countable at a glance, which is the whole job, and
   two bare paragraphs under a heading were what the founder rejected
   here: "this part looks undesigned".

   The marker is a real list marker, not a font glyph, so it cannot fail
   to load and it cannot be the wrong Font Awesome major version. An item
   that leads with its own <i> suppresses the marker instead of showing
   both, which is how one component covers a plain point list and an
   icon-per-point list without a second name.
   ------------------------------------------------------------------ */
/* NOT display:flex, and this is the whole reason the first build of this
   showed no bullets at all. A flex container turns its children into flex
   items, and a flex item does not generate a list marker. The gap between
   items is a margin instead. Scoped .fnd ul.fnd-bullets so it outranks the
   foundation's own list reset, which is .fnd ul at (0,1,1). */
.fnd ul.fnd-bullets {
  list-style: disc;
  margin: 0;
  padding-left: 18px;
  font-size: var(--fnd-t-sm);
  line-height: 1.55;
  color: var(--fnd-text-soft);
}
.fnd ul.fnd-bullets li { margin: 0; padding-left: 2px; }
.fnd ul.fnd-bullets li + li { margin-top: var(--fnd-s2); }
.fnd ul.fnd-bullets li::marker { color: var(--fnd-text-faint); }
.fnd ul.fnd-bullets b, .fnd ul.fnd-bullets strong { color: var(--fnd-text); font-weight: 700; }

/* An item that brings its own icon drops the marker and hangs the icon in
   the space the marker would have used, so both shapes keep one left edge. */
.fnd ul.fnd-bullets li:has(> i:first-child) { list-style: none; display: flex; gap: var(--fnd-s2); margin-left: -18px; }
.fnd ul.fnd-bullets li > i:first-child { flex: 0 0 auto; margin-top: 3px; font-size: 14px; color: var(--fnd-text-faint); }

/* Inside a callout it inherits the callout's own size and keeps its bullets
   clear of the callout's icon column. */
.fnd .fnd-callout ul.fnd-bullets { font-size: inherit; margin-top: 6px; }

/* ---------------------------------------------------------------------
   THE FIELD GROUP   .fnd-fieldgroup
   Promoted from /collaborations/new, 2026-08-14.

   WHY IT EXISTS, measured rather than argued. Step 2 of that form put four
   questions on one card and the founder said "it is like I do not know where
   to look". He was right, and the reason was visible in two numbers:

     every label   15.5px, weight 700   ->  four questions, one voice
     every gap     26px, all identical  ->  proximity carrying no meaning

   A form where everything is equally loud and equally far apart has no
   entry point. The eye looks for the biggest thing and the closest pair,
   and when neither exists it just stops. .fnd-field solved ONE field and
   the system had nothing above it, so every form was a flat run.

   WHAT IT DOES. It makes distance mean something. Inside a group the
   fields sit --fnd-s3 apart; between groups it is --fnd-s6 plus a hairline.
   That is more than double, which is the point: two fields that belong
   together now LOOK like they do, before a word is read.

   The caption is the second level of heading. It does not compete with the
   field labels by being bigger; it is separated by the rule and the space
   above it, which is how a settings form in any well-made product does it.

       <div class="fnd-fieldgroup">
         <p class="fnd-fieldgroup-t">What creators will see</p>
         <div class="fnd-field">...</div>
         <div class="fnd-field">...</div>
       </div>
       <div class="fnd-fieldgroup">
         <p class="fnd-fieldgroup-t">Who can reach you</p>
         <p class="fnd-fieldgroup-sub">Optional. Leave it open to hear from more partners.</p>
         <div class="fnd-field">...</div>
       </div>

   USE IT WHENEVER A FORM HAS MORE THAN THREE FIELDS. Below that, a flat run
   reads fine and a caption is ceremony. Above it, the flat run is the fault
   this device exists to prevent, and it will be found by a founder rather
   than by any checker we own: every gate passed that form.
   --------------------------------------------------------------------- */
.fnd .fnd-fieldgroup + .fnd-fieldgroup {
  margin-top: var(--fnd-s6);
  padding-top: var(--fnd-s5);
  border-top: 1px solid var(--fnd-rule);
}

.fnd .fnd-fieldgroup-t {
  display: block;
  margin: 0 0 var(--fnd-s4);
  font-family: var(--fnd-display-font);
  font-weight: 700;
  /* 18px, NOT --fnd-t-sm. This device shipped claiming to be "the second
     level of heading", and it was not: it set the same 15.5px, the same
     weight 700, the same display font and the same ink as .fnd-label, so a
     caption and the labels under it were the same line at different heights.
     On the onboarding setup form that produced EIGHT identical lines down one
     card, and the founder read the page exactly the way the device's own
     documentation predicts: "so much going on with no visual hierarchy and
     separation" (2026-08-16). The hairline and the space above it were
     carrying the whole distinction, and space alone does not make a heading.
     One clear rung: 18px caption, 15.5px label, and .fnd-card-t still above
     both. Fixed here rather than on that page, because every migrated form
     has the same eight lines. */
  font-size: var(--fnd-t-h3);
  letter-spacing: -.012em;
  color: var(--fnd-text);
}

/* A caption's own line of explanation sits UNDER the caption and above the
   first field, so the group is introduced before it is filled in. The caption
   gives up its own bottom margin rather than the sub pulling itself up with a
   negative one, because a negative margin tuned to a token is a number that
   silently breaks the day the token moves. */
.fnd .fnd-fieldgroup-t:has(+ .fnd-fieldgroup-sub) { margin-bottom: 6px; }
.fnd .fnd-fieldgroup-sub {
  margin: 0 0 var(--fnd-s4);
  font-size: var(--fnd-t-meta);
  line-height: 1.55;
  color: var(--fnd-text-faint);
}

/* Tight INSIDE the group. This is the half of the rule that does the work:
   .fnd-field's own 20px bottom margin is the spacing for a flat run, and a
   grouped run needs to be visibly tighter than the space between groups or
   the caption is decoration. */
.fnd .fnd-fieldgroup > .fnd-field { margin-bottom: var(--fnd-s3); }
.fnd .fnd-fieldgroup > .fnd-field:last-child { margin-bottom: 0; }

/* ==================================================================
   CHOICE CARD, COMPLETED  (.fnd-choice*)

   `.fnd-choice` shipped as a stacked list: a radio, a title and a
   sentence. Every real picker in the product needs three more things
   than that, and until 2026-08-14 each one built them privately.
   /create-collab step 1 was the extreme case: 99 uses of a
   `.service-card` family and 826 lines of page CSS, drawing a control
   the system already owned, on a page that was ALSO using `.fnd-choice`
   for its other step. The founder's question was the right one: is this
   built from the system or painted to look like it?

   So the missing parts are added HERE rather than there, and they are
   the parts any picker of paid options needs:

     --3          six options do not read as a stacked list. The grid
                  mirrors .fnd-cards--3 exactly, same two breakpoints,
                  because a choice grid and a card grid landing on
                  different columns at the same width is the kind of
                  small disagreement that makes a product feel assembled.
     -sub         the one line that says what an option is FOR. Six
                  similar options are separated by this line, not by the
                  paragraph under it, and it is the line the eye scans
                  down a column.
     -foot        what it costs, on its own rule at the bottom of the
                  card. A price is not body copy, and it has to sit at
                  the same height on every card in a row or the column
                  cannot be compared.
     --rec        the one we recommend. Tint, not a badge, because a
                  badge is a label and this is the whole card.
     --go         an option that LEAVES rather than selects. Same card,
                  and the left mark is what tells them apart: a radio
                  means this becomes your choice, an arrow means this
                  opens somewhere else. Without it a grid of pickable
                  cards silently contains four that are not.
   ================================================================== */

/* A fieldset is the correct grouping element for a set of radios and it
   arrives with a border, padding, a margin and `min-width: min-content`,
   the last of which refuses to shrink and scrolls the page sideways.
   Every page using .fnd-choices in a fieldset re-declared this. */
fieldset.fnd-choices { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset.fnd-choices > legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* --3 itself lives in foundation-members.css beside --2. It cannot live
   here: this file loads BEFORE that one, the two selectors tie on
   specificity, and the base rule wins on order. */

/* The body becomes a column so a foot can be pushed to the bottom of it.
   Its existing children are block-level with explicit margins, so
   nothing that already uses .fnd-choice moves. */
.fnd .fnd-choice-b { display: flex; flex-direction: column; flex: 1 1 auto; }

/* ONLY when there is a foot. The base component aligns to flex-start on
   purpose, and stretching a body with no foot in it would hand the
   sentence the card's whole height for no reason. */
.fnd .fnd-choice:has(.fnd-choice-foot) { align-items: stretch; }

/* THE EYEBROW MUST NOT PUSH ITS OWN TITLE DOWN while its neighbours'
   titles stay up. In a set where only some options carry a tag, the
   names in a row start at three different heights, which is a raggedness
   the eye reads before it reads a word. So an option with no tag
   reserves the tag's line, and only inside a set where at least one
   option has one, so a set with no tags anywhere loses nothing.

   This is why the old private version floated its badge OUTSIDE the card
   as an absolutely positioned pill: that kept the titles aligned, at the
   cost of a badge overlapping the card's top edge. Reserving the line
   buys the same alignment honestly.

   ONE COLUMN NEEDS NONE OF IT. Alignment across a row is the entire
   point, so on a phone the reserved line is 24px of scroll per untagged
   option buying nothing. Measured on /create-collab step 1: seven
   untagged options, 168px of dead height. */
@media (min-width: 720px) {
  .fnd .fnd-choices:has(.fnd-choice-tag) .fnd-choice-b:not(:has(.fnd-choice-tag))::before {
    content: ""; display: block; height: 24px;
  }
}
.fnd .fnd-choice-tag { display: block; line-height: 18px; margin-bottom: 6px; }

/* THE OPTIONS ARE THE SCREEN, not a field inside a form. On a step whose
   whole job is picking one of six, the option NAME is the page's primary
   content and the h3 rung is the size of a field label. Set on the grid
   rather than the card so a page states the intent once. */
.fnd .fnd-choices--lead .fnd-choice-t { font-size: var(--fnd-t-h3-lg); font-weight: 800; letter-spacing: -.02em; }

/* THE FLAG ROW. The short label an option sometimes carries ("FASTEST",
   "NEW"), on its own line under the name.

   It was tried twice in the two other places it could go, and both failed
   for a reason worth keeping:

   ABOVE the title, as `.fnd-choice-tag`, it sits on the radio's line and
   pushes the NAME down a row. The founder asked for the opposite and he is
   right: the name is the thing being chosen between, the label is a note
   about it.

   BESIDE the title, inline, it does not fit. Measured at three-up: a
   320px card leaves 246px inside its padding, radio and gap, and
   "Community Watch" plus its badge wants 275px. It wrapped on all four
   badged cards, which put every sub line 33px lower than its neighbours'.

   So it gets its own row, and THE ROW IS ALWAYS THERE above 720px, empty
   or not. That is the whole point: it is what keeps the sub line, the
   sentence, the chip and the price landing on the same line in every card
   of a row. On a phone there is one card per row, nothing to align with,
   and an empty row would be 33px of scroll per card buying nothing. */
/* SO IT COMES OUT OF THE FLOW ENTIRELY, and that is the whole answer.

   A flag is applied TO a card. It is not one of the card's lines. The
   moment it takes a line it has to be reserved on every card that has no
   flag, and four of the ten cards on /create-collab then carried a 33px
   hole under their name that read as a bug. The founder called it before
   I did: "far worse than before", and "perhaps make it a badge on the
   card that partly comes out of the card in the top right of it".

   Out of flow it cannot push anything, so nothing needs reserving, no
   card grows, and the alignment below is exact by construction rather
   than by a rule that has to be maintained.

   The geometry, all of it measured rather than picked:
     top: -11px  the pill is 25px, so 14px sits inside the card and 11px
                 hangs over the edge, which is what makes it read as
                 applied rather than contained. The grid's row gap is
                 14px, leaving 3px clear of the card above.
     right: s4   the card's own padding, so it lines up with the content
                 edge and not with the corner radius.
     no collision with the title: the pill's lower edge lands 14px down,
                 the card's top padding is 20px, so the name starts below
                 it and needs no reserved space beside it either.

   INK, not the badge's own quiet grey. A `.fnd-badge` is a state read
   inside a card; this is a label stuck on the outside of one, and at
   11px of overhang on paper the grey pill disappears into the card edge.
   The dot goes with it: the dot exists so a STATE is not carried by
   colour alone, and a flag is not a state. */
.fnd .fnd-choice { overflow: visible; }

/* THE FLAG LIVES IN THE GAP, SO THE GAP HAS TO PAY FOR IT.

   `.fnd-choices` was written as a stacked list of two or three options and
   carries a 14px gap, which is right for that. A three-up grid of full cards
   is a different object: `.fnd-cards`, the card grid it sits beside, uses
   20px. And once a flag hangs 11px over a card's top edge, a 14px row gap
   leaves FOUR pixels of clear space above it. The founder saw it without
   knowing the cause and named the cause anyway: "the cards in the first row
   barely have any padding from the cards in the 2nd row ... maybe due to the
   badges in the top right corner being so close to the cards above."
   Measured at 4px.

   So a three-up choice grid takes the card grid's gap, and a set carrying
   flags takes a deeper ROW gap plus its own top padding. The padding is what
   gives the FIRST row the same clearance as every row under it, without the
   group heading above needing to know that a flag exists. 26 less the 11px
   overhang leaves 15px clear. */
/* AND EVERY ROW IS THE SAME HEIGHT. A grid row is only as tall as its own
   tallest card, so a last row holding ONE option came out shorter than the
   full row above it and read as a different, lesser kind of card. Founder,
   2026-08-16: "we just need the AI Studio card to be similar sized to the
   other cards". Sizing the implicit rows at 1fr makes them all match the
   tallest,
   which costs nothing on a full grid and fixes the ragged last row.
   The card contents do not stretch with it: the sentence absorbs the slack
   and the price stays pinned to the bottom, which is the same arrangement
   that keeps a row aligned. */
.fnd .fnd-choices--3 { gap: var(--fnd-s4); grid-auto-rows: 1fr; }
.fnd .fnd-choices:has(.fnd-choice-flag) { row-gap: var(--fnd-s5); padding-top: 11px; }

.fnd .fnd-choice-flag {
  position: absolute; top: -11px; right: var(--fnd-s4);
  display: flex; align-items: center;
  max-width: calc(100% - var(--fnd-s7));
  /* A label, never a target. Without this it eats clicks meant for the
     card underneath it, which on this screen is the whole control. */
  pointer-events: none;
}
.fnd .fnd-choice-flag .fnd-badge {
  min-height: 0;
  background: var(--fnd-ink); color: var(--fnd-on-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fnd .fnd-choice-flag .fnd-badge::before { content: none; }

.fnd .fnd-choice-sub {
  margin: 5px 0 0;
  font-size: var(--fnd-t-meta); font-weight: 600; line-height: 1.4;
  color: var(--fnd-accent-deep);
}
/* The sentence follows the sub, so its own top margin would double up. */
.fnd .fnd-choice-sub + .fnd-choice-d { margin-top: 7px; }

/* THE SENTENCE ABSORBS THE SLACK, so everything under it lands on the
   same line in every card of a row. Founder, 2026-08-14: "I dont like
   when elements between cards are misaligned from card to card
   horizontally." He is right, and it is not a nitpick: a row of cards is
   read by scanning DOWN a column, and a price that moves 24px per card
   makes the eye re-find it every time.

   The descriptions are different lengths and always will be, so the only
   thing that can pay for the difference is the description itself. It
   grows; the chip and the foot under it do not move. */
.fnd .fnd-choice-d { flex: 1 1 auto; }

.fnd .fnd-choice-foot {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--fnd-s2);
  /* AUTO, and nothing may override it. A `margin-top: <length>` on this
     element from any later rule silently unpins the foot from the bottom
     of the card, which is exactly how the prices ended up at three
     different heights in one row: the air-above-the-rule rule that used
     to sit here won on order and killed the auto. The air is padding
     now, which cannot fight it. */
  margin-top: auto;
  padding-top: var(--fnd-s2);
  border-top: 1px solid var(--fnd-rule);
}
/* EVERY MARK IN A FOOT IS THE SAME HEIGHT AS THE PRICE. `.fnd-credits` is
   36px and `.fnd-badge` is 25px, and because the foot is pinned to the
   bottom of the card, a foot holding only a badge is 12px shorter and
   therefore STARTS 12px lower than its neighbour holding a price. That is
   the row of prices at two heights, and the cause is the content rather
   than the layout: `min-height` on the foot itself cannot fix it, because
   box-sizing means the 20px of padding eats the floor. Measured on
   /create-collab step 1, two rows of three, foot heights 57 / 57 / 45. */
.fnd .fnd-choice-foot .fnd-badge { min-height: 36px; }
/* THE FOOT IS ONE ROW, and it took a member with a real balance to show it.
   Every test account here holds plenty of credits, so the "X short" mark
   never rendered and the foot never had two things in it. On a member who
   cannot afford the card, which is 93% of them, the price and the shortfall
   wrapped onto two lines and the founder saw it immediately: "the from and
   short pills at the bottom are not on the same row. That messes it up."

   Three quiet millimetres bought the fit at three-up, where the body is
   246px and the pair wanted 250: the state dot goes (a shortfall is stated
   in words, so the dot was carrying nothing colour was not), the marks
   tighten a little, and the numbers stay tabular so they cannot jitter. */
/* WRAP, not nowrap. Forcing one row made the two Studio marks clip
   instead, and text cut off is worse than text on a second line. The pair
   fits now because the marks themselves got tighter, so the wrap simply
   never triggers on a real card. Proved with a 149.50 shortfall, which is
   wider than anything the page can actually show. */
.fnd .fnd-choice-foot .fnd-badge::before { content: none; }
.fnd .fnd-choice-foot .fnd-badge { padding-left: 0; padding-right: 0; background: transparent; white-space: nowrap; }
/* AND THE PRICE IS A PLAIN MARK IN A FOOT, not a pill. Two reasons, and
   they agree. The shortfall beside it lost its pill above, so a pill on one
   and not the other reads as two different kinds of thing when they are the
   same kind. And the pill spends 20px on padding that the widest real pair
   (a price plus Open Studio, on the AI Video Studio card) needed: with it
   they wanted 258px against 246px available and stacked. */
.fnd .fnd-choice-foot .fnd-credits { padding: 0; background: transparent; white-space: nowrap; }
@media (max-width: 520px) {
  .fnd .fnd-choice-foot { flex-wrap: wrap; }
}
/* THE FOOT NO LONGER STACKS ON A PHONE. It used to, because a price pill
   and a status pill really did collide on a 375px row. Both are plain marks
   now, so the pair measures about 225px inside a 269px card and the rule was
   costing a line of height on every card for a collision that cannot happen.
   Wrapping is still there as the backstop if a translation makes one of
   them much longer. */

/* A chip inside the body is blockified by the column and takes the whole
   width unless it is told not to. `inline-flex` does not save it; the
   same trap is already documented on .fnd-segment. */
/* THE RULE MUST NOT TOUCH THE CHIP ABOVE IT, and the air cannot come out
   of the card, because a picker is already a long scroll. Founder,
   2026-08-14: "the horizontal line underneath the Learn more button is
   touching the button. I dont want to make the cards larger though."

   It happened only on the cards whose sentence is long enough to leave no
   slack for the foot to push down with, which is why it looked arbitrary.
   So the gap is RESERVED under the chip rather than borrowed from the
   slack, and paid for out of the space that was already there: 14 above
   the chip plus 20 under the rule became 10 + 14 + 10. Same 34px, moved
   to where the eye needed it. */
.fnd .fnd-choice-b > .fnd-chip-btn { align-self: flex-start; margin-top: var(--fnd-s2); margin-bottom: var(--fnd-s3); }

/* THE RECOMMENDED ONE. Tinted rather than badged, and it keeps the same
   ink ring when it is chosen, so "we suggest this" and "you picked
   this" stay two different statements. */
.fnd .fnd-choice--rec { background: var(--fnd-accent-soft); border-color: transparent; box-shadow: inset 0 0 0 1px var(--fnd-accent); }
.fnd .fnd-choice--rec:hover { border-color: transparent; box-shadow: inset 0 0 0 1px var(--fnd-accent-deep); }
.fnd .fnd-choice--rec:has(input:checked) { border-color: var(--fnd-ink); box-shadow: inset 0 0 0 2px var(--fnd-ink); }

/* CHOSEN HAS TO BEAT RECOMMENDED, AND IT DID NOT.

   Two independent reviewers opened this screen and both said the same
   thing first: the tinted card looks like the one you already picked. It
   is the strongest visual on the page and it was saying the opposite of
   what it meant, while the card that WAS chosen wore a 1px ring that a
   tint beats easily.

   Two changes, and both are needed. Chosen goes to a 2px ink ring, so it
   is unambiguously heavier than any suggestion. And a recommendation now
   has to carry a WORD: a tint alone is a colour with no meaning attached,
   which is the same failure as a status carried by hue. `--rec` is for
   the ground; the flag says why. */
/* SCOPED THROUGH THE SET, and that is not decoration: the base rule for
   this state lives in foundation-members.css, which loads AFTER this file,
   so a selector that merely TIES with it loses on order and the ring stays
   1px while every value looks correct in the source. Second time this file
   has hit that exact trap; the first was .fnd-choices--3 silently staying
   one column. Measure the computed value, never read your own rule back. */
.fnd .fnd-choices > .fnd-choice:has(input:checked) { box-shadow: inset 0 0 0 2px var(--fnd-ink); }
/* And a focus ring you can actually see. The 3px soft-accent halo is
   invisible against a tinted card and nearly invisible against paper, so
   a keyboard user on a 324px card had a 20px radio as their only cue. */
.fnd .fnd-choices > .fnd-choice:has(input:focus-visible) { box-shadow: inset 0 0 0 2px var(--fnd-accent-deep), 0 0 0 3px var(--fnd-accent-soft); }

/* A SQUARE RING ON A ROUND CONTROL. Pressing a choice flashed a light purple
   SQUARE over the circular radio, on every .fnd-choice in the product and not
   just on the page it was reported from (founder, 2026-08-16). It is not one
   of our rules: it is Chrome's own focus ring, which it tints to match
   `accent-color` and draws around the input's 20x20 BOX. The widget paints a
   circle; the box it lives in is a square, so the ring is a square.

   Two halves to the fix and both are needed. The radius makes the ring follow
   the circle in any engine that honours it. Removing the input's own outline
   is safe here, and only here, because the line above already draws a focus
   ring around the WHOLE CARD when that input is focused: keyboard focus stays
   visible, on a bigger and clearer target than a 20px dot. A choice is the one
   control where the label is the hit area, so the card is the honest place to
   show focus. */
/* The radius is deliberately NOT here. Chrome paints a radio with
   `appearance: auto`, so it draws the widget itself and border-radius on the
   box changes nothing; it was tried and measured at 0px. Two things actually
   paint the square, and both have to go.

   The OUTLINE is Chrome's focus ring, tinted to match `accent-color` and drawn
   around the input's 20x20 box.

   The SHADOW is not ours: measured rgba(79,70,229,.15), which is the OLD
   library's indigo at 15% and not a foundation token (ours would be
   --fnd-accent-soft). Some pre-foundation `:focus` rule reaches a bare radio
   on any page that still loads the old sheets, which is every page during the
   migration. Rather than chase which one, the component states what it wants.

   Safe because the rule above already rings the WHOLE CARD when this input is
   focused, so keyboard focus stays visible on a bigger, clearer target. On a
   choice the label IS the hit area, so the card is the honest place for it. */
.fnd .fnd-choice input[type="radio"]:focus,
.fnd .fnd-choice input[type="checkbox"]:focus,
.fnd .fnd-choice input[type="radio"]:focus-visible,
.fnd .fnd-choice input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: none;
}
.fnd .fnd-choice--go:focus-visible { outline: 3px solid var(--fnd-accent-deep); outline-offset: 2px; }
/* On the tint the foot's hairline all but disappears. */
.fnd .fnd-choice--rec .fnd-choice-foot { border-top-color: rgba(68, 60, 196, .18); }
/* AND SO DOES EVERY PALE-GROUNDED MARK ON IT. `.fnd-credits` sits on
   --fnd-paper-2 and `.fnd-chip-btn` on --fnd-field-bg, both of which are
   near-white warm greys chosen against the card. Dropped on the tint they
   measure about 1.1:1 and the price reads as plain text on a coloured
   card, which is what the founder saw: "the from 2 credits pill isnt
   really visible due to the light purple background". White is the only
   ground that separates from both surfaces. Same trap the --fnd-ok note
   in this file already records: a token checked against ONE surface
   fails the day it lands on the other. */
/* Only the chip needs it now. The price stopped being a pill in a foot, so
   a white ground under it on the tinted card was the one price on the screen
   still wearing one. Near-black on the lavender clears AA comfortably. */
.fnd .fnd-choice--rec .fnd-chip-btn { background: var(--fnd-card); }

/* THE ONE THAT LEAVES. An anchor, so it is a link to the keyboard and
   to a screen reader, wearing the same card. */
.fnd .fnd-choice--go { text-decoration: none; color: inherit; }
/* THE NAME IS INK WHEREVER IT SITS. On the cards that are an anchor, the
   title had no colour of its own, so it inherited the link hover and turned
   indigo while the identical title on the card beside it did not. Founder,
   2026-08-14: "the title changes colours, unlike when I hover over
   collaborator spot card". Setting the colour ON the title is what stops any
   ancestor reaching it, and it is the honest fix: a choice's name is the same
   thing whether the card selects or navigates. */
.fnd .fnd-choice-t { color: var(--fnd-text); }
.fnd .fnd-choice-go {
  flex: 0 0 20px; width: 20px; height: 20px; margin: 2px 0 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--fnd-paper-2); color: var(--fnd-text-faint);
  /* 12px, the floor, and not the 10px this was first written at. The floor
     is about text and this is a glyph, but a rule with an exception in it
     stops being enforceable, and a 12px arrow sits inside a 20px circle
     with room to spare. The circle stays 20px so it lines up with the
     radio it stands in for. */
  font-size: 12px;
}
/* Hover moves the MARK, not the words. A link that recolours its own
   label on hover is an interaction no other page in the product has,
   and this card's label is a heading. */
.fnd .fnd-choice--go:hover .fnd-choice-go { background: var(--fnd-ink); color: var(--fnd-on-ink); }
/* THE SLOT WITHOUT THE ARROW. An option that happens to be configured on
   another page is still one of the options, and the arrow told members it
   was a way OUT of the screen they were choosing on. Founder, 2026-08-14,
   about the Collaboration Listing card: "we intended on removing that
   feeling for it". The element stays so the body still starts on the same
   line as its neighbours' bodies, which is the alignment above; only the
   mark goes. `visibility` and not `display`, for exactly that reason. */
/* AND THE RING, for an option that is one of the choices but is configured
   on another page. The slot was left empty, which read as a missing icon:
   "the collaboration listing one is missing the round radio button in the
   corner". It is drawn, not a real input, because nothing about this card is
   selectable; clicking it goes somewhere. It matches the radio beside it so
   the row reads as one set. */
.fnd .fnd-choice-go--blank { visibility: hidden; }
.fnd .fnd-choice-go--ring {
  background: transparent;
  border: 1px solid var(--fnd-edge);
  box-shadow: inset 0 0 0 2px var(--fnd-card);
}
.fnd .fnd-choice--go:hover .fnd-choice-go--ring { background: transparent; border-color: var(--fnd-text-faint); }
.fnd .fnd-choice--go:focus-visible { outline: 2px solid var(--fnd-ink); outline-offset: 2px; }

/* ------------------------------------------------------------------
   TOAST, THE FOUR STATES AND THE DISMISS  (added 2026-08-14)

   `.fnd-toast` shipped in foundation.css with two states, ok and bad,
   no dismiss and no icon beyond a 7px dot. It was rendered on
   /dev/design-system and used on ZERO real pages. The site's actual
   after-an-action bar is `.flash-alert` in the old library, and
   migrating it here is what forced these gaps into the open.

   Measured over the 30 days to 2026-08-14, from app_logs log_type
   'flash', which records every one that was shown:

       success   4,306 shown to 1,284 members
       danger    3,280 shown to   419 members
       info        383 shown to   207 members
       warning     218 shown to    72 members

   So all four states are real and two of them had no component. A
   member who is told "your card expired, update it before Friday"
   cannot be shown the same bar as "saved".

   WHY THE DOT AND NOT AN ICON. The old bar carried a Font Awesome
   glyph per state. On an ink bar the dot IS the icon: the colour is
   the whole signal at 7px, and a glyph at that size on a dark ground
   reads as dirt. The copy carries the rest, which is the system's
   position everywhere else. The state also reaches a screen reader
   through role/aria-live, which no icon has ever done.

   WHY A DISMISS EXISTS HERE AND NOT IN THE ORIGINAL. The original
   auto-dismissed and assumed that was enough. The real bar has always
   had a close, some flash messages carry a link the member may want to
   read slowly, and taking a control away during a migration is how a
   migration becomes a regression.
   ------------------------------------------------------------------ */

/* The message. A flex child with no min-width will not wrap a long
   unbroken string (a URL, a channel handle), it will push the bar
   wider than its container instead. */
.fnd-toast-msg {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: break-word;
  word-break: break-word;
}
.fnd-toast-msg > :first-child { margin-top: 0; }
.fnd-toast-msg > :last-child  { margin-bottom: 0; }

/* Every state gets the dot, including the plain one. The original gave
   a dot only to ok and bad, so an info toast had its text starting at a
   different x than a success toast in the same stack. */
.fnd-toast::before {
  content: ""; flex: 0 0 auto;
  width: 7px; height: 7px; border-radius: 50%;
  margin-top: 7px;
  background: currentColor;
}
/* Light on ink, not the on-paper status tokens. --fnd-warn is #8A5A0B
   and --fnd-ok is #1F7A47; both are chosen to be read as TEXT on paper
   and both disappear on a #16141A ground. Same reason the original
   picked #7BE0A5 rather than --fnd-ok. */
.fnd-toast--warn::before { color: #F2C46B; }
.fnd-toast--info::before { color: var(--fnd-accent); }

/* THE DISMISS.
   44x44 because that is the floor, and negative margins so the target
   bleeds to the bar's own padding edges instead of inflating the bar.
   Without them a one-line toast grows from 44px tall to 68px, which on
   a phone is the difference between clearing the header and not. This
   is the same trick the old `.flash-alert__close` used and it is worth
   keeping; it was the one part of that component that was already
   right. */
.fnd-toast-x {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  margin: -12px -20px -12px -6px;
  padding: 0;
  background: none; border: 0;
  color: var(--fnd-on-ink-faint);
  font-size: 22px; line-height: 1;
  cursor: pointer;
  transition: color 140ms ease;
}
.fnd-toast-x:hover,
.fnd-toast-x:focus-visible { color: var(--fnd-on-ink); }
.fnd-toast-x:focus-visible {
  outline: 2px solid #fff; outline-offset: -4px; border-radius: 4px;
}

/* A LINK INSIDE A TOAST.
   Rare but real: one of these carries "Connect your channel" straight
   into the OAuth flow, and it is the only way out of that message. It
   must not inherit the paper link colour (--fnd-accent-deep, #443CC4)
   which is unreadable on ink, and it must not be a naked underline
   that reads as body text. A soft plate, the same move the old
   `.flash-alert__link` made, kept because it was correct. */
.fnd-toast a:not(.fnd-btn) {
  color: var(--fnd-on-ink);
  font-weight: 700;
  text-decoration: none;
  background: rgba(255, 255, 255, .16);
  padding: .15em .45em;
  border-radius: var(--fnd-r-xs);
  transition: background 140ms ease;
}
.fnd-toast a:not(.fnd-btn):hover,
.fnd-toast a:not(.fnd-btn):focus { background: rgba(255, 255, 255, .28); color: var(--fnd-on-ink); }
/* On the red bar the same plate needs to darken, not lighten, or it
   turns pink. */
.fnd-toast--bad a:not(.fnd-btn) { background: rgba(0, 0, 0, .24); }
.fnd-toast--bad a:not(.fnd-btn):hover,
.fnd-toast--bad a:not(.fnd-btn):focus { background: rgba(0, 0, 0, .38); }

/* ------------------------------------------------------------------
   WHERE A TOAST GOES, AND WHY IT IS NOT ALWAYS THE BOTTOM
   (added 2026-08-14)

   `.fnd-toasts` pins the stack to the bottom centre, "near the thumb,
   NOT in a far corner of a phone screen". That is right on a public
   page, where the bottom of the screen is empty.

   It is wrong on a member page, and this was measured rather than
   guessed. At 375px a member page already has TWO fixed things down
   there: `.mobile-bottom-nav` at 64px plus the safe area (z-index 900)
   and the Concierge dock sitting on top of it at 63px plus the safe
   area (z-index 800). A toast at z-index 10060 does not slide under
   them, it covers them, so a success message would land on the
   navigation for its full ten seconds. That is the exact collision
   recorded in `reference-bottom-of-screen-collisions`: the app nav
   sitting on the Pay button while every check passed green.

   `--top` therefore is not a preference, it is the member shell's
   answer. The stack keeps the geometry the old `#flash-container` had
   worked out over several fixes: below the header, banner-aware via
   --header-offset, full width with a 15px inset on a phone.
   ------------------------------------------------------------------ */
.fnd-toasts--top {
  top: calc(var(--header-offset, 0px) + 80px);
  bottom: auto;
  left: auto; right: 20px;
  transform: none;
  width: 100%; max-width: 380px;
}
@media (max-width: 767px) {
  .fnd-toasts--top {
    top: calc(var(--header-offset, 0px) + 70px);
    left: 15px; right: 15px;
    width: auto; max-width: none;
  }
}

/* ARRIVING AND LEAVING.
   `fade-out` is the shared state hook main.js sets on either markup, so the
   name is deliberately the old library's rather than a new one: one script
   drives both bars and a second name would mean a second code path.

   NO `opacity: 0` RESTING STATE, which is how the old `.flash-alert` did it.
   Under prefers-reduced-motion the foundation sets `animation: none !important`
   on everything inside `.fnd`, and an element parked at opacity 0 waiting for
   an animation that will never run is simply invisible. Animating FROM
   transparent instead means the no-animation case renders the bar at its
   natural opacity, which is the correct outcome for someone who asked for less
   motion: they get the message, immediately, without the slide. */
.fnd-toast { animation: fnd-toast-in 300ms ease-out both; }
.fnd-toast.fade-out { animation: fnd-toast-out 320ms ease-in forwards; }

@keyframes fnd-toast-in {
  from { opacity: 0; transform: translateX(16px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fnd-toast-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateX(16px); }
}

/* AN INK BAR OVER AN INK SURFACE HAS NO EDGE.
   The original shadow (`0 8px 26px rgba(16,14,20,.28)`) lifts the toast off
   paper, which is the case it was designed against. On a member page it
   frequently lands on something dark: on /dashboard the success bar sat
   directly on the Video Ideas card and read as that card's header rather than
   as a message floating over the page. A shadow cannot separate two dark
   things; only an edge can.

   So: a 1px light ring outside the bar, plus a deeper shadow. On a dark ground
   the ring is the whole separation. On paper it is a near-white line against a
   near-white page and disappears, which is why it can be unconditional rather
   than something each page has to opt into. */
.fnd-toast {
  box-shadow: 0 12px 32px rgba(16, 14, 20, .40),
              0 0 0 1px rgba(255, 255, 255, .16);
}
.fnd-toast--bad {
  box-shadow: 0 12px 32px rgba(16, 14, 20, .40),
              0 0 0 1px rgba(255, 255, 255, .26);
}

/* ---------------------------------------------------------------------
   THE TICK-OFF LIST                                          .fnd-checks
   (promoted 2026-08-14 from /collab-job-accepted)

   A short list of things a member confirms with their own hand before a
   decision that cannot be taken back: submitting work for review, agreeing
   to terms of a job, ticking off a setup they did somewhere else.

   NOT .fnd-choice, which is the card-shaped picker for "which of these two
   plans". A choice card is 24px of padding and an h3 title because it is
   selling one option against another. This is four short lines somebody
   reads once and ticks, and dressed as choice cards it took over the whole
   step it was supposed to end.

   NOT .fnd-bullets, which is for facts the reader SCANS and cannot touch.

   PROMOTED BECAUSE IT WAS WRITTEN TWICE ON ONE PAGE. The media kit job has a
   four-item pre-submit checklist and the video shoutout job has a
   three-item confirmation inside its popup, and before this they were two
   hand-built lists with two sets of inline styles, two checkbox sizes and
   two different label alignments. A device written twice on a single page is
   the system telling you it is missing something.

   THE WHOLE ROW IS THE TARGET. The `for`/`id` pairing is what makes the
   label press the box, so every item needs one; a bare <span> next to a
   checkbox gives a member a 20px target on a phone. Padding takes each row
   past 44px on its own.

   Whatever gates on these must use aria-disabled and never `disabled`: a
   disabled button fires no click event, so pressing it tells the member
   nothing at all about what is still unticked.
   --------------------------------------------------------------------- */
.fnd ul.fnd-checks, .fnd ol.fnd-checks {
  list-style: none;
  margin: 0 0 var(--fnd-s4);
  padding: 0;
  border-top: 1px solid var(--fnd-rule);
}
.fnd .fnd-check {
  display: flex;
  align-items: flex-start;
  gap: var(--fnd-s3);
  margin: 0;
  border-bottom: 1px solid var(--fnd-rule);
}
.fnd .fnd-check > input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  /* Lines the box up with the first line of a label that carries the row's
     padding, rather than with the top of the row. */
  margin: 13px 0 0;
  accent-color: var(--fnd-accent-deep);
  cursor: pointer;
}
/* THE PADDING IS ON THE LABEL, NOT ON THE ROW, and that is the whole trick.
   Padding on the row makes the row 45px tall and leaves the label 21px, so a
   press anywhere in the other 24px lands on nothing. On the label it grows the
   real target to the full row.

   AND THE LABEL IS NOT A FLEX CONTAINER. The first build made it
   `display:flex` to centre the text vertically, which collapses the whitespace
   between inline children: every label reading "I opened the <strong>Profile</strong>
   tab" painted as "I opened theProfiletab". Caught by eye on the media kit
   checklist, 2026-08-14; no machine check can see it, because the DOM is
   correct and only the painting is wrong. */
.fnd .fnd-check > label {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 12px 0;
  font-family: var(--fnd-body-font);
  font-weight: 400;
  font-size: var(--fnd-t-sm);
  line-height: 1.5;
  color: var(--fnd-text-soft);
  cursor: pointer;
}
.fnd .fnd-check > label strong,
.fnd .fnd-check > label b { color: var(--fnd-text); font-weight: 700; }
/* Ticked reads as settled: the words firm up rather than the row filling in,
   because a filled row would compete with the one filled button on screen. */
.fnd .fnd-check:has(input:checked) > label { color: var(--fnd-text); }
.fnd .fnd-check:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--fnd-accent-soft); border-radius: var(--fnd-r-sm); }

/* ---------------------------------------------------------------------
   THE POINT LIST, NUMBERED                        .fnd-bullets on an <ol>
   (completion of an existing device, 2026-08-14)

   `.fnd-bullets` was written as `.fnd ul.fnd-bullets` so it could outrank
   the foundation's own `.fnd ul` reset at (0,1,1). That left an ordered
   list of the same shape with no styling at all, and the Collaborator Spot
   job needs exactly that: four sub-actions inside one step, where the ORDER
   is the information ("copy the link BEFORE you close anything").

   Same rules, decimal markers. Everything else is inherited by listing the
   ol alongside the ul in the base rules above rather than restating it.
   --------------------------------------------------------------------- */
.fnd ol.fnd-bullets {
  list-style: decimal;
  margin: 0;
  padding-left: 20px;
  font-size: var(--fnd-t-sm);
  line-height: 1.55;
  color: var(--fnd-text-soft);
}
.fnd ol.fnd-bullets li { margin: 0; padding-left: 2px; }
.fnd ol.fnd-bullets li + li { margin-top: var(--fnd-s2); }
.fnd ol.fnd-bullets li::marker { color: var(--fnd-text-faint); font-variant-numeric: tabular-nums; }
.fnd ol.fnd-bullets b, .fnd ol.fnd-bullets strong { color: var(--fnd-text); font-weight: 700; }

/* ---------------------------------------------------------------------
   THE ACTION LIST                                    .fnd-bullets--do
   (modifier on the numbered point list, 2026-08-17)

   The same ordered list, set as PRIMARY reading rather than supporting
   text. Use it when the list IS the work: the actions a member has to
   perform right now, inside the one step they are on. Keep plain
   `.fnd-bullets` for facts they scan and cannot act on.

   WHY IT EXISTS. Founder, 2026-08-17, on the job screen: "I keep
   questioning the font used for the individual steps, in all job types.
   It's the actual instructions, yet it's tiny and almost barely
   visible."

   He was reading the styling correctly. Measured on a live description
   shoutout: the instructions were 15.5px in `--fnd-text-soft`, and the
   numerals beside them were `--fnd-text-faint`, the faintest ink on the
   page. That is the costume of a footnote, worn by the most important
   sentence on the screen. The class name was already in the markup on
   every job type and had NO rules anywhere, so the intent had been
   written down and never built.

   THE FIX IS HIERARCHY, NOT A SECOND BIG CIRCLE. The founder's first
   instinct was to put the big round marker of `.fnd-task-mark` beside
   each of these too. That would give one page two identical devices at
   two sizes, and the big circle would stop meaning "which part of the
   job am I on", which is the only thing it is for. One circle scale for
   phases; strong numerals for the actions inside the live phase. Body
   text at reading size, numerals in ink at display weight, so the
   sequence reads as structure.

   THE MARKER COLOUR IS THE SPEC'S, NOT A NEW CHOICE. Section 8 of
   design-system-spec.md already described this device down to the
   treatment, "small decimal markers in the accent at display weight",
   and `.fnd-stepnum` already resolves "the accent" to `accent-deep` on
   paper and `accent` on ink. Written down in full, built by nobody, for
   three days.
   --------------------------------------------------------------------- */
.fnd ol.fnd-bullets--do {
  font-size: var(--fnd-t-body);
  line-height: 1.5;
  color: var(--fnd-text);
  padding-left: 24px;
}
.fnd ol.fnd-bullets--do li + li { margin-top: var(--fnd-s3); }
.fnd ol.fnd-bullets--do li::marker {
  color: var(--fnd-accent-deep);
  font-family: var(--fnd-display-font);
  font-weight: 800;
  /* SMALLER THAN THE SENTENCE IT LEADS. The spec says "small decimal markers",
     and the first build let them inherit the raised body size, which put a
     17px display-weight numeral immediately above the circled numeral of the
     next PHASE. Two numbering systems at the same scale, counting different
     things. Colour and weight are what make these read as structure; size is
     what keeps them subordinate to the circle. */
  font-size: var(--fnd-t-sm);
}
.fnd-ink-surface ol.fnd-bullets--do li::marker,
.fnd-card--ink ol.fnd-bullets--do li::marker { color: var(--fnd-accent); }

/* NO ORPHANED LAST WORD. Founder, 2026-08-16, on a live comment shoutout: "the
   word 'it.' is on its own line." Measured at 1440: the last line of "Paste the
   exact comment into Add a comment. Do not edit, shorten, or rephrase it." was
   14px wide. List items are where every instruction on a job screen now lives,
   and the foundation only ever set a wrap style on paragraphs.

   `pretty`, and NOT `balance`, which was the first attempt and lasted about an
   hour. `balance` does kill the orphan, by splitting the sentence into two even
   half-width lines instead of filling the first one, and the founder saw that
   immediately: "I noticed the following step broke into 2 lines unnecessarily."
   Balance is for HEADINGS, where two even lines is the point. On body copy it
   throws away the width it was given.

   `pretty` is the right setting here and does not guarantee the orphan away, so
   the sentence that actually orphaned binds its last two words with a
   non-breaking space at the source. That is deterministic, costs nothing, and
   does not reflow anything else. */
.fnd ul.fnd-bullets li, .fnd ol.fnd-bullets li { text-wrap: pretty; }
.fnd .fnd-check > label { text-wrap: pretty; }

/* ---------------------------------------------------------------------
   THE INSET PANEL                                             .fnd-inset
   (promoted 2026-08-14 from /collab-job-accepted)

   A block set INTO a card rather than sitting on it: a quoted example, a
   picture of somebody else's interface, a waiting state, a small result.
   Tinted paper, a hairline, the small radius, one step of padding.

   It is not a card. `.fnd-card` sits ON the page and casts the page's own
   surface; this sits INSIDE something and reads as recessed, which is the
   whole difference. Nesting a card in a card is what it exists to stop.

   Found by the device gate, which matched this page's private version of it
   against `.streak-status` on /community-watch at the same four
   declarations. That page still carries its own copy and should take this
   one when it is next opened; leaving a second private version standing is
   the debt the gate is naming, not a reason to keep a third.
   --------------------------------------------------------------------- */
.fnd .fnd-inset {
  padding: var(--fnd-s3);
  background: var(--fnd-paper-2);
  border: 1px solid var(--fnd-rule);
  border-radius: var(--fnd-r-sm);
}
/* On ink the tint has nothing to sit on, so it takes the ink surface's own
   raised value and its hairline, the same swap every device makes there. */
.fnd .fnd-ink-surface .fnd-inset,
.fnd .fnd-card--ink .fnd-inset {
  background: rgba(255, 255, 255, .05);
  border-color: var(--fnd-on-ink-rule);
}

/* ------------------------------------------------------------------
   FIELD FOOT  (the row under a text field)
   A note, counter or status on the left and the action on the right,
   wrapping to two lines when the two cannot share one.

   PROMOTED 2026-08-14 because it had already been built twice, under
   two names, on two pages that never saw each other:
     - .rvl2-correct-foot / .rvl2-correct-counter  (/onboarding/reveal)
     - .dna-edit-footer   / .dna-char-counter      (/my-profile)
   Declaration for declaration the two were identical: flex, wrap,
   space-between, centre, s3 gap, with a --fnd-t-meta / --fnd-text-faint
   note on the left. `check.js devices` flagged them as twins and it was
   right. /my-profile still carries its private copy and should adopt
   this the next time that page is opened.

   The note collapses while it is empty rather than being display:none'd,
   because on both pages it is the aria-live region a message is written
   into, and a hidden live region is not announced when it later fills.
   Reserving its height instead cost a measured 60px hole between the
   field and its button at 375px on the reveal, in the state most members
   see (nothing has been written yet).
   ------------------------------------------------------------------ */
.fnd-field-foot {
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: space-between;
  gap: var(--fnd-s3);
}
.fnd-field-foot-note {
  font-size: var(--fnd-t-meta);
  color: var(--fnd-text-faint);
  font-variant-numeric: tabular-nums;
  flex: 1 1 200px;
  min-height: 1.4em;
}
.fnd-field-foot-note:empty { flex: 0 0 0; min-height: 0; }
/* The note stops being background when it is carrying a limit or a
   refusal. Same weight step both pages had reached independently. */
.fnd .fnd-field-foot-note--loud { color: var(--fnd-text-soft); font-weight: 600; }

/* ------------------------------------------------------------------
   A CARD THAT FILLS THE HEIGHT ITS ROW GAVE IT
   .fnd-cards--2 / --3 stretch every card to the tallest, which is right:
   a ragged row reads as broken. The cost lands on the card with the least
   to say, and it is invisible to every other check we own, because nothing
   overflows, touches or goes off-token. Measured on /onboarding/reveal at
   1440: card 01 carries three facts and its content ended at 298px inside a
   430px box. 132px of dead white beside two full neighbours, in the state
   97.6% of members see (niche is null for 18,060 of the 18,497 who reached
   that page in 30 days).

   Check this on any card row where one card is data-driven and the others
   are not, AND the thin state is the common one.

   .fnd-bands gives the slack to the ROWS, not to the gaps between them.
   justify-content: space-between is the obvious first try and it is wrong:
   it leaves each hairline floating under its own pair with a void beneath,
   which reads as pairs pushed apart. Growing the rows puts each rule at the
   foot of its own band, so the card reads as a ruled spec sheet.
   ------------------------------------------------------------------ */
.fnd-card--fill { display: flex; }
.fnd-card--fill > .fnd-card-body {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
}
.fnd-bands { flex: 1 1 auto; }
.fnd-bands > * { flex: 1 1 auto; }

/* ------------------------------------------------------------------
   .fnd-idhead — WHO THIS PAGE IS ABOUT: the member's own face, their
   name in display type, and one line saying what happens here.

   Promoted 2026-08-14 out of /onboarding/reveal, on the day the two
   screens BEFORE it were migrated and both needed the same block.
   Three pages in one flow, seen inside about two minutes by the same
   person, is exactly the case the promotion gate exists for: three
   private copies would have drifted in avatar size, gap and where the
   text centres, and the drift would have been visible as a flicker
   between screens rather than as a fault on any one of them.

   NOT .fnd-pagehead. That one is a left-aligned working header with a
   figure in a slot on the right, for a page a member visits daily. This
   is the identity block for a page ABOUT them, and it carries a picture
   where the pagehead carries a number.

   Sizes are reveal's, unchanged: 72px face by default, and --hero for
   the one screen where the member's own photo IS the moment (88px on a
   phone, 120px from tablet up). Anything bigger than --hero is not a
   variant of this, it is a landing page.
   ------------------------------------------------------------------ */
.fnd-idhead {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--fnd-s3);
  margin-bottom: var(--fnd-s6);
}
/* --center stays stacked and centred at every width. Use it when the
   page is a WAIT or a confirmation, where there is one thing to look at
   and no reading column to line the face up against. */
@media (min-width: 768px) {
  .fnd-idhead:not(.fnd-idhead--center) {
    flex-direction: row;
    align-items: center;
    text-align: left;
    gap: var(--fnd-s5);
    margin-bottom: var(--fnd-s7);
  }
}

.fnd-idhead-media { flex: 0 0 auto; }
.fnd-idhead-text  { min-width: 0; }

.fnd-idhead-face {
  display: block;
  width: 72px; height: 72px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--fnd-paper-2);
  /* The white ring plus one hairline, not a border. A YouTube avatar is
     frequently a dark logo on a dark square, and a plain 1px rule around
     it disappears; the card-coloured ring is what separates the picture
     from the paper whatever the picture is. */
  border: 3px solid var(--fnd-card);
  box-shadow: 0 0 0 1px var(--fnd-rule);
}
.fnd-idhead--hero .fnd-idhead-face { width: 88px; height: 88px; }
@media (min-width: 768px) {
  .fnd-idhead--hero .fnd-idhead-face { width: 120px; height: 120px; border-width: 4px; }
}

/* No avatar on file. Same box, same ring, a quiet glyph. */
.fnd-idhead-face--fallback {
  display: flex; align-items: center; justify-content: center;
  color: var(--fnd-text-faint);
  font-size: 28px;
}
.fnd-idhead--hero .fnd-idhead-face--fallback { font-size: 34px; }
@media (min-width: 768px) {
  .fnd-idhead--hero .fnd-idhead-face--fallback { font-size: 44px; }
}

.fnd-idhead-t {
  font-family: var(--fnd-display-font);
  font-weight: 800;
  letter-spacing: -.028em;
  line-height: 1.08;
  font-size: var(--fnd-t-h2);
  color: var(--fnd-text);
  margin: 0 0 var(--fnd-s2);
  /* A channel name is arbitrary user text and is regularly one unbroken
     40-character string. Without this it runs off a 375px screen. */
  word-break: break-word;
  overflow-wrap: break-word;
}

.fnd-idhead-sub {
  font-size: var(--fnd-t-body);
  line-height: 1.55;
  color: var(--fnd-text-soft);
  margin: 0 auto;
  max-width: 52ch;
}
@media (min-width: 768px) {
  .fnd-idhead:not(.fnd-idhead--center) .fnd-idhead-sub { margin: 0; }
}

/* ------------------------------------------------------------------
   .fnd-tagfield — a text input that collects removable tags.

   Promoted 2026-08-14. Two pages had built it privately: the Growth
   Studio DNA popup (studio-v2.css, scoped to #studio-dna-modal) and the
   onboarding Content Keywords field. Both are driven by DIFFERENT
   JavaScript files that happen to write the same three class names,
   which is why nothing caught the duplicate: check.js devices hunts
   page-private NAMES, and these two agreed on the names and disagreed
   on nothing but where the rules lived.

   THE INNER CLASS NAMES ARE JAVASCRIPT HOOKS, NOT DEVICE PARTS, and
   they are deliberately not renamed to .fnd-*. Two shipped scripts
   create .dna-tag-chip and .dna-tag-chip__remove with innerHTML, and
   both also serve pages that are still on the old library, so a rename
   would break the branch members are using today. The wrapper is the
   only class a template adds.
   ------------------------------------------------------------------ */
.fnd-tagfield {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  /* Matches .fnd-input exactly, so a tag field and the select above it
     read as the same kind of control. Same 52px floor, same edge, same
     field ground. */
  min-height: 52px;
  padding: 8px 10px;
  background: var(--fnd-field-bg);
  border: 1px solid var(--fnd-edge);
  border-radius: var(--fnd-r-sm);
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.fnd .fnd-tagfield:focus-within {
  border-color: var(--fnd-text);
  box-shadow: 0 0 0 3px var(--fnd-accent-soft);
}

.fnd .fnd-tagfield .dna-tag-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--fnd-accent-soft); color: var(--fnd-accent-deep);
  border-radius: 999px;
  padding: 4px 6px 4px 12px;
  font-size: var(--fnd-t-meta); font-weight: 600;
  max-width: 100%;
}
.fnd .fnd-tagfield .dna-tag-chip > span { min-width: 0; overflow-wrap: break-word; }

.fnd .fnd-tagfield .dna-tag-chip__remove {
  flex: 0 0 auto;
  border: 0; background: none; color: inherit; cursor: pointer;
  font-size: 15px;
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.fnd .fnd-tagfield .dna-tag-chip__remove:hover { background: rgba(0,0,0,.08); }
/* 22px is the right SIZE for a control inside a chip and the wrong hit area
   on a phone. The pseudo-element gives it the 44px floor without growing the
   chip. This is invisible to every check we own, because a chip only exists
   after somebody has typed one and `check.js live` grades the page as it
   loads, when there are none. (Written once, lost when a parallel tab stomped
   this file, and only noticed when a sweep measured the box. Re-added
   2026-08-16.) */
.fnd .fnd-tagfield .dna-tag-chip__remove { position: relative; }
.fnd .fnd-tagfield .dna-tag-chip__remove::after {
  content: ""; position: absolute; inset: -11px;
}

/* The typing slot. It is the field's own input, so it carries no edge of
   its own; the wrapper is the control. */
.fnd .fnd-tagfield > input[type="text"] {
  flex: 1 1 120px; min-width: 100px; width: auto;
  min-height: 34px;
  border: 0; outline: none; background: transparent;
  padding: 6px 4px;
  font-family: var(--fnd-body-font);
  /* 17px, same reason as .fnd-input: iOS Safari zooms the page on a
     focused input under 16px. */
  font-size: var(--fnd-t-body);
  color: var(--fnd-text);
}
.fnd .fnd-tagfield > input[type="text"]::placeholder { color: var(--fnd-text-faint); }
.fnd .fnd-tagfield > input[type="text"]:disabled { background: transparent; color: var(--fnd-text-faint); }

/* ------------------------------------------------------------------
   .fnd-fieldrow — two short fields on one line.

   Promoted 2026-08-14 from the onboarding setup form, which pairs
   Primary Category with Language and Brand Safety with Target Age.
   .fnd-fieldgroup already says "these fields belong together"; this
   says the stronger thing, that two of them are short enough to read
   as one question and should not cost two rows of a phone screen.

   It is deliberately narrow. Two children, never three: a third column
   puts every label under about 15 characters at 1440 and they start
   wrapping, and there is no width at which four short fields in a row
   are easier than two rows of two.

   The row owns the vertical gap, so the fields inside it give up their
   own bottom margin. Without that the stacked phone layout gets the
   field margin AND the grid gap and the pair drifts apart exactly where
   it most needs to look like a pair.
   ------------------------------------------------------------------ */
.fnd-fieldrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--fnd-s3);
  margin-bottom: var(--fnd-s3);
}
/* 560, not 768: these are short controls and they fit side by side on a
   large phone in landscape long before a tablet. */
@media (min-width: 560px) {
  .fnd-fieldrow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.fnd .fnd-fieldrow > .fnd-field { margin-bottom: 0; min-width: 0; }

/* A face inside a proportion ring. Both halves already ship; what nobody
   can know from either file alone is that .fnd-ring::before paints its
   inner disc at inset 7px, so an 84px ring leaves 70px and the device's
   default 72px face covers the track completely. Settled here once,
   because the next page to put a member's picture inside a progress ring
   would measure it again. Promoted with .fnd-idhead on 2026-08-14. */
.fnd-ring > .fnd-idhead-face { position: relative; width: 62px; height: 62px; border-width: 2px; }
.fnd-ring > .fnd-idhead-face--fallback { font-size: 22px; }

/* ------------------------------------------------------------------
   .fnd-actionbar-in — the action bar's contents, held to the page's
   reading width.

   .fnd-actionbar is full bleed on purpose: it carries the only shadow in
   this system and an inset one reads as a floating panel rather than as
   the floor of the screen. But its BUTTONS have to line up with the
   column above them, or the confirm sits against the edge of a 1440px
   window while the thing it confirms is 640px wide in the middle.

   Promoted 2026-08-14 after the reveal screen and the onboarding setup
   form had each written it, five declarations apart. A page that reads
   narrower than the shell overrides max-width and nothing else.
   ------------------------------------------------------------------ */
.fnd-actionbar-in {
  width: 100%;
  max-width: var(--fnd-shell-w, 1080px);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--fnd-s3);
}

/* ============================================================================
   AN EMPTY PICTURE BOX, AND THE CUE THAT A QUESTION IS UNANSWERED
   Promoted 2026-08-16 out of /create-collab.

   WHY THIS IS IN THE SYSTEM AND NOT ON THE PAGE. The founder built a test
   campaign and skipped the required "Choose a video" question himself, then
   found the cause: its button showed a stack of thumbnails from his library, so
   an UNANSWERED question was drawing the one signal a member reads as ANSWERED.
   At 375px it was worse than that, because the page hid all but the first
   thumbnail to save room, making the empty state pixel-for-pixel the shape of
   the chosen state.

   The rule the fix encodes: A PICTURE IS AN ANSWER. Never show one until there
   is something to answer with. An empty slot must look like a slot.

   Both parts are here rather than on the page because the counting test says
   so: /create-collab alone asks this question twice (Community Watch and the
   shoutout video target), and every form in the product has required fields. */

/* The empty slot. A modifier on .fnd-media, so an empty box and a filled one
   are the same object at the same size and the row cannot change shape when it
   is answered. The dashed edge replaces the ::before hairline rather than
   sitting inside it, because two rings at 62px read as a mistake. */
.fnd .fnd-media--empty {
  background: var(--fnd-paper-2);
  border: 1px dashed rgba(22, 20, 26, .26);
  display: flex;
  align-items: center;
  justify-content: center;
}
.fnd .fnd-media--empty::before { box-shadow: none; }
.fnd .fnd-media--empty > i {
  font-size: 15px;
  line-height: 1;
  color: var(--fnd-text-faint);
}
@media (max-width: 559px) {
  .fnd .fnd-media--empty > i { font-size: 13px; }
}

/* The required cue. Sits inside a .fnd-label, after the words. Deliberately a
   WORD and not an asterisk: an asterisk is a convention a non-technical creator
   has to already know, it is invisible to anyone skim-reading, and it does not
   translate, which matters on a page served in 34 languages. */
.fnd .fnd-req {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--fnd-paper-2);
  font-family: var(--fnd-body-font);
  font-size: var(--fnd-t-micro);
  font-weight: 700;
  letter-spacing: .03em;
  color: var(--fnd-text-faint);
  vertical-align: middle;
}
/* Once the question is answered the cue stops being information and becomes
   noise, so the page flips this attribute rather than removing the element. */
.fnd .fnd-req[data-answered="true"] { display: none; }

/* ==================================================================
   STATUS ICON  (.fnd-status-icon)
   A subtle state MARK sitting above a status or result message: a plain
   coloured icon, no filled circle, so it signals the outcome at a glance
   without reintroducing the badge-y decoration the system deliberately
   strips. Colour keyed to the outcome with the same --ok / --bad / --info
   scheme as .fnd-badge. For /verify-email, password-reset results,
   subscription errors, and any focused result screen built on .fnd-empty.
   First used on /verify-email, 2026-08-18.
   ------------------------------------------------------------------ */
.fnd-status-icon {
  display: block;
  text-align: center;
  margin: 0 0 var(--fnd-s3);
  font-size: 38px;
  line-height: 1;
  color: var(--fnd-accent-deep);
}
.fnd-status-icon > i { line-height: 1; }
.fnd-status-icon--ok   { color: var(--fnd-ok); }
.fnd-status-icon--bad  { color: var(--fnd-danger); }
.fnd-status-icon--info { color: var(--fnd-accent-deep); }

/* ============================================================================
   THE PROMO BANNER  (.fnd-promo)
   ----------------------------------------------------------------------------
   A flat, time-boxed offer band: a big percentage, a two-line deal, an eyebrow
   tag, and a live countdown. It is the foundation's `.fnd-callout--tip` surface
   (flat accent-soft ground, #D6D2FB rule, #2E2856 ink) given the one job a tip
   box cannot do, which is carry a running deadline, and it does that WITHOUT a
   gradient or a shadow. That restraint is the whole point: the first version of
   this banner wore a warm amber gradient lifted from a promo template and read
   instantly as an old-library sticker sitting on a foundation page.

   Promoted 2026-08-24 from the lifetime-discount banner that ships in the
   upgrade modal (`.ncm-v2__discount-banner`, member) and on /pricing
   (`.cp-offer-strip`, public). Those two predate this device and match its
   surface; they keep their own class names because their markup is wired to
   JavaScript by data-attribute. New promo bands use THIS class.
   ========================================================================== */
.fnd-promo {
  display: flex;
  align-items: center;
  gap: var(--fnd-s4);
  flex-wrap: wrap;
  padding: var(--fnd-s3) var(--fnd-s4);
  border: 1px solid #D6D2FB;
  border-radius: var(--fnd-r-sm);
  background: var(--fnd-accent-soft);
  color: #2E2856;
  font-family: var(--fnd-body-font);
}
/* The percentage is the one loud thing on the band. */
.fnd-promo__pct {
  font-family: var(--fnd-display-font);
  font-weight: 800;
  letter-spacing: -.03em;
  font-size: clamp(2rem, 6vw, 2.6rem);
  line-height: 1;
  color: var(--fnd-accent-deep);
}
.fnd-promo__body { flex: 1 1 200px; min-width: 0; }
.fnd-promo__title {
  display: block;
  font-family: var(--fnd-display-font);
  font-weight: 800;
  letter-spacing: -.015em;
  color: #2E2856;
}
/* The saving steps down to soft text so the percentage still leads. */
.fnd-promo__sub {
  display: block;
  margin-top: 2px;
  font-size: var(--fnd-t-meta);
  color: var(--fnd-text-soft);
}
.fnd-promo__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  margin-left: auto;
}
.fnd-promo__tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--fnd-card);
  border: 1px solid #D6D2FB;
  color: var(--fnd-accent-deep);
  font-family: var(--fnd-display-font);
  font-weight: 700;
  font-size: var(--fnd-t-micro);
}
.fnd-promo__timer {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fnd-t-micro);
  color: var(--fnd-text-soft);
}
/* Tabular numerals are load-bearing: without them the digits change width every
   second and the whole band jitters, which is the one thing a deadline cannot
   do. */
.fnd-promo__timer b {
  font-family: var(--fnd-display-font);
  font-weight: 800;
  font-size: var(--fnd-t-h3);
  font-variant-numeric: tabular-nums;
  color: #2E2856;
}
@media (max-width: 560px) {
  .fnd-promo__meta { align-items: flex-start; margin-left: 0; width: 100%; }
}
