/* Celebrate Diversity — Design Tokens v2.0.1
 * Single source of truth. Every colour, size, radius and shadow in the
 * design language is here. Nothing in the implementation should invent a
 * value that is not in this file.
 *
 * Load this once, globally, before any component CSS.
 *
 * v2.0.1 (21 Aug 2026) — three measured defects corrected. Each change is marked
 * [v2.0.1] inline with its evidence. See CHANGELOG.md.
 */

:root {

  /* ─────────────────────────────────────────────────────────────
   * 1. CORE PALETTE — six colours, each with exactly one job
   * ───────────────────────────────────────────────────────────── */

  --cd-navy:        #020F3F;  /* THE GROUND. Heroes, footers, dark sections, primary text on light */
  --cd-blue:        #308EC3;  /* TRADEMARK BLUE. Headlines on white, rules, active states, the curve */
  --cd-ember:       #FF6B4A;  /* GIVING ONLY. Donate/Give buttons. Never anything else. */
  --cd-green:       #0C4F3F;  /* Wellbeing programs + the testimony/quote ground */
  --cd-mint:        #A0D8C4;  /* Evidence. Numbers, stats, impact bands */
  --cd-lilac:       #C3B3EA;  /* Learning programs. The one accent with no warmth */

  /* Text colours that pair with each core ground (all >= 4.5:1) */
  --cd-on-navy:     #F4F5F6;
  --cd-on-blue:     #04173A;
  /* [DL-076] Was #25060A, a warm near-black. Contrast is unchanged to two
   * decimal places - 6.52:1 against ember where the old ink gave 6.72 - but a
   * warm near-black inside a large saturated orange field gets pushed
   * perceptually toward orange's complement and reads olive. The client saw the
   * word Donate as dark green, which it never was; a cool near-black does not
   * pick up the cast. Simultaneous contrast, not a colour-picking error. */
  --cd-on-ember:    #020F3F;
  --cd-on-green:    #F0EDE6;
  --cd-on-mint:     #062A20;
  --cd-on-lilac:    #020F3F;

  /* Muted body text for use ON dark grounds */
  --cd-navy-body:   #B9C3D9;  /* body copy on navy */
  --cd-navy-meta:   #8E9AB4;  /* metadata on navy */
  --cd-green-body:  #B6CFC6;  /* body copy on green */
  --cd-green-meta:  #99C0B3;  /* [v2.0.1] was #8FB3A7 = 4.16:1 on --cd-green, which
                                 fails AA for 12px normal text. Now 4.78:1. */

  /* Body text on LIGHT grounds */
  --cd-ink:         #020F3F;  /* headings */
  --cd-ink-body:    #2A3242;  /* long-form body */
  --cd-ink-muted:   #4A5364;  /* card copy, secondary */
  --cd-ink-meta:    #5C6578;  /* bylines, captions, dates */

  /* ─────────────────────────────────────────────────────────────
   * 2. QUIET GROUNDS — two pale tints per core colour
   *    GHOST = whole-section backgrounds, long reading
   *    SOFT  = objects sitting ON a light ground (cards, pills, stripes)
   *    Navy text is legible on all twelve (>= 12:1).
   * ───────────────────────────────────────────────────────────── */

  --cd-navy-ghost:  #F2F3F7;
  --cd-navy-soft:   #D6DAE6;
  --cd-blue-ghost:  #EDF3FA;
  --cd-blue-soft:   #CBE1F1;
  --cd-green-ghost: #F0F4F2;
  --cd-green-soft:  #CFE0D9;
  --cd-mint-ghost:  #F1F7F5;
  --cd-mint-soft:   #D5EBE2;
  --cd-lilac-ghost: #F5F3FA;
  --cd-lilac-soft:  #E1D9F2;

  /* [v2.8] The ghost button's hover fill. A token rather than a literal because
   * the choice between blue-soft, lilac-soft and mint is a judgement the client
   * may want to revisit, and it should be one line when they do.
   *
   * blue-soft over the other two on two grounds. Measured button-against-ground
   * separation across the seven hero grounds it has to work on, blue-soft is the
   * highest on every one of them (mean 6.69:1, against 6.62 for lilac-soft and
   * 5.63 for mint). And mint is spent already: rule 1 reserves it for evidence -
   * numbers, stats, impact bands - so borrowing it for a hover state on every
   * hero would leave it meaning nothing in particular. */
  --cd-btn-ghost-hover: var(--cd-blue-soft);
  --cd-grey-ghost:  #F4F5F6;
  --cd-grey-soft:   #E1E4E8;

  --cd-white:       #FFFFFF;
  --cd-chalk:       #F0EDE6;  /* warm off-white. The ONE warm ground. Programs section. */

  /* ─────────────────────────────────────────────────────────────
   * 2b. THE EXTRA 6 — one ground per program theme
   *
   * The six core colours have six jobs and rule 1 forbids lending one to
   * another, so the six program themes could not each take a core colour
   * without breaking it. This is a second, subordinate palette whose single
   * job is to tell those six themes apart.
   *
   * Derived rather than picked. Five sit at one perceptual lightness
   * (OKLCH L 0.42) and one chroma (C 0.085), so no card in the grid shouts
   * louder than its neighbours; teal is held to 0.078 because cyan-blue is the
   * most gamut-limited hue in sRGB and 0.085 is not reachable there. That
   * chroma sits inside the core set's own range of 0.064 to 0.117, so the Extra
   * 6 read as quiet relatives of the palette rather than as a louder second
   * one. Only ember, the attention colour, is more saturated than any of these.
   *
   * Hues are placed in the gaps left by the core six, each at least 16 degrees
   * clear of its nearest core neighbour and at least 34 degrees from each other.
   *
   * Gold is the deliberate exception. Yellow has no dark form: at L 0.42 it is
   * olive, not gold. It therefore sits at its own natural lightness and takes
   * navy ink, exactly as blue, mint and lilac already do in the core set.
   *
   * Every one clears 7:1 against its text partner. Verified, in order:
   * 7.54, 7.47, 8.07, 8.11, 7.94, 9.13. See defect log DL-046. */

  --cd-teal:        #005765;  /* Education   */
  --cd-moss:        #2C592F;  /* Wellbeing   */
  --cd-plum:        #673B63;  /* Art         */
  --cd-maroon:      #74383B;  /* Cultural    */
  --cd-brown:       #6F4017;  /* Community   */
  --cd-gold:        #D9B24F;  /* Children's  */

  --cd-on-teal:     #F4F5F6;
  --cd-on-moss:     #F4F5F6;
  --cd-on-plum:     #F4F5F6;
  --cd-on-maroon:   #F4F5F6;
  --cd-on-brown:    #F4F5F6;
  --cd-on-gold:     #020F3F;  /* the exception: navy ink on a light ground */

  /* Ghost tints, for a whole band behind a theme's own cards.
   *
   * [v2.1.1] Chroma raised from 0.0067 to 0.024. The first set matched the mean
   * of the existing ghosts exactly, on the reasoning that a theme band should
   * not read heavier than a navy-ghost one. That was right about weight and
   * wrong about the job: six tints at identical lightness AND chroma differ
   * only in hue, and at 0.0067 hue is very nearly invisible. Measured as OKLCH
   * dE between the bands that actually touch on /programs/:
   *
   *     maroon -> brown  0.45      plum -> maroon  0.54
   *     teal   -> moss   0.70      moss -> plum    1.36
   *
   * The client reported the first pair as "too similar". All four were. A
   * palette of six that reads as one colour is not a palette, so the constraint
   * that mattered was separation, not matching the old mean. At 0.024 the
   * touching pairs run 1.86 to 4.87 and the tints are still pale enough that
   * navy ink clears 16.5:1 on every one. */
  --cd-teal-ghost:   #E3F8FE;
  --cd-moss-ghost:   #EAF8EA;
  --cd-plum-ghost:   #FEEEFC;
  --cd-maroon-ghost: #FFF0F0;
  --cd-brown-ghost:  #FFF1E7;   /* unused on /programs/: Community takes chalk */
  --cd-gold-ghost:   #F9F4E2;

  /* Soft tints, for the pill that sits on each card. Navy ink on all six,
   * 13.6:1 to 14.1:1. */
  --cd-teal-soft:   #BFE8F2;
  --cd-moss-soft:   #CEE8CE;
  --cd-plum-soft:   #F2D5EE;
  --cd-maroon-soft: #FCD5D5;
  --cd-brown-soft:  #F7D9C3;
  --cd-gold-soft:   #ECDFBE;

  /* Hairlines / dividers
   *
   * [v2.0.7] These were opaque hexes, and an opaque hex can only be correct on
   * one ground. --cd-rule-light was chosen against white, where it reaches
   * 1.35:1. Measured on the grounds it is actually used on:
   *
   *     white 1.35   grey-ghost 1.23   mint-ghost 1.24   navy-ghost 1.21
   *     blue-ghost 1.21   green-ghost 1.21   lilac-ghost 1.22   chalk 1.15
   *
   * The line stays put while the ground darkens toward it, so the divider is
   * weakest on exactly the tinted bands where it does the most work. On lilac
   * it was also the wrong hue: a cool grey laid over a violet ground.
   *
   * Navy is the ink partner of every light ground in this system, so the rule
   * is now navy at low alpha. It composites against whatever sits behind it and
   * holds 1.47-1.48:1 on all eight light grounds, and it takes the ground's own
   * hue with it instead of fighting it. Subtle by intent: a divider, not a
   * border. Adjust the alpha, not the hue. See defect log DL-038. */
  --cd-rule-light:  rgba(2,15,63,0.18);         /* white, chalk, all six ghosts */
  --cd-rule-lilac:  var(--cd-rule-light);       /* alias: the alpha rule needs no per-ground variant */
  --cd-rule-dark:   rgba(255,255,255,0.14);     /* on navy */
  --cd-rule-green:  rgba(240,237,230,0.25);     /* on green (currently unused: green bands take --cd-rule-dark) */

  /* ─────────────────────────────────────────────────────────────
   * 3. TYPEFACES — two families, plus mono for metadata. No others.
   * ───────────────────────────────────────────────────────────── */

  --cd-font-display: 'Archivo Black', 'Archivo', system-ui, sans-serif;
  --cd-font-body:    'Archivo', system-ui, -apple-system, sans-serif;
  --cd-font-mono:    'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;
  --cd-font-accent:  'Instrument Serif', Georgia, serif; /* ONE italic word in a hero. Nothing else. */

  /* ─────────────────────────────────────────────────────────────
   * 4. TYPE SCALE — ten roles. Each role = size + line-height + tracking.
   *    Never mix and match across roles.
   * ───────────────────────────────────────────────────────────── */

  --cd-serif-size:        28px; --cd-serif-lh:     1.34;  /* cd/statement, serif variant */
  /* [v2.3.2] The footer tagline is the hero headline in miniature, and it gets
   * its own size rather than borrowing --cd-card-size. A card title and a
   * footer tagline have no reason to move together, and reusing a size couples
   * two things that will want tuning separately. */
  --cd-footer-tagline-size:  26px;
  --cd-footer-tagline-lh:    1.08;
  --cd-footer-tagline-track: -0.02em;
  --cd-hero-size:        104px; --cd-hero-lh:      0.88; --cd-hero-track:      -0.035em;
  --cd-section-size:      54px; --cd-section-lh:   0.94; --cd-section-track:   -0.035em;
  --cd-feature-size:      44px; --cd-feature-lh:   0.98; --cd-feature-track:   -0.035em;
  --cd-quote-size:        42px; --cd-quote-lh:     1.02; --cd-quote-track:     -0.030em;
  --cd-card-size:         30px; --cd-card-lh:      0.98; --cd-card-track:      -0.030em;
  --cd-figure-size:       78px; --cd-figure-lh:    0.85; --cd-figure-track:    -0.040em;
  --cd-standfirst-size:   20px; --cd-standfirst-lh: 1.55;
  --cd-body-size:         19px; --cd-body-lh:      1.60;
  --cd-small-size:        16px; --cd-small-lh:     1.55;
  --cd-nav-size:          17px; --cd-nav-track:     0.06em;
  --cd-pill-size:         13px; --cd-pill-track:    0.10em;
  --cd-meta-size:         12px; --cd-meta-track:    0.12em;

  /* [v2.8] A listing card is not a cd/card, and its title role is not
   * --cd-card-size. A card title is copy we author, three or four words chosen
   * to fit; a post title is editorial and arrives at whatever length the writer
   * gave it. Measured on the Events archive: the longest is 53 characters, which
   * at 30px in a 365px column is five lines and turns the card into a wall of
   * uppercase. 24px brings it to three and leaves the excerpt room to matter.
   * The two roles are deliberately separate so tuning one never moves the other,
   * the same reason --cd-footer-tagline-size exists. */
  --cd-post-card-size:    24px; --cd-post-card-lh: 1.06; --cd-post-card-track: -0.025em;

  /* [v2.0.1] was 66ch. The CSS `ch` unit is the advance of the "0" glyph, which in
   * Archivo is 1.283x wider than the average prose character, so 66ch rendered
   * 84 characters and breached rule 6 by 27%. Measured at 19px: 1ch = 10.875px,
   * average character = 8.476px. 556px = 66 characters. */
  --cd-measure-body:      556px; /* hard cap on any long-form column: 66 characters */
  /* [v2.1.5] A second, looser measure for copy that sits beside a full-bleed
   * object and would otherwise look stranded in the left third of the band.
   * 880px is about 105 characters at 19px, past the 66 that long-form reading
   * wants, so it is for short passages only: an intro of two or three
   * sentences, not an article. Opt in per section, never the default. */
  --cd-measure-wide:      880px;

  /* [v2.0.2] A numbered row is an ordinal column plus a body column, so its rule
   * has to reach a little past the prose it separates without spanning the whole
   * band. 64px index + 40px gap + the 556px body measure, rounded up.
   * See defect log DL-023. */
  --cd-measure-list:      680px;

  /* [v2.0.2] 22 characters of Archivo Black at 46px, measured rather than
   * expressed in ch. See defect log DL-004. */
  --cd-measure-statement: 762px;

  /* [v2.0.2] Separation between top-level nav items. See defect log DL-010. */
  --cd-nav-gap: 22px;
  --cd-measure-standfirst: 46ch;  /* NB renders ~59 characters at 20px, not 46.
                                   * Within rule 6, so left as a visual value. */
  --cd-measure-hero:      15ch;
  --cd-measure-section:   14ch;

  /* ─────────────────────────────────────────────────────────────
   * 5. SPACING — 4px base. Use these, not arbitrary numbers.
   * ───────────────────────────────────────────────────────────── */

  --cd-space-1:   4px;
  --cd-space-2:   8px;
  --cd-space-3:  12px;
  --cd-space-4:  16px;
  --cd-space-5:  24px;
  --cd-space-6:  30px;
  --cd-space-7:  40px;
  --cd-space-8:  56px;   /* standard horizontal page gutter (desktop) */
  --cd-space-9:  72px;   /* standard section vertical padding */
  --cd-space-10: 80px;

  --cd-gutter:        56px;  /* desktop */
  --cd-gutter-tablet: 32px;
  --cd-gutter-mobile: 20px;
  /* [v2.0.2] Band padding ran to four unexplained values on the built site:
   * 72/72, 60/60, 76/0 and 56/56. No rule anyone could state predicted which
   * band got which, and the 76/0 case had no bottom padding at all because it
   * borrowed it from an inner element. Three named values, each with a job.
   * See defect log DL-021. */
  --cd-section-y:      72px;  /* standard band */
  --cd-section-y-tight:56px;  /* single-statement bands: stats, giving */
  --cd-section-y-hero: 88px;  /* the page opening, which earns the extra air */
  --cd-section-y-mob:  48px;
  --cd-grid-gap:      24px;
  /* [v2.8] The client specified the listing gutter in centimetres, not in steps
   * of this scale, so it gets a name of its own rather than being rounded to the
   * nearest token and quietly drifting later. 1cm = 37.795px at 96dpi. */
  --cd-gap-1cm:       38px;
  --cd-max-width:   1440px;  /* content max width; grounds bleed full width */

  /* [v2.0.2] The hero's media panel width, promoted to a token because the
   * hero text has to reserve room for it. Those were two separate hard-coded
   * numbers (520px panel, 300px reserve) that had to agree and did not, so the
   * headline overlapped the photograph by 164px. See defect log DL-003. */
  --cd-hero-media-w: 520px;
  /* [v2.0.7] The hero photograph is atmosphere, not subject: it sits at 20%
   * over the #0A1A4C panel so the headline owns the band. A knob rather than a
   * literal, because this is a value to tune by eye against real photography. */
  --cd-hero-media-opacity: 0.2;
  /* [v2.1] The theme mark gets its own knob rather than sharing the photo's.
   * They are set to the same value today, but a photograph and a flat mark do
   * not fade alike, and tuning one should never move the other. */
  --cd-hero-icon-opacity:  0.2;

  /* ─────────────────────────────────────────────────────────────
   * 6. THE CURVE — the signature device. One cut corner per object.
   * ───────────────────────────────────────────────────────────── */

  --cd-radius-base:    8px;    /* the three UNCUT corners */
  --cd-radius-pill:    999px;  /* buttons, pills, badges */

  /* ─────────────────────────────────────────────────────────────
   * [v2.0.3] THE CUT: one shape, one knob, three permitted sizes.
   *
   * THE RULE. The cut is always a SINGLE LENGTH, so the arc is a
   * quarter-CIRCLE. Never a percentage.
   *
   * border-radius percentages resolve per axis: the horizontal radius
   * against the box WIDTH, the vertical radius against the box HEIGHT.
   * On any box that is not square that is an ELLIPSE, by definition, and
   * no percentage can ever produce a circle on a non-square object. A
   * 652x279 two-up card at 28% rendered a 120px x 78px arc, a ratio of
   * 1.54; a 360x240 event thumbnail rendered 101px x 67px, a ratio of
   * 1.50. That is the elongation, and percentages are its only cause.
   *
   * THE SECOND RULE. The cut never exceeds 40% of the object's SHORTER
   * side. Measured across all 62 cut objects on the built site, the
   * binding dimension is almost always the HEIGHT, not the width: cards
   * measure 212px to 416px tall, so the old flat 120px was 29% to 57% of
   * the short side and swallowed the smaller ones. 120px was never the
   * right value for a card on this site.
   *
   * Components set --cd-cut and the recipes below follow. Custom
   * properties resolve at the point of use, so a component that sets
   * --cd-cut gets its own size out of the shared recipe.
   * ───────────────────────────────────────────────────────────── */

  --cd-cut-panel: 220px;  /* full-bleed panels. Short side >= 500px. */
  --cd-cut-lg:    120px;  /* large images and figures. Short side >= 300px. */
  --cd-cut-md:     60px;  /* cards, thumbnails, tiles. Short side >= 150px. */

  --cd-cut: var(--cd-cut-lg);   /* the knob. Components override it. */

  /* There are deliberately NO --cd-cut-tr / --cd-cut-br recipe TOKENS here,
   * and this is worth stating because the obvious design is a trap.
   *
   * A custom property has its var()s substituted at computed-value time on the
   * element where it is DECLARED, and the resolved result is what inherits. So
   * a recipe declared here as
   *     --cd-cut-tr: 8px var(--cd-cut) 8px 8px;
   * resolves var(--cd-cut) against THIS element, computes to "8px 120px 8px 8px"
   * and inherits that fixed string. A component further down that sets
   * --cd-cut: 60px can never affect it. Measured: a card with --cd-cut of 60px
   * still painted a 120px corner, silently.
   *
   * The corner shapes are therefore RULES, in cd-components.css, matched on the
   * element itself, where var(--cd-cut) resolves against that element. See the
   * "THE CUT" block there.
   *
   * Aliases kept so the /styles block variations and older rules keep resolving.
   * These are plain values, not knob-dependent, so they are safe here. */
  --cd-radius-cut:    var(--cd-cut-lg);
  --cd-radius-cut-lg: var(--cd-cut-panel);
  --cd-radius-cut-sm: var(--cd-cut-md);

  /* ─────────────────────────────────────────────────────────────
   * 7. ELEVATION — one shadow. Light grounds only.
   * ───────────────────────────────────────────────────────────── */

  --cd-shadow: 0 18px 40px -12px rgba(2,15,63,0.24), 0 4px 10px -4px rgba(2,15,63,0.12);
  --cd-shadow-soft: 0 18px 40px -12px rgba(2,15,63,0.18), 0 4px 10px -4px rgba(2,15,63,0.08);

  /* ─────────────────────────────────────────────────────────────
   * 8. MOTION
   * ───────────────────────────────────────────────────────────── */

  --cd-ease:       cubic-bezier(0.2, 0, 0.2, 1);
  --cd-dur-fast:   120ms;
  --cd-dur:        200ms;
  --cd-dur-slow:   320ms;

  /* ─────────────────────────────────────────────────────────────
   * 9. TOUCH TARGETS
   * ───────────────────────────────────────────────────────────── */

  --cd-tap-min:    44px;
}

/* ───────────────────────────────────────────────────────────────
 * RESET + GLOBAL DEFAULTS
 * ─────────────────────────────────────────────────────────────── */

body {
  margin: 0;
  font-family: var(--cd-font-body);
  font-size: var(--cd-body-size);
  line-height: var(--cd-body-lh);
  color: var(--cd-ink-body);
  background: var(--cd-white);
  text-wrap: pretty;
  -webkit-font-smoothing: antialiased;
}

/* [v2.0.1] Logo blue on white is 3.63:1. 06-accessibility-and-qa.md forbids it on
 * small non-bold text, and an inline link in 19px prose is exactly that. The
 * previous rule also removed the underline, leaving colour as the only affordance.
 * Prose links are now navy + underline; logo blue is reserved for the 13px
 * Archivo Black text button, which qualifies as large bold text. */
a { color: var(--cd-navy); text-decoration: underline; text-underline-offset: 3px; }
a:hover { color: var(--cd-green); text-decoration: underline; }

:focus-visible {
  outline: 3px solid var(--cd-blue);
  outline-offset: 3px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ───────────────────────────────────────────────────────────────
 * [v2.0.1] RESPONSIVE CURVE
 *
 * The cut radii above are the desktop values and are unchanged. Measured on a
 * 360px viewport, a flat 120px cut on a 280px-wide card is 43% of its width and
 * the device stops reading as a cut corner.
 *
 * Below 700px the radii step down to values already in the system's own
 * vocabulary (--cd-radius-cut-sm is 60px). Measured result: the card cut falls
 * from 43% to 21% of card width at 360px, close to the 28% it occupies on a
 * 427px desktop card.
 * ─────────────────────────────────────────────────────────────── */
@media (max-width: 700px) {
  :root {
    --cd-radius-cut:    60px;
    --cd-radius-cut-lg: 96px;
  }
}
