/* The page shell: container, rhythm, header, mega-menus, drawer, closing
 * slab, footer.
 *
 * Extracted from design/claude-design/latest/HOME ORIGINAL.dc.html — the homepage, which the
 * handoff calls "the single source of truth for design" and whose header and
 * footer the five page-type templates were "copied by hand" from. Where a
 * sub-page's copy of the chrome differs, the homepage wins. The design carries
 * every rule inline on every element, deliberately, so it streams and stays
 * editable; the brief's instruction is to "extract that styling into a real
 * component system, not to keep the markup".
 *
 * THREE DEPARTURES FROM THE SOURCE, EACH DELIBERATE.
 *
 * 1. LOGICAL PROPERTIES, NOT PHYSICAL ONES. Arabic is planned and Django
 *    flags `ar` as bidi. Written with margin-inline-start rather than
 *    margin-left, the whole shell mirrors from one attribute on <html>. Where
 *    CSS has no logical form — a transform, a gradient angle, a
 *    transform-origin — there is a [dir="rtl"] rule beside it, and every
 *    sideways nudge multiplies by --ed-dir, except on an element that is
 *    itself mirrored (see .ed-arr).
 *
 * 2. A SHORT BREAKPOINT LADDER, NOT SIXTEEN ONE-OFFS. The design uses sixteen
 *    distinct widths, most of them once. The ones kept here are the ones the
 *    shell's layout actually changes at, and 1160px is kept EXACTLY because
 *    the handoff names it as where the nav becomes a drawer.
 *
 * 3. MOBILE FIRST. Base rules are the narrow layout; media queries widen it.
 *
 * Nothing in this file sets a colour that is not a token. A hex here is a bug,
 * and core/tests_shell.py fails on one.
 */

/* ---- Breakpoints -------------------------------------------------------
 * Custom properties cannot be used in a media query, so these are documented
 * rather than declared.
 *
 *    380px  the compact "Assessment" pill fits beside the logo and burger
 *    640px  the footer goes to two columns
 *   1000px  the footer's full four-track grid
 *   1160px  the nav leaves the drawer — NAMED IN THE HANDOFF, do not move it
 *   1280px  the nav labels go from 15px back to 16px
 */

/* ---- Base ---------------------------------------------------------------
 * The design's own base (HOME:50-52), and two measured defects it closes.
 *
 * BORDER-BOX. There was no box-sizing reset anywhere, so every `min-height`
 * and `max-width` measured the CONTENT box: the header's 44px pills rendered
 * 66px tall inside a 68px bar, and every container was its max-width plus two
 * gutters wide. The design sizes every box by its border.
 *
 * NO BODY MARGIN. The browser's default 8px framed the black header in white
 * on every page.
 */
*,
*::before,
*::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ed-bg);
  color: var(--ed-ink);
  font-family: var(--ed-font-body);
  -webkit-font-smoothing: antialiased;
}

/* Headings balance their lines and paragraphs avoid a lone last word, on
 * every page, as the design's global rule has them (HOME: "h1,h2,h3 {
 * text-wrap: balance } p, dd { text-wrap: pretty }"). Zero specificity, so a
 * component that wraps its own way still wins. */
:where(h1, h2, h3) { text-wrap: balance; }
:where(p, dd) { text-wrap: pretty; }
::selection { background: var(--ed-cta); color: var(--ed-on-brand); }

/* ---- Container and rhythm ---------------------------------------------- */

.ed-container {
  width: 100%;
  max-width: var(--ed-maxw);
  margin-inline: auto;
  padding-inline: var(--ed-gutter);
}

/* The reading measure for document-style pages: 1080px, but left-aligned on
 * the page grid so it shares the logo's left edge rather than centring. */
.ed-container--read > * { max-width: var(--ed-maxw-read); }

.ed-section { padding-block: var(--ed-section-y); }

/* ---- Focus -------------------------------------------------------------
 * One visible ring everywhere (HOME:93). Each dark component redefines
 * --ed-focus for its own ground below; article.css keeps its own.
 *
 * FOCUS NEVER WAITS FOR HOVER (the owner, 7 October 2026). A hover answer
 * is kept off touch screens with (hover: hover), where a tap would leave it
 * stuck; but an iPad with a keyboard is a touch screen too, so a rule that
 * also answers :focus-visible gives that half outside the hover gate,
 * behind the reduced-motion gate alone. A tap never matches :focus-visible.
 * The ring itself is never gated. core/tests_design.py holds every
 * stylesheet to it.
 *
 * NEVER UNDER THE STICKY BAR (WCAG 2.4.11, docs/plans/a11y-wcag22aa.md item
 * 1): Shift+Tab scrolled focused controls to y 12-56, behind the 68px bar.
 * scroll-padding on the root reserves the sticky block for everything the
 * browser scrolls into view, focus included; each anchor's own scroll-margin
 * adds a further 8px, 24px in all as the design clears the bar (HOME:86). A
 * page with a context bar sets .ed-has-ctxbar on <html>, where this is read. */
html { scroll-padding-top: calc(var(--ed-sticky-h) + 16px); }
:focus-visible {
  outline: 2px solid var(--ed-focus);
  outline-offset: 3px;
}
/* The ring's own corners (HOME: "border-radius: 2px" in the same rule), at
 * zero specificity so a pill or an 8px button keeps its shape. */
:where(:focus-visible) { border-radius: var(--ed-radius-ring); }
/* NO RING ROUND WHAT IS FOCUSED TO BE READ, NOT USED: the skip link's
 * target, and a form's thanks or errors, which take focus on arrival so a
 * keyboard or screen-reader user hears them (a role and tabindex="-1").
 * Without it every page drew a ring round its whole main element the moment
 * the skip link was used. A control a script focuses keeps its ring. */
:where(#main, [role="status"][tabindex="-1"], [role="alert"][tabindex="-1"]):focus { outline: none; }

/* ---- Skip link ---------------------------------------------------------
 * First focusable thing on the page and invisible until focused.
 *
 * PARKED ABOVE THE PAGE, NOT BESIDE IT. It used to sit at
 * inset-inline-start: -9999px, which in a right-to-left region is 9999px off
 * the RIGHT edge: measured on /ar/, the document became 9999px wider than the
 * viewport at every width. Above the top edge is the same in both directions
 * and adds nothing a reader can scroll to.
 *
 * FOCUSED, AS DRAWN (HOME: "a.ed-skip:focus"): a near-black tab 12px in from
 * the corner, 8px round, in the body's Archivo 16px. The words and the
 * target are the build's (docs/BASELINE.md §5).
 */
.ed-skip {
  position: absolute;
  inset-inline-start: 12px;
  inset-block-start: 0;
  transform: translateY(-110%);
  z-index: 200;
  background: var(--ed-ink);
  color: var(--ed-on-dark);
  padding: 12px 18px;
  border-radius: var(--ed-radius);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-nav);
  font-weight: var(--ed-weight-regular);
  text-decoration: none;
}
.ed-skip:focus { transform: none; inset-block-start: 12px; }

/* ---- Header ------------------------------------------------------------
 * A square black bar, 68px, with nothing under it in any state: no hairline
 * and, since the designer's 27 September update, no scroll-progress fill
 * (HANDOFF.md, "Header").
 */

.ed-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 70;
  background: var(--ed-nav);
  /* #C40C7C, fixed: 3.69:1 on the black bar. The themed --ed-focus is the
   * one for light grounds. */
  --ed-focus: var(--ed-nav-line);
}

/* THE HOMEPAGE'S BAR OVER THE HERO (HANDOFF.md, "Page settings": navBar
 * "Transparent over hero", the default; the owner, 28 September). No fill
 * while the page is within 40px of its top and no menu or the drawer is
 * open; solid black as soon as it scrolls or one opens. The language list
 * is neither: the design's bar stays clear with it open. js/shell.js marks
 * the top (data-top). WITHOUT THE SCRIPT THE BAR STAYS SOLID, so its white
 * text never lands on a light section. Over the hero the links are 16.53:1
 * on the design's scrim and 8.89:1 at worst over a photo (tokens.css).
 *
 * SOLID, IT BLURS WHAT SCROLLS UNDER IT, as the design's bar does; clear, it
 * does not. The filter is on a layer behind the bar's contents, NEVER on
 * .ed-header itself: a backdrop filter there makes the header the
 * containing block of the fixed full-screen drawer, which then shrank from
 * 832px to 31px (measured at 390px). Only this bar is ever see-through, so
 * only this bar carries it. */
.ed-header--over-hero { transition: background-color var(--ed-duration-bar) ease; }
.ed-header--over-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  -webkit-backdrop-filter: var(--ed-bar-backdrop);
  backdrop-filter: var(--ed-bar-backdrop);
}
.ed-header--over-hero[data-top]:not(:has(.ed-nav__menu[open], .ed-drawer-wrap[open])) { background-color: transparent; }
.ed-header--over-hero[data-top]:not(:has(.ed-nav__menu[open], .ed-drawer-wrap[open]))::before {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.ed-header__bar {
  max-width: var(--ed-maxw);
  margin-inline: auto;
  padding-inline: var(--ed-gutter);
  min-height: var(--ed-header-h);
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.6vw, 26px);
}

.ed-header__logo { display: flex; align-items: center; flex: 0 0 auto; }
.ed-header__logo img { height: var(--ed-logo-h); width: auto; display: block; }

/* Hidden until there is room. The handoff is firm that the nav never DROPS
 * items to fit: it tightens, then becomes a drawer.
 *
 * ROOM IS MEASURED, NOT ASSUMED. The breakpoint is in em, so larger browser
 * text gets the drawer sooner; but the page's container is capped in pixels,
 * so with 20-24px text on a wide screen the six items still ran into the
 * search and language controls (measured, 27 September 2026). shell.js adds
 * `ed-nav-tight` to <html> whenever the items do not fit beside the
 * utilities, and the header then keeps its drawer at any width. At the
 * default text size, in every language, the items fit and nothing changes. */
.ed-nav,
.ed-header__utility { display: none; }

@media (min-width: 72.5em) {
  :root:not(.ed-nav-tight) .ed-nav,
  :root:not(.ed-nav-tight) .ed-header__utility { display: flex; align-items: center; }
  /* 6px apart, so a hovered item and an open one never share a border
   * (HANDOFF.md, "Header", 28 September). */
  .ed-nav { gap: 6px; flex: 1 1 auto; min-width: 0; }
  .ed-header__utility { gap: clamp(8px, 1vw, 16px); flex: 0 0 auto; }
}

.ed-nav__link {
  display: block;
  white-space: nowrap;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-nav);
  font-weight: var(--ed-weight-medium);
  letter-spacing: -0.009em;
  color: var(--ed-nav-item);
  padding: 10px 15px;
  border: 1px solid transparent;
  border-radius: var(--ed-radius);
  transition: background var(--ed-transition-quick), color var(--ed-transition-quick), border-color var(--ed-transition-quick);
}
/* Hovered or open: the #25252B fill with the magenta border (HANDOFF.md,
 * "Header", 27 September). Hovered, the label goes to the files' --nav-ink,
 * #F4F4F5 (HANDOFF's "100%" is that token); open with the pointer elsewhere
 * it stays at its resting 95%, as drawn. */
/* THE SECTION BEING READ WEARS THE SAME PILL (the owner, 9 October 2026), at
 * rest: the fill, the magenta border and the radius, with the hovered ink.
 * It replaces the 2px rule this item carried under it. The pill's shape is
 * the cue, not its colour: the border is 3.69:1 on the black bar, and the
 * box it draws is there for a reader who cannot tell the inks apart
 * (SC 1.4.1). "page" is the item's own page; "true" is somewhere inside it. */
.ed-nav__link:hover,
.ed-nav__menu[open] > .ed-nav__link,
.ed-nav__link[aria-current] {
  background: var(--ed-nav-hover-fill);
  border-color: var(--ed-nav-line);
}
.ed-nav__link:hover,
.ed-nav__link[aria-current] { color: var(--ed-on-dark-soft); }

/* French is the longest language and still fits, because the labels drop a
 * size here rather than wrapping or losing an item (HOME:79). */
.ed-nav__link-inner { display: inline-flex; align-items: center; gap: 7px; }
.ed-nav__caret {
  flex: 0 0 auto;
  display: block;
  opacity: 0.6;
  transition: transform var(--ed-duration-bar) var(--ed-ease);
}
.ed-nav__menu[open] > .ed-nav__link .ed-nav__caret { transform: rotate(180deg); }

/* AFTER the base rules, not before them: the caret's fade has the same
 * specificity as its base opacity, so ahead of it the base won at every width
 * and the design's 0.45 never applied. */
/* AT EVERY DESKTOP WIDTH SINCE 2 OCTOBER (until then up to 1399px, the
 * design's being 1279px): the full-size bar needs about 1160px of content
 * and the grid now holds content to 1140px (tokens.css, "One page grid"),
 * so the six items keep the compact size, 8px either side where the design
 * has 10px. Six items 6px apart, and this bar's search and language controls
 * are real targets (40px and 44px) where the design's are 26px: measured, the
 * items ran into the utility cluster at 1280px in English and at 1160px in
 * French, and since 28 September, with "Get a free assessment", at 1360px in
 * English (19px to spare at 1400; 31.6px since the search and language
 * targets overhang their drawn boxes). So the labels stay at the design's own
 * smaller size until there is room — the handoff's rule is that the nav
 * tightens and never drops an item (docs/BASELINE.md §5). The label-to-caret
 * gap stays the design's 7px throughout, and the caret fades to 0.45 only
 * where the design fades it, up to 1279px. */
@media (min-width: 72.5em) {
  .ed-nav__link { padding: 9px 8px; font-size: var(--ed-size-body); }
}
@media (min-width: 72.5em) and (max-width: 79.9375em) {
  .ed-nav__caret { opacity: 0.45; }
}

/* WHERE YOU ARE, IN THE PHONE MENU: the bar's pill (above) on the row of the
 * section being read. The border is an inset ring, so the row keeps its
 * height, and the row reaches into the drawer's gutter by the pill's own
 * padding, so its label stays on the column with every other row's. */
.ed-drawer__top[aria-current],
.ed-drawer__summary[aria-current] {
  margin-inline: calc(-1 * var(--ed-drawer-pill-pad));
  padding-inline: var(--ed-drawer-pill-pad);
  border-radius: var(--ed-radius);
  background: var(--ed-nav-hover-fill);
  box-shadow: inset 0 0 0 1px var(--ed-nav-line);
}

/* ---- Utility cluster ---------------------------------------------------- */

/* A 40px target round an 18px icon: the design's box is 26px, below the
 * 24px-plus-spacing that WCAG 2.2 asks of a lone icon control.
 *
 * WHERE DRAWN, AT THE BUILD'S SIZE. A negative inline margin of half the
 * difference keeps the design's 26px box in the layout, so the icon sits
 * where drawn and the target overhangs the gaps either side; so does the
 * language button's below. The two targets stay apart at every width (1.8px
 * at 1160px, where the gap is narrowest), and js/shell.js measures the nav's
 * clearance against this target, not the cluster. */
.ed-header__search {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-inline: calc((26px - 40px) / 2);
  color: var(--ed-nav-util);
  transition: color var(--ed-transition-quick);
}
.ed-header__search:hover { color: var(--ed-on-dark-soft); }

/* ---- Language picker -----------------------------------------------------
 * "As small as possible" (HANDOFF.md, 28 September): the current code alone,
 * no icon and no border in any state; hover and open add only the #25252B
 * fill. It rests at the nav items' 95% and turns #F4F4F5 on hover, as the
 * nav items do; open, with the pointer elsewhere, it stays at 95%. The list
 * is a plain white sheet as wide as its longest name, native names only. A
 * light island (`ed-light` in the markup), so its inks are the light ones
 * under the black bar.
 *
 * 44px TALL, not the design's 33px: the bar is 68px, so the target grows and
 * nothing moves. The flex layout is on the inner span, never the <summary>,
 * for the Safari reason `.ed-nav__link-inner` gives. */
.ed-lang { position: relative; flex: 0 0 auto; }
.ed-lang__button {
  display: block;
  min-height: var(--ed-target);
  min-width: var(--ed-target);              /* the code alone is 38px wide: a 44px target */
  /* The drawn box is the two-letter code, its tracking, 10px either side
   * and the border: half of what the 44px adds comes off each side. */
  margin-inline: calc((2ch + 0.16em + 22px - var(--ed-target)) / 2);
  text-align: center;
  padding-inline: 10px;
  border: 1px solid transparent;
  border-radius: var(--ed-radius);
  color: var(--ed-nav-item);
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: 0.08em;
  /* The fill fades; the label changes at once, as drawn. */
  transition: border-color var(--ed-transition), background-color var(--ed-transition);
}
.ed-lang__button:hover { background: var(--ed-nav-hover-fill); color: var(--ed-on-dark-soft); }
.ed-lang[open] > .ed-lang__button { background: var(--ed-nav-hover-fill); }
/* THE INNER BOX OF THE BAR'S TWO BORDERED SUMMARIES, the language button
 * and the burger: the target less their two 1px borders, so each is exactly
 * 44px and its label sits centred, where drawn. */
.ed-lang__inner,
.ed-header__burger-inner { display: inline-flex; align-items: center; min-height: calc(var(--ed-target) - 2px); }

/* Anchored to the control's END edge, so it opens inward: under the right
 * end of the bar in English, the left end in the mirrored Arabic bar. */
.ed-lang__list {
  position: absolute;
  inset-block-start: calc(100% + var(--ed-menu-gap));
  inset-inline-end: 0;
  z-index: 80;
  display: flex;
  flex-direction: column;
  width: max-content;
  min-width: 116px;             /* HANDOFF.md: "at least 116px wide" (27 Sep) */
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--ed-surface);
  border: 1px solid var(--ed-border);
  border-radius: var(--ed-radius-list);
  box-shadow: var(--ed-lang-shadow);
  animation: ed-menuin var(--ed-duration) var(--ed-ease) both;
}
.ed-lang__link {
  display: block;
  padding: 7px 12px;
  border-radius: var(--ed-radius);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-small);
  line-height: 1.3;
  text-align: start;
  white-space: nowrap;
  color: var(--ed-dek);
  transition: color var(--ed-transition-quick);
}
/* Ink and semibold on hover, with no fill (HANDOFF.md, "Menu link hover
 * underline": "Language options keep their semibold hover with no fill"). */
.ed-lang__link:hover,
.ed-lang__link:focus-visible,
.ed-lang__link[aria-current] {
  color: var(--ed-ink);
  font-weight: var(--ed-weight-semibold);
}
/* Each name reserves its semibold width, so hovering one never widens the
 * list: at 116px it absorbs the change at the default text size, but not at
 * 200% (the footer picker's own trick, .ed-flang__link::after). */
.ed-lang__link::after {
  content: attr(data-label);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: var(--ed-weight-semibold);
}
/* A touch screen at desktop width (a tablet in landscape) gets 44px rows;
 * a mouse keeps the design's 32px. A column, so the reserve above stays
 * under the name rather than beside it. */
@media (pointer: coarse) {
  .ed-lang__link { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; min-height: var(--ed-target); }
}

/* The compact CTA below 1160px. Shown only where the logo, this pill and the
 * burger fit on one line inside the gutters — the design has no rule for the
 * narrow end and would overflow, and "no horizontal overflow at any width" is
 * one of its non-negotiables. The drawer carries the full CTA at every width.
 * Measured with the 28 September label, and 4px less padding either side
 * below 414px: "Free assessment" (145px) needs 389px, "Évaluation gratuite"
 * (154px) 398px, and the Arabic label (100px) fits from 380px. So English
 * shows it from 390px, French from 400px, Arabic from 380px. */
/* Two classes deep on purpose: `.ed-btn` sets `display` too, and comes later
 * in this file, so a one-class rule here lost to it and the pill showed at
 * every width. */
.ed-header .ed-header__compact { display: none; }
@media (min-width: 23.75em) {
  .ed-header .ed-header__compact { display: inline-flex; margin-inline-start: auto; padding: 11px 18px; }
}
@media (min-width: 23.75em) and (max-width: 25.8125em) {
  .ed-header .ed-header__compact { padding-inline: 14px; }
}
@media (max-width: 24.3125em) {
  .ed-header .ed-header__compact:lang(en) { display: none; }
}
@media (max-width: 24.9375em) {
  .ed-header .ed-header__compact:lang(fr) { display: none; }
}
@media (min-width: 72.5em) {
  :root:not(.ed-nav-tight) .ed-header .ed-header__compact { display: none; }
}

/* ---- Buttons -----------------------------------------------------------
 * One pill, its treatments and its sizes, and the colours are FIXED tokens:
 * see the note on the pills in tokens.css.
 *
 * THE BOX IS THE DRAWN PILL, THE TARGET IS 44px. A pill is exactly its
 * padding and its line, as drawn (the header's 37px, the footer's 42px), and
 * its 44px target is the hit area every such control shares, laid over it
 * ("Text links", .ed-btn::after); it never moves the layout.
 */

.ed-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Two tokens, which each size restates and the main button's badge is
   * sized from (tokens.css, "The pill's padding"). */
  padding: var(--ed-btn-pad-y) var(--ed-btn-pad-x);
  border: 0;
  border-radius: var(--ed-radius-pill);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.01em;
  /* "normal", as every pill in the design: 16px for Archivo 15px, where 1.2
   * made each pill 2px taller than drawn. */
  line-height: normal;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--ed-transition), color var(--ed-transition),
              border-color var(--ed-transition);
}

/* ---- The main button ----------------------------------------------------
 * THE OWNER'S, 4 OCTOBER 2026, ON EVERY MAIN BUTTON: the in-page pill
 * (.ed-btn--primary) and the purple one (.ed-btn--purple), which is the same
 * button now, so every form's submit, the newsletter's Subscribe, the flip
 * cards' and the slabs' calls to action take it with no template changed.
 * Not the header's slim pill, the outlined ones or the text links. The
 * design's pills carried no arrow (HANDOFF.md, "Arrows"); BASELINE.md §5.
 *
 * A pill with a round badge at its end. At rest: --ed-cta, white words, a
 * white badge holding a magenta ↗. On hover and keyboard focus: near-white
 * (--ed-cta-hover-fill) with a thin --ed-cta edge, magenta words and a
 * magenta badge holding a white →, the arrow turning 45° to get there in
 * --ed-duration-turn on the site's ease. Under reduced motion every
 * transition is cut to nothing ("Motion", at the end of this file), so it
 * simply changes. Contrast, measured: tokens.css, at --ed-cta-hover-fill.
 *
 * THE BADGE IS ::before, ONE SHAPE, ONE STATIC FILE. img/button-arrow.svg is
 * a disc with the arrow cut out of it, used as a mask over the badge's own
 * colour, so the arrow is whatever the pill is filled with: magenta in the
 * white disc at rest, near-white in the magenta disc on hover. Served from
 * this origin (img-src 'self'), and the turn is the disc's own `transform`,
 * which turns a disc into itself. Under Arabic `scale` mirrors it AFTER the
 * turn, so ↖ turns to ←.
 *
 * THE PILL KEEPS ITS DRAWN HEIGHT. The badge is the pill's height less
 * --ed-btn-badge-inset all round, and its negative block margins give the
 * line back what it overhangs, so it sits concentric with the pill's end
 * (the inline-end padding is that inset) without making any pill taller.
 * A small pill (.ed-btn--sm) takes a wider inset and so a smaller badge. The
 * edge is an inset shadow, so the hover moves nothing either.
 */
:is(.ed-btn--primary, .ed-btn--purple) {
  gap: var(--ed-btn-badge-gap);
  padding-inline-end: var(--ed-btn-badge-inset);
  background: var(--ed-cta);
  color: var(--ed-on-brand);
  transition: background-color var(--ed-transition), color var(--ed-transition),
              box-shadow var(--ed-transition);
}
:is(.ed-btn--primary, .ed-btn--purple)::before {
  content: "";
  order: 1;
  flex: none;
  inline-size: calc(1lh + 2 * var(--ed-btn-pad-y) - 2 * var(--ed-btn-badge-inset));
  aspect-ratio: 1;
  margin-block: calc(var(--ed-btn-badge-inset) - var(--ed-btn-pad-y));
  background-color: var(--ed-on-brand);
  -webkit-mask: url("../img/button-arrow.cfb1ded5bc71.svg") center / 100% 100% no-repeat;
  mask: url("../img/button-arrow.cfb1ded5bc71.svg") center / 100% 100% no-repeat;
  transition: transform var(--ed-duration-turn) var(--ed-ease),
              background-color var(--ed-transition);
}
:is(.ed-btn--primary, .ed-btn--purple):dir(rtl)::before { scale: -1 1; }
:is(.ed-btn--primary, .ed-btn--purple):is(:hover, :focus-visible) {
  background: var(--ed-cta-hover-fill);
  color: var(--ed-cta);
  box-shadow: inset 0 0 0 1px var(--ed-cta);
}
:is(.ed-btn--primary, .ed-btn--purple):is(:hover, :focus-visible)::before {
  background-color: var(--ed-cta);
  transform: rotate(45deg);
}
/* The small pill's badge sits further in and closer to its words, so the
 * flip cards' longest label, "Discuss time & materials", stays on one line
 * in a 320px screen's 236px (measured: 234px). */
.ed-btn--sm:is(.ed-btn--primary, .ed-btn--purple) { --ed-btn-badge-inset: 10px; --ed-btn-badge-gap: 8px; }
/* THE PLAIN MAIN BUTTON (.ed-btn--plain; the owner, 4 and 7 October 2026):
 * the main button's colors at rest and on hover and keyboard focus, edge
 * included, with no badge, so its words sit centered between the size's own
 * padding. Every enquiry form's submit, the footer's "Get an assessment"
 * and Subscribe, and the cookie card's Reject and Accept. A full-width main
 * button is always plain (core/tests_design.py), since a badge in a wide
 * pill would sit beside centered words, not at the pill's end. */
.ed-btn--plain:is(.ed-btn--primary, .ed-btn--purple) { padding-inline-end: var(--ed-btn-pad-x); }
.ed-btn--plain:is(.ed-btn--primary, .ed-btn--purple)::before { content: none; }

/* The header's CTA rests a shade deeper, in every design file. */
.ed-btn--header {
  background: var(--ed-brand-surface);
  color: var(--ed-on-brand);
  font-size: var(--ed-size-small);
  letter-spacing: -0.008em;
  padding: 11px 20px;
}
.ed-btn--header:hover { background: var(--ed-cta-hover); color: var(--ed-on-brand); }

/* A transparent pill with a 55% white edge, filling magenta on hover. Its
 * hover is the fixed --ed-cta, the filled pill's colour, never the magenta
 * for text. It is the medium pill (below). */
.ed-btn--ghost {
  background: transparent;
  color: var(--ed-on-dark);
  border: 1px solid var(--ed-ghost-line);
}
.ed-btn--ghost:hover { background: var(--ed-cta); border-color: var(--ed-cta); }
/* The quieter outline, beside a filled pill on a dark slab. */
.ed-btn--quiet { border-color: var(--ed-ghost-line-quiet); }

/* THE SIZES, as drawn: the base 13px 24px, then small, medium and large.
 * A size is its own modifier, never part of a style, so an outlined pill
 * takes any size: with its 1px border, a small outline stands as tall as
 * the medium filled pill beside it (the Mid CTA), and a medium one as tall
 * as a large filled pill (the hero). Each sets the two padding values, so
 * the main button's badge follows the size. */
.ed-btn--sm { --ed-btn-pad-y: 14px; --ed-btn-pad-x: 26px; }
.ed-btn--md { --ed-btn-pad-y: 15px; --ed-btn-pad-x: 28px; }
.ed-btn--lg { --ed-btn-pad-y: 16px; --ed-btn-pad-x: 30px; }
.ed-btn--block { width: 100%; }
/* A long label wraps inside its pill rather than overflow it. */
.ed-btn--wrap { max-width: 100%; white-space: normal; text-align: center; }

/* ---- Arrows that appear -----------------------------------------------
 * A secondary link beside a pill, and every menu card, hides its arrow until
 * hover or keyboard focus. Only opacity and transform change, so the space is
 * reserved and nothing shifts (HOME:32-34). The glyph mirrors under RTL.
 *
 * NO --ed-dir HERE, and that is the RTL fix, not an omission. Under Arabic the
 * arrow is mirrored with `scale: -1 1`, and the `scale` property applies
 * around the element's own axis AFTER its `transform`, so the mirror already
 * turns this -6px round to point the other way. Multiplying by --ed-dir as
 * well turned it round twice, and the arrow slid in from the wrong side.
 */
.ed-arr {
  display: inline-block;
  margin-inline-start: 6px;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity var(--ed-duration-reveal) ease, transform var(--ed-duration-slide) var(--ed-ease);
}
.ed-arr:dir(rtl) { scale: -1 1; }
a:hover .ed-arr,
a:focus-visible .ed-arr { opacity: 1; transform: none; }

/* The text links, on light and on dark: see "Text links" below. */

/* ---- Disclosure controls ------------------------------------------------
 *
 * Every menu in the shell is a native <details>: it opens on click and on
 * Enter, announces its own state and needs no script, which matters because
 * `core/middleware.py` sends `script-src 'self'` with no 'unsafe-inline'.
 * js/shell.js adds Escape, click-away and one-panel-at-a-time.
 *
 * MARKER OFF, DISPLAY LEFT ALONE. Safari drops a <summary>'s disclosure role
 * when its `display` is changed, so VoiceOver stops announcing it; the marker
 * goes with `list-style` and the WebKit pseudo-element, and every flex layout
 * lives on a child element instead.
 */
.ed-header summary { list-style: none; cursor: pointer; }
.ed-header summary::-webkit-details-marker { display: none; }

/* AND THE SUMMARIES' OWN RULES MUST NOT UNDO THIS. `.ed-nav__link`,
 * `.ed-header__burger` and `.ed-drawer__summary` all set `display: block` for
 * the links that share their classes; on a <summary> that is the change that
 * costs VoiceOver the disclosure. `list-item` is the summary's own display: it
 * is block-level, so padding and min-height still apply, and the marker is
 * already gone with `list-style`. Two elements deep so it outranks them all. */
.ed-header summary.ed-nav__link,
.ed-header summary.ed-header__burger,
.ed-header summary.ed-drawer__summary { display: list-item; }

.ed-nav__menu { position: static; }

/* ---- Mega-menu panel ----------------------------------------------------
 * A floating card: 8px below the bar, inset from the viewport edges, round on
 * all four corners, a 1px outline, a faint outer ring and a layered drop
 * shadow, and NO page dimming. Aubergine with no brand glows, so it reads as
 * chrome and never blends into a dark hero or slab. AS WIDE AS A SLAB (the
 * owner, 2 October): it anchors to the full-width header and takes the
 * slabs' edges, the slab's distance from the viewport or, on a wide screen,
 * the slab's width centred (tokens.css, "A slab reaches").
 */
.ed-megamenu {
  position: absolute;
  inset-inline: max(var(--ed-slab-edge), calc((100% - var(--ed-slab-panel-maxw)) / 2));
  inset-block-start: calc(100% + var(--ed-menu-gap));
  z-index: 71;
  /* A SOLID COLOUR UNDER THE GRADIENT. Forced-colours mode drops background
   * images, and the panel was left with a transparent ground, its links
   * sitting over the hero (a11y plan item 4). Unchanged otherwise. */
  background-color: var(--ed-menu-bottom);
  background-image: linear-gradient(180deg, var(--ed-menu-top) 0%, var(--ed-menu-bottom) 100%);
  border: 1px solid var(--ed-menu-outline);
  border-radius: var(--ed-radius-menu);
  box-shadow: var(--ed-menu-shadow);
  color: var(--ed-menu-ink);
  /* Clear of the bar, and the same gap again at the bottom of the screen. */
  max-height: calc(100vh - var(--ed-header-h) - 2 * var(--ed-menu-gap));
  max-height: calc(100dvh - var(--ed-header-h) - 2 * var(--ed-menu-gap));
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: ed-menuin var(--ed-duration-menu) var(--ed-ease) both;
  font-family: var(--ed-font-display);
  /* The neutral ring: #C40C7C is 2.90:1 at the Aubergine top, under the 3:1
   * a focus indicator needs; #C8C8D0 is 9.93:1. */
  --ed-focus: var(--ed-label-on-dark);
}

@keyframes ed-menuin {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: none; }
}

/* Content takes a slab's padding (the slab frame, tokens.css), so every
 * column heading and the card row start on the logo's left edge. */
.ed-megamenu__inner,
.ed-megamenu__cards { padding-inline: var(--ed-slab-text-pad); }
.ed-megamenu__inner { padding-block: clamp(34px, 3.4vw, 54px) clamp(44px, 4.2vw, 68px); }
.ed-megamenu__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(196px, 100%), 1fr));
  gap: clamp(10px, 1vw, 14px);
  padding-block-end: clamp(18px, 1.8vw, 26px);
}

/* THE PANEL'S FOOT (core/navigation.py, PANEL_FOOT; the owner, 4 and 9
 * October): a row of links under the cards, on the content's edge, over a
 * hairline in the cards' own edge colour, as far apart as the columns above
 * them. Each is a menu link, with the links' hover and focus underline under
 * its words, and its arrow at rest, as a standalone link's is
 * (.ed-link__arr). */
.ed-megamenu__foot {
  margin-inline: var(--ed-slab-text-pad);
  padding-block: clamp(10px, 1vw, 14px) clamp(14px, 1.4vw, 20px);
  border-block-start: 1px solid var(--ed-menu-card-line);
}
.ed-megamenu__foot-list {
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ed-megamenu__foot-link { width: fit-content; max-width: calc(100% + 10px); }

.ed-megamenu__grid { display: grid; }
.ed-megamenu--services .ed-megamenu__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ed-megamenu--services .ed-megamenu__grid,
.ed-megamenu__foot-list { gap: clamp(16px, 2vw, 30px); }
.ed-megamenu--grouped .ed-megamenu__grid {
  grid-template-columns: repeat(auto-fit, minmax(min(168px, 100%), 1fr));
  gap: clamp(18px, 2.2vw, 32px);
}
.ed-megamenu--rows .ed-megamenu__grid {
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(24px, 3vw, 44px);
}
/* Products uses the Insights layout (HANDOFF.md, "Products menu"). */
.ed-megamenu--insights .ed-megamenu__grid,
.ed-megamenu--products .ed-megamenu__grid {
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
}

.ed-megamenu__col { display: flex; flex-direction: column; gap: clamp(18px, 1.8vw, 24px); }

/* The section's own page — "All services" — on the logo's edge above the
 * columns. A standalone text link, so its arrow shows at rest. */
.ed-megamenu__all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-block-end: clamp(20px, 2vw, 28px);
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-eyebrow);
  text-transform: uppercase;
  color: var(--ed-menu-ink-3);
  transition: color var(--ed-transition);
}
.ed-megamenu__all:hover,
.ed-megamenu__all:focus-visible,
.ed-megamenu__all[aria-current] { color: var(--ed-menu-ink); }
.ed-megamenu__all-arr:dir(rtl) { scale: -1 1; }

/* A practice heading is a link to the practice. */
.ed-megamenu__heading {
  display: block;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-bold);
  letter-spacing: -0.014em;
  color: var(--ed-menu-ink-1);
  margin-block-end: 7px;
  transition: color var(--ed-transition);
}
/* Only a heading that IS a link lights up; a static label must not look
 * clickable. It takes the links' underline, its box reaching 10px either
 * side of its words as drawn, the line under the words alone. */
a.ed-megamenu__heading {
  width: fit-content;
  max-width: calc(100% + 20px);
  margin-inline: -10px;
  padding-inline: 10px;
  border-radius: var(--ed-radius);
}
a.ed-megamenu__heading:hover,
a.ed-megamenu__heading:focus-visible { color: var(--ed-menu-ink); }

/* Every other group label is static text, in the mono label style. */
.ed-megamenu__heading--static {
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-eyebrow);
  text-transform: uppercase;
  color: var(--ed-menu-ink-3);
  margin-block: 0 16px;
}

.ed-megamenu__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* A link's box starts 10px before its column (margin-inline-start: -10px),
 * so its item stops 10px short of the column's end and the text wraps where
 * the design's does (its links: width fit-content, max-width 100%). */
.ed-megamenu__list > li { max-width: calc(100% - 10px); }
.ed-megamenu--services .ed-megamenu__list { gap: 1px; }
.ed-megamenu--rows .ed-megamenu__list { gap: 2px; }

.ed-megamenu__link,
.ed-megamenu__row {
  display: block;
  font-size: var(--ed-size-body);
  color: var(--ed-menu-ink-2);
  padding: 5px 10px;
  margin-inline-start: -10px;
  border-radius: var(--ed-radius);
  transition: color var(--ed-transition);
}
.ed-megamenu--services .ed-megamenu__link { padding-block: 6px; }

/* HOVER AND KEYBOARD FOCUS: full white, and a 1.5px underline in that white
 * wiping in from the inline start in 0.38s, under the text only (the content
 * box, not the padding), and nothing else: no fill, no weight change, no
 * nudge (HANDOFF.md, "Menu link hover underline", 27 and 28 September). With
 * no weight change, a link never rewraps on hover. A background, not
 * text-decoration, because only a background's size can be transitioned;
 * forced-colours mode drops it, and gets a real underline (the end of this
 * file). The design's one-line links snapped on, an inline transition
 * cancelling the wipe; on 28 September it made the wipe win everywhere.
 * The line is always full white, not the text's colour, so it does not dim
 * with the text as it fades back; the colour fades in 0.16s, as drawn.
 *
 * DRAWN ON THE WORDS, NOT THE BOX (the owner, 2 October): the line is the
 * background of an inline span round the label, so a label that wraps,
 * "Performance & reliability engineering", is underlined under each line's
 * words, where a block's background ran the line on to the column's edge.
 * The wipe runs through the lines in reading order. With line-height normal
 * the span's box is the line's, so the line sits where the block drew it. */
.ed-megamenu__link,
a.ed-megamenu__heading,
.ed-megamenu__row-title,
.ed-megamenu__all-label { transition: color var(--ed-transition-quick); }
.ed-megamenu__words {
  background-image: linear-gradient(var(--ed-menu-ink), var(--ed-menu-ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% var(--ed-wipe-thickness);
  transition: background-size var(--ed-wipe-duration) var(--ed-ease-wipe);
}
.ed-megamenu__words:dir(rtl) { background-position: 100% 100%; }
:is(.ed-megamenu__link, a.ed-megamenu__heading, .ed-megamenu__row, .ed-megamenu__all):is(:hover, :focus-visible) .ed-megamenu__words {
  background-size: 100% var(--ed-wipe-thickness);
}
.ed-megamenu__link:hover,
.ed-megamenu__link:focus-visible { color: var(--ed-menu-ink); }

/* A two-line row reads like a practice and its services: the name at 95%,
 * the description at 74%, and both full white when the row is hovered. The
 * underline is under the name alone, as wide as the name (28 September:
 * the name's box no longer stretches to the description's width). */
.ed-megamenu__row { display: flex; flex-direction: column; gap: 3px; padding-block: 8px; }
.ed-megamenu__row-title { align-self: flex-start; max-width: 100%; font-weight: var(--ed-weight-medium); color: var(--ed-menu-ink-1); }
.ed-megamenu__row-desc { font-size: var(--ed-size-caption); font-weight: var(--ed-weight-regular); color: var(--ed-menu-ink-2); }
.ed-megamenu__row:hover .ed-megamenu__row-title,
.ed-megamenu__row:hover .ed-megamenu__row-desc,
.ed-megamenu__row:focus-visible .ed-megamenu__row-title,
.ed-megamenu__row:focus-visible .ed-megamenu__row-desc { color: var(--ed-menu-ink); }

/* The page you are on, inside a panel: full white, and semibold as the cue
 * that is not colour (SC 1.4.1). A state, not a hover, so the no-weight-
 * change rule does not reach it. A practice heading is already bold, so it
 * takes a 2px rule. */
.ed-megamenu__link[aria-current] { color: var(--ed-menu-ink); font-weight: var(--ed-weight-semibold); }
.ed-megamenu__row[aria-current] .ed-megamenu__row-title,
.ed-megamenu__row[aria-current] .ed-megamenu__row-desc { color: var(--ed-menu-ink); }
.ed-megamenu__row[aria-current] .ed-megamenu__row-title { font-weight: var(--ed-weight-semibold); }
a.ed-megamenu__heading[aria-current] {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
/* It already carries its 2px line: never a second one on hover. */
a.ed-megamenu__heading[aria-current]:is(:hover, :focus-visible) .ed-megamenu__words { background-size: 0% var(--ed-wipe-thickness); }

/* ---- Menu cards ---------------------------------------------------------
 * One material. Their hover is a touch stronger than a link's: the fill from
 * 5% to 9% white, the edge to 40% white, and a tight purple glow
 * (0 0 14px -2px) that stays inside the gap between cards.
 */
.ed-menucard {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: clamp(14px, 1.4vw, 18px);
  background: var(--ed-menu-card);
  border: 1px solid var(--ed-menu-card-line);
  border-radius: var(--ed-radius-card);
  color: var(--ed-menu-ink-2);
  transition: background var(--ed-transition), border-color var(--ed-transition),
              box-shadow var(--ed-transition), color var(--ed-transition);
}
/* The title at 95%, the rest at 74%; everything full white on hover. */
.ed-menucard:hover,
.ed-menucard:focus-visible {
  color: var(--ed-menu-ink);
  background: var(--ed-menu-card-hover);
  border-color: var(--ed-menu-card-hover-line);
  box-shadow: var(--ed-menu-card-glow);
}
.ed-menucard:hover .ed-menucard__title,
.ed-menucard:focus-visible .ed-menucard__title { color: var(--ed-menu-ink); }
.ed-megamenu--rows .ed-menucard { align-self: start; }

.ed-menucard__eyebrow {
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: var(--ed-track-eyebrow);
  text-transform: uppercase;
}
.ed-menucard__title {
  color: var(--ed-menu-ink-1);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-lead);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.018em;
  line-height: 1.22;
  min-height: 42px;
  /* It fades to white with the rest of the card, not at once. */
  transition: color var(--ed-transition);
}
.ed-megamenu--rows .ed-menucard__title { min-height: 0; }
.ed-menucard__body { font-size: var(--ed-size-small); line-height: 1.55; }
.ed-menucard__action {
  margin-block-start: auto;
  padding-block-start: 4px;
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-semibold);
}

/* ---- Burger and drawer -------------------------------------------------
 * A LABELLED control. The design's button reads "Menu" with
 * aria-label="Open menu" over it — a WCAG 2.5.3 mismatch, since the accessible
 * name then does not contain the visible label. The word stays visible and
 * the aria-label goes. Text only, as the design has it.
 */
/* The drawer's landmark is the flex item; the <details> sits inside it. */
.ed-drawer-nav { flex: 0 0 auto; margin-inline-start: auto; }
.ed-header__compact + .ed-drawer-nav { margin-inline-start: 10px; }
/* Where the pill is hidden, the burger takes the free space itself. */
@media (max-width: 23.6875em) {
  .ed-header__compact + .ed-drawer-nav { margin-inline-start: auto; }
}
@media (max-width: 24.3125em) {
  .ed-header__compact:lang(en) + .ed-drawer-nav { margin-inline-start: auto; }
}
@media (max-width: 24.9375em) {
  .ed-header__compact:lang(fr) + .ed-drawer-nav { margin-inline-start: auto; }
}
@media (min-width: 72.5em) {
  :root:not(.ed-nav-tight) .ed-drawer-nav { display: none; }
}

/* 44px tall, where the design's 11px padding draws 40px: the label is
 * centred by its inner box (above), 13px below the box's top edge, so it
 * sits at the drawn y in every language. */
.ed-header__burger {
  display: block;
  min-height: var(--ed-target);
  padding-block: 0;
  padding-inline: 17px;
  background: none;
  border: 1px solid var(--ed-border-dark-soft);
  border-radius: var(--ed-radius);
  color: var(--ed-on-dark-soft);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.01em;
}
/* NO FILL ON HOVER OR WHILE OPEN, as drawn: the open drawer is its own cue,
 * and the <summary> announces its expanded state. */

/* FULL SCREEN, as the handoff's text has it. The design files draw a dropdown
 * with a max-height instead; a fixed sheet is the version where the page
 * cannot scroll underneath a reader's thumb. */
.ed-drawer {
  position: fixed;
  inset-block: var(--ed-header-h) 0;
  inset-inline: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--ed-nav);
  border-block-start: 1px solid var(--ed-border-dark-soft);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px var(--ed-gutter) 26px;
  --ed-focus: var(--ed-nav-line);
}
/* THE SHEET SCROLLS; ITS ROWS NEVER SHRINK. A flex column squeezed the rows
 * and the pill towards their 44px floor as soon as an open group overflowed
 * it; the design's keep their height and its drawer scrolls. */
.ed-drawer > * { flex-shrink: 0; }
@media (min-width: 72.5em) {
  :root:not(.ed-nav-tight) .ed-drawer { display: none; }
}

.ed-drawer__group { border-block-end: 1px solid var(--ed-border-dark-soft); }

.ed-drawer__summary,
.ed-drawer__top {
  display: block;
  min-height: var(--ed-target);
  padding-block: 17px;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.008em;
  color: var(--ed-on-dark);
}
.ed-drawer__top { border-block-end: 1px solid var(--ed-border-dark-soft); }

.ed-drawer__summary-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
/* White at 74%, as drawn since 27 September (it was #C40C7C, 3.69:1 on
 * black): 11.18:1, and the only thing saying whether a group is open. */
.ed-drawer__summary-inner::after {
  content: "+";
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-lead);
  line-height: 1;
  color: var(--ed-nav-util);
}
.ed-drawer__group[open] > .ed-drawer__summary .ed-drawer__summary-inner::after {
  content: "\2212";
}

.ed-drawer__panel { padding-block-end: 18px; }

.ed-drawer__label {
  margin: 0;
  padding-block: 12px 4px;
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: var(--ed-track-label);
  text-transform: uppercase;
  color: var(--ed-on-dark-faint);
}

.ed-drawer__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
  gap: 0 clamp(16px, 3vw, 40px);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Archivo, as the design's drawer links inherit from its body; the build's
 * body is IBM Plex Sans. */
.ed-drawer__link {
  display: flex;
  align-items: center;
  min-height: var(--ed-target);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-small);
  color: var(--ed-on-dark-mute);
  transition: color var(--ed-transition-quick);
}
.ed-drawer__link:hover { color: var(--ed-on-dark); }
.ed-drawer__link--all { color: var(--ed-on-dark-soft); font-weight: var(--ed-weight-semibold); }
.ed-drawer__link[aria-current] { color: var(--ed-on-dark); font-weight: var(--ed-weight-semibold); }

/* The drawer's language row: the design's drawer has none, and below 1160px
 * the bar's picker is hidden, so without it a phone could not change
 * language. The drawer's link colours; the current one white and semibold. */
.ed-drawer__langs {
  display: flex;
  flex-wrap: wrap;
  gap: 0 28px;
  margin: 0;
  padding: 6px 0;
  list-style: none;
  border-block-end: 1px solid var(--ed-border-dark-soft);
}
.ed-drawer__lang {
  display: flex;
  align-items: center;
  min-height: var(--ed-target);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-small);
  color: var(--ed-on-dark-mute);
  transition: color var(--ed-transition);
}
.ed-drawer__lang:hover { color: var(--ed-on-dark); }
.ed-drawer__lang[aria-current] { color: var(--ed-on-dark); font-weight: var(--ed-weight-semibold); }

.ed-drawer__cta {
  margin-block-start: 20px;
  padding: 17px 22px;
  font-size: var(--ed-size-body);
  letter-spacing: -0.01em;
}

/* ---- The slab frame -------------------------------------------------------
 * EVERY DARK BAND BELOW THE HERO IS A SLAB (HANDOFF.md, "Corner rule"): a
 * white wrapper, a panel rounded on all four corners that reaches
 * --ed-slab-reach past the content column each side (the owner, 2 October;
 * the design's runs to the viewport less the inset), and an inner column
 * whose padding brings its words back to the content's edge, so its
 * headings, cards and the logo share one left edge. Written once; each slab
 * adds only its own ground and rhythm (tokens.css, "A slab reaches").
 */
.ed-slab {
  background: var(--ed-bg);
  padding-inline: var(--ed-slab-edge);
}
.ed-slab__panel {
  position: relative;
  overflow: hidden;
  max-width: var(--ed-slab-panel-maxw);
  margin-inline: auto;
  border-radius: var(--ed-radius-slab);
  color: var(--ed-on-dark);
}
.ed-slab__inner { padding-inline: var(--ed-slab-text-pad); }

/* ---- Closing slab -------------------------------------------------------
 * The last panel on every page: the near-black three-colour mesh in the slab
 * frame, with a white gap above it so it never touches a dark section. It
 * does not animate — the handoff: "It is part of the page structure and
 * should feel built, not performed."
 */
.ed-slabcta {
  padding-block-start: var(--ed-slab-inset);
  /* The neutral ring: in the mesh's magenta glow #C40C7C is under 3:1 (2.78:1
   * beside the quiet link on a phone); #C8C8D0 is 9.51:1 or better. */
  --ed-focus: var(--ed-label-on-dark);
}

.ed-slabcta__slab {
  background: var(--ed-slab-mesh);
  background-color: var(--ed-slab-ground);
}

.ed-slabcta__inner {
  padding-block: var(--ed-slab-close-y);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 26px 40px;
}

.ed-slabcta__copy { max-width: 620px; }

.ed-slabcta__title {
  margin: 0 0 16px;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-h2);
  font-weight: var(--ed-weight-bold);
  line-height: 1.08;
  letter-spacing: var(--ed-track-tight);
  text-wrap: balance;
  color: var(--ed-on-dark);
}

.ed-slabcta__lede {
  margin: 0;
  font-size: var(--ed-size-lead);
  line-height: 1.65;
  color: var(--ed-on-dark-86);
}

.ed-slabcta__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }

/* ---- The enquiry form (contact/_enquiry_form.html) ---------------------
 * The design's lead form panel (HOME:1223-1259, rules HOME:36-47): a white
 * card that gains a purple ring on hover and while a field has focus — no bar
 * or stripe (HANDOFF.md, 26 September) — and underlined fields whose label
 * turns magenta as you type in them. The
 * homepage's contact slab and the contact page both render it; the panel is
 * a light island (ed-light), so it is white with light inks on the dark slab
 * too.
 *
 * THREE MEASURED DEPARTURES (BASELINE.md §5): the resting underline is
 * --ed-input-line, not the design's #D6D6DA at 1.45:1, because it is the
 * field's only edge; placeholders are --ed-muted (5.61:1), not #A3A3AB
 * (2.50:1), because they are example values a reader must be able to read;
 * and there is an error state, which the design does not have.
 *
 * MOBILE: rows are two fields where two fit at 190px each and one otherwise,
 * so a phone gets one column with no media query; every control is at least
 * 44px tall and 17px, which is also over the 16px below which iOS zooms the
 * page on focus.
 */
.ed-leadform {
  --lf-base: var(--ed-model-shadow);
  position: relative;
  overflow: hidden;
  scroll-margin-top: 8px;
  padding: clamp(24px, 2.7vw, 40px);
  background: var(--ed-surface);
  border: 1px solid var(--ed-leadform-edge);
  border-radius: var(--ed-radius-card);
  box-shadow: var(--lf-base);
  color: var(--ed-ink);
}
.ed-leadform:hover { box-shadow: var(--lf-base), var(--ed-leadform-ring); }
.ed-leadform:focus-within { box-shadow: var(--lf-base), var(--ed-leadform-focus); }

.ed-leadform__title {
  margin: 0 0 8px;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-card);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.018em;
  color: var(--ed-ink);
}
.ed-leadform__intro {
  margin: 0 0 20px;
  font-size: var(--ed-size-body);
  line-height: 1.55;
  color: var(--ed-ink);
}
.ed-leadform__errors {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-inline-start: 3px solid var(--ed-error);
  background: var(--ed-error-wash);
  font-size: var(--ed-size-body);
  line-height: 1.5;
  color: var(--ed-error);
}
.ed-leadform__errors p { margin: 0; }

.ed-leadform__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 16px;
  margin-block-end: 16px;
}
.ed-leadform__row:last-of-type { margin-block-end: 20px; }

.ed-field { display: flex; flex-direction: column; min-width: 0; }
.ed-field__label {
  margin-block-end: 4px;
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ed-sub);
  transition: color var(--ed-transition-quick);
}
.ed-field:focus-within .ed-field__label { color: var(--ed-magenta); }

/* The underline is the focus indicator: 2px of magenta, 7.28:1 on white. */
.ed-field__control {
  width: 100%;
  min-height: var(--ed-target);
  margin: 0;
  padding: 10px 0;
  background-color: transparent;
  border: 0;
  border-block-end: 1px solid var(--ed-input-line);
  border-radius: 0;
  /* Archivo, as the design's controls inherit it, and the line "normal",
   * as every pill's: each control is then exactly 44px (a textarea keeps
   * its own 1.5, below). */
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-lead);
  line-height: normal;
  color: var(--ed-ink);
  /* Transparent, not none: forced-colours mode paints a transparent outline
   * in the system colour, so focus stays visible there (a11y plan item 7). */
  outline: 2px solid transparent;
  outline-offset: 2px;
  transition: border-color var(--ed-transition-quick), box-shadow var(--ed-transition-quick);
}
.ed-field__control::placeholder { color: var(--ed-muted); opacity: 1; }
.ed-field__control:hover { border-block-end-color: var(--ed-byline); }
.ed-field__control:focus {
  border-block-end-color: var(--ed-magenta);
  box-shadow: inset 0 -1px 0 var(--ed-magenta);
}
/* Filled in and valid: purple, as drawn (HOME:44), but never over focus. */
input.ed-field__control:not(:placeholder-shown):valid:not(:focus),
textarea.ed-field__control:not(:placeholder-shown):not(:focus) {
  border-block-end-color: var(--ed-link);
}
.ed-field--error .ed-field__control:not(:focus) { border-block-end-color: var(--ed-error); }
textarea.ed-field__control { resize: vertical; line-height: 1.5; }

/* A <select> cannot carry a pseudo-element, so the chevron is two small
 * gradients on the control itself, placed from the inline end. 28px at that
 * end, and an ellipsis, so a long value never runs under the chevron
 * (HANDOFF.md, "Form fields", 27 September). */
.ed-field__select .ed-field__control {
  appearance: none;
  padding-inline-end: 28px;
  text-overflow: ellipsis;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ed-sub) 50%),
    linear-gradient(135deg, var(--ed-sub) 50%, transparent 50%);
  background-position: calc(100% - 12px) 55%, calc(100% - 7px) 55%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
}
.ed-field__select .ed-field__control:dir(rtl) { background-position: 7px 55%, 12px 55%; }

.ed-field__error {
  margin: 8px 0 0;
  font-size: var(--ed-size-body);
  line-height: 1.45;
  color: var(--ed-error);
}

/* The plain main button: no badge (the owner, 4 October 2026; "The main
 * button"). An editor's label runs to 40 characters, which at 320px is
 * wider than the pill, so this one pill wraps rather than clip; "Book the
 * call" stays on one line. */
.ed-leadform__submit { --ed-btn-pad-y: 17px; --ed-btn-pad-x: 24px; white-space: normal; text-wrap: balance; }

/* Under the pill: the owner's notice (always; 14px, the cookie card's notice
 * size), then an editor's optional fine print (13px). Both in --ed-sub,
 * 6.13:1 on the form's white. The notice's link: "A link in a short notice",
 * below. */
.ed-leadform__notice,
.ed-leadform__fine {
  margin: 13px 0 0;
  line-height: 1.5;
  color: var(--ed-sub);
}
.ed-leadform__notice { font-size: var(--ed-size-small); }
.ed-leadform__fine { font-size: var(--ed-size-caption); }

.ed-leadform__done {
  min-height: 320px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 16px;
}
.ed-leadform__done .ed-leadform__title {
  margin-block-end: 14px;
  font-size: var(--ed-size-h3);
  letter-spacing: -0.022em;
}
.ed-leadform__text {
  max-width: 420px;
  margin: 0;
  font-size: var(--ed-size-body);
  line-height: 1.62;
  color: var(--ed-ink);
}

/* ---- The footer's newsletter sign-up (newsletter/_footer_form.html) ----
 * HOME:1572-1580: a label, a pill input and a Subscribe pill, under Why
 * EvolveDash and Company. It renders only once the consent line is written.
 *
 * DEPARTURES (BASELINE.md §5): the input's edge is --ed-input-line, because
 * the design's #DEDEE1 is 1.23:1 against the footer and it is the field's
 * only edge; the input is 16px, not 14px, or iOS zooms the page on focus;
 * and the row wraps, putting the button under the input where the two do not
 * fit side by side with a usable input — a 320px phone.
 */
.ed-news {
  grid-column: 1 / -1;
  max-width: 420px;
  margin-block-start: clamp(6px, 0.8vw, 12px);
  scroll-margin-top: 8px;
}
.ed-news__form { margin: 0; }
.ed-news__label {
  display: block;
  margin: 0 0 8px;             /* a <p> above the thanks, the <label> in the form */
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-label);
  text-transform: uppercase;
  color: var(--ed-sub);
}
.ed-news__row { display: flex; flex-wrap: wrap; gap: 8px; }
.ed-news__input {
  /* In em, so enlarged text wraps the button under it (item 22); 11em keeps
   * Subscribe on the input's row at 1000-1023px, and still wraps the row
   * under about 294px. */
  flex: 1 1 11em;
  min-width: 0;
  min-height: var(--ed-target);
  margin: 0;
  padding: 11px 16px;
  background: var(--ed-surface);
  border: 1px solid var(--ed-input-line);
  border-radius: var(--ed-radius-pill);
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-input);
  color: var(--ed-ink);
  outline: 2px solid transparent;   /* visible in forced colours; item 7 */
  outline-offset: 2px;
  transition: border-color var(--ed-transition-quick), box-shadow var(--ed-transition-quick);
}
.ed-news__input::placeholder { color: var(--ed-muted); opacity: 1; }
.ed-news__input:hover { border-color: var(--ed-byline); }
.ed-news__input[aria-invalid="true"] { border-color: var(--ed-error); }
.ed-news__input:focus {
  border-color: var(--ed-link);
  box-shadow: var(--ed-field-focus-ring);
}
/* The plain main button, 44px tall from its own padding, as the field
 * beside it is. */
.ed-news__btn { --ed-btn-pad-y: calc((var(--ed-target) - 1lh) / 2); --ed-btn-pad-x: 22px; flex: 0 0 auto; font-size: var(--ed-size-small); letter-spacing: normal; }
.ed-news__consent {
  margin: 10px 0 0;
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-body);
  line-height: 1.5;
  color: var(--ed-sub);
}
.ed-news__error {
  margin: 8px 0 0;
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-body);
  line-height: 1.45;
  color: var(--ed-error);
}
.ed-news__done {
  margin: 0;
  font-size: var(--ed-size-small);
  line-height: 1.55;
  color: var(--ed-magenta);
}

/* ---- Footer ------------------------------------------------------------
 * The same on every page: brand, Services, How to buy it, and a group holding
 * Why EvolveDash and Company. A column with nothing real to link is not
 * rendered, and the grid places each column explicitly so a missing one
 * leaves its track empty rather than sliding the rest along.
 *
 * ARCHIVO THROUGHOUT, as the design's footer inherits it: its blurb, reply
 * line, links and thanks are <div>s and <a>s, which its "p { IBM Plex Sans }"
 * rule never reaches. The copyright line, the email field and the two
 * newsletter lines the design has no drawing for keep the body face.
 */

.ed-footer {
  font-family: var(--ed-font-display);
  background: var(--ed-ground-footer);
}
/* The design draws no footer line as a <p>, so none takes the base rule's
 * "pretty" wrapping: every line breaks where the design's does. */
.ed-footer :where(p) { text-wrap: wrap; }

.ed-footer__inner {
  max-width: var(--ed-maxw);
  margin-inline: auto;
  padding: clamp(40px, 4vw, 60px) var(--ed-gutter) clamp(14px, 1.4vw, 20px);
}

.ed-footer__cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 2.4vw, 36px);
  padding-block-end: clamp(22px, 2.2vw, 32px);
  border-block-end: 1px solid var(--ed-rule-soft);
}

.ed-footer__group {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 2.2vw, 34px) clamp(26px, 2.6vw, 40px);
  align-content: start;
}

@media (min-width: 40em) {
  .ed-footer__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ed-footer__brand,
  .ed-footer__group { grid-column: 1 / -1; }
}
@media (min-width: 62.5em) {
  .ed-footer__cols { grid-template-columns: 1.25fr 1.25fr 1fr 2fr; }
  .ed-footer__brand { grid-column: 1; }
  .ed-footer__col--services { grid-column: 2; }
  .ed-footer__col--buy { grid-column: 3; }
  .ed-footer__group { grid-column: 4; }
}

.ed-footer__logo { height: var(--ed-logo-h); width: auto; display: block; margin-block-end: 16px; }


.ed-footer__tagline {
  margin: 0 0 10px;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-h3);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: var(--ed-track-snug);
  line-height: 1.14;
  color: var(--ed-ink);
}

.ed-footer__blurb {
  margin: 0 0 22px;
  max-width: 260px;
  font-size: var(--ed-size-body);
  line-height: 1.6;
  color: var(--ed-dek);
}

.ed-footer__cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }

.ed-footer__reply {
  margin: 0;
  max-width: 260px;
  font-size: var(--ed-size-small);
  line-height: 1.5;
  color: var(--ed-dek);
}

.ed-footer__heading {
  margin: 0 0 18px;
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-label);
  text-transform: uppercase;
  color: var(--ed-sub);
}

.ed-footer__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ed-footer__list a {
  font-size: var(--ed-size-body);
  line-height: 1.4;
  color: var(--ed-body);
  transition: color var(--ed-transition-quick);
}
.ed-footer__list a:hover { color: var(--ed-purple-deep); }

.ed-footer__legal {
  padding-block-start: clamp(18px, 1.8vw, 24px);
  display: flex;
  flex-wrap: wrap;
  gap: 14px 30px;
  justify-content: space-between;
  align-items: center;
}
.ed-footer__legal-left { display: flex; flex-direction: column; gap: 6px; }

.ed-footer__copy {
  margin: 0;
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-small);
  color: var(--ed-sub);
}

/* --ed-sub, NOT the design's #67676F: that is 4.26:1 where this line
 * actually sits, over the footer's bottom-left fade, and fails AA on every
 * page; #61616A is 4.66:1 there. */
.ed-footer__places {
  margin: 0;
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-places);
  text-transform: uppercase;
  color: var(--ed-sub);
}

.ed-footer__legal-links { display: flex; flex-wrap: wrap; gap: 20px; }

/* The footer's language picker (HANDOFF.md, "Language in the footer", 27
 * September): light footer, so a #D6D6DA border and a white list. Below
 * 1000px, where the row wraps, it is pushed to the end of its line
 * (margin-inline-start: auto) so the list, anchored at its inline end, stays
 * inside the page; the design's wraps to the start and opens off screen.
 * From 1000px the row is one line and the design's space-between places all
 * three blocks, the links midway between the copyright and the picker. */
.ed-flang { position: relative; margin-inline-start: auto; }
@media (min-width: 62.5em) {
  .ed-flang { margin-inline-start: 0; }
}
.ed-flang__button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 11px;
  border: 1px solid var(--ed-rule);
  border-radius: var(--ed-radius);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-small);
  color: var(--ed-body);
  cursor: pointer;
  list-style: none;
  transition: border-color var(--ed-transition-quick), color var(--ed-transition-quick);
}
.ed-flang__button::-webkit-details-marker { display: none; }
/* One line height for every name, the English rows' own: the Arabic name's
 * taller face grew its row by 3px and the Arabic page's button by 6px. */
.ed-flang__button,
.ed-flang__link { line-height: var(--ed-leading-lang); }
.ed-flang__button:hover { border-color: var(--ed-ink); color: var(--ed-ink); }
.ed-flang__globe { flex: 0 0 auto; }
.ed-flang__chev { display: block; opacity: 0.7; transition: transform var(--ed-duration-reveal) ease; }
.ed-flang[open] .ed-flang__chev { transform: rotate(180deg); }
.ed-flang__list {
  position: absolute;
  inset-block-end: calc(100% + var(--ed-menu-gap));
  inset-inline-end: 0;
  z-index: 20;
  min-width: 176px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--ed-surface);
  border: 1px solid var(--ed-border);
  border-radius: var(--ed-radius-tile);
  box-shadow: var(--ed-flang-shadow);
}
.ed-flang__link {
  display: block;
  font-family: var(--ed-font-display);
  padding: 8px 10px;
  border-radius: var(--ed-radius);
  font-size: var(--ed-size-small);
  text-align: start;
  color: var(--ed-dek);
  transition: color var(--ed-transition-quick);
}
/* Every name reserves its semibold width, so the current one's weight never
 * moves anything (the design's own ::after trick). */
.ed-flang__link::after {
  content: attr(data-label);
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: var(--ed-weight-semibold);
}
/* Ink on hover only; keyboard focus shows the ring alone. The current
 * language is semibold in the list's own #44444A (HANDOFF.md: "the current
 * one is semibold"). */
.ed-flang__link:hover { color: var(--ed-ink); }
.ed-flang__link[aria-current] { font-weight: var(--ed-weight-semibold); }
/* Touch gets 44px targets; a mouse keeps the design's sizes. */
@media (pointer: coarse) {
  .ed-flang__button { min-height: var(--ed-target); }
  .ed-flang__link { display: flex; flex-direction: column; justify-content: center; min-height: var(--ed-target); }
}
.ed-footer__legal-links :is(a, button) { font-size: var(--ed-size-small); color: var(--ed-body); transition: color var(--ed-transition-quick); }
.ed-footer__legal-links :is(a, button):hover { color: var(--ed-purple-deep); }
/* "Cookie settings" is a <button>, because it opens the cookie card rather
 * than going anywhere, drawn as the links beside it: this strips what a
 * browser gives a button, and the two rules above give it the links' look.
 * Its 44px target with a mouse is the shared hit area (.ed-hit, "Text
 * links"); on a touch screen it grows with the links (the touch rule at the
 * end of this file). */
.ed-footer__cookies {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  line-height: inherit;
  text-align: start;
  cursor: pointer;
}

/* Back-to-top, flush with the viewport's inline-end edge (HOME:1610-1611).
 * 11px, not the 10px this used to be: the handoff's floor for any mono label.
 * The homepage's own padding (16px at the end), not the sub-pages'.
 *
 * THE BOX IS THE DRAWN 33px TAB; its 44px target is the shared hit area
 * (.ed-hit, "Text links"), turned to reach only upward, 11px into the
 * footer's padding: the tab sits on the page's bottom edge, and a hit area
 * below it would make the page taller. */
.ed-footer__totop-row {
  display: flex;
  justify-content: flex-end;
  padding-inline: var(--ed-gutter);
}
.ed-footer__totop {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-inline-end: calc(var(--ed-gutter) * -1);
  padding-block: 9px 10px;
  padding-inline: 14px 16px;
  background: var(--ed-tab-bg);
  color: var(--ed-tab-ink);
  /* One round corner, and square ones, the focus ring's included (the
   * global 2px would otherwise round the other three). */
  border-radius: 0;
  border-start-start-radius: var(--ed-radius-tab);
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-tab);
  text-transform: uppercase;
  transition: background var(--ed-transition), color var(--ed-transition);
}
.ed-footer__totop:hover { background: var(--ed-dark-panel); color: var(--ed-on-dark); }
/* Two classes, so it outranks the shared hit area, which comes later. */
.ed-footer__totop.ed-hit::after { inset-block: min(0px, calc(100% - var(--ed-target))) 0; }

/* ---- The cookie card (core/templates/core/consent_card.html) -------------
 * The owner's, 3 October 2026; the design has none (docs/BASELINE.md §5). A
 * card, not a banner and not a modal: fixed at the bottom-left, the bottom
 * edge on a phone inside the page gutter, over the page and under the header,
 * its menus and the phone drawer (z-index 60 and up), which cover it while
 * they are open. Hidden in the HTML; analytics.js shows it.
 *
 * REJECT AND ACCEPT ARE THE SAME PILL, the plain main button (the owner, 7
 * October 2026), the same size, side by side in two equal columns:
 * neither is the easier one to press. Equal at every width: a bare `1fr`
 * column grows to its own label when the card is narrow, and with the
 * badge Reject came out 2.4px narrower than Accept at 320px (review of 4
 * October); minmax(0, 1fr) never lets a label size its column.
 *
 * NOTHING MOVES WHEN IT APPEARS: it is out of the flow. While it shows,
 * <html> carries `ed-consent-open` and --ed-consent-space (tokens.css), so
 * what the browser scrolls into view, focus included, stops above it (WCAG
 * 2.4.11), and the footer gains that much room at its end, so the last row
 * of the page can scroll out from under it. Both go when the visitor chooses.
 *
 * EXCEPT ON A SCREEN 25em TALL OR LESS, where it sits in the page instead:
 * where it already is in the document, after the skip link and above the
 * header, and it scrolls away with the page. 1280x1024 at 400% zoom is
 * 320x256 (the reference size of WCAG 1.4.10): there the fixed card and the
 * sticky header covered every pixel, so all 16 controls Tab reached in
 * <main> on /blog/ were hidden (2.4.11), and at 320x180 (1280x720 at 400%)
 * the card's heading sat above the screen where no scrolling could reach it.
 * A phone on its side is that short too, and a card over most of it is
 * worse than one at the top of the page. The price, for a first visit on a
 * screen that short only: the page moves down once when the card appears
 * (docs/BASELINE.md §5).
 */
.ed-consent {
  position: fixed;
  inset-inline: var(--ed-consent-inset);
  inset-block-end: var(--ed-consent-inset);
  z-index: 50;
  display: grid;
  gap: 10px;
  padding: 18px 20px 20px;
  background: var(--ed-surface);
  color: var(--ed-body);
  border: 1px solid var(--ed-border);
  border-radius: var(--ed-radius-card);
  box-shadow: var(--ed-consent-shadow);
}
.ed-consent[hidden] { display: none; }
@media (min-width: 40em) {
  .ed-consent {
    inset-inline-end: auto;
    inline-size: var(--ed-consent-w);
    max-inline-size: calc(100% - 2 * var(--ed-consent-inset));
    padding: 22px 24px 24px;
  }
}
.ed-consent__title {
  margin: 0;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-card-title);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: var(--ed-track-snug);
  line-height: 1.2;
  color: var(--ed-ink);
}
.ed-consent__text {
  margin: 0;
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-small);
  line-height: 1.55;
  color: var(--ed-body);
}
/* Its link: "A link in a short notice", after the landmarks' reset. */
.ed-consent__actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-block-start: 6px;
}
.ed-consent__choice { --ed-btn-pad-y: calc((var(--ed-target) - 1lh) / 2); --ed-btn-pad-x: 16px; min-block-size: var(--ed-target); }
/* It rises into place the way a menu panel opens, unless the reader asked
 * for less motion. */
@media (prefers-reduced-motion: no-preference) {
  .ed-consent:not([hidden]) { animation: ed-consent-in var(--ed-duration-menu) var(--ed-ease); }
}
@keyframes ed-consent-in {
  from { opacity: 0; transform: translateY(8px); }
}
/* The same 25em as the short-screen rule below, in its exact complement. */
@media not all and (max-height: 25em) {
  .ed-consent-open { scroll-padding-block-end: calc(var(--ed-consent-space) + 8px); }
  .ed-consent-open .ed-footer { padding-block-end: calc(var(--ed-consent-space) + 8px); }
}
/* Short screens: in the page, not over it (see the note above). Last, so it
 * outranks the placement above at every width. */
@media (max-height: 25em) {
  .ed-consent { position: static; margin: var(--ed-consent-inset); }
}
@media print {
  .ed-consent { display: none; }
}

/* ---- Link decoration in the shell --------------------------------------
 *
 * NAVIGATION LINKS ARE NOT BODY LINKS. WCAG 1.4.1 asks that a link be told
 * apart by more than colour when it sits in running text; these are lists of
 * links in the header's and footer's landmarks, where position, grouping and
 * role already say what they are, so none is underlined in any state. The
 * footer's links change colour on hover and show the ring on focus, as drawn.
 */
.ed-header a,
.ed-drawer a,
.ed-slabcta a,
.ed-footer a { text-decoration: none; }

/* A LINK IN A SHORT NOTICE: "privacy policy" in the cookie card, under the
 * enquiry form and in the newsletter's consent line (docs/legal/
 * privacy-policy.md, "The short notices on the site"). A word in running
 * text, so underlined (SC 1.4.1), in the light ground's link colour, since
 * all three sit on a light ground: #6B21C4, 7.96:1 on white. AFTER THE RESET
 * ABOVE, ON PURPOSE: the newsletter's line is in the footer, and its link is
 * part of a sentence, not navigation. Its target is its line, as for any link
 * inside a sentence (SC 2.5.8's inline exception). */
:is(.ed-consent__text, .ed-leadform__notice, .ed-news__consent) a {
  color: var(--ed-link);
  text-decoration: underline;
  text-decoration-thickness: var(--ed-underline);
  text-underline-offset: 0.18em;
  transition: color var(--ed-transition-quick),
              text-decoration-thickness var(--ed-wipe-duration) var(--ed-ease);
}
/* On hover and keyboard focus its underline swells from --ed-underline to
 * --ed-underline-hover as the color deepens: an inline link's answer, as in
 * an article's body (the owner, 4 October: "Hover and focus: ... inline
 * links"). Nothing moves or reflows: the line only grows away from the
 * words. */
:is(.ed-consent__text, .ed-leadform__notice, .ed-news__consent) a:is(:hover, :focus-visible) {
  color: var(--ed-link-hover);
  text-decoration-thickness: var(--ed-underline-hover);
}

/* The skip link's target. Without scroll-margin the sticky bar covers the
 * heading it just jumped to (its ring is reset under "Focus"). */
#main { scroll-margin-top: 8px; }

/* Read by a screen reader, drawn nowhere: "(opens in a new tab)", the text
 * behind a redaction bar. The clip-path form, because `clip` is deprecated. */
.ed-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Scripts ------------------------------------------------------------
 * ARABIC TEXT IS SET IN IBM PLEX SANS ARABIC, WITH NO TRACKING AND NO CASE
 * (HANDOFF.md, "Language picker", and the design's own rule, HOME:27).
 * Arabic is joined-up writing: letter-spacing prises a word's letters apart,
 * so the design's tracked mono labels and tightened headings lose it here.
 * And a Latin word inside an Arabic label — "5.0 على Clutch" — keeps its own
 * case rather than the label's upper-casing. `!important` because this is a
 * rule of the script, not a style to be outranked.
 *
 * `:lang(ar)` ALONE, never `:lang(ar) *`: each element matches by its OWN
 * language, so the English islands inside an Arabic page — the service rail,
 * the pillars, the footer, marked lang="en" (core/i18n.py) — keep their
 * design faces. The family token is tokens.css's --ed-font-arabic.
 */
:lang(ar) {
  font-family: var(--ed-font-arabic) !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
}

/* In-page links glide rather than jump (HOME:84), unless the reader asked
 * for less motion — then the reduced-motion block below sets it back. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* ---- Motion ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- No horizontal overflow, at any width ------------------------------ */
html, body { overflow-x: clip; }

/* ---- Section primitives and the insight card ----------------------------
 * MOVED FROM home.css (27 September 2026), unchanged: the homepage uses them,
 * and so do the related cards under every article (blog/article_page.html)
 * and the IA pages to come. HANDOFF.md, "Components to build once". */

/* THE EYEBROW, on every section. It wraps plainly: every eyebrow the design
 * draws is a <div> or <span>, which its "p { text-wrap: pretty }" rule never
 * reaches (the same rule as here, under "Base"). */
.ed-eyebrow {
  margin: 0 0 18px;
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-eyebrow);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-eyebrow);
  text-transform: uppercase;
  text-wrap: wrap;
  color: var(--ed-magenta);
}
/* ON A DARK GROUND (HANDOFF.md and CLAUDE.md, 28 September, night): brand
 * purple on dark, the slabs' --ed-slab-eyebrow, never magenta, never plain
 * white and never a tint. */
.ed-eyebrow--on-dark { color: var(--ed-slab-eyebrow); }

/* A DOT-LED TAG (HANDOFF.md, "Tags and badges": never a pill): a 6px dot
 * in the tag's own colour before its words. Only what every tag shares; each
 * keeps its own type and colour. */
.ed-tag { display: inline-flex; align-items: center; gap: var(--ed-tag-gap); }
.ed-tag::before {
  content: "";
  flex: none;
  inline-size: var(--ed-dot-size);
  block-size: var(--ed-dot-size);
  border-radius: 50%;
  background: currentColor;
}

/* THE BAR THAT LEADS AN EYEBROW: 18x2px, magenta to purple, never a pill.
 * Its own class, since the delivery draws it on light grounds too. */
.ed-eyebrow-bar {
  display: flex;
  align-items: center;
  gap: 10px;
}
.ed-eyebrow-bar::before {
  content: "";
  flex: 0 0 auto;
  inline-size: 18px;
  block-size: 2px;
  border-radius: var(--ed-radius-pill);
  background: var(--ed-eyebrow-bar);
}
.ed-eyebrow-bar:dir(rtl)::before { background: var(--ed-eyebrow-bar-rtl); }

.ed-h2 {
  margin: 0;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-h2);
  font-weight: var(--ed-weight-bold);
  line-height: 1.08;
  letter-spacing: var(--ed-track-tight);
  color: var(--ed-ink);
  text-wrap: balance;
}

.ed-lede {
  margin: 0;
  font-size: var(--ed-size-lead);
  line-height: 1.65;
  color: var(--ed-dek);
  text-wrap: pretty;
}

/* ---- Text links ---------------------------------------------------------
 * ONE COMPONENT ON TWO GROUNDS: .ed-link on a light section (#6B21C4,
 * hovering to #4B0F9E; tokens.css, --ed-link) and .ed-textlink on a dark one
 * (86% white, hovering to white). IBM Plex Sans 15px/600 in sentence case
 * (HANDOFF.md). The design leaves three of them with no hover rule; HANDOFF
 * gives the hover, and all of them take it.
 *
 * THE BOX IS THE LINE, THE TARGET IS 44px. The design draws a text link as a
 * plain line of text, so that is the box: each section spaces it with the
 * design's own values and nothing else. The owner's 44px target
 * (--ed-target) is an invisible hit area laid over it, reaching above and
 * below the line; it never moves the layout. ONE HIT AREA FOR EVERY CONTROL
 * WHOSE BOX IS ITS DRAWN SHAPE: the text links, every pill (.ed-btn), and
 * anything else that takes .ed-hit (the back-to-top tab, a row button).
 *
 * THE ARROW (HANDOFF.md, "Arrows"). A standalone link ends in " →": a real
 * word space in the link's own face, then the arrow, both at rest
 * (.ed-link__arr). A link beside a pill reveals its arrow on hover or focus,
 * 8px from the words, as the design's flex links space it (.ed-arr). Both
 * mirror under Arabic, the space staying on the words' side.
 */
.ed-link,
.ed-textlink {
  position: relative;
  display: inline-flex;
  align-items: center;
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: -0.005em;
  text-decoration: none;
  transition: color var(--ed-transition);
}
.ed-link { color: var(--ed-link); }
.ed-link:hover { color: var(--ed-link-hover); }
.ed-textlink { color: var(--ed-on-dark-86); }
.ed-textlink:hover { color: var(--ed-on-dark); }
.ed-link::after,
.ed-textlink::after,
.ed-btn::after,
.ed-hit::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  /* Half of what the line lacks of the target, above and below; a link
   * that wraps to two lines is already taller and reaches no further. */
  inset-block: min(0px, calc((100% - var(--ed-target)) / 2));
}
.ed-hit { position: relative; }
.ed-link__arr { display: inline-block; }
.ed-link__arr::before { content: " "; white-space: pre; }
.ed-link__arr:dir(rtl) { scale: -1 1; }
.ed-link__arr:dir(rtl)::before { content: none; }
.ed-link__arr:dir(rtl)::after { content: " "; white-space: pre; }
:is(.ed-link, .ed-textlink) .ed-arr { margin-inline-start: 8px; }
/* THE ARROW STEPS FORWARD (the owner, 4 October: "Hover and focus: ...
 * inline links"; HANDOFF.md's own "the submit arrow nudges 4px on hover"):
 * on hover and keyboard focus a standalone link's resting arrow moves
 * --ed-nudge on, and back when the pointer leaves. Plainly, not times
 * --ed-dir: the mirror above turns the step round under Arabic (see .ed-arr).
 * Transform only, so the words never move. The hover step never on a touch
 * screen, where a tap would leave it stepped; the keyboard's on every
 * screen, an iPad with a keyboard included, since a tap never matches
 * :focus-visible (FOCUS NEVER WAITS FOR HOVER: the owner, 7 October 2026);
 * neither for a reader who asked for less motion. A hidden arrow (.ed-arr)
 * already slides in, and nothing here touches it. */
.ed-link__arr { transition: transform var(--ed-duration-slide) var(--ed-ease); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  :is(.ed-link, .ed-textlink):hover > .ed-link__arr { transform: translateX(var(--ed-nudge)); }
}
@media (prefers-reduced-motion: no-preference) {
  :is(.ed-link, .ed-textlink):focus-visible > .ed-link__arr { transform: translateX(var(--ed-nudge)); }
}

/* THE UNDERLINED WHITE TEXT LINK, on a dark slab: white, with a magenta
 * underline at 60% that turns full magenta on hover. */
.ed-textlink--underline {
  color: var(--ed-on-dark);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--ed-stack-link-line);
  transition: color var(--ed-transition), text-decoration-color var(--ed-transition);
}
.ed-textlink--underline:hover { text-decoration-color: var(--ed-cta); }

/* Heading on one side, a link on the other, wrapping under it when narrow. */
.ed-split {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-block-end: clamp(16px, 1.8vw, 22px);
}
.ed-split__head { max-width: var(--ed-head-maxw); }
/* FROM A TABLET UP THE HEAD SHARES ITS ROW WITH THE LINK (2 October, with
 * the wide heads): the link keeps the row's end and the head takes the rest,
 * so a wide head never pushes it under. On a phone the link drops under, as
 * drawn. */
@media (min-width: 48em) {
  .ed-split { flex-wrap: nowrap; }
  .ed-split__head { flex: 1 1 auto; min-width: 0; }
  .ed-split > .ed-link { flex: 0 0 auto; }
}
/* A WIDE HEAD'S HEADING FILLS ITS LINES (the owner, 2 October: "expand the
 * heading and description text to right"): balanced, a two-line heading
 * split in half and left the row's end empty; pretty fills each line and
 * still never leaves one word alone on the last. The site-wide balance
 * (above) holds everywhere else. */
.ed-split__head .ed-h2,
.ed-how__title,
.ed-engage__head .ed-h2 { text-wrap: pretty; }

/* Card lists are lists for a screen reader and nothing else. */
.ed-insights__grid { margin: 0; padding: 0; list-style: none; }
.ed-insight__arrow { display: block; }

.ed-insights__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(14px, 1.5vw, 20px);
  align-items: stretch;
}
/* ONE CARD SURFACE (HANDOFF.md, "Cards — one material"): white, the one
 * border, the 18px radius and the faint shadow; and one hover, the 4px lift
 * with the deeper shadow and the purple edge, over the one lift duration.
 * A plain white card wears .ed-card, and .ed-card--lift when it lifts, and
 * adds only its layout. The lift answers a hover wherever there is one, as
 * drawn. */
.ed-card {
  background: var(--ed-surface);
  border: 1px solid var(--ed-border);
  border-radius: var(--ed-radius-card);
  box-shadow: var(--ed-card-shadow);
}
.ed-card--lift {
  transition: transform var(--ed-duration-lift) var(--ed-ease),
              box-shadow var(--ed-duration-lift) ease,
              border-color var(--ed-duration-lift) ease;
}
.ed-card--lift:hover {
  transform: translateY(-4px);
  box-shadow: var(--ed-card-shadow-hover);
  border-color: var(--ed-purple);
}

.ed-insights__grid > li { display: flex; min-width: 0; }
.ed-insight {
  --insight-pad: clamp(20px, 1.9vw, 26px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1 1 auto;
  min-width: 0;
  min-height: clamp(188px, 15vw, 236px);
  padding: var(--insight-pad);
  color: var(--ed-ink);
  text-decoration: none;
}
/* THE ARTICLE'S PHOTOGRAPH ON TOP (the owner, 4 October 2026: the homepage's
 * cards; the design's are text only, docs/BASELINE.md §5): flush with the
 * card's edges under its own top corners, about 3:1 (16 / 5.4: the owner's
 * polish that evening, 40% shorter than 16:9), its ground the light grey
 * until it arrives. The renditions are cut to this frame around the focal
 * point (home/insights.py, IMAGE_SPECS), so `cover` crops nothing more. A gentle zoom on hover and keyboard focus, clipped to the
 * frame, over the card's lift; none for a reader who asked for less motion. */
.ed-insight__media {
  display: block;
  margin: calc(-1 * var(--insight-pad)) calc(-1 * var(--insight-pad)) 4px;
  aspect-ratio: 16 / 5.4;
  overflow: hidden;
  border-start-start-radius: calc(var(--ed-radius-card) - 1px);
  border-start-end-radius: calc(var(--ed-radius-card) - 1px);
  background: var(--ed-bg-alt);
}
.ed-insight__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--ed-duration-zoom) var(--ed-ease);
}
.ed-insight:hover .ed-insight__img,
.ed-insight:focus-visible .ed-insight__img { transform: scale(1.05); }
@media (prefers-reduced-motion: reduce) {
  .ed-insight:hover .ed-insight__img,
  .ed-insight:focus-visible .ed-insight__img { transform: none; }
}
/* A label inside a card: royal blue (HANDOFF.md, "Colour roles"). */
.ed-insight__tag {
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-semibold);
  letter-spacing: var(--ed-track-label);
  text-transform: uppercase;
  color: var(--ed-card-label);
}
.ed-insight__title {
  margin: 0;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-card-title);
  font-weight: var(--ed-weight-semibold);
  line-height: 1.24;
  letter-spacing: -0.02em;
  color: inherit;
  text-wrap: pretty;
}
/* Two lines, then an ellipsis (HANDOFF.md, "Insights cards": 15px, #44444A),
 * in the card's Archivo, as the design's excerpt inherits it. */
.ed-insight__excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  line-height: 1.55;
  color: var(--ed-dek);
  text-wrap: pretty;
}
.ed-insight__cta {
  margin-block-start: auto;
  padding-block-start: 10px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  /* Royal blue, as the tag: 7.32:1 on white. The box and the arrow follow
   * through currentColor. */
  color: var(--ed-card-label);
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-medium);
  letter-spacing: var(--ed-track-label);
  text-transform: uppercase;
}

/* The CTA's words fold away until the card is hovered or focused, and the
 * boxed arrow nudges (HOME:88-91), as on the practice cards. */
.ed-insight__cta > span:first-child {
  display: inline-block;
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  transform: translateX(calc(8px * var(--ed-dir)));
  transition: max-width var(--ed-reveal-words) var(--ed-ease), opacity var(--ed-reveal-fade) ease,
              transform var(--ed-reveal-words) var(--ed-ease);
}
.ed-insight:hover .ed-insight__cta > span:first-child,
.ed-insight:focus-visible .ed-insight__cta > span:first-child {
  max-width: 230px;
  opacity: 1;
  transform: none;
}
.ed-insight__box {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: var(--ed-radius);
  border: 1px solid currentColor;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--ed-reveal-fade) ease, transform var(--ed-reveal-nudge) var(--ed-ease);
}
.ed-insight:hover .ed-insight__box { transform: translateX(calc(3px * var(--ed-dir))); }
.ed-insight__arrow:dir(rtl) { scale: -1 1; }

@media (min-width: 37.5em) {
  .ed-insights__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 56.25em) {
  .ed-insights__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---- The two-column head, the hero rule, the stack layer and its chips ---
 * MOVED FROM home.css (27 September 2026), unchanged: the homepage uses them,
 * and so do the hub and service pages (docs/plans/ia-pages.md §C5). The
 * protected practice rail's CSS stays in home.css. */

.ed-2up {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(30px, 4vw, 80px);
  align-items: start;
}
@media (min-width: 56.25em) {
  .ed-2up { grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); }
}

/* The 3px rule under every hero. */
.ed-hero__rule { height: 3px; background: var(--ed-rule-brand); }

/* A layer: a numbered name, a line of description and its chips, on a dark
 * ground (HOME:1044-1067). */
.ed-layer {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding-block-start: 16px;
  border-block-start: 1px solid var(--ed-on-dark-rule);
}
.ed-layer__head { display: flex; flex-direction: column; gap: 7px; }
.ed-layer__row { display: flex; align-items: baseline; gap: 9px; }
.ed-layer__num {
  font-family: var(--ed-font-mono);
  font-size: var(--ed-size-label);
  font-weight: var(--ed-weight-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
  color: var(--ed-on-dark);
}
/* An <h3> for the outline; the design's name is a <span>, so it wraps
 * plainly, never balanced. */
.ed-layer__name {
  margin: 0;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-body);
  font-weight: var(--ed-weight-bold);
  letter-spacing: -0.015em;
  text-wrap: wrap;
  color: var(--ed-on-dark);
}
.ed-layer__desc {
  margin: 0;
  font-size: var(--ed-size-body);
  line-height: 1.5;
  color: var(--ed-on-dark-56);
  text-wrap: pretty;
}
.ed-layer__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ed-chip {
  display: inline-block;
  padding: 8px 12px;
  border: 1px solid var(--ed-chip-dark-line);
  border-radius: var(--ed-radius);
  background: var(--ed-chip-dark-bg);
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-caption);
  line-height: 1;
  letter-spacing: -0.004em;
  white-space: nowrap;
  color: var(--ed-chip-dark-ink);
  text-decoration: none;
  transition: background var(--ed-duration) var(--ed-ease), border-color var(--ed-duration) ease,
              color var(--ed-duration) ease, transform var(--ed-duration) var(--ed-ease);
}
.ed-chip:hover {
  background: var(--ed-chip-dark-hover-bg);
  border-color: var(--ed-chip-dark-hover-line);
  color: var(--ed-on-dark);
  transform: translateY(-2px);
}

/* ---- The search page ----------------------------------------------------
 * Until the designer draws one (docs/plans/a11y-wcag22aa.md item 3): the
 * site's own container, a field and button 44px tall, results as a plain
 * list at the reading measure. */
.ed-search__form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  max-width: 640px;
  margin-block: 24px 32px;
}
.ed-search__input {
  flex: 1 1 16em;
  min-height: var(--ed-target);
  padding: 10px 14px;
  border: 1px solid var(--ed-input-line);
  border-radius: var(--ed-radius);
  background: var(--ed-surface);
  color: var(--ed-ink);
  font-family: var(--ed-font-body);
  font-size: var(--ed-size-input);
}
.ed-search__count {
  margin: 0 0 20px;
  color: var(--ed-muted);
  overflow-wrap: anywhere; /* the query is whatever was typed */
}
.ed-search__results {
  display: flex;
  flex-direction: column;
  gap: 20px;
  max-width: var(--ed-measure);
  margin: 0;
  padding: 0;
  list-style: none;
}
.ed-search__title {
  margin: 0 0 6px;
  font-family: var(--ed-font-display);
  font-size: var(--ed-size-title);
}
.ed-search__pages {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-block: 28px 0;
}
.ed-search__step {
  display: inline-flex;
  align-items: center;
  min-height: var(--ed-target);
  padding-inline: 16px;
  border: 1px solid var(--ed-border);
  border-radius: var(--ed-radius);
}

/* ---- Forced colours (Windows contrast themes) ---------------------------
 * Beyond AA, and serious for the people who use them (a11y plan items 8 and
 * 9): the system drops backgrounds and shadows, so a button kept no edge and
 * the current page's rule, a box-shadow, vanished. */
@media (forced-colors: active) {
  .ed-btn { border: 1px solid ButtonText; }
  /* The main button's badge is a background, which forced colours would
   * make the pill's own colour, arrow and all; in the text's colour it
   * stays, the arrow cut out of it in the pill's. */
  :is(.ed-btn--primary, .ed-btn--purple)::before,
  :is(.ed-btn--primary, .ed-btn--purple):is(:hover, :focus-visible)::before {
    forced-color-adjust: none;
    background-color: ButtonText;
  }
  /* A tag's dot is a background, which forced colours would drop. */
  .ed-tag::before { background: CanvasText; }
  /* The menus' underline is a background, which forced colours removes. */
  :is(.ed-megamenu__link, a.ed-megamenu__heading, .ed-megamenu__row, .ed-megamenu__all):is(:hover, :focus-visible) .ed-megamenu__words {
    text-decoration: underline;
    text-decoration-thickness: 1.5px;
    text-underline-offset: 3px;
  }
  .ed-nav__link[aria-current],
  .ed-drawer__top[aria-current],
  .ed-drawer__summary[aria-current] {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 6px;
  }
}

/* THE SITE'S 44px TOUCH RULE for the last small targets (a11y plan item 28;
 * beyond WCAG 2.5.8, which spacing already meets): footer and legal links
 * (the one-letter "X" among them), role titles, the header logo, and the
 * bar's items and every link in its panels at desktop width (a tablet in
 * landscape), on a touch screen only, where a finger is the pointer; a mouse
 * keeps every drawn size. The footer's columns and the panels grow taller
 * there (a panel scrolls inside its max-height); the designer is told.
 *
 * A NAV ITEM AND A PANEL LINK GROW BY THEIR PADDING: the target less their
 * one line (1lh) and a nav item's two 1px borders, half above and half
 * below, so the label stays centred and the hover underline, drawn at the
 * foot of the text (its content box), stays under the words. The search
 * link keeps its 40px width: any wider and its target would meet the
 * language button's at 1160px. */
@media (pointer: coarse) {
  .ed-footer__list a,
  .ed-footer__legal-links :is(a, button),
  .ed-roles__title a,
  .ed-header__logo { display: inline-flex; align-items: center; min-block-size: var(--ed-target); }
  .ed-footer__legal-links :is(a, button) { min-inline-size: var(--ed-target); justify-content: center; }
  .ed-nav .ed-nav__link { padding-block: calc((var(--ed-target) - 2px - 1lh) / 2); }
  .ed-megamenu .ed-megamenu__link,
  a.ed-megamenu__heading { padding-block: calc((var(--ed-target) - 1lh) / 2); }
  .ed-header__search,
  .ed-megamenu__all { min-block-size: var(--ed-target); }
  .ed-megamenu__row { min-block-size: var(--ed-target); justify-content: center; }
}
