/* ============================================================================
   THE TYPE AND LABEL RULES FOR THIS FILE (DESIGN-BOOK §15.6, §17)

   There are two label devices and only two. Sans means eyebrow, mono means
   stamp. An eyebrow is the signpost above a headline: sans 14px (13px in a
   panel), .14em, uppercase, brand blue. A stamp is every other uppercase label
   -- data, meta, indices, figure labels: mono 11px, .13em, --muted on the page
   surface, white on artwork. Nothing here may invent a third.

   The eyebrow carries NO square dot. §3 of the book specifies one, but
   `.eyebrow .d { display: none }` in site.css has retired it on every live
   page, and the live site wins. Do not reintroduce it here.

   Display type is Afical Neue at weight 500 with letter-spacing between -.01
   and -.015em (-.02em is the floor, for the h1 only). Tighter than that is off
   brand: the h1 ran -.035em and the pull-stat -.05em before this pass.

   Geometry follows §5: outer frames and figure frames are squared, buttons and
   arrow squares are 8px, surfaces nested inside a card are 10px. No other
   radius appears in this file.

   SIZES COME FROM THE LADDER, NEVER FROM A LITERAL. The --fs-* tokens now live
   in site.css :root (ported from index.html, where they were trapped) so this
   file names roles instead of numbers. --fs-read is the one documented
   deviation: a 760px reading column sets running copy larger than --fs-body,
   which is sized for marketing copy in a 440px measure.

   BLUE IS A SIGNAL, NOT A SURFACE. On the home page the brand blue only ever
   appears as an eyebrow, a tick, an index, the uplane glyph, a 2px progress
   bar, or a button. Nothing large is filled with it. This page had four big
   blue fills -- a 124x198 engine plate, two 214x60 content blocks, four phase
   chips -- which is why it read as a different brand: a page of blue slabs next
   to a page of white cards on hairlines. The only fill left is the adoption
   chart, where blue is a measured quantity.

   ONE HAIRLINE: var(--line). #E5E7EB is the site's structural hairline, used on
   the home page for card borders, list dividers and grid dividers alike. This
   file had its own --art-hair / --fig-line / --fig-line-2 ramp at 6-12% navy,
   two to four times lighter, which is why the figures read as floating text
   rather than as the home page's framed cards.
   ========================================================================= */

.article-head {
  padding: clamp(148px, 15vw, 210px) 0 clamp(48px, 7vw, 92px);
}

/* a text-link CTA (§17): 15px/500, no rule, the arrow is the affordance */
.article-head .back {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: clamp(30px, 4vw, 52px);
  color: var(--muted);
  font-size: var(--fs-cta);
  font-weight: 500;
  transition: color .25s var(--ease-micro);
}

.article-head .back:hover {
  color: var(--ink);
}

.article-head .back span {
  font-family: inherit;
  transition: transform .2s var(--ease-micro);
}

.article-head .back:hover span {
  transform: translateX(-3px);
}

/* The topic is the signpost for the whole piece, so it takes the eyebrow; the
   read time is meta, so it takes the stamp. Both were mono blue before this,
   which spent the signal colour on a duration and left the piece without a
   signpost at all. */
.article-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 22px;
}

.article-meta > span:first-child {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--blue);
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.article-meta > span + span {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  letter-spacing: .13em;
  text-transform: uppercase;
}

.article-head h1 {
  max-width: 20ch;
  margin-top: 20px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-display);
  font-weight: 500;
  letter-spacing: -.015em;
  line-height: 1.02;
}

/* a paragraph under an h1 is the lead (§17.4), so it takes --fs-lead's ramp */
.article-head .deck {
  max-width: 62ch;
  margin-top: 24px;
  color: var(--muted);
  font-size: var(--fs-lead);
  line-height: 1.55;
}

/* The hero band is a photographic artwork stage, the same treatment the
   Why Uplane page gives its .sit-figure squares: brand photography under a
   navy tint, with the product graphic floating on top. Pages pass their photo
   through --visual-img, the mechanism the listing thumbnails use for
   --thumb-img, so a card and its article share one image.

   It is a full-bleed stage in the site's sense (§6.5), which means its edges
   sit exactly ON the outer rails: `width: min(var(--frame-max), calc(100% -
   48px))`. It used to run the whole viewport width and crossed straight over
   both outer hairlines, so the one section on the page that should have proved
   the rail system was the one that broke it.

   Squared, always. The height is measured, not chosen: it is the tallest fully
   revealed card plus the same margin top and bottom as it has left and right,
   which is the rule §14.9 used to size `.hw-figure`. The card tops out at 467px
   at desktop widths, so 588px covers it with 56px above and below plus a small
   font-loading margin. Re-measure with tmp/stagefit.js after ANY change to the
   card's rows: an unreserved reveal is a page shift, not a taller card.

   EVERY branch reserves a height, including the narrow ones. §6.5 lets a stage
   go content-driven below 880px, which is right for the engine's multi-panel
   stage and wrong here: with `min-height: 0` the stage grew as the card revealed
   its rows and moved the whole page below it 226px through the timeline --
   exactly what §8 forbids. The narrow reserves are LARGER, not smaller, because
   the card's own text wraps more as it narrows: 467px at 1512, 500px at 390. */
.article-visual {
  position: relative;
  display: grid;
  place-items: center;
  width: min(var(--frame-max), calc(100% - 48px));
  min-height: 588px;
  margin: 0 auto;
  padding: clamp(24px, 5%, 56px);
  overflow: hidden;
  border: 0;
  border-radius: 0;
  background: #071859;
  color: #fff;
  isolation: isolate;
  overflow-anchor: none;
}

/* the card's own geometry on this stage lives with the card block below */

/* The tint is a wash, not a filter. It ran
   `rgba(7,16,84,.64) -> .26 -> rgba(5,12,70,.60)`, which is dense enough that
   the band artwork underneath read as flat navy: the home page's own stages
   carry no tint at all and let the photograph be a photograph (§16.3). What is
   left is the minimum that holds the mono stamp over a bright band, measured
   rather than guessed -- see tmp/artstamp.js. */
.article-visual::before {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(5, 12, 70, .20), rgba(5, 12, 70, .10) 46%, rgba(4, 10, 62, .34)),
    var(--visual-img, radial-gradient(circle at 76% 28%, rgba(35, 182, 255, .75), transparent 34%))
      center / cover no-repeat,
    linear-gradient(145deg, #0b1a79 0%, #174dff 52%, #05a8e6 100%);
  content: "";
}

/* A deeper wash, for a stage whose artwork is brighter than the others' where its
   type sits.

   This is not a taste knob. tmp/artbands.mjs crops every candidate exactly as
   this stage does and reports the brightest 5% of the three bands a hero motif
   sets type in. 19.jpg, which five-shifts uses, measures 7.2 / 17.1 / 17.5
   against white; the best remaining option measures 7.2 / 10.3 / 11.0, and at
   narrow widths `cover` crops to a brighter part of it still. So the same wash
   that is sufficient for the reference is not sufficient here, and the honest fix
   is more wash on this stage rather than dimmer type on it.

   Flat-ish rather than a ramp, for §16.3's reason: a gradient running across a
   line of type puts a different tone under each word. */
.article-visual--deep::before {
  background:
    linear-gradient(180deg, rgba(5, 12, 70, .54), rgba(5, 12, 70, .42) 46%, rgba(4, 10, 62, .56)),
    var(--visual-img, radial-gradient(circle at 76% 28%, rgba(35, 182, 255, .75), transparent 34%))
      center / cover no-repeat,
    linear-gradient(145deg, #0b1a79 0%, #174dff 52%, #05a8e6 100%);
}

@media (max-width: 880px) {
  .article-visual {
    min-height: 600px;
    padding: clamp(28px, 7vw, 44px) 20px 56px;
  }
}

@media (max-width: 560px) {
  .article-visual {
    min-height: 600px;
  }
}

@media (max-width: 440px) {
  .article-visual {
    min-height: 672px;
  }
}

/* The reading column is a three-track grid: text lives in the centre
   min(760px) track, and structural graphics (figures, pull-stats, summaries,
   sources, next) span all three tracks and bleed a further 24px so their
   rules and box edges land exactly on the inner rails instead of ending in
   the air. Text inside a bleed block pads the 24px back, so nothing moves. */
.article-body {
  /* The site's structural hairline, the same one the home page draws every card
     border, list divider and stat divider with. It was a 6% navy tint, which is
     roughly a third of this weight: at that value a figure frame disappeared and
     the summary grid read as four floating paragraphs. */
  --art-hair: var(--line);
  /* the home page's `.ck` path, at its stroke weight and caps, as a mask */
  --tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(760px, 100%) minmax(0, 1fr);
  width: 100%;
  margin: 0 auto;
  padding: clamp(64px, 8vw, 120px) 0;
}

.article-body > * {
  grid-column: 2;
  min-width: 0;
}

.article-body > .article-figure,
.article-body > .pull-stat,
.article-body > .article-summary,
.article-body > .article-sources,
.article-body > .article-next {
  grid-column: 1 / -1;
  width: auto;
  margin-inline: -24px;
}

@media (max-width: 1100px) {
  /* the rails are hidden below 1100px, so there is nothing to bleed to */
  .article-body > .article-figure,
  .article-body > .pull-stat,
  .article-body > .article-summary,
  .article-body > .article-sources,
  .article-body > .article-next {
    margin-inline: 0;
  }
}

/* Opening lede: the first paragraph speaks in the display face, the same
   move the welcome article makes, before the column settles into body copy.
   Sized on --fs-quote (§17), the ladder's role for a display paragraph; it was
   31px at -.018em, which is between two ladder rungs and tighter than the
   -.015em display floor. */
.article-body .article-lede {
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-quote);
  font-weight: 500;
  letter-spacing: -.015em;
  line-height: 1.3;
}

.article-body > .article-lede + p {
  margin-top: 24px;
}

/* Section kicker: the signpost above each h2, so it is the EYEBROW device --
   sans, 14px, .14em, brand blue (§15.6). It was mono 11px, which is the stamp,
   and the page therefore had five stamps where it wanted five eyebrows and no
   eyebrow anywhere. The index inside it stays in the eyebrow's own face, the
   way index.html's .solution-kicker sets its `01` / `02`.

   Each numbered section opens on a hairline that lands on the inner rails, so
   the sections read as the page's top-level structure and the rule belongs to
   the rail system rather than floating at an arbitrary margin (§4.2 rule 4).
   Reaching the rails is why the kicker is a BLEED BLOCK like `.pull-stat` and
   `.article-next`: it spans all three tracks, bleeds the same 24px, and re-
   declares the three-track grid so its label drops back onto the text column.
   Drawn any other way the rule cannot find the rails -- a `::before` at
   `left: -24px` inside the 760px text track measured 352px against an inner
   rail at 188px, which is aligned with nothing on the page. */
.article-body > .kicker {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(760px, 100%) minmax(0, 1fr);
  width: auto;
  margin-top: clamp(62px, 8vw, 96px);
  margin-inline: -24px;
  padding-top: clamp(30px, 3.4vw, 44px);
  border-top: 1px solid var(--art-hair);
}

/* A block that already closes on a full-width rule does not need a second one.
   `.pull-stat` and `.article-summary` both end on a hairline at the inner rails,
   so a kicker straight after them drew a parallel rule 180px below the first
   (84px of the stat's bottom margin plus 96px of the kicker's top), which is a
   void bounded by two identical lines. The preceding rule becomes the section
   boundary and the gap closes to one step. */
.article-body > .pull-stat + .kicker,
.article-body > .article-summary + .kicker {
  margin-top: clamp(34px, 4vw, 52px);
  padding-top: 0;
  border-top: 0;
}

/* the label is a real element, not a bare text node: as a text node it becomes
   an anonymous grid item and lands in the left gutter track */
.article-body .kicker .kt {
  grid-column: 2;
  color: var(--blue);
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
}

@media (max-width: 1100px) {
  /* the rails are hidden here, so there is nothing to bleed to */
  .article-body > .kicker {
    margin-inline: 0;
  }
}

/* The square dot was retired site-wide: `.eyebrow .d { display: none }` in
   site.css hides it on every other page, so the articles were the only place
   still drawing it. Kept in the markup so one rule governs it again. */
.article-body .kicker .d,
.afig-eyebrow .d {
  display: none;
}

.article-body .kicker + h2 {
  margin-top: 16px;
}

.article-body > p,
.article-body > ul,
.article-body > ol {
  color: var(--text);
  font-size: var(--fs-read);
  line-height: 1.78;
}

.article-body > p + p,
.article-body > p + ul,
.article-body > ul + p,
.article-body > ol + p {
  margin-top: 20px;
}

.article-body h2 {
  margin: clamp(62px, 8vw, 96px) 0 20px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h2);
  font-weight: 500;
  /* -.01em is the base display tracking (site.css `h1, h2, h3`). This ran
     -.025em, two and a half times tighter than any headline on the home page. */
  letter-spacing: -.01em;
  line-height: 1.02;
}

.article-body h3 {
  margin: 38px 0 12px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.06;
}

.article-body ul {
  display: grid;
  gap: 12px;
  margin-top: 20px;
  padding: 0;
  list-style: none;
}

.article-body li {
  position: relative;
  padding-left: 30px;
}

/* The brand's list mark is a BLUE TICK, not a square: index.html leads every
   USP row with `.ck`, a 24-unit path at stroke-width 2.4 with round caps, and
   the square is only ever the (retired) eyebrow dot. Drawn as a mask so the
   glyph is the same path the home page ships, at the same weight and caps,
   while staying a ::before and needing no markup. */
.article-body li::before {
  position: absolute;
  top: .38em;
  left: 0;
  width: 17px;
  height: 17px;
  background: var(--blue);
  -webkit-mask: var(--tick) center / contain no-repeat;
  mask: var(--tick) center / contain no-repeat;
  content: "";
}

/* the underline was #1436FF at 38%, a bright blue that is not in the palette */
.article-body a:not(.btn) {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: rgba(26, 68, 255, .38);
  text-underline-offset: .16em;
  transition: text-decoration-color .25s var(--ease-micro);
}

.article-body a:not(.btn):hover {
  text-decoration-color: var(--blue);
}

/* ---- A list of claims takes the home page's USP row anatomy ----
   index.html #solutions sets its three USPs as hairline-separated rows led by
   a blue tick. A list that asserts things (the three principles here) is the
   same object, so it uses the same device instead of the square bullet, which
   stays the default for ordinary lists. */
.article-body ul.checks {
  gap: 0;
  margin-top: 28px;
  border-top: 1px solid var(--art-hair);
}

.article-body ul.checks li {
  display: flex;
  align-items: center;
  gap: 13px;
  min-height: 58px;
  padding: 12px 0;
  border-bottom: 1px solid var(--art-hair);
}

.article-body ul.checks li::before {
  display: none;
}

.article-body ul.checks .ck {
  width: 17px;
  height: 17px;
  flex: none;
  color: var(--blue);
}

.article-body sup {
  margin-left: 2px;
  color: var(--blue);
  font-family: var(--mono);
  font-size: .65em;
  font-weight: 600;
}

/* The stat block: rules run rail to rail while the numeral and its sentence
   stay on the text column, so the page gains a full-width beat without the
   copy ever leaving its measure. The numeral and text sit side by side from
   720px up, which stops a two-line sentence reading as a caption. */
.pull-stat {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(760px, 100%) minmax(0, 1fr);
  margin: clamp(54px, 7vw, 84px) 0;
  padding: clamp(30px, 4vw, 48px) 0;
  border-block: 1px solid var(--art-hair);
}

.pull-stat strong,
.pull-stat span {
  grid-column: 2;
}

/* --fs-display-word (§17.1) is the ladder's role for a big stat numeral, and
   -.015em is the display floor. This was clamp(48px, 8vw, 92px) at -.05em: a
   size no other numeral on the site uses, set more than three times tighter
   than any other display line, which is why the digits touched. */
.pull-stat strong {
  display: block;
  color: var(--blue);
  font-family: var(--serif);
  font-size: var(--fs-display-word);
  font-weight: 500;
  letter-spacing: -.015em;
  line-height: 1;
}

.pull-stat span {
  display: block;
  max-width: 46ch;
  margin-top: 18px;
  color: var(--ink);
  font-size: var(--fs-lead);
  line-height: 1.5;
}

/* Side by side from 720px up. The two tracks total 760px, the same measure as
   the text column, so the pair stays centred on the reading axis while the
   rules above and below still run out to the rails. */
@media (min-width: 720px) {
  .pull-stat {
    grid-template-columns:
      minmax(0, 1fr)
      minmax(0, 240px)
      minmax(0, 520px)
      minmax(0, 1fr);
  }

  .pull-stat strong {
    grid-area: 1 / 2;
    align-self: start;
  }

  .pull-stat span {
    grid-area: 1 / 3;
    max-width: none;
    margin-top: 6px;
    align-self: start;
  }
}

/* ============================================================================
   Article figure kit
   Diagrams are built in markup, not placed as images, so they inherit the
   type ramp, respond at every width, and stay editable. They sit in the
   reading column and take the same vertical rhythm as .pull-stat.
   Geometry follows DESIGN-BOOK §5: the figure frame is squared (radius 0) and
   every surface nested inside it takes the sub-row radius, 10px. The kit used
   to mix 2 / 3 / 5 / 6 / 8px, none of which is a radius the site owns.
   ========================================================================= */
.article-figure {
  /* one hairline, the site's own: internal dividers and connector wires both
     draw at --line, the weight index.html gives every card border and every
     list divider. The old ramp was 6% and 12% navy, so a divider inside a
     figure was lighter than the text it separated and the connector wires
     antialiased to nothing. --fig-tint survives for the sibling articles. */
  --fig-line: var(--line);
  --fig-line-2: var(--line);
  --fig-tint: rgba(26, 68, 255, .07);
  /* A diagram draws itself through these, never through the page tokens
     directly, so the same markup can sit on white or on warm paper: the stage
     variant below re-points all six at the agent-log card's tones (§7.1) and
     every rule inside follows. Brand blue is deliberately NOT among them -- it
     is the one colour that is correct on both surfaces. */
  --fig-surface: var(--card);
  --fig-tile: var(--cream);
  --fig-tile-2: var(--cream-2);
  --fig-ink: var(--ink);
  --fig-text: var(--text);
  --fig-muted: var(--muted);
  width: 100%;
  margin: clamp(54px, 7vw, 84px) 0;
}

.article-figure img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--fig-line);
  background: #fff;
}

/* A figure is the same object as index.html's `#solutions .solution-card`, so
   it takes that card's anatomy exactly: white surface, 1px --line frame, radius
   0, and the one card lift the site owns (--shadow-card). Without the lift a
   white card on a white page is only a hairline, which is why these diagrams
   read as loose text while the home page's cards read as objects. */
.afig {
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--card);
  box-shadow: var(--shadow-card);
}

/* ============================================================================
   .afig--stage : a diagram presented the way the site presents every other
   graphic (DESIGN-BOOK §6.5, §7)

   why-us `#situations`, `#how` on the home page and `#implementation` at the
   foot of the enterprise page all do the same thing: a SQUARED band-art panel
   with exactly ONE warm-paper card floating on it, a mono stamp on the artwork,
   and the prose beside or beneath it. The article's figures were the only
   graphics on the site drawn on plain white with no artwork anywhere, which is
   why they read as diagrams pasted into a document rather than as the site's
   own product graphics.

   The card is `.alog`'s recipe verbatim -- #F6F4F3, radius 16px, the same two
   shadows, #2F2C2B ink, a white-glass hairline -- because § 7 says every product
   graphic on the site is one of these. What sits inside it is this page's own
   drawing, which is exactly what why-us does with `.sit-fov` inside an
   `.al-act.blk`: a page-specific block in the shared card.

   `min-height` is reserved so the artwork loading cannot shift the page (§11.5).
   ========================================================================= */
.afig--stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 520px;
  padding:
    clamp(58px, 6vw, 84px)
    clamp(24px, 3.5vw, 52px)
    clamp(30px, 4vw, 56px);
  overflow: hidden;
  border: 0;
  border-radius: 0;
  /* A top-down wash at the minimum strength that holds a white mono stamp over
     a bright band (§ 14.9 hit this on the hero; § 16.3 is why it stops at 22%
     and lets the rest of the photograph be a photograph). The fallback colour
     matches the stage while the artwork loads. */
  background:
    linear-gradient(180deg, rgba(4, 10, 62, .30) 0, rgba(4, 10, 62, 0) 22%),
    var(--fig-img, none) center / cover no-repeat,
    #0B1A5E;
  box-shadow: none;
  isolation: isolate;
  overflow-anchor: none;
}

/* The figure's signpost, on artwork: the stamp device at
   rgba(255,255,255,.72), which is § 15.6's value for a label over a photograph.
   It replaces the white `.afig-head` band -- a stage carries its label ON the
   artwork (`.stage-stamp`, `.sit-num`), it does not sit under a header bar. */
.afig--stage .afig-stamp {
  position: absolute;
  top: clamp(24px, 2.8vw, 34px);
  left: clamp(26px, 3.5vw, 40px);
  z-index: 1;
  color: rgba(255, 255, 255, .72);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  letter-spacing: .13em;
  text-transform: uppercase;
}

.afig--stage .afig-card {
  position: relative;
  width: min(94%, var(--fig-card-w, 780px));
  padding: clamp(22px, 2.4vw, 28px) clamp(22px, 2.6vw, 30px) clamp(22px, 2.4vw, 28px);
  border: 1px solid rgba(255, 255, 255, .42);
  border-radius: 16px;
  background: #F6F4F3;
  box-shadow: 0 2px 6px rgba(6, 10, 40, .08), 0 36px 90px rgba(6, 10, 40, .30);
  color: #2F2C2B;
  text-align: left;

  /* The card's tones, from `.sit .alog` and § 7.1. Two hairline weights, not
     one: --fig-line divides rows (.10-.12 is the card's own `--card-hair`), and
     --fig-line-2 draws the connector wires, which carry the argument and
     antialias away at the row weight. --fig-tile is two steps off the card, not
     one -- at #F1EEEC a tile on #F6F4F3 was invisible. */
  --fig-line: rgba(47, 44, 43, .12);
  --fig-line-2: rgba(47, 44, 43, .24);
  --fig-surface: #FCFAF9;
  --fig-tile: #EAE4E0;
  --fig-tile-2: #E4DEDA;
  --fig-ink: #2F2C2B;
  --fig-text: #2F2C2B;
  --fig-muted: rgba(47, 44, 43, .58);
  /* --fig-tint was the one token this block forgot to re-point. The white-page
     value is 7% blue, and 7% blue over #F6F4F3 warm paper resolves lilac. At 4%
     over the card's own tone the highlighted row reads as blue-tinted paper,
     and the 2px blue edge beside it does the rest of the work. */
  --fig-tint: rgba(26, 68, 255, .04);
}

/* the card head is `.al-head`: blue glyph, then the title. Nothing else. */
.afig-card-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: clamp(18px, 2vw, 24px);
}

.afig-glyph {
  width: 20px;
  height: 20px;
  flex: none;
  margin-top: 2px;
}

.afig-glyph svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: var(--blue);
}

/* `.al-title`'s exact spec: 15.5px/500 at .002em in the card ink */
.afig-card-title {
  font-family: var(--sans);
  font-size: 15.5px;
  font-weight: 500;
  letter-spacing: .002em;
  line-height: 1.4;
  color: #2F2C2B;
}

/* the card supplies the inset now */
.afig--stage .afig-body { padding: 0; }

@media (max-width: 700px) {
  .afig--stage {
    min-height: 0;
    padding: clamp(52px, 12vw, 68px) 16px clamp(22px, 5vw, 34px);
  }

  .afig--stage .afig-card { width: 100%; }
}

/* `.article-body li` and `.article-body ul` are descendant selectors written
   for prose lists, and they were reaching into the diagrams: the blue square
   bullet and its 24px inset, plus a 20px top margin, a 12px row gap and the
   1.78 prose line-height. The margin was the visible bug -- it pushed each
   figure list 20px below the connector column stretched beside it, so every
   wire left its row 4 to 16px high. Reset here (one class + one type, declared
   after the prose rules, so it wins) and let the components below re-declare
   what they need with two classes.

   Deliberately does NOT reset `gap`: a one-class component rule cannot
   out-specify `.article-body ul`, so zeroing it here would silently flatten any
   figure list that had asked for its own row gap. A component that wants a gap
   inside a figure has to say so at two classes, the way `.afig-orch
   .orch-signals` does. */
.afig li { padding-left: 0; }
.afig li::before { content: none; }

.afig ul,
.afig ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* the card inset index.html gives `.solution-copy`: it scales with the card
   instead of holding a fixed 24px against a 1136px frame */
.afig-head {
  padding: clamp(24px, 2.6vw, 34px) clamp(26px, 3vw, 38px) clamp(22px, 2.4vw, 30px);
  border-bottom: 1px solid var(--fig-line);
}

/* an in-panel signpost, so it is the eyebrow at 13px (§15.6), not a stamp */
.afig-eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--blue);
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* a card title is the display face at h3 scale (§15.6, §16.4), not a label */
.afig-title {
  margin-top: 11px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.012em;
  line-height: 1.12;
}

.afig-body { padding: clamp(26px, 3vw, 38px); }

/* The diagram card spans the rails; its caption returns to the text column.
   Both are centred on the same axis, so a 760px centred caption aligns
   exactly with the body copy above it. */
.article-figure figcaption {
  width: min(760px, 100%);
  margin: 18px auto 0;
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.55;
}

/* a figure label is a stamp: mono 11px, .13em, muted. Blue is reserved for the
   eyebrow and for the one mark in a graphic that carries the signal. */
.article-figure figcaption b {
  display: block;
  margin-bottom: 6px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

/* ---- A. orchestration: signals -> engine -> decisions ----
   Five tracks: signals, a wire column, the engine, a wire column, decisions.
   The two wire columns are grids with the same number of equal (1fr) rows as
   the list beside them, so every hairline leaves a row's exact centre and the
   trunk line leaves the column's exact middle, which is the engine's centre.
   No pixel heights are hard-coded anywhere, so a wrapping label moves the row
   and its wire together. Replaces two 26px stubs that started at a random
   pill edge and ended in empty air (DESIGN-BOOK §8: endpoints must land on
   something). The whole diagram is centred rather than stretched: at 1136px a
   stretched version left the decision column two thirds empty. */
.afig-orch {
  display: grid;
  grid-template-columns: minmax(0, 300px) 44px 152px 44px minmax(0, 320px);
  justify-content: center;
  align-items: stretch;
  gap: 0;
}

/* two classes throughout, so these beat the `.afig ul` reset above */
/* The signal list is index.html's USP row, not a stack of chips: hairline-
   separated rows on the page surface, one line icon, --fs-body in --text,
   radius 0. It was five blue-tinted rounded pills, and the site owns no tinted
   pill -- a chip on the home page is either squared and borderless
   (`.solution-chips span`) or a 999px tag inside a product graphic. A tinted
   rounded box in content is neither. */
/* The head rule is a pseudo-element, not a border: a border on a grid shrinks
   its content box by 1px, so the five rows became (h-1)/5 while the connector
   column beside it kept h/5 and every wire left its row about 0.7px high. */
.afig-orch .orch-signals {
  position: relative;
  display: grid;
  grid-template-rows: repeat(5, minmax(46px, 1fr));
  gap: 0;
}

.afig-orch .orch-signals::before {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--fig-line);
  content: "";
}

.orch-signals li {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 0 10px 0 0;
  border-bottom: 1px solid var(--fig-line);
  color: var(--fig-text);
  /* a row inside a card is 14px -- `.al-step`'s size, not --fs-body's 15px */
  font-size: 14px;
  line-height: 1.4;
}

/* The icon spec, from index.html's `.al-sub` rows: 24-unit box, no fill, round
   caps and joins, stroke 1.8, muted. Blue is reserved for the tick, the index
   and the glyph, so a row icon is never blue -- and the five rows carry five
   different icons, because the home page never repeats one mark down a list. */
.orch-signals svg {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--fig-muted);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- the wires ----
   in:  one hairline per signal row from the pill edge to the trunk, the trunk
        spanning first row centre to last row centre, then one line to the engine
   out: the mirror image
   The trunk is assembled from per-row segments so it needs no pixel offsets:
   every row draws a full-height segment plus the gap beneath it, and the first
   and last rows start/stop at their own centre. */
.orch-wire {
  position: relative;
  display: grid;
  gap: 7px;
}

.orch-wire.is-in { grid-template-rows: repeat(5, 1fr); gap: 0; }
.orch-wire.is-out { grid-template-rows: repeat(3, 1fr); gap: 0; }

.orch-wire i { position: relative; }

/* the branch: pill edge -> trunk (in), trunk -> decision (out) */
.orch-wire i::before {
  position: absolute;
  top: 50%;
  height: 1px;
  background: var(--fig-line-2);
  content: "";
}

.orch-wire.is-in i::before { left: 0; right: 50%; }
.orch-wire.is-out i::before { left: 50%; right: 0; }

/* the trunk */
.orch-wire i::after {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: var(--fig-line-2);
  content: "";
}

.orch-wire i:first-child::after { top: 50%; }
.orch-wire i:last-child::after { bottom: 50%; }

/* the trunk line into or out of the engine, on the column's own centre */
.orch-wire::after {
  position: absolute;
  top: 50%;
  height: 1px;
  background: var(--fig-line-2);
  content: "";
}

.orch-wire.is-in::after { left: 50%; right: 0; }
.orch-wire.is-out::after { left: 0; right: 50%; }

/* The engine is a CARD, not a blue plate. index.html never fills a surface
   this size with brand blue: a focal object there is a white card on a --line
   hairline carrying the card lift, and the blue arrives as the uplane glyph
   inside it -- which is precisely the agent-log card head (blue mark, ink
   title). A 124x198 solid --blue block was the largest single brand break on
   the page. Squared, because a figure's internals follow the figure. */
/* Centred, not stretched. Stretching made the card as tall as the tallest
   column (287px at desktop once the rows grew), which read as an empty
   vertical panel rather than a card. Its centre is still the grid row's centre,
   which is where both trunk lines arrive, so nothing moves. */
.orch-engine {
  position: relative;
  align-self: center;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 150px;
  padding: 20px 12px;
  border: 1px solid var(--fig-line);
  /* 10px is § 5's radius for a surface nested inside a card, and `.al-sub`'s
     value. No drop shadow: this sits ON the card, so a second lift would be
     card-on-card. On the white variant --fig-surface is still #FFFFFF. */
  border-radius: 10px;
  background: var(--fig-surface);
  color: var(--fig-ink);
  text-align: center;
}

.orch-engine svg { width: 26px; height: 26px; color: var(--blue); }

/* ---- in-figure keys are the inline bold label, not a stamp ----
   The uppercase device belongs to a signpost above a headline and to a stamp
   on data or artwork, one per block. Inside a diagram it multiplied: this
   figure alone shouted ORCHESTRATION, DECISION ENGINE, WHAT, WHEN, WHERE and
   THE ORCHESTRATION LAYER in one view, six labels competing at the same pitch
   with no hierarchy between them. The eyebrow and the caption stamp stay
   uppercase because they label the whole figure, and so do the card kickers in
   the summary grid, which are kickers above card titles. Every key *inside* a
   drawing takes the inline bold label instead (§17.2's --fs-label): sans, 500,
   sentence case, ink, white on the blue plate. It is not a third device -- the
   ink and the absence of tracking are what keep it off the eyebrow, which is
   always blue, uppercase and tracked .14em. Applies to the decision keys and to
   the two ends of the adoption scale. */
.orch-engine span {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.005em;
  line-height: 1.25;
}

/* the same object as the signal list, so the same anatomy: a pseudo-element
   head rule (a border would shrink the grid and break the wires) and one rule
   under every row */
.afig-orch .orch-out {
  position: relative;
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  gap: 0;
}

.afig-orch .orch-out::before {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--fig-line);
  content: "";
}

.orch-out li {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 12px 0 12px 16px;
}

.orch-out li { border-bottom: 1px solid var(--fig-line); }

.orch-out b {
  display: block;
  margin-bottom: 4px;
  color: var(--fig-ink);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.005em;
}

/* 14px/500 ink over 12.5px/400 muted: `.al-step` over `.al-step .mt`, the
   card's own label/meta pair. Weight and colour carry the hierarchy. */
.orch-out span {
  display: block;
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.45;
}

/* Stacked: the wires would have to turn a corner, so they go and the engine
   grows its own short stubs top and bottom, which do land on a block. */
@media (max-width: 820px) {
  .afig-orch { grid-template-columns: 1fr; gap: 18px; }
  .orch-wire { display: none; }
  .afig-orch .orch-signals { grid-template-rows: repeat(5, 46px); }
  .orch-engine { min-height: 0; flex-direction: row; gap: 12px; }
  .orch-engine::before,
  .orch-engine::after {
    position: absolute;
    left: 50%;
    width: 1px;
    height: 18px;
    background: var(--fig-line-2);
    content: "";
  }
  .orch-engine::before { bottom: 100%; }
  .orch-engine::after { top: 100%; }
  .afig-orch .orch-out { grid-template-rows: auto; }
  .orch-out li { padding-left: 0; }
}

/* ---- B. atomic components recombined into dynamic content ----
   The drawing is capped instead of fluid. At `width: 100%` in this column the
   480-unit viewBox scaled 1.85x, which turned 4px corners into 7px, 44px tiles
   into 81px, and made this figure 759px tall against 503px and 530px for the
   other two. Capped at 520px it renders near 1:1, the radii read as drawn, and
   the figure sits in the same height band as its siblings. */
.afig-atomic {
  display: grid;
  grid-template-columns: minmax(0, 280px) minmax(0, 520px);
  justify-content: center;
  gap: 56px;
  align-items: center;
}

/* On a card the two tracks no longer have 1088px to share, so the fixed pair
   overflowed and the drawing shrank to 323px while the key kept its 280px.
   The key takes what it needs and the drawing takes the rest. */
.afig--stage .afig-atomic {
  grid-template-columns: minmax(0, 224px) minmax(0, 1fr);
  justify-content: stretch;
  gap: 30px;
}

.atomic-key { display: flex; flex-direction: column; gap: 22px; }

.atomic-key h4 {
  color: var(--fig-ink);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.008em;
}

/* The legend swatch IS the shape it stands for, at 12px: a cream part tile, and
   a white built tile under its blue signal bar. It used to be a 22%-blue square
   beside a solid blue square, the only place on the site where brand blue was a
   fill at two strengths. */
.atomic-key .sw {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 9px;
  border: 1px solid var(--fig-line);
  border-radius: 0;
  background: var(--fig-tile);
  vertical-align: baseline;
}

.atomic-key .sw-b {
  background: linear-gradient(var(--blue) 0 3px, var(--fig-surface) 3px);
}

.atomic-key p {
  margin-top: 6px;
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.atomic-svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Everything here is a white tile on a --line hairline, the site's card
   anatomy at diagram scale. The two built assets were 214x60 slabs of solid
   --blue, the second-largest blue fill on the page; they are now the same white
   tile carrying a 3px blue bar, which is how the site marks a result -- the
   `.al-prog` progress bar is the same 2px of blue on a neutral track. */
/* A part is raw material, so it takes --cream, the palette's neutral light
   surface -- the same tone index.html gives a tile inside a product graphic.
   Pure white on a white card was only a hairline outline and read as an empty
   placeholder box. */
.atomic-svg .at-part {
  fill: var(--fig-tile);
  stroke: var(--fig-line);
}

.atomic-svg .at-wire {
  fill: none;
  stroke: var(--fig-line-2);
}

/* A built asset is finished, so it is the white card surface, and the ONE blue
   element in the drawing is the 3-unit signal bar across its head -- the same
   move `.al-prog` makes with 2px of blue on a neutral track. Parts read cream,
   output reads white-plus-signal, and the figure spends brand blue once. */
.atomic-svg .at-built {
  fill: var(--fig-surface);
  stroke: var(--fig-line);
}

.atomic-svg .at-cap { fill: var(--blue); }

/* the seams inside a built asset: one per component feeding it, so the block
   reads as assembled rather than as one surface */
.atomic-svg .at-seam { stroke: var(--fig-line); }

@media (max-width: 640px) {
  /* `.afig--stage .afig-atomic` above is 0-2-0 and this rule was 0-1-0, so the
     stage kept its `minmax(0,224px) minmax(0,1fr)` pair all the way down. Inside
     a ~330px card the 224px track plus the 30px gap leaves nothing for the
     drawing, and the SVG ran 443px past the card at 390px wide -- clipped, not
     scrollable, because `.afig--stage` is `overflow: hidden`. The stage variant
     has to be named here too or it never collapses. */
  .afig-atomic,
  .afig--stage .afig-atomic { grid-template-columns: 1fr; gap: 22px; }
  .atomic-svg { width: 100%; }
}

/* ---- C. four phases of adoption ---- */
/* ---- ROWS, not columns ----
   `#implementation` at the foot of the enterprise page is the reference: a
   mono index in a left gutter, a title, a body, and one hairline between steps.
   Four columns of prose forced 15px copy into ~200px tracks once the figure
   moved onto a card, and a step SEQUENCE reads down a list, not across a row --
   the columns were also the only thing on the page claiming four equal weights
   for what is a progression. */
.afig-phases {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

.phase {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  column-gap: 16px;
  padding: 12px 0;
  border-top: 1px solid var(--fig-line);
}

.phase:first-child {
  padding-top: 0;
  border-top: 0;
}

.phase:last-child { padding-bottom: 0; }

/* Four solid --blue chips in a row was the third big blue fill on the page, and
   the site has no filled chip at all. The pattern index.html uses for a column
   inside a card is a KICKER ROW plus a title: a mono index at --fs-stamp, blue
   because here the stamp IS the signal (§15.6), over an in-card title at
   --fs-card-ttl. Same anatomy as `.solution-kicker` + the card h3 beneath it,
   one step down in scale because four of them share a row. */
.phase-chip {
  display: contents;
}

/* the gutter index: mono, blue because the stamp IS the signal here (§15.6),
   10px because it is inside a card. Same slot `#implementation` puts `01` in. */
.phase-chip b {
  grid-column: 1;
  align-self: baseline;
  color: var(--blue);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.phase-chip span {
  grid-column: 2;
  display: block;
  color: var(--fig-ink);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.2;
}

/* the role sits on the title's own line, right-aligned, the way `.al-step .mt`
   carries a row's meta -- it is a classification, not a second heading */
.phase-role {
  grid-column: 2;
  margin-top: 4px;
  color: var(--fig-muted);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.35;
}

.phase p {
  grid-column: 2;
  margin-top: 7px;
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.phase p b { color: var(--fig-text); font-weight: 500; }

/* Manual effort falls as trust rises. Two right triangles sharing one
   hypotenuse, so together they tile a single rectangle: at the left edge the
   graphite wedge is the full height and the blue is nothing, at the right edge
   the reverse. Reading a fixed total means the two quantities trade against
   each other, which two crossing hairlines could not say -- they only showed
   two independent slopes and left the space between them meaningless. Each
   label sits inside its own wedge at that wedge's thick end, so no legend is
   needed, and the three white seams fall on the phase-column separators above,
   so the scale is measured by the same grid. */
.phase-scale {
  position: relative;
  margin-top: 20px;
  border-top: 1px solid var(--fig-line);
  padding-top: 20px;
}

.phase-scale svg {
  display: block;
  width: 100%;
  height: 76px;
}

/* The one place a large blue fill is right: blue is a measured quantity here,
   the same job it does in a progress bar. Its counterpart takes --cream-2, the
   palette's neutral light surface, instead of an ad-hoc navy tint. */
.phase-scale .ps-fall { fill: var(--fig-tile-2); }
.phase-scale .ps-rise { fill: var(--blue); }

.phase-scale .ps-grid line {
  stroke: #fff;
  stroke-opacity: .8;
  stroke-width: 1.5;
}

.phase-scale .ps-a,
.phase-scale .ps-b {
  position: absolute;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -.005em;
}

/* pinned inside the wedges: the graphite one is thickest top left, the blue
   one bottom right. 38px = the svg's own 26px top offset plus a 12px inset. */
.phase-scale .ps-a { top: 31px; left: 12px; color: var(--fig-ink); }
.phase-scale .ps-b { right: 12px; bottom: 11px; color: #fff; }

@media (max-width: 720px) {
  /* already one column; the quarter seams would divide nothing at this width */
  /* the row is no longer four columns, so quarter seams would divide nothing */
  .phase-scale .ps-grid { display: none; }
}

@media (max-width: 460px) {
  .phase { grid-template-columns: 24px minmax(0, 1fr); column-gap: 12px; }
}

/* Squared cells that touch each other and the rails on both sides */
/* index.html's card kicker is a ROW: the eyebrow left, its index right, both in
   the eyebrow's own face and colour (`.solution-kicker` + `.solution-kicker
   .number`). These four cells are an ordered sequence and carried no index at
   all, so the counter supplies one and the cell head becomes that row. */
.article-summary {
  --summary-rule: 1px solid var(--art-hair);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 40px 0 0;
  border-top: var(--summary-rule);
  border-left: var(--summary-rule);
  background: #fff;
  box-shadow:
    0 1px 2px rgba(10, 16, 60, .05),
    0 6px 14px rgba(10, 16, 60, .04),
    0 20px 46px rgba(10, 16, 60, .08);
  counter-reset: summary;
}

/* 170px reserved two dead lines under every cell: the longest of the four
   bodies is one line at this measure. Content-driven with an even 30px inset
   instead, so the four cells stay identical without the void. */
.article-summary > div {
  position: relative;
  padding: 30px;
  border-right: var(--summary-rule);
  border-bottom: var(--summary-rule);
  counter-increment: summary;
}

/* the index sits on the kicker's own baseline, at its right, in its face */
.article-summary > div::after {
  position: absolute;
  top: 30px;
  right: 30px;
  color: var(--blue);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: .14em;
  content: counter(summary, decimal-leading-zero);
}

/* A card kicker paired with a card title is the eyebrow at 11px -- §15.6 names
   this exact case, and index.html's .solution-kicker is the reference. Uppercase
   and .14em are what make it a kicker rather than a bold first word; without
   them a 12.5px blue sans label is a third device the site does not own. */
.article-summary b {
  display: block;
  margin-bottom: 12px;
  color: var(--blue);
  font-family: var(--sans);
  /* the eyebrow's 11px card-kicker step (§15.6). No sans 11px token exists, so
     it borrows --fs-stamp's size and keeps the eyebrow's family and tracking. */
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* the card title: display face at h3 scale (§16.4), not a fixed 21px */
.article-summary strong {
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.012em;
  line-height: 1.14;
}

.article-summary p {
  margin-top: 10px;
  color: var(--muted);
  font-size: var(--fs-body);
  line-height: 1.55;
}

/* the sentence that closes the cadence, spaced off the grid it summarises
   (was an inline `style="margin-top:28px"` on the page) */
.article-body > .article-summary + p {
  margin-top: 28px;
}

.article-sources {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(760px, 100%) minmax(0, 1fr);
  margin-top: clamp(72px, 9vw, 120px);
  padding-top: 34px;
  border-top: 1px solid var(--art-hair);
}

.article-sources > * {
  grid-column: 2;
}

/* an in-component title, so it is the stamp, muted: it inherited the h2's ink
   and read as heavy as a headline for a label that is pure apparatus */
.article-sources h2 {
  margin: 0 0 18px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

/* A numbered reference list is the site's hairline row again: index at the left
   in the mono stamp, rule under every row, --fs-meta muted copy. It was a
   browser-default `<ol>` -- proportional digits, a 22px marker gutter, 14px
   gaps and no rules -- which is the one list on the page that looked unstyled.
   `decimal-leading-zero` because every index on the site is two digits. */
.article-sources ol {
  display: grid;
  gap: 0;
  padding-left: 0;
  border-top: 1px solid var(--art-hair);
  counter-reset: fn;
  list-style: none;
}

/* Normal flow with the index in the gutter, NOT a two-track grid: a reference
   is inline content -- text, links and a back-arrow -- so as grid items each run
   of text became its own cell and every source set one word per line in a 30px
   column. */
.article-sources li {
  position: relative;
  padding: 13px 0 13px 42px;
  border-bottom: 1px solid var(--art-hair);
  counter-increment: fn;
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.55;
}

/* Every tick property has to be unset explicitly. `.article-body li::before`
   paints the blue tick as a masked 17px box at equal specificity, so overriding
   only `display` and `content` left the mask and the absolute box in place and
   each reference grew a tick beside its number. */
.article-sources li::before {
  display: block;
  position: absolute;
  top: 15px;
  left: 0;
  width: auto;
  height: auto;
  background: none;
  -webkit-mask: none;
  mask: none;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  letter-spacing: .13em;
  content: counter(fn, decimal-leading-zero);
}

/* Rules run rail to rail; the label and the arrow return to the text column,
   the arrow pinned to its right edge so it lines up with the copy above. */
.article-next {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(760px, 100%) minmax(0, 1fr);
  align-items: center;
  margin-top: 72px;
  padding: 32px 0;
  border-block: 1px solid var(--art-hair);
}

.article-next > div {
  grid-area: 1 / 2;
  justify-self: start;
  padding-right: 68px;
}

.article-next > a {
  grid-area: 1 / 2;
  justify-self: end;
}

/* a signpost above a headline is the eyebrow (§15.6) */
.article-next span {
  display: inline-block;
  color: var(--blue);
  font-family: var(--sans);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.article-next h3 {
  margin: 10px 0 0;
  font-size: var(--fs-h3);
  line-height: 1.14;
}

/* ---- a link to an article carries that article's listing image ----------
   Requested rule: whenever we link to an article, show the image it has on the
   resources overview, so the card and the link are the same object in two
   places. The thumbnails are `.article-thumb` + a `.thumb-*` motif, already
   defined below for the listing grid, so this only sizes one for a row and
   scales the motif's internal padding down with it.

   `.article-next span` is the eyebrow at descendant specificity, so the copy
   wrapper here must not be a <span> or it inherits blue uppercase. Divs. */
.article-next .an-row {
  display: flex;
  align-items: center;
  gap: 22px;
}

.article-next .an-thumb {
  flex: none;
  width: 150px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.article-next .an-copy { min-width: 0; }

/* the motifs are drawn for a ~360px card, so their padding and gaps are
   proportionally huge at 150px. Scaled, not redrawn. */
.article-next .an-thumb .thumb-system,
.article-next .an-thumb .thumb-five {
  padding: 12px;
  gap: 6px;
}

.article-next .an-thumb .thumb-five i::after { height: 2px; }

/* .thumb-loop places its four satellites with ABSOLUTE box-shadow offsets
   (+/-84px, +/-64px) and an absolute -27px spread, tuned for the ~360px listing
   card. In a 150x84 row thumb the box is 75x42 from its centre, so every
   satellite falls outside it and is clipped by overflow:hidden -- the link showed
   a bare ring, which is not the mark the listing shows. The ring is a percentage
   and already scales; the offsets and the spread are what have to come down.
   These values also clear the 190x107 thumb the mobile column uses. */
.article-next .an-thumb .thumb-loop::after {
  border-width: 1.5px;
  box-shadow:
    -46px 0 0 -22px rgba(255, 255, 255, .25),
     46px 0 0 -22px rgba(255, 255, 255, .25),
    0 -29px 0 -22px rgba(255, 255, 255, .25),
    0  29px 0 -22px rgba(255, 255, 255, .25);
}

/* Below 620px the text column is ~230px and `.article-next > div` already
   reserves 68px of it for the arrow. A thumb, a headline and the arrow cannot
   share the remaining 162px -- measured, the copy ran under the arrow. The
   image is never dropped, so the row becomes a column. */
@media (max-width: 620px) {
  .article-next .an-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }

  .article-next .an-thumb { width: min(100%, 190px); }
}

/* The one arrow-button recipe on the site: 44px, radius 8px, white on a
   hairline, hover fill, press to .94 (DESIGN-BOOK §5, and the same rule as
   #results .tstmnl-nav button on the home page). This one was a hard square. */
.article-next a {
  display: grid;
  width: 44px;
  height: 44px;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  color: #3A3A3A;
  text-decoration: none !important;
  transition:
    background .2s var(--ease-micro),
    border-color .2s var(--ease-micro),
    color .2s var(--ease-micro),
    transform .2s var(--ease-micro);
}

.article-next a:hover {
  background: #F3F3F3;
  border-color: #E5E5E5;
  color: var(--ink);
}

.article-next a:active {
  transform: scale(.94);
}

/* Five-shift editorial graphic */
/* `.article-visual` is `display: grid; place-items: center` with a reserved
   min-height, so this graphic is a centred grid ITEM: `min-height: inherit`
   resolved to the stage's own 588px inside a stage that also has 56px of
   padding, which pushed the frame 112px taller than it reserved. Stretching in
   the block axis instead makes the five vertical hairlines run the full inner
   height, which is the point of them. */
.five-shifts-graphic {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  width: min(1120px, 100%);
  align-self: stretch;
  justify-self: center;
  align-items: stretch;
}

.five-shifts-graphic article {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 32px 22px 34px;
  border-left: 1px solid rgba(255, 255, 255, .24);
}

.five-shifts-graphic article:last-child {
  border-right: 1px solid rgba(255, 255, 255, .24);
}

/* On artwork the site sets a stamp at --fs-stamp in rgba(255,255,255,.72) --
   `.stage-stamp` and `.al-*` both do. This was solid white at .14em, which made
   five indices as loud as the five titles under them. */
.five-shifts-graphic b {
  margin-bottom: auto;
  color: rgba(255, 255, 255, .72);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
}

/* A hairline that touches the text it labels (§4.2 rule 4), not a 30x3 white
   dash: the site draws no dash anywhere, and this one sat in space above the
   title. Full column width, so it lines up with the vertical rails beside it
   and the reveal draws it in from the left. */
.five-shifts-graphic i {
  width: 100%;
  height: 1px;
  margin-bottom: 20px;
  background: rgba(255, 255, 255, .34);
}

/* Two lines are reserved and the title is set to the bottom of that box, so
   the five white rules above the titles land on one line however many lines a
   title takes. Bottom-packing the column alone was not enough: "Full funnel"
   and "Hybrid teams" are one line, so their rules sat 40px lower than the
   other three. Reserving the space without the bottom alignment just moves the
   hole under the short titles instead. */
.five-shifts-graphic h2 {
  display: flex;
  align-items: flex-end;
  min-height: 2.12em;
  color: #fff;
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.06;
}

.five-shifts-graphic p {
  margin-top: 12px;
  color: rgba(255, 255, 255, .72);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

/* ============================================================================
   Welcome-to-uplane editorial graphic: the three eras, drawn as resolution

   Every article's hero motif and its listing thumbnail are the same idea at two
   scales (.thumb-five, .thumb-loop, .thumb-system). Welcome had neither: its
   headline sat inside a photograph and its listing card was a bare photo, the
   only one in the grid without a drawn mark.

   The motif states the article's own argument. Its middle section tracks three
   operating models of increasing precision -- one message for everyone, then
   targeted segments with generic creative, then individual relevance -- so the
   graphic draws precision itself: one bar, then four, then a dot field. The
   marks are the same object subdividing, which is what "increasing resolution"
   looks like, and it reads at 340px as well as at 1400px.

   Vocabulary is the reference's, deliberately, so the two heroes agree: mono
   index at --fs-stamp in rgba(255,255,255,.72), a full-column-width 1px rule at
   .34, vertical hairlines at .24, serif title on --fs-h3 bottom-aligned in a
   reserved two-line box, muted sub-line on --fs-meta.
   ========================================================================= */
.eras-graphic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: min(1120px, 100%);
  align-self: stretch;
  justify-self: center;
  align-items: stretch;
}

.eras-graphic article {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 32px 26px 34px;
  border-left: 1px solid rgba(255, 255, 255, .24);
}

.eras-graphic article:last-child {
  border-right: 1px solid rgba(255, 255, 255, .24);
}

/* Full strength, not the reference's .72.
   Measured on the real composited pixels (tmp/motifcontrast.mjs), an 11px mono
   index at .72 white reads 3.1-4.6:1 against §16.3's 5.7:1 floor, and
   tmp/artbands.mjs shows that is true of EVERY band artwork in the library --
   including 19.jpg, which the reference itself uses. The opacity is the binding
   constraint, not the photograph. At full white the same index reads 8.7:1 at
   desktop widths. Hierarchy against the 26px serif title below it comes from
   size, face and case, which is enough: the two are never confusable. */
.eras-graphic b {
  margin-bottom: auto;
  color: #fff;
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
}

/* The three marks, drawn with background-image rather than child elements, so a
   column carries no markup that exists only to be a shape. One 28px block each,
   so the three sit on one baseline and only their density differs. */
/* All three top-align in the same 25px band, so the first mark of every column
   shares one line and only the density below it changes. Centring the single bar
   instead put it 10px below the first of the four beside it, and the eye compares
   first marks, not optical centres. */
.eras-viz {
  width: 100%;
  height: 25px;
  margin: 26px 0 20px;
}

/* one message for the entire market: one mark, and nothing under it */
.eras-viz.is-one {
  background: linear-gradient(#fff, #fff) left top / 100% 3px no-repeat;
}

/* sophisticated targeting, generic creative: the same bar, subdivided */
.eras-viz.is-few {
  /* an 8px period puts FOUR marks in the 25px band. At 11px it drew three, which
     read as the same count as the three columns and muddied the step. */
  background: repeating-linear-gradient(
    180deg,
    rgba(255, 255, 255, .92) 0 3px,
    transparent 3px 8px
  ) left top / 100% 25px no-repeat;
}

/* individual relevance: the field resolves to one mark per person */
.eras-viz.is-many {
  background: radial-gradient(rgba(255, 255, 255, .92) 1.2px, transparent 1.4px)
    left top / 9px 9px;
}

.eras-graphic .rule {
  width: 100%;
  height: 1px;
  margin-bottom: 20px;
  background: rgba(255, 255, 255, .34);
}

.eras-graphic h2 {
  display: flex;
  align-items: flex-end;
  min-height: 2.12em;
  color: #fff;
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.06;
}

.eras-graphic p {
  margin-top: 12px;
  color: rgba(255, 255, 255, .92);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

/* The device §14.9 kept for a label on artwork once the scrim idea was dropped:
   the type carries its own shadow and the photograph stays a photograph. Note it
   does NOT show up in the contrast numbers -- the harness hides the text to read
   the artwork, which hides the shadow with it -- so it is a real perceptual gain
   the measurement cannot credit. */
.eras-graphic b,
.eras-graphic h2,
.eras-graphic p {
  text-shadow: 0 1px 12px rgba(3, 8, 35, .45);
}

/* ============================================================================
   Resource-card motifs at article scale

   These two stages deliberately use the same photograph, navy wash, and white
   drawing as their cards on the Resources page. The larger treatment stays as
   restrained as the thumbnail: no mock product interface, no floating card,
   no explanatory copy inside the artwork, and no animated ornament.
   ========================================================================= */
.article-visual--card-motif::before {
  background:
    linear-gradient(145deg, rgba(7, 20, 97, .58), rgba(6, 16, 80, .20) 52%, rgba(7, 20, 97, .56)),
    var(--visual-img, radial-gradient(circle at 80% 20%, rgba(35, 185, 255, .78), transparent 34%))
      center / cover no-repeat,
    linear-gradient(145deg, #071461, #1748ff 58%, #0ba9dd);
}

/* Beyond the campaign: the listing card's static loop, enlarged without the
   extra orbit, connector spokes, centre square, or travelling stroke that made
   the previous masthead feel like a loading animation. */
.campaign-mark {
  position: relative;
  width: min(76%, 470px);
  aspect-ratio: 1;
}

.campaign-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 38%;
  aspect-ratio: 1;
  border: 2px solid #fff;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.campaign-point {
  position: absolute;
  width: clamp(32px, 9.8%, 46px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(255, 255, 255, .25);
}

.campaign-point.point-north,
.campaign-point.point-south {
  left: 50%;
  transform: translateX(-50%);
}

.campaign-point.point-north { top: 21%; }
.campaign-point.point-south { bottom: 21%; }

.campaign-point.point-east,
.campaign-point.point-west {
  top: 50%;
  transform: translateY(-50%);
}

.campaign-point.point-east { right: 17%; }
.campaign-point.point-west { left: 17%; }

/* Continuous learning: the Resources card's three operating plates. Their
   equal crop and common baseline make the system feel ordered; the white,
   lifted centre plate is the single point of emphasis from the thumbnail. */
.learning-mark {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 2.2vw, 24px);
  align-items: center;
  width: min(76%, 780px);
}

.learning-mark i {
  position: relative;
  width: 100%;
  aspect-ratio: .78;
  border: 1px solid rgba(255, 255, 255, .42);
  background: rgba(255, 255, 255, .12);
}

.learning-mark i:nth-child(2) {
  border-color: #fff;
  background: #fff;
  transform: translateY(clamp(-24px, -2.2vw, -12px));
}

@media (max-width: 560px) {
  .article-visual--card-motif { min-height: 520px; }
  .campaign-mark { width: min(100%, 340px); }
  .learning-mark { width: 100%; }
}

/* ============================================================================
   HERO MOTIF FRAME, shared (DESIGN-BOOK §30, §31)

   `.five-shifts-graphic` and `.eras-graphic` each implement this frame privately.
   The two motifs added after them share ONE implementation instead, because four
   private copies of the same grid is how the label devices drifted in the first
   place. The two older ones are left alone deliberately: five-shifts is the
   approved reference and folding it in would risk its rendering for no gain.

   The frame is: columns divided by white hairlines, a mono index per column, one
   MARK, a full-column rule, a serif title bottom-aligned in a reserved two-line
   box, and a muted sub-line. Only the mark changes between articles -- that is
   what keeps four heroes recognisably one family while still letting each state
   its own argument.

     five-shifts   a plain rule            (five connected shifts)
     welcome       density: 1 bar, 4, many (three eras of precision)
     engagement    one filled square advancing along a row of empty ones
                   (the decision happens at the customer's moment)
     testing       a small bar chart with one bar solid
                   (many variants, one promoted)

   Type is at FULL strength, not .72. §30.4: no band artwork in the library clears
   §16.3's 5.7:1 for an 11px mono index at .72, including the reference's own.
   ========================================================================= */
.hm-grid {
  display: grid;
  width: min(1120px, 100%);
  align-self: stretch;
  justify-self: center;
  align-items: stretch;
}

.hm-grid.is-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }

.hm-grid > article {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 32px 22px 34px;
  border-left: 1px solid rgba(255, 255, 255, .24);
}

.hm-grid > article:last-child {
  border-right: 1px solid rgba(255, 255, 255, .24);
}

.hm-grid b {
  margin-bottom: auto;
  color: #fff;
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
}

.hm-mark {
  width: 100%;
  height: 34px;
  margin: 20px 0 18px;
}

.hm-grid .rule {
  width: 100%;
  height: 1px;
  margin-bottom: 20px;
  background: rgba(255, 255, 255, .34);
}

.hm-grid h2 {
  display: flex;
  align-items: flex-end;
  min-height: 2.12em;
  color: #fff;
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1.06;
}

.hm-grid p {
  margin-top: 12px;
  color: rgba(255, 255, 255, .92);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

/* §14.9's device for type on artwork: the glyphs carry their own shadow and the
   photograph stays a photograph. Not visible to the contrast harness, which hides
   the type to read the artwork and hides the shadow with it. */
.hm-grid b,
.hm-grid h2,
.hm-grid p {
  text-shadow: 0 1px 12px rgba(3, 8, 35, .45);
}

/* ---- mark A: one filled square advancing along a row of empty ones ----
   Beyond the campaign. Its claim is that the decision belongs to the customer's
   moment rather than to a schedule, so the mark is POSITION: six slots, one of
   them live, and the live one is somewhere different in every column. Squares
   because the square is the brand's mark; a row because the axis is time. */
.hm-slots {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 4px;
  /* bottom-aligned, so the slots sit on the same line the bars stand on */
  align-items: flex-end;
  height: 34px;
}

.hm-slots i {
  height: 7px;
  border: 1px solid rgba(255, 255, 255, .42);
}

.hm-slots i.on {
  background: #fff;
  border-color: #fff;
}

/* ---- mark B: a small bar chart with one bar solid ----
   From production to continuous learning. Its claim is that a cycle tests many
   variants and promotes one, so the mark is a MEASUREMENT: five bars at real
   heights with the winner filled. This is §15.4's chart language at motif scale,
   which is why it reads as evidence rather than as decoration. */
/* 34px tall and 9px wide, not 22px tall and a fifth of the column wide. At the
   shared mark height the "bars" were 40x8 horizontal dashes and the 38-78% spread
   resolved to 8-17px, so it read as a row of ticks rather than as a measurement.
   A chart needs the vertical axis to be the long one. */
.hm-bars {
  display: grid;
  grid-template-columns: repeat(5, 9px);
  justify-content: start;
  gap: 5px;
  align-items: flex-end;
  height: 34px;
}

.hm-bars i {
  height: var(--h, 40%);
  background: rgba(255, 255, 255, .38);
}

.hm-bars i.on {
  background: #fff;
}

@media (max-width: 900px) {
  .hm-grid.is-5 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* four and five would each be a 60px column: the title cannot set in that */
  .hm-grid.is-5 > article:nth-child(n+4) { display: none; }
}

@media (max-width: 620px) {
  .hm-grid.is-5 { grid-template-columns: 1fr; }
  .hm-grid.is-5 > article:nth-child(n+3) { display: none; }
  .hm-grid > article { border-left: 0; border-top: 1px solid rgba(255, 255, 255, .24); }
  .hm-grid > article:first-child { border-top: 0; }
  .hm-grid > article:last-child { border-right: 0; }
}

/* ============================================================================
   The agent-log card on an article stage (DESIGN-BOOK §6.5, §7)

   Replaces `.system-graphic`: three warm cards side by side, each holding a
   drawn mock of a UI -- gradient "variant" thumbnails, rounded score bars, two
   empty boxes labelled PEOPLE and AGENTS. §7 forbids exactly that ("never use
   dashboard screenshots, glassy mock UIs, or illustration"), its labels ran
   9-10px against the 10px in-card floor (§15.6), its radii were 3 / 4 / 5 / 8px,
   and three cards on one frame is not the language: a stage carries ONE card.

   The card itself comes from assets/alog.css unchanged, so there is nothing to
   restyle here. What this block does is the two things a stage owes it: keep the
   frame larger than the card, and light the card for artwork rather than for the
   white page (§7.1's light-surface note in reverse -- here the surround is dark,
   so the card keeps its full shadow and drops the hairline).
   ========================================================================= */
/* §7.1's card is `min(86%, 540px)`, which is right on the ~700px frames it was
   written for. On a 1400px full-bleed masthead 540px is 39% of the stage, where
   every other card on the site sits at 74-86% of its frame and reads as the
   subject rather than as an object dropped in a field. A masthead cannot get
   narrower, so the card gets wider: 640px is 46% at 1400px and still leaves the
   stage 62px of clearance above and below (tmp/stagefit.js). */
.article-visual .alog {
  width: min(86%, 640px);
  box-shadow:
    0 2px 6px rgba(6, 10, 40, .10),
    0 36px 90px rgba(6, 10, 40, .34);
}

/* alog.css styles `.al-logo svg` but not `.al-logo img`, and the LinkedIn mark
   is the one channel logo that ships as a file rather than an inline path. */
.article-visual .al-logo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* The card's own steps are the graphic, so the sub-row's connector line has to
   read on warm paper rather than on the page: alog.css already sets it, this
   only keeps the row from touching the card wall at the narrow end. */
@media (max-width: 560px) {
  .article-visual .alog {
    width: 100%;
    padding: 20px 18px 18px;
  }

  .article-visual .al-sub {
    margin-left: 22px;
  }

  .article-visual .al-sub::before {
    left: -15px;
  }
}

/* the stamp bottom-left of the stage, mono, on artwork (§6.5). Positioned off
   the stage's own padding so it sits on the same inset as the card. */
.article-visual .stage-stamp {
  position: absolute;
  right: auto;
  bottom: clamp(16px, 2.4vw, 26px);
  left: clamp(20px, 2.6vw, 30px);
  z-index: 3;
  /* Pure white, not the 85-88% the other stages use. Measured on the real
     composited pixels (tmp/artstamp.js) the artwork under this stamp sits at
     luma .108, its brightest at 1512px: white reads 6.65:1 there and 88% white
     reads 5.1:1, under §16.3's 5.7:1 floor. The alternative was a scrim over
     the foot of the stage, which §14.12 already tried on the hero ticker and
     reverted -- it just made the artwork look grey. */
  color: #fff;
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
}

.article-visual .stage-stamp .sep {
  /* site.css has a bare `span` rule at element specificity (§19) */
  margin: 0 8px;
  font-family: inherit;
  opacity: .5;
}

@media (max-width: 560px) {
  .article-visual .stage-stamp {
    white-space: normal;
    line-height: 1.5;
  }
}

/* Resources card thumbnails */
.article-thumb {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #1230e6;
  color: #fff;
}

/* The backdrop behind the drawn motif. Cards pass a photo through --thumb-img
   (`--thumb-img: url(...)` inline) so the thumbnails sit on the same imagery as
   the photographic cards; the flat brand gradient is the fallback. The tint on
   top is what keeps the white line-art legible wherever a photo goes bright. */
.article-thumb::before {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(145deg, rgba(7,20,97,.58), rgba(6,16,80,.20) 52%, rgba(7,20,97,.56)),
    var(--thumb-img, radial-gradient(circle at 80% 20%, rgba(35,185,255,.78), transparent 34%))
      center / cover no-repeat,
    linear-gradient(145deg, #071461, #1748ff 58%, #0ba9dd);
  content: "";
}

.thumb-five {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  padding: 18px;
}

.thumb-five i {
  position: relative;
  border-left: 1px solid rgba(255,255,255,.34);
}

.thumb-five i:last-child {
  border-right: 1px solid rgba(255,255,255,.34);
}

.thumb-five i::after {
  position: absolute;
  right: 5px;
  bottom: calc(8% + var(--n) * 3%);
  left: 5px;
  height: 3px;
  background: #fff;
  content: "";
}

/* The miniature of .eras-graphic: the same three marks at the same three
   densities, on the same hairline columns. It is the motif, not a smaller
   drawing of it -- which is what makes a card and its article read as one thing
   in the grid. Welcome's card was the only bare photograph among four drawn
   marks. */
.thumb-eras {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 18px;
}

.thumb-eras i {
  position: relative;
  border-left: 1px solid rgba(255,255,255,.34);
}

.thumb-eras i:last-child {
  border-right: 1px solid rgba(255,255,255,.34);
}

.thumb-eras i::after {
  position: absolute;
  right: 9px;
  bottom: 22%;
  left: 9px;
  height: 22px;
  content: "";
}

.thumb-eras i:nth-child(1)::after {
  background: linear-gradient(#fff, #fff) left center / 100% 3px no-repeat;
}

.thumb-eras i:nth-child(2)::after {
  background: repeating-linear-gradient(
    180deg,
    rgba(255,255,255,.92) 0 3px,
    transparent 3px 10px
  ) left top / 100% 23px no-repeat;
}

.thumb-eras i:nth-child(3)::after {
  background: radial-gradient(rgba(255,255,255,.92) 1.1px, transparent 1.3px)
    left top / 8px 8px;
}

/* The miniature of the slots motif: five hairline columns, each with one live
   slot in a different place. Replaces `.thumb-loop`, a ring with four soft
   satellites -- which read as a campaign cycle, the thing the article argues
   against, and which was the only circle in a grid of squared marks. */
.thumb-slots {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  padding: 18px;
}

.thumb-slots i {
  position: relative;
  border-left: 1px solid rgba(255,255,255,.34);
}

.thumb-slots i:last-child {
  border-right: 1px solid rgba(255,255,255,.34);
}

/* four stacked slots per column, the live one set by --on */
.thumb-slots i::after {
  position: absolute;
  right: 7px;
  bottom: 26%;
  left: 7px;
  height: 30px;
  background:
    linear-gradient(#fff, #fff) left calc(var(--on, 0) * 10px) / 100% 6px no-repeat,
    repeating-linear-gradient(180deg, rgba(255,255,255,.42) 0 1px, transparent 1px 10px)
      left top / 100% 31px no-repeat;
  content: "";
}

.thumb-loop {
  display: grid;
  place-items: center;
}

.thumb-loop::after {
  position: relative;
  width: 38%;
  aspect-ratio: 1;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow:
    -84px 0 0 -27px rgba(255,255,255,.25),
    84px 0 0 -27px rgba(255,255,255,.25),
    0 -64px 0 -27px rgba(255,255,255,.25),
    0 64px 0 -27px rgba(255,255,255,.25);
  content: "";
}

/* The miniature of the bars motif: five hairline columns, each a small chart with
   one bar solid. Replaces `.thumb-system`, three plates with the middle one white,
   which drew the three stages but nothing about testing. */
.thumb-bars {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  padding: 18px;
}

.thumb-bars i {
  position: relative;
  border-left: 1px solid rgba(255,255,255,.34);
}

.thumb-bars i:last-child {
  border-right: 1px solid rgba(255,255,255,.34);
}

/* three bars per column: the middle one is the winner, at --w of the height */
.thumb-bars i::after {
  position: absolute;
  right: 8px;
  bottom: 24%;
  left: 8px;
  height: 34px;
  background:
    linear-gradient(0deg, #fff, #fff) center bottom / 7px calc(var(--w, 3) * 8px) no-repeat,
    linear-gradient(0deg, rgba(255,255,255,.40), rgba(255,255,255,.40)) left bottom / 7px 14px no-repeat,
    linear-gradient(0deg, rgba(255,255,255,.40), rgba(255,255,255,.40)) right bottom / 7px 18px no-repeat;
  content: "";
}

.thumb-system {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  align-items: center;
  padding: 24px;
}

.thumb-system i {
  position: relative;
  aspect-ratio: .78;
  border: 1px solid rgba(255,255,255,.42);
  background: rgba(255,255,255,.12);
}

.thumb-system i:nth-child(2) {
  background: #fff;
  transform: translateY(-8px);
}

@media (max-width: 760px) {
  .article-head {
    padding-top: 126px;
  }

  /* `.article-visual { min-height: 520px }` used to live here. It sat AFTER the
     stage's own responsive reserves and so out-ordered them below 760px, which
     silently undid the reservation and let the page shift again at 390 and 360.
     The stage's heights are declared in one place, at the top of this file. */

  .article-summary {
    grid-template-columns: 1fr;
  }

  /* the centre track is already the full width here, so the label and arrow
     stay in one row; they just need less room reserved between them */
  .article-next > div {
    padding-right: 60px;
  }

  .five-shifts-graphic {
    grid-template-columns: 1fr;
    width: calc(100% - 36px);
    padding: 24px 0;
  }

  .five-shifts-graphic article {
    min-height: 0;
    padding: 18px 20px;
    border-top: 1px solid rgba(255,255,255,.2);
    border-right: 1px solid rgba(255,255,255,.24);
  }

  .five-shifts-graphic b {
    margin-bottom: 14px;
  }

  /* Stacked, there is no shared baseline to align to, so the reserved second
     line is just a hole above every one-line title. */
  .five-shifts-graphic h2 {
    min-height: 0;
  }

  .five-shifts-graphic i {
    display: none;
  }

  .five-shifts-graphic p {
    display: none;
  }

  .loop-graphic,
  .system-graphic {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    gap: 10px;
    width: calc(100% - 36px);
    padding: 26px 0;
  }

  .loop-core {
    grid-column: 1;
    grid-row: auto;
    width: 180px;
  }

  .loop-node,
  .loop-node:nth-of-type(2),
  .loop-node:nth-of-type(4) {
    max-width: none;
    justify-self: stretch;
  }

}

/* ============================================================================
   Footnote apparatus
   Superscript references link to the sources list; each source carries a
   back-link to the first citation. Digits stay mono and blue, the anchor
   itself is invisible chrome (no underline).
   ========================================================================= */
/* `.launch-article` is gone: welcome-to-uplane was the only page using it and it
   now sits on `.article-body` like the other three, so the duplicated selectors
   here went with assets/welcome-article.css. */
.article-body sup a {
  color: inherit;
  text-decoration: none;
}

.article-body sup a:hover {
  text-decoration: underline;
  text-underline-offset: .2em;
}

.article-sources .fn-back {
  margin-left: 8px;
  color: var(--blue);
  font-family: var(--mono);
  font-size: 11px;
  text-decoration: none;
}

.article-sources li:target {
  color: var(--ink);
}

/* ============================================================================
   Closing CTA band
   The approved home-page closing treatment, reused beneath each article:
   squared, spanning the outer rails, artwork under a top-down gradient with
   the ken-burns breath, testimonial + glass capture form centred inside.
   Quote styles mirror managed-growth's .cta-closing (mg.css is page-scoped,
   so the rules are duplicated here for the blog routes).

   Add `closing--quiet` to drop the photograph, the way enterprise-software and
   managed-growth already close: this band and the footer hero were two
   full-bleed blue images 24px apart, so neither one landed and the quote in
   the middle of the first lost its authority. The section keeps its footprint
   and stays transparent, so the rails run straight through it.
   ========================================================================= */
.cta-closing .cta-quote {
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--fs-quote);
  line-height: 1.4;
  letter-spacing: -.012em;
  color: #fff;
}

.cta-closing .cta-who {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 22px;
}

.cta-closing .cta-who img {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}

/* Defensive: the portrait is the one asset in this block that can go missing,
   and a 40px broken-image icon on a photographic band is worse than a disc. A
   tinted circle underneath means an absent file degrades to a neutral mark. */
.cta-closing .cta-who img {
  background: rgba(10, 16, 60, .10);
}

/* the client mark beside the attribution, behind a hairline so the name and the
   company do not read as one string. hero-magic-mind.png is black (it was cut
   for light surfaces), so it takes the site's own whitening filter -- the same
   `brightness(0) invert(1)` site.css:3848 uses on the hero ticker, per §9.4's
   "recolor to white for dark". */
.cta-closing .cta-org {
  display: flex;
  align-items: center;
  flex: none;
  padding-left: 13px;
  margin-left: 1px;
  border-left: 1px solid rgba(255, 255, 255, .28);
}

.cta-closing .cta-org img {
  width: auto;
  height: 17px;
  border-radius: 0;
  background: none;
  opacity: .88;
  /* whitened for the photographic band; re-toned for the quiet variant below */
  filter: brightness(0) invert(1);
}

/* .closing--quiet is this CTA on WHITE, not on band art -- the type is --ink
   there, so the whitening filter turned a black mark into an invisible white
   one. The mark keeps its own colour and the divider flips to the light-surface
   hairline. Per-context re-toning, the §14.12 pattern. */
.cta-closing.closing--quiet .cta-org {
  border-left-color: rgba(10, 16, 60, .16);
}

.cta-closing.closing--quiet .cta-org img {
  filter: none;
  opacity: .82;
}

.cta-closing .cta-who span {
  text-align: left;
  font-family: var(--sans);
  /* an attribution is --fs-meta (§17.2); 13.5px was a half-pixel off the rung */
  font-size: var(--fs-meta);
  line-height: 1.4;
  color: rgba(255, 255, 255, .8);
}

/* the name is the inline bold label, the role beside it is meta -- exactly the
   pair index.html sets on `#results .tstmnl-who`. It was inheriting --fs-meta
   from the span, so name and role were the same size and only weight told them
   apart. */
.cta-closing .cta-who strong {
  display: block;
  font-size: var(--fs-label);
  font-weight: 500;
  color: #fff;
}

.cta-closing .capture { margin-top: 30px; }

/* ---- the same band without the photograph ---- */
.cta-closing.closing--quiet .closing-inner {
  max-width: 760px;
}

.cta-closing.closing--quiet .cta-quote {
  color: var(--ink);
}

.cta-closing.closing--quiet .cta-who strong {
  color: var(--ink);
}

.cta-closing.closing--quiet .cta-who span {
  color: var(--muted);
}

/* the quote mark hangs in the margin so the first word keeps the centre axis,
   the detail the photographic version could hide behind its own contrast */
.cta-closing.closing--quiet .cta-quote {
  text-indent: -.42em;
}

.cta-closing .closing-kb {
  animation: kenburns 40s var(--ease-in-out-quart) infinite alternate;
}

@keyframes kenburns {
  from { transform: scale(1.05); }
  to { transform: scale(1.14) translateY(-2%); }
}

@media (prefers-reduced-motion: reduce) {
  .cta-closing .closing-kb { animation: none; }
}

/* ---- D. next-best-action: competing candidate actions, one selected ---- */
.nba-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
}

.nba-option {
  padding: 16px 14px;
  border-left: 1px solid var(--fig-line);
}

.nba-option:first-child { padding-left: 0; border-left: 0; }
.nba-option:last-child { padding-right: 0; }

.nba-option b {
  display: block;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.nba-option strong {
  display: block;
  margin-top: 8px;
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: -.008em;
  line-height: 1.3;
}

.nba-option p {
  margin-top: 7px;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.nba-option.is-chosen {
  border-left: 0;
  border-radius: 10px;
  padding: 16px;
  background: var(--blue);
}

.nba-option.is-chosen b { color: rgba(255, 255, 255, .72); }
.nba-option.is-chosen strong { color: #fff; }
.nba-option.is-chosen p { color: rgba(255, 255, 255, .78); }

.nba-option.is-chosen + .nba-option { border-left: 0; }

@media (max-width: 640px) {
  .nba-row { grid-template-columns: 1fr; gap: 14px; }
  .nba-option { padding: 0; border-left: 0; }
  .nba-option.is-chosen { padding: 16px; }
}

/* ---- E. exploration vs exploitation budget split ----
   THE SITE HAS ONE CHART DEVICE AND THIS IS IT (DESIGN-BOOK §15.4): a label on
   the left, its value on the right, and a light track underneath carrying a
   proportional fill. One shape, repeated once per row. Two colours and no
   legend -- track `rgba(10,16,60,.06)`, grey fill `rgba(10,16,60,.30)`, and
   --blue for the one bar that matters. The rows are labelled, so nothing needs
   keying.

   It replaces a single 100% bar split 28 / 72 into a tinted half and a solid
   blue half. That bar was readable but it made Exploit the loud one purely
   because it was bigger, and the figure's whole point is that the small
   protected share is what buys the learning. On one shared axis the 28% bar in
   blue against a grey 72% says that without a caption doing the work.

   The axis is the budget, so the two shares sum to exactly 100%: the fills are
   real measurements of one quantity, not a graphic device. */
.fchart {
  display: grid;
  gap: 0;
}

.fchart-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px 16px;
  padding: 18px 0;
  border-top: 1px solid var(--fig-line);
}

.fchart-row:first-child {
  border-top: 0;
  padding-top: 4px;
}

.fchart-row b {
  color: var(--ink);
  font-size: var(--fs-body);
  font-weight: 500;
  letter-spacing: -.006em;
}

/* the value is data, so it is the display face -- the same move §15.4's head
   stat makes, which is what lets the bars be read without a tick axis */
.fchart-val {
  align-self: baseline;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.01em;
  line-height: 1;
}

.fchart-track {
  grid-column: 1 / -1;
  display: block;
  height: 8px;
  margin-top: 10px;
  background: rgba(10, 16, 60, .06);
}

.fchart-track em {
  display: block;
  width: var(--v);
  /* a 229px mobile track still has to show the smaller share (§15.4) */
  min-width: 4px;
  height: 100%;
  background: rgba(10, 16, 60, .30);
}

.fchart-track em.is-signal {
  background: var(--blue);
}

/* The track spans the whole card, because the card's width IS the axis. Prose
   must not: at 1136px the figure gives its body a 1086px measure, and 13.5px
   copy set that wide is about 190 characters a line. Capped at a readable
   measure while the bar it annotates keeps the full scale. */
.fchart-row p {
  grid-column: 1 / -1;
  max-width: 74ch;
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

/* the three failure modes, as hairline rows under the chart rather than a
   bulleted list: they are readings of the same axis, not prose */
.fnotes {
  display: grid;
  gap: 0;
  margin: 24px 0 0;
  padding: 0;
  border-top: 1px solid var(--fig-line);
  list-style: none;
}

/* The index column is a fixed 108px, not `auto`. Each `li` is its own grid, so
   an `auto` track is sized per row and the three labels ("IF 0%", "IF 100%",
   "IN PRACTICE") each set their own column width -- the sentences beside them
   started at 265, 280 and 313px, three left edges where there should be one.
   108px is what the longest label needs at mono 11px / .13em. */
.fnotes li {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr);
  gap: 14px;
  align-items: baseline;
  padding: 13px 0;
  border-bottom: 1px solid var(--fig-line);
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

.fnotes li > span {
  max-width: 74ch;
}

@media (max-width: 560px) {
  /* the label takes its own line rather than squeezing the sentence to nothing */
  .fnotes li {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
  }
}

.fnotes li:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.fnotes li::before {
  display: none;
}

/* a mono index: §15.6 lists indices under the stamp device */
.fnotes b {
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.fnotes strong {
  color: var(--ink);
  font-weight: 500;
}

/* ---- F. a three-step loop, as a figure rather than a blue panel ----
   Welcome stated "Analyze. Create. Optimize." inside a 1088x520 panel filled with
   a brand-blue gradient, carrying three columns of white type. Nothing on this
   site is a blue surface that size: blue is an eyebrow, a tick, an index, a 2px
   progress bar or a button. The steps are the same three columns on the figure
   kit's white card instead, divided by its hairlines, which is how the phases
   diagram on five-shifts already draws a sequence. */
.afig-loop {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
}

.afig-loop > div {
  padding: 0 20px;
  border-left: 1px solid var(--fig-line);
}

.afig-loop > div:first-child {
  padding-left: 0;
  border-left: 0;
}

.afig-loop > div:last-child {
  padding-right: 0;
}

/* a mono index: §15.6 lists indices under the stamp device */
.afig-loop b {
  display: block;
  color: var(--muted);
  font-family: var(--mono);
  font-size: var(--fs-stamp);
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.afig-loop h4 {
  margin: 12px 0 8px;
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--fs-h3);
  font-weight: 500;
  letter-spacing: -.012em;
  line-height: 1.1;
}

.afig-loop p {
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.55;
}

@media (max-width: 700px) {
  .afig-loop {
    grid-template-columns: 1fr;
    gap: 26px;
  }

  .afig-loop > div {
    padding: 0;
    border-left: 0;
  }

  .afig-loop > div + div {
    padding-top: 26px;
    border-top: 1px solid var(--fig-line);
  }
}

/* ============================================================================
   SIX FIGURES THAT DRAW THEIR ARGUMENT (DESIGN-BOOK §32)

   `Beyond the campaign` and `Production to learning` between them carried the
   SAME component, `.afig-loop`, three times: three columns of prose behind a
   card head, once per article and twice in one of them. A figure that is a list
   is not a figure -- five-shifts is the approved reference precisely because
   each of its three carries a drawing that says something the sentence beside
   it cannot (a 5-to-1-to-3 wire schematic, an assembly diagram, a phase ladder
   under an effort/trust wedge).

   Each device below is used ONCE. That is deliberate: the moment two sections
   share a diagram, the diagram has stopped describing either of them.

   Everything draws through the --fig-* tokens (§ the .afig--stage block above),
   so all six sit on the warm card and would survive being moved to white. Brand
   blue is the single accent in each and it always marks the same thing: the
   live element, the one that changed, the one that was selected.
   ========================================================================= */

/* ---- G. two clocks on one axis --------------------------------------------
   "The campaign calendar is not the customer's clock" was three columns headed
   Detect / Interpret / Respond, which is a description of any event system and
   not of the claim in the heading. Two lanes on ONE shared axis state it
   directly: the top row is on a grid, the bottom row is not, and the section's
   own worked example -- an acquisition offer landing just after a return -- is
   the place where the two lanes touch. */
.afig-clock { display: block; }

.afig-clock svg { display: block; width: 100%; height: auto; }

.clk-lane-label {
  fill: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.clk-axis { stroke: var(--fig-line-2); }
.clk-tick { stroke: var(--fig-line); }

/* a scheduled send is planned material, so it takes the part tile -- the same
   cream-on-hairline the atomic diagram gives an unbuilt component. --fig-tile-2
   rather than --fig-tile: one step off the card was not enough separation for a
   12px mark standing beside an 8px solid-blue one. */
.clk-plan { fill: var(--fig-tile-2); stroke: var(--fig-line-2); }

/* a customer event is the live thing on the page, so it is the blue */
.clk-event { fill: var(--blue); }

/* the ring marks the one event the annotation names */
.clk-ring { fill: none; stroke: var(--blue); stroke-opacity: .42; }

/* the collision: a hairline dropped between the two lanes, dashed so it reads
   as an annotation rather than as a third data series */
.clk-hit {
  fill: none;
  stroke: var(--fig-line-2);
  stroke-dasharray: 2 3;
}

.clk-note {
  fill: var(--fig-ink);
  font-family: var(--sans);
  font-size: 11.5px;
}

.clk-note.is-muted { fill: var(--fig-muted); }

.afig-clock figcaption,
.clk-key {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--fig-line);
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.clk-key span { display: flex; align-items: baseline; gap: 8px; }

.clk-key i {
  flex: none;
  width: 10px;
  height: 10px;
  border: 1px solid var(--fig-line-2);
  background: var(--fig-tile-2);
  transform: translateY(1px);
}

.clk-key i.is-event {
  border-color: var(--blue);
  background: var(--blue);
}

/* The site had no visually-hidden utility, and the matrix below needs one: its
   pass/fail column is a glyph, which carries nothing to a screen reader, and a
   <table> wants a caption that the layout has no room to show. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  font-size: var(--fs-meta);
  white-space: nowrap;
  border: 0;
}

/* ---- H. the decision layer as a matrix, not four cards --------------------
   `.nba-row` put four candidate actions side by side and coloured the winner.
   It was true but it asserted the outcome: nothing showed WHY three lost. The
   same four actions against the three tests the section names (consent,
   contact pressure, signal support) turn the figure into the readout of a
   decision rather than a picture of one. */
.afig-matrix { display: block; }

/* The selected row carries a 2px blue edge, so it needs 12px of lead-in before
   its text. Indenting only that row left a ragged first column, so every row
   takes the indent and the table is pulled back into the card's own padding by
   the same amount -- one left edge, and the blue mark sits outside it. */
.amx {
  width: calc(100% + 12px);
  margin-left: -12px;
  border-collapse: collapse;
  text-align: left;
}

.amx th:first-child,
.amx td:first-child { padding-left: 12px; }

.amx th {
  padding: 0 12px 10px 0;
  border-bottom: 1px solid var(--fig-line-2);
  color: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
  vertical-align: bottom;
}

/* the three test columns are equal and narrow; the action and the result carry
   the words, so they take what is left */
.amx th.amx-test,
.amx td.amx-test {
  width: 74px;
  padding-right: 0;
  text-align: center;
}

.amx th.amx-result,
.amx td.amx-result { width: 30%; padding-right: 0; }

.amx td {
  padding: 13px 12px 13px 0;
  border-bottom: 1px solid var(--fig-line);
  color: var(--fig-text);
  font-size: var(--fs-meta);
  line-height: 1.45;
  vertical-align: top;
}

.amx tr:last-child td { border-bottom: 0; }

.amx td.amx-action { font-weight: 500; }

/* pass is the blue tick the site already uses for a satisfied claim (`.checks
   .ck` on the home page); fail and not-applicable are hairline marks, so the
   column reads as one blue run down the selected row */
.amx .mk {
  display: inline-block;
  width: 13px;
  height: 13px;
  vertical-align: -2px;
}

.amx .mk svg { display: block; width: 100%; height: 100%; }
.amx .mk.is-pass { color: var(--blue); }
.amx .mk.is-fail,
.amx .mk.is-na { color: var(--fig-muted); }

.amx .amx-result span {
  display: block;
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.4;
}

.amx .amx-result b {
  color: var(--fig-ink);
  font-size: var(--fs-meta);
  font-weight: 500;
}

/* the selected row is the one blue surface in the figure, at the tint strength
   the kit already reserves for a highlighted row rather than a solid fill --
   `.nba-option.is-chosen` was a solid --blue block, the largest blue area in
   either article */
.amx tr.is-chosen td {
  background: var(--fig-tint, rgba(26, 68, 255, .07));
  border-bottom-color: var(--fig-line-2);
}

.amx tr.is-chosen td:first-child {
  box-shadow: inset 2px 0 0 var(--blue);
}

.amx tr.is-chosen .amx-result b { color: var(--blue); }

@media (max-width: 700px) {
  /* the matrix stops being a matrix and becomes one block per action, with the
     three tests as an inline run -- a 5-column table at 320px is unreadable */
  .amx, .amx tbody, .amx tr, .amx td { display: block; width: auto; }
  .amx thead { display: none; }

  .amx tr {
    padding: 14px 0;
    border-bottom: 1px solid var(--fig-line);
  }

  .amx tr:last-child { border-bottom: 0; }
  .amx td { padding: 0; border-bottom: 0; }
  .amx td + td { margin-top: 6px; }

  .amx td.amx-test {
    display: inline-block;
    width: auto;
    margin-right: 18px;
    text-align: left;
  }

  .amx td.amx-test::before {
    content: attr(data-test) " ";
    color: var(--fig-muted);
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: .13em;
    text-transform: uppercase;
  }

  .amx tr.is-chosen td:first-child { padding-left: 10px; }
  .amx tr.is-chosen td { background: none; }
  .amx tr.is-chosen { box-shadow: inset 2px 0 0 var(--blue); padding-left: 10px; }
}

/* ---- I. a persona beside a decision context -------------------------------
   The section's title is "segments of one are decision contexts, NOT personas",
   and the figure under it was three columns headed Evidence / Boundaries /
   Assembly -- the same component the same article had already used two figures
   earlier. A contrast in the heading wants a contrast in the drawing: one
   sealed block that was written once, beside one assembled from five live
   feeds and thrown away after a single decision. */
.afig-versus {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 30px;
}

.vs-col > b {
  display: block;
  margin-bottom: 4px;
  color: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.vs-col > h4 {
  margin-bottom: 14px;
  color: var(--fig-ink);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -.008em;
}

.vs-stack {
  margin: 0;
  padding: 0;
  border: 1px solid var(--fig-line-2);
  list-style: none;
}

.vs-stack li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-top: 1px solid var(--fig-line);
  color: var(--fig-text);
  font-size: 12.5px;
  line-height: 1.35;
}

.vs-stack li:first-child { border-top: 0; }

/* the persona's rows are one surface: it is a single record, so nothing inside
   it is separately sourced */
.vs-static .vs-stack { background: var(--fig-tile); }

/* every row of a decision context arrives from somewhere, and the source is
   named beside it -- the 2px blue edge is the same mark `.al-prog` uses for a
   live feed, spent once per row rather than as a fill */
.vs-live .vs-stack li { box-shadow: inset 2px 0 0 var(--blue); }

.vs-stack em {
  flex: none;
  color: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  font-style: normal;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.vs-col > p {
  margin-top: 12px;
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.vs-col > p strong { color: var(--fig-ink); font-weight: 500; }

@media (max-width: 640px) {
  .afig-versus { grid-template-columns: 1fr; gap: 26px; }
}

/* ---- J. control beside variant, one row different -------------------------
   "A testable brief defines one question, one controlled variable, one decision
   rule" was that sentence split across three columns, which restates it rather
   than showing it. Two builds of the same asset with four rows held identical
   and ONE row different is the definition, drawn: the controlled variable is
   the only place the two columns disagree, and it is the only blue on the
   card. */
.afig-control { display: block; }

.ctl-grid {
  display: grid;
  grid-template-columns: minmax(0, 132px) minmax(0, 1fr) minmax(0, 1fr);
  gap: 0;
  align-items: stretch;
}

.ctl-grid > * { padding: 10px 14px; border-bottom: 1px solid var(--fig-line); }

.ctl-head {
  padding-bottom: 9px;
  border-bottom: 1px solid var(--fig-line-2);
  color: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.ctl-row-label {
  padding-left: 0;
  color: var(--fig-muted);
  font-size: 12.5px;
}

.ctl-cell {
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.4;
}

/* a held-fixed cell says so once, in the muted voice, so the eye skips four
   rows and lands on the fifth */
.ctl-cell.is-held { background: var(--fig-tile); }

.ctl-cell.is-var {
  color: var(--fig-ink);
  font-weight: 500;
  box-shadow: inset 0 -2px 0 var(--blue);
}

/* the label of the varying row is promoted out of the muted voice too, so the
   row reads as one object across all three columns */
.ctl-row-label.is-var {
  color: var(--fig-ink);
  font-weight: 500;
}

.ctl-grid > :nth-last-child(-n + 3) { border-bottom: 0; }

/* the question and the decision rule are the two things a brief must state, so
   they sit under the build as named rows rather than as prose */
.ctl-out {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 14px;
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--fig-line-2);
  color: var(--fig-text);
  font-size: 12.5px;
  line-height: 1.5;
}

.ctl-out + .ctl-out { margin-top: 10px; padding-top: 10px; border-top: 0; }

.ctl-out b {
  color: var(--fig-muted);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
}

@media (max-width: 640px) {
  .ctl-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .ctl-row-label { grid-column: 1 / -1; padding: 12px 0 2px; border-bottom: 0; }
  .ctl-grid > .ctl-head:first-child { display: none; }
  .ctl-out { grid-template-columns: 1fr; gap: 4px; }
}

/* ---- K. variants circulating between two budgets --------------------------
   THE FIGURE THIS REPLACES WAS THE ONE ACTUAL DEFECT. `.fchart` is the site's
   chart device and its contract, written into section E above, is that "the
   fills are real measurements of one quantity". The markup here set BOTH rows
   to `--v:100%` and labelled them "Protected" and "Remainder": two full-width
   bars, no number, no axis, nothing measured. It had the form of a chart and
   the content of a caption.

   There is no split to plot -- the section's own point is that the allocation
   is "a governed decision, not a fixed percentage" -- so plotting one would
   have meant inventing it. What IS true and drawable is the movement: a
   challenger crosses into exploit when evidence clears the threshold, a
   decaying winner crosses back. The two lanes and the two crossings are the
   mechanism the section describes, with no quantity claimed. */
.afig-flow { display: block; }

.afig-flow svg { display: block; width: 100%; height: auto; }

/* the exploit lane is a filled band because that budget is committed; the
   explore lane is a dashed outline because it is reserved rather than spent --
   the dash is the "protected" in its label */
.flw-lane { fill: var(--fig-tile); }

.flw-lane.is-explore {
  fill: none;
  stroke: var(--fig-muted);
  stroke-opacity: .5;
  stroke-dasharray: 4 4;
}

.flw-label {
  fill: var(--fig-ink);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
}

.flw-sub {
  fill: var(--fig-muted);
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* an untested variant is a part (cream on a hairline); a promoted one is a
   finished asset, so it takes the built tile plus the single blue cap -- the
   same two states the atomic diagram already defines, reused here because it is
   literally the same object at two stages of its life */
.flw-part { fill: var(--fig-tile); stroke: var(--fig-line-2); }
.flw-built { fill: var(--fig-surface); stroke: var(--fig-line); }
.flw-cap { fill: var(--blue); }

.flw-arrow { fill: none; stroke: var(--blue); stroke-width: 1.25; }
.flw-arrow.is-back { stroke: var(--fig-line-2); }
.flw-head { fill: var(--blue); }
.flw-head.is-back { fill: var(--fig-line-2); }

.flw-move {
  fill: var(--fig-text);
  font-family: var(--sans);
  font-size: 11px;
}

/* ---- L. who hands what to whom --------------------------------------------
   The hybrid-workflow figure used `.afig-phases`, which is five-shifts'
   adoption ladder -- the same four-row component, in an article that links to
   five-shifts two screens later. It also dropped `.phase-scale`, the wedge that
   is the only drawn thing in the original, so what remained was the list with
   the graphic taken out.

   The section's own claim is that "the system makes every handoff visible,
   reviewable, and reversible", so the handoffs are the subject: two lanes, and
   a marked node every time work crosses between them. */
.afig-lanes { display: block; }

.afig-lanes svg { display: block; width: 100%; height: auto; }

.lns-lane { stroke: var(--fig-line); }

.lns-tag {
  fill: var(--fig-muted);
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: .13em;
  text-transform: uppercase;
}

/* a human step is an outline, an agent step is a filled tile: the lane a node
   sits in already says who owns it, so the fill carries the second fact --
   whether a person is in the loop at that step */
.lns-human { fill: var(--fig-surface); stroke: var(--blue); }
.lns-agent { fill: var(--fig-tile); stroke: var(--fig-line-2); }

.lns-node-t {
  fill: var(--fig-ink);
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
}

.lns-wire { fill: none; stroke: var(--fig-line-2); }

/* a handoff is the one thing this figure is about, so a crossing wire is blue
   and carries the review dot; a wire that stays inside a lane is a hairline */
.lns-wire.is-cross { stroke: var(--blue); }
.lns-dot { fill: var(--fig-surface); stroke: var(--blue); }

/* the key sits under the drawing on the same hairline the clock figure's key
   uses, and its bullet IS the review dot at text scale */
.lns-key {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--fig-line);
  color: var(--fig-muted);
  font-size: 12.5px;
  line-height: 1.5;
}

.lns-key > span {
  flex: none;
  width: 9px;
  height: 9px;
  border: 1.5px solid var(--blue);
  border-radius: 50%;
  background: var(--fig-surface);
  transform: translateY(1px);
}

@media (prefers-reduced-motion: no-preference) {
  /* the fill draws from its own left edge, the one motion this figure has */
  .article-figure.in .fchart-track em {
    animation: article-line 1.5s var(--ease-out-quint) both;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .five-shifts-graphic i {
    animation: article-line 2.8s var(--ease-out-quint) both;
  }

  /* `.score-bars i::after` and `.variant-stack i:nth-child(2)` were the other
     two animations here. Both belonged to `.system-graphic`, which is gone: the
     hero stage now carries one agent-log card and the card sequencer owns its
     motion (§7.2). `article-winner` went with them -- nothing else used it. */
  @keyframes article-line {
    from { transform: scaleX(0); transform-origin: left; }
    to { transform: scaleX(1); transform-origin: left; }
  }
}
