/* ============================================================
   DEVICES — the inline SVG exhibits. "THE OPEN EXHIBIT."
   Loaded on reading views only, after article.css and before
   figures.css (inc/enqueue.php:178). Nothing later names a
   .cz-dev__ class.

   ------------------------------------------------------------
   UNBOXED, 2 SEPTEMBER
   ------------------------------------------------------------
   "why are your infographics imprisoned in a box with lame color
   inside. Why can't it be free? It's not a lame school project."

   There is no panel, no ring, no lift, no radius, no wash and no
   card padding. A device is line-work and type standing on the
   page, aligned to the prose's own left edge and running past
   its right one. Everything that used to make it an object —
   the frame, the light, the top rule — is gone; what holds it
   together is contrast, alignment and air, which is what holds
   a newspaper exhibit together.

   Every colour here is a custom property. Not one literal hex
   outside the stud's shadow. A device has to survive a palette
   change, and it has to sit on paper-white and inside a dark
   strip without being redrawn.

   There is no legend rule and no caption rule (R42): the
   paragraph above a device is its caption.

   ------------------------------------------------------------
   THE CONTRACT THIS FILE IS THE COLOUR HALF OF
   ------------------------------------------------------------
   inc/devices-draw.php draws six kinds on a 720-unit viewBox
   with ONE outer margin (ink from x=24 to x=696), ONE frame
   (first ink at y=12, last ink + 12 = height) and one left
   datum family (count gutter 24-76, rule 84, text 104). Nothing
   is boxed. The drawing is rule, tick, mark, count and ramp.

   PHP owns geometry, class names, stroke-width, stroke-linecap,
   `fill="none"` on every stroked shape, the `stroke-dasharray`
   attribute on cz-dev__track ONLY and the `opacity` attribute on
   cz-dev__tier-rule ONLY (the ladder's rank ramp).

   This file owns every colour, weight, tracking, numeric
   variant, the one filter, and every transition. It never sets
   font-size (PHP wrapped against the size it emitted), never
   sets opacity on cz-dev__tier-rule (it would flatten the ramp)
   and never sets stroke-dasharray on cz-dev__track (it would
   erase the dashed track).

   Sizes PHP emits, so the R7 floor can be checked from here:
   the smallest is 12u (colhead, attr, axis-head, mark-text).
   .cz-dev__svg pins the drawing to 749px, so 12u renders at
   12 x 749/720 = 12.48px at every width below ~772px, and
   larger above. Nothing in this file changes a size.

   CORRECTION, 2 September: reading.css:412 does NOT merely
   restate this file's margin-inline. `.cz-prose figure` is
   (0,1,1) and out-specifies `.cz-dev`, which broke the
   negative margin the unboxed exhibit uses to hold the one
   left edge. See the (0,2,0) rule under the scrollbar block.

   ------------------------------------------------------------
   THE THREE BEATS (R16)
   ------------------------------------------------------------
   A. The ground draws: every `cz-dev__draw` path runs its
      dashoffset from 1400 to 0 at constant speed (1.2s linear
      over 1400u, so a 450u flow rule is drawn in 386ms).
      Timeline and matrix grounds fade instead — a dashed track
      cannot draw on without losing its dashes.
   B. Rows arrive top-down, 80ms apart, from 6px below.
      Fork rows slide in from the left; ladder stairs along their
      own indent; the timeline's duration chips from the right,
      late.
   C. Gold lands last: every stud stamps down from 1.35x to 1x,
      220ms after its row, 60ms per matrix column; the arrowhead
      appears when the rule reaches it.
   Nothing bounces, spins or loops. The pre-state exists only
   under `.cz-dev[data-reveal]:not(.visible)`; a figure without
   the hook renders the finished drawing, and so does every
   reader under prefers-reduced-motion or in print.
   ============================================================ */

.cz-dev {
  /* Gold at ink weight. --cz-gold (#c7a36b) measures 2.36:1 on white, which
     fails the 3:1 floor for a graphical object — and the gold here IS
     graphical: the stud, the diamond, the landing dash and the header rule
     carry meaning with no text to fall back on. --cz-gold-ink is the same
     hue at 5.40:1 on white and 4.91:1 on the panel below. The dark block
     puts --cz-gold back, where it measures 8.57:1. */
  --dev-accent: var(--cz-gold-ink, #856527);

  /* The decision band edges. A fork is announced by two gold hairlines
     crossing the whole width; at 55% they read as a band without becoming a
     fill (R17: gold is emphasis, never an area). */
  --dev-accent-soft: color-mix(in srgb, var(--dev-accent) 55%, transparent);

  /* Kept for the focus ring only. R17: "Blue is an action you take". A
     keyboard focus ring is an action affordance; nothing drawn inside a
     diagram is. */
  --dev-action: var(--cz-blue, #1769ff);

  /* ============================================================
     THE EXHIBIT PALETTE — the cool counter to the brand gold
     ============================================================
     The client, third time of asking: "I need professional, good looking,
     WITH COLOURED ELEMENTS, informative infographics." The devices were a
     single hue — gold — used sparingly on a neutral ground, and that reads as
     a wireframe however well it is drawn.

     Two families, no third. Both come out of main.css:14-26 and nothing here
     is invented, because R11 removed six warm tones from this site and adding
     a seventh would be the same mistake with a new name:

       WARM   --cz-gold-soft #e0c79f / --cz-gold #c7a36b / --cz-gold-ink #856527
       COOL   --navy #071d2e / --slate #5e6871

     17-ART-DIRECTION-COUNTER-LIGHT specifies the grammar exactly: "warm source
     against cool ground". Gold is the source, petrol is the ground.

     ONE RULE, LEARNABLE IN A SECOND, AND IT IS THE SAME ON ALL SIX KINDS:

       GOLD marks what APPLIES, where the process ARRIVES, and how far a
            consequence has ESCALATED.
       COOL marks what does NOT apply, the OTHER position, and the measure
            beside the thing measured — context, not claim.
       INK  is the words.

     Nothing here is a decoration: every use below encodes state, category or
     magnitude, which is the only licence R42 gives colour in a device.

       --dev-cool       #5e6871, 4.77:1 on the panel. The negative mark and the
                        branch index: present, quiet, unmistakably not gold.
       --dev-cool-deep  navy over slate, 9.69:1. The B position's head and rule,
                        and the timeline's schedule column — a second ink, not
                        a lighter one.
       Nothing here fills an area: the cool is a stroke or a glyph, never a
       wash. The one wash the system had is gone with the box. */
  --dev-cool: var(--slate, #5e6871);
  --dev-cool-deep: color-mix(in srgb, var(--navy, #071d2e) 62%, var(--dev-cool));

  /* THE RANK RAMP. Five steps from the cool end to the brand gold, walked by
     cz-dev__rank--N, which PHP puts on a ladder's tier rules. Rank is the one
     quantity in the set that is genuinely ordinal, so it is the one that earns
     a colour scale rather than a colour. Five and not n, so a three-rung
     ladder and a six-rung one land on the same colours and two ladders in one
     article are comparable (R1: variation is computed, never arbitrary).

     Written against --dev-cool-deep and --dev-accent rather than against the
     hexes, so the dark block re-points the whole ramp by re-pointing its two
     ends and there is no second copy of it to drift. */
  --dev-rank-1: var(--dev-cool-deep);
  --dev-rank-2: color-mix(in srgb, var(--dev-cool-deep) 62%, var(--dev-accent));
  --dev-rank-3: color-mix(in srgb, var(--dev-cool-deep) 30%, var(--dev-accent));
  --dev-rank-4: var(--dev-accent);
  --dev-rank-5: var(--dev-accent);

  --dev-ink: var(--cz-black, #050607);

  /* ---------- THE WARM NEUTRAL, and why every line is mixed from it ----------
     --dev-ink is #050607, a near-black whose BLUE channel is its highest.
     Diluted on white it is a cool grey, and a column of cool grey is a
     wireframe. --dev-ink-w is that ink carrying 22% of --cz-gold-ink: the
     same lightness, moved warm. The warm source is the DARK gold, not the
     light one, so the mix moves temperature and leaves density alone.

     Every LINE and WASH mixes from it; every TEXT colour still mixes from
     --dev-ink, because R17 fixes body copy and this file has no licence to
     warm it. Warm furniture, neutral words — which is the grammar of
     17-ART-DIRECTION-COUNTER-LIGHT: "warm source against cool ground". */
  --dev-warm: var(--cz-gold-ink, #856527);
  --dev-ink-w: color-mix(in srgb, var(--dev-ink) 78%, var(--dev-warm));

  /* ---------- THE FURNITURE RAMP, AND WHY IT WAS RAISED ----------
     The previous pass set this ramp by eye and measured only the two objects
     it happened to doubt (the stud and the arrowhead). Measured on the live
     panel, 2 September, every value in it was under the 3:1 non-text floor
     that WCAG 1.4.11 sets for a graphical object a reader has to perceive:

       was 26%  the spine, track, trunk, tab, tick and fold     1.73:1
       was 12%  ledger hairlines, row separators, the leader    1.27:1
       was 16%  the panel's own ring                            1.41:1

     That is the arithmetic behind "lame boring generic". The drawing was not
     the wrong drawing; it was drawn in a tone the eye does not register, so
     six kinds whose whole difference IS their line-work all read as one empty
     panel with small text in it. Raising the ramp is what makes them tell
     themselves apart.

       --dev-hair   22%   1.55:1   separators only. A row rule divides, it does
                                   not connect, and the register is legible
                                   without it — the one line here allowed to
                                   sit under the floor, and it says so.
       --dev-line   26%   —        the panel's own 1px ring, so the plate has
                                   an edge on the page.
       --dev-rule   50%   3.05:1   spine, track, trunk, tab, tick, fold and the
                                   matrix leader — everything the reader has to
                                   see to follow the drawing. Rank inside this
                                   group is carried by PHP's stroke-width
                                   (1.5u structure, 1u leader), not by tone.
     The ladder's tier rules take --dev-ink-w at full strength and let PHP's
     opacity attribute (now .52 to .88 by rank) do the grading; that floor was
     raised in the same pass, because .30 measured 1.89:1 and the bottom two
     rungs of every ladder were invisible. */
  --dev-hair: color-mix(in srgb, var(--dev-ink-w) 22%, transparent);
  --dev-line: color-mix(in srgb, var(--dev-ink-w) 26%, transparent);
  --dev-rule: color-mix(in srgb, var(--dev-ink-w) 50%, transparent);

  /* ---------- THE TYPE RAMP ----------
     Re-measured 2 September on the deeper panel, over live HTTP, worst of the
     lit corner and the vignette corner. The figures the previous pass printed
     here — 18.45 / 9.58 / 5.69 — were true of the rgb(245,244,242) ground and
     are not true of this one; they are replaced rather than kept, because a
     ratio without its ground is not a measurement.

       --dev-ink   100%   14.62:1   the thing itself     (step, route, tier, end)
       --dev-mid    76%    8.33:1   its measure          (duration, the nil dash)
       --dev-mute   62%    5.23:1   its qualifier        (authority, note, heads)
       --dev-ghost  50%    3.49:1   the count            (34u ordinal, 24u letter)
     The count is the largest mark on four of the six kinds and it still sits
     BEHIND the drawing — order is carried by position and the numeral only
     makes that order visible from across the room. At 18% it measured
     **1.49:1** and could not be read at any distance: a numeral nobody can see
     is not restraint, it is R4.4's "scale that reads" missing, and it is the
     client's "text not visible" landing on the largest glyph in the device.
     50% clears the 3:1 a >=24px mark needs with real headroom, and still sits
     the 100% ink of the label it serves, so the hierarchy the ghost was
     reaching for survives being legible. Every other tone clears AA at
     12.48px on the worst composite the panel presents (the lit corner: ink
     16.82:1, mid 9.07:1, mute 5.51:1 — measured by the previous pass, and
     unchanged here because no plane has been added between type and panel). */
  --dev-mid: color-mix(in srgb, var(--dev-ink) 76%, transparent);
  --dev-mute: color-mix(in srgb, var(--dev-ink) 62%, transparent);
  --dev-ghost: color-mix(in srgb, var(--dev-ink) 50%, transparent);

  /* THE GROUND THE DEVICE STANDS ON — the page's own, not one of its own.
     There is no panel any more. This token exists so the two scroll fades
     below dissolve INTO the page rather than into a colour the page does not
     have, and so the dark block can re-point them in one place. */
  --dev-ground: var(--cz-paper, #fff);

  /* The site's own easings (main.css:108-109), with the same fallbacks the
     rest of the file has always carried. */
  --dev-ease: var(--cz-ease, cubic-bezier(.2, .7, .2, 1));
  --dev-ease-out: var(--cz-ease-out, cubic-bezier(.16, 1, .3, 1));

  /* ============================================================
     UNBOXED — 2 September, the client's fifth complaint
     ============================================================
     "why are your infographics imprisoned in a box with lame color inside.
     Why can't it be free? It's not a lame school project."

     He is right, and the box was the answer to an earlier question. Everything
     that made this a card is gone: the panel fill, the 1px ring, the three-stage
     lift, the 3px radius, the raked gold top rule, the warm pool and the cool
     vignette, and the padding that framed all six kinds identically. A filled
     rectangle around a diagram reads as a slide pasted into an article; an
     exhibit sits ON the page and is held together by rules, alignment and air.

     What replaces the frame is not nothing — it is the three things a
     newspaper exhibit uses instead:
       - the drawing's own line-work, now at 3:1 and up rather than 1.7:1;
       - alignment, below: the ink starts exactly on the prose's left edge;
       - air, in margin-block, which is where a card's padding went.

     Kept, because they are affordances rather than decoration: the horizontal
     scroller (the drawing is pinned to 749px so the 12u labels never fall
     under the R7 floor, so below ~1050px it MUST scroll), its styled bar, and
     two 14px fades that dissolve the drawing at the box edges instead of
     cutting it. Nothing here paints a surface. */
  margin: 0;
  margin-block: clamp(44px, 4.6vw, 76px);

  /* ---------- THE MEASURE, BROKEN, WITH THE LEFT EDGE HELD ----------
     An editorial exhibit earns its own width. --cz-fig-full is the site's own
     name for "the column plus the margin column plus the gap" — the idiom
     placement.css:125 states for every figure that breaks the measure — and
     the device now takes it whole instead of growing to a 820px cap.

     THE ARITHMETIC THAT KEEPS R19's ONE LEFT EDGE. The drawing's leftmost ink
     is at x=24 of 720 and its rightmost at x=696, so an SVG laid flush in the
     box would inset its ink by W/30 and the exhibit would start 3.3% right of
     every paragraph above it. Solving for ink-left = 0 and ink-right = F:

         W = F x 720/672 = F x 1.0714286
         margin-left = -F x 24/672 = -F x 0.0357143

     Both resolve against the same containing block, so they cancel exactly:
     the INK spans the prose's left edge to the full-bleed right edge at every
     width, and the 24u of drawing margin hangs outside the box where the
     fades live.

     THE CAP IS A TYPE DECISION, NOT A LAYOUT ONE. The viewBox is fixed at
     720u, so widening the box magnifies the whole drawing rather than fitting
     more into it: at the 1040px this was first set to, the scale ran 1.55 and
     a 17.5u step label rendered at 27px against 18.5px body copy — an exhibit
     shouting over the argument it exists to serve. 880px of ink is scale 1.31:
     step 22.9px, the smallest caps 15.7px, the count 44.5px, and the ink still
     runs 165px past the 715px measure, which is the break the eye reads. */
  --dev-f: min(var(--cz-fig-full, 100%), 880px);

  width: calc(var(--dev-f) * 1.0714286);
  margin-left: calc(var(--dev-f) * -0.0357143);

  /* ---------- the scroller ----------
     The SVG carries a min-width, so any column narrower than that overflows
     and must scroll; the reading column is narrower than that below roughly
     1050px. Above that nothing scrolls and nothing here paints. */
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--dev-rule) transparent;

  /* The two fades, pinned to the box, 14px each. At rest they sit entirely
     inside the 24u (~25px) of blank drawing margin that hangs past each edge,
     so they cover no ink; mid-scroll they dissolve the drawing at the edge
     rather than guillotining it, which is the one thing a reader needs to be
     told and the only thing left painting on this element. */
  background-image:
    linear-gradient(to right, var(--dev-ground), transparent),
    linear-gradient(to left, var(--dev-ground), transparent);
  background-position: left center, right center;
  background-size: 14px 100%;
  background-repeat: no-repeat;
  background-attachment: scroll;

  /* Only opacity, because there is no longer a box to lift or a shadow to
     deepen. This shorthand still wins over main.css:443's [data-reveal]
     transition (same specificity, later sheet), so the exhibit fades in under
     its own drawing, whose first beat starts at 180ms. */
  transition: opacity .4s var(--dev-ease);
}

/* THE CASCADE COLLISION, FOUND BY MEASURING RATHER THAN BY READING (§23.1).
   reading.css:412 is `.cz-prose figure { margin-inline: 0 }` at (0,1,1), and
   it out-specifies `.cz-dev` at (0,1,0) however late this sheet is enqueued.
   That was harmless while the device's margin WAS 0; the moment the negative
   margin above became load-bearing, the exhibit silently snapped back flush
   with the column and its ink sat 38px right of every paragraph. Measured:
   prose left 328, device box left 328, ink left 366.

   (0,2,0), and only the one property. The header note at the top of this file
   claiming reading.css "only restates the margin-inline this file already sets
   to 0" is no longer true, and is corrected here rather than left to be
   rediscovered. */
.cz-prose .cz-dev {
  margin-left: calc(var(--dev-f) * -0.0357143);
}

.cz-dev::-webkit-scrollbar {
  height: 8px;
}

.cz-dev::-webkit-scrollbar-track {
  background: transparent;
}

.cz-dev::-webkit-scrollbar-thumb {
  background: var(--dev-rule);
  border-radius: 4px;
}

.cz-dev:focus-visible {
  outline: 2px solid var(--dev-action);
  outline-offset: 3px;
}

/* THE HOVER LIFT IS GONE WITH THE BOX IT LIFTED. R16 says hover informs and
   never decorates; with no card there is nothing for a lift to inform about,
   and a diagram that rises off the page when the pointer crosses it is the
   school-project tell all over again. The scroller keeps its focus ring above
   and its styled bar, which are the only two states this element has left. */

/* A device is a block of reasoning, not a picture. min-width is the R7 fix
   and it is arithmetic: 749/720 = 1.0403, so the 12u labels render at
   12.48px at every width where the min-width binds. overflow: visible lets
   the stud shadow out of the SVG; the panel above clips at its padding box
   in both axes (a horizontal scroller cannot keep overflow-y visible), and
   the 1.75px reach of that shadow is well inside the smallest padding. */
.cz-dev__svg {
  display: block;
  width: 100%;
  min-width: 749px;
  height: auto;
  overflow: visible;
}

/* ============================================================
   TYPE
   ============================================================
   Sizes are set in the SVG. Weight, colour, tracking and numeric variants
   belong here.

   TRACKING MOVES IN ONE DIRECTION ONLY. cz_device_wrap() commits to a break
   using $per = $size x 0.52, and any tracking added here lands on a line
   whose length is already settled: negative tracking can only leave a line
   shorter than PHP allowed for, positive tracking can push it past. So the
   display sizes get negative tracking, the small sizes get none, and the
   one positive value is the .04em on the caps micro-labels argued for
   below. */

/* The reading sizes: flow step 17u, tree route 15/17u, matrix row head 16u,
   ladder tier name 16u, compare values 14u. Ink, 600, a shade under normal
   letterfit so a two-line label reads as one label. */
.cz-dev__label,
.cz-dev__rowhead {
  fill: var(--dev-ink);
  font-weight: 600;
  letter-spacing: -.008em;
}

.cz-dev__route,
.cz-dev__tier-name {
  fill: var(--dev-ink);
  font-weight: 700;
  letter-spacing: -.008em;
}

/* The flow's decision question sits on a gold band with a diamond at its
   head; 700 against the steps' 600 so the question weighs what the band
   says it weighs. */
.cz-dev__label--on-decision {
  font-weight: 700;
  letter-spacing: -.014em;
}

/* The flow's end: a 19u headline on a 2u ink rule. The heaviest type in
   the device, because it is where the process lands. */
.cz-dev__label--end {
  font-weight: 800;
  letter-spacing: -.02em;
}

/* The top tier of the ladder — the rule that beats every rule above it. */
.cz-dev__tier-name--top {
  font-weight: 800;
}

/* The tree's question, 20u, the one heading in the set: tight enough to
   close into a single object above the routes it opens. */
.cz-dev__question {
  fill: var(--dev-ink);
  font-weight: 800;
  letter-spacing: -.024em;
}

/* ---------- THE COUNT ----------
   34u numerals on the timeline and flow, 24-32u on the ladder (growing with
   rank), 24u letters on the tree. Weight 800, tabular lining figures so "01"
   and "10" share a right edge at x=70, tracking closed because a two-glyph
   numeral at this size opens up otherwise. Emitted first in each row, so the
   tick and the label print over it. This is the mark no diagramming tool
   draws, and it is what gives the device scale (R4.4: 34u against 17.5u). */
.cz-dev__ordinal,
.cz-dev__letter {
  fill: var(--dev-ghost);
  font-weight: 800;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -.02em;
  /* Motion (Beat B): the count settles more slowly than its row, so the
     numeral is still arriving as the label is already readable — the count
     stays behind. --cz-row-delay is inherited from the row <g>. */
  transition:
    opacity .9s var(--dev-ease),
    transform .9s var(--dev-ease);
  transition-delay: var(--cz-row-delay, 180ms);
}

/* THE TREE'S LETTER IS AN INDEX, NOT A COUNT, and it now says so in colour.
   A, B, C do not measure anything — they name alternatives — so they take the
   cool family at 4.77:1 and leave the warm family to the gold landing dash
   beside them, which marks where the stem actually arrives. Two marks, two
   jobs, two colours: the reader can see the difference without being told it.
   Printed after the shared rule above so it wins on source order at equal
   specificity. */
.cz-dev__letter {
  fill: var(--dev-cool);
}

/* The ladder's top ordinal is gold at full strength — 4.91:1 on the panel.
   It was held to .55, which put the ONE numeral the device is arguing towards
   at 2.4:1, fainter than the rungs below it: the ladder's answer was its least
   visible mark. Gold is emphasis and state (R17), and the top of an escalation
   is both. This is an opacity removed from a ghost numeral, not one added to a
   tier rule; PHP's ramp attribute is untouched. */
.cz-dev__ordinal--top {
  fill: var(--dev-accent);
}

/* THE SCHEDULE COLUMN, IN ITS OWN INK. The timeline's durations sit hard
   right on the step's own baseline, and they are the second half of what the
   device is for — "Day 0", "Within 3 months", "6 to 18 months" is the answer
   the reader came for. In neutral grey they read as a footnote to the step.
   In the cool deep (9.69:1) they read as a second column of data measured
   against the first, which is what they are. Tabular, so the figures inside
   "10-14 days" line up down the column. */
.cz-dev__meta {
  fill: var(--dev-cool-deep);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
}

/* Tree consequences (12.5 / 13.5u) and ladder notes (13u): the qualifier,
   two tones below the thing it qualifies. */
.cz-dev__muted,
.cz-dev__tier-note {
  fill: var(--dev-mute);
  font-weight: 500;
}

/* ---------- the caps micro-labels ----------
   THIS FILE UPPERCASES THEM AND PHP DOES NOT KNOW. cz_device_wrap() measures
   lowercase at 0.52; uppercase at weight 800 draws at ~0.62 and the .04em
   here adds 0.04. PHP compensates through cz_dev_caps_w(), which allocates
   these classes 0.788 of the nominal width (0.52/0.66), so the wrap and the
   render finally agree. .04em is the value the previous pass measured as the
   floor below which weight-800 caps set too tight, and it is ONE value for
   all five classes so two devices on one page share a letterfit (R1).

   Colour is the hierarchy: colhead and attr label an axis the reader
   consults once, and stay muted; the axis head (the recovered $head[0] on
   matrix and compare) and the compare's side heads NAME what is being
   compared, and take ink. The timeline's authority line is emitted as
   cz-dev__attr and is muted like every other qualifier. */
.cz-dev__colhead,
.cz-dev__attr,
.cz-dev__axis-head,
.cz-dev__side-head {
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.cz-dev__colhead,
.cz-dev__attr {
  fill: var(--dev-mute);
}

.cz-dev__axis-head {
  fill: var(--dev-ink);
}

/* THE TWO POSITIONS ARE TWO COLOURS. A compare sets one thing against another
   across a fold, and until now both sides were the same ink under the same
   gold rule, so the reader had to hold "left is off-plan, right is ready" in
   their head for seven rows. Side A takes the warm family, side B the cool —
   4.91:1 and 9.69:1, both clear of AA at 19.5u — and the head rule under each
   carries the same colour, so a value 400 units down the page still knows
   which column it is in. Neither is marked as favoured: polarity is
   inconsistent across the 26 authored compares, and a colour that meant
   "better" would be a claim nobody wrote. */
.cz-dev__side-head--a {
  fill: var(--dev-accent);
}

.cz-dev__side-head--b {
  fill: var(--dev-cool-deep);
}

/* A matrix word mark ("Optional", "By notice") is a qualifier, not a row:
   74% ink at 600, below the row head beside it and above the column head
   over it. 8.92:1 on the panel. */
.cz-dev__mark-text {
  fill: color-mix(in srgb, var(--dev-ink) 74%, transparent);
  font-weight: 600;
}

/* ============================================================
   LINE-WORK
   ============================================================
   Every stroked class carries fill: none here as well as on the element:
   PHP guarantees the attribute, and an SVG path's default fill is black, so
   the one failure mode worth a redundant declaration is a compound path
   filling itself. Widths are PHP's (they are geometry). Colour is here.

   THE DIVISION THE WHOLE FILE KEEPS: gold marks structure and the answer;
   neutral carries connection. Six kinds, one sentence. */

/* Structure at 50%: the flow's process rule, the timeline's dashed track
   (its dashes are PHP's attribute and are not restated here), the tree's
   trunk-bracket-stems and its tab rules, the flow's step ticks, the
   compare's centre fold. */
.cz-dev__spine,
.cz-dev__track,
.cz-dev__trunk,
.cz-dev__tab,
.cz-dev__tick,
.cz-dev__fold {
  fill: none;
  stroke: var(--dev-rule);
}

/* Separation at 22%: the timeline's ledger hairlines and the matrix and
   compare row separators. These divide, they do not connect, so a separator
   is the one line in the file allowed to sit under 3:1. */
.cz-dev__hair {
  fill: none;
  stroke: var(--dev-hair);
}

/* THE LEADER IS NOT A SEPARATOR, and it was drawn as one. It runs from a
   matrix row head across to that row's studs, gapped around each one so the
   stud sits ON it — which means it is the mark that answers "which row is
   this cell in", on the one device where the answer is five columns away.
   At 12% it measured 1.27:1: the association was carried by alignment alone,
   across a register that scrolls sideways on a phone.

   It takes the STRUCTURE tone, 3.05:1, and is subordinated by WEIGHT instead
   — PHP draws it at 1u against the structure's 1.5u. Tone was the wrong knob:
   a leader lighter than the floor is not a quiet leader, it is an absent one,
   and a draughtsman answers this with a finer pen, not with paler ink. */
.cz-dev__leader {
  fill: none;
  stroke: var(--dev-rule);
}

/* THE GOLD RULES. The header rule under a matrix's column heads, under a
   compare's three heads and under a tree's question is the site's own
   section rule — the same 2u mark the panel wears at its top edge. The
   tree's landing dash is the 10u of gold where a stem meets its tab. R17
   gives gold to "rules" and "table-header accents" by name. */
.cz-dev__head-rule,
.cz-dev__landing {
  fill: none;
  stroke: var(--dev-accent);
}

/* The compare's three head rules, each the colour of the column it heads: the
   attribute spine is not a position, so its rule steps back to the structure
   tone and lets the two coloured ones carry the reading. Printed after the
   shared gold rule above, equal specificity, later in source — deliberate. */
.cz-dev__head-rule--axis {
  stroke: var(--dev-rule);
}

.cz-dev__head-rule--a {
  stroke: var(--dev-accent);
}

.cz-dev__head-rule--b {
  stroke: var(--dev-cool-deep);
}

/* The flow's decision band: two gold hairlines crossing the full width. */
.cz-dev__fork {
  fill: none;
  stroke: var(--dev-accent-soft);
}

/* The flow's terminal rule, 2u of ink, the heaviest line in the device. */
.cz-dev__end-rule {
  fill: none;
  stroke: var(--dev-ink);
}

/* THE LADDER'S RULES LENGTHEN, DARKEN AND WARM BY RANK — three channels
   saying one thing. Length and opacity (.62 to .92, PHP's attribute, never
   restated here because an opacity in this rule would override every step of
   it) were already doing two of them in a single neutral, which is a lot of
   machinery to say "worse" without ever changing colour.

   The rank class walks the exhibit palette from the cool deep at rung one to
   the brand gold at the top, so a reader crossing the device sees the
   consequence heat up. Base declaration first for anything unranked. */
.cz-dev__tier-rule {
  fill: none;
  stroke: var(--dev-ink-w);
}

.cz-dev__tier-rule.cz-dev__rank--1 { stroke: var(--dev-rank-1); }
.cz-dev__tier-rule.cz-dev__rank--2 { stroke: var(--dev-rank-2); }
.cz-dev__tier-rule.cz-dev__rank--3 { stroke: var(--dev-rank-3); }
.cz-dev__tier-rule.cz-dev__rank--4 { stroke: var(--dev-rank-4); }
.cz-dev__tier-rule.cz-dev__rank--5 { stroke: var(--dev-rank-5); }

/* The top tier's rule is gold at full opacity and 2u: the answer the ladder
   climbs to. (0,2,0) so it beats the rank rules above it whatever rank the
   top rung computes to. */
.cz-dev__tier-rule--top.cz-dev__tier-rule {
  stroke: var(--dev-accent);
}

/* A MATRIX "NO", IN THE COLOUR OF NO. A 10u dash at 2u, in the cool family at
   4.77:1. Against a gold disc at 4.91:1 the two marks now differ in HUE and
   in SHAPE rather than only in shape, so a five-column register answers
   "which of these applies" from across the room instead of one cell at a
   time. It stays quieter than the stud despite the near-equal ratio, because
   a 5.5u filled disc carries roughly four times the ink of a 10 x 2u dash —
   weight is area here, not contrast. */
.cz-dev__nil {
  fill: none;
  stroke: var(--dev-cool);
}

/* THERE IS NO FILL RULE HERE ANY MORE. The cz-dev__col class styled the matrix's
   alternate column washes and PHP has stopped emitting them: a tint behind a
   register is a ground, a ground is a container, and the client's objection
   was to exactly that. The class and its --dev-cool-wash token went out
   together rather than being left as CSS with no markup (§12.8 — the same bug
   inverted, and harder to see). Not one shape in the six kinds fills an area
   now; the only fills left are glyphs, the gold stud and the arrowhead. */

/* ============================================================
   THE PHYSICAL OBJECTS
   ============================================================
   The stud is the one thing in the drawing that is not a line or a glyph: a
   5.5u gold disc on the timeline track and in the matrix cells, a 14u gold
   diamond at the head of a flow decision. It is the only shape that stands
   ON the panel, so it is the only shape that casts. 1px down, .75px blur,
   22% shade: a contact shadow, on the same light as the panel's lift. Half
   the blur a card would get, because a 5.5u dot with a soft shadow is a
   smudge.

   drop-shadow rather than a second element, because CSS cannot add elements
   and wp_kses_post() would not pass a <filter> if PHP drew one. */
.cz-dev__stud {
  fill: var(--dev-accent);
  stroke: none;
  filter: drop-shadow(0 1px .75px color-mix(in srgb, var(--dev-shade) 22%, transparent));
}

/* The arrowhead is the statement of direction, and a graphical object a
   reader needs, so it clears 3:1 on every ground the panel presents
   (measured by the previous pass at 58%: 3.98 / 4.11 / 3.91:1; inverted
   5.91:1). It is neutral, not gold: connection, not structure. */
.cz-dev__arrowhead {
  fill: color-mix(in srgb, var(--dev-ink-w) 58%, transparent);
  stroke: none;
  /* Motion (Beat C): the arrowhead appears when the rule has reached it —
     1.2s is the full draw of a 1400u dash. */
  transition: opacity .4s var(--dev-ease);
  transition-delay: 1.2s;
}

/* ============================================================
   MOTION
   ============================================================
   Base state = the finished drawing. The pre-state exists ONLY under
   `.cz-dev[data-reveal]:not(.visible)`: main.js adds .visible when the
   figure enters the viewport (and immediately, before observing, under
   prefers-reduced-motion). A figure that never had the hook renders
   finished; a figure whose script never ran is already invisible site-wide
   via main.css:443, which this file neither worsens nor fixes.

   The delays are one arithmetic:
     --cz-i          the row index, 0..13, set by cz-dev__row--N
     --cz-row-delay  180ms + i x 80ms, computed on the row and inherited by
                     everything inside it
     --cz-c          the matrix column, 0..4, set by cz-dev__c--C
   so a stud lands at row + 220ms + column x 60ms, a duration chip at
   row + 260ms, and the compare's A and B values at row + 90 / 180ms. The
   longest device in the corpus (13-row matrix, 5 columns) lands its last
   stud at ~1.95s. */

/* ---------- pre-state ---------- */
.cz-dev[data-reveal]:not(.visible) .cz-dev__draw {
  stroke-dashoffset: 1400;
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__row {
  opacity: 0;
  transform: translateY(6px);
}

/* Two row modifiers deliberately carry no rule of their own: cz-dev__row--end
   (the flow's terminal row) and cz-dev__row--branch (a tree branch) arrive
   exactly as any row does, from 6px below. Only the fork and the stair have
   their own direction. */
.cz-dev[data-reveal]:not(.visible) .cz-dev__row--fork {
  transform: translateX(-10px);
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__row--stair {
  transform: translateX(-12px);
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__stamp {
  opacity: 0;
  transform: scale(1.35);
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__sched {
  opacity: 0;
  transform: translateX(8px);
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__ordinal,
.cz-dev[data-reveal]:not(.visible) .cz-dev__letter {
  opacity: 0;
  transform: translateY(4px);
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__label--a,
.cz-dev[data-reveal]:not(.visible) .cz-dev__label--b {
  opacity: 0;
}

.cz-dev[data-reveal]:not(.visible) .cz-dev__arrowhead {
  opacity: 0;
}

/* The dashed track and the column washes cannot draw on; they fade. */
.cz-dev[data-reveal]:not(.visible) .cz-dev--timeline .cz-dev__ground,
.cz-dev[data-reveal]:not(.visible) .cz-dev--matrix .cz-dev__ground,
.cz-dev--timeline[data-reveal]:not(.visible) .cz-dev__ground,
.cz-dev--matrix[data-reveal]:not(.visible) .cz-dev__ground {
  opacity: 0;
}

/* ---------- Beat A: the ground draws ----------
   1400u of dash covers the longest line-work in the corpus with room in hand;
   a constant 1.2s over 1400u means every rule draws at the same speed, so a
   short flow finishes early and a long matrix header takes its time. The
   :not() guard is belt and braces for the one path whose dasharray is
   PHP's: the timeline track is never a draw path, and if it ever were, this
   rule must not erase its dashes. */
.cz-dev__draw:not(.cz-dev__track) {
  stroke-dasharray: 1400;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 1.2s linear;
}

.cz-dev__ground {
  transition: opacity .4s var(--dev-ease);
}

/* ---------- Beat B: the rows arrive ---------- */
.cz-dev__row {
  --cz-row-delay: calc(180ms + var(--cz-i, 0) * 80ms);
  transition:
    opacity .5s var(--dev-ease),
    transform .6s var(--dev-ease);
  transition-delay: var(--cz-row-delay);
}

.cz-dev__row--1  { --cz-i: 0; }
.cz-dev__row--2  { --cz-i: 1; }
.cz-dev__row--3  { --cz-i: 2; }
.cz-dev__row--4  { --cz-i: 3; }
.cz-dev__row--5  { --cz-i: 4; }
.cz-dev__row--6  { --cz-i: 5; }
.cz-dev__row--7  { --cz-i: 6; }
.cz-dev__row--8  { --cz-i: 7; }
.cz-dev__row--9  { --cz-i: 8; }
.cz-dev__row--10 { --cz-i: 9; }
.cz-dev__row--11 { --cz-i: 10; }
.cz-dev__row--12 { --cz-i: 11; }
.cz-dev__row--13 { --cz-i: 12; }
.cz-dev__row--14 { --cz-i: 13; }

/* The timeline's duration chip slides in from the right, late, so the
   schedule column is the last thing to settle on each row. */
.cz-dev__sched {
  transition:
    opacity .4s var(--dev-ease),
    transform .5s var(--dev-ease);
  transition-delay: calc(var(--cz-row-delay, 180ms) + 260ms);
}

/* The compare's values: attribute, then A, then B. */
.cz-dev__label--a,
.cz-dev__label--b {
  transition: opacity .5s var(--dev-ease);
}

.cz-dev__label--a {
  transition-delay: calc(var(--cz-row-delay, 180ms) + 90ms);
}

.cz-dev__label--b {
  transition-delay: calc(var(--cz-row-delay, 180ms) + 180ms);
}

/* ---------- Beat C: gold lands ----------
   transform-box: fill-box makes the scale run about the stud's own centre
   rather than the SVG origin; without it a 1.35x scale would fling every
   stud toward the bottom right. --dev-ease-out so the stamp decelerates into
   place rather than easing symmetrically: it lands. */
.cz-dev__stamp {
  transform-box: fill-box;
  transform-origin: center;
  transition:
    opacity .25s var(--dev-ease-out),
    transform .35s var(--dev-ease-out);
  transition-delay: calc(var(--cz-row-delay, 180ms) + 220ms + var(--cz-c, 0) * 60ms);
}

.cz-dev__c--1 { --cz-c: 0; }
.cz-dev__c--2 { --cz-c: 1; }
.cz-dev__c--3 { --cz-c: 2; }
.cz-dev__c--4 { --cz-c: 3; }
.cz-dev__c--5 { --cz-c: 4; }

/* ============================================================
   DARK GROUND
   ============================================================
   A device inside a dark section inverts through the same properties. Every
   line and wash is mixed from --dev-ink-w, so re-pointing the ink and the
   warm source re-points all of them; there are no fills left to invert, so
   there is no second set of rules. */
.cz-dark .cz-dev,
.section--dark .cz-dev,
.cz-stat .cz-dev {
  --dev-ink: #fff;
  --dev-mute: color-mix(in srgb, var(--dev-ink) 62%, transparent);
  --dev-mid: color-mix(in srgb, var(--dev-ink) 76%, transparent);

  /* One number for the count on both grounds, so a device lifted into a dark
     strip is the same device (R1). Light gains ground faster than ink loses
     it, so the same 50% buys more on the dark side — about 4.9:1 of white on
     the near-black panel against 3.49:1 of ink on paper — and that headroom is
     well spent, because a numeral is where a thin stroke suffers most. It was
     26%, which was set to match an 18% paper value that could not be read. */
  --dev-ghost: color-mix(in srgb, var(--dev-ink) 50%, transparent);

  /* The ground is the SECTION's, not the device's — there is no panel to
     re-point any more, only the colour the scroll fades dissolve into. */
  --dev-ground: var(--cz-panel, #0b0c0e);
  --dev-accent: var(--cz-gold, #c7a36b);

  /* THE COOL FAMILY, INVERTED. On paper the cool is a dark petrol under warm
     gold; here it has to be LIGHT to exist at all, so it is white carried
     toward --navy: a steel that is unmistakably not the white of the type.
     6.5:1 and 10:1 on the section's own ground. The whole rank ramp is
     written against --dev-cool-deep and --dev-accent, so re-pointing these
     two re-points the ladder as well. */
  --dev-cool: color-mix(in srgb, var(--dev-ink) 55%, var(--navy, #071d2e));
  --dev-cool-deep: color-mix(in srgb, var(--dev-ink) 68%, var(--navy, #071d2e));

  /* THE WARM SOURCE FLIPS WITH THE GROUND. On paper the warmth is carried into
     the ink by --cz-gold-ink; here every line is made of light, so it is
     carried by the light gold: 14% of --cz-gold in white is a warm off-white,
     and the rules mixed from it read as a lamp, not a tube. */
  --dev-warm: var(--cz-gold, #c7a36b);
  --dev-ink-w: color-mix(in srgb, var(--dev-ink) 86%, var(--dev-warm));

  /* The one property that does NOT invert. A shadow is black in both worlds,
     and the stud's 0.75px contact shadow is the last one in the file. */
  --dev-shade: #000;
}

/* A device inside a dark callout keeps the callout's own ground under its
   fades and gives up the right to break the measure — the callout has already
   set its width and an exhibit hanging out of it would hang out of a padded
   box, which is the very thing this pass removed. */
.cz-stat .cz-dev {
  --dev-ground: var(--cz-panel-2, #101114);
  --dev-f: 100%;
}

/* ============================================================
   PHONE
   ============================================================
   The phone block that lived here set a fixed 18px/12px pad on the panel.
   There is no panel and there is no pad, so it is gone rather than
   re-tuned — R7 is satisfied by the SCALE, not by a frame: the SVG is pinned
   to 749px at every width below ~772px, so the smallest label renders at
   12.48px on a 375px phone exactly as it does at 621px, and the drawing
   scrolls inside its own box (R42's sanctioned pattern for a matrix that
   genuinely cannot compress).

   Air, however, does need tightening: the desktop clamp bottoms out at 44px,
   which is right beside a 730px measure and generous beside a 343px one. */
@media (max-width: 620px) {
  .cz-dev {
    margin-block: 34px;
  }
}

/* ============================================================
   REDUCED MOTION AND PRINT
   ============================================================
   main.js adds .visible before observing under prefers-reduced-motion, and
   main.css:333 clamps every duration to .01ms. This block is the third lock:
   with the script absent and main.css:690 forcing the figure opaque, every
   pre-state above would otherwise leave an empty panel. So the finished
   drawing is restated for the not-yet-visible state, property by property.

   NEVER `opacity: initial` on `*` here — it would wipe the ladder's ramp
   attribute. Only the classes that carry a pre-state are named, and the
   ladder's rules are not among them. The ladder's top ordinal no longer
   carries an opacity of its own, so the `opacity: 1` above is now the whole
   of its restatement and the two overrides that used to pin it to .55 are
   gone with it. */
@media (prefers-reduced-motion: reduce) {
  .cz-dev,
  .cz-dev * {
    transition: none !important;
    animation: none !important;
  }

  .cz-dev[data-reveal]:not(.visible) :is(
    .cz-dev__row,
    .cz-dev__stamp,
    .cz-dev__sched,
    .cz-dev__ordinal,
    .cz-dev__letter,
    .cz-dev__label--a,
    .cz-dev__label--b,
    .cz-dev__arrowhead,
    .cz-dev__ground
  ) {
    opacity: 1;
    transform: none;
  }

  .cz-dev[data-reveal]:not(.visible) .cz-dev__draw {
    stroke-dashoffset: 0;
  }
}

@media print {
  .cz-dev[data-reveal]:not(.visible) :is(
    .cz-dev__row,
    .cz-dev__stamp,
    .cz-dev__sched,
    .cz-dev__ordinal,
    .cz-dev__letter,
    .cz-dev__label--a,
    .cz-dev__label--b,
    .cz-dev__arrowhead,
    .cz-dev__ground
  ) {
    opacity: 1;
    transform: none;
  }

  .cz-dev[data-reveal]:not(.visible) .cz-dev__draw {
    stroke-dashoffset: 0;
  }
}
