/* ============================================================================
   Theory Media · INSTRUMENTS
   The evidence-device library, recovered 2026-08-30.

   WHY THIS FILE EXISTS
   The Squarespace site carried a substantially richer set of hand-coded charts
   and diagrams than the 4 Aug Cloudflare rebuild kept. Ryan asked for them back
   (brief of 30 Aug, section 3.4). Every one of them was CSS and markup scoped to
   .tm-root, never an image and never a third-party embed, so all of it was
   recoverable from the 5 Aug archive at
   Projects/Theory Media/squarespace-archive-2026-08-05/raw-html/.

   These are rebuilt, not pasted. The originals used the old Squarespace type
   stack and a flat palette. These are re-expressed in the current token system
   and held to tm-data-viz's seven-point review.

   PROVENANCE, device by device
     .tmi-path      <- home.html          fpath/fentry/farrow/fcost/fev/fevv
     .tmi-spine     <- growth-diagnostic  exmap/exspine/exnode/extier/extlabel
     .tmi-funnel    <- growth-diagnostic  ifun/istage/iname/ipct
     .tmi-ledger    <- growth-diagnostic  ledger/lhdr/ltab/lfoot/tbl/tcell
     .tmi-bars      <- proof.html         dbars/dbar/dtrack/dfill/dlabel/dnote
     .tmi-grid      <- local-engine.html  tm-grid/tm-cell
     .tmi-track     <- home.html          ovis/ovtrack/ovfill/ovtop/ovv
     .tmi-timeline  <- proof.html         tld/tli

   THE RULES THESE ARE BUILT TO (tm-data-viz, non-negotiable)
     1. Bar length always starts at zero. No truncated axes anywhere in here.
     2. The accent (--logo) marks ONE thing per instrument: what is measured,
        live, or the subject's own. Rivals and context run pencil grey.
     3. Nothing critical is carried by tone alone. Every state pairs a tone with
        a word and a mark, so the figure survives a black and white print.
     4. Every instrument has a footing slot (.tmi-foot). A figure without its
        footing is not a firm figure. The slot is not optional decoration; it is
        why the page looks like it was made by someone accountable.
     5. Final state is in the markup. Motion only enhances; with JS off or
        reduced motion on, the instrument is fully readable.

   TYPE NOTE
   The legislature's standing build rule says Manrope and IBM Plex Mono. Plex
   Mono was retired 2026-07-18 and fonts.css confirms only Manrope and Hanken
   Grotesk load. Numerals here run Hanken with tabular-nums, per the repo rule.
   Flagged to Ryan rather than silently resolved.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   0 · Shared chassis
   --------------------------------------------------------------------------- */

.tmi {
  --tmi-rule: rgba(14, 19, 24, 0.12);
  --tmi-track: rgba(14, 19, 24, 0.07);
  --tmi-ink: var(--body-ink);
  --tmi-quiet: var(--slate);
  --tmi-subject: var(--logo);
  --tmi-rival: var(--slope);

  width: 100%;
  margin: 0;
  font-family: var(--font-label);
  color: var(--tmi-ink);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* On a dark stage the ladder inverts. Tone roles stay identical so no
   instrument needs a separate dark variant. */
.stage-dark .tmi {
  --tmi-rule: rgba(236, 237, 236, 0.13);
  --tmi-track: rgba(236, 237, 236, 0.08);
  --tmi-ink: var(--paper);
  --tmi-quiet: var(--slope);
  --tmi-rival: var(--slate);
}

/* The dark acts are deliberately colorless: invisibility has no color.
   So the accent resolves to plain paper there, not to logo-slate. */
.stage-dark .tmi { --tmi-subject: var(--paper); }

.tmi__title {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  color: var(--tmi-ink);
  margin: 0 0 var(--space-2);
  text-wrap: balance;
}

/* The action-title rule: the eyebrow names the variable, the title states the
   finding. Never the other way round. */
.tmi__eyebrow {
  display: block;
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--tmi-quiet);
  margin: 0 0 var(--space-2);
}

.tmi__foot,
.tmi-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--tmi-rule);
  font-size: var(--text-caption);
  line-height: 1.5;
  color: var(--tmi-quiet);
}

/* Footing badges. Tone plus WORD, never tone alone. */
.tmi-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.tmi-badge::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.tmi-badge--verified     { color: var(--good); }
.tmi-badge--reasoned     { color: var(--mid); }
.tmi-badge--illustrative { color: var(--tmi-quiet); }
.tmi-badge--illustrative::before { border-radius: 0; transform: rotate(45deg); }
.tmi-badge--reasoned::before     { border-radius: 1px; }

.tmi-src { font-size: var(--text-caption); color: var(--tmi-quiet); }


/* ---------------------------------------------------------------------------
   1 · .tmi-bars  ·  labelled bar chart with a built-in note slot
   Recovered from proof.html (dbars/dbar/dtrack/dfill/dlabel/dnote/dtop).

   The original's best idea, kept: a note slot per row. The footing lives beside
   the bar it foots, not in a caption the eye has to travel to.

   Length encodes the quantity, which is the most accurate channel available
   after position. Axis is implicitly zero because the track always starts at the
   left edge and --tmi-v is a fraction of it. There is no mechanism in this
   device to truncate an axis, by design.
   --------------------------------------------------------------------------- */

.tmi-bars__rows { display: grid; gap: var(--space-4); }

.tmi-bar {
  display: grid;
  grid-template-columns: minmax(7rem, 22%) 1fr auto;
  align-items: center;
  gap: var(--space-3) var(--space-4);
}

.tmi-bar__label {
  font-size: var(--text-small);
  line-height: 1.35;
  color: var(--tmi-ink);
}

.tmi-bar__track {
  position: relative;
  height: 12px;
  background: var(--tmi-track);
  border-radius: var(--radius-tight);
  overflow: hidden;
}

.tmi-bar__fill {
  position: absolute;
  inset: 0 auto 0 0;
  /* Final state is in the markup via --tmi-v. No JS required to read it. */
  width: calc(var(--tmi-v, 0) * 100%);
  background: var(--tmi-rival);
  border-radius: inherit;
}

/* The one accent. Exactly one row per chart should carry this. */
.tmi-bar--subject .tmi-bar__fill { background: var(--tmi-subject); }

/* Survives greyscale: the subject also gets a rule the rivals do not have. */
.tmi-bar--subject .tmi-bar__track {
  box-shadow: inset 0 0 0 1px var(--tmi-subject);
}

.tmi-bar__value {
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--tmi-ink);
  white-space: nowrap;
}

.tmi-bar__note {
  grid-column: 2 / -1;
  margin-top: calc(var(--space-1) * -1);
  font-size: var(--text-caption);
  color: var(--tmi-quiet);
}

@media (max-width: 640px) {
  .tmi-bar { grid-template-columns: 1fr auto; }
  .tmi-bar__label { grid-column: 1 / -1; }
  .tmi-bar__track { grid-column: 1; }
  .tmi-bar__note  { grid-column: 1 / -1; }
}


/* ---------------------------------------------------------------------------
   2 · .tmi-track  ·  single filled readout
   Recovered from home.html (ovis/ovtrack/ovfill/ovtop/ovv).

   One number, at scale, with the track showing what it is a share OF. Used where
   a bar chart would be overkill because there is only one value that matters.
   --------------------------------------------------------------------------- */

.tmi-track__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
}

.tmi-track__v {
  font-family: var(--font-display);
  font-size: var(--text-fig);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: var(--tracking-tight);
  color: var(--tmi-subject);
}

.tmi-track__of {
  font-size: var(--text-small);
  color: var(--tmi-quiet);
  text-align: right;
  max-width: 18ch;
  line-height: 1.4;
}

.tmi-track__rail {
  position: relative;
  height: 6px;
  background: var(--tmi-track);
  border-radius: var(--radius-round);
  overflow: hidden;
}

.tmi-track__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--tmi-v, 0) * 100%);
  background: var(--tmi-subject);
  border-radius: inherit;
}


/* ---------------------------------------------------------------------------
   3 · .tmi-funnel  ·  staged funnel carrying a percentage per stage
   Recovered from growth-diagnostic.html (ifun/istage/iname/ipct).

   The legislature named this as one of the two devices /growth-diagnostic has to
   carry. Each stage shows its own count AND its conversion from the stage above,
   because a funnel that only shows counts hides where the loss is, which is the
   entire thing a founder is trying to see.

   Honest by construction: stage width is proportional to the count, so the shape
   cannot be drawn to flatter a bad step.
   --------------------------------------------------------------------------- */

.tmi-funnel__stages { display: grid; gap: var(--space-2); }

.tmi-stage {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--tmi-rule);
  border-radius: var(--radius-tight);
  position: relative;
  /* Width proportional to the count. Never hand-set. */
  width: calc(38% + var(--tmi-v, 1) * 62%);
  min-width: 12rem;
  background: transparent;
}

.tmi-stage__name {
  font-size: var(--text-small);
  color: var(--tmi-ink);
}

.tmi-stage__n {
  font-weight: 700;
  font-size: var(--text-small);
  color: var(--tmi-ink);
  white-space: nowrap;
}

/* The drop between stages. This is the finding, so it gets the accent, and it
   also gets a word so it survives greyscale. */
.tmi-stage__drop {
  grid-column: 1 / -1;
  margin-top: var(--space-1);
  font-size: var(--text-caption);
  color: var(--tmi-quiet);
}

.tmi-stage--loss { border-color: var(--tmi-subject); }
.tmi-stage--loss .tmi-stage__drop { color: var(--tmi-subject); font-weight: 600; }

@media (max-width: 640px) {
  .tmi-stage { width: 100%; }
}


/* ---------------------------------------------------------------------------
   4 · .tmi-spine  ·  tiered node-and-spine system map
   Recovered from growth-diagnostic.html (exmap/exspine/exnode/extier/extlabel).

   The closest thing the old site had to a diagram of how the firm thinks. The
   legislature ruled /method carries this one. A vertical spine with tiers
   hanging off it; each tier is a labelled row of nodes.
   --------------------------------------------------------------------------- */

.tmi-spine__map {
  position: relative;
  padding-left: var(--space-8);
}

/* The spine itself. */
.tmi-spine__map::before {
  content: "";
  position: absolute;
  left: 7px; top: 0.6em; bottom: 0.6em;
  width: 1px;
  background: var(--tmi-rule);
}

.tmi-tier {
  position: relative;
  padding-bottom: var(--space-8);
}
.tmi-tier:last-child { padding-bottom: 0; }

/* The node on the spine. */
.tmi-tier::before {
  content: "";
  position: absolute;
  left: calc(var(--space-8) * -1 + 3px);
  top: 0.45em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--paper);
  border: 1px solid var(--tmi-quiet);
}
.stage-dark .tmi-tier::before { background: var(--ink); }

.tmi-tier--now::before {
  background: var(--tmi-subject);
  border-color: var(--tmi-subject);
}

.tmi-tier__label {
  font-family: var(--font-display);
  font-size: var(--text-h4);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  color: var(--tmi-ink);
  margin: 0 0 var(--space-1);
}

.tmi-tier__k {
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--tmi-quiet);
  display: block;
  margin-bottom: var(--space-2);
}

.tmi-tier__nodes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.tmi-node {
  font-size: var(--text-caption);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--tmi-rule);
  border-radius: var(--radius-tight);
  color: var(--tmi-ink);
  line-height: 1.3;
}


/* ---------------------------------------------------------------------------
   5 · .tmi-path  ·  branching path diagram carrying a value per branch
   Recovered from home.html (fpath/fpaths/fentry/fstart/farrow/fcost/fcv/fev).

   The most distinctive device the old site had, and the one worth reviving most.
   One entry, then branches, each branch carrying its own cost and its own
   outcome. It is how the firm argues that the path a stranger takes is a design
   decision rather than an accident.
   --------------------------------------------------------------------------- */

.tmi-path__entry {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--tmi-ink);
  border-radius: var(--radius-tight);
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--tmi-ink);
  margin-bottom: var(--space-6);
}

.tmi-path__branches {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.tmi-branch {
  position: relative;
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  padding-top: var(--space-6);
  border: 1px solid var(--tmi-rule);
  border-radius: var(--radius-tight);
}

/* The connector back up to the entry. Drawn, not implied. */
.tmi-branch::before {
  content: "";
  position: absolute;
  left: var(--space-4); top: 0;
  width: 1px; height: var(--space-4);
  background: var(--tmi-rule);
}

.tmi-branch__name {
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  color: var(--tmi-ink);
}

.tmi-branch__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-caption);
  color: var(--tmi-quiet);
  border-top: 1px solid var(--tmi-rule);
  padding-top: var(--space-2);
}

.tmi-branch__v {
  font-weight: 700;
  font-size: var(--text-small);
  color: var(--tmi-ink);
  white-space: nowrap;
}

/* A branch whose FIGURE is the argument. Used where the gap between two branches
   is the finding, so the number carries display scale instead of caption scale.
   Added 2026-08-30: the fork's figures were rendering at ~13px on a page whose
   grammar is huge display type, which made the argument the quietest thing on
   the screen. Deliberately a modifier, so the ladder use of .tmi-branch on
   /local keeps its compact form. Tabular figures per the house rule, since the
   two values sit one above the other and must align digit for digit. */
.tmi-branch__k {
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--tmi-quiet);
  display: block;
  border-top: 1px solid var(--tmi-rule);
  padding-top: var(--space-3);
  margin-top: var(--space-1);
}
.tmi-branch__big {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 1.6rem + 2.4vw, 3.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--tracking-tight);
  color: var(--tmi-ink);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  margin-top: var(--space-2);
}
.tmi-branch--found .tmi-branch__big { color: var(--tmi-subject); }

/* The branch that turned out to be the true one. Same accent as --live, but it
   marks a FINDING rather than a recommendation, so it deliberately carries no
   LIVE label: calling a diagnosed fault "live" would misdescribe it. Added
   2026-08-30 for the homepage fork fragment. Per tm-data-viz rule 3 the state is
   never carried by tone alone; the branch names carry it in words. */
.tmi-branch--found { border-color: var(--tmi-subject); }
.tmi-branch--found .tmi-branch__v { color: var(--tmi-subject); }

/* The branch the firm actually recommends. One per diagram. */
.tmi-branch--live { border-color: var(--tmi-subject); }
.tmi-branch--live .tmi-branch__v { color: var(--tmi-subject); }
.tmi-branch--live .tmi-branch__name::after {
  content: "LIVE";
  margin-left: 0.6em;
  font-family: var(--font-label);
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wider);
  font-weight: 600;
  color: var(--tmi-subject);
  vertical-align: 0.15em;
}


/* ---------------------------------------------------------------------------
   6 · .tmi-grid  ·  map grid / heat grid
   Recovered from local-engine.html (tm-grid/tm-cell).

   The one place the firm's reserved --good/--mid/--bad palette is allowed on a
   marketing surface, because here tone IS the data: it encodes rank. Standing
   rule from the legislature, restated so it cannot drift: color heatmaps are
   permitted ONLY where they encode rank data, never as chrome.

   Every cell prints its own rank numeral, so the grid is fully readable with no
   color at all. That is the greyscale-survival requirement, satisfied by
   redundancy rather than by argument.
   --------------------------------------------------------------------------- */

.tmi-grid__plot {
  display: grid;
  grid-template-columns: repeat(var(--tmi-cols, 7), 1fr);
  gap: 3px;
  max-width: 26rem;
}

.tmi-cell {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 2px;
  font-size: var(--text-caption);
  font-weight: 700;
  color: var(--paper);
  background: var(--tmi-rival);
  line-height: 1;
}

.tmi-cell--top   { background: var(--good); }   /* rank 1 to 3   */
.tmi-cell--mid   { background: var(--mid); }    /* rank 4 to 10  */
.tmi-cell--low   { background: var(--bad); }    /* rank 11 to 20 */
.tmi-cell--none  {                              /* not in results */
  background: transparent;
  border: 1px solid var(--tmi-rule);
  color: var(--tmi-quiet);
}

.tmi-grid__key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-size: var(--text-caption);
  color: var(--tmi-quiet);
}
.tmi-grid__key span { display: inline-flex; align-items: center; gap: 0.45em; }
.tmi-grid__key i {
  width: 10px; height: 10px; border-radius: 2px; flex: none;
  font-style: normal;
}


/* ---------------------------------------------------------------------------
   7 · .tmi-ledger  ·  ruled ledger table
   Recovered from growth-diagnostic.html (ledger/lhdr/ltab/lfoot/tbl/tcell/row).

   A working document's table, not a website's table. Ruled fields, tabular
   figures, a total row that is visually settled rather than decorated. The
   legislature ruled /growth-diagnostic carries this alongside the funnel.
   --------------------------------------------------------------------------- */

.tmi-ledger__tab {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-small);
}

.tmi-ledger__tab th,
.tmi-ledger__tab td {
  text-align: left;
  padding: var(--space-3) var(--space-3);
  border-bottom: 1px solid var(--tmi-rule);
  vertical-align: top;
}

.tmi-ledger__tab thead th {
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--tmi-quiet);
  border-bottom-color: var(--tmi-ink);
}

.tmi-ledger__tab td.num,
.tmi-ledger__tab th.num { text-align: right; white-space: nowrap; }

.tmi-ledger__tab tbody tr:last-child td { border-bottom: none; }

.tmi-ledger__tab tfoot td {
  border-top: 1px solid var(--tmi-ink);
  border-bottom: none;
  font-weight: 700;
  color: var(--tmi-ink);
}

.tmi-ledger__tab .is-subject { color: var(--tmi-subject); font-weight: 700; }

@media (max-width: 640px) {
  .tmi-ledger { overflow-x: auto; }
  .tmi-ledger__tab { min-width: 32rem; }
}


/* ---------------------------------------------------------------------------
   8 · .tmi-timeline  ·  dated sequence
   Recovered from proof.html (tld/tli).

   Used where the argument is "this happened, then this, and here is what moved."
   Dates are the spine; the move is the content.
   --------------------------------------------------------------------------- */

.tmi-timeline__list {
  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--space-8);
  position: relative;
}

.tmi-timeline__list::before {
  content: "";
  position: absolute;
  left: 4px; top: 0.55em; bottom: 0.55em;
  width: 1px;
  background: var(--tmi-rule);
}

.tmi-tl {
  position: relative;
  padding-bottom: var(--space-6);
}
.tmi-tl:last-child { padding-bottom: 0; }

.tmi-tl::before {
  content: "";
  position: absolute;
  left: calc(var(--space-8) * -1);
  top: 0.5em;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--tmi-quiet);
}
.tmi-tl--now::before { background: var(--tmi-subject); }

.tmi-tl__d {
  display: block;
  font-size: var(--text-caption);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--tmi-quiet);
  margin-bottom: var(--space-1);
}

.tmi-tl__t {
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  color: var(--tmi-ink);
  margin: 0 0 var(--space-1);
}

.tmi-tl__b { font-size: var(--text-small); color: var(--tmi-quiet); margin: 0; }


/* ---------------------------------------------------------------------------
   9 · Motion
   Instruments draw themselves once on entry. The final state is already in the
   markup, so this is enhancement only: with JS off, reduced motion on, or the
   class never applied, every instrument reads complete.
   --------------------------------------------------------------------------- */

.tm-js .tmi[data-draw] .tmi-bar__fill,
.tm-js .tmi[data-draw] .tmi-track__fill {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-slow) var(--ease-instrument);
}

.tm-js .tmi[data-draw].is-drawn .tmi-bar__fill,
.tm-js .tmi[data-draw].is-drawn .tmi-track__fill {
  transform: scaleX(1);
}

/* Staggered, so a multi-row chart reads as being measured rather than switched
   on. Capped at six because past that the wait stops reading as deliberate. */
.tm-js .tmi[data-draw] .tmi-bar:nth-child(1) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 0); }
.tm-js .tmi[data-draw] .tmi-bar:nth-child(2) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 1); }
.tm-js .tmi[data-draw] .tmi-bar:nth-child(3) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 2); }
.tm-js .tmi[data-draw] .tmi-bar:nth-child(4) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 3); }
.tm-js .tmi[data-draw] .tmi-bar:nth-child(5) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 4); }
.tm-js .tmi[data-draw] .tmi-bar:nth-child(6) .tmi-bar__fill { transition-delay: calc(var(--stagger) * 5); }

@media (prefers-reduced-motion: reduce) {
  .tm-js .tmi[data-draw] .tmi-bar__fill,
  .tm-js .tmi[data-draw] .tmi-track__fill {
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   9 · .tmi-tile  ·  capability tiles with bespoke diagram glyphs
   Recovered from home.html (menu/mtile/ml), 2026-08-30.

   WHY. The Cloudflare rebuild reduced these to twelve plain text pills. Ryan's
   note, 30 Aug: "this is boring", and the wider one, that the pages read as
   calm because the sections carry no visuals. The archive had a hand-drawn SVG
   glyph per capability: a node path for strategy, an org tree for leadership,
   ascending bars for paid. Those are the visuals he has twice said already
   exist. This restores them.

   The archive hardcoded #6C6D74 / #B3B7BA / #ECEDEC, and it ran on a dark
   field. Every hex is stripped here and the glyph inherits the current token
   palette instead, so the same markup works on either stage. The one solid
   element per glyph carries .on: it is emphasis, deliberately drawn in ink and
   NOT in the accent, because the accent's job is what is measured, live or
   yours, and a capability label is none of those.
   --------------------------------------------------------------------------- */

.tmi-tiles {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.tmi-tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-4) var(--space-4) var(--space-3);
  border: 1px solid var(--tmi-rule);
  border-radius: var(--radius-tight);
  transition: border-color .35s var(--ease-instrument), transform .35s var(--ease-instrument);
}
.tmi-tile:hover { border-color: var(--tmi-quiet); transform: translateY(-3px); }

.tmi-tile svg { width: 100%; height: 58px; display: block; overflow: visible; }
.tmi-tile svg * { vector-effect: non-scaling-stroke; }
.tmi-tile svg line,
.tmi-tile svg polyline,
.tmi-tile svg path   { stroke: var(--tmi-quiet); fill: none; }
.tmi-tile svg circle,
.tmi-tile svg rect   { stroke: var(--tmi-rule); fill: none; }
.tmi-tile svg .on    { fill: var(--tmi-ink); stroke: var(--tmi-ink); }

.tmi-tile figcaption {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-small);
  letter-spacing: var(--tracking-tight);
  line-height: 1.2;
  color: var(--tmi-ink);
}

@media (prefers-reduced-motion: reduce) {
  .tmi-tile { transition: none; }
  .tmi-tile:hover { transform: none; }
}

/* ---------------------------------------------------------------------------
   10 · .tmi-cycle  ·  a closed loop of stations

   HONESTLY LABELLED AS AN INVENTION, NOT A RECOVERY. Every other instrument in
   this file was recovered from the Squarespace archive. This one is not, and
   Ryan flagged that distinction before it was built.

   I proposed building this on .tmi-track and was wrong: .tmi-track is a single
   filled readout, one number against a share-of rail, and is not a sequence
   device at all. .tmi-timeline is a dated linear sequence and .tmi-spine is a
   vertical tiered one; neither closes, and both are vertical lines with nodes,
   so a third use would have read as repetition on a page that already carries
   the spine's cousins elsewhere. The archive has no cycle. So this is new.

   WHY A CYCLE AND NOT A LIST. The section's claim is that the firm builds, runs,
   and answers for the result, and that answering feeds the next build. A list of
   three states that. A loop performs it, which is the standing rule for every
   instrument on this site.

   NO FOOTING BADGE. It diagrams how the firm works. It measures nothing, so a
   badge would imply data that does not exist. Same distinction that kept the
   badge off the /growth spine and off the /method cutaway.
   --------------------------------------------------------------------------- */

.tmi-cycle__fig { display: block; width: 100%; height: auto; overflow: visible; }
.tmi-cycle__fig .rail   { stroke: var(--tmi-rule); stroke-width: 1.5; fill: none; }
.tmi-cycle__fig .ret    { stroke: var(--tmi-quiet); stroke-width: 1.5; fill: none; stroke-dasharray: 4 4; }
.tmi-cycle__fig .stn    { fill: var(--paper); stroke: var(--tmi-quiet); stroke-width: 1.5; }
.stage-dark .tmi-cycle__fig .stn { fill: var(--ink); }
.tmi-cycle__fig .stn--on { fill: var(--tmi-subject); stroke: var(--tmi-subject); }
.tmi-cycle__fig .arw    { fill: var(--tmi-quiet); }
.tmi-cycle__fig .cap {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  fill: var(--tmi-quiet);
}
.tmi-cycle__fig .cap--ret { fill: var(--tmi-subject); }

/* The loop draws once on entry, like every other instrument. Final state is in
   the markup, so with JS off or reduced motion on it reads complete. */
.tm-js .tmi[data-draw] .tmi-cycle__fig .ret {
  stroke-dasharray: 4 4;
  stroke-dashoffset: 160;
  transition: stroke-dashoffset var(--dur-slow) linear;
}
.tm-js .tmi[data-draw].is-drawn .tmi-cycle__fig .ret { stroke-dashoffset: 0; }

@media (prefers-reduced-motion: reduce) {
  .tm-js .tmi[data-draw] .tmi-cycle__fig .ret { stroke-dashoffset: 0; transition: none; }
}
