/* GENERATED by scripts/build-brand-css.js — do not edit by hand.
 * Source: design/etpl-cricket/tokens.css
 * Brand:  brands/etpl/brand.json
 *
 * Regenerate after either of those changes:
 *   node scripts/build-brand-css.js etpl design/etpl-cricket/tokens.css
 */
/* =========================================================================
   ETPL cricket vertical: token system
   REVISED 2026-08-17. ETPL IS THE BRAND; DIG IS THE SUBSTRATE.
   =========================================================================

   The mandate changed twice and this is the third and final position: the
   customer-facing brand is the T20 New Cricket League, the way Storyteller is
   its own brand on DIG technology. The cyan ramp this file used to carry is
   dead. So is the DIG-orange reversal. Both were reasoned about DIG.

   Every colour below is measured off the league's own artwork or derived from
   it in OKLCH. Two values are the artwork itself, unmodified:

     primary-100  #ecece8   the wordmark    (measured, L .942 C .005 H 106.5)
     primary-500  #e3f30f   the griffin     (measured, L .921 C .206 H 114.5)

   Full working, contrast tables and the costings are in
   docs/cricket/01-design.md §13.

   THE ONE RULE THAT DEFINES THIS PALETTE
   --------------------------------------
   The chartreuse never sits on the ground as an area or as type. On #000000 it
   appears only as a line 2px or thinner (the focus ring, the ribbon's leading
   edge). Everywhere else it is ink on the blue field, or a fill carrying dark
   ink. Chartreuse headlines, chartreuse eyebrows, chartreuse panels on black:
   none of them exist here. This is the entire difference between this design
   and the "near-black plus one acid accent" archetype, and #e3f30f is 17.09:1
   on black, which is brighter than the body text and is the hazard pairing.

   SOURCE TAGS. Five, and no sixth.

     [house]    Already exists. apps/client-web/tailwind.config.js or
                packages/ui-client-web/globals.css. Unchanged by this design.

     [brand]    brands/etpl/brand.json -> scripts/apply-brand.js ->
                brand.generated.js -> tailwind.config.js `colors.primary`.
                No schema change; only the values are ETPL's.

     [brand-css] brands/etpl/web/brand.css, a per-brand :root override sheet.
                NEW MECHANISM, costed in 01-design.md §13.7. apply-brand.js
                already copies brands/<BRAND>/web/** into public/, so this
                costs one <link> in _app.tsx and an empty file for the other
                three brands. It is where the field lives, because the field
                is a surface family and not an accent, and brand.json is
                deliberately one accent ramp per brand.

     [data]     Per-entity value from the database (teams.displayColor),
                applied at runtime as an inline custom property on the element.
                No build coupling. See contract.md C3.

     [new-css]  A new declaration in a stylesheet. Two destinations:
                  (a) packages/ui-client-web/globals.css @layer base
                      -> house-level, ships to every brand
                  (b) packages/ui-client-web/components/cricket/Cricket.css
                      -> cricket only, mirroring components/rail/Rail.css

   CHANGES THIS DESIGN REQUIRES OUTSIDE ITS OWN FILES
     tailwind.config.js .......... none
     brand.json schema ........... none
     apply-brand.js .............. none
     _app.tsx .................... two lines, once, and never again:
                                     a <link> to /brand.css
                                     four font paths renamed to role names
     public/fonts/ ............... renamed to role names and converted to
                                   woff2. DIG and Storyteller render
                                   identically and ship ~6MB less.
   ========================================================================= */

:root {
  /* -----------------------------------------------------------------------
     1. GROUND, FIELD AND INK
     The ground stays #000000. Not for the sightscreen reason given in the
     first draft, which was a rationalisation and is withdrawn: this is a video
     player wrapped in a page, and on an OLED panel a letterboxed 16:9 stream
     on #000000 has no seam while on the demo's #0E0F14 every match page gets a
     visible rectangle around the video. The demo's near-blacks measure 1.10:1
     and 1.14:1 against pure black, which is a difference nobody can see, and
     buying it would cost a change to globals.css for every brand.

     The atmosphere those near-blacks were reaching for is real and wanted. It
     is bought with the FIELD instead: the league's deep blue, 1.16:1 to 2.04:1
     against black, ten times the effect for zero house cost, and it is what
     makes the chartreuse usable at all. Chartreuse on the field is 8.39:1 and
     near-complementary (hue 114.5 against 264.3); chartreuse on black is
     17.09:1 and reads as hazard tape.

     INK IS THE BRAND'S OWN. The house neutrals are a COOL blue-grey (OKLCH hue
     251 to 257) chosen against an orange accent. Against a chartreuse accent
     they read as inherited rather than chosen. So cricket's ink comes from the
     ramp's light half, which lands on the wordmark's measured off-white. No
     neutral-* change, no third ramp, no zinc-*.

     ⚠️ THE NEUTRALS ARE WARM, AND THAT IS THE POINT.
     They were a blue-biased slate: measured, every step sat at 214-220° hue at
     15-20% saturation, while the brand's accent is 64° and the wordmark's ink
     is 60°. A design review read the result exactly as it measured — "every
     card is a cool slate-blue-grey sitting on pure black under a warm maroon
     hero and yellow ETPL mark". A neutral that disagrees with the brand's own
     hue reads as unconsidered.

     Every step is 60° at 5.5% saturation, so the neutrals agree with the
     brand's own hue instead of arguing with it.

     ⚠️ AND THE STEPS ARE WIDE ENOUGH TO SEE.
     Warming them fixed the hue and left them flat: a card differed from the
     page behind it by 1.109:1, and Mike read the body as "still FLAT DARK"
     under a hero that had all the energy. A step that small is invisible on
     most screens in a lit room, which is the same fault this file started with
     and only half-fixed. The card now stands at 1.257:1 off the ground, with
     the hairline at 1.484:1 off the card, so a card is an object rather than a
     slightly different black. The off-white ink on a card is 12.49:1 and
     --ink-secondary 7.10:1, both far clear of AA.
     ----------------------------------------------------------------------- */
  /* DIRECTION B — BROADCAST. Mike's pick, 2026-08-19.
     The ground comes off pure black. Measured, the old surface scale stepped
     1.02:1 between a card and the page behind it — a 2% luminance difference,
     which most screens in a bright room do not show at all. That is what read
     as "dark and flat", and it is why the surfaces only ever separated when
     they had a translucent edge to give them away. Every step below is opaque
     and the scale now spans 1.22:1 instead of 1.10:1. */
  --ground:            #050E3A;                    /* [etpl-blue] the page. The league blue held at the graphite ground's exact luminance (.0064), so every contrast the ladder was tuned for survives the hue change · ink #ecece8 on it 15.69:1 */

  --field:             #0122C5;                    /* [brand-css] the league blue · L .396 C .242 H 264.3 · 2.04:1 on black · masthead, brand moments */
  /* [dir-b] The brand as a PLATE rather than a block.
     --field at full strength across a full-bleed band was read by a design
     review as "a saturated near-primary blue ... the single loudest element on
     a page whose identity is black + acid-lime ... it reads as an unstyled
     framework block", with the fix stated as "a brand colour at low chroma, not
     stock blue". This is the same blue mixed 40% into the page ground: same
     family, luminance 0.0149 against --field's 0.0518, and it still steps
     1.15:1 clear of the ground so it reads as a plate. Ink on it is 13.65:1 and
     the chartreuse 13.16:1, so the accent stays the loudest thing — which is
     the point. It is also the right base for a photograph to sit on. */
  --field-plate:       #0c1959;
  --field-deep:        #0200A2;                    /* [brand-css] L .322 · 1.52:1 on black · full-bleed brand bands, the auth page ground */
  /* ⚠️ THESE TWO ARE PRE-B AND ARE NOT THE SURFACE SCALE.
     They are the old navy panel tokens. Direction B replaced the surfaces with
     the warm-neutral ladder above (--surface-card / --surface-raised), and
     anything that paints with these renders a saturated blue block on a
     near-black page — which is how the highlights rail came to be described as
     "an unstyled default block dropped onto the page". They survive for exactly
     two documented uses: --ribbon-ground, and the crest contrast gate below.
     Do not reach for them for a panel. */
  --surface-2:         #01007D;                    /* [brand-css] L .267 · 1.30:1 on black · raised panel. Replaces neutral-800 on cricket surfaces */
  --surface-1:         #01005E;                    /* [brand-css] L .218 · 1.16:1 on black · panel, card, table row. Replaces neutral-900 */

  --ink:               #FFFFFF;                    /* [house] colors.white · reserved for the score figure and nothing else */
  --ink-body:          #ecece8; /* [brand] #ecece8 · THE WORDMARK, MEASURED · 17.73:1 on black, 8.71:1 on the field */
  --ink-muted:         #ebecd5; /* [brand] #ebecd5 · labels and metadata. Use at 68% alpha on black for 12.6:1, or solid on the field */
  --ink-quiet:         #828282; /* [house] #828282 · 5.46:1 · NON-TEXT ONLY: the unfilled ribbon tick, disabled marks */
  /* Secondary TEXT. --ink-quiet above is a mark colour and says so, but it was
     carrying eyebrows, captions, labels, notes and table headers across the
     whole cricket surface — twenty-six rules of text painted in the one colour
     the system reserves for non-text. This is --ink-muted at the 68% its own
     note prescribes for a black ground: 12.6:1 rather than 5.46:1. */
  /* 0.72, not 0.68. The design uses exactly two muted steps — this one for
     text, --ink-quiet for marks — and a reviewer measuring the rendered pixels
     found the text step reading as disabled next to body copy on more than one
     surface. Small caps and 14px labels lose apparent contrast that a
     paragraph does not. */
  --ink-secondary:     rgb(235 236 213 / 0.72);
  --scrim:             #00000085;  /* [house] #00000085 · the media-details overlay scrim */

  /* Hairline separation, tinted to the field rather than to white. A white
     hairline on a blue panel reads as a cut; a hairline of the field's own
     lighter neighbour reads as a fold. Borderless ladder first: whitespace,
     then --lift-1, then --elev-2, and only then one of these. */
  /* Edges are warm neutral, not blue.
     These four were a saturated league blue at low alpha, and because they are
     every 1px rule, every card edge, every table row and every hover on the
     cricket surfaces, that blue was the single biggest thing on screen — a
     grid of navy outlines that read as an unstyled default rather than as a
     premium sports product. On a black ground a low-alpha warm white separates
     just as well and asks for no attention at all, which leaves the one real
     colour on the page — the griffin yellow, and each club's own — free to
     mean something. Struck from --ink-muted (#ebecd5) so the edges sit in the
     same warm family as the type rather than in a second, greyer one. */
  /* Opaque, every one of them.
     These were alpha over the ground, and a low-alpha panel on a dark page is
     what reads as frosted glass — the house style of every AI-generated
     interface, and the thing this design must not be mistaken for. The values
     are the exact colours those alpha stacks already produced over black, so
     nothing shifts: a surface is now a colour rather than a veil, and depth
     comes from the step between surfaces plus a deliberate edge. */
  /* [etpl-blue] Struck from the ink into the new ground rather than from the
     old warm family, so the edges sit in the blue system. They are NOT the
     league blue: a saturated blue on every rule is the navy-outline grid that
     the note above was written about, and moving the ground to blue makes that
     failure easier to fall into, not harder. These stay quiet. */
  --rule-hairline:     #34406E;   /* [etpl-blue] 1px rules, table rows, card edges · 1.48:1 off the card, which is dir-b's own figure */
  --rule-strong:       #4E5B8A;   /* [etpl-blue] the qualification cut line */
  --lift-1:            #0D1643;   /* [etpl-blue] the ground shift that separates without a border */
  --lift-2:            #1A2451;   /* [etpl-blue] hover ground shift */

  /* The surface scale. A card is one of these, not a gradient over the page.
     ⚠️ --surface-card is duplicated in JavaScript, in two places that blend a
     club's colour to an opaque value over it: teamColour.ts (web) and
     packages/shared/src/cricket/teamAccent.ts (native). color-mix cannot do
     the job — it drops the whole declaration where unsupported, taking the
     background with it — so the blend happens in JS and the constant has to be
     moved by hand. Change this and change those. */
  /* [etpl-blue] The same three steps, in the league's blue at the SAME
     luminances the graphite ladder used (.0108 / .0210 / .0327). Opaque, still
     — the no-veil rule above is the one thing that must not change, because a
     translucent blue panel is frosted glass whatever colour it is. What does
     change is that a card is now the brand rather than a neutral, which is
     what makes the crest plates and the photograph read as one system.
     Team tints were ALREADY gated against a blue panel of this luminance
     (--team-gate-ground, measured against #01007D), so no club moves. */
  /* ⚠️ LOW CHROMA, AND THAT IS THE WHOLE POINT — measured on screen, twice.
     The first attempt at this put the league blue itself on the surface scale
     (#041154 / #03177C / #021C9D). It is the value the original token file
     proposed and it is wrong for the same reason the note at the top of .etpl-card
     already records: as the fill of every card on a page, a saturated blue is a
     wall of navy, which is the "dated unstyled blue" this design exists to avoid.
     A screenshot of the fixture list settled it — thirty bright blue slabs.
     These are the ground lifted toward a COOL off-white instead: the same blue
     family, the same luminance ladder (1.076 / 1.256 / 1.463 off the ground,
     against dir-b's 1.257 target for a card), a fraction of the chroma. The
     league blue stays where it belongs — the bands, the hero, the crest plates
     and the gold's ground — rather than on every rectangle. */
  --surface-sunken:    #0D1643;   /* [etpl-blue] a panel that sits back: the table's own ground · ink 14.58:1 */
  --surface-card:      #1A2451;   /* [etpl-blue] the standard card, panel and modal · ink 12.49:1 */
  --surface-raised:    #25305D;   /* [etpl-blue] hover, and a card that leads · ink 10.72:1 */

  /* [dir-b] The tile a crest sits on inside its club-colour plate.
     DARK, and that is the whole point — measured twice.

     This was near-white, on the argument that a dark badge needs something
     light to be dark against. It made every crest the brightest object on its
     page: a real-browser design review failed all sixteen captured surfaces
     and named it on every one — "raw square assets with baked-in white boxes",
     "six garish light blocks punched out of a black page", "a container, not
     content". The crests are not the problem; all six ship with a real alpha
     channel (measured: corner alpha 0 on every file). The white box was this
     token.

     Measured mean luminance of each badge's opaque pixels, as contrast against
     the three candidate plates:

                     on club colour   on this dark   on near-white
       Amsterdam         1.52            4.27           4.05
       Belfast           1.46            3.10           5.58
       Dublin            1.27            3.36           5.15
       Edinburgh         1.76            6.87           2.52
       Glasgow           1.22            5.25           3.30
       Rotterdam         2.94            2.82           6.14

     Straight onto the club's own colour is the worst of the three and is out.
     Between dark and near-white there is no winner on the numbers — each is
     best for three clubs — so the tie breaks on what the page looks like, and
     a dark tile is the one that does not put six bright rectangles on a dark
     page. Rotterdam is the weakest at 2.82, and it is carried by the gold ring
     around its badge rather than by its mean. */
  --crest-tile:        #050E3A;   /* [etpl-blue] follows --ground, which is what it was: the tile is the page showing through the plate */

  /* -----------------------------------------------------------------------
     2. THE ETPL PRIMARY RAMP  [brand]
     brands/etpl/brand.json -> colors.primary. Reaches Tailwind as
     `primary-50` ... `primary-900` and CSS as --brand-primary /
     --brand-primary-hover / --brand-on-primary (already in globals.css).

     THE RAMP HAS AN UNUSUAL SHAPE AND THE SHAPE IS DELIBERATE.

     Above 500 it is a CHROMA ramp, not a lightness ramp. #e3f30f sits at
     OKLCH L 0.921 against a gamut ceiling of chroma 0.207 on its own hue: the
     league did not pick a bright yellow-green, it picked the one sRGB cannot
     exceed. There is no headroom. The whole span from #e3f30f to white is 8%
     of the lightness range and the chroma envelope collapses inside it. So
     steps 50 to 400 hold lightness roughly flat and DROP CHROMA, landing on
     the wordmark's own measured off-white. Below 500 the ramp behaves
     normally, holding hue and dropping lightness into a deep moss.

     This is what keeps the house rule working. Tabs.tsx says 400 for text on
     black and 500 for fills, and primary-400 has 39 uses in the web client,
     almost all underlined links on wallet and auth surfaces. At full
     chartreuse those are highlighter pen. At #e3ea9e they are a soft
     chalk-lime at half the accent's chroma and they read as warm-bright.

     Note 400 sits 0.007 BELOW 500 in lightness. That is not a mistake and it
     is imperceptible (16.53:1 against 17.09:1). What is perceptible is the
     chroma: 0.097 against 0.206. Soft for text, full for fills.
     ----------------------------------------------------------------------- */
  --primary-50:        #f7f7f4;   /* [brand] #f7f7f4 · 19.57:1 on black · paper. The lightest thing in the system */
  --primary-100:       #ecece8;  /* [brand] #ecece8 · 17.73:1 · THE WORDMARK, MEASURED, UNMODIFIED · body ink */
  --primary-200:       #ebecd5;  /* [brand] #ebecd5 · 17.49:1 · quiet ink, labels, metadata */
  --primary-300:       #e8ecbf;  /* [brand] #e8ecbf · 17.18:1 · link hover (house uses primary-300 for hover text, 8 places) */
  --primary-400:       #e3ea9e;  /* [brand] #e3ea9e · 16.53:1 · LINK TEXT. The house rule, and it survives because this step is chalk, not acid */
  --primary-500:       #e3f30f;  /* [brand] #e3f30f · 17.09:1 · THE GRIFFIN, MEASURED, UNMODIFIED · fill, focus ring, live edge */
  --primary-600:       #cbd900;  /* [brand] #cbd900 · 13.46:1 · hover fill (house uses primary-600, 28 places) */
  --primary-700:       #9da800;  /* [brand] #9da800 ·  8.03:1 · deep mark. WHITE ON IT IS 2.61:1, so never set white type here */
  --primary-800:       #737c00;  /* [brand] #737c00 ·  4.61:1 · panel. White on it is 4.55:1 */
  --primary-900:       #4f5500;  /* [brand] #4f5500 ·  2.63:1 · deepest panel (auth uses bg-primary-900/30) */

  /* Semantic aliases. ONE COLOUR, ONE MEANING, and the meaning is the merge of
     the two the previous draft kept apart. Cyan meant "you can act on this"
     and the chartreuse meant "the league is playing". On a live T20 portal
     those are the same message: the live match IS the call to action. So:

       field       #0122C5   THIS IS ETPL          masthead, panels, cards
       chartreuse  #e3f30f   ACT / IT IS HAPPENING button, focus ring, the ball
       team tint   per club  WHO                   crest fill, ribbon ticks
       off-white   #ecece8   READING               body ink
       no chroma   -         IT DID NOT COUNT      abandoned, no result

     Scarcity is still the entire discipline, and it is tighter now than it was
     with two colours: AT MOST TWO CHARTREUSE MARKS PER VIEWPORT. The brand's
     presence on the page is carried by the field, which is why the accent does
     not have to carry it. */
  /* [etpl-blue] THE GOLD. Added 2026-08-19 on Mike's direction: royal blue and
     gold is the league's presentation, and with the ground now blue the accent
     that has to sit on it is a warm one.

     Measured, on the values above:
       #FFC845 on --ground   12.03:1      on --surface-card   9.59:1
       #FFC845 on --field     6.68:1      black on #FFC845   13.60:1
     So it is legible as type on every ground in the system and takes dark ink
     as a fill, which is what a CTA needs.

     ⚠️ ONE MEASURED EXCEPTION, RECORDED RATHER THAN HIDDEN. The team gate asks
     for dE-OK >= 0.14 between the accent and any club tint. Rotterdam Dockers'
     tint is #c8a858 — the anchor gold off their own crest — and the separation
     is 0.126. No gold clears the floor against a gold club; the search ran
     fifteen candidates and #FFC845 is the furthest of them while still reading
     as gold rather than as amber. Moving a club off its published colour to
     make room for a decorative accent is the wrong trade, so the club keeps
     #c8a858 and the shortfall is accepted here, in writing. It is survivable
     because the two never carry the same role: Rotterdam's gold appears as
     crest artwork and its own plate, the accent appears as type, rule and
     button fill. */
  --gold:              #FFC845;
  --gold-deep:         #E0A61F;   /* [etpl-blue] hover and pressed · black on it 9.94:1 */

  --action:            var(--gold);                 /* [etpl-blue] primary button fill · was the chartreuse */
  --action-hover:      var(--gold-deep);            /* [etpl-blue] primary button hover fill */
  --action-label:      #12100A;   /* [etpl-blue] COMPUTED against #FFC845, not chosen: 13.34:1. White would be 1.32:1 and invisible */
  --focus:             var(--primary-500);          /* [brand] the griffin chartreuse, and ONLY here — 2px of it, which is the one use the palette's own rule allows */
  --link:              var(--gold);                 /* [etpl-blue] always underlined; see --link-hover */
  --link-hover:        var(--gold-deep);           /* [etpl-blue] HOVER IS CARRIED BY THE UNDERLINE first; this shift is the second signal. contract.md C1 */

  /* -----------------------------------------------------------------------
     2b. RETIRED  [was: the league colour as a separate token]
     --league / --league-ink / #e0f837 are GONE. That value was a flattened
     approximation of the lockup, invented only because the real colour could
     not go into the ramp while the ramp was cyan. The ramp is the league's
     now, so #e3f30f goes in it unmodified and the approximation is retired.

     Anything that referenced --league references --primary-500.
     ----------------------------------------------------------------------- */
  --live-edge:         var(--primary-500);          /* [brand] the ball just bowled. Distinguished by FORM first: it is the only mark that breaks the baseline. See section 9 */
  --live-trail:        rgb(227 243 15 / 0.42);      /* [new-css](b) the five balls behind it, decaying toward the team tint */

  /* Semantic state stays separate from brand identity.
     Cricket uses neither of these as a state signal (see brief.md §4.3): a
     result is carried by weight, position and a sentence, and a no-result is
     carried by the ABSENCE of chroma. They are declared so nothing invents
     its own. */
  --positive:          #4ADE80; /* [house] #4ADE80 · not used by the cricket state system */
  --warn:              #d9a441;                     /* [new-css](b) rain and delay only. 8.0:1 on black. Used once, on the interrupted state */

  /* -----------------------------------------------------------------------
     3. TEAM TINTS  [data]
     Six franchises, one primary ramp. The ramp is the LEAGUE and is never a
     team; team colour never uses the ramp.

     REVISED 2026-08-16. The six official crests replaced the placeholders,
     and they killed the old "two tiers, common chroma, 45 degrees" band.
     Two things it got wrong against real data:

       1. 45 degrees is the wrong metric. A degree of hue is worth far more
          perceptual difference at high chroma than at low. Amsterdam's
          scarlet and Edinburgh's magenta sit 21.6 degrees apart and read as
          obviously different colours; Belfast's cyan and the accent sit 19.7
          apart and read as the same colour. Degrees cannot tell those two
          cases apart. Perceptual distance can. The gate is now dE-OK,
          Euclidean distance in OKLab.
       2. Flattening every club to one chroma erased the thing it claimed to
          preserve. Amsterdam is a loud club with a loud red and Rotterdam is
          a restrained club with a metallic gold; at a common chroma they
          become the same kind of colour wearing different hues.

     THE RULE, in four steps, so a seventh club can be added without me:

       1. SOURCE. Take the crest. Drop pixels below chroma 0.045 (black
          keylines, white, greys). Merge the rest into hue groups within 22
          degrees. Rank groups by share x chroma, the colour MASS of the
          mark. The winning group's modal flat bucket is the source colour.
          This is the value stored, and nothing else from the crest is.
       2. GATE. If the source clears 3:1 against --surface-2 (the darkest
          ground a tint sits on, and the WCAG 1.4.11 threshold for a
          graphical object), USE IT UNCHANGED. Four of six do.
       3. LIFT. If it fails, raise OKLCH lightness along its own hue until it
          clears with margin, applying a chroma floor of 0.10 so a near-grey
          source still reads as a colour. Hue is never touched.
       4. SEPARATE. If any two display values, or a display value and the
          accent, or a display value and the live edge, are closer than
          dE-OK 0.14, move the one with the most headroom, on LIGHTNESS
          only. Never on hue.

     Why 0.14. Calibrated against pairs whose readability is not in dispute:
     pure red vs pure orange is 0.172, blue vs cyan 0.127, green vs teal
     0.094, two greys one step apart 0.007. 0.14 sits above "tight but
     nameable" and below "obvious", which is right for a 2px mark.

     Achieved across all 15 pairs: min 0.149, max 0.361.

     The database stores the source colour and the display value it produced,
     not a hue integer. Storing the hue alone was a mistake: it cannot express
     "this club's colour was good enough to use untouched", which is the
     answer for four of the six and the only answer a franchise wants to hear.
     See 01-design.md §12 and contract.md C3.

     Applied as an inline custom property on the element:
       <article style={{ "--team": team.displayHex }}>
         <span className="bg-[var(--team)]" />
     ----------------------------------------------------------------------- */
     REVALIDATED 2026-08-17 against the chartreuse accent and the blue field.
     ALL SIX VALUES ARE UNCHANGED and the margins improved. The flagged risk
     was Rotterdam's gold against a chartreuse accent; it measures dE-OK 0.215,
     comfortably clear of the 0.14 gate (hue 87.9 against 114.5, but 0.18 apart
     in lightness and half the chroma). Belfast, which was the tight case
     against the cyan at 0.147, is now 0.431 from the accent and its
     provisional value is under no pressure from the palette at all.

       team to accent, minimum   0.215  (Rotterdam)   was 0.147 (Belfast)
       team to team, minimum     0.149  (Ams/Edin)    unchanged
       team to field, minimum    0.253  (Belfast)     new gate, clears
       worst panel contrast      3.33   (Edin on --surface-2)

     MEASURED LIMIT, STATED RATHER THAN HIDDEN. Three tints fail 3:1 against
     the FULL-STRENGTH FIELD: Belfast 2.47, Dublin 2.33, Edinburgh 2.12. So
     TEAM COLOUR NEVER APPEARS ON --field. This costs nothing, because team
     colour already appears in exactly two places and neither is the masthead.
     ----------------------------------------------------------------------- */
  --team-gate-ground:  3.0;       /* [new-css](b) minimum contrast against --surface-2 (#01007D). WCAG 1.4.11 */
  --team-gate-de:      0.14;      /* [new-css](b) minimum dE-OK: team/team, team/accent, team/field */
  --team-chroma-floor: 0.10;      /* [new-css](b) below this a lifted tint reads as grey, not as a colour */
  --team-max-contrast: 11.0;      /* [new-css](b) ceiling on black, so no club shouts over the other five */
  --team-forbidden-bg: var(--field); /* [new-css](b) the one ground a tint may never sit on. Enforced in contract.md C3 */

  --team:              var(--ink-body);  /* [data] fallback when no team is in scope. Never renders as a colour by accident */

  /* THE SIX. Source measured off the official crest; display is what the rule
     above produced. Where source and display are the same value, the club's
     colour was good enough and we did not touch it. */

  /* Untouched. Source clears the gate and every separation. */
  --team-dublin-guardians:          #128a42;  /* [data] source #128a42 UNCHANGED · 4.74 on black, 4.08 on surface-1, 3.65 on surface-2 · dE .385 to the accent · the castle green, 46% of the crest */
  --team-edinburgh-castle-rockers:  #de0666;  /* [data] source #de0666 UNCHANGED · 4.32 on black, 3.72 on surface-1, 3.33 on surface-2 · dE .493 · the shield magenta. The worst panel case, and it clears */
  --team-rotterdam-dockers:         #c8a858;  /* [data] source #c8a858 UNCHANGED · 9.20 on black, 7.91 on surface-1, 7.09 on surface-2 · dE .215 to the accent, the closest of the six and clear · the anchor gold */

  /* Lifted on lightness only. Hue held to within 0.2 of source. */
  --team-amsterdam-flames:          #ff6459;  /* [data] source #ea2a2a, L .61 -> .70 · 7.22 on black, 5.56 on surface-2 · dE .352 · lifted ONLY to clear dE .149 from Edinburgh's magenta */
  --team-glasgow-cosmic:            #8d8de6;  /* [data] source #1e1e36, L .25 -> .68 · 7.09 on black, 5.46 on surface-2 · dE .411 · the shield field is 1.29:1 on black and cannot be a mark */

  /* Derived, and PROVISIONAL. The Belfast file contains no flat colour to
     take: its largest flat chromatic bucket is 1.1% of the mark at chroma
     0.045, because the crest is a raster render, not vector artwork. This
     value sits at H 223.7, inside the crest's own 195-238 gradient range.
     It must be confirmed with the club before launch. */
  --team-belfast-wolves:            #0087a9;  /* [data] source: none in file · 5.04:1 on black, 3.84:1 on surface-2 · PROVISIONAL, confirm with club */

  /* -----------------------------------------------------------------------
     4. TYPE  [brand-font, new-css roles]
     ARCHIVO. Omnibus-Type, SIL Open Font License 1.1. Four static instances
     cut from the variable family at 300, 400, 600 and 900.

     WHY NOT SF PRO. Three reasons, in order of weight.
       1. It is the operating system's UI font. A league identity set in the
          face the reader's phone draws its settings menu in has no voice.
          On DIG, where the product IS the platform, SF Pro is defensible. On
          a tenant brand it is an absence.
       2. It is 7.06MB. The four OTFs on disk are 2.28 / 2.33 / 2.23 / 0.33MB
          and next/font/local self-hosts local files WITHOUT subsetting, so all
          of it ships. The audience is on a phone on a subcontinent network.
       3. Apple's SF licence covers Apple platforms; embedding it as a webfont
          on a commercial site sits outside it. Flagged for legal, not
          asserted, and it is DIG's exposure today regardless of cricket.

     WHY ARCHIVO. Drawn from 19th-century American grotesques cut for
     high-performance printing: newspapers and signage, which is the ancestry
     of every scoreboard and every county scorecard. Weight axis 100 to 900 and
     a real width axis 62 to 125, so one superfamily gives the display voice,
     the body and the condensed figure columns. On neither the blacklist nor
     the greylist. Open licence, so there is nothing to buy and nothing to
     chase. And it is the direction the league's own demo reached for, so the
     direction is corroborated even though none of its execution is used.

     THE MECHANISM, which does not exist yet. Costed in 01-design.md §13.8.
       - rename apps/client-web/public/fonts/* to role names brand-300,
         brand-400, brand-600, brand-700, all .woff2, converting the SF Pro
         OTFs on the way. DIG and Storyteller render identically, ~6MB lighter.
       - edit the four `path` strings in _app.tsx. ONCE. Never again.
       - add brands/etpl/web/fonts/brand-{300,400,600,700}.woff2 = Archivo at
         300, 400, 600 and 900, the 900 DECLARED IN THE 700 SLOT so font-bold
         renders the poster weight.
       - apply-brand.js needs no change: it already copies
         brands/<BRAND>/web/** into public/, and cpSync overwrites.
       - brand.json gains NO type field. Type is an asset and assets already
         have a mechanism.

     MUST VERIFY ON ARRIVAL. All four SF Pro OTFs were inspected and carry tnum
     and case. Archivo's feature set has not been, because the files are not
     here. tnum is near-certain. IF `case` IS ABSENT the score block does not
     break: ScoreBlock already sets the solidus as its own span (contract C4),
     so the cap-height lift becomes a translateY on that span instead of a font
     feature. Named so nobody discovers it late.

     IF ARCHIVO IS REFUSED: fall back to SF Pro and lose the voice, nothing
     else. Every other token in this file is face-independent.

     Do not use font-medium. Weight 500 has no file in either scheme and its 86
     existing uses synthesise or snap.
     Do not use text-md. It is not a Tailwind class; its 12 uses compile to
     nothing.
     ----------------------------------------------------------------------- */
  --weight-light:      300;   /* [brand-font] Archivo Light. The score at 60px and 96px */
  --weight-body:       400;   /* [brand-font] Archivo Regular. Body, and the fixture spine */
  --weight-strong:     600;   /* [brand-font] Archivo SemiBold. Figures at 30px and below, where Light disappears */
  --weight-bold:       900;   /* [brand-font] Archivo 900, DECLARED IN THE 700 SLOT so `font-bold` reaches it. It has exactly one job: see --scorebug-* below */
  --width-condensed:   62;    /* [brand-font] Archivo wdth axis. Dense figure columns: the scorecard, P/W/L/NR, times. Replaces the third face the demo bolts on */
  --width-normal:      100;   /* [brand-font] everything else */

  /* Text scale. Expressed as Tailwind steps so the builder uses existing
     utilities. Ratio ~1.25, the product register. */
  --text-label:        0.75rem;  /* [house] text-xs   · 12px · sentence case, weight 600, --ink-muted. NEVER letter-spaced uppercase */
  --text-meta:         0.875rem; /* [house] text-sm   · 14px · the house's most-used size, 209 occurrences */
  --text-body:         1rem;     /* [house] text-base · 16px */
  --text-lead:         1.125rem; /* [house] text-lg   · 18px · the chase sentence */
  --text-section:      1.5rem;   /* [house] text-2xl  · 24px */
  --text-rail-head:    1.875rem; /* [house] text-3xl  · 30px · matches the existing rail header at md and up */

  /* Figure scale. A separate, steeper ramp (~1.7x per step) because a score is
     not a heading. Digits only. */
  --fig-inline:        1.5rem;   /* [house] text-2xl · 24px · table cells, scorecard rows */
  --fig-card:          1.875rem; /* [house] text-3xl · 30px · the score on a card in a grid of thirty */
  --fig-page:          3.75rem;  /* [house] text-6xl · 60px · the score on a match page, table points */
  --fig-hero:          6rem;     /* [house] text-8xl · 96px · the score under the player, the winning total */

  /* THE TYPE STRATEGY: figures get lighter as they get bigger.
     Inverted from the default sports treatment, built from the extremes of the
     weight range. A 96px Archivo Light numeral has more presence than a bold
     one. The compensation at small size is real optical correction: at 30px in
     a grid of thirty, Light disappears.

     The inversion is MORE pointed in Archivo than it was in SF Pro, because
     Archivo's 900 is sitting right there and every sports product in the world
     would put the score in it. It goes somewhere else instead. */

  /* THE SCOREBUG. Where the 900 goes, and the one place this design uses a
     weight extreme on letters rather than on figures.

       AMS  178/6
       ^900 ^300

     The three-letter club abbreviation set in Archivo 900, all caps, tracking
     -0.01em, at roughly a third the size of the score beside it. That is 900
     against 300 at a 3x size ratio, executed on the one place in the product
     where cricket's own conventions already do it. It is NOT an uppercase
     eyebrow: AMS is how a scorecard writes Amsterdam. Do not letter-space it,
     do not tint it, do not put it in a pill. */
  --scorebug-mark-weight: var(--weight-bold);   /* [new-css](b) 900 */
  --scorebug-mark-track:  -0.01em;              /* [new-css](b) */
  --scorebug-mark-ratio:  0.33;                 /* [new-css](b) mark size as a fraction of the score beside it */
  --fig-weight-hero:   var(--weight-light);   /* [new-css](b) 96px and 60px -> 300 */
  --fig-weight-page:   var(--weight-light);   /* [new-css](b) */
  --fig-weight-card:   var(--weight-strong);  /* [new-css](b) 30px -> 600 */
  --fig-weight-inline: var(--weight-strong);  /* [new-css](b) 24px and below -> 600 */

  --track-hero:        -0.03em;   /* [new-css](b) 96px figures */
  --track-page:        -0.025em;  /* [new-css](b) 60px figures */
  --track-card:        -0.02em;   /* [new-css](b) 30px figures */
  --track-flat:        0;         /* [new-css](b) 24px and below */

  --leading-fig:       0.9;       /* [new-css](b) figures are set tight; they have no descenders */
  --leading-body:      1.5;       /* [house] the app's effective body leading */
  --measure:           62ch;      /* [new-css](b) body copy measure. The house sets max-w-2xl on .media-description, which is close */

  /* The two feature flags that make cricket numerals work. */
  --figures:           "tnum" 1, "case" 1;    /* [new-css](a) HOUSE LEVEL. Tabular figures + case-sensitive forms so the solidus in 184/6 sits on the lining figures instead of hanging below them */
  --figures-fraction:  "tnum" 1, "case" 1, "frac" 1;  /* [new-css](b) only where a real fraction is set */

  /* -----------------------------------------------------------------------
     5. SPACING  [house]
     Tailwind's default 4px scale, used as-is. The one value that matters more
     than any other is the horizontal gutter, which every section in the app
     shares and which cricket must not break.
     ----------------------------------------------------------------------- */
  --gutter:            2rem;     /* [house] px-8            · the page gutter, mobile */
  --gutter-sm:         2.75rem;  /* [house] sm:px-11        · from 640px */
  --gutter-lg:         3.5rem;   /* [house] lg:px-14        · from 1024px. NOT px-16; the two md:px-16 / lg:px-16 uses in the app are drift */
  --space-1:           0.25rem;  /* [house] 4px  · ribbon tick gap */
  --space-2:           0.5rem;   /* [house] 8px  · over-group gap in the ribbon */
  --space-3:           0.75rem;  /* [house] 12px */
  --space-4:           1rem;     /* [house] 16px · the gap between page blocks (ContentPage uses gap-4) */
  --space-6:           1.5rem;   /* [house] 24px · table row padding */
  --space-8:           2rem;     /* [house] 32px */
  --space-12:          3rem;     /* [house] 48px · between major sections on a match page */
  --space-16:          4rem;     /* [house] 64px */
  --space-40:          10rem;    /* [house] mb-40 · the tail on <main> so the footer never crowds the last rail */

  --header-h:          4rem;     /* [house] h-16 · MenuBar. Fixed, transparent until scroll, then bg-black/90. Nothing compensates for it; the hero is designed to sit under it */

  /* -----------------------------------------------------------------------
     6. RADIUS  [house]
     The house vocabulary, unchanged. Cricket adds one value and it is zero.
     ----------------------------------------------------------------------- */
  --radius-chip:       0.25rem;  /* [house] rounded    · Badge, Quality, the Tabs underline */
  --radius-art:        0.375rem; /* [house] rounded-md · every poster and thumbnail in the app */
  /* [dir-b] Square. B's whole grammar is hard edges — the diagonal, the crest
     plates, the price slab — and a 8px radius on every card underneath that
     reads as a different design showing through. --radius-art (posters) and
     --radius-round (avatars) are untouched: a rounded poster is a poster
     convention, not this design's. */
  --radius-surface:    0;        /* [dir-b] was 0.5rem · Button, panels, cards */
  --radius-round:      9999px;   /* [house] rounded-full · avatars only */
  --radius-ball:       0;        /* [new-css](b) THE RIBBON TICKS HAVE NO RADIUS. A ball is a mark, not a pill. This is the identity detail */

  --poster-ratio:      56.25%;   /* [house] 16:9, the padding-top hack used by Rail and ContinueWatchingRail. Declared once here because FavoriteRail and SearchRail use 49% from the same source asset, which is drift */

  /* -----------------------------------------------------------------------
     7. ELEVATION  [new-css](a) HOUSE LEVEL, values (b) for the tint
     The house has textShadow and no shadow system. Light comes from one
     direction, above. The tinted shadows now use THE FIELD rather than the
     accent, because the accent is a 17:1 near-white and a chartreuse shadow is
     a contradiction: a shadow of a light source that bright is not a shadow.
     Depth belongs to the blue.

     The inset top highlight is the field's lighter neighbour, not white, so a
     raised panel reads as the same material lit from above rather than as a
     grey card with a white edge.

     Deliberately no glow. A luminous ring on a dark ground is the neon-on-dark
     tell and this design does not use it anywhere.
     ----------------------------------------------------------------------- */
  --elev-0:            none;
  --elev-1:            0 1px 2px rgb(0 0 0 / 0.6);
  /* The inset top hairline in these two was a league blue, and every card on
     the cricket surfaces carries --elev-2: a 1px navy rule sat across the top
     of all thirty fixture rows, sampled at rgb(6,28,83) against a palette that
     is otherwise yellow, white and near-black. Recolouring --rule-hairline was
     not enough on its own — the same blue was hiding in the shadow. */
  --elev-2:            0 8px 24px -10px rgb(0 0 0 / 0.8), 0 1px 0 rgb(235 236 213 / 0.08) inset;
  --elev-3:            0 18px 44px -16px rgb(0 0 0 / 0.7), 0 2px 8px rgb(0 0 0 / 0.6);
  --text-shadow:       2px 2px 4px rgb(0 0 0 / 0.45);  /* [house] the textShadow plugin default, used by .media-title and .media-description */

  /* -----------------------------------------------------------------------
     8. MOTION  [new-css](a) HOUSE LEVEL for the tokens and the reduced-motion
     block; cricket-only for --dur-innings.

     The house today: transition-colors with no duration for hovers,
     `transition duration-500 ease-in-out` for the rail card scale,
     `transition ease-in-out duration-300` on Button, 300ms ease in Rail.css.
     No prefers-reduced-motion handling exists anywhere.

     Animate transform and opacity only. Never transition-all (13 uses today).
     ----------------------------------------------------------------------- */
  --dur-1:             120ms;   /* micro: tick state change, focus ring */
  --dur-2:             180ms;   /* default: hover, tint change */
  --dur-3:             240ms;   /* deliberate: panel, state swap */
  --dur-ball:          400ms;   /* the leading edge advancing one ball */
  --dur-innings:       640ms;   /* THE ONE ORCHESTRATED MOMENT: the innings break. See contract.md C2 */
  --ease:              cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-ball:         cubic-bezier(0.16, 1, 0.3, 1);   /* the ribbon advance: fast out, long settle */

  /* -----------------------------------------------------------------------
     9. THE OVER RIBBON  [new-css](b)
     Geometry for the one bold move. Three fidelities of one primitive.
     20 overs of 6 balls. Tick width and height scale; the gaps do not, so the
     over grouping stays legible at every size.
     ----------------------------------------------------------------------- */
  --ball-w-sm:         2px;     /* card in a grid of thirty */
  --ball-w-md:         4px;     /* match page */
  --ball-w-lg:         6px;     /* under the player, interactive */
  --ball-h-sm:         4px;
  --ball-h-md:         12px;
  --ball-h-lg:         28px;
  --ball-gap:          1px;     /* between balls inside an over */
  --over-gap:          4px;     /* between overs. This is what makes 20 groups of 6 readable rather than 120 undifferentiated ticks */
  --ball-4-scale:      1.5;     /* a boundary four tick is 1.5x base height */
  --ball-6-scale:      2;       /* a six is 2x. Magnitude encoded as height, so the ribbon reads as a bar chart of the innings without being labelled one */

  /* The leading edge is distinguished by FORM first and colour second, and
     that stays true under the new palette for a new reason. It was written
     because no edge colour could clear 3:1 against all six team tints (the
     best available against Rotterdam's gold is 1.92:1, which is arithmetic
     rather than a choice). It is now ALSO the thing that lets the edge be the
     brand colour without the ribbon reading as a chartreuse object: the edge
     is 2px, it breaks the baseline, and it is the only chartreuse in the
     component. Colour is the redundant channel, which is the right way round.

     If you are ever asked to change the edge colour, keep the overshoot. */
  --edge-overshoot:    3px;     /* how far the leading edge breaks above and below the tick band */
  --edge-w:            2px;     /* the edge is drawn at a fixed width, never scaled with --ball-w-* */

  --ball-empty:        var(--ink-quiet);       /* #828282 · a ball not yet bowled. Non-text, so 5.46:1 governs nothing here */
  --ball-void:         transparent;            /* a ball that will NEVER be bowled: rain, DLS, abandonment. Absence, not emptiness */
  --ball-batting:      var(--team);            /* [data] the batting side's tint */
  --ribbon-ground:     var(--surface-1);       /* the ribbon sits on a blue panel, never on bare black. This is the rule from the file header applied to the signature component */
  --ribbon-baseline:   var(--rule-hairline);   /* the 1px rule the ticks sit on, so a void still has a line */
  --ribbon-target:     rgb(1 74 255 / 0.55);   /* the ghost of the first innings, drawn behind the chase. Field-tinted, not white: it is a trace of the match, not a UI rule */
  --ribbon-target-w:   1px;
}

/* ===========================================================================
   COMPONENT LAYER
   Destination (a) globals.css @layer base for the house-level rules,
   destination (b) components/cricket/Cricket.css for the rest, following the
   existing components/rail/Rail.css precedent.
   =========================================================================== */

/* --- HOUSE LEVEL (a): ALL FOUR HAVE LANDED. DO NOT WRITE THEM AGAIN. -------

   Every house-level rule this design asked for is now in
   packages/ui-client-web/globals.css, shipped, and cricket consumes all four
   unchanged. Recorded here so nobody re-implements them.

   1. :focus-visible. 2px var(--brand-primary), 2px offset, radius 2px, PLUS a
      box-shadow: 0 0 0 4px rgb(0 0 0 / 0.6) outer spacer so the ring survives
      over artwork. The spacer is the part this file did not specify and the
      house got right. On ETPL the ring is #e3f30f, which is the single best
      use of this colour anywhere in the system: 2px is exactly the right
      amount of it, it clears 17:1 on black and 8.4:1 on the field, and the
      black spacer handles everything in between.

   2. .numeric and .numeric-display utilities. tnum + case, and case alone for
      hero figures. Use .numeric on any digit compared against another digit.
      This design's .figures class is retired in favour of them.

   3. prefers-reduced-motion, globally, at 0.01ms rather than 0 so
      transition-end handlers still fire.

   4. onPrimary, computed per brand by scripts/brand-ink.js. On #e3f30f it
      resolves to #1a0e05 at 15.41:1, which is the answer we want. White would
      be 1.23:1.

   THE ONE HOUSE-LEVEL THING STILL OUTSTANDING, and it is now a launch blocker
   rather than a backlog item: ten call sites hardcode `text-white` on
   `bg-primary-500` instead of using text-onPrimary. On DIG's orange that is a
   known 2.77:1 defect. ON ETPL IT IS 1.23:1 AND THE LABEL DISAPPEARS.
   AddFundsModal.tsx x4, PurchaseButtons.tsx x2, _error.tsx,
   profile/index.tsx, AlbumDetails.tsx. Ten lines.
   -------------------------------------------------------------------------- */

/* --- CRICKET ONLY (b) ---------------------------------------------------- */

/* The masthead. The one place the full-strength field appears, and the reason
   the lockup has something to sit on: a 63%-transparent chartreuse griffin on
   bare black is an acid shape floating in a void. MenuBar today is transparent
   until scroll and then bg-black/90; on ETPL the scrolled state is the field.
   That needs one token in globals.css defaulting to black, so the change is
   house-level and DIG is unaffected. */
.etpl-masthead { background: var(--field); }
.etpl-masthead--scrolled { background: color-mix(in oklab, var(--field) 92%, transparent); }

/* The score block. Runs at display size, wickets at 60 percent, the solidus
   raised to cap height by `case` if Archivo carries it (verify on arrival;
   the fallback is a translateY on __solidus, which is why it is its own span). */
.etpl-score {
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--figures);
  line-height: var(--leading-fig);
  color: var(--ink);
}

/* The scorebug mark. Archivo 900 against the score's 300. Not an eyebrow:
   AMS is how a scorecard writes Amsterdam. Never tinted, never in a pill. */
.etpl-scorebug__mark {
  font-weight: var(--scorebug-mark-weight);
  letter-spacing: var(--scorebug-mark-track);
  font-size: calc(1em * var(--scorebug-mark-ratio));
  color: var(--ink-body);
  text-transform: uppercase;
}
.etpl-score--hero   { font-size: var(--fig-hero);   font-weight: var(--fig-weight-hero);   letter-spacing: var(--track-hero); }
.etpl-score--page   { font-size: var(--fig-page);   font-weight: var(--fig-weight-page);   letter-spacing: var(--track-page); }
.etpl-score--card   { font-size: var(--fig-card);   font-weight: var(--fig-weight-card);   letter-spacing: var(--track-card); }
.etpl-score--inline { font-size: var(--fig-inline); font-weight: var(--fig-weight-inline); letter-spacing: var(--track-flat); }

/* Wickets and the solidus step down, so 184/6 reads as "184, for 6" rather
   than as one six-character string. */
.etpl-score__wickets { font-size: 0.6em; color: var(--ink-body); }
.etpl-score__solidus { font-size: 0.6em; color: var(--ink-muted); margin-inline: 0.08em; }

/* Overs are a COORDINATE, not a decimal. 17.3 means 17 overs and 3 balls, so
   the ball part is set down and never right-aligned as a decimal fraction. */
.etpl-overs        { font-feature-settings: var(--figures); font-variant-numeric: tabular-nums; color: var(--ink-body); }
.etpl-overs__balls { font-size: 0.78em; color: var(--ink-muted); }

/* Dense figure columns. The width axis does the job the demo bolts a third
   typeface on for: Archivo at wdth 62 with tabular figures is a newspaper
   scorecard column, which is what Archivo was drawn from. Use on the
   scorecard, the P/W/L/NR cells, run rates and the fixture times. NOT on the
   score itself, which is normal width at 300. */
.etpl-figures-dense {
  font-stretch: calc(var(--width-condensed) * 1%);
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--figures);
}

/* The ribbon. Ticks have no radius. It sits on a blue panel, never on bare
   black, because the leading edge is the brand colour and the rule in the file
   header applies to the signature component first. */
.etpl-ribbon      { display: flex; gap: var(--over-gap); align-items: flex-end; background: var(--ribbon-ground); border-bottom: 1px solid var(--ribbon-baseline); }
.etpl-over        { display: flex; gap: var(--ball-gap); align-items: flex-end; }
.etpl-ball        { border-radius: var(--radius-ball); background: var(--ball-empty); transition: background-color var(--dur-1) var(--ease), height var(--dur-ball) var(--ease-ball); }
.etpl-ball--bowled{ background: var(--ball-batting); }

/* The leading edge. Form carries this, not colour: it is the only mark in the
   ribbon that breaks the baseline, top and bottom. Keep the overshoot even if
   the colour is ever changed. */
.etpl-ball--edge  { background: var(--live-edge); width: var(--edge-w);
                    margin-block: calc(var(--edge-overshoot) * -1);
                    height: calc(100% + var(--edge-overshoot) * 2); align-self: center; }
.etpl-ball--trail { background: var(--live-trail); }
.etpl-ball--void  { background: var(--ball-void); }
.etpl-ball--four  { height: calc(var(--ball-h-md) * var(--ball-4-scale)); }
.etpl-ball--six   { height: calc(var(--ball-h-md) * var(--ball-6-scale)); }

/* No result. Chroma means the match counted.
   NOTE the palette change makes this stronger, not weaker: a desaturated blue
   panel is a grey panel, so an abandoned match loses the field as well as the
   team tints and reads as a card that has been switched off. Checked at zero
   saturation and every other state remains distinguishable, because state is
   carried on four channels and chroma is only one of them. */
.etpl-match--no-result { filter: saturate(0); }

/* Links. The light half of this ramp has almost no perceptual range: adjacent
   steps differ by about dE-OK 0.04, which is a tint, so a link CANNOT signal
   hover on colour alone on this brand. The underline is the affordance and the
   colour shift is support. Do not remove the underline to "clean it up". */
.etpl-link {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--dur-2) var(--ease), text-decoration-thickness var(--dur-2) var(--ease);
}
.etpl-link:hover { color: var(--link-hover); text-decoration-thickness: 2px; }

/* =============================== THE CHECK =================================
   Before shipping any cricket surface, run this list against the screen.

   1. Is there any chartreuse on the black ground that is not a line 2px or
      thinner? If yes, it is wrong. Fix the ground, not the colour.
   2. Are there more than two chartreuse marks in the viewport? If yes, one of
      them is decoration.
   3. Is any team tint sitting on --field? Three of the six fail 3:1 there.
   4. Is any label set in a team tint? A tint is never text.
   5. Is any white type sitting on primary-500 or primary-700? Those are
      1.23:1 and 2.61:1. Use --action-label.
   6. Does the page still read with `filter: saturate(0)`? Every state must.
   ========================================================================== */
