/* ==========================================================================
   The visualization kit.

   Two rules govern everything here.

   1. Colour carries one meaning and only one: grey is "before", teal is
      "after". There is no categorical ramp, because the library is almost
      entirely before-and-after pairs and a rainbow would invent distinctions
      the data does not have.

   2. Nothing is legible by colour alone. Every after-value is also labelled
      in text, and every figure is preceded by a results table or a caption
      carrying the same numbers -- so the charts are decoration on top of a
      readable document rather than the document itself.

   Data-driven dimensions live in SVG geometry attributes, never here and
   never in an inline style. See pages/templatetags/viz.py.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Figure frame
   -------------------------------------------------------------------------- */

.fig {
  background: var(--card);
  border: 1px solid var(--rule);
  padding: clamp(14px, 1.6vw, 22px);
}
.fig--flat { background: transparent; border: 0; padding: 0; }
.fig--paper { background: var(--paper-2); }

/* A framed figure holding a lone capped chart shrinks to it, rather than
   leaving most of a full-width box empty -- which read as something that had
   failed to load.

   The gauge is the exception. It sits directly under the results table it
   illustrates, and a narrow box under a full-width table reads as two
   unrelated blocks. It keeps the table's width and centres its contents
   instead, so the pair line up as one figure with its own caption. */
.fig:has(> .chart--m):not(:has(> .gg)) { width: fit-content; max-width: 100%; }
.fig:has(> .gg) > .gg { justify-content: center; }

.fig__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  margin-block-end: 14px;
}
.fig__ttl {
  font-size: 13.5px;
  font-weight: 650;
  letter-spacing: -.012em;
  line-height: 1.35;
  color: var(--charcoal);
}
.fig__cap {
  font-size: 12px;
  color: var(--gray);
  line-height: 1.5;
  margin-block-start: 12px;
  max-width: 64ch;
}
.fig__cap b { color: var(--ink-soft); font-weight: 600; }
html[lang="ar"] .fig__ttl { letter-spacing: 0; }

/* A figure whose numbers have not been independently verified says so once,
   quietly, rather than being presented as audited. */
.fig__src {
  font-size: 11px;
  color: var(--gray);
  margin-block-start: 10px;
  letter-spacing: .01em;
}

/* --------------------------------------------------------------------------
   The results table. THE repeated motif: navy header, grey before, teal
   after. It appears on the site, the proposal PDF, the case-study PDF and
   the deck, identically. That repetition is what makes a small practice read
   as an institution.
   -------------------------------------------------------------------------- */

.rt { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.rt caption {
  text-align: start;
  margin-block-start: 22px;
  font-size: var(--label);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gray);
  padding-block-end: 10px;
}
html[lang="ar"] .rt caption { letter-spacing: .04em; text-transform: none; }
.rt thead th {
  background: var(--navy);
  color: #fff;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-align: start;
  padding: 9px 12px;
  white-space: nowrap;
}
html[lang="ar"] .rt thead th { letter-spacing: .03em; text-transform: none; }
.rt tbody th {
  font-weight: 500;
  text-align: start;
  padding: 11px 12px;
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink-soft);
  line-height: 1.4;
}
.rt tbody td {
  padding: 11px 12px;
  border-bottom: 1px solid var(--rule-soft);
  /* Was nowrap. Most after-values are short, but a few are a sentence --
     "96% clean digital forms / 84% poor scans" -- and nowrap pushed those
     past the table's edge, so reading the row meant scrolling sideways. The
     figures still line up because tabular-nums holds the digits to one
     width; only the prose ones wrap. */
  overflow-wrap: break-word;
  font-variant-numeric: tabular-nums;
}
/* Before values are always short -- a figure, or one of two fixed phrases --
   so they keep nowrap. Only the after column ever carries a sentence, and it
   is the only one that needed to start wrapping. */
.rt .before { color: var(--gray); white-space: nowrap; }
.rt .after { color: var(--teal); font-weight: 650; }

/* The numeric columns align with their own headings. `.rt` is rendered
   inside `.results` on some pages, which right-aligns any `th` past the
   first -- so the two head cells moved and the body cells did not, and the
   table read as if the columns had slipped. Stated here, on the component
   itself, so it holds wherever the component is placed. */
.rt :is(thead th, tbody td):nth-child(n + 2) { text-align: end; }
.rt thead th:first-child, .rt tbody th { text-align: start; }
/* A prose column, not a figure column: it reads from the start and wraps. */
.rt .ev { text-align: start; white-space: normal; }
.rt tbody tr:last-child :is(th, td) { border-bottom: 0; }
/* The movement marker and the note that resolves it. The marker is a link to
   an explanation, not an abbreviation to expand, so it keeps the pointer
   affordance and drops the dotted underline browsers add. */
.rt__fn {
  color: var(--gray);
  text-decoration: none;
  border: 0;
  cursor: help;
  font-size: 13px;
}
.rt__note {
  font-size: 11.5px;
  color: var(--gray);
  line-height: 1.5;
  margin-block-start: 10px;
  max-width: 72ch;
}
.rt--tight tbody :is(th, td) { padding-block: 8px; }

/* --------------------------------------------------------------------------
   Stat tiles: the results table compressed to a single figure
   -------------------------------------------------------------------------- */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.tile { background: var(--card); padding: 16px 18px 18px; }
.tile__lbl {
  font-size: 11px;
  color: var(--gray);
  line-height: 1.45;
  min-height: 2.9em;
}
.tile__val {
  font-size: clamp(21px, 2.3vw, 29px);
  font-weight: 650;
  letter-spacing: -.032em;
  color: var(--teal);
  margin-block-start: 10px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tile__from {
  font-size: 11.5px;
  color: var(--gray);
  margin-block-start: 7px;
  font-variant-numeric: tabular-nums;
}
html[lang="ar"] .tile__val { letter-spacing: 0; }

/* --------------------------------------------------------------------------
   Charts
   -------------------------------------------------------------------------- */

/* overflow: hidden clips at the viewBox, which is the guarantee that a
   label cannot push the page sideways at phone width. Everything is drawn
   inside the box; this is the backstop, not the layout. */
.chart { display: block; width: 100%; height: auto; overflow: hidden; }

/* A metric figure is not a hero image, and an SVG scales its own typography
   along with its box. Uncapped, a 320-unit viewBox in a 930px content column
   ran at 2.9x -- an 11px label set at 32px, a 17px figure at 49px -- and the
   116-unit gauge rendered 930px across as a circle with a number in it. Each
   small figure is capped near the size its type was drawn for: 420/320 is
   1.3x, 168/116 is 1.4x. The diagrams on the same page are deliberately not
   capped; they are drawn at page scale and their labels are HTML. */
.chart--m { max-width: 420px; }
.chart--gauge { max-width: 168px; }

/* Split-by-input-quality bars. Labels are HTML for the reason recorded on
   the partial: SVG text cannot wrap, and these labels are long in English
   and longer in Arabic. Same grid shape as .fn so the two read as one
   family. */
.sg { margin-block-start: 4px; }
.sg__row {
  display: grid;
  grid-template-columns: minmax(0, 10fr) minmax(70px, 11fr) 3.4em;
  align-items: center;
  gap: 12px;
  padding-block: 6px;
}
.sg__lb {
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--gray);
  font-weight: 600;
  line-height: 1.35;
}
html[lang="ar"] .sg__lb { letter-spacing: 0; text-transform: none; font-size: 12.5px; }
.sg__track { display: block; min-width: 0; }
.sg__bar {
  display: block;
  width: 100%;
  height: 14px;
  background: var(--paper-2);
  border: 1px solid var(--rule-soft);
}
.sg__v {
  font-size: 15px;
  font-weight: 650;
  color: var(--teal);
  text-align: end;
  font-variant-numeric: tabular-nums;
}
.sg__v--mute { color: var(--gray); font-weight: 500; }

/* Gauge plus its key. The key is what turns the arc into a chart: a share
   read against nothing is just a number in a circle. */
.gg {
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 30px);
  flex-wrap: wrap;
}
.gg__key { min-width: 0; max-width: 38ch; }
.gg__v {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-size: 19px;
  font-weight: 650;
  color: var(--charcoal);
  font-variant-numeric: tabular-nums;
}
.gg__l {
  margin-block-start: 4px;
  padding-inline-start: 21px;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.45;
}
.gg__of {
  margin-block-start: 10px;
  padding-inline-start: 21px;
  font-size: 11.5px;
  color: var(--gray);
  line-height: 1.45;
}
.gg__sw {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 2px;
  transform: translateY(1px);
}
.gg__sw--on { background: var(--teal); }
.gg__sw--off { background: var(--before); }

/* Weighted dimensions. One grid, three columns: the name, the default
   weight, the weight adjusted for this region. HTML labels, SVG bars -- see
   the note on the partial for what the all-SVG version did to its own
   headings. */
.wb { margin-block-start: 4px; }
.wb__hd, .wb__row {
  display: grid;
  /* A floor on the name column. minmax(0, ...) let it shrink under its own
     content at tablet width, which is how the label ended up painted across
     the bar beside it. */
  grid-template-columns: minmax(158px, 1.6fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px 16px;
  align-items: center;
}
.wb__hd {
  font-size: 9.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gray);
  font-weight: 600;
  line-height: 1.3;
  padding-block-end: 8px;
  border-bottom: 1px solid var(--rule-soft);
}
html[lang="ar"] .wb__hd { letter-spacing: 0; text-transform: none; font-size: 11.5px; }
.wb__row { padding-block: 8px; }
.wb__row + .wb__row { border-top: 1px solid var(--rule-soft); }
/* overflow-wrap is load-bearing at tablet width. "Research/Benchmarking
   Capability" has no space to break at until its twenty-second character, so
   without this it overflowed its own track and painted over the bar, the
   value and the next cell. */
.wb__n {
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.4;
  /* break-word, not anywhere: `anywhere` breaks greedily and split
     "Research/Benchmarking" into "Benchmarkin / g" even where the whole word
     would have fitted on the next line. This breaks only when a word truly
     cannot fit, which with the column floor below is almost never. */
  overflow-wrap: break-word;
}
.wb__cell { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* The figure sizes to its container, never past it. It was overflowing by
   6px at 1440 and clipping the per-cent sign off every adjusted value. */
.wb { max-width: 100%; overflow: hidden; }
.wb__bar {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  height: 13px;
  /* The track is the element's own background and border, not a rect: this
     SVG is drawn with preserveAspectRatio="none", so a stroked rect inside
     it would stretch to an uneven outline. */
  background: var(--paper-2);
  border: 1px solid var(--rule-soft);
}
.wb__v { flex: none; min-width: max-content; font-size: 12px; font-variant-numeric: tabular-nums; }
.wb__v--b { color: var(--gray); font-weight: 500; }
.wb__v--a { color: var(--teal); font-weight: 650; }
.wb__v--m { color: var(--gray); font-weight: 400; }

@media (max-width: 880px) {
  /* The two weight columns stack under the name rather than squeezing to
     nothing, which is what the old figure did in Arabic. 880px, not 620px:
     the name column needs its 150px floor plus two 84px cells plus gaps, and
     the figure sits inside a padded card inside a padded shell. */
  .wb__hd { display: none; }
  .wb__row { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .wb__cell::before {
    content: attr(data-l);
    font-size: 9.5px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--gray);
    font-weight: 600;
    flex: none;
  }
}

.c-before { fill: var(--before); }
.c-after { fill: var(--teal); }
/* The empty part of a bar's track. It is #F1EFEA and most figures sit on a
   white card, which is 1.09:1 -- so on /frameworks/, where five of six
   adjusted weights are unchanged and therefore drawn as track, five rows
   read as empty beside labels saying 20%, 15%, 10%. The outline is what
   makes a track visible as a track rather than as a missing value. */
.c-track { fill: var(--paper-2); stroke: var(--rule); stroke-width: .75; }
.c-rule { stroke: var(--rule); stroke-width: 1; }
.c-axis { stroke: var(--rule); stroke-width: 1; }
/* A reference value the bar is read against, not a gridline. */
.c-ref { stroke: var(--navy); stroke-width: 1; stroke-dasharray: 3 2.5; opacity: .55; }
.c-navy { fill: var(--navy); }
.c-line-before { stroke: var(--before); stroke-width: 2; fill: none; }
.c-line-after { stroke: var(--teal); stroke-width: 2; fill: none; }

.c-t {
  font-family: var(--font-sans);
  font-size: 11px;
  fill: var(--ink-soft);
}
html[lang="ar"] .c-t { font-family: var(--font-arabic); }
.c-t--mute { fill: var(--gray); }
.c-t--after { fill: var(--teal); font-weight: 650; }
.c-t--before { fill: var(--gray); }
.c-t--big { font-size: 17px; font-weight: 650; letter-spacing: -.02em; }
.c-t--lbl {
  font-size: 9.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  fill: var(--gray);
  font-weight: 600;
}
html[lang="ar"] .c-t--lbl { letter-spacing: .02em; text-transform: none; }
.c-t--inv { fill: #fff; }

/* Slope: a grey dot and a teal dot on one axis, joined. The clearest way to
   show two comparable percentages without implying a trend between them. */
.c-slope-line { stroke: var(--rule); stroke-width: 1.5; }
.c-dot-before { fill: var(--before); stroke: var(--paper); stroke-width: 2; }
.c-dot-after { fill: var(--teal); stroke: var(--paper); stroke-width: 2; }

/* Radar */
.c-radar-fill { fill: var(--teal); fill-opacity: .13; stroke: var(--teal); stroke-width: 1.75; }
.c-radar-grid { fill: none; stroke: var(--rule); stroke-width: 1; }
.c-radar-spoke { stroke: var(--rule-soft); stroke-width: 1; }
.c-radar-dot { fill: var(--teal); }

/* Gauge */
.c-gauge-track { fill: none; stroke: var(--paper-2); }
.c-gauge-arc { fill: none; stroke: var(--teal); stroke-linecap: butt; }

/* Ladder, matrix, sankey, timeline */
.c-step { fill: var(--paper-2); stroke: var(--rule); stroke-width: 1; }
.c-step--on { fill: var(--teal); stroke: var(--teal); }
.c-step--gap { fill: none; stroke: var(--teal); stroke-width: 1.5; stroke-dasharray: 4 3; }
.c-cell { fill: var(--card); stroke: var(--rule); stroke-width: 1; }
.c-cell--warm { fill: rgba(14, 124, 123, .07); }
/* Fragmentation: a tangle of repositories, then one workspace. The tangle is
   SVG because it is geometry; the panel is HTML because it is three lines of
   prose, and prose inside a 340-unit viewBox cannot wrap. */
.frag {
  display: grid;
  grid-template-columns: minmax(0, 176fr) minmax(0, 164fr);
  gap: clamp(14px, 2vw, 24px);
  align-items: center;
}
.frag__before { width: 100%; }
.frag__box {
  background: var(--teal);
  color: #fff;
  padding: 14px 16px;
  margin-block-start: 8px;
}
.frag__box p { font-size: 12px; line-height: 1.45; }
.frag__box p + p { margin-block-start: 6px; }
.frag__t { font-weight: 700; }
@media (max-width: 560px) {
  .frag { grid-template-columns: minmax(0, 1fr); }
}

/* The radar's key: which dimension each numbered vertex is, and what it
   scored. Under the figure, so nothing has to be cross-referenced to the
   card beside it. */
.rkey {
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2px;
}
.rkey li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.45;
  padding-block: 4px;
  border-top: 1px solid var(--rule-soft);
}
.rkey__n {
  flex: none;
  width: 17px;
  font-weight: 700;
  color: var(--teal-deep);
  font-variant-numeric: tabular-nums;
}
.rkey__nm { flex: 1 1 auto; min-width: 0; }
.rkey__v {
  flex: none;
  color: var(--charcoal);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* The 2x2's marker key. HTML, under the figure: three swatches and their
   meanings would not fit inside an already crowded 340-unit box, and this is
   prose rather than geometry. */
.mkey {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  color: var(--gray);
}
.mkey li { display: flex; align-items: center; gap: 8px; }
.mkey__s {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex: none;
}
.mkey__s--on { background: var(--teal); }
.mkey__s--part { background: var(--before); border: 1.75px solid var(--teal); }
.mkey__s--off { background: var(--card); border: 1.75px solid var(--teal); }

.c-marker { fill: var(--teal); }
.c-marker--hollow { fill: var(--card); stroke: var(--teal); stroke-width: 1.75; }
.c-marker--part { fill: var(--before); stroke: var(--teal); stroke-width: 1.75; }
.c-flow { fill: var(--teal); fill-opacity: .16; }
.c-flow--mute { fill: var(--before); fill-opacity: .4; }
.c-node { fill: var(--navy); }
.c-band { fill: var(--teal); fill-opacity: .16; }
.c-band--omit { fill: var(--before); fill-opacity: .45; }

/* --------------------------------------------------------------------------
   Non-SVG figures: grids and ledgers built from real markup, because a table
   of scope is a table, and forcing it into SVG would cost it to a screen
   reader for nothing.
   -------------------------------------------------------------------------- */

.ledger {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.ledger__col { background: var(--card); padding: 16px 18px 20px; }
.ledger__col--out { background: var(--paper-2); }
.ledger h3 {
  font-size: var(--label);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gray);
  margin-block-end: 14px;
  font-weight: 600;
}
html[lang="ar"] .ledger h3 { letter-spacing: .04em; text-transform: none; }
.ledger ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.ledger li {
  font-size: 13px;
  line-height: 1.45;
  padding-inline-start: 17px;
  position: relative;
  color: var(--ink-soft);
}
.ledger li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .58em;
  width: 7px;
  height: 1.5px;
  background: var(--teal);
}
.ledger__col--out li::before { background: var(--before); height: 1.5px; }
.ledger small {
  display: block;
  color: var(--gray);
  font-size: 11px;
  margin-block-start: 2px;
}

/* Small multiples: one cell per module in a market gap survey */
.smalls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.small { background: var(--card); padding: 13px 14px 15px; }
.small--open { background: rgba(14, 124, 123, .05); }
.small__n {
  font-size: 24px;
  font-weight: 650;
  letter-spacing: -.03em;
  line-height: 1;
  /* --before is a chart fill, not a foreground. Used here it put a 24px
     statistic on white at 1.71:1, which is not readable at any size -- and
     the number is what the cell exists to say. Charcoal, with the teal
     reserved for the cells that carry the finding. */
  color: var(--charcoal);
  font-variant-numeric: tabular-nums;
}
.small--open .small__n { color: var(--teal); }
.small__of { font-size: 11px; color: var(--gray); margin-block-start: 4px; }
.small__ttl { font-size: 12px; line-height: 1.4; margin-block-start: 9px; color: var(--ink-soft); }

/* The matrix of problem shapes against study counts */
.shapes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.shapes__c { background: var(--card); padding: 16px 18px 20px; }
.shapes__h { font-size: 14px; font-weight: 600; line-height: 1.35; letter-spacing: -.014em; }
.shapes__h a { color: var(--charcoal); border-bottom: 1px solid var(--rule); }
.shapes__h a:hover { color: var(--teal); border-bottom-color: var(--teal); }
.shapes__d { font-size: 11.5px; color: var(--gray); margin-block-start: 8px; line-height: 1.45; }
.shapes__n {
  font-size: 12px;
  color: var(--teal);
  font-weight: 650;
  margin-block-start: 12px;
  font-variant-numeric: tabular-nums;
}
html[lang="ar"] .shapes__h { letter-spacing: 0; }

/* --------------------------------------------------------------------------
   Layout helpers used by the pages that carry figures
   -------------------------------------------------------------------------- */

.stack { display: grid; gap: clamp(18px, 2.2vw, 30px); }
.stack--tight { gap: 14px; }
.two-up {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(18px, 2.4vw, 32px);
  align-items: start;
}
.figrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.figrow > * { background: var(--card); padding: 16px 18px 18px; margin: 0; }

@media (max-width: 560px) {
  .rt { font-size: 12.5px; }
  .rt tbody :is(th, td) { padding-inline: 9px; }
}

/* ==========================================================================
   Diagram primitives.

   These carry the figures that argue rather than count. Colour is set here
   so the palette stays in one place; the single unavoidable exception is
   .d-knock, whose fill must equal the figure's own background because it is
   knocking a hole in it.
   ========================================================================== */

.d-grid { stroke: var(--rule-soft); stroke-width: 1; }
.d-axis-dash { stroke: var(--teal); stroke-width: 1; stroke-dasharray: 3 5; opacity: .32; }
.d-register { stroke: var(--rule); stroke-width: 1.4; }
.d-form { fill: var(--charcoal); }
.d-knock { fill: var(--card); }
.d-plane { fill: var(--teal); }
.d-mark { fill: var(--paper); font-family: var(--font-sans); font-size: 11px; font-weight: 700; }

/* The delivery graticule */
/* The outline map. Land is the "before" grey -- the same neutral used for a
   before-value everywhere else -- so the teal markers are the only saturated
   thing in the figure and read as the subject rather than competing with it.

   Water is painted in the figure's own background rather than a blue: the
   palette has no blue, and a blue sea would be the only decorative colour on
   the site. The seas here are the ones enclosed by their continent's outline
   (Mediterranean, Red Sea, Gulf, Black Sea, Caspian, Hudson Bay) and painting
   them back is what makes the Arabian peninsula read as a peninsula. */
/* No overflow override here. `.chart` clips at the viewBox, and that clip is
   the guarantee the page body never scrolls sideways at phone width -- the
   map keeps it. Everything it draws is inside the box, which is asserted
   rather than assumed: see MapTests.test_no_geometry_leaves_the_viewbox. */
.d-land path { fill: var(--before); stroke: none; }
.d-water path { fill: var(--card); stroke: none; }
.d-ptr { fill: var(--teal); fill-opacity: .16; }
.d-pt { fill: var(--teal); }
/* Semibold because these numbers now carry the whole of the map's labelling,
   against a grey landmass, and on a 400px phone the drawing renders them at
   about 7px. A digit at that size needs the weight; a country name at that
   size could not be rescued by any, which is part of why the names moved to
   the key. */
.d-ptn { font-family: var(--font-sans); font-size: 3.6px; font-weight: 600; fill: var(--charcoal); letter-spacing: -.02em; }
html[lang="ar"] .d-ptn { font-family: var(--font-arabic); letter-spacing: 0; }
.d-leader { stroke: var(--navy); stroke-width: .25; opacity: .5; fill: none; }

/* Fragmentation and its resolution */
.d-frag rect { fill: var(--paper-2); stroke: var(--before); stroke-width: 1; }
.d-tangle { stroke: var(--before); stroke-width: 1.2; }
.d-arrow { stroke: var(--teal); stroke-width: 1.6; fill: none; }

/* The permissions collision */
.d-set { fill: var(--paper-2); stroke: var(--rule); stroke-width: 1; }
.d-set-overlap { fill: var(--teal); fill-opacity: .16; stroke: var(--teal); stroke-width: 1.2; }

/* --------------------------------------------------------------------------
   The bridge: built for one industry, the same shape in yours
   -------------------------------------------------------------------------- */

.bridge { border: 1px solid var(--rule); background: var(--card); }
.bridge__hd,
.bridge__r {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(10px, 1.6vw, 22px);
  padding: 13px clamp(12px, 1.6vw, 18px);
  align-items: start;
}
.bridge__hd { border-bottom: 1px solid var(--rule); background: var(--paper-2); }
.bridge__r + .bridge__r { border-top: 1px solid var(--rule-soft); }
.bridge__src, .bridge__tgt { font-size: 12.5px; line-height: 1.45; color: var(--gray); }
.bridge__mid { font-size: 13.5px; line-height: 1.4; font-weight: 600; letter-spacing: -.014em; }
.bridge__mid a { color: var(--charcoal); border-bottom: 1px solid var(--rule); }
.bridge__mid a:hover { color: var(--teal); border-bottom-color: var(--teal); }
.bridge__mid span {
  display: block;
  font-weight: 500;
  font-size: 11.5px;
  color: var(--teal);
  margin-block-start: 6px;
  letter-spacing: 0;
}
html[lang="ar"] .bridge__mid { letter-spacing: 0; }

/* --------------------------------------------------------------------------
   The thirteen-phase timeline
   -------------------------------------------------------------------------- */

/* The key. Two swatches matching the two row states, plus a line saying what
   span the figure covers -- without it the shading is a mystery and the list
   gets read as a single tier's scope. */
.tl__key { margin-block-end: 14px; }
.tl__scope { font-size: 12.5px; color: var(--ink-soft); line-height: 1.55; margin: 0 0 10px; max-width: 62ch; }
.tl__key ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 20px; }
.tl__key li {
  font-size: 11.5px;
  color: var(--gray);
  display: flex;
  align-items: center;
  gap: 7px;
}
.tl__key li::before {
  content: "";
  width: 11px;
  height: 11px;
  border: 1px solid var(--rule);
  flex: none;
}
.tl__key-a::before { background: var(--card); }
.tl__key-b::before { background: var(--paper-2); }

.tl { list-style: none; margin: 0; padding: 0; border: 1px solid var(--rule); background: var(--card); }
.tl__i {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) minmax(0, 120px) minmax(0, 150px);
  gap: 12px;
  align-items: baseline;
  padding: 10px clamp(12px, 1.5vw, 16px);
  font-size: 13px;
}
.tl__i + .tl__i { border-top: 1px solid var(--rule-soft); }
.tl__i--omit { background: var(--paper-2); }
/* --teal-deep, not --teal: these numerals sit on --paper-2, where --teal
   is 4.36:1 against a 4.5:1 requirement at this size. */
.tl__n { font-size: 11px; font-weight: 700; color: var(--teal-deep); font-variant-numeric: tabular-nums; }
.tl__nm { font-weight: 500; line-height: 1.35; }
.tl__d { font-size: 12px; color: var(--gray); }
.tl__m { font-size: 11px; letter-spacing: .01em; color: var(--gray); }
.tl__i--omit .tl__m { color: var(--teal); }

@media (max-width: 720px) {
  .bridge__hd { display: none; }
  .bridge__r { grid-template-columns: 1fr; gap: 6px; }
  .bridge__mid { order: -1; }
  .tl__i { grid-template-columns: 26px minmax(0, 1fr); }
  .tl__d, .tl__m { grid-column: 2; }
}

/* A figure that follows prose needs air above it. Set here rather than as an
   inline style, because the CSP has no unsafe-inline for styles. */
.fig--gap { margin-block-start: 22px; }

/* --------------------------------------------------------------------------
   Figure prose.

   SVG text cannot wrap, so anything longer than a label sits here instead.
   That also puts it in reading order for a screen reader, which text inside
   a viewBox is not.
   -------------------------------------------------------------------------- */

.fig__notes { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
.fig__notes li { font-size: 11.5px; color: var(--gray); line-height: 1.45; }

/* --------------------------------------------------------------------------
   The provenance funnel: 18 market services down to 14 we will sell.

   Count, bar, label as three grid cells, so the label is HTML that wraps
   instead of SVG text that gets clipped. The bar track is a fixed fraction of
   the row and the rect inside it carries the proportion, which keeps the
   three bars on one shared scale however wide the figure gets.
   -------------------------------------------------------------------------- */

.fn { margin-block-start: 4px; }
.fn__row {
  display: grid;
  grid-template-columns: 2.6em minmax(60px, 8.5fr) minmax(0, 11fr);
  align-items: center;
  gap: 12px;
  padding-block: 7px;
}
.fn__n {
  font-size: 15px;
  font-weight: 700;
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  text-align: end;
}
.fn__track { display: block; min-width: 0; }
.fn__bar { display: block; width: 100%; height: 16px; }
.fn__lb { font-size: 12.5px; color: var(--ink-soft); line-height: 1.4; }

/* The subtraction, sitting between the two rows it explains. Indented to the
   bar column so it reads as an operation on the bar above it. */
.fn__cut {
  margin: 0;
  padding-inline-start: calc(2.6em + 12px);
  font-size: 11.5px;
  color: var(--teal);
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  .fn__row { grid-template-columns: 2.6em minmax(0, 1fr); }
  .fn__lb { grid-column: 2; }
}
.figrow--flush { border: 0; background: transparent; gap: clamp(12px, 2vw, 24px); }
.figrow--flush > * { padding: 0; background: transparent; }

/* --------------------------------------------------------------------------
   Proof strip: how much delivered proof stands behind one service line.

   One mark per delivered engagement, teal where the record is published on
   this site and grey where it is not. The comparison between lines still
   holds -- every mark is the same size -- but nothing has to be divided by
   an invisible denominator to read it, which is what went wrong with the bar
   this replaced.
   -------------------------------------------------------------------------- */

.ps { margin-block: 10px 12px; }
.ps__marks {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  max-width: 250px;
}
.ps__m {
  width: 9px;
  height: 9px;
  border-radius: 1px;
  background: var(--before);
}
.ps__m--on { background: var(--teal); }
.ps__t {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--gray);
  letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
}
/* The qualifier rides on the same line as the counts, because separating the
   number from the caveat is how a partial line comes to look like a strong
   one. */
.ps__q {
  margin-inline-start: 8px;
  padding-inline-start: 8px;
  border-inline-start: 1px solid var(--rule);
  color: var(--teal);
}
.ps__t--none { margin-block: 10px 12px; color: var(--gray); font-style: italic; }
