/* Newsroom frontend. Plain CSS, no build step.
 *
 * Structure, accessibility and layout live here and are shared by all three
 * publications. Everything that varies between them arrives as a custom
 * property written into each page's <head> by src/generate/theme.js — fonts,
 * type scale, rhythm, density, shape. There is no per-publication stylesheet
 * and no per-publication template.
 *
 * The values below are fallbacks only, used if a token is ever missing.
 *
 * Breakpoints: base = mobile, 600 = tablet, 900 = desktop, 1280 = wide.
 */

*, *::before, *::after { box-sizing: border-box; }

:root {
  --accent: #1f6feb; --accent-ink: #ffffff; --ink: #11151b; --muted: #5b6470;
  --surface: #ffffff; --canvas: #f5f6f8; --border: #e2e5ea;
  /* Extended roles. Every one of these is also emitted per publication by
     theme.js; these are the fallbacks a page keeps if that block is missing. */
  --accent-weak: #e8eef9; --faint: #666d74; --sunken: #eef0f3; --rule: #dfe3e8;

  --font-head: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-body: var(--font-head);
  --font-meta: var(--font-head);
  /* Mastheads and lead headlines. Falls back to the headline face, so a
     publication that declares nothing looks exactly as it does today. */
  --font-display: var(--font-head);

  --step-n1: 13px; --step-0: 16px; --step-1: 19px; --step-2: 23px;
  --step-3: 27px; --step-4: 33px; --step-5: 39px;

  --head-weight: 700; --head-tracking: -0.02em; --lh-head: 1.12; --lh-body: 1.6;
  --display-weight: 700; --display-tracking: -0.022em; --lh-display: 1.06;

  --radius: 6px; --border-w: 1px; --rule-w: 1px; --space: 8px;
  --wrap: 1180px; --measure: 700px; --gutter: 20px;
  --density: 1; --section-gap: 34px; --stack-gap: 16px;

  --card-pad: 18px; --card-gap: 22px; --card-min: 280px; --thumb: 92px;
  --meta-size: 12px; --meta-weight: 700; --meta-tracking: 0.06em; --meta-transform: uppercase;

  --masthead-size: 28px; --masthead-weight: 700; --masthead-tracking: -0.02em;
  --masthead-align: left; --masthead-transform: none;
}

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  /* Nothing should ever produce a sideways scrollbar. */
  overflow-x: hidden;
}

a { color: var(--accent); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }

/* Long words — URLs, compound club names — must never widen the page. */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 calc(var(--space) * 2);
}

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: var(--accent-ink);
  padding: 10px 16px; z-index: 100;
}
.skip:focus { left: 0; }

/* ---------- masthead ----------
   One markup shape, three identities. Everything that differs between the
   publications is either a token or a rule keyed off the body's layout class;
   there is no per-publication stylesheet.

   The header is a BAND — a coloured block carrying the wordmark, with the
   section bar beneath it — rather than white space with a rule under it. That
   is why --head-bg/--head-ink and --nav-bg/--nav-ink exist: the page's own ink
   on its own surface cannot describe white type on a dark green bar.

   Nothing in this header is revealed by JavaScript, so nothing here shifts
   after load. It sticks rather than being taken out of flow, so it reserves
   exactly its own height whatever that height turns out to be — the three
   mastheads are three different heights and no offset would fit all of them. */

.masthead { position: sticky; top: 0; z-index: 30; background: var(--head-bg); }

.masthead__utility {
  background: var(--head-bg); color: var(--head-ink);
  font-family: var(--font-meta); font-size: var(--meta-size);
  letter-spacing: var(--meta-tracking); opacity: 0.82;
}
.dateline { margin: 0; padding: 7px 0; font-variant-numeric: tabular-nums; }

/* The seam between the nameplate and the section bar. On the two coloured
   bands a hairline of their own ink; on the broadsheet's white the same ink
   rule its nameplate already sits between. */
.masthead__band { background: var(--head-bg); color: var(--head-ink); border-bottom: 1px solid rgb(255 255 255 / 0.18); }
.lay-newspaper .masthead__band { border-bottom-color: var(--ink); }
.masthead__bar {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: calc(var(--space) * 1.5);
  min-height: 52px; padding: var(--space) 0;
}

/* Explicit placement. The burger is display:none at desktop, which takes it
   out of the grid entirely — so without this the wordmark slid into column
   one and the two publications that centre their nameplate stopped centring
   it the moment the phone chrome went away. */
.burger { grid-column: 1; }
.brand { grid-column: 2; display: block; color: inherit; text-decoration: none; min-width: 0; padding: 3px 0; }
.masthead__acts { grid-column: 3; }
.brand:hover { text-decoration: none; }
/* On the home page the wordmark is the page's <h1>. It must look identical to
   the link form, so the heading's default margin and font are neutralised — the
   size and weight come from .brand__name, exactly as before. */
.brand--h1 { margin: 0; font-size: inherit; font-weight: inherit; }
.brand__name {
  display: block; font-family: var(--font-wordmark); font-style: var(--masthead-style);
  font-size: var(--masthead-size); font-weight: var(--masthead-weight); line-height: 1.02;
  letter-spacing: var(--masthead-tracking); text-transform: var(--masthead-transform);
}
/* Two-tone nameplate. The accent half is the publication's own colour on the
   band, so it reads on a near-black bar and on white paper alike. */
/* The two halves are now separated by a real space in the markup (so the
   wordmark reads correctly as text and as the home <h1>), so no left margin is
   needed to fake the gap. */
.brand__accent { color: var(--accent-on); }
/* The strapline under the wordmark. Small, spaced and quiet — it identifies
   the title, it does not compete with it. */
.brand__tag {
  display: block; margin-top: 3px;
  font-family: var(--font-meta); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.72;
}

/* ---- supplied wordmark artwork ----
   A publication that ships its own drawn logo renders it INSTEAD of
   .brand__name — never beside it — so the title still appears exactly once.
   The rendered height is set here and the width follows from the file's own
   aspect ratio, which is why the <img> carries its intrinsic width/height:
   the box is reserved before the bytes land and the masthead cannot jump.
   The heights below are chosen to sit inside the bar each width already had,
   so adding artwork does not make the masthead taller. */
.brand__logo {
  /* inline-block, not block: the three layouts align the wordmark with
     text-align (centred on wire and newspaper, left on desk) and an image has
     to obey the same switch. vertical-align keeps the line box from adding a
     descender's worth of dead space under it. */
  display: inline-block; vertical-align: bottom;
  width: auto; height: var(--brand-logo-h, 32px);
  max-width: 100%; object-fit: contain;
}

/* ---- header actions ----
   Search only. There is deliberately no account control: these sites have no
   accounts, and a button that cannot do anything would be the one dishonest
   pixel on the page. */
.masthead__acts { display: flex; align-items: center; gap: var(--space); justify-self: end; }
.masthead__bar > .navtoggle + * { min-width: 0; }
.hact {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 40px; padding: 0 12px; color: inherit;
  border: 1px solid currentColor; border-radius: 999px;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: 600;
}
.hact:hover, .hact:focus-visible { background: rgb(255 255 255 / 0.14); text-decoration: none; }

/* ---- the desk's header row ----

   The reference gives the sports desk a working header rather than a nameplate
   with two controls parked on the right: a search field wide enough to type a
   club into, and a Live pill that is the shortest route to the scores from any
   page. Both are real — the field is a GET form to /search/, the pill is a link
   to /results/ — and both are desk-only, which is what keeps the other three
   titles' mastheads byte-identical.

   The field takes the middle track, so the nameplate stays flush left where
   this title's logo is drawn to sit and the actions stay flush right. Below
   62rem it is withdrawn and the bottom bar's Search cell is the route, exactly
   as the burger and the Search link already are. */
.hsearch { display: none; }
.hlive {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 38px; padding: 0 14px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: 800;
  letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap;
}
.hlive:hover, .hlive:focus-visible { text-decoration: none; filter: brightness(1.1); }
.hlive__dot {
  width: 7px; height: 7px; border-radius: 50%; background: currentColor;
}
.hlive__n::before { content: "("; }
.hlive__n::after { content: ")"; }
.hlive__n[hidden] { display: none; }

@media (min-width: 62rem) {
  .lay-desk .masthead__bar {
    grid-template-columns: auto minmax(0, auto) minmax(220px, 1fr) auto;
  }
  .lay-desk .hsearch {
    grid-column: 3; display: flex; align-items: center; gap: 9px;
    max-width: 440px; width: 100%; justify-self: center;
    min-height: 40px; padding: 0 14px; border-radius: 999px;
    background: rgb(255 255 255 / 0.08);
    border: 1px solid rgb(255 255 255 / 0.16);
  }
  .lay-desk .hsearch:focus-within { border-color: var(--accent-on); background: rgb(255 255 255 / 0.12); }
  .lay-desk .masthead__acts { grid-column: 4; }
  /* The visible field makes the labelled Search button a second route to the
     same page sitting next to it. The label stays for screen readers; the
     glyph-only button stays for a reader who wants the full search page. */
  .lay-desk .hact--sm .hact__t { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .lay-desk .hact--sm { padding: 0 11px; }
}
/* The field's own label is for screen readers; the glyph says what it is. */
.hsearch__l { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.hsearch__i {
  flex: 1 1 auto; min-width: 0; border: 0; background: transparent; color: inherit;
  font-family: var(--font-body); font-size: var(--step-n1); line-height: 1.2;
}
.hsearch__i::placeholder { color: currentColor; opacity: 0.52; }
.hsearch__i:focus { outline: none; }
.hsearch__i::-webkit-search-cancel-button { filter: invert(1); opacity: 0.5; }

/* Appearance sits beside Search; its rules live with `.tmode` further down,
   because the base `.tmode` block comes later in this file and would otherwise
   win on source order and hand the masthead a 48px full-width drawer row. */
.masthead__pref { display: flex; align-items: center; }
/* The whole pictogram set, in one rule: 18px, monochrome, and inheriting the
   ink of whatever surface it sits on. Round joins as well as round caps -
   the set is drawn against that, and a mitred corner on the football or the
   flag reads sharp next to everything else. */
.ico {
  width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}

/* The FILLED set (sportmarks.js) rides the same box and the same `.ico` sizing,
   but it must not inherit the stroke: every shape in it states its own fill, and
   a shape that stated only a fill would otherwise be outlined 1.7px in the
   reader's text colour - a white football ringed in black ink on a black card.
   The handful of shapes there that DO want a stroke say so on the element, and a
   presentation attribute beats an inherited value, so they are unaffected. */
.ico--mark { stroke: none; }

/* ---- section navigation ----
   The primary navigation at every width. Scrolls sideways when it outgrows
   the viewport, which is the whole of its narrow-screen behaviour. */
.nav { background: var(--nav-bg); color: var(--nav-ink); }
.nav__in { display: flex; align-items: stretch; gap: var(--space); }
/* `flex: 0 1 auto`, not `1 1 auto`.
   The list used to take the whole track, which pushed the trailing control to
   the far right edge of the row: measured, the gap between the last section
   and "More" was 13-20px at 992-1280 but 45-114px at 1440 and above, and 106px
   at every width on the newspaper. It is meant to read as the item after the
   last item, not as a control parked in the corner. Shrinking is still
   allowed, so the narrow-screen scroll below 900px is unaffected. */
.nav__list {
  display: flex; list-style: none; margin: 0; padding: 0; min-width: 0; flex: 0 1 auto;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.nav__list::-webkit-scrollbar { display: none; }
.nav__link {
  display: flex; align-items: center; padding: 0 11px; min-height: 38px; white-space: nowrap;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
  color: inherit; text-decoration: none;
  border-bottom: 3px solid transparent;
}
.nav__link:first-child { padding-left: 0; }
.nav__link:hover { text-decoration: none; opacity: 0.75; }

/* ---- the launch badge ----

   A newly opened section wears one word beside its label for a few weeks.
   Deliberately the quietest thing that still reads as a badge: the accent at
   its normal weight on a transparent ground, a hairline border, and no fill.
   A filled chip in the accent sits on a bar that is ALREADY the accent on the
   desk, so it would either disappear into it or have to fight it with a second
   colour the design system does not have.

   `position: absolute` is refused on purpose. The badge has to take part in the
   row's width or the bar cannot be measured, and the whole difficulty of adding
   an eleventh section here is that the track is measured to the pixel. It is an
   inline-flex item with its own small type scale, and it costs the row a known
   amount rather than an unknown one.

   No `white-space` of its own: the link is already `nowrap`, so the badge
   cannot wrap away from the label it belongs to. */
.nav__new {
  display: inline-flex; align-items: center; margin-left: 6px;
  padding: 0 4px; border: 1px solid currentColor; border-radius: 2px;
  font-size: 9px; line-height: 14px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 0.85;
}
/* ---- fitting eleven sections on the desk's one row ----

   Sport Daily Mail is the only `desk` layout and the only title with eleven
   sections, so both rules below are scoped to it and no other publication's bar
   changes by a pixel.

   MEASURED, at 1.6px stroke and the deployed type, with the eleventh section and
   its badge in place (viewport / links needed / room the list has):

     glyphs on, 14px padding     1280: 1358/1200   1440: 1355/1280   1600: 1355/1280
     glyphs off, 14px padding    1280: 1083/1200   1440: 1080/1280   1600: 1080/1280
     glyphs off, 10px padding    1180: 1034/1099   1280: 1039/1200   1440: 1036/1280

   THE GLYPHS CANNOT STAY. `.wrap` caps at 1360px, so the list's room stops
   growing at 1280px however wide the screen is - and eleven glyphs with their
   gaps cost 297px against the 80px of slack that cap leaves. There is no
   viewport at which the full set fits, which is why this is not a raised
   breakpoint: at 1600px the bar was still two rows tall. The stylesheet already
   states the rule this follows - "section-bar glyphs are withheld until the row
   can afford them" - and the drawer carries the same glyphs at every width, so
   nothing becomes unreachable and no meaning is lost. Only the desk has to pay
   it; the wire and the newspaper keep theirs.

   10px rather than 14px of padding brings the single row down from 1200px to
   1180px, which covers the common 1280 and 1366 laptop widths with room over.

   BETWEEN 992px AND 1179px THE BAR IS TWO ROWS, and that is arithmetic rather
   than a choice: the eleven labels measure 885px bare and the badge 35px, in a
   track that offers 919px at 1000px wide. Zero padding would not fit them. The
   62rem block deliberately wraps rather than scrolls - "when the links outgrow
   the track the last one drops onto a second row" - so this is the behaviour the
   design already chose for an overfull bar, reached honestly. The header is 97px
   tall instead of 49px across that band; every section stays visible and
   clickable, nothing is clipped, and from 1180px up it is one row again. */
/* THE GLYPHS ARE BACK, from 80rem. The arithmetic above was taken with eleven
   sections on the row; the secondary sections have since moved into "More",
   so the row holds ten plus More, and measured with the glyphs on it fits
   1280, 1440 and 1920 with room over. See "the desk's dark section bar". */
/* 10px, and it stays 10px. It was cut to 7 in a draft of the redesign, while
   this bar carried thirteen sections and eight section-menu chevrons; the
   secondary sections move into the disclosure instead, so the row holds ten
   items and exactly one chevron and has room to spare at 1024, 1280 and 1440.
   The comment sits OUTSIDE the block because the rule's shape is asserted. */
@media (min-width: 64rem) {
  .lay-desk .nav__link { padding-right: 10px; }
}


/* In the drawer there is room, so the badge is set at the panel's own rhythm
   rather than the bar's cramped one, and pushed to the trailing edge where a
   status marker belongs in a vertical list. */
.drawer__new {
  display: inline-flex; align-items: center; margin-left: auto;
  padding: 1px 6px; border: 1px solid currentColor; border-radius: 2px;
  font-family: var(--font-meta); font-size: 10px; line-height: 16px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 0.85;
}
.nav__link[aria-current="page"] { border-bottom-color: var(--accent-on); font-weight: 700; }
/* On the broadsheet's white bar the current section is set in the accent
   itself, which is what makes a restrained header read as deliberate. */
.lay-newspaper .nav__link[aria-current="page"] { color: var(--accent); }
/* ---- the section menus (the sports desk only) ----

   The trailing "More" disclosure is gone. It held exactly one item, /results/,
   and the masthead's Live pill now goes there from every page at every width.
   The width it returns pays for these.

   Same no-script mechanics as the disclosure had, and as the side drawer still
   has: a checkbox carries the state, the accessible name and the keyboard; a
   label carries the pointer and draws the chevron; a fixed transparent scrim
   closes it on a click anywhere else. The checkbox is a sibling of the panel
   and the scrim inside the <li>, because `~` cannot climb out of a wrapper.

   HOVER OPENS IT TOO, on a device that has a real pointer. That is what the
   reference does and what a reader of a news portal reaches for, and it costs
   the keyboard and the touchscreen nothing: both still go through the
   checkbox. `any-hover: hover` keeps it off touchscreens, where hover is
   synthesised from the first tap and a menu that opens on the way to a link is
   a menu that eats the tap.

   Below 62rem none of this exists. The phone has the drawer and the tab rail,
   and a hover menu on a touchscreen is the control this file already refuses
   to ship elsewhere. */
.nav__in { position: relative; }
.nav__i { position: relative; display: flex; align-items: stretch; }
.nav__t { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; pointer-events: none; }
.nav__chev, .nav__menu-wrap { display: none; }
.moretoggle { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; pointer-events: none; }
.nav__end { position: relative; display: flex; align-items: stretch; flex: none; }
/* The checkbox is 1px and invisible, so its focus ring has to move to the
   control a keyboard reader can actually see. */
.moretoggle:focus-visible ~ .nav__end .nav__more { outline: 2px solid currentColor; outline-offset: -3px; }
.nav__menu {
  display: none; position: absolute; top: 100%; right: 0; z-index: 30;
  min-width: 11rem; margin: 0; padding: 6px; list-style: none;
  background: var(--surface); color: var(--ink);
  border: var(--border-w) solid var(--border); border-radius: var(--radius);
  box-shadow: 0 10px 28px rgb(0 0 0 / 0.18);
}
.moretoggle:checked ~ .nav__end .nav__menu { display: block; }
.nav__menuitem {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 0 12px; border-radius: var(--radius);
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
.nav__menuitem:hover { background: var(--sunken); text-decoration: none; }
.nav__menuitem:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; text-decoration: none; }
.nav__menuitem[aria-current="page"] { color: var(--accent); font-weight: 700; }
/* A secondary section keeps its launch badge in the menu, set at the trailing
   edge as it is in the drawer. The menu is a light panel, so the badge takes
   the menu's ink rather than the bar's. */
.nav__menuitem .nav__new { margin-left: auto; padding-left: 4px; }
.nav__menuitem .ico { flex: none; }
/* A click anywhere else closes it. Transparent and behind the menu, exactly as
   the drawer's own scrim works. */
.nav__scrim { display: none; position: fixed; inset: 0; z-index: 20; cursor: default; }
.moretoggle:checked ~ .nav__scrim { display: block; }
/* The chevron points at what the control will do next. */
.moretoggle:checked ~ .nav__end .nav__more::after { transform: translateY(2px) rotate(-135deg); }

@media (min-width: 62rem) {
  .lay-desk .nav__i--has .nav__chev {
    display: flex; align-items: center; flex: none; cursor: pointer;
    width: 14px; margin-left: -4px; color: inherit;
  }
  .lay-desk .nav__i--has .nav__chev::after {
    content: ""; width: 5px; height: 5px;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
  }
  /* The chevron points at what the control will do next. */
  .lay-desk .nav__t:checked ~ .nav__chev::after { transform: translateY(1px) rotate(-135deg); }
  /* The checkbox is 1px and invisible, so its focus ring moves to the label a
     keyboard reader can actually see. */
  .lay-desk .nav__t:focus-visible ~ .nav__chev { outline: 2px solid currentColor; outline-offset: -2px; }

  .lay-desk .nav__menu-wrap {
    display: block; position: absolute; top: 100%; left: 0; z-index: 30;
    visibility: hidden; opacity: 0;
  }
  /* THE PANEL HANGS FROM THE CONTENT COLUMN, NOT FROM ITS OWN NAV ITEM.
     `.nav__i` is positioned, so a panel with left: 0 started at the item's
     left edge — 78px in from the page for Football — and a 963px panel from
     there is 1041px of document in a 1024px window. That shipped: the live
     capture at 1024 read scrollW 1040, and it had been invisible for months
     because a CLOSED menu is visibility: hidden rather than display: none, so
     it is still laid out and still counts, and because no capture had ever
     looked at 1024.
     Anchoring to .nav__in — which is the wrap, and already positioned — puts
     the panel's left edge at the content column's, which is also where the
     reference draws it. The item goes static for this one case only.
     The local preview never reproduced any of it: its menu has three columns
     where the live one has four, so its panel was 788px and fitted. */
  .lay-desk .nav__i--has { position: static; }
  .lay-desk .nav__menu-wrap { max-width: 100%; }
  /* The second half of the bar hangs its panel from the column's trailing edge
     instead, which is the same reasoning one anchor over. */
  .lay-desk .nav__menu-wrap--end { left: auto; right: 0; }
  .lay-desk .nav__t:checked ~ .nav__menu-wrap { visibility: visible; opacity: 1; }
  .lay-desk .nav__t:checked ~ .nav__scrim { display: block; position: fixed; inset: 0; z-index: 20; cursor: default; }
}

/* The narrowest laptop band pays for the chevrons the same way it already pays
   for the labels: the glyph shrinks rather than the row wrapping. It sits AFTER
   the base rule because the two have the same specificity and source order is
   what decides - written above it, as it first was, the 14px base won and the
   band's own value never applied. */
@media (min-width: 62rem) and (max-width: 71.99rem) {
  .lay-desk .nav__i--has .nav__chev { width: 11px; margin-left: -5px; }
}

@media (min-width: 62rem) and (any-hover: hover) {
  .lay-desk .nav__i--has:hover .nav__menu-wrap,
  .lay-desk .nav__i--has:focus-within .nav__menu-wrap { visibility: visible; opacity: 1; }
}

/* The panel itself. It sits on the header band's own ground rather than the
   page's, because that is what it hangs from and what the reference draws: a
   white panel under a near-black bar reads as a different site. */
.mmenu {
  display: grid; gap: 0 26px; padding: 18px 22px;
  background: var(--head-bg); color: var(--head-ink);
  border: 1px solid rgb(255 255 255 / 0.14); border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: 0 18px 40px rgb(0 0 0 / 0.35);
  max-width: min(94vw, 980px);
}
/* Sized by what is in it, not by what it could hold.
   The fixture column is there on the pages the build hands scores to and
   absent elsewhere, and the stories column is absent whenever the ticker
   already carries this section's newest. A fixed three-column track drew a
   980px panel with two columns in it and a third of it empty. `auto-fit` over
   a content-sized track lets the panel be as wide as its columns and no
   wider. */
.mmenu--wide {
  grid-auto-flow: column;
  grid-auto-columns: minmax(150px, max-content);
  width: max-content;
}
.mmenu--wide .mmenu__live { min-width: 300px; max-width: 380px; }
.mmenu--wide .mmenu__col--stories { min-width: 210px; max-width: 280px; }
.mmenu__col { min-width: 0; }

/* ---- the four-column panel ----
   The reference reads Competitions | Popular Clubs | Football | Live Now, with
   the section's own stories under the fixtures rather than beside them. Four
   content-sized tracks plus the fixture column do not fit 980px at 1280, so the
   last two SHARE a track and stack, which is the reference's own arrangement
   and not a compromise: a fixture row and a story row are both full-width
   things, and they read as one feed down the right-hand side.

   Measured at the two widths this has to hold: 1280 and 1440. The cap is the
   viewport, so the panel can never be the thing that puts a scrollbar on the
   page. */
.mmenu--wide:has(.mmenu__col--clubs) { max-width: min(96vw, 1120px); gap: 0 22px; }
.mmenu--wide:has(.mmenu__col--clubs) .mmenu__live { min-width: 270px; max-width: 330px; }
.mmenu--wide:has(.mmenu__col--clubs) .mmenu__col--stories {
  min-width: 0; max-width: none; grid-column: 4; margin-top: 12px;
  padding-top: 12px; border-top: 1px solid rgb(255 255 255 / 0.12);
}
.mmenu--wide:has(.mmenu__col--clubs) .mmenu__live { grid-column: 4; grid-row: 1; }
.mmenu--wide:has(.mmenu__col--clubs) .mmenu__col--stories { grid-row: 2; }
/* The first three columns stay on row 1 and leave row 2 to the stories. */
.mmenu--wide:has(.mmenu__col--clubs) > .mmenu__col:not(.mmenu__col--stories) { grid-row: 1; }

/* A row with a mark in front of it. Used by the Football column's actions and
   by the club rows; the mark is a fixed box so the labels line up whether a
   club has a stored crest or falls back to its monogram. */
.mmenu__list--ico .mmenu__link { gap: 9px; }
.mmenu__list--ico .ico { width: 15px; height: 15px; flex: none; opacity: 0.75; }
.mmenu__link:hover .ico, .mmenu__link:focus-visible .ico { opacity: 1; }

.mmenu__col--clubs .mmenu__link { gap: 9px; min-height: 32px; }
.mmenu__crest { width: 20px; height: 20px; flex: none; object-fit: contain; }
/* A competition's own mark, a size down from a club badge: it sits beside a
   longer word and it is the row's second thing, not its first. `contain`
   because these arrive in whatever aspect the provider drew them. */
.mmenu__comp { width: 18px; height: 18px; flex: none; object-fit: contain; }
.mmenu__col:has(.mmenu__comp) .mmenu__link { gap: 9px; }
/* The established neutral fallback, exactly as a fixture row draws it: two
   letters from the club's own name, in the publication's own type, in the space
   a crest would occupy. It imitates no badge and invents none. */
.mmenu__crest--mono {
  display: grid; place-items: center; border-radius: 999px;
  background: rgb(255 255 255 / 0.1); font-family: var(--font-meta);
  font-size: 9px; font-weight: 800; letter-spacing: 0.02em; opacity: 0.85;
}
.mmenu__h {
  margin: 0 0 8px; font-family: var(--font-meta); font-size: 11px; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.62;
  display: flex; align-items: baseline; gap: 8px;
}
.mmenu__n {
  padding: 1px 6px; border-radius: 999px; background: var(--nav-bg); color: var(--nav-ink);
  font-size: 10px; letter-spacing: 0.04em; opacity: 1;
}
.mmenu__all { margin-left: auto; color: inherit; opacity: 0.8; text-transform: none; letter-spacing: 0; font-weight: 600; }
.mmenu__list { list-style: none; margin: 0; padding: 0; }
.mmenu__link {
  display: flex; align-items: center; min-height: 30px; color: inherit;
  font-size: var(--step-n1); opacity: 0.88; white-space: nowrap;
}
.mmenu__link:hover, .mmenu__link:focus-visible { opacity: 1; text-decoration: underline; }
.mmenu__more {
  display: inline-block; margin-top: 8px; color: var(--accent-on);
  font-family: var(--font-meta); font-size: 11px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.mmenu__more::after { content: " \2192"; }
.mmenu__story { display: block; padding: 7px 0; color: inherit; }
.mmenu__story:hover .mmenu__title { text-decoration: underline; }
.mmenu__title { display: block; font-family: var(--font-head); font-weight: 700; font-size: var(--step-n1); line-height: 1.25; }
.mmenu__meta { display: flex; gap: 8px; margin-top: 3px; font-size: 11px; opacity: 0.6; }
.mmenu__live { min-width: 0; }
/* ---- the grouped competitions column ----
   Card rows under three compact group labels. A fixed mark box on the left
   (the stored competition mark, or the site's own drawn mark) so every name
   starts on the same line whatever is in front of it; one row height; a
   chevron drawn in CSS so it is never read out. The column spans both rows of
   the four-column panel - the space under the club and football columns that
   the stories feed already makes the panel tall enough to hold - so it adds no
   height on the pages that carry stories. */
.mmenu__col--comps { width: 236px; }
.mmenu--wide:has(.mmenu__col--clubs) > .mmenu__col.mmenu__col--comps { grid-row: 1 / span 2; }
.mcomp__g {
  margin: 10px 0 5px; padding: 4px 8px; border-radius: 5px;
  background: rgb(255 255 255 / 0.05); border-left: 2px solid var(--accent);
  font-family: var(--font-meta); font-size: 10px; font-weight: 800;
  letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.78;
}
.mmenu__col--comps .mmenu__h + .mcomp__g { margin-top: 0; }
.mcomp__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.mcomp__row {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) 8px; align-items: center; gap: 8px;
  height: 31px; padding: 0 8px 0 6px; border-radius: 6px;
  border: 1px solid rgb(255 255 255 / 0.07); background: rgb(255 255 255 / 0.025);
  color: inherit; font-size: var(--step-n1); font-weight: 500;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.mcomp__row::after {
  content: ""; width: 6px; height: 6px; justify-self: end;
  border-top: 1.6px solid currentColor; border-right: 1.6px solid currentColor;
  transform: rotate(45deg); opacity: 0.45; transition: opacity 0.15s ease, transform 0.15s ease;
}
.mcomp__row:hover, .mcomp__row:focus-visible {
  text-decoration: none;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
}
.mcomp__row:hover::after, .mcomp__row:focus-visible::after { opacity: 1; transform: translateX(2px) rotate(45deg); }
.mcomp__row:focus-visible { outline: 2px solid var(--accent-on); outline-offset: 1px; }
.mcomp__mark { display: grid; place-items: center; width: 22px; height: 22px; }
.mcomp__mark img { width: 20px; height: 20px; object-fit: contain; }
.mcomp__mark--drawn { border-radius: 5px; background: rgb(255 255 255 / 0.07); }
.mcomp__svg { width: 17px; height: 17px; opacity: 0.88; }
.mcomp__row:hover .mcomp__svg, .mcomp__row:focus-visible .mcomp__svg { opacity: 1; color: var(--accent-on); }
.mcomp__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mcomp__all {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  height: 34px; margin-top: 12px; padding: 0 12px; border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: inherit; font-family: var(--font-meta); font-size: 11px; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  transition: background-color 0.15s ease;
}
.mcomp__all::after { content: "\2192"; content: "\2192" / ""; color: var(--accent-on); font-size: 14px; transition: transform 0.15s ease; }
.mcomp__all:hover, .mcomp__all:focus-visible { text-decoration: none; background: color-mix(in srgb, var(--accent) 28%, transparent); }
.mcomp__all:hover::after, .mcomp__all:focus-visible::after { transform: translateX(3px); }
.mcomp__all:focus-visible { outline: 2px solid var(--accent-on); outline-offset: 1px; }
@media (prefers-reduced-motion: reduce) {
  .mcomp__row, .mcomp__row::after, .mcomp__all, .mcomp__all::after { transition: none; }
}
.mmenu__rows { list-style: none; margin: 0; padding: 0; }
.mmrow { padding: 7px 0; border-top: 1px solid rgb(255 255 255 / 0.1); }
.mmrow:first-child { border-top: 0; }
.mmrow__comp { display: flex; align-items: center; gap: 6px; font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase; opacity: 0.55; }
.mmrow__line { display: grid; grid-template-columns: 1fr auto 1fr auto; align-items: center; gap: 8px; margin-top: 3px; }
.mmrow__side { display: flex; align-items: center; gap: 6px; min-width: 0; }
.mmrow__line > .mmrow__side:last-of-type { justify-content: flex-end; }
.mmrow__team { font-size: var(--step-n1); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The state chip goes back IN FLOW here.
   On a card it is lifted to the top-left corner by `position: absolute`, which
   is right there and wrong in a menu row: the row is not positioned, so the
   chip escaped to the panel itself and sat over the Competitions heading. In a
   row there is a column waiting for it at the trailing edge, which is where the
   reference puts it. */
.mmrow__line .mrow__state {
  position: static; top: auto; inset-inline-start: auto;
  justify-self: end; font-size: 10px; padding: 3px 7px;
}
.mmrow__line .mrow__state--live { padding: 0; }
.mmrow__line .mrow__score { font-size: var(--step-0); font-weight: 800; }

/* The row's own current-page mark, carried by "More" when the page a reader is
   on is one of the sections inside it - otherwise the bar would show no current
   section at all. The transparent rule keeps every item on the same baseline. */
.nav__more {
  display: none; align-items: center; gap: 6px; flex: none; cursor: pointer;
  padding-left: 12px; min-height: 38px; color: inherit;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
}
.nav__more { border-bottom: 3px solid transparent; }
.nav__more--current { border-bottom-color: var(--accent-on); font-weight: 700; }
.nav__more::after { content: ""; width: 7px; height: 7px; border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor; transform: translateY(-2px) rotate(45deg); }

/* Section-bar glyphs are withheld until the row can afford them.
   .nav__list is one nowrap line with its scrollbar deliberately hidden, and it
   is already full: the ten-section publications measure 896px and 900px of
   links against 883px and 879px of room at 992px. A glyph and its gap add 25px
   a link - 250px - so below this width the row would either scroll with no
   scrollbar to say so, or squash the labels, and either way sections a reader
   could see before would stop being visible. At 1280px there is room for the
   full set on all three, so that is where they appear. The drawer carries the
   same glyphs at every width, and "More" reaches it from here. */
.nav__link .ico { display: none; }
@media (min-width: 80rem) {
  .nav__link { gap: 7px; }
  .nav__link .ico { display: block; flex: none; }
}

/* ---- live strip ----
   The desk's signature. Real rows only; the markup is omitted entirely when a
   publication has published nothing. */

/* The band earns its height at desktop: a masthead that is 60px tall above a
   1360px page reads as a toolbar, not a masthead. */
@media (min-width: 62rem) {
  /* The nameplate carries the page at desktop, so it is set well above the
     interface scale rather than a step above it. The section bar stays compact
     underneath: presence belongs to the wordmark, not to the chrome. */
  .masthead__bar { min-height: 82px; padding: calc(var(--space) * 2) 0; }
  .lay-desk { --masthead-size: 44px; }
  .brand__logo { --brand-logo-h: 64px; }
  .lay-wire { --masthead-size: 40px; }
  .lay-newspaper { --masthead-size: 62px; }
  .brand__tag { margin-top: 5px; font-size: 11px; letter-spacing: 0.16em; }
  .nav__link { min-height: 42px; padding: 0 13px; }
  .nav__more { min-height: 42px; }
  .hact { min-height: 38px; padding: 0 14px; }
}

@media (min-width: 48rem) and (max-width: 61.99rem) {
  .brand__logo { --brand-logo-h: 52px; }
}

/* ---- WIRE — Daily All In: dark band, wordmark centred over it ---- */
.lay-wire .masthead__utility { border-bottom: 1px solid rgb(255 255 255 / 0.14); }
.lay-wire .brand { text-align: center; }
.lay-wire .nav { border-top: 1px solid rgb(255 255 255 / 0.14); }
/* The list is content-sized now, so centring it does nothing; the row is
   what has the spare width. */
.lay-wire .nav__in { justify-content: center; }

/* ---- NEWSPAPER — Dayli Mail Today: a nameplate on paper, between rules ---- */
.lay-newspaper .masthead__bar { min-height: 76px; padding: calc(var(--space) * 2) 0; }
@media (min-width: 62rem) {
  .lay-newspaper .masthead__bar { min-height: 116px; padding: calc(var(--space) * 3.5) 0; }
}
.lay-newspaper .brand { text-align: center; }
.lay-newspaper .masthead__utility--under {
  border-bottom: var(--border-w) solid var(--rule);
  text-align: center;
}
.lay-newspaper .dateline { padding: 4px 0; font-size: 11px; }
.lay-newspaper .nav { border-bottom: var(--border-w) solid var(--rule); }
/* The list is content-sized now, so centring it does nothing; the row is
   what has the spare width. */
.lay-newspaper .nav__in { justify-content: center; }
.lay-newspaper .hact { border-color: var(--border); }
.lay-newspaper .hact:hover, .lay-newspaper .hact:focus-visible { background: var(--sunken); }

/* ---- DESK — Sport Daily Mail: dark green band over an accent section bar ---- */
.lay-desk .brand__name { line-height: 1; }
.lay-desk .nav { border-top: 1px solid rgb(255 255 255 / 0.16); }
/* SENTENCE CASE, WHICH IS WHAT THE REFERENCE DRAWS. The bar read "FOOTBALL
   CRICKET RUGBY" against a reference that reads "Football Cricket Rugby", and
   capitals are the one thing in this bar a reader cannot skim. It also buys
   room rather than costing it — capitals are the wider setting, so the eleven
   items and their three NEW badges fit at every width with more air than
   before, not less. */
.lay-desk .nav__link { text-transform: none; letter-spacing: 0.01em; }
/* And "More", which sits on the same row and takes its casing from the meta
   scale rather than from the links beside it. */
.lay-desk .nav__more { text-transform: none; letter-spacing: 0.01em; }

/* ---- the desk's dark section bar (desktop only) ----
   A dark surface under the black masthead instead of a full-width red band:
   a charcoal gradient, a low red glow and a thin red line along the foot, so
   the bar reads as part of the same dark/red family as the Match Centre and
   the Football menu that hangs from it. The red is the bar's own token
   (--nav-bg, #C8101A in both appearances), which is why the bar looks the
   same in light and dark - like the masthead above it.

   Three states, and they must never be confused:
     default   clean dark, text at 86% white, glyphs at 62%
     hover     a translucent dark-red wash glowing towards the lower edge
     current   a compact solid red pill with its own glow, white type

   Everything here is inside 62rem and scoped to .lay-desk. Below 62rem .nav is
   display:none - the phone uses the drawer and the bottom bar - so none of it
   can reach the mobile header, drawer or bottom bar. */
@media (min-width: 62rem) {
  .lay-desk .nav {
    --dnav-red: var(--nav-bg);
    --dnav-ring: #ff5a62;
    border-top: 1px solid rgb(255 255 255 / 0.05);
    background:
      linear-gradient(180deg, transparent 52%, color-mix(in srgb, var(--dnav-red) 16%, transparent) 100%),
      radial-gradient(ellipse 60% 120% at 50% 150%, color-mix(in srgb, var(--dnav-red) 22%, transparent), transparent 70%),
      linear-gradient(180deg, #17181c 0%, #121316 50%, #0c0c0f 100%);
    box-shadow: inset 0 -2px 0 var(--dnav-red), 0 12px 26px -14px color-mix(in srgb, var(--dnav-red) 85%, transparent);
  }
  /* The row spans the masthead: its first glyph sits under the wordmark's left
     edge and More finishes under the masthead's actions, as the reference
     draws it. The section menu hangs from .nav__in's box, not its padding, so
     it does not move. */
  .lay-desk .nav__in { padding-left: 12px; padding-right: 12px; }
  .lay-desk .nav__list { gap: 2px; padding-bottom: 2px; }
  .lay-desk .nav__i {
    align-items: center; margin: 7px 0 5px; border-radius: 9px;
    transition: background-color 0.18s ease, box-shadow 0.18s ease;
  }
  .lay-desk .nav__i > .nav__link {
    gap: 7px; min-height: 36px; padding: 0 9px; border-bottom: 0; border-radius: 9px;
    font-size: 13.5px; font-weight: 500; letter-spacing: 0;
    color: rgb(255 255 255 / 0.9); opacity: 1; transition: color 0.18s ease;
  }
  .lay-desk .nav__i--has { padding-right: 10px; }
  .lay-desk .nav__i--has > .nav__link { padding-right: 5px; }
  .lay-desk .nav__i--has .nav__chev { width: 12px; margin-left: 0; justify-content: center; }
  .lay-desk .nav__link .ico { width: 18px; height: 18px; opacity: 0.78; transition: opacity 0.18s ease; }

  /* hover: soft, and only on an item that is not already the current one */
  .lay-desk .nav__i:not(:has(> .nav__link[aria-current="page"])):hover {
    background: linear-gradient(180deg, color-mix(in srgb, var(--dnav-red) 8%, transparent), color-mix(in srgb, var(--dnav-red) 24%, transparent));
    box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--dnav-red) 55%, transparent), 0 6px 14px -9px color-mix(in srgb, var(--dnav-red) 70%, transparent);
  }
  .lay-desk .nav__i:hover > .nav__link { color: #fff; text-decoration: none; }
  .lay-desk .nav__i:hover .ico { opacity: 1; }

  /* current: the strong state */
  .lay-desk .nav__i:has(> .nav__link[aria-current="page"]) {
    background: linear-gradient(180deg, color-mix(in srgb, var(--dnav-red), #fff 6%), var(--dnav-red));
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.18), 0 6px 18px -5px color-mix(in srgb, var(--dnav-red) 85%, transparent);
  }
  .lay-desk .nav__i > .nav__link[aria-current="page"] { color: #fff; font-weight: 600; }
  .lay-desk .nav__link[aria-current="page"] .ico { opacity: 1; }

  /* keyboard focus: a red ring with a soft halo; white on the red pill */
  .lay-desk .nav__i > .nav__link:focus-visible {
    text-decoration: none; outline: 2px solid var(--dnav-ring); outline-offset: 1px;
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--dnav-red) 30%, transparent);
  }
  .lay-desk .nav__i > .nav__link[aria-current="page"]:focus-visible { outline-color: #fff; }
  .lay-desk .nav__t:focus-visible ~ .nav__chev { outline: 2px solid var(--dnav-ring); outline-offset: 0; border-radius: 4px; }

  /* the launch badge: a small solid red chip, centred on the label */
  .lay-desk .nav__link .nav__new {
    margin-left: 7px; padding: 0 5px; border: 0; border-radius: 4px;
    background: var(--dnav-red); color: #fff; opacity: 1;
    font-size: 9.5px; line-height: 17px; letter-spacing: 0.06em;
  }
  .lay-desk .nav__link[aria-current="page"] .nav__new { background: rgb(0 0 0 / 0.28); }

  /* More: the same three states as a section */
  .lay-desk .nav__end { align-items: center; }
  .lay-desk .nav__more {
    gap: 8px; min-height: 36px; margin: 7px 0 5px; padding: 0 10px; border-bottom: 0; border-radius: 9px;
    font-size: 13.5px; font-weight: 500; letter-spacing: 0;
    color: rgb(255 255 255 / 0.9); transition: background-color 0.18s ease, color 0.18s ease;
  }
  .lay-desk .nav__more .ico { width: 18px; height: 18px; opacity: 0.85; }
  .lay-desk .nav__more::after { margin-left: 2px; }
  .lay-desk .nav__more:not(.nav__more--current):hover {
    color: #fff;
    background: linear-gradient(180deg, color-mix(in srgb, var(--dnav-red) 8%, transparent), color-mix(in srgb, var(--dnav-red) 24%, transparent));
    box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--dnav-red) 55%, transparent);
  }
  .lay-desk .nav__more:hover .ico { opacity: 1; }
  .lay-desk .nav__more--current { background: var(--dnav-red); color: #fff; font-weight: 600; box-shadow: 0 6px 18px -5px color-mix(in srgb, var(--dnav-red) 85%, transparent); }
  .lay-desk .nav__more--current .ico { opacity: 1; }
  .lay-desk .moretoggle:focus-visible ~ .nav__end .nav__more { outline: 2px solid var(--dnav-ring); outline-offset: 1px; }
}
/* 1280 to 1439: the glyphs are on and the column is at its narrowest, so the
   row is set a notch tighter rather than any section being moved into "More"
   by sectionBarFits(). Sized in Edge/Segoe UI with the script off, with ~5%
   headroom for wider system fonts (SF Pro): see the report. */
@media (min-width: 80rem) and (max-width: 89.99rem) {
  .lay-desk .nav__list { gap: 1px; }
  .lay-desk .nav__i > .nav__link { gap: 6px; padding: 0 8px; font-size: 13px; }
  .lay-desk .nav__i--has { padding-right: 8px; }
  .lay-desk .nav__i--has > .nav__link { padding-right: 4px; }
  .lay-desk .nav__link .ico, .lay-desk .nav__more .ico { width: 17px; height: 17px; }
  .lay-desk .nav__link .nav__new { margin-left: 6px; padding: 0 5px; }
  .lay-desk .nav__more { padding: 0 8px; gap: 7px; font-size: 13px; }
}
/* From 1440 the column has stopped growing (.wrap caps it), and the masthead's
   actions finish flush with .nav__in's right edge, so the row does too - More
   ends under the appearance control, as the reference draws it. */
@media (min-width: 90rem) {
  .lay-desk .nav__in { padding-right: 0; }
}
/* 992 to 1279: no glyphs (the base rule withholds them below 80rem), and the
   spacing drops so this band keeps every section it kept before - the row
   must never need more room than it did.
   (Written max-first so it is not mistaken for the article band's query.) */
@media (max-width: 79.99rem) and (min-width: 62rem) {
  .lay-desk .nav__list { gap: 0; }
  .lay-desk .nav__i > .nav__link { padding: 0 6px; font-size: 13.5px; }
  .lay-desk .nav__i--has { padding-right: 4px; }
  .lay-desk .nav__i--has > .nav__link { padding-right: 2px; }
  .lay-desk .nav__link .nav__new { margin-left: 5px; padding: 0 4px; }
  .lay-desk .nav__more { padding: 0 6px; font-size: 13.5px; }
}
@media (min-width: 62rem) and (prefers-reduced-motion: reduce) {
  .lay-desk .nav__i, .lay-desk .nav__i > .nav__link, .lay-desk .nav__link .ico, .lay-desk .nav__more { transition: none; }
}

/* ---------- breadcrumbs ---------- */

.crumbs { margin: 0 0 calc(var(--space) * 2); }
.crumbs__list {
  display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0;
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
}
.crumbs__list li + li::before { content: "/"; margin-right: 6px; opacity: 0.55; }
.crumbs__list li[aria-current="page"] {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch;
}

/* ---------- layout ---------- */

main { padding: calc(var(--space) * 3) 0 calc(var(--space) * 6); }
.pagehead { margin: 0 0 calc(var(--space) * 3); }
.pagehead h1 {
  font-family: var(--font-head); font-size: var(--step-4); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 0 0 6px;
}
.pagehead p { color: var(--muted); margin: 0; font-size: var(--step-n1); }

/* ---------- section fronts ----------
   A category page is the surface that ranks for "football news", so it opens
   by saying plainly what it is, how much is in it and when it last moved.
   The description renders only when a publication declares one. */
.pagehead--cat {
  padding-bottom: calc(var(--space) * 2);
  border-bottom: var(--rule-w) solid var(--ink);
  margin-bottom: var(--section-gap);
}
.pagehead--cat h1 { font-family: var(--font-display); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking); line-height: var(--lh-display); }
.pagehead__desc { color: var(--muted); font-size: var(--step-0); margin: 8px 0 0; max-width: var(--measure); }
.pagehead__meta {
  font-family: var(--font-meta); font-size: var(--meta-size); font-weight: var(--meta-weight);
  letter-spacing: var(--meta-tracking); text-transform: var(--meta-transform);
  color: var(--faint); margin-top: 10px; font-variant-numeric: tabular-nums;
}

/* WIRE: an index. Tight head, hairline rules between every row. */
.lay-wire .pagehead--cat { margin-bottom: calc(var(--section-gap) * 0.7); }
.wire--cat .wire__flow > li { border-top: var(--border-w) solid var(--rule); }

/* NEWSPAPER: a section front. Generous head, italic standfirst, ruled tiers. */
.lay-newspaper .pagehead--cat { text-align: center; padding-bottom: calc(var(--space) * 3); }
.lay-newspaper .pagehead__desc { font-style: italic; margin-left: auto; margin-right: auto; }

/* DESK: a sports section. Heavy rule, uppercase head, tight tail. */
.lay-desk .pagehead--cat h1 { text-transform: uppercase; }
.lay-desk .pagehead--cat { border-bottom-width: var(--rule-w); }

.grid {
  display: grid; gap: var(--card-gap);
  grid-template-columns: 1fr;
}

/* min-width:0 stops a long word in a grid child from forcing the track wider. */
.grid > * { min-width: 0; }

/* ---------- cards ---------- */

/* Cards take their chrome from the publication's own token rather than a fixed
   panel: two of the three show a bare image over type, and the third a white
   card on a faint ground. Nothing is raised and nothing is rounded - the
   reference draws every division with a hairline. */
.card {
  background: var(--card-bg); border: var(--card-border);
  overflow: hidden; display: flex; flex-direction: column;
  /* The one gap a chrome-less card needs between its picture and its type,
     and the one a carded card needs under its picture. Same value either way. */
  gap: calc(var(--space) * 1.1);
}
/* A PEER FRAME. Fixed ratio, full width of its track, cropped to fill, so four
   cards in a row are four identical boxes whatever shape their files are. The
   ratio here is the fallback; the is-* class the card asks for wins below. */
.card__media {
  background: var(--canvas); aspect-ratio: 16 / 9;
  width: 100%; overflow: hidden;
}
.card__media img { width: 100%; height: 100%; object-fit: cover; }
.card__body {
  padding: var(--card-pad); display: flex; flex-direction: column;
  gap: calc(var(--space) * 0.9); flex: 1; min-width: 0;
}
.card__cat {
  font-family: var(--font-meta); font-size: var(--meta-size); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking); color: var(--accent);
}
/* The section kicker is a real link to a real page, and it sits directly above
   a much larger headline link. At 17.6px of text height it was a 17px target
   under a 40px one — under the 24px WCAG 2.5.8 asks for, and easy to hit by
   mistake. inline-flex with a min-height rather than padding, so the number is
   the number whatever the publication's meta size happens to be, and the text
   still sits on the same baseline it did. The hero kicker already cleared this
   with its own padding and is deliberately left alone. */
.card__cat, .feedrow__cat, .compact__cat {
  display: inline-flex; align-items: center; min-height: 24px;
}
.card__title {
  font-family: var(--font-head); font-size: var(--step-1); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 0;
}
.card__title a { color: var(--ink); }
.card__title a:hover { color: var(--accent); text-decoration: none; }
.card--lead .card__title {
  font-size: var(--step-2); font-family: var(--font-display);
  font-weight: var(--display-weight); letter-spacing: var(--display-tracking);
  line-height: var(--lh-display);
}
.card__excerpt { color: var(--muted); font-size: var(--step-n1); margin: 0; }

/* ---------- image frames ----------
   The container crops to the frame; the <img> keeps the intrinsic width and
   height that reserve its space. Declared after .card__media so the frame a
   card asks for wins over the 16:9 default at equal specificity. */
.is-16x9 { aspect-ratio: 16 / 9; }
.is-3x2  { aspect-ratio: 3 / 2; }
.is-4x3  { aspect-ratio: 4 / 3; }
.is-1x1  { aspect-ratio: 1 / 1; }

/* ---------- card roles ----------
   Chrome by role, not by default. A lead earns a surface and a rule; a
   standard card earns a surface; a compact row earns only a hairline. One
   radius and one shadow on everything is what flattens a news page. */
.card--lead { border-top: var(--rule-w) solid var(--accent); }
.card--featured .card__title { font-size: var(--step-1); }
.card--standard .card__body { gap: calc(var(--space) * 0.6); }

/* Overlay: the body sits on the artwork instead of beneath it. Markup order is
   unchanged, so reading order and the single accessible link survive. */
.card--overlay { position: relative; }
.card--overlay .card__body {
  position: absolute; inset: auto 0 0 0; z-index: 1;
  background: linear-gradient(to top, rgba(0,0,0,0.82) 30%, rgba(0,0,0,0));
  padding: calc(var(--space) * 4) var(--card-pad) var(--card-pad);
}
.card--overlay .card__title a,
.card--overlay .card__meta { color: #fff; }
.card--overlay .card__cat { color: #fff; }

/* ---------- time badge ---------- */
.tbadge {
  font-family: var(--font-meta); font-size: var(--meta-size);
  font-weight: var(--meta-weight); letter-spacing: var(--meta-tracking);
  font-variant-numeric: tabular-nums; color: var(--accent);
  background: var(--accent-weak); padding: 2px 7px; border-radius: var(--radius);
  white-space: nowrap;
}
.card__badge { align-self: flex-start; }

/* ---------- compact row ----------
   A thumbnail, a headline, and its time. The densest unit that still carries
   a picture; the thumbnail edge is a token so each publication sets its own. */
.compact {
  display: grid; grid-template-columns: var(--thumb) minmax(0, 1fr);
  gap: calc(var(--space) * 1.5); align-items: start;
  padding: var(--stack-gap) 0;
}
/* A peer frame too, in a fixed --thumb track: its width is the track and its
   height follows the ratio, so a list of rows lines up down its left edge. */
.compact__media {
  background: var(--canvas); width: 100%; overflow: hidden; border-radius: var(--radius);
}
.compact__media img { width: 100%; height: 100%; object-fit: cover; }
.compact__body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.compact__title {
  font-family: var(--font-head); font-size: var(--step-0); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 0;
  /* A short headline should not leave one word alone on the last line, and a
     long one should not break a word it could have carried. */
  text-wrap: pretty;
}
.compact__title a { color: var(--ink); }
.compact__title a:hover { color: var(--accent); text-decoration: none; }
.compact__meta {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
}

/* ---------- latest item ----------
   Clock time and a headline, no artwork. A column of times scans faster than
   a column of thumbnails, which is what "what just happened" needs. */
.latest {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: calc(var(--space) * 1.5); align-items: baseline;
  padding: var(--stack-gap) 0; border-top: var(--border-w) solid var(--rule);
}
.latest:first-of-type { border-top: 0; }
.latest__time {
  font-family: var(--font-meta); font-size: var(--meta-size); font-weight: var(--meta-weight);
  font-variant-numeric: tabular-nums; color: var(--faint); letter-spacing: var(--meta-tracking);
}
.latest__title {
  font-family: var(--font-head); font-size: var(--step-0); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 0;
}
.latest__title a { color: var(--ink); }
.latest__title a:hover { color: var(--accent); text-decoration: none; }

/* Section overflow: stories a section block could not fit into its three cards. */

.card__meta {
  margin-top: auto; font-family: var(--font-meta); font-size: var(--step-n1);
  color: var(--muted); display: flex; gap: 8px; flex-wrap: wrap;
}

/* ---------- article furniture shared by every variant ---------- */

.sourcebox {
  margin: calc(var(--space) * 3.5) 0 0; padding: calc(var(--space) * 2);
  background: var(--canvas); border: var(--border-w) solid var(--border);
  border-radius: var(--radius); font-size: var(--step-n1);
}
.sourcebox strong { display: block; margin-bottom: 4px; }
.sourcebox__list { margin: 6px 0 0; padding: 0; list-style: none; }
.sourcebox__list li { margin-top: 2px; overflow-wrap: anywhere; }

/* ================= layout variants =================
 * Composition only. Colour, type and rhythm all still come from the tokens
 * above, so a variant changes arrangement without redefining identity.
 * Mobile is authored first and deliberately per variant — none of these is a
 * collapsed desktop grid.
 */

.blockhead {
  font-family: var(--font-meta); font-size: var(--meta-size); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
  color: var(--muted); margin: calc(var(--space) * 4) 0 calc(var(--space) * 2);
  border-bottom: var(--border-w) solid var(--border); padding-bottom: 6px;
}
.blockhead a { color: inherit; }

/* ---- WIRE: density and scanability ---- */

.wire__flow { list-style: none; margin: 0; padding: 0; }
.wire__flow > li { border-top: var(--border-w) solid var(--border); }
.wire__flow > li:first-child { border-top: 0; }

.row { padding: calc(var(--space) * 1.5) 0; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.row__title {
  font-family: var(--font-head); font-size: var(--step-0); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 0;
}
.row__title a { color: var(--ink); }
.row__title a:hover { color: var(--accent); text-decoration: none; }

/* ---- TABLOID: one dominant lead ---- */

.paper-sub { display: grid; gap: var(--card-gap); grid-template-columns: 1fr; margin-bottom: var(--card-gap); }
.paper-sub > * { min-width: 0; }

/* ---- BROADSHEET: asymmetric lead plus section blocks ---- */

.brief { padding: calc(var(--space) * 2) 0; border-top: var(--border-w) solid var(--border); min-width: 0; }
.brief:first-of-type { border-top: 0; }
.brief__title {
  font-family: var(--font-head); font-size: var(--step-1); line-height: var(--lh-head);
  font-weight: var(--head-weight); margin: 4px 0 6px;
}
.brief__title a { color: var(--ink); }
.brief__excerpt { font-size: var(--step-n1); }

.desk__grid { display: grid; gap: var(--card-gap); grid-template-columns: 1fr; }
.desk__grid > * { min-width: 0; }

/* ---- article variants ----

   One skeleton, three readings. layouts.js composes all three from the same
   set of parts; everything that makes them feel different is here — the
   measure, the type, and how much furniture sits around the words.

   Measures are declared in `ch`, not px. A reading measure is a character
   count, and the newspaper's Georgia and the wire's system sans put a very
   different number of characters into the same 680px. In `ch` the brief holds
   in both: 64 characters is 64 characters whatever the face.

   Headline sizes are `min(step, cap)`. The scale below each cap is the shared
   fluid one, so the headline still tracks the viewport on a phone; the cap is
   an editorial rule, that an article headline never shouts as loudly as the
   front page hero it was promoted from. Without it the newspaper's scale —
   tuned so its hero can reach 73px — would set a 55px article headline.       */

.art {
  /* Flat. The story is the page, not an object sitting on it — the panel and
     its border were the last thing making an article read as a widget. */
  background: none; border: 0; border-radius: 0; padding: 0;
  max-width: var(--measure); margin: 0 auto;
}
.art__head { display: flex; flex-direction: column; gap: calc(var(--space) * 0.8); }
.art__title {
  font-family: var(--font-head); font-size: var(--step-5); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 6px 0 4px;
}
/* The article headline is the page's loudest object and it should be. On a
   390px screen, though, the newspaper's scale reached 38px and ran a headline
   to five lines - 190px of type before the story had begun. Capped on a phone
   only; every publication keeps its own desktop cap below (34, 44 and 38). */


/* ---- byline and sharing ----

   One row under the standfirst: who published it and when on the left, the
   controls for passing it on at the right, and a rule under the pair. */
.art__byline {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: calc(var(--space) * 1.5) var(--space);
  margin-top: calc(var(--space) * 0.5);
}
.byline {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
}
.byline__pub { font-weight: 700; color: var(--ink); }
/* A separator between the publisher and the time, and none before the source:
   when the row wraps, a leading interpunct starts the second line on its own,
   which reads as a bullet rather than as a separator. */
.byline > * + *:not(.byline__src)::before { content: "·"; margin-right: 10px; color: var(--faint); }
.byline__src { color: var(--faint); }
/* Derived from the body rather than stored, so it is set like the source
   credit rather than like the publication time beside it. */
.byline__read { color: var(--faint); }
.share { display: flex; align-items: center; gap: 6px; }
.share__label {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
}
.share__btn {
  /* 36px, which clears the 24px WCAG 2.5.8 asks for with room for a thumb. */
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  border: var(--border-w) solid var(--rule); border-radius: 999px;
  background: var(--surface, transparent); color: var(--muted); cursor: pointer;
}
.share__btn svg { width: 17px; height: 17px; fill: currentColor; }
.share__btn:hover { color: var(--accent); border-color: var(--accent); text-decoration: none; }
.share__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.share__copy { position: relative; }
.share__done {
  position: absolute; bottom: calc(100% + 6px); right: 0;
  font-family: var(--font-meta); font-size: 11px; white-space: nowrap;
  color: var(--accent-ink, #fff); background: var(--ink); padding: 3px 7px;
  border-radius: var(--radius); opacity: 0; transition: opacity .15s ease;
  pointer-events: none;
}
.share__copy.is-done .share__done { opacity: 1; }

/* THE WIRE — narrow, unadorned, ruled.

   No card. A wire story is not an object sitting on the page, it is the page,
   so the border and the tinted panel come off and the divisions are made by
   rule instead. The head is separated from the story by a heavy rule and the
   continuation by another: two lines doing the work a box was doing, which is
   the whole idea of a wire front carried into the article.                    */
.art--wire {
  background: none; border: 0; border-radius: 0; padding: 0;
  max-width: 64ch;
}
.art--wire .art__title { font-size: min(var(--step-4), 34px); }
.art--wire .art__head {
  gap: calc(var(--space) * 0.7);
  border-bottom: 3px solid var(--ink); padding-bottom: calc(var(--space) * 1.6);
}
/* The head already carries the rule; the meta row must not draw a second. */
.art--wire .art__meta { border-bottom: 0; padding-bottom: 0; }
/* Restrained lead media: present, sized to inform, not to dominate. */
.art--wire .art__media { margin: calc(var(--space) * 2) 0; }
/* Sibling, not descendant: the continuation block is rendered after the
   </article>, not inside it, so that an article page has exactly one <article>
   element for the story itself. */
.art--wire + .art__related {
  margin-top: calc(var(--space) * 4);
  border-top: 3px solid var(--ink); padding-top: calc(var(--space) * 2);
}

/* THE NEWSPAPER — a wide serif measure with room around it. */
.art--newspaper { max-width: 72ch; padding-top: 0; }
.art--newspaper .art__title {
  font-family: var(--font-display); font-size: min(var(--step-4), 44px);
  font-weight: var(--display-weight); letter-spacing: var(--display-tracking);
  line-height: var(--lh-display); text-wrap: balance;
}
/* The standfirst is the one italic on the page, and it is the reason the
   reader continues. Set in the display face so it reads as part of the
   headline rather than as the first line of the body. */
.art--newspaper .art__standfirst {
  font-family: var(--font-display); font-style: italic;
  font-size: var(--step-1); line-height: 1.5; color: var(--muted);
}
/* Serif body, opened up. The size floor keeps the long read at a comfortable
   18px even where the shared scale bottoms out lower. */
.art--newspaper .art__body {
  font-family: var(--font-display);
  font-size: max(var(--step-0), 18px); line-height: 1.75;
}
.art--newspaper .art__head {
  gap: calc(var(--space) * 1.3); padding-top: calc(var(--space) * 2.5);
}

/* THE DESK — a middle measure, and the clock never off the page. */
.art--desk { max-width: 68ch; }
.art--desk .art__title { font-size: min(var(--step-4), 38px); }
@media (max-width: 47.99rem) {
  /* Scoped to each layout on purpose: every publication sets its own
     .art--x .art__title, which out-specifies a bare .art__title however late
     it appears. A cap that loses to the rule it is capping is not a cap. */
  .art--wire .art__title,
  .art--newspaper .art__title,
  .art--desk .art__title,
  .art__title { font-size: min(var(--step-4), 30px); line-height: 1.16; }
}

/* ---------- the article head, on a phone ----------
   Category, headline, standfirst, byline, sharing and the picture are ONE
   editorial block. At desktop spacing on a 390px screen they arrive as six
   separated objects and the picture is pushed most of a screen below the
   headline it belongs to. These are phone-only spacing overrides: no size,
   colour or face changes, and nothing above 48rem moves. */
@media (max-width: 47.99rem) {
  .art__head { gap: calc(var(--space) * 0.6); }
  .art--wire .art__head {
    gap: calc(var(--space) * 0.55);
    border-bottom-width: 2px; padding-bottom: calc(var(--space) * 1.1);
  }
  .art--newspaper .art__head { gap: calc(var(--space) * 0.8); padding-top: var(--space); }
  .art--desk .art__head { gap: calc(var(--space) * 0.6); }
  .art__standfirst { line-height: 1.45; }
  /* The byline and the share row belong to the headline above them, not to
     the picture below. */
  .art__byline { gap: calc(var(--space) * 0.8) var(--space); margin-top: calc(var(--space) * 0.35); }
  .share__btn { width: 34px; height: 34px; }
  .share__btn svg { width: 16px; height: 16px; }
  /* Each layout sets its own lead-picture margin, so each is answered here. */
  .art--wire .art__media,
  .art--newspaper .art__media,
  .art--desk .art__media,
  .art__media { margin: calc(var(--space) * 1.2) 0 calc(var(--space) * 1.6); }
}

/* The badge is the desk's signature on every surface; on the article page it
   sits in the meta row at reading size rather than card size. */
.art--desk .art__meta { align-items: center; }
.art--desk .art__meta .tbadge,
.art--desk .byline .tbadge { font-size: var(--step-n1); padding: 3px 9px; }
.art--desk .art__media { margin: calc(var(--space) * 2.5) 0 calc(var(--space) * 3); }
.art__standfirst {
  font-family: var(--font-head); font-size: var(--step-1); line-height: 1.45;
  color: var(--ink); margin: 0;
}
.art__meta, .art__metabar {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
  display: flex; gap: 10px; flex-wrap: wrap;
  padding-bottom: calc(var(--space) * 2); border-bottom: var(--border-w) solid var(--border);
}
.art__metabar {
  border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink);
  padding: calc(var(--space) * 1.2) 0; margin: calc(var(--space) * 2) 0;
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
  font-weight: var(--meta-weight); color: var(--ink);
}
/* ---------- photo credits, at the foot of the article ----------
   The credit is no longer under the picture: it sat between the photograph
   and the first paragraph in three different lengths depending on the
   licence, on every article. Here it is one compact block, in the page's own
   text, visible without a control, with the link intact - which is what the
   licences require and what a reader looking for it can find. Set quietly,
   because it is not the story; complete, because it is a condition of using
   the picture at all. */
.artcredits {
  margin-top: calc(var(--space) * 3);
  padding-top: calc(var(--space) * 1.2);
  border-top: var(--border-w) solid var(--border);
  max-width: var(--measure);
}
.artcredits__h {
  margin: 0 0 4px; font-family: var(--font-meta); font-size: var(--step-n1);
  font-weight: var(--meta-weight); letter-spacing: var(--meta-tracking);
  text-transform: var(--meta-transform); color: var(--muted);
}
.artcredits__line {
  margin: 0; font-family: var(--font-meta); font-size: var(--step-n1);
  line-height: 1.5; color: var(--faint); overflow-wrap: anywhere;
}
/* The CC BY-SA modification notice, beside the credit it qualifies. Quieter
   than the attribution and never a link: it states a fact about the cards,
   not a source. */
.artcredits__mod { color: var(--faint); }
.artcredits__line a { color: inherit; text-decoration: underline; }
.artcredits__line a:hover { color: var(--accent); }
@media (max-width: 47.99rem) {
  .artcredits { margin-top: calc(var(--space) * 2); }
}

.art__context { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.art__context-note { font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted); }
.art__media { margin: calc(var(--space) * 3) 0; }
.art__media img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--radius); background: var(--canvas);
}
/* The newspaper hero bleeds to the article edges. */
/* The newspaper's lead plate. It used to bleed past the article's padding with
   a negative margin; now the article has no padding, so it simply fills the
   column — and no longer pushes 4px off the side of a phone. */
.art__media--full {
  margin: 0 0 calc(var(--space) * 2);
  border-radius: var(--radius) var(--radius) 0 0; overflow: hidden;
}
.art__media--full img { border-radius: 0; }

/* Licensed photography that must not be cropped.
   Every media box above is 16:9 and fills it with object-fit: cover, which
   cuts whatever does not fit. A ShareAlike photograph shown that way is a
   crop, and a crop is an adapted work — so those are shown whole inside the
   same frame, with canvas where the aspect does not match. The stored file is
   identical either way; only the presentation differs. Each selector names its
   container so it outranks the plain `.x__media img` rule regardless of order. */
.card__media.is-contain img,
.compact__media.is-contain img,
.feedrow__media.is-contain img,
.hero__media.is-contain img,
.art__media.is-contain img {
  object-fit: contain; background: var(--canvas);
}

.art__body { font-size: var(--step-0); }
.art__body p { margin: 0 0 1em; }
.art--newspaper .art__body p { margin-bottom: 0.9em; }
/* Two levels, two sizes. These shared one rule, which meant a long piece with
   both had no hierarchy at all: same size, same weight, same margins. The
   family, weight and leading stay on the publication's own tokens, so each
   paper's voice is unchanged — only the step and the space above it differ. */
.art__body h2, .art__body h3 {
  font-family: var(--font-head); line-height: var(--lh-head);
  font-weight: var(--head-weight); margin: 1.5em 0 0.5em;
}
.art__body h2 { font-size: var(--step-2); }
/* One step down, and less air above it: a subhead belongs to the section it
   sits in, so it should read as part of it rather than as another break. */
.art__body h3 { font-size: var(--step-1); margin-top: 1.15em; }
.art__body ul, .art__body ol { margin: 0 0 1em; padding-left: 1.4em; }
/* A link in running text was distinguished by hue and nothing else. On Daily
   All In the green sits at 2.82:1 against the body ink — under the 3:1 that
   colour-only links need — so the underline is the cue that carries it. Kept
   restrained: a hairline, dropped clear of the descenders. Scoped to prose
   inside the article body, so nav, cards and kickers are untouched. */
.art__body p a, .art__body li a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
.art__body blockquote {
  margin: 1.3em 0; padding: 2px 0 2px 16px;
  border-left: 3px solid var(--accent); color: var(--muted);
}
.art__related { margin-top: calc(var(--space) * 5); }
/* The premium read earns the most air before it offers the next story. */
.art--newspaper + .art__related { margin-top: calc(var(--space) * 7); }

/* ---- the page ----

   The chrome is a header band across the top and nothing down the side. The
   fixed 220px left rail that used to carry the sections is gone: on a 1440px
   viewport it took a seventh of the screen and pushed the front into a column
   too narrow for a lead story to lead, which is most of why the pages read as
   undersized. Horizontal navigation costs the content nothing and is what a
   reader of a news portal looks for anyway.                                */

.portal {
  /* A column, so a short page — Results with no provider, a 404 — puts its
     footer at the bottom of the viewport instead of halfway down it with
     white space underneath. */
  min-width: 0; display: flex; flex-direction: column; min-height: 100vh;
}
.portal > main { flex: 1 0 auto; }

.media__stamp {
  position: absolute; top: 12px; left: 12px;
  font-family: var(--font-meta); font-size: var(--step-n1);
  font-variant-numeric: tabular-nums; letter-spacing: var(--meta-tracking);
  color: #fff; background: rgb(0 0 0 / 0.78);
  padding: 4px 9px; border-radius: var(--radius);
}
/* The stamp is positioned against its frame, so every frame that can carry
   one must establish a containing block. */
.art__media, .card__media, .feedrow__media, .compact__media, .hero__media { position: relative; }

/* The photo credit.

   A licence obligation rendered as quietly as it can be while still being
   read: the same meta face, a step below body copy, in the muted ink every
   secondary line on the page already uses. Both theme tokens are defined for
   light and dark, so this needs no theme rules of its own — which is the point
   of taking the colour from --muted rather than naming one here.

   It sits under the picture, inside the same <figure>, so it is associated
   with the image both visually and structurally. Only the article page's lead
   carries one; thumbnails link through to it. */
.media__credit {
  margin: 8px 0 0;
  font-family: var(--font-meta); font-size: var(--step-n1);
  line-height: 1.4; color: var(--muted);
}
.media__credit a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.media__credit a:hover { color: var(--ink); }
/* The credit line stays on one line, and the context that used to run to four
   lines of grey type under the lead sits behind a control. Everything is still
   in the markup and one tap away; what has gone is four lines about a
   photograph sitting between the reader and the article. */
.media__creditmore { display: inline; }
.media__creditmore > summary {
  display: inline; list-style: none; cursor: pointer;
  margin-left: 6px; color: var(--muted);
  text-decoration: underline; text-underline-offset: 2px;
}
.media__creditmore > summary::-webkit-details-marker { display: none; }
.media__creditmore > summary:hover { color: var(--ink); }
.media__creditmore > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.media__creditmore[open] > summary { color: var(--ink); }
.media__creditmore > span { display: block; margin-top: 4px; }
/* The newspaper's lead plate bleeds to the column edges and its own margin
   collapses to zero, so the credit is inset to sit under the picture rather
   than against the page edge. */
.art__media--full .media__credit { padding: 0 var(--card-pad) 0; }

/* ---- index shell ----

   One architecture — content column plus sidebar — filled differently by each
   publication. Everything that makes the three fronts feel unrelated is a
   token: the ground the page sits on, whether a story is separated by nothing,
   a rule or a card, the grid proportion, and the spacing unit. The markup is
   identical; only the values differ.

   The shell is mobile-first single-column and becomes two tracks at 900px.
   `--shell-cols` carries each publication's own proportion, so the stylesheet
   does no per-publication arithmetic.                                       */

.shell { display: grid; grid-template-columns: 1fr; gap: var(--shell-gap); }
.shell__main, .shell__side { min-width: 0; }   /* min-width:0 or a long word
                                                  in a grid child widens the page */
.shell--solo { display: block; }

@media (min-width: 900px) {
  .shell { grid-template-columns: var(--shell-cols); }
  /* Sticky is a per-publication decision: a section index and a live column
     both want to follow the reader; a printed page's second column does not. */
  .shell__side { position: var(--side-position); top: var(--space); align-self: start; }
}

/* ---- the feed ----

   The continuous editorial list every front ends with. One row markup, three
   readings: the thumbnail ratio, the timestamp form and the rhythm all come
   from tokens, and the newspaper turns the thumbnail off entirely.           */

.feed { list-style: none; margin: var(--section-gap) 0 0; padding: 0; }
.feed > li { border-top: var(--rule-w) solid var(--rule); }
.feed > li:first-child { border-top: 0; }

.feedrow {
  display: grid; grid-template-columns: var(--thumb-px, 92px) minmax(0, 1fr);
  gap: calc(var(--space) * 1.5); align-items: start;
  padding: calc(var(--feed-rhythm) / 4) 0;
}
.feedrow--text { grid-template-columns: minmax(0, 1fr); }
/* And the feed's own. Same contract: track width, ratio height, cropped to fill. */
.feedrow__media { width: 100%; border-radius: var(--radius); overflow: hidden; }
.feedrow__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.feedrow__body { min-width: 0; }
.feedrow__cat {
  display: inline-block; font-family: var(--font-meta); font-size: var(--meta-size);
  font-weight: var(--meta-weight); text-transform: var(--meta-transform);
  letter-spacing: var(--meta-tracking); color: var(--accent); text-decoration: none;
}
.feedrow__title {
  font-family: var(--font-head); font-size: var(--step-0); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 2px 0 4px;
}
.feedrow__title a { color: inherit; text-decoration: none; }
.feedrow__title a:hover { color: var(--accent); }
.feedrow__meta {
  display: flex; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
}

/* ---- sidebar fillings ---- */

.sindex__list, .brieflist__list, .livecol__list { list-style: none; margin: 0; padding: 0; }

/* Wire: a section index. Name, count, last movement — a navigational table. */
.sindex__row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px;
  align-items: baseline; padding: calc(var(--space) * 1.1) 0;
  border-top: var(--rule-w) solid var(--rule);
}
.sindex__list > li:first-child { border-top: 0; }
.sindex__name { color: var(--ink); text-decoration: none; font-weight: 600; }
.sindex__name:hover { color: var(--accent); }
.sindex__n {
  font-family: var(--font-meta); font-size: var(--step-n1); font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.sindex__when {
  font-family: var(--font-meta); font-size: var(--step-n1);
  font-variant-numeric: tabular-nums; color: var(--muted);
}

/* Newspaper: In Brief. Text only, ruled, no clocks anywhere. */
.brieflist__list > li { padding: calc(var(--space) * 1.4) 0; border-top: var(--rule-w) solid var(--rule); }
.brieflist__list > li:first-child { border-top: 0; }
.brieflist__title {
  font-family: var(--font-display); font-size: var(--step-0); line-height: 1.3;
  font-weight: var(--display-weight); margin: 0 0 4px;
}
.brieflist__title a { color: inherit; text-decoration: none; }
.brieflist__title a:hover { color: var(--accent); }
.brieflist__meta { font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted); }

/* Desk: the live column. Clock first, headline second, no pictures. */
.livecol__list > li { border-top: var(--rule-w) solid var(--rule); }
.livecol__list > li:first-child { border-top: 0; }

/* Section wrappers. The heading owns the top margin; the list owns the rest. */
.sindex, .brieflist, .livecol { margin: 0 0 var(--section-gap); }
.sindex > .blockhead, .brieflist > .blockhead, .livecol > .blockhead { margin-top: 0; }
.brieflist__item { margin: 0; }

/* Feed variants. The class is on the list so a publication's feed can be
   recognised in the markup as well as inherited through the body class. */
.feed--wire > li { border-top-width: var(--rule-w); }
.feed--paper > li { border-top-style: solid; }
.feed--desk > li { border-top-color: var(--border); }

/* ---- per-publication grounds and chrome ----

   Three different page grounds is the fastest way to tell the sites apart at a
   glance, and the one rule that must never converge.                         */

body { background: var(--ground); }

/* Card chrome is the publication's own token now (cardChrome in config), not a
   rule per layout class. Two of the three show a bare picture over type; the
   third shows a white card on a faint ground. Nothing here forks a template. */
.card { border-radius: 0; }

/* THE INTERNATIONAL FRONT — white cards on a faint ground. */
.lay-wire .feedrow { --thumb-px: 84px; }
.lay-wire .feed > li { border-top-color: var(--rule); }

/* THE BROADSHEET — paper, hairline rules, no card ever. */
.lay-newspaper .feed > li { border-top: var(--rule-w) solid var(--rule); }
.lay-newspaper .feedrow { padding: calc(var(--feed-rhythm) / 3) 0; }

/* THE SPORTS DESK — no panel at all; the picture and the type do the work. */
.lay-desk .feedrow { --thumb-px: 96px; }
/* The square crop is the desk's alone. */
.lay-desk .feedrow__media { aspect-ratio: 1 / 1; }

/* ---- search ----

   One skeleton, three readings, exactly as the article page does it: the form,
   the status line and the result rows are shared, and what differs per
   publication is measure, type and how much furniture surrounds them.

   Results are built in the browser by site.js, so every class here has to be
   styled from the markup that script produces — there is no server-rendered
   result row to inspect. The classes it emits are: .search__list, .sresult,
   .sresult__cat, .sresult__title, .sresult__sf, .sresult__meta, .search__empty
   and .search__note.                                                        */

/* A label that a screen reader announces and nobody sees. A search box with
   only a placeholder loses its name the moment the placeholder clears. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.search { max-width: var(--measure); margin: 0 auto; }

/* Search and the error page start at the gutter, like every other page type.
   Both were centred in the viewport, which put their first element 285-350px
   in from a masthead that starts at 76-131px: at 1440 the search box began
   293px to the right of the brand above it, and at 1280, 265px. Every other
   page on these sites lines its content up with the masthead to within about
   10px. These two were the exceptions, and there is nothing in either of them
   that wants to be centred - a control and an apology are not a reading
   column. /about/ IS a reading page and is deliberately left as it was. */
.search, .art--404 { margin-inline: 0; }

/* Somewhere to go, under both of them.

   Rendered by each publication's own continuation treatment - the wire's ruled
   flow, the newspaper's serif cards, the desk's time-stamped grid - so the
   three do not converge on one generic block. Only the frame is shared. It
   takes the full page width rather than the reading measure, because the point
   of it is the space below the fold that these two pages were leaving empty. */
.browse {
  margin: var(--section-gap) 0 0;
  padding-top: calc(var(--space) * 3);
  border-top: var(--border-w) solid var(--border);
}
.browse__sections { margin: 0 0 var(--section-gap); }
.browse__list {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 0; padding: 0; list-style: none;
}
.browse__link {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 0 14px;
  font-family: var(--font-meta); font-size: var(--meta-size);
  font-weight: var(--meta-weight); text-transform: var(--meta-transform);
  letter-spacing: var(--meta-tracking);
  color: var(--ink); text-decoration: none;
  background: var(--surface);
  border: var(--border-w) solid var(--border); border-radius: var(--radius);
}
.browse__link:hover { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.browse__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.browse__recent > .blockhead { margin-bottom: calc(var(--space) * 2); }

.searchform {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin: calc(var(--space) * 2) 0 calc(var(--space) * 1.5);
}
.searchform__input {
  flex: 1 1 12rem; min-width: 0;      /* min-width:0 is what stops a flex item
                                         forcing the row wider than the page */
  font-family: var(--font-body); font-size: var(--step-0); color: var(--ink);
  background: var(--surface); border: var(--border-w) solid var(--border);
  border-radius: var(--radius); padding: 12px 14px;
}
.searchform__input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.searchform__go {
  font-family: var(--font-meta); font-size: var(--meta-size); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
  color: var(--accent-ink); background: var(--accent);
  border: var(--border-w) solid var(--accent); border-radius: var(--radius);
  padding: 12px 20px; cursor: pointer;
}
.searchform__go:hover { filter: brightness(1.08); }
.searchform__go:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.search__status {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
  margin: 0 0 calc(var(--space) * 2);
}
.search__list { list-style: none; margin: 0; padding: 0; }
.search__note, .search__noscript {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
  margin: calc(var(--space) * 2) 0 0;
}
.search__empty { padding: calc(var(--space) * 3) 0; color: var(--muted); }

.sresult { padding: calc(var(--space) * 2) 0; border-top: var(--border-w) solid var(--border); }
.search__list > li:first-child .sresult { border-top: 0; }
.sresult__cat {
  display: inline-block; font-family: var(--font-meta); font-size: var(--meta-size);
  font-weight: var(--meta-weight); text-transform: var(--meta-transform);
  letter-spacing: var(--meta-tracking); color: var(--accent); text-decoration: none;
}
.sresult__title {
  font-family: var(--font-head); font-size: var(--step-1); line-height: var(--lh-head);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); margin: 4px 0 6px;
}
.sresult__title a { color: inherit; text-decoration: none; }
.sresult__title a:hover { color: var(--accent); }
.sresult__sf { color: var(--muted); margin: 0 0 6px; }
.sresult__meta {
  display: flex; flex-wrap: wrap; gap: 10px;
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
}

/* THE WIRE — a utility. No card, rules between rows, tightest rhythm. */
.search--wire { max-width: 64ch; }
.search--wire .sresult { padding: calc(var(--space) * 1.4) 0; }
.search--wire .sresult__title { font-size: var(--step-0); }
.search--wire .sresult__sf { display: none; }   /* density over description */

/* THE NEWSPAPER — the serif reading treatment, given room. */
.search--newspaper { max-width: 72ch; }
.search--newspaper .sresult { padding: calc(var(--space) * 3) 0; }
.search--newspaper .sresult__title {
  font-family: var(--font-display); font-size: var(--step-2);
  font-weight: var(--display-weight); line-height: var(--lh-display);
}
.search--newspaper .sresult__sf { font-family: var(--font-display); line-height: 1.6; }

/* THE DESK — compact, and the clock stays on every row. */
.search--desk { max-width: 68ch; }
.search--desk .sresult { padding: calc(var(--space) * 1.8) 0; }
.search--desk .sresult__meta time {
  font-family: var(--font-meta); font-variant-numeric: tabular-nums;
  color: var(--accent); background: var(--accent-weak);
  padding: 2px 7px; border-radius: var(--radius); white-space: nowrap;
}

/* ---- tags ---- */

.tags { display: flex; flex-wrap: wrap; gap: 8px; margin: calc(var(--space) * 3) 0 0; padding: 0; list-style: none; }
.tags li {
  padding: 3px 11px; border: var(--border-w) solid var(--border); border-radius: 999px;
  font-family: var(--font-meta); font-size: var(--step-n1);
}
.tags li a { color: var(--ink); }
.tags li a:hover { color: var(--accent); text-decoration: none; }
.tags__plain { color: var(--muted); border-style: dashed; }
.tags--flow { border-top: var(--border-w) solid var(--border); padding-top: calc(var(--space) * 2); }

/* ---------- homepage composition ----------
   Three different fronts, one component set. Each block below is used by
   exactly one variant; nothing here is shared scaffolding pretending to be
   three designs. */

/* WIRE: section blocks against a sticky latest rail. */

/* NEWSPAPER: ruled two-column blocks and a quiet text column. */

/* DESK: sport blocks sit tight together; the tail is the densest tier. */

/* ---------- pagination ---------- */

.pager {
  display: flex; gap: 8px; justify-content: center; align-items: center;
  margin: calc(var(--space) * 4.5) 0 0; flex-wrap: wrap;
}
/* The listing pager's controls are <button>, not <a>: a listing has one URL and
   later pages are fragments, so there is no per-page address to link to. The
   search pager (#search-pager) is still links, because a search result page IS a
   shareable URL. Both are styled here, identically, so the two read as the same
   control. */
.pager a, .pager span, .pager button {
  /* A comfortable tap target: the old 9px padding left the controls ~34px tall,
     under the 44px a thumb needs, with several sitting a hand's-width apart. */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 14px;
  border: var(--border-w) solid var(--border); border-radius: var(--radius);
  background: var(--surface); font-size: var(--step-n1); color: var(--ink);
}
/* A button inherits none of this from the page the way a link does. */
.pager button {
  font-family: inherit; font-weight: inherit; line-height: inherit;
  cursor: pointer; -webkit-appearance: none; appearance: none;
}
.pager a:hover, .pager button:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
/* A branded ring in place of the UA default, which several browsers draw
   faintly or not at all on a bordered link. */
.pager a:focus-visible, .pager button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; text-decoration: none;
}
.pager .is-current {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-ink); font-weight: 600;
}
.pager .is-disabled { opacity: 0.45; }
/* Mid-fetch the whole pager is inert, so a second click cannot queue a page the
   reader will not end up looking at. */
.pager button[disabled] { opacity: 0.45; cursor: default; }
.pager button[disabled]:hover { border-color: var(--border); color: var(--ink); }

.empty {
  background: var(--surface); border: var(--border-w) dashed var(--border);
  border-radius: var(--radius); padding: calc(var(--space) * 5);
  text-align: center; color: var(--muted);
}

/* ---------- footer ---------- */

.foot {
  background: var(--surface); border-top: var(--border-w) solid var(--border);
  padding: calc(var(--space) * 4) 0; margin-top: calc(var(--space) * 5);
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--muted);
}
.foot__row {
  display: flex; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  align-items: baseline; padding-bottom: calc(var(--space) * 2);
  border-bottom: var(--border-w) solid var(--rule);
}
.foot__brand { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.foot__name {
  font-family: var(--font-display); font-size: var(--step-0); color: var(--ink);
  font-weight: var(--masthead-weight); letter-spacing: var(--masthead-tracking);
  text-transform: var(--masthead-transform);
}
.foot__tagline { color: var(--faint); }
/* One link. The footer is where a reader looks for About, and since the drawer
   became the phone's navigation and nothing else it is the only place a
   desktop reader can be offered it. Deliberately not a link list: the feed is
   advertised in the head of every page and the sitemap in robots.txt, and
   neither comes back. */
.foot__about {
  color: var(--ink); text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: var(--meta-weight);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
}
.foot__about:hover { color: var(--accent); text-decoration: underline; }
.foot__about:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* THE TITLE'S OWN PROFILES.

   The same 36px ringed mark the article share row uses, because it is the same
   icon at the same size and inventing a second treatment for it would make the
   footer look like a different site's footer. Declared here rather than by
   reusing .share__btn: the two controls are deliberately independent, and a
   later change to how an article shares must not silently restyle the brand's
   own links (or the reverse).

   min-height 44px on the group keeps the row's touch target honest on a phone
   even though the marks themselves are 36px. */
.foot__end { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.foot__social { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; }
.foot__social__label {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
  text-transform: var(--meta-transform); letter-spacing: var(--meta-tracking);
}
.foot__social__btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  border: var(--border-w) solid var(--rule); border-radius: 999px;
  background: var(--surface, transparent); color: var(--muted); text-decoration: none;
}
.foot__social__btn svg { width: 17px; height: 17px; fill: currentColor; }
.foot__social__btn:hover { color: var(--accent); border-color: var(--accent); }
.foot__social__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.foot__legal { padding-top: calc(var(--space) * 2); color: var(--faint); }

/* The newspaper signs off centred, like its nameplate. */
.lay-newspaper .foot { border-top: var(--rule-w) solid var(--ink); }
.lay-newspaper .foot__row { justify-content: center; text-align: center; flex-direction: column; align-items: center; }
.lay-newspaper .foot__brand { align-items: center; }
.lay-newspaper .foot__end { justify-content: center; }
.lay-newspaper .foot__legal { text-align: center; }
/* The desk keeps its footer as tight as its header. */
.lay-desk .foot { padding: calc(var(--space) * 3) 0; }

/* ---------- tablet ---------- */

@media (min-width: 600px) {
  /* The newspaper's secondary tier becomes two columns once there is room. */
  .grid { grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr)); }
  .art { padding: 0; }
  /* ...but not the wire, which has no box to pad. Same specificity as the
     rule above, so it must stay after it. */
  .art--wire { padding: 0; }
  .art__media--full { margin: 0 0 calc(var(--space) * 2.5); }
  .crumbs__list li[aria-current="page"] { max-width: 40ch; }

  /* wire: two co-equal leads, then the flow in two columns */

  /* tabloid: supporting stories sit two-up under the lead */
  .paper-sub { grid-template-columns: 1fr 1fr; }

  /* broadsheet: section blocks become a real grid */
  .desk__grid { grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr)); }
}

/* ---------- desktop ---------- */

@media (min-width: 900px) {
  /* The wire's rail becomes a real column and sticks while the main
     column scrolls; it is the section index a wire reader lives in. */

  /* The strip has room to breathe and no longer needs to scroll. */
  .nav__list { flex-wrap: wrap; overflow-x: visible; }
  .nav__link { padding: 13px 14px 11px; }
  .nav__link:first-child { padding-left: 0; }

  /* The lead story earns a wider track than the rest of the grid. */

  /* wire: the latest flow runs in two dense columns beside itself */
  .wire__flow { columns: 2; column-gap: calc(var(--space) * 5); }
  .wire__flow > li { break-inside: avoid; border-top: var(--border-w) solid var(--border); }
  .wire__flow > li:first-child { border-top: var(--border-w) solid var(--border); }

  /* The newspaper lead runs its 3:2 plate beside the headline.

     `align-items: start` and no `height: 100%`, deliberately. The media frame
     carries an aspect-ratio (3:2 here, via is-3x2), and an element with BOTH
     an aspect-ratio and height:100% derives its WIDTH from its height — so in
     a stretched grid row it grew to whatever the text column's height implied,
     1534px inside a 1090px track, and pushed the headline, kicker, standfirst
     and meta outside the card where overflow:hidden clipped them. The lead
     story on the front page had no visible headline at any desktop width.

     Sized from its track instead, the plate keeps the 3:2 print proportion
     that makes this a newspaper front, and the two columns simply top-align. */
  /* `aspect-ratio: auto` is the fix, and it must accompany height:100%.
     Stretching was always the intent here — a plate the full height of the
     headline beside it — but the frame also carries an aspect-ratio, and an
     element with BOTH derives its width from its height. Left together they
     made the plate 1534px wide inside a 1090px track. Released from the ratio,
     it takes its width from the grid track and its height from the row, and
     the image still crops through object-fit: cover.

     The ratio keeps doing its job in the stacked composition below 900px,
     which is the only place a fixed proportion was ever visible. */
  .paper-sub { grid-template-columns: repeat(4, 1fr); }

  /* broadsheet: the defining asymmetry — lead against a rule-separated aside */
}

/* ---------- wide ---------- */

@media (min-width: 1280px) {
  /* padding-inline, not the `padding: 0 x` shorthand it used to be. The
     shorthand also set padding-block to 0, and because it comes later in the
     file than .masthead__bar's own `padding: calc(var(--space) * 2) 0` it won:
     the masthead lost 32px of vertical padding at exactly 1280 and the header
     got SHORTER as the screen got wider (104.8px at 1024, 82px at 1280). The
     footer's two rows lost their 16px the same way. Nothing here ever wanted
     to change block padding; it only ever wanted the wider gutter. */
  .wrap { padding-inline: calc(var(--space) * 3); }

  /* wire gets a third column of flow: maximum stories above the fold */
  .wire__flow { columns: 3; }

  /* broadsheet opens the measure and the gutter further still */
}

/* ---------- preferences ---------- */

/* Dark mode is not defined here.
 *
 * These five generic values predate the token system. They set no ground, no
 * sunken tier, no rule, no header band and no accent, so a page using them was
 * half-dark - dark type on a still-light page. Each publication now declares
 * its own dark palette in config and src/generate/theme.js emits it, into both
 * the prefers-color-scheme block and the [data-theme="dark"] block, from the
 * same inline <style> that carries the light one. See the Appearance section
 * at the end of this file for the parts a token could not cover. */

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

@media print {
  .masthead, .nav, .foot, .pager, .sourcebox, .crumbs { display: none; }
  body { background: #fff; color: #000; }
  .art { border: none; padding: 0; max-width: none; }
}

/* ================================================================== *
 * Scores and results — the match centre
 *
 * Built to an approved reference rather than to taste. The reference is a
 * broadcast match centre: a stadium field behind the masthead and the day
 * selector, a full-bleed competition banner carrying large artwork, and a
 * four-across grid of cards that each put the two teams under their badges
 * with the score between them.
 *
 * Three things the reference could not give us, and why:
 *
 *   ARTWORK. The reference shows the competitions' own logos and a
 *   photographic stadium. A tournament's mark is a trademark and a stock
 *   photograph is a licence; neither is ours. So the atmosphere here is
 *   drawn — gradients, a floodlight bloom, pitch geometry, a crowd
 *   texture — and the competition mark is the original set in compmark.js,
 *   scaled to the weight the reference gives it. No request, no licence,
 *   nothing imitating a real badge.
 *
 *   GROUP LETTERS. The reference labels each card "Group L". The provider
 *   sends "League A - 1" and "Group Stage - 1" on 22 of 22 fixtures: the
 *   tier is real, the number is a matchday, and the group letter does not
 *   exist. So the tier renders and the number renders as the round it is.
 *
 *   TWO CONTROLS. "Go to date" and "All competitions" are functional, and
 *   the day selector beside them already navigates. They are left out
 *   rather than drawn as buttons that do nothing.
 *
 * The runtime contract is unchanged: site.js reconciles by data-match,
 * redraws [data-mrow-mid], and rewrites only mrow--<status>. The state
 * chip is drawn at the top of a card by CSS while staying inside that
 * element, so a match that kicks off mid-session restyles with no
 * re-render and no layout shift.
 * ================================================================== */

.scores, .results {
  --sc-radius: 12px;
  --sc-radius-sm: 8px;
  --sc-shadow: 0 1px 2px rgb(0 0 0 / 0.05), 0 2px 6px rgb(0 0 0 / 0.04);
  --sc-shadow-hi: 0 2px 6px rgb(0 0 0 / 0.08), 0 10px 24px rgb(0 0 0 / 0.07);
  --sc-line: color-mix(in srgb, var(--border) 85%, transparent);
  --sc-card: linear-gradient(180deg, color-mix(in srgb, var(--ink) 2%, var(--surface)), var(--surface) 58%);
  --sc-edge: inset 0 1px 0 rgb(255 255 255 / 0.55);
  --sc-plate: color-mix(in srgb, var(--ink) 4%, transparent);
  /* The stadium the masthead and the banners sit on. Two colours and a
     brightness, so one set of rules serves a night match and a day one. */
  --sc-field: #0d1220;
  --sc-field-2: #131b2e;
  --sc-beam: rgb(255 255 255 / 0.16);
  --sc-crowd: rgb(255 255 255 / 0.055);
  --sc-on-field: #fff;
  --sc-on-field-dim: rgb(255 255 255 / 0.68);
  /* The competition plate carries dark artwork in BOTH themes, so its type
     stays light in both. Tying it to --sc-on-field put near-black text on a
     near-black banner the moment the page went light. */
  --sc-on-plate: #ffffff;
  --sc-on-plate-dim: rgb(255 255 255 / 0.72);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .scores,
  :root:not([data-theme="light"]) .results {
    --sc-shadow: 0 1px 0 rgb(255 255 255 / 0.03), 0 2px 8px rgb(0 0 0 / 0.5);
    --sc-shadow-hi: 0 1px 0 rgb(255 255 255 / 0.07), 0 10px 26px rgb(0 0 0 / 0.6);
    --sc-card: linear-gradient(180deg, color-mix(in srgb, #fff 5%, var(--surface)), var(--surface) 60%);
    --sc-edge: inset 0 1px 0 rgb(255 255 255 / 0.05);
    --sc-plate: color-mix(in srgb, #fff 6%, transparent);
    --sc-field: #080b13;
    --sc-field-2: #0f1522;
  }
}
:root[data-theme="dark"] .scores,
:root[data-theme="dark"] .results {
  --sc-shadow: 0 1px 0 rgb(255 255 255 / 0.03), 0 2px 8px rgb(0 0 0 / 0.5);
  --sc-shadow-hi: 0 1px 0 rgb(255 255 255 / 0.07), 0 10px 26px rgb(0 0 0 / 0.6);
  --sc-card: linear-gradient(180deg, color-mix(in srgb, #fff 5%, var(--surface)), var(--surface) 60%);
  --sc-edge: inset 0 1px 0 rgb(255 255 255 / 0.05);
  --sc-plate: color-mix(in srgb, #fff 6%, transparent);
  --sc-field: #080b13;
  --sc-field-2: #0f1522;
}
/* On the light page the reference keeps the same stadium, lifted and
   desaturated so dark type reads on it. Same geometry, different weather. */
:root[data-theme="light"] .results,
:root[data-theme="light"] .scores { --sc-field: #dfe6f2; --sc-field-2: #eef2f8;
  --sc-beam: rgb(255 255 255 / 0.85); --sc-crowd: rgb(15 23 42 / 0.022);
  --sc-on-field: #0b1220; --sc-on-field-dim: rgb(11 18 32 / 0.62); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .results,
  :root:not([data-theme="dark"]) .scores { --sc-field: #dfe6f2; --sc-field-2: #eef2f8;
    --sc-beam: rgb(255 255 255 / 0.85); --sc-crowd: rgb(15 23 42 / 0.022);
    --sc-on-field: #0b1220; --sc-on-field-dim: rgb(11 18 32 / 0.62); }
}

/* THE STADIUM: THE SUPPLIED PHOTOGRAPH.
 *
 * Nothing here draws a stadium any more. bin/make-sports-art.mjs, which used
 * to, is gone: the artwork was supplied and is final, and this file's whole job
 * is to POSITION, SCALE, FADE and MASK it into the band it goes behind.
 *
 * public/assets/sports/ IS THE SOURCE. Those files are already cropped and
 * already have their third-party marks neutralised, and no earlier version of
 * them is kept anywhere in the tree — the cutting script and the originals it
 * read were removed once the result was signed off. They are not intermediates
 * to be regenerated: to change the artwork you replace those files. The crops,
 * the retouch rectangles and the measurements behind both are in the repository
 * history, under "Use the supplied sports artwork" and "Neutralise the
 * third-party marks in the supplied artwork".
 *
 * ONE FILE, BOTH THEMES. There is no daylight twin, so the masthead's type is
 * pinned light in both themes (--sc-on-plate, the same decision the competition
 * banners already made) instead of following the page ink into near-black on a
 * night photograph.
 *
 * HOW THE POSITION WAS CHOSEN. The picture is about 4.4:1 and the band about
 * 16:1, so `cover` scales it to the band's width and keeps roughly a quarter
 * of its height. 64% down the frame is the slice the reference's own band
 * holds: the lit stand across the width, the striking leg and the boot at two
 * thirds over. Lower loses the stand and leaves a dark strip; higher loses the
 * leg, which is the one thing in the picture a reader reads as football.
 *
 * The scrim on top is what keeps the masthead legible. The artwork is behind
 * an element with no intrinsic size, so it can never move the page.
 */
.sc-field {
  position: absolute; inset: 0; z-index: -2; pointer-events: none; overflow: hidden;
  background-image: url("sports/stadium-results-hero.webp");
  background-size: cover;
  background-position: center 64%;
  background-repeat: no-repeat;
  filter: brightness(0.84) saturate(0.96);
}
/* SUBDUED, and faded into the page on the reading side. Fixed dark rather than
   the canvas colour: the photograph is a night match in both themes, so a scrim
   that went white on the light page would bleach it rather than seat it. */
.sc-field::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgb(3 6 13 / 0.88) 0%, rgb(3 6 13 / 0.62) 26%, rgb(3 6 13 / 0.18) 50%, transparent 68%),
    linear-gradient(to top, rgb(3 6 13 / 0.70) 0%, rgb(3 6 13 / 0.10) 42%, transparent 70%),
    linear-gradient(to bottom, rgb(3 6 13 / 0.45) 0%, transparent 34%);
}

/* ---------- the results masthead ---------- */
.results { padding-block: 0 0; }
.results__more { margin-top: calc(var(--section-gap) * 1.5); }
/* Masthead and day selector share one band over the field, as the reference
   has them, and the band runs to the edge of the content column. */
.results__head {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: center; justify-content: flex-start;
  flex-wrap: wrap; gap: var(--space) calc(var(--space) * 2);
  padding: 6px calc(var(--space) * 1.8);
  margin-bottom: calc(var(--space) * 1.15);
  /* THE REFERENCE'S PROPORTION, not the picture's. Its hero band is 68px on a
     1290px page — 5.3% of the width — and a deeper one reads as a poster with a
     page under it rather than as a masthead. The picture is 4.4:1 and gets
     cropped hard to fit; that is the right way round, because the composition
     is the thing being matched and the artwork is what serves it.
       The floor here is the day selector, not the type: the strip cannot go
     below a 44px touch target, so the band is as thin as its controls allow. */
  min-height: 74px;
  border-radius: var(--sc-radius);
  box-shadow: var(--sc-shadow);
}
.results__masthead { min-width: 0; text-align: start; }
.results__h1 {
  font-family: var(--font-display); margin: 0; border: 0; padding: 0;
  color: var(--sc-on-plate); line-height: 1.02; letter-spacing: -0.02em;
  font-size: clamp(1.7rem, 1.1rem + 2vw, 2.6rem); text-align: start;
  text-shadow: 0 2px 18px rgb(0 0 0 / 0.6);
}
.lay-desk .results__h1 { border: 0; }
.results__sf {
  margin: 1px 0 0; color: var(--sc-on-plate-dim); max-width: var(--measure);
  font-size: var(--step-n1); line-height: 1.25;
  text-shadow: 0 1px 10px rgb(0 0 0 / 0.65);
}

/* ---------- the day selector ---------- */
/* On the field, so it is a control on a surface rather than a tray on the
   page: a translucent shell, hairline cells, and the chosen day filled in
   the publication's red exactly as the reference has it. */
.daystrip {
  position: relative; z-index: 1;
  display: flex; align-items: stretch; gap: 5px; margin-inline: auto;
  max-width: 32rem; padding: 4px; border-radius: 12px;
  background: rgb(255 255 255 / 0.07);
  border: 1px solid rgb(255 255 255 / 0.10);
}
/* No light-theme override. The strip now sits on the supplied night
   photograph in BOTH themes, so a white tray on the light page would be a
   white slab over a floodlit stand. Same shell, same ink, both ways. */
/* The cells SCROLL rather than shrink below a thumb: seven 44px targets do
   not fit in a 320px screen, and a cell too small to hit is worse than one
   you swipe to. The mask is what makes a part-shown cell read as "there is
   more this way" instead of as a clipped layout. */
.daystrip__list {
  list-style: none; margin: 0; padding: 0; display: flex; gap: 6px;
  overflow-x: auto; scrollbar-width: none; min-width: 0;
}
.daystrip__list::-webkit-scrollbar { display: none; }
.daystrip__i { flex: 0 0 auto; min-width: 0; }
.daystrip__step {
  flex: none; display: grid; place-items: center; min-width: 46px; min-height: 46px;
  border: 1px solid rgb(255 255 255 / 0.10); border-radius: 10px;
  color: var(--sc-on-plate); background: rgb(255 255 255 / 0.05);
  font-size: var(--step-1); line-height: 1;
}

.daystrip__step:hover { background: rgb(255 255 255 / 0.14); color: var(--sc-on-plate); text-decoration: none; }
.daystrip__step:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.daystrip__d {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; min-width: 58px; min-height: 46px; padding: 4px 10px;
  border-radius: 10px; border: 1px solid transparent;
  color: var(--sc-on-plate); text-align: center;
  transition: background 0.15s ease;
}
.daystrip__d:hover { background: rgb(255 255 255 / 0.12); text-decoration: none; }
.daystrip__d:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.daystrip__wd {
  font-family: var(--font-meta); font-size: 10px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--sc-on-plate-dim);
}
.daystrip__n {
  font-family: var(--font-meta); font-size: 19px; font-weight: 800;
  font-variant-numeric: tabular-nums; line-height: 1.05; letter-spacing: -0.01em;
}
.daystrip__d.is-on {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 40%, transparent);
}
.daystrip__d.is-on .daystrip__wd { color: var(--accent-ink); opacity: 0.9; }
.daystrip__d.is-on:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -4px; }
.daystrip__d.is-disabled, .daystrip__step.is-disabled { opacity: 0.4; cursor: default; }
.daystrip__d.is-disabled:hover { background: none; }

/* ---------- a competition, as a broadcast banner ---------- */
.cgroup { margin-bottom: calc(var(--space) * 1.15); }
.cgroup__fold { border-radius: var(--sc-radius); }
.cgroup__head {
  position: relative; isolation: isolate; overflow: hidden; cursor: pointer;
  display: flex; align-items: center; gap: calc(var(--space) * 1.1);
  padding: 6px calc(var(--space) * 1.2);
  /* THE REFERENCE'S PROPORTION AGAIN: its competition banner is 58px on a
     1290px page, 4.5% of the width. The plates are posters and do not fit;
     they are cropped to the band rather than the band opened to them. What
     keeps that readable is that the cup layer is sized in BAND HEIGHTS (see
     below), so it shrinks with the band instead of being cropped away. */
  min-height: 60px;
  border-radius: var(--sc-radius);
  box-shadow: var(--sc-shadow);
  list-style: none;
}
.cgroup__head::-webkit-details-marker { display: none; }
.cgroup__head::marker { content: ""; }
.cgroup__head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* THE BANNER ARTWORK: THE SUPPLIED PLATES, cropped and positioned. Nothing
   here draws anything. One picture per competition identity, chosen from the
   competition's own name — see competitionArt in compmark.js. Anything we have
   no plate for gets the pitch, which identifies no competition at all.
 *
 * WHY EACH PLATE IS DRAWN TWICE.
 *
 * The supplied plates are posters: about 4.5:1 for the European one and 3:1
 * for the African. The banner they go in is nearly 11:1. Scaling a poster to
 * COVER a band three times its proportions keeps about a third of its height,
 * and a third of a trophy's height is a metallic column — the shape that says
 * "cup" is exactly what the crop throws away. Measured: at cover the European
 * cup came out 2.4x the banner's height across and unrecognisable, against
 * 0.84x and perfectly legible in the approved reference.
 *
 * So each plate is laid down twice, from the one file:
 *
 *   ::before  the whole plate at cover, blurred and dropped hard. Atmosphere
 *             and the competition's colour, edge to edge, plus the scrim that
 *             keeps the name readable. Blurred, so where the big crop of the
 *             cup shows past the sharp copy it reads as bloom, not as a
 *             second cup.
 *   ::after   the plate again, sharp, scaled so the WHOLE cup fits the band's
 *             height, anchored so the cup's right edge lands at 88% across —
 *             which is where the reference puts its cup — and masked on its
 *             left so it dissolves into the atmosphere behind it.
 *
 * Every number below is measured: cup at x 66.5%-88.1% of the European crop
 * and 52.7%-88.5% of the African one, which is what sets the two positions. */
.cgroup__head::before {
  content: ""; position: absolute; inset: -26px; z-index: -2; pointer-events: none;
  background-image:
    linear-gradient(90deg, rgb(0 0 0 / 0.82) 0%, rgb(0 0 0 / 0.60) 28%, rgb(0 0 0 / 0.20) 52%, transparent 72%),
    linear-gradient(to bottom, rgb(0 0 0 / 0.32) 0%, transparent 42%, rgb(0 0 0 / 0.38) 100%),
    url("sports/banner-default.webp");
  background-size: auto, auto, cover;
  background-position: center, center, center 58%;
  background-repeat: no-repeat;
  filter: brightness(0.78) saturate(0.94);
}
/* The two identity plates: their cover copy is the ATMOSPHERE, so it goes
   further down and out of focus than the pitch, which is already banner-shaped
   and stays sharp. */
.cgroup__head[data-art="uefa"]::before,
.cgroup__head[data-art="africa"]::before {
  filter: brightness(0.54) saturate(0.86) blur(8px);
}
.cgroup__head[data-art="uefa"]::before {
  background-image:
    linear-gradient(90deg, rgb(0 0 0 / 0.82) 0%, rgb(0 0 0 / 0.60) 28%, rgb(0 0 0 / 0.20) 52%, transparent 72%),
    linear-gradient(to bottom, rgb(0 0 0 / 0.32) 0%, transparent 42%, rgb(0 0 0 / 0.38) 100%),
    url("sports/banner-uefa.webp");
}
.cgroup__head[data-art="africa"]::before {
  background-image:
    linear-gradient(90deg, rgb(0 0 0 / 0.82) 0%, rgb(0 0 0 / 0.60) 28%, rgb(0 0 0 / 0.20) 52%, transparent 72%),
    linear-gradient(to bottom, rgb(0 0 0 / 0.32) 0%, transparent 42%, rgb(0 0 0 / 0.38) 100%),
    url("sports/banner-africa.webp");
  /* Down at the foot of the plate. Higher up, the cover copy's own cup is a
     broad gold smear across the middle of the band — the sharp copy only
     covers the last third, so anything bright to the left of it shows. At the
     foot the cup is just its stem, and what fills the band is the map. */
  background-position: center, center, center 68%;
}
/* The cup itself: sharp, whole, on the right. Pulled down a little so it sits
   IN the blurred plate behind it rather than on top of it — a sharp copy at
   full strength over a dropped one reads as a pasted rectangle. */
.cgroup__head::after {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-repeat: no-repeat;
  filter: brightness(0.88) saturate(0.96);
}
.cgroup__head[data-art="uefa"]::after {
  background-image: url("sports/banner-uefa.webp");
  /* 130%: a band this thin cannot hold the whole cup and stay at the
     reference's proportion, and the reference does not hold its whole cup
     either — it crops top and bottom. So the cup is drawn 1.3 band-heights
     tall and the band takes what it takes.
       The mask stops sit ON THE IMAGE'S OWN EDGES: at auto 130% the plate is
     350px wide in a 1324px band and lands at 64.7%-91.1% across, so it fades
     in over 64-72% and out over 90-93%. Stops anywhere else leave a hard
     rectangle, which is exactly what a pasted-in panel looks like. */
  background-size: auto 130%;
  background-position: 88% 45%;
  -webkit-mask-image: linear-gradient(90deg, transparent 64%, #000 72%, #000 90%, transparent 93%);
  mask-image: linear-gradient(90deg, transparent 64%, #000 72%, #000 90%, transparent 93%);
}
.cgroup__head[data-art="africa"]::after {
  background-image: url("sports/banner-africa.webp");
  /* 160% puts this cup at 1.62 band-heights across against the reference's
     1.58, cropped top and bottom as the reference's is. Its plate lands at
     69.9%-90.4%, so the mask fades there. 5% down is the globe and the ring of
     spheres under it — the part of the cup that says which cup it is. */
  background-size: auto 160%;
  background-position: 88% 5%;
  -webkit-mask-image: linear-gradient(90deg, transparent 69%, #000 77%, #000 89%, transparent 92%);
  mask-image: linear-gradient(90deg, transparent 69%, #000 77%, #000 89%, transparent 92%);
}
/* The vector ghost that used to sit here is gone: the cup is in the artwork
   now, at the scale the reference gives it. The element stays so the markup
   does not change, and carries nothing. */
.cgroup__art { display: none; }
.cgroup__badge {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: 10px; color: var(--accent);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.16), rgb(255 255 255 / 0.06));
  border: 1px solid rgb(255 255 255 / 0.18);
  box-shadow: 0 6px 18px rgb(0 0 0 / 0.25), inset 0 1px 0 rgb(255 255 255 / 0.25);
}
.cgroup__badge .cmark { width: 23px; height: 23px; }
/* A SUPPLIED mark is the tile, not a glyph inside one. It arrives as a square
   picture already carrying its own rounded shape and its own ground, so it
   fills the tile edge to edge and the tile stops drawing a plate and a hairline
   under it — two rounded frames one inside the other is the look of an icon
   dropped into a box, and the reference does not have it.
     The tile keeps its size, its radius, its place and its spacing. What the
   radius now does is CLIP: neither supplied file has an alpha channel, so
   outside its own rounded corners one is black and the other white. Their
   corner arcs run to about 18% and 22% of the side and the tile rounds at 26%,
   so the tile's own corner takes more than either background occupies and none
   of it survives. */
.cgroup__badge .cmark--id { width: 100%; height: 100%; object-fit: cover; display: block; }
.cgroup__badge:has(.cmark--id) {
  background: none; border-color: transparent; overflow: hidden; padding: 0;
  box-shadow: 0 6px 18px rgb(0 0 0 / 0.3);
}
.cgroup__id { min-width: 0; flex: 1 1 auto; display: block; }
.cgroup__name {
  display: block; font-family: var(--font-head);
  font-size: clamp(1rem, 0.8rem + 0.55vw, 1.22rem);
  margin: 0; line-height: 1.1; letter-spacing: -0.015em;
  color: var(--sc-on-plate); font-weight: 800;
}
.cgroup__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0; margin: 1px 0 0;
  font-family: var(--font-meta); font-size: 11.5px;
  color: var(--sc-on-plate-dim);
}
.cgroup__sport { margin: 0; font-family: var(--font-meta); letter-spacing: 0.06em;
  text-transform: uppercase; font-weight: 700; color: var(--sc-on-plate-dim); }
.cgroup__where::before, .cgroup__count::before {
  content: "\00B7"; margin-inline: 8px; color: var(--sc-on-plate-dim); opacity: 0.7;
}
.cgroup__count { font-weight: 600; font-variant-numeric: tabular-nums; }
/* The collapse control the reference draws in the corner. Real: <details>. */
.cgroup__fold-mark {
  flex: none; width: 32px; height: 32px; border-radius: 8px;
  background: rgb(255 255 255 / 0.10); border: 1px solid rgb(255 255 255 / 0.16);
  display: grid; place-items: center; position: relative; z-index: 1;
}
.cgroup__fold-mark::before {
  content: ""; width: 9px; height: 9px; border-left: 2px solid var(--sc-on-plate);
  border-top: 2px solid var(--sc-on-plate); transform: rotate(45deg) translate(1px, 1px);
  transition: transform 0.18s ease;
}
.cgroup__fold:not([open]) .cgroup__fold-mark::before { transform: rotate(225deg) translate(-2px, -2px); }
.cgroup__head:hover .cgroup__fold-mark { background: rgb(255 255 255 / 0.18); }
/* No light-theme override for these two: the plate they sit on is the dark
   artwork in both themes, so the treatment that works on it is the same one. */

/* ---------- THE FIXTURE GRID ---------- */
/* Four across, as the reference has it, stepping down with the viewport. The
   card stacks its names under their badges, so four fit where two symmetric
   rows used to and a long name still has the full column to wrap into. */
.cgroup__list {
  list-style: none; margin: calc(var(--space) * 0.75) 0 0; padding: 0;
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}
@media (min-width: 40rem) { .cgroup__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .cgroup__list { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 82rem) { .cgroup__list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ---------- one fixture, as a card ---------- */
.mrow {
  position: relative; isolation: isolate; min-width: 0;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: start;
  column-gap: 8px; row-gap: 0;
  padding: 34px 13px 12px;
  background: var(--sc-card);
  border: var(--border-w) solid var(--sc-line);
  border-radius: var(--sc-radius);
  box-shadow: var(--sc-shadow), var(--sc-edge);
  transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.mrow:hover { box-shadow: var(--sc-shadow-hi); border-color: var(--border); }
@media (prefers-reduced-motion: no-preference) {
  .mrow:hover { transform: translateY(-2px); }
}
/* THE STAGE, top right. Real provider data — see stageCell in scores.js. */
.mrow__stage {
  position: absolute; top: 11px; inset-inline-end: 12px; z-index: 1;
  font-family: var(--font-meta); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.02em; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 58%;
}
/* A side is a badge with its club under it, centred, as the reference has it.
   Both sides are identical, so the away side no longer mirrors. */
.mrow__side {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  min-width: 0; text-align: center;
}
.mrow__side--away { flex-direction: column-reverse; justify-content: flex-end; }
.mrow__team {
  font-size: 11.5px; font-weight: 700; color: var(--ink); line-height: 1.22;
  letter-spacing: -0.012em; white-space: normal; overflow-wrap: break-word;
  hyphens: auto; max-width: 100%;
}
/* The badge. The ring is not decoration: half of these are national flags,
   and England, Poland and Switzerland are a flat field to their own edge, so
   without it England is a red cross floating in a light page. */
.mrow__mark {
  width: 30px; height: 30px; flex: none; object-fit: contain;
  background: var(--sunken); border: 1px solid var(--sc-line);
  border-radius: 5px; box-sizing: border-box; padding: 1px;
}
.mrow__mark--mono {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--surface-3, var(--sunken));
  border: var(--rule-w) solid var(--rule);
  font-family: var(--font-meta); font-size: 12px; font-weight: 700;
  letter-spacing: 0; color: var(--muted); text-transform: uppercase;
}
/* A finished match states its winner in the type. */
.mrow.is-home .mrow__side--home .mrow__team,
.mrow.is-away .mrow__side--away .mrow__team { font-weight: 800; color: var(--ink); }

/* THE CENTRE. A fixed floor so the score column lines up down a competition
   and a VS becoming 2-1 on a poll moves nothing around it. */
.mrow__mid {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 3px; flex: none; min-width: 4rem; padding-top: 5px;
}
.mrow__score {
  font-family: var(--font-meta); font-weight: 800; font-size: 21px;
  font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap;
  line-height: 1.1; letter-spacing: -0.02em;
}
.mrow__dash { padding-inline: 5px; color: var(--faint); }
/* VS: the marker for a fixture that has not kicked off. Deliberately not
   score-sized — the moment a real score replaces it the number should win. */
.mrow__score--none {
  color: var(--muted); font-weight: 800; font-size: 13px; letter-spacing: 0.06em;
}
.mrow__pens {
  font-family: var(--font-meta); font-size: 10px; font-weight: 700;
  letter-spacing: var(--meta-tracking); color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 1.3;
}

/* THE STATE CHIP, LIFTED TO THE TOP LEFT.
   It stays inside [data-mrow-mid] — the element site.js redraws — and is
   placed here by CSS, so a clock that starts ticking mid-session keeps
   ticking and nothing reflows when it does. */
.mrow__state {
  position: absolute; top: 9px; inset-inline-start: 12px; z-index: 1;
  font-family: var(--font-meta); font-size: 11px; font-weight: 700;
  letter-spacing: 0.02em; white-space: nowrap; line-height: 1;
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--ink); background: var(--sc-plate);
  border: var(--border-w) solid var(--sc-line);
  border-radius: 7px; padding: 5px 9px;
  font-variant-numeric: tabular-nums;
}
.mrow__state--off { text-decoration: line-through; color: var(--accent); border-color: transparent; background: none; }
/* LIVE: a filled red badge and the minute beside it, which is the reference's
   strongest state and the one a reader must find without reading. */
.mrow__state--live { background: none; border-color: transparent; padding: 3px 0; gap: 7px; }
.mrow__live {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--accent); color: var(--accent-ink);
  border-radius: 6px; padding: 4px 7px; font-size: 10px; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 45%, transparent);
}
.mrow__min { font-size: 11px; font-weight: 800; color: var(--accent); }
.mrow__dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
@media (prefers-reduced-motion: no-preference) {
  .mrow__state--live .mrow__dot { animation: mrow-pulse 1.6s ease-in-out infinite; }
}
@keyframes mrow-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* ---------- match states ----------
 * Driven entirely by mrow--<status>, the ONE class site.js rewrites on a
 * poll, so none of this needs a re-render and none of it changes the box. */
.mrow--live {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--sc-line));
  background:
    radial-gradient(120% 90% at 0% 0%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 60%),
    var(--sc-card);
  box-shadow: var(--sc-shadow), inset 3px 0 0 var(--accent);
}
.mrow--live .mrow__score { color: var(--ink); font-size: 23px; }
/* FINISHED keeps the score prominent and the chip neutral: the result is the
   news, "FT" is only the reason it stopped changing. */
.mrow--finished .mrow__score { font-size: 23px; }
.mrow--finished .mrow__state {
  font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
}
/* POSTPONED and CANCELLED are neither upcoming nor a result. */
.mrow--postponed, .mrow--cancelled { background: var(--sunken); }
.mrow--postponed .mrow__team, .mrow--cancelled .mrow__team { color: var(--muted); }

/* ---------- the rail on a front ---------- */
/* The compact sibling of the card above: same badge ring, same VS and score
   hierarchy, same LIVE badge, same surface language, at rail size. */
.scores { background: var(--sunken); border-block: var(--rule-w) solid var(--rule); }
.scores__in { padding-block: calc(var(--space) * 0.9); }
/* The band's head.
   A phone cannot fit a label, a scrolling chip row, the odds chip and the
   all-results link on one line, and four of them stacked is 150px of chrome
   above the first fixture. So it is a two-row grid there — label and link on
   the first, chips on the second, odds under them — and one row from 48rem up,
   where it all fits. */
.scores__top {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; gap: 8px var(--space); margin-bottom: calc(var(--space) * 0.75);
}
.scores__top .schips { grid-column: 1 / -1; grid-row: 2; }
.scores__top [data-odds] { grid-column: 1 / -1; }
@media (min-width: 48rem) {
  .scores__top { grid-template-columns: auto minmax(0, 1fr) auto; }
  .scores__top .schips { grid-column: 2; grid-row: 1; }
  /* THE ODDS CHIP IS A SIBLING OF THE HEAD NOW, NOT A CHILD OF IT.
     The mobile reference puts it UNDER the fixtures — a secondary row at the
     foot of the module, not a third thing in the header above them — which is
     also the order a reader meets them in. The markup follows that, and the
     desktop band puts it back on the header row from outside, where it has
     always sat. */
  .scores__in {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: center; column-gap: var(--space);
  }
  .scores__in > .scores__top { grid-column: 1; grid-row: 1; }
  .scores__in > [data-odds] { grid-column: 2; grid-row: 1; justify-self: end; }
  .scores__in > .scores__rail { grid-column: 1 / -1; grid-row: 2; }
}
.scores__label {
  margin: 0; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-meta); font-size: 11px;
  font-weight: var(--meta-weight); letter-spacing: 0.1em;
  text-transform: var(--meta-transform); color: var(--ink);
}
.scores__label::before {
  content: ""; width: 3px; height: 13px; border-radius: 2px;
  background: var(--accent); flex: none;
}
/* The live dot. Rendered only when something really is in play — see
   scoresStrip — so it is never a permanent red light over a row of fixtures
   that all kick off this evening. It pulses only where motion is welcome. */
.scores__dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex: none;
}
@media (prefers-reduced-motion: no-preference) {
  .scores__dot { animation: sc-pulse 1.8s ease-in-out infinite; }
  @keyframes sc-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
}

/* ---- the competition filter chips ----

   The reference's row of sport chips with a count in each. These filter by
   competition instead, for the reason written beside compChipsHtml: one sport
   has a provider behind it, so six of those seven numbers would be invented.

   Every chip is a LINK to that competition's own section on the Results page,
   so the row works before any script loads. site.js upgrades it in place to a
   filter over the rail; without site.js it is still a working destination. */
.schips { min-width: 0; flex: 1 1 auto; }
.schips__list {
  list-style: none; margin: 0; padding: 0; display: flex; gap: 6px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.schips__list::-webkit-scrollbar { display: none; }
.schip {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 4px 11px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); color: var(--muted);
  font-family: var(--font-meta); font-size: 11px; font-weight: 700;
  letter-spacing: 0.03em; white-space: nowrap;
}
.schip:hover, .schip:focus-visible { color: var(--ink); border-color: var(--rule); text-decoration: none; }
.schip.is-on {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.schip__n { font-variant-numeric: tabular-nums; opacity: 0.68; }
.schip.is-on .schip__n { opacity: 0.85; }
.scores__all {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-meta); font-size: var(--step-n1);
  font-weight: var(--meta-weight); white-space: nowrap; color: var(--ink);
  padding: 4px 2px; border-radius: var(--sc-radius-sm);
}
.scores__all::after {
  content: "\2192"; color: var(--accent); font-size: 1.05em;
  transition: transform 0.18s ease;
}
.scores__all:hover { text-decoration: none; color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .scores__all:hover::after { transform: translateX(2px); }
}
.scores__all:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; text-decoration: none; }
.scores__more {
  display: inline-block; background: var(--accent); color: var(--accent-ink);
  border-radius: 999px; padding: 1px 8px; font-size: 11px; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.scores__rail:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scores__rail {
  list-style: none; margin: 0; padding: 2px 0 4px;
  display: flex; gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
@media (max-width: 47.99rem) {
  .scores__rail {
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    scroll-padding-inline-start: var(--gutter);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 52px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 52px), transparent);
  }
}
.mcard {
  position: relative; isolation: isolate;
  scroll-snap-align: start; flex: 0 0 min(66vw, 240px); min-width: 0;
  /* home | score | away, the same three columns the results card uses. The
     markup nests the two sides in a wrapper and keeps the middle outside it —
     that shape belongs to site.js, which redraws the middle — so the wrapper
     goes display:contents and the three real children lay out in this grid.
     It is a presentational div with no role, so contents costs no semantics. */
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: start;
  column-gap: 6px; padding: 32px 12px 12px;
  background: var(--sc-card); border: var(--border-w) solid var(--sc-line);
  border-radius: var(--sc-radius); box-shadow: var(--sc-shadow), var(--sc-edge);
  transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
@media (min-width: 48rem) { .mcard { flex-basis: 15.5rem; } }
.mcard:hover { box-shadow: var(--sc-shadow-hi); border-color: var(--border); }
@media (prefers-reduced-motion: no-preference) {
  .mcard:hover { transform: translateY(-2px); }
}
.mcard:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
/* A fixture card with a Match Centre page carries one link laid over the whole
   card (scores.js, matchLink): transparent, above the card's own layers, the
   card's corners. Nothing about the card's appearance changes - the whole card
   simply becomes the target, with the card's own hover. Keyboard focus draws
   the ring the rail card already draws on :focus-within, on the other cards
   too; the rail card keeps its own so it is not drawn twice. */
.mlink { position: absolute; inset: 0; z-index: 2; border-radius: inherit; }
.mlink:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mcard > .mlink:focus-visible { outline: none; }
.mmrow.is-linked { position: relative; }
.mcard__comp {
  position: absolute; top: 10px; inset-inline-start: 12px; inset-inline-end: 12px;
  padding-inline-end: 74px; margin: 0;
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-meta); font-size: 9.5px; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); min-width: 0;
}
.mcard__comp .cmark { width: 13px; height: 13px; color: var(--accent); flex: none; }
.mcard__comp > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mcard__teams { display: contents; }
.mcard__side--home { grid-column: 1; }
.mcard__side--away { grid-column: 3; }
.mcard__side { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; text-align: center; }
/* The rail card renders the badge first on BOTH sides — unlike the results
   row, which mirrors its away side around the score — so nothing is reversed
   here. Reversing it put every away club's name above its badge. */
.mcard .mrow__mark { width: 26px; height: 26px; border-radius: 5px; }
.mcard .mrow__mark--mono { font-size: 9px; }
.mcard__team {
  font-size: 12px; font-weight: 700; color: var(--ink); line-height: 1.2;
  overflow-wrap: break-word; hyphens: auto; letter-spacing: -0.005em;
}
.mcard.is-home .mcard__side--away .mcard__team,
.mcard.is-away .mcard__side--home .mcard__team { font-weight: 500; color: var(--muted); }
/* The rail card's middle sits between the two sides, like the results card. */
.mcard__mid {
  grid-column: 2; grid-row: 1; margin: 0; padding-top: 5px;
  display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 3.4rem;
}
.mcard__mid .mrow__score { font-size: 18px; }
.mcard__mid .mrow__score--none { font-size: 12px; }
.mcard .mrow__state { top: 9px; inset-inline-start: auto; inset-inline-end: 11px; font-size: 10px; padding: 4px 7px; }
.mcard .mrow__live { font-size: 9px; padding: 3px 6px; }
.mcard .mrow__min { font-size: 10px; }
.mcard.mrow--live { box-shadow: var(--sc-shadow), inset 3px 0 0 var(--accent); }

/* The flag beside a competition name, where a device draws one. */
.cflag { font-size: 1.05em; line-height: 1; flex: none; }
/* The competition mark: drawn in compmark.js, in currentColor. */
.cmark { width: 1em; height: 1em; display: block; flex: none; }

/* The honest empty state. */
.scores__empty {
  display: grid; place-items: center; gap: var(--space);
  border: var(--border-w) dashed var(--border); border-radius: var(--sc-radius);
  padding: calc(var(--space) * 6) calc(var(--space) * 3); text-align: center;
  background: var(--sunken);
}
.scores__emptyT { margin: 0; font-weight: 700; color: var(--ink); font-size: var(--step-1); }
.scores__emptyD { margin: var(--space) auto 0; max-width: 52ch; color: var(--muted); font-size: var(--step-n1); }

/* ---------- narrow ---------- */
@media (max-width: 61.99rem) {
  /* A phone cannot hold the desktop's proportion — the day selector alone is
     54px and its 44px targets are not negotiable — so the band is as thin as
     the controls inside it, and no thinner. */
  .results__head { padding: 11px calc(var(--space) * 1.1); gap: 9px; min-height: 0; }
  /* The artwork crops toward the lit stand rather than squeezing the desktop
     composition into a phone. The player sits at the right of a 10:1 picture
     and simply leaves the frame, which is the right answer for the space. */
  /* The picture is 4.4:1 and a phone's band is nearer 2:1, so `cover` keeps
     its full height and crops the sides; 78% across is the crop that keeps the
     boot and the ball rather than the empty half of the bowl. */
  .sc-field { background-position: 78% 50%; background-size: cover; }
  /* On a phone the competition's name and its cup are competing for the same
     two hundred pixels, so the cup is pushed to the last third and the
     atmosphere behind it is dropped further. Same layers as the desktop, moved
     — no different picture, no different crop of it. */
  .cgroup__head[data-art="uefa"]::after,
  .cgroup__head[data-art="africa"]::after {
    background-position: 99% center;
    -webkit-mask-image: linear-gradient(90deg, transparent 52%, #000 64%, #000 97%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 52%, #000 64%, #000 97%, transparent 100%);
  }
  .cgroup__head::before {
    background-image:
      linear-gradient(90deg, rgb(0 0 0 / 0.88) 0%, rgb(0 0 0 / 0.72) 40%, rgb(0 0 0 / 0.26) 62%, transparent 80%),
      linear-gradient(to bottom, rgb(0 0 0 / 0.34) 0%, transparent 42%, rgb(0 0 0 / 0.40) 100%),
      var(--cgroup-art, url("sports/banner-default.webp"));
  }
  .cgroup__head[data-art="uefa"]::before { --cgroup-art: url("sports/banner-uefa.webp"); }
  .cgroup__head[data-art="africa"]::before { --cgroup-art: url("sports/banner-africa.webp"); }
  /* Five days and two steps have to FIT, not scroll: a strip whose last day is
     sliced in half reads as a broken layout, not as something to swipe. So the
     cells shrink to the width available and the auto margin comes off. */
  .daystrip { width: 100%; max-width: none; margin-inline: 0; }
  .daystrip__list {
    flex: 1 1 auto; gap: 4px;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
  }
  .daystrip__i { flex: 1 1 auto; min-width: 2.9rem; }
  .daystrip__d { min-width: 2.9rem; width: 100%; padding: 6px 4px; }
}
@media (max-width: 47.99rem) {
  .cgroup__head { padding: 9px 12px; min-height: 62px; gap: 11px; }
  .cgroup__badge { width: 36px; height: 36px; border-radius: 10px; }
  .cgroup__badge .cmark { width: 23px; height: 23px; }
/* A SUPPLIED mark is the tile, not a glyph inside one. It arrives as a square
   picture already carrying its own rounded shape and its own ground, so it
   fills the tile edge to edge and the tile stops drawing a plate and a hairline
   under it — two rounded frames one inside the other is the look of an icon
   dropped into a box, and the reference does not have it.
     The tile keeps its size, its radius, its place and its spacing. What the
   radius now does is CLIP: neither supplied file has an alpha channel, so
   outside its own rounded corners one is black and the other white. Their
   corner arcs run to about 18% and 22% of the side and the tile rounds at 26%,
   so the tile's own corner takes more than either background occupies and none
   of it survives. */
.cgroup__badge .cmark--id { width: 100%; height: 100%; object-fit: cover; display: block; }
.cgroup__badge:has(.cmark--id) {
  background: none; border-color: transparent; overflow: hidden; padding: 0;
  box-shadow: 0 6px 18px rgb(0 0 0 / 0.3);
}
  /* The artwork narrows and crops rather than crowding the name. */
  .cgroup__art { width: clamp(120px, 34%, 190px); opacity: 0.42; }
  .cgroup__fold-mark { width: 30px; height: 30px; }
  .mrow { padding: 40px 12px 14px; }
  .mrow__mark { width: 30px; height: 30px; }
  .mrow__team { font-size: 12.5px; }
}
@media (max-width: 30rem) {
  .daystrip { padding: 4px; gap: 4px; }
  .daystrip__d { padding: 6px 4px; }
  .daystrip__n { font-size: 18px; }
  .daystrip__wd { font-size: 9px; letter-spacing: 0.06em; }
  .results__h1 { font-size: 2rem; }
}
/* ================================================================== *
 * The front
 *
 * One architecture for all three publications: a lead against a rail, a
 * four-across grid, then the day's feed beside the publication's own
 * module. The reference sets this composition and it is what a reader of
 * a news portal expects; what still separates the three sites is the
 * band proportion, the crop of a thumbnail, whether a row carries a
 * clock, and every colour and face in the token block.
 * ================================================================== */

.front { padding-top: var(--section-gap); }
/* The scores band belongs to the masthead, not to the news. It sits flush
   under the navigation - main's own top padding is cancelled above it - and
   the front's top space starts underneath it, so the lead story follows the
   band directly instead of both floating in the middle of a gap. */
.front:has(> .scores:first-child) { padding-top: 0; }
.front > .scores:first-child {
  margin-top: calc(var(--space) * -3);
  margin-bottom: calc(var(--section-gap) * 0.45);
}
@media (min-width: 62rem) {
  .front > .scores:first-child { margin-bottom: calc(var(--section-gap) * 1.15); }
}
@media (min-width: 62rem) {
  /* More air between bands than inside them, so the page reads as three
     deliberate blocks rather than one long column of stuff. */
  .front { padding-top: calc(var(--section-gap) * 1.15); }
  .fblock { margin-bottom: calc(var(--section-gap) * 1.5); }
  .band { margin-bottom: calc(var(--section-gap) * 1.5); }
  .band__head { margin-bottom: calc(var(--space) * 2.5); }
  .band__name { font-size: var(--step-3); }
}

.fblock { display: grid; gap: var(--shell-gap); margin-bottom: var(--section-gap); }
.fblock__lead, .fblock__side, .fblock__third { min-width: 0; }

@media (min-width: 62rem) {
  /* --front-cols is one declared number per publication (leadShare), so the
     stylesheet does no per-publication arithmetic. */
  .fblock { grid-template-columns: var(--front-cols); }
  /* The desk's lead block is three columns, as the reference draws it: hero,
     Top Stories, and the cross-sport column. At the narrow end of desktop
     three columns would leave the hero too small to lead, so the third drops
     under the other two until there is room for all of it. */
  .fblock--three { grid-template-columns: var(--front-cols); }
  .fblock--three .fblock__third { grid-column: 1 / -1; }
}
@media (min-width: 80rem) {
  .fblock--three { grid-template-columns: minmax(0, 2.1fr) minmax(250px, 1fr) minmax(250px, 1fr); }
  .fblock--three .fblock__third { grid-column: auto; }
}

/* ---------- the dominant story ----------
   A large picture with the type in a panel BENEATH it.

   The two used to share one grid cell: the body sat at the foot of the
   picture under a scrim run to near-solid black, so the headline could clear
   AA against whatever the artwork underneath happened to be. That held only
   while the type was short. On a 390px screen the plate is ~219px tall and a
   five-line headline with a standfirst is ~450px, so the body — scrim and all
   — grew past the top of the picture and the photograph was entirely covered:
   measured at 100% on all three publications at 320, 375, 390 and 430px, and
   94-100% at 1280 and 1440 once the headline ran long.

   A news front's first job is to show the photograph. So the picture and the
   words no longer compete for the same pixels. The plate keeps its dark
   ground, its accent kicker and its display headline — the hierarchy is
   exactly what it was — but the body is now a panel under the image and may
   grow to any length without taking a single pixel off the picture. */
.hero {
  /* Two rows, picture then words. Explicit, so neither child needs to be
     placed and a third element could not land on top of the image by
     accident. */
  display: grid; grid-template-rows: auto auto;
  margin: 0;
  /* NO PANEL. The words used to sit in a solid near-black block under the
     picture, which on a 390px phone was 240px of ink for four lines of type
     and pushed the second story off the screen entirely. A lead does not need
     a slab behind it to read as the lead - it has the largest picture and the
     largest type on the page, and those are the two things that say so.
     Without the panel the headline is ordinary page ink, which is also what
     makes it correct in dark mode instead of white-on-black inside
     white-on-black. */
  background: transparent;
}
/* The frame keeps the rounding the plate used to carry. */
.hero__media { overflow: hidden; border-radius: var(--radius); }
.hero__media {
  aspect-ratio: var(--hero-ratio); width: 100%; background: var(--sunken);
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; }
/* A light tonal wash, and nothing more.
   While the headline sat on the picture this ran to 0.42 at the top edge so
   the type had something to sit against. No type sits here now, so that much
   ink only makes the photograph harder to see — which is the fault this block
   exists to fix. What is left seats the plate as one object on a publication
   whose generated artwork is near-white at the top, and is light enough that
   the picture reads as a picture. */
/* The wash is gone with the panel it was seating. No type sits on this
   picture, so any ink laid over it is a photograph made worse for nothing. */
/* Crop toward the lower two thirds, where every one of the three drawing
   systems puts its marks. The top third is where they all leave air. */
.hero__media img { object-position: center 64%; }
.compact__media img, .card__media img, .feedrow__media img { object-position: center 62%; }
/* The broadsheet's drawing puts its ink panel down the left edge, so a centred
   crop of it is mostly the pale half. Cropping left gives a thumbnail with
   something in it. */
.lay-newspaper .compact__media img,
.lay-newspaper .feedrow__media img { object-position: 26% 58%; }

/* ---------- the shape of the photograph ----------

   Everything above this point frames a picture the same way whatever it is: a
   box wider than it is tall, filled with object-fit: cover, anchored where the
   DRAWN artwork puts its marks. That is right for the drawing, which is
   authored at 16:9 in a 1600x900 user space and composed low, and it is the
   whole of the reported fault for a photograph, which is not.

   Measured on production: of 146 published photographs shown with cover, 26
   are taller than they are wide and 8 are square. In a 1.85:1 hero a 1048x2384
   picture shows 29% of its own height, a 1778x2561 one 38% — a horizontal band
   through the middle of a standing figure — and the anchor then put that band
   at 64%, which is below the face. Sixteen of them show under 60% of the file
   in the hero frame and seven under 45%.

   Two changes, and neither touches a stored file. Nothing is re-encoded, no
   derivative is made and no photograph is replaced; the same bytes are shown
   differently.

   1. The anchor follows the shape. The taller a picture is relative to its
      frame, the higher the visible band has to sit to keep the subject in it,
      so a portrait is anchored at 30% and a 16:9 photograph — which has almost
      nothing to lose — near the middle. The drawing keeps 64% and 26%/58%,
      because that is still where it is drawn: those rules are above and this
      block never applies to it.

   2. And it rises again with the frame. The same portrait keeps three
      quarters of itself in a 4:3 thumbnail and two fifths of itself in a
      1.85:1 lead plate, so the band that holds a face is not in the same place
      in both. The lead frame therefore anchors a tall picture higher than a
      thumbnail does.

   A photograph whose file cannot be read carries no shape class, none of this
   applies to it, and it is shown exactly as it was. */

.hero__media.is-photo img,
.card__media.is-photo img,
.compact__media.is-photo img,
.feedrow__media.is-photo img,
.art__media.is-photo img { object-position: center 42%; }

.is-photo.is-wide img      { object-position: center 45%; }
.is-photo.is-landscape img { object-position: center 40%; }
.is-photo.is-square img    { object-position: center 36%; }
.is-photo.is-portrait img  { object-position: center 30%; }

/* The lead plate is the widest frame on the page and keeps the least of a tall
   picture: two fifths of a 4:5 portrait, a third of a 2:3 one. A band that
   narrow has to sit high or it is a photograph of a chest. */
.hero__media.is-photo.is-square img   { object-position: center 28%; }
.hero__media.is-photo.is-portrait img { object-position: center 20%; }

/* ---------- the lead frame ----------

   ONE frame, and the picture does not get a say in it.

   Two attempts before this one let the photograph decide. The first made the
   frame the picture's own shape, so a 1898x2372 lead ran 390x487 on a phone
   and pushed its own headline off the screen. The second bounded it, but a
   portrait still got a taller box than a landscape, so the height of the whole
   card moved with whatever picture the day's lead story happened to carry.

   The frame is the publication's own ratio again - 1.85, 1.50, 1.78 - at every
   width and for every picture, exactly as it was designed. The card is the
   same height whatever is in it.

   What a tall picture gets instead is the crop anchor below, and where even
   that cannot hold the subject, a different photograph. A frame is not the
   place to fix a picture that does not fit it.

   A picture shown whole - which is only ever a photograph whose licence
   forbids cropping - sits on the frame's own canvas, flat and quiet. The
   blurred copy of the photograph that used to fill that space read as a grey
   panel at thumbnail size and as a pair of oversized side panels on a lead
   plate, and a background is not the place to put an image at all. */

/* The article page is the one place with no neighbour to keep in line — no
   grid row whose cards must start their headlines level, no band whose rhythm
   a taller picture would break — and it is where a reader came to look at the
   photograph. So here the picture is simply its own shape.

   A landscape or 16:9 photograph fills the measure and keeps its real height
   instead of being cropped to 16:9; a portrait or a square is bounded by the
   screen rather than by a ratio, and centred, so the story is still on it. The
   width and height attributes are the file's own now, so this reserves the
   right space before a byte of the image arrives. */
.art__media.is-photo.is-wide img,
.art__media.is-photo.is-landscape img {
  width: 100%; height: auto; aspect-ratio: auto; object-fit: contain;
  display: block;
}
.art__media.is-photo.is-portrait img,
.art__media.is-photo.is-square img {
  width: auto; height: auto; max-width: 100%; max-height: 62vh;
  aspect-ratio: auto; object-fit: contain;
  display: block; margin-inline: auto;
}
/* The broadsheet's lead plate is a surface, and a picture narrower than the
   column would otherwise leave the page showing through it. */
.art__media--full.is-photo.is-portrait,
.art__media--full.is-photo.is-square { background: var(--sunken); }
.hero__body {
  display: flex; flex-direction: column; gap: 6px;
  /* A grid item is min-width:auto by default, so an unbreakable token in a
     headline could widen the whole column and push the page sideways. */
  min-width: 0;
  /* Aligned to the page gutter rather than inset inside a panel: the lead's
     headline now starts on the same vertical line as every other headline on
     the front, which is what makes a column of stories read as a column. */
  padding: calc(var(--space) * 1.5) 0 0;
  color: var(--ink);
}
.hero__cat {
  align-self: flex-start; display: inline-flex; align-items: center; min-height: 26px;
  background: var(--accent); color: var(--accent-ink);
  padding: 3px 10px; font-family: var(--font-meta); font-size: 11px;
  font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}
.hero__cat:hover { text-decoration: none; filter: brightness(1.12); }
.hero__title {
  margin: 0; font-family: var(--font-display); font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  /* 1.06 is a display line height, set for one or two lines. A phone headline
     is three or four, and at that length the lines closed up into a block.
     Loosened here and restored to the display value once the headline is
     short enough to need it. */
  line-height: 1.14;
  /* CAPPED, not rescaled. Each publication keeps its own fluid scale; this
     stops the fastest of them reaching 38px on a 390px screen, where the
     headline alone ran to five lines. The cap sits above the card headline
     below it, so the lead is still plainly the lead. */
  font-size: min(var(--step-3), 28px); text-wrap: balance;
  /* A headline is generated copy: it can carry a URL or a hyphenless compound
     no soft-wrap opportunity would break. Breaking it inside the plate is the
     lesser of the two evils; the other is a horizontal scrollbar on the whole
     front page. */
  overflow-wrap: anywhere;
}
/* A scoreline is one word. A hyphen is a break opportunity in CSS, so
   "Australia 1-0 up" broke after the hyphen and left a lone 0 on the next
   line. The text is unchanged - only the digits are wrapped. */
.nbr { white-space: nowrap; }
.hero__title a { color: inherit; }
.hero__title a:hover { color: inherit; text-decoration: underline; }
/* The standfirst is a trail, not the story.
   The renderer already truncates it to 200 characters, which is five or six
   lines at 320px — enough to push the headline it belongs to off the fold on
   the smallest phone we support. Three lines is the trail; the article page
   carries the whole thing and is one tap away. */
.hero__sf {
  margin: 0; color: var(--muted); font-size: var(--step-n1); max-width: 54ch;
  display: -webkit-box; -webkit-box-orient: vertical;
  /* Two lines on a phone, three once there is room. The trail exists to say
     what the story is about; the article page carries the whole thing. */
  -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
  overflow-wrap: anywhere;
}
.hero__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space);
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
}

@media (min-width: 48rem) {
  .hero__body { padding: calc(var(--space) * 2) 0 0; }
  .hero__title { font-size: min(var(--step-4), 36px); line-height: 1.1; }
  .hero__sf { font-size: var(--step-0); -webkit-line-clamp: 3; line-clamp: 3; }
}
@media (min-width: 62rem) {
  /* The lead now takes everything the rail does not, so at 1440px the plate is
     ~950px rather than ~700px and the headline can hold it. Capped so the
     broadsheet's fast scale cannot reach 63px, and every cap here stays above
     the article-page caps (34/44/38) — a story never shouts louder on its own
     page than on the front it was promoted from. */
  .hero__body { padding: calc(var(--space) * 2.5) 0 0; }
  .hero__title { font-size: min(var(--step-5), 46px); line-height: var(--lh-display); }
  .hero__sf { max-width: 62ch; }
}

/* ---------- the front, on a phone ----------
   A front page is not a desktop front made narrower. On a 390px screen the
   reader gets roughly one and a half screens before deciding, so the lead has
   to read as the lead and the stories under it have to be scannable in the
   same glance. What that means here:

   - the picture, the kicker and the headline are ONE block, set tight, not
     three elements separated by desktop air;
   - the headline is capped lower than the desktop cap, because a 99-character
     headline at 28px is five lines and at 26px is four;
   - the lead ends with a hairline, and the stories under it are a ruled list
     rather than a second, smaller set of cards.

   Every size here is a phone-only override. Nothing above 48rem moves. */
@media (max-width: 47.99rem) {
  /* The band above — scores on Sport Daily Mail, the navigation on the other
     two — should hand straight over to the news. */
  .front { padding-top: calc(var(--section-gap) * 0.45); }
  .fblock { gap: calc(var(--space) * 1.6); }

  .hero__body { padding: calc(var(--space) * 0.9) 0 0; gap: 5px; }
  .hero__cat { min-height: 22px; padding: 2px 8px; font-size: 10px; }
  .hero__title { font-size: min(var(--step-3), 26px); line-height: 1.12; }
  .hero__sf { line-height: 1.45; }
  .hero__meta { gap: calc(var(--space) * 0.75); font-size: 12px; }

  /* The lead is finished. What follows is a list, and it says so. */
  .fblock__side { border-top: 2px solid var(--ink); padding-top: calc(var(--space) * 0.8); }
  .sidelist { gap: calc(var(--stack-gap) * 0.5); }
  .sidelist > li { padding-bottom: calc(var(--stack-gap) * 0.5); }
  /* A 76px thumbnail against a 16px headline is about 1:3 - enough picture to
     identify the story, enough column for the headline to take two lines
     rather than four. The same proportion is used for the grid band below, so
     a reader meets one kind of row on the way down the page. */
  .sidelist .compact { --thumb: 76px; gap: calc(var(--space) * 0.85); padding: 0; }
  .sidelist .compact__body { gap: 3px; }
  .sidelist .compact__title {
    font-size: 16px; line-height: 1.25;
    /* Two lines here, and the third is on the story's own page. A four-line
       headline in a secondary row competes with the lead. */
    display: -webkit-box; -webkit-box-orient: vertical;
    -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden;
  }
  .sidelist .compact__cat { font-size: 10px; }
  .sidelist .compact__meta { font-size: 11px; }
  /* The grid band's rows are the rail's rows. */
  .sgrid > .card + .card { grid-template-columns: 76px 1fr; gap: calc(var(--space) * 0.85); }
}

/* Dayli Mail Today sets its hero headline in the nameplate serif, which is
   the whole of its argument for being a newspaper rather than a portal. */
.lay-newspaper .hero { border-radius: 0; }
.lay-newspaper .hero__cat { border-radius: 0; }
.lay-desk .hero { border-radius: 0; }

/* ---- the desk's lead card ----

   ONE CARD, ONE SHAPE, WHATEVER THE PHOTOGRAPH IS. The frame declares its own
   aspect ratio and the picture is cropped to fill it, so a portrait lead and a
   landscape lead produce the same card. Without that a portrait came through at
   its own proportions — 390px wide inside a 600px column on the desktop, and
   nearly a whole screen tall on a phone — which is what the live capture showed
   on both.

   The type sits ON the picture. The block above explains why it was taken off:
   the body and the picture shared one grid cell, the body is in flow, it grows
   with the copy, and past the height of the plate the photograph was gone —
   100% covered at 320-430px, 94-100% at 1280-1440.

   THAT FINDING STANDS, and three things answer it rather than one. The body is
   out of flow, so it cannot push the plate around at all. The plate's height is
   set by its ratio rather than by the image, so it cannot be short. And the
   body is capped and its lines are clamped, so a long headline shortens instead
   of climbing. Re-measured on the pathological case in both orientations; see
   test/hero-layout.test.mjs. */
.lay-desk .hero--overlay { position: relative; display: block; }
/* THE PHONE'S PLATE IS REFERENCE B'S, AND REFERENCE B DISAGREES WITH THE
   MOCKUP BEFORE IT — which is worth stating plainly, because this plate has
   been re-cut four times and the reason changed each time.
   The first mobile mockup drew a near-square card: 194x184 of a 212px screen,
   1.056 wide-to-tall. The final mobile reference draws a LANDSCAPE one: 920 of
   a 920px screen by 504 tall, which at 390 is full width by 214 — 11:6. It is
   the dominant element of that screen because it is the full width of it, not
   because it is tall.
   So: full-bleed, 11:6, and the body sits on the lower third of it. The two
   wrong answers in between are still worth knowing — a square plate took 42%
   of the screen for one story, and cutting the BODY to reach 4:3 made the card
   shorter than any reference draws it — because both were attempts to buy
   space that belonged to the score module above.
   Re-measured on a 140-character headline; see test/hero-layout.test.mjs. */
.lay-desk .hero--overlay .hero__media {
  margin: 0; aspect-ratio: 11 / 6; height: auto; overflow: hidden;
  /* UNDOING THE WHOLE-PHOTOGRAPH IDIOM, DELIBERATELY AND ONLY HERE.
     Further down this file the hero frame is sized BY its picture —
     width: fit-content, a centring flex box, and the picture at its own shape
     under a --media-cap. That is right for a lead with nothing on it and is
     untouched for the other three titles. It is wrong for a card whose whole
     premise is that type sits on the picture: the frame took its height from
     the column, the picture stopped at its 520px cap in the middle of it, and
     the first desktop capture of this showed 225px of grey above a photograph
     floating in a 817px plate. Every declaration below reverses exactly one
     declaration of that block. */
  width: auto; display: block;
}
/* The picture is wrapped in its own link, and a link that does not fill the
   frame gives height: 100% nothing to resolve against. */
.lay-desk .hero--overlay .hero__media > a { display: block; width: 100%; height: 100%; }
.lay-desk .hero--overlay .hero__media img {
  width: 100%; height: 100%; min-height: 0;
  max-width: none; max-height: none;
  object-fit: cover;
}
.lay-desk .hero--overlay .hero__body {
  position: absolute; inset: auto 0 0 0; z-index: 1;
  /* TWO BOUNDS, AND THE CLAMP IS THE ONE THAT BINDS.
     The headline is clamped to three lines and the standfirst is not rendered
     at this width, so the body cannot grow past about 161px whatever the copy
     does — 60% of a phone's 4:3 plate, measured on a 140-character headline.
     The ceiling is the backstop for a font that renders taller than measured,
     and it is deliberately above the measurement rather than on it: a cap the
     content already touches clips the moment anything changes. */
  /* THE CEILING IS A BACKSTOP AND THE CLAMP IS THE DESIGN, which this plate
     has now proved twice. At 339px tall a 25px headline fitted under 64%; at
     Reference B's 213 the same body wanted 80% of it and the ceiling cut the
     headline through the middle of a line. The type came down with the plate —
     17px, which is what the reference sets it at — and the ceiling moved up to
     leave room for a face that renders taller than measured. */
  max-height: 72%; overflow: hidden;
  /* The top of this padding is gradient, not type. */
  padding: 22px 14px 12px;
  background: linear-gradient(to top,
    rgb(0 0 0 / 0.88) 0%, rgb(0 0 0 / 0.72) 42%, rgb(0 0 0 / 0.28) 76%, rgb(0 0 0 / 0) 100%);
  color: #fff;
}
.lay-desk .hero--overlay .hero__title,
.lay-desk .hero--overlay .hero__title a,
.lay-desk .hero--overlay .hero__sf { color: #fff; }
.lay-desk .hero--overlay .hero__meta { color: rgb(255 255 255 / 0.78); }
.lay-desk .hero--overlay .hero__title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
/* A size for the overlay card specifically. The phone's shared hero headline is
   26px, which is right for a headline standing under a picture and four lines
   deep inside one: three lines of it is 88px of the 268px card before the
   category and the time are counted. */
/* A CARD AT THE GUTTER, NOT A FULL-BLEED BAND — which reverses what stood here.
   This block used to say Reference B's hero "runs the whole width of the screen
   while the rows under it keep a gutter". It does not. That reading came from a
   mis-scaled crop of the mockup; re-measured with a pixel grid run down the
   mockup's whole left edge, the scores card, the hero, the Top Stories heading
   and its thumbnails, and the Explore heading ALL share one content edge, and
   the hero carries a rounded corner at each end of it. A full-bleed hero is the
   one band on the phone that breaks the page's own left margin.

   The height does not change: the reference's card is 377x222 against a ~9px
   gutter, which is 1.70, and 358x213 inside this page's 16px gutter is 1.68. So
   this is the same picture moved in, not a smaller one. The headline stays 17px
   over it. */
@media (max-width: 47.99rem) {
  .lay-desk .fblock__lead .hero--overlay {
    border-radius: 12px; overflow: hidden;
  }
  /* AND THE PICTURE KEEPS ITS HEIGHT. The shared plate is 11/6, which at the
     full 390 gave 213; moving the card inside the gutter would have taken the
     same ratio down to 358x195, and a narrower hero that is also shorter is the
     one thing this pass was told not to do. 5/3 is the reference's own
     proportion (its card is 377x222, 1.70) and puts 358 back at 215 — the same
     picture, moved in, not a smaller one. */
  .lay-desk .fblock__lead .hero--overlay .hero__media { aspect-ratio: 5 / 3; }
  .lay-desk .hero--overlay .hero__title { font-size: 17px; line-height: 1.12; }
  .lay-desk .hero--overlay .hero__body { gap: 3px; padding: 20px 16px 10px; }
}
/* The standfirst is desktop-only. On a phone the reference's lead carries a
   category, a headline and a time and nothing else, and every line of
   standfirst there is a line of photograph lost. */
.lay-desk .hero--overlay .hero__sf { display: none; }

@media (min-width: 62rem) {
  /* The lead fills its column rather than stopping short of the panels beside
     it: three columns of different heights with a 300px hole under the tallest
     thing on the page is what the first capture of this showed. */
  .lay-desk .fblock__lead { display: flex; }
  /* min-width: 0 IS THE WHOLE FIX FOR A SIDEWAYS SCROLLBAR, and the reason is
     worth writing down because the symptom pointed somewhere else entirely.
     A ratio plus a definite height gives a box a ratio-derived MIN-CONTENT
     WIDTH, and a flex item defaults to min-width: auto, which is that
     min-content width. So `aspect-ratio: 16/10; height: 100%` on a plate that
     stretches to an 854px grid row asked for 1367px of width inside a 1232px
     wrap, the item refused to shrink, and the whole document scrolled — at
     1024 and 1280, where the row is tall relative to the column, and not at
     1440, where it is not. Measured before and after at all four widths. */
  .lay-desk .hero--overlay { flex: 1 1 auto; min-width: 0; }
  /* THE RATIO STAYS, AND IT IS NOT THE THING THAT SCROLLED THE PAGE. Taking it
     out was the first answer and it shipped: the live capture then came back
     with a 652x964 plate on a 1626x2406 portrait in a 702px column, because
     every percentage height in the chain — plate against card, card against
     column — is indefinite until something makes it definite, and with nothing
     resolving them the picture's own 1.48 ratio decided the frame. That is the
     portrait fault this block exists to prevent, arriving at the desktop
     instead of the phone.
     The ratio is only consulted when the height is indefinite, which is
     exactly the case that went wrong: it caps the plate's contribution to the
     grid row at width/1.6, so a tall file cannot inflate the row. When the
     panels beside it are taller the row IS definite, the ratio stands aside,
     and the plate fills the column with the picture cropped into it. The
     sideways scroll is answered by min-width: 0 above, which is what should
     have answered it the first time. */
  .lay-desk .hero--overlay .hero__media {
    aspect-ratio: 16 / 10; height: 100%; min-height: 20rem;
  }
  /* THE CAP AND THE CLAMP HAVE TO BE SET TOGETHER, and the density pass is what
     proved it. The plate went from 712px to 457 when the panels beside it were
     tightened; the body did not move, so a four-line 44px headline over a
     standfirst and a time no longer fitted under 56% of a shorter plate and
     the ceiling cut it through the middle of a line. A cap only ever hides the
     overflow — the clamp is what has to make it fit. Three lines at 34px over
     a two-line standfirst is 230px against the 283 this allows, measured on the
     140-character headline, with nothing clipped.

     32px is also what the reference sets this headline at: about 24px against
     its own 1030px container, which is 32 against this one. The 44px it was
     is the size that stopped fitting. */
  .lay-desk .hero--overlay .hero__body {
    max-height: 62%;
    padding: 36px clamp(20px, 3vw, 34px) clamp(16px, 2.2vw, 24px);
  }
  .lay-desk .hero--overlay .hero__title {
    -webkit-line-clamp: 3; font-size: min(var(--step-4), 32px); line-height: 1.08;
  }
  /* ONE LINE OF STANDFIRST, which is the line the shorter plate can afford.
     At two the body came to 282px against a 283px ceiling — content that is
     1px under its own cap is content that clips the next time anything moves,
     which is the fault the cap exists to catch rather than cause. At one the
     body is 260 and 57% of the picture is still picture. */
  .lay-desk .hero--overlay .hero__sf {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden;
    max-width: 46rem;
  }
}

/* ---------- the panels beside the lead ----------
   The reference draws Top Stories and the cross-sport column as bordered
   panels rather than lists running into the page. One component for both, so
   the two cannot drift. */
.panel {
  border: var(--border-w) solid var(--border); border-radius: var(--radius);
  background: var(--surface); min-width: 0;
}
.panel__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space);
  padding: 13px 15px; border-bottom: var(--rule-w) solid var(--rule);
}
.lay-desk .panel__head { border-bottom-color: var(--accent); }
.panel__name {
  margin: 0; font-family: var(--font-head); font-size: var(--step-1);
  font-weight: var(--head-weight); letter-spacing: var(--head-tracking); line-height: 1.1;
}
.panel__more {
  flex: none; font-family: var(--font-meta); font-size: 11px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent);
}
.panel__more::after { content: " \2192"; }
.panel__body { padding: 13px 15px; }
.panel__body > .sidelist { gap: 13px; }

/* ---- the cross-sport list ----
   Numbered because the reference numbers it. The number is the POSITION in the
   list and nothing else: there is no read count behind it (see acrossHtml) and
   the meta line states the time and the source, like every other card here. */
.xlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.xrow { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 11px; align-items: start; }
.xrow + .xrow { border-top: 1px solid var(--rule); padding-top: 12px; }
.xrow__n {
  font-family: var(--font-head); font-size: var(--step-2); font-weight: 800;
  line-height: 1; color: var(--accent); font-variant-numeric: tabular-nums;
}
.xrow__b { min-width: 0; }
.xrow__cat {
  display: block; font-family: var(--font-meta); font-size: 10px; font-weight: 800;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent);
}
.xrow__t {
  margin: 2px 0 0; font-family: var(--font-head); font-size: var(--step-n1);
  font-weight: 700; line-height: 1.25;
}
.xrow__t a { color: var(--ink); }
.xrow__m {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px;
  font-family: var(--font-meta); font-size: 11px; color: var(--faint);
}

/* ---------- the section tiles ----------
   Photographic cards under a dark overlay, as the reference draws them. The
   picture is a real licensed photograph from that section's own reporting (see
   exploreHtml); a section that has none keeps the glyph, so a row can be mixed.

   ONE ROW ON DESKTOP where the sections fit, and a horizontal rail on a phone
   rather than a grid four rows deep. */
.tiles {
  list-style: none; margin: 0; padding: 2px 0 6px;
  display: grid; gap: 10px;
  /* PIXELS, NOT PERCENTAGES. A percentage track on a grid whose own width comes
     from its content is circular: the browser resolves it against a box the
     tracks are themselves sizing, the row grows, and the PAGE scrolls sideways
     — measured at 1391px of document inside a 1280px window, and 1315 inside
     1024. A fixed track cannot do that, and `min-width: 0` keeps the rail from
     widening the grid it sits in. */
  grid-auto-flow: column; grid-auto-columns: 170px;
  min-width: 0; max-width: 100%;
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.tiles::-webkit-scrollbar { display: none; }
.tiles > li { scroll-snap-align: start; min-width: 0; }
@media (min-width: 34rem) { .tiles { grid-auto-columns: 220px; } }
/* ONE ROW, AND THE CARDS ARE WIDE AND SHORT — which is what the reference
   draws, and the opposite of what an earlier reading of it produced.

   That reading went: ten across a 1360px column is 122px a card, too narrow
   for a photograph, so five across and two deep. The reference settles it the
   other way. It puts all nine of its sports in ONE row at about 0.11 of its
   container each — 127px here — and makes them SHORT: 0.056 of the container
   tall, against the 0.123 that shipped. The card is a wide strip with a name
   on it, not a square tile, and at 16:9 a 127px card is 71px tall and still
   reads as a photograph because it is cropped to a letterbox rather than
   shrunk to a thumbnail. The band goes from 425px to about 140.

   DESCRIPTOR UNDER THE NAME IS OPT-IN. The default (glyph) tile shows the name
   only. A title that declares an `explore` block with its own navigation copy
   (SportDailyMail does) adds a short descriptor beneath the name — "News,
   Scores, Transfers", "Six Nations, Premiership" — as approved navigation copy,
   not a fabricated statistic. The descriptor renders inside .tile__tw. */
@media (min-width: 80rem) {
  .tiles {
    grid-auto-flow: row; grid-auto-columns: auto;
    /* As many equal tracks as there are tiles (set inline as --tile-n), so the
       band is ONE clean row of exactly its own count — never a fixed 10-track
       grid that wraps the moment a title has nine sports or eleven. */
    grid-template-columns: repeat(var(--tile-n, 10), minmax(0, 1fr));
    gap: 8px; overflow-x: visible;
  }
}

/* ONE CARD, PHOTOGRAPHED OR NOT. The first build of this gave the fallback the
   page's own panel colours, so a row of ten came out as six dark photographs
   and four pale boxes — which reads as four tiles that failed to load rather
   than four sections without a photograph yet. The card is dark in both
   states: the photograph lands under the same overlay the dark base already
   is, and the glyph is the only thing that changes. Fixed colours rather than
   tokens, for the same reason the hero's type is: white on a photograph is
   white in both themes. */
.tile {
  position: relative; display: flex; align-items: flex-end;
  /* A LETTERBOX, AND NO MIN-HEIGHT WORTH THE NAME. A ratio plus a floor is a
     MINIMUM WIDTH as well — 3/2 with min-height: 118px is a card that cannot
     be narrower than 177px, so in a ten-track grid of 124px columns every
     card overflowed its own cell and the page scrolled sideways again, at
     1317px inside 1280. The floor is 72, which at 3/2 is a 108px card: under
     the 116px a ten-track row gives at the narrowest desktop width, so the
     ratio always decides and the track always decides the card.

     3/2 RATHER THAN 16/9, because at 16:9 the band read as a strip of
     thumbnails rather than the way into every sport on the site. 128x85 is
     half as tall again as 128x72 and still landscape, which is the shape the
     reference draws. */
  aspect-ratio: 3 / 2; min-height: 72px;
  padding: 10px 11px; border-radius: var(--radius);
  background: #15181c; color: #fff;
  border: var(--border-w) solid transparent;
  overflow: hidden; isolation: isolate;
}
.tile:hover, .tile:focus-visible { text-decoration: none; border-color: var(--accent); }
.tile:hover .tile__t { text-decoration: underline; }

/* The photograph fills the card and is cropped by the frame, exactly as a
   story card's is. */
.tile__img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
}
/* The overlay that makes the name readable over any photograph. Stronger at
   the foot, where the type sits, and never a flat wash over the whole picture. */
.tile--photo::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to top,
    rgb(0 0 0 / 0.88) 0%, rgb(0 0 0 / 0.6) 34%, rgb(0 0 0 / 0.18) 70%, rgb(0 0 0 / 0.04) 100%);
}
/* The glyph is the fallback's own treatment, and it steps back behind a
   photograph rather than sitting on top of one. */
.tile__art {
  position: absolute; right: -8px; top: -8px; opacity: 0.3; color: var(--accent);
  pointer-events: none;
}
.tile--photo .tile__art { display: none; }
.tile__art svg { width: 52px; height: 52px; }
.tile__t {
  position: relative; font-family: var(--font-head); font-size: var(--step-n1);
  font-weight: 800; line-height: 1.1; color: #fff;
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.5);
}
/* Name + navigation descriptor, stacked at the foot of the card. The descriptor
   is smaller and muted so the name leads; both sit over the foot gradient. */
.tile__tw { position: relative; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tile__d {
  font-family: var(--font-head); font-size: 10.5px; font-weight: 600; line-height: 1.15;
  color: rgb(255 255 255 / 0.85); text-shadow: 0 1px 2px rgb(0 0 0 / 0.65);
  /* Full navigation copy, never cut to an ellipsis: wrap to at most two lines so
     "News, Scores, Transfers" reads in full at nine-across. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}
/* The dedicated-asset treatment: a stronger, premium image card. A touch taller
   than the glyph tiles so the name and a two-line descriptor sit comfortably. */
.tiles--cards .tile { aspect-ratio: 16 / 11; min-height: 92px; }

/* ---------- the sports desk's vertical density ----------

   THE ONE THING THE REFERENCE AND THE LIVE BUILD STILL DISAGREED ON, and it is
   not a component — it is how much room every component takes.

   Measured off the reference against its own container width, which is the
   only scale-free way to compare a mockup with a page, and then against the
   live build at a 1360px wrap:

                        reference    live    over
     lead block           0.233w      817     2.6x
     Top Stories row      0.058w      165     2.1x
     cross-sport row      0.042w      101     1.8x
     fixture card         0.053w      107     1.5x
     Explore band         0.056w      425     4.0x

   The COLUMN WIDTHS already matched — lead 0.49w against 0.48w, the two panels
   within a point of the reference — so nothing here moves a column. What was
   wrong is that every row was roughly twice as tall as the reference draws it,
   which is why the live page needs two screens for what the reference fits in
   one.

   NOT TAKEN ALL THE WAY DOWN. Hitting 0.233 exactly would put the Top Stories
   headline near 11px, and a sports front nobody can read at arm's length is a
   worse answer than one that is slightly airier than its mockup. The target
   here is the reference's SHAPE at a size this publication can still be read
   at: nothing below 13px, every headline still two full lines.

   Scoped to .lay-desk throughout. The other three titles keep the rhythm they
   shipped with. */

/* The fixture cards. The reference draws a crest, a name and a score in a strip
   about 0.053 of its container tall; this one used 32px of top padding to clear
   a competition label that only needs 24, and a line of team name under each
   crest that can sit beside the score instead. */
.lay-desk .scores .mcard { padding: 24px 11px 10px; }
.lay-desk .scores .mcard__comp { top: 8px; font-size: 9px; }
.lay-desk .scores .mcard__side { gap: 4px; }
.lay-desk .scores .mcard__team { font-size: 11px; }

/* THE MASTHEAD, which the side-by-side put at 152px against the reference's 93.
   The bar is 102 of that and the wordmark is 70 of the bar: the reference sets
   its logo at about 0.029 of the container's width in height — 39px here —
   against the 64 this was carrying. 46px keeps the mark legible at arm's
   length and takes 24px off the top of every page. Sports desk only; the other
   three nameplates are untouched. */
@media (min-width: 62rem) {
  .lay-desk .brand__logo { --brand-logo-h: 46px; }
  .lay-desk .masthead__bar { min-height: 64px; padding: 13px 0; }
}

/* The Top Stories rail: a 4:3 thumbnail instead of a square one, and a headline
   held to two lines. The square was 96px of height for a 40px headline. */
/* 76px, and NOT the 64 that was tried: at a two-line headline the BODY is the
   taller side of the row, so shrinking the picture took nothing off the row
   height and only made the picture smaller. The reference's own thumbnail is
   about 0.27 of its panel's width; 76 of 310 is 0.245. */
.lay-desk .fblock__side .sidelist .compact { --thumb: 76px; padding: 0; gap: 10px; }
.lay-desk .fblock__side .compact__media.is-1x1 { aspect-ratio: 4 / 3; }
.lay-desk .fblock__side .compact__title {
  font-size: var(--step-n1); line-height: 1.26;
  /* TWO LINES, WHICH IS WHAT THE REFERENCE'S RAIL RUNS TO. The thumbnail is
     57px tall and a three-line headline is 49 over a 15px meta line, so the
     TEXT was setting the row height and the picture was sitting in a column of
     its own air. At two lines the two sides of the row are the same height and
     the row is 79px against the reference's 71. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.lay-desk .fblock__side .compact__meta { font-size: 11px; }
.lay-desk .fblock__side .panel__body > .sidelist { gap: 11px; }

/* The cross-sport column, the same way: the headline is the only part that was
   growing, so it is the part that is held. */
.lay-desk .xlist { gap: 9px; }
.lay-desk .xrow + .xrow { padding-top: 9px; }
.lay-desk .xrow__cat { font-size: 9px; }
.lay-desk .xrow__t {
  margin-top: 1px; line-height: 1.2;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.lay-desk .xrow__m { margin-top: 3px; font-size: 10px; gap: 6px; }
.lay-desk .xrow__m .tbadge { font-size: 10px; padding: 1px 5px; min-height: 0; }
/* The rank is a marker beside the row, not a display figure. */
.lay-desk .xrow { grid-template-columns: 20px minmax(0, 1fr); gap: 9px; }
.lay-desk .xrow__n { font-size: var(--step-1); }

/* Both panels: the head is a label, not a band. */
@media (min-width: 62rem) {
  .lay-desk .fblock__side .panel__head,
  .lay-desk .fblock__third .panel__head { padding: 10px 13px; }
  .lay-desk .fblock__side .panel__body,
  .lay-desk .fblock__third .panel__body { padding: 11px 13px; }
  /* The Explore heading had 44px of air under a 72px row of cards. The
     reference gives its band heading about a third of that. */
  .lay-desk .band--explore .band__head { margin-bottom: 14px; padding-bottom: 5px; }
}

/* ---------- the rail beside the lead ---------- */
.sidelist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--stack-gap); }
/* Big enough to read as a picture, small enough to leave the headline two
   comfortable lines rather than four cramped ones. */
/* Compact and secondary: a smaller thumbnail, a tighter measure and rows that
   close the gap the rail used to leave under the lead. */
.sidelist .compact { --thumb: 88px; padding-top: 0; gap: var(--space); }
.sidelist .compact__title { font-size: var(--step-0); line-height: 1.2; }
.sidelist .compact__body { gap: 2px; }
.sidelist .compact__cat { font-size: 11px; }
/* In the rail the time is prose, not a chip. A tinted badge on every one of
   four rows put four accent blocks in a column beside the lead, which is more
   accent than the whole page carries elsewhere. */
.sidelist .tbadge { background: none; color: var(--faint); padding: 0; font-weight: 600; }
@media (min-width: 62rem) { .sidelist .compact { --thumb: 96px; } }
.sidelist > li { padding-bottom: calc(var(--stack-gap) * 0.7); }
.sidelist { gap: calc(var(--stack-gap) * 0.7); }
.sidelist > li { padding-bottom: var(--stack-gap); border-bottom: var(--rule-w) solid var(--rule); }
.sidelist > li:last-child { border-bottom: 0; padding-bottom: 0; }
/* Dayli Mail Today's rail is set in the display serif; the other two keep the
   interface face, which is the difference a reader actually notices. */
.lay-newspaper .sidelist .compact__title { font-family: var(--font-display); }

/* ---------- a band, and its head ---------- */
.band { margin-bottom: var(--section-gap); }
.band__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space);
  border-bottom: var(--rule-w) solid var(--ink); padding-bottom: 7px;
  margin-bottom: calc(var(--space) * 2);
}
.band__name {
  margin: 0; font-family: var(--font-head); font-weight: 700;
  font-size: var(--step-2); letter-spacing: var(--head-tracking);
}
.band__name a { color: var(--ink); }
.band__more {
  flex: none; display: inline-flex; align-items: center; gap: 5px; min-height: 26px;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: 600;
  color: var(--accent); white-space: nowrap;
}
.band__more::after { content: "\2192"; }

/* Sport Daily Mail rules its band heads in the accent, at its own 3px. */
.lay-desk .band__head { border-bottom-color: var(--accent); }
/* Daily All In uses a two-tone rule: accent under the heading, hairline after. */
.lay-wire .band__head { border-bottom-color: var(--accent); }

/* ---------- the four-across grid ---------- */
.sgrid { display: grid; gap: var(--card-gap); grid-template-columns: 1fr; }
.sgrid > * { min-width: 0; }

/* ---------- the section grid on a phone ----------

   A card is a picture with a headline under it, and four of them stacked in a
   single column is four 16:9 pictures: 370px per story, which is a story and a
   half per screen and the reason the front felt empty while being very long.

   So on a phone the FIRST card of a block keeps its picture - a block needs
   something to lead with, and losing that is how three publications start
   looking like one list - and the rest become rows: the same markup, laid out
   as thumbnail and headline. Nothing is hidden. The category, the headline,
   the time and the source are all still there, and the article they point at
   is unchanged. The block goes from roughly 1,480px to roughly 700px.

   `.card` is already flex, so this is a grid-template change and nothing
   else, and it reverts at the first breakpoint where a real grid begins. */
@media (max-width: 33.99rem) {
  .sgrid { gap: 0; }
  .sgrid > .card + .card {
    display: grid; grid-template-columns: 116px 1fr; align-items: start;
    gap: calc(var(--space) * 1.5);
    margin-top: var(--card-gap);
  }
  .sgrid > .card + .card .card__media {
    aspect-ratio: 4 / 3; border-radius: var(--radius); align-self: start;
  }
  /* A row is not a card: it carries no chrome, so it matches the secondary
     rows higher up the page instead of putting a second card style beside
     them. The rule between rows is the one the compact list already uses. */
  .sgrid > .card + .card {
    background: none; border: 0; border-top: var(--rule-w) solid var(--rule);
    padding-top: var(--card-gap);
  }
  .sgrid > .card + .card .card__body { padding: 0; gap: calc(var(--space) * 0.6); }
  .sgrid > .card + .card .card__title { font-size: var(--step-0); }
  /* Two lines of trail under a thumbnail is a paragraph in a 230px column. */
  .sgrid > .card + .card .card__excerpt { display: none; }
}
@media (min-width: 34rem) { .sgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62rem) { .sgrid { grid-template-columns: repeat(4, 1fr); } }

/* Dayli Mail Today divides its grid with hairlines rather than cards — the
   closest thing on screen to a page set in columns. */
@media (min-width: 34rem) {
  .sgrid--paper { gap: 0; }
  .sgrid--paper > * { padding: 0 calc(var(--space) * 2); border-right: var(--rule-w) solid var(--rule); }
  .sgrid--paper > *:first-child { padding-left: 0; }
  .sgrid--paper > *:last-child { border-right: 0; padding-right: 0; }
}
@media (min-width: 34rem) and (max-width: 61.99rem) {
  .sgrid--paper > *:nth-child(2n) { border-right: 0; padding-right: 0; }
  .sgrid--paper > *:nth-child(2n+1) { padding-left: 0; }
}

/* ---------- the section chips over the feed ---------- */
.chips { margin: 0 0 var(--space); }
.chips__list {
  display: flex; gap: calc(var(--space) * 2); list-style: none; margin: 0; padding: 0;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.chips__list::-webkit-scrollbar { display: none; }
.chip {
  display: flex; align-items: center; min-height: 40px; white-space: nowrap;
  font-family: var(--font-meta); font-size: var(--step-n1); font-weight: 600;
  color: var(--muted); border-bottom: 3px solid transparent;
}
.chip:hover { color: var(--ink); text-decoration: none; }
.chip.is-on { color: var(--ink); border-bottom-color: var(--accent); font-weight: 700; }

/* ================================================================== *
 * The drawer, the three views, and the bar along the bottom
 *
 * The drawer is a checkbox and a sibling selector. No script: navigation
 * must never depend on JavaScript having loaded, and these pages are
 * indexed. The checkbox is the control and keeps its focus ring; each
 * visible opener is a label bound to it and is marked decorative, so a
 * screen reader is told about one control rather than two.
 *
 * It is available at every width, from whichever opener that width shows:
 * the section bar's "More" at desktop, the bottom bar's "More" on a phone.
 * The burger is hidden at both — see "what belongs to which width".
 * ================================================================== */

.navtoggle {
  position: absolute; top: 10px; left: 10px; width: 44px; height: 44px;
  opacity: 0; margin: 0; z-index: 41; cursor: pointer;
}
.burger {
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  width: 40px; height: 40px; color: inherit; margin-left: -6px;
}
.burger__i, .burger__i::before, .burger__i::after {
  display: block; width: 20px; height: 2px; background: currentColor; content: '';
}
.burger__i { position: relative; }
.burger__i::before { position: absolute; top: -6px; }
.burger__i::after { position: absolute; top: 6px; }
/* The checkbox is transparent but keeps a visible focus ring, drawn on the
   label the reader can actually see. */
.navtoggle:focus-visible ~ .masthead__band .burger { outline: 2px solid currentColor; outline-offset: 3px; }

/* The panel is a layer over the PAGE, so it takes the page's surface — not the
   masthead's band, which is what it used to borrow.
   `--head-bg` is a publication's nameplate colour, and on two of the three it
   is deliberately dark in BOTH schemes: Daily All In's is #0B3B2A at all times
   and Sport Daily Mail's #111114. A drawer built on it was therefore a black
   panel over a white page in light mode, on those two, with no way for the
   reader's choice to reach it. Dayli Mail Today escaped only because its
   nameplate happens to be white — its own rule below already reaches for
   `--surface`, which is the correct source and the model for this.
   The tokens carry the light values; the dark block near the foot of this file
   puts back exactly what each publication showed before. */
.drawer {
  position: fixed; inset: 0 auto 0 0; width: min(86vw, 22rem); z-index: 40;
  --drawer-bg: var(--surface);
  --drawer-ink: var(--ink);
  --drawer-rule: var(--rule);
  background: var(--drawer-bg); color: var(--drawer-ink);
  /* Scrolls inside itself, and a scroll that reaches the end does not carry on
     into the page behind it. On a 568px-tall phone ten sections plus the
     secondary list is taller than the viewport, so this is the normal case,
     not the edge one. */
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(-100%); visibility: hidden;
  padding: var(--space) 0 calc(var(--space) * 3);
  display: flex; flex-direction: column; gap: var(--space);
}
/* The drawer stops above the bottom bar rather than covering it, so the bar
   stays usable while the panel is open — including the control that closes it.

   And on a phone it comes in from the RIGHT. The control that opens it is
   "More", the last cell of the bottom bar, in the bottom-right corner: a panel
   that answers a right-hand thumb by flying in from the opposite edge makes
   the reader's hand cross the screen to reach what they just asked for. The
   base rule above still anchors it left, so nothing at desktop width moves.

   `inset: 0 0 62px auto` — top, right, bottom, LEFT auto — is what re-anchors
   it; the transform is the same distance in the other direction. The open
   state is `transform: none` either way, so one rule still opens both. */
@media (max-width: 61.99rem) {
  .drawer { inset: 0 0 62px auto; transform: translateX(100%); }
  .drawer__scrim { inset: 0 0 62px 0; }
}
/* The head stays put while the sections scroll under it. */
.drawer__head { position: sticky; top: calc(var(--space) * -1); background: inherit; z-index: 1; padding-top: var(--space); }
@media (prefers-reduced-motion: no-preference) {
  .drawer { transition: transform 0.18s ease, visibility 0.18s; }
}
.drawer__scrim { display: none; position: fixed; inset: 0; z-index: 39; background: rgb(0 0 0 / 0.5); }
.navtoggle:checked ~ .drawer { transform: none; visibility: visible; }
.navtoggle:checked ~ .drawer__scrim { display: block; }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); padding: 0 var(--gutter) var(--space);
  border-bottom: 1px solid currentColor;
}
/* A hairline, not a full-strength rule in the text colour. Grey-at-45% reads on
   a dark panel and disappears on a light one, so it is a token now too. */
.drawer__head, .drawer__list--sec { border-color: var(--drawer-rule); }
.drawer__brand { font-family: var(--font-display); font-weight: var(--display-weight); font-size: var(--step-2); }
.drawer__x {
  cursor: pointer; font-size: 28px; line-height: 1; min-width: 44px; min-height: 44px;
  display: grid; place-items: center; color: inherit;
}
.drawer__edition {
  margin: 0; padding: 0 var(--gutter); font-family: var(--font-meta);
  font-size: var(--step-n1); opacity: 0.7;
}
.drawer__list { list-style: none; margin: 0; padding: 0; }
.drawer__list--sec { border-top: 1px solid currentColor; margin-top: var(--space); padding-top: var(--space); }
.drawer__link {
  display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 0 var(--gutter);
  color: inherit; font-family: var(--font-head); font-size: var(--step-1); font-weight: 600;
}
/* Every row in the panel carries a glyph, the secondary list included. A list
   where only some rows have one has two left edges and reads as an oversight
   rather than a decision. `flex: none` on the glyph is what keeps that edge
   straight when a label is long enough to want the space. */
.drawer__link .ico { flex: none; }
.drawer__link:hover, .drawer__link:focus-visible { background: rgb(127 127 127 / 0.18); text-decoration: none; }
/* A FORWARD MARK AT THE END OF EACH ROW, which is how the reference draws its
   drawer. Generated rather than marked up, because it is decoration on a link
   that already goes somewhere — it opens nothing of its own, so it is not a
   control and must not be in the accessibility tree. The row's own label and
   its NEW badge keep their place; the mark takes the space at the end that
   nothing else was using. Sports desk only: the other three drawers are
   unchanged. */
.lay-desk .drawer__link { position: relative; padding-inline-end: calc(var(--gutter) + 14px); }
.lay-desk .drawer__link > span:first-of-type { flex: 1 1 auto; }
.lay-desk .drawer__link::after {
  content: ""; position: absolute; inset-inline-end: var(--gutter); top: 50%;
  width: 7px; height: 7px; margin-top: -4px;
  border-right: 2px solid currentColor; border-top: 2px solid currentColor;
  transform: rotate(45deg); opacity: 0.38;
}
/* A row with a NEW badge keeps both, in the reference's order: the badge, then
   the mark. Without this the badge sits where the mark is and the three newest
   sections are the three rows missing it. */
.lay-desk .drawer__new { margin-inline-end: 15px; }
/* Dayli Mail Today's drawer is paper, not a dark panel — the same decision
   its masthead makes. */
.lay-newspaper .drawer { background: var(--surface); color: var(--ink); border-right: var(--border-w) solid var(--border); }
.lay-newspaper .drawer__head, .lay-newspaper .drawer__list--sec { border-color: var(--rule); }

/* ---- the row you are on, on the two titles that had no mark for it ----

   `aria-current="page"` has always been on the right row in all three drawers,
   so a screen reader has always been told. Only the sports desk drew it. These
   two carried the attribute and showed nothing, in either scheme.

   Each takes its OWN section bar's answer to the same question rather than a
   copy of the desk's, which is why they do not look alike:

     the wire       marks the current section with a rule and a heavier weight
                    (`border-bottom-color` + 700). In a vertical list the
                    translation of an underline is a rule down the left edge.
     the newspaper  adds the accent to the LABEL itself — that is the thing its
                    bar does that the others do not — so the row reads in the
                    publication's red and the rule stays out of it.

   An inset shadow, not a border, for the same reason the desk uses one: a
   border would move the label 2px and the column of glyphs would stop being a
   column. Neither mark is carried by colour alone — the wire also gains weight,
   and the newspaper's label changes colour AND weight — and `aria-current` is
   what actually carries it for anyone not looking. */
.lay-wire .drawer__link[aria-current="page"] {
  font-weight: 700; box-shadow: inset 2px 0 0 var(--accent);
}
.lay-newspaper .drawer__link[aria-current="page"] {
  font-weight: 700; color: var(--accent);
}

/* On a phone the panel is a drawer over the page, not a navigation screen, so
   it is a good deal denser than the "More" overlay a desktop opens: narrower,
   smaller type, and every band of vertical padding cut back. Sizes are written
   against the tokens rather than as flat pixels, so each publication keeps the
   proportions of its own scale.

   Rows sit at 40px and the close control at 36px square - short of the 44px
   AAA figure, comfortably past the 24px WCAG 2.5.8 AA minimum, and neither is
   the only route to what it does: the sections are also on the bottom bar and
   the scrim closes the panel. Row height is deliberately the one thing not
   trimmed further here: the panel is long because it has ten to thirteen
   sections in it, and the honest way to shorten it is not to shrink what a
   thumb has to hit. What came off instead is width, the padding around the
   head, the gaps between blocks, and the edition line. The panel still scrolls
   inside itself when a section list outruns a short screen.

   Placed after the rules above because a media query adds no specificity. */
@media (max-width: 61.99rem) {
  .drawer { width: min(78vw, 300px); padding: 3px 0 10px; gap: 3px; }
  /* The sticky offset has to stay the negative of the drawer's own top padding,
     so the head parks flush against the top edge when the list scrolls under it. */
  .drawer__head { top: -3px; padding: 3px var(--gutter) 2px; }
  .drawer__brand { font-size: var(--step-0); line-height: 1.1; }
  .drawer__x { font-size: 22px; min-width: 36px; min-height: 36px; }
  /* The edition line is desk furniture. On a phone it is a row of small grey
     type above the sections saying something the reader did not come here to
     read, and the panel is long enough already: ten to thirteen sections, a
     secondary list and the appearance control. It stays at desktop, where the
     panel has the room and the line has somewhere to sit. */
  .drawer__edition { display: none; }
  .drawer__list--sec { margin-top: 4px; padding-top: 4px; }
  .drawer__link { min-height: 40px; font-size: calc(var(--step-0) * 0.93); }
}

/* ---- Sport Daily Mail's phone drawer ----
   A palette and a weight, nothing structural: the panel keeps its width, its
   40px rows, its 62px stop above the bottom bar and every destination in it.
   What changes is that the panel stops borrowing the masthead's near-black and
   the section list stops reading at one flat weight — the row you are on is
   the only red in it.

   Scoped to .lay-desk, so the other two publications' drawers are untouched;
   scoped inside the phone query, so the desktop panel is too. Placed after the
   block above because a media query adds no specificity and this has to win.

   The colours are written once here as tokens rather than repeated down the
   block: the whole point of the specification is that there are five of them. */
@media (max-width: 61.99rem) {
  /* Light is the default here, and the dark block at the foot of this file
     puts the five back to the exact values they have always had. Written as
     page tokens rather than hex: the relationships are what the specification
     is about — a panel on the surface, the row you are on at full ink, every
     other row a step back, glyphs a step above their label — and the tokens
     already carry those per publication and per scheme. */
  .lay-desk .drawer {
    --dr-bg: var(--surface);      /* the page's own surface, not the nameplate */
    --dr-ink: var(--ink);         /* primary: the row you are on, and the nameplate */
    --dr-ink-2: var(--muted);     /* every other row */
    --dr-glyph: var(--ink);       /* glyphs sit a step above their label */
    --dr-rule: var(--rule);
    --dr-accent: var(--accent);   /* #C8101A light, #FF4B54 dark — its own red */
    --dr-pref-label: var(--ink);  /* the appearance control, a step back again */
    --dr-pref-state: var(--muted);
    background: var(--dr-bg); color: var(--dr-ink-2);
  }

  /* ---- head ----
     The nameplate is one colour here, not the masthead's two-tone: the red in
     this panel means "you are on this row", and a red half-wordmark above the
     list would be the loudest thing in it saying nothing. The brand accent is
     a 2px rule beside the name instead — beside rather than under, so it costs
     no height in a panel whose whole problem is height. */
  .lay-desk .drawer__head { border-bottom-color: var(--dr-rule); }
  .lay-desk .drawer__brand {
    color: var(--dr-ink); font-weight: 700;
    border-left: 2px solid var(--dr-accent); padding-left: 9px;
  }
  .lay-desk .drawer__brand .brand__lead,
  .lay-desk .drawer__brand .brand__accent { color: inherit; }
  .lay-desk .drawer__x { color: var(--dr-glyph); }
  .lay-desk .drawer__x:hover,
  .lay-desk .drawer__x:focus-visible,
  .lay-desk .drawer__x:active { color: var(--dr-accent); }

  /* ---- rows ----
     Inset and gap only; min-height stays 40px and the label stays centred in
     it, so the panel is exactly as tall as it was. */
  .lay-desk .drawer__link { gap: 14px; padding: 0 20px; color: var(--dr-ink-2); }
  .lay-desk .drawer__list--sec { border-top-color: var(--dr-rule); }

  /* ---- glyphs ----
     Same set, same mapping, same 21x21 box for every one of them — heavier in
     the stroke and a step brighter than the label, which is what makes a row
     scan as a glyph and a word rather than as one grey line. `color` rather
     than `stroke`, because .ico strokes in currentColor. */
  .lay-desk .drawer__link .ico {
    width: 21px; height: 21px; stroke-width: 2.1; color: var(--dr-glyph);
  }

  /* ---- the row you are on ----
     A glyph in the publication's red, a label at full strength, and a 2px rule
     down the left edge. The rule is an inset shadow, not a border: a border
     would move the label 2px and the column of glyphs would stop being a
     column. Deliberately not a filled red row — this is a list of sections,
     not a selected state in a form. */
  .lay-desk .drawer__link[aria-current="page"] {
    color: var(--dr-ink); box-shadow: inset 2px 0 0 var(--dr-accent);
  }
  .lay-desk .drawer__link[aria-current="page"] .ico { color: var(--dr-accent); }

  /* ---- the appearance control ----
     Unchanged in behaviour and in the word it prints. It sits at the foot of a
     list of destinations without being one, so it reads a step back from them
     and the switch itself a step back from its own label. */
  .lay-desk .drawer__pref { border-top-color: var(--dr-rule); }
  /* These were three fixed light-on-dark greys, which is exactly what a white
     panel cannot use. Tokens, with the greys restored in the dark block. */
  .lay-desk .tmode__label { color: var(--dr-pref-label); }
  .lay-desk .tmode__state { color: var(--dr-pref-state); opacity: 1; }
  .lay-desk .tmode__mark { color: var(--dr-pref-state); }

  /* ======================================================================
     THE PANEL AS CARDS, which is the whole of this pass.

     What changed is the SURFACE, not the structure: the same rows, the same
     order, the same routes, the same disclosure checkbox, the same scroll and
     the same 62px of clearance over the bottom bar. A flat list on a flat grey
     became a near-black panel with a card per row, because a list of twelve
     sports reads as a wall of grey text and the one thing a reader is looking
     for is a sport.

     Scoped to `.lay-desk` and to this width. The other three publications'
     drawers and the desk's OWN drawer at desktop width are untouched — the
     desktop panel is opened from the section bar's More and is not what this
     brief is about.
     ====================================================================== */
  /* THE VALUES HERE ARE THE LIGHT ONES, and the dark block at the foot of this
     file replaces all six. That is deliberate: this panel follows the reader's
     chosen scheme like every other surface on the site, and the appearance
     control is three rows below it. A drawer hard-coded to near-black would be
     the one thing on the page that ignores the switch it contains. The dark
     scheme — which is this title's default, and what the reference is drawn in
     — is where the near-black panel and its raised cards actually land. */
  /* A LITTLE WIDER THAN THE OTHER THREE PANELS. Each row now carries a name
     over a descriptor, and at 300px the descriptors were ellipsing mid-word
     ("PREMIER LEAGUE • EFL • EUR..."). 328 is still a panel rather than a page
     — the screen behind it stays visible, which is what tells a reader this
     closes — and it is what lets the copy fit instead of being cut. */
  .lay-desk .drawer { width: min(84vw, 328px); }
  .lay-desk .drawer {
    --dr-card: #F3F4F6;             /* a row */
    --dr-card-edge: rgb(0 0 0 / 0.09);
    --dr-card-hover: #E9EBEF;
    --dr-sub: #666D76;              /* the descriptor under a name */
    --dr-group: #777E87;            /* the TOOLS heading */
    --dr-lead: #C8101A;             /* the filled lead card, white text on it */
    padding: 0 0 calc(var(--space) * 2);
    gap: 7px;
  }

  /* ---- head ----
     Brand, strapline and a round close control, in a two-column grid so the
     strapline sits under the name rather than beside it and the control keeps
     its own full-height tap area. */
  .lay-desk .drawer__head {
    display: grid; grid-template-columns: 1fr auto; align-items: center;
    row-gap: 1px; padding: 12px var(--gutter) 11px;
  }
  .lay-desk .drawer__brand {
    grid-column: 1; border-left: 0; padding-left: 0;
    font-size: var(--step-2); line-height: 1.05;
  }
  /* ONE LINE. The real strapline is "Results, fixtures and the story behind
     them", which wrapped to two and made the head taller than the lead card.
     It is a strapline, not a sentence to read here. */
  .lay-desk .drawer__strap {
    grid-column: 1; font-family: var(--font-meta); font-size: 9px;
    letter-spacing: 0.04em; text-transform: uppercase; color: var(--dr-sub);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 100%;
  }
  .lay-desk .drawer__x {
    grid-column: 2; grid-row: 1 / span 2;
    min-width: 36px; min-height: 36px; width: 36px; height: 36px;
    font-size: 20px; border-radius: 999px;
    background: var(--dr-card); border: 1px solid var(--dr-card-edge);
  }

  /* ---- a row is a card ----
     The inline padding moves off the link and onto the list, so the card's own
     edge is what sits at the gutter. */
  .lay-desk .drawer__list { padding: 0 12px; display: grid; gap: 7px; }
  .lay-desk .drawer__link {
    min-height: 52px; padding: 8px 12px; gap: 12px;
    background: var(--dr-card); border: 1px solid var(--dr-card-edge);
    border-radius: 10px; color: var(--dr-ink);
    padding-inline-end: 26px;
  }
  .lay-desk .drawer__link:hover,
  .lay-desk .drawer__link:focus-visible { background: var(--dr-card-hover); }
  .lay-desk .drawer__txt { display: grid; gap: 1px; min-width: 0; }
  /* The name never wraps: "Horse Racing" beside a NEW badge broke onto two
     lines and that row alone became 20px taller than every other. */
  .lay-desk .drawer__name {
    /* 18px, not --step-1 (19.2 here). "Darts & Snooker" is the longest name
       in the list and it carries a NEW badge: at 19.2 it needed 178px of a
       166px column and ellipsed. It is still the row's primary, at nearly
       twice its own descriptor. */
    font-family: var(--font-head); font-size: 18px; font-weight: 700;
    line-height: 1.15; color: var(--dr-ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .lay-desk .drawer__sub {
    font-family: var(--font-meta); font-size: 10px; line-height: 1.3;
    letter-spacing: 0.055em; text-transform: uppercase; color: var(--dr-sub);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .lay-desk .drawer__link::after { inset-inline-end: 11px; opacity: 0.3; }

  /* ---- the lead row ----
     The one filled card in the panel. It is the publication's front, which is
     what every other row is a narrowing of; `aria-current` still marks the row
     the reader is actually on, including this one. */
  .lay-desk .drawer__link[data-lead] {
    background: var(--dr-lead); border-color: transparent; color: #fff;
    min-height: 58px;
  }
  .lay-desk .drawer__link[data-lead]:hover,
  .lay-desk .drawer__link[data-lead]:focus-visible { background: var(--dr-lead); filter: brightness(1.08); }
  .lay-desk .drawer__link[data-lead] .drawer__name,
  .lay-desk .drawer__link[data-lead] .ico { color: #fff; }
  .lay-desk .drawer__link[data-lead] .drawer__sub { color: rgb(255 255 255 / 0.82); }
  .lay-desk .drawer__link[data-lead]::after { opacity: 0.85; }
  /* The lead is already a filled red card, so the current-page rule's inset
     red bar would be red on red. It keeps the mark everywhere else. */
  .lay-desk .drawer__link[data-lead][aria-current="page"] { box-shadow: none; }

  /* ---- the row you are on ----
     The inset bar now has a radius to follow, so it is drawn as a left border
     the card can round rather than as a square shadow over a rounded corner. */
  .lay-desk .drawer__link[aria-current="page"] {
    box-shadow: inset 2px 0 0 var(--dr-accent);
    border-color: rgb(255 255 255 / 0.14);
  }

  /* ---- the glyphs ----
     One family, one box, one stroke — the set this project already ships, not
     a new dependency and not emoji. What is new is a restrained per-sport hue,
     which is what makes a column of twelve scan as twelve different things.
     Each is a desaturated tint chosen to clear 4.5:1 on the card beneath it. */
  .lay-desk .drawer__link .ico { width: 22px; height: 22px; stroke-width: 2; color: var(--cat, var(--dr-glyph)); }
  /* The sports rows wear the filled mark instead, and it is drawn 4px larger:
     a ball is a round silhouette with no straight edge to line up on, so at the
     stroke set's 22px it reads SMALLER than the line glyph beside it even
     though the boxes match. 26px is the size at which a football and the
     Results trophy look like one family on one row. The hue below no longer
     reaches these rows - each mark carries its sport's own colours - but it is
     left in place for the tools, which keep the stroke set. */
  .lay-desk .drawer__link .ico--mark { width: 26px; height: 26px; }
  /* The hue is carried on the ROW as --cat rather than set on the glyph, so the
     dark scheme restates thirteen custom properties instead of thirteen
     selectors. These are the LIGHT values: a tint picked to read on a near-white
     card clears about 2:1 on a near-black one, which is under the 3:1 a 22px
     graphic needs, so the pale set that looked right in dark mode was failing
     the moment a reader chose light. Both sets are checked against their own
     card, not against each other. */
  .lay-desk .drawer__link[data-cat="football"]      { --cat: #1E6FCC; }
  .lay-desk .drawer__link[data-cat="analysis"]      { --cat: #3C63C8; }
  .lay-desk .drawer__link[data-cat="transfers"]     { --cat: #16834A; }
  .lay-desk .drawer__link[data-cat="cricket"]       { --cat: #C33A2E; }
  .lay-desk .drawer__link[data-cat="rugby"]         { --cat: #6B46C1; }
  .lay-desk .drawer__link[data-cat="tennis"]        { --cat: #6E7A12; }
  .lay-desk .drawer__link[data-cat="motorsport"]    { --cat: #44505E; }
  .lay-desk .drawer__link[data-cat="golf"]          { --cat: #157A58; }
  .lay-desk .drawer__link[data-cat="us-sports"]     { --cat: #B35A12; }
  .lay-desk .drawer__link[data-cat="horse-racing"]  { --cat: #8A5A22; }
  .lay-desk .drawer__link[data-cat="combat"]        { --cat: #C0392F; }
  .lay-desk .drawer__link[data-cat="darts-snooker"] { --cat: #7A3FB5; }
  .lay-desk .drawer__link[data-cat="results"]       { --cat: #9A6B10; }

  /* ---- NEW ----
     A filled chip rather than an outlined one. It is a status marker, so it
     keeps its place before the chevron. */
  .lay-desk .drawer__new {
    background: var(--dr-lead); color: #fff; border: 0; border-radius: 999px;
    padding: 2px 7px; font-size: 9px; line-height: 13px; letter-spacing: 0.07em;
    opacity: 1; margin-inline-end: 6px;
  }

  /* ---- tools ----
     A heading over the lower list instead of a rule above it: the cards
     already separate themselves, and a rule plus a gap is two separations. */
  .lay-desk .drawer__group {
    margin: 9px 0 0; padding: 0 calc(12px + 12px);
    font-family: var(--font-meta); font-size: 10px; font-weight: 700;
    letter-spacing: 0.14em; text-transform: uppercase; color: var(--dr-group);
  }
  /* ROOM UNDER THE LAST ROW FOR THE PINNED CONTROL. The appearance control is
     `position: sticky; bottom: 0` and always has been — it is the one thing in
     this panel a reader should never have to hunt for. Sticky means it OVERLAYS
     the rows while they scroll, so the final row needs somewhere to go. Most of
     that clearance is the control's OWN in-flow height at the end of the list —
     this is the margin for error on top of it, not the whole of it. */
  .lay-desk .drawer__list--sec { border-top: 0; margin-top: 0; padding-top: 0; padding-bottom: 12px; }

  /* ---- the appearance control ----
     Same button, same behaviour, same words. It is given the card's surface so
     it belongs to the panel rather than sitting on the bare background. */
  /* IT STAYS PINNED, which is what it already did: `position: sticky; bottom: 0`
     keeps the appearance control reachable in a panel that scrolls. So the
     CARD has to go on the button and the opaque backdrop has to stay on the
     wrapper — a card with 12px of transparent gutter either side lets the rows
     scroll through the gap beside it, which is what the first cut of this did. */
  .lay-desk .drawer__pref {
    border-top: 1px solid var(--dr-rule); margin: 0;
    padding: 6px 12px calc(var(--space) * 0.5);
    background: var(--dr-bg);
  }
  .lay-desk .drawer__pref .tmode {
    min-height: 50px; padding: 0 12px; width: 100%;
    background: var(--dr-card); border: 1px solid var(--dr-card-edge);
    border-radius: 10px;
  }

  /* ======================================================================
     THE TARGET TREATMENT.

     The pass above made each row a CARD. This one makes each card carry its
     sport's own PHOTOGRAPH, which is the difference between the panel and the
     target: a reader scanning thirteen sports recognises a picture before a
     word, and the cards were reading as thirteen identical grey tiles
     distinguished only by a 26px glyph.

     It deliberately costs height. The target is a long panel a reader scrolls,
     and the previous pass had been squeezing everything above the fold - which
     is why the names were at 18px with the descriptors ellipsing. Rows are
     taller, type is bigger, and the list scrolls, which it already did.

     Last in the block on purpose: everything here overrides the pass above,
     including the lead row's own height.
     ====================================================================== */
  /* 82.5vw, MEASURED off the target: its drawer is 1064px of a 1290px frame.
     The previous pass had it at 96vw, which is why the page behind it had all
     but disappeared - the target deliberately leaves a strip of the page
     showing, and that strip is what tells a reader the panel closes. */
  .lay-desk .drawer { width: min(82.5vw, 356px); gap: 12px; }

  /* ---- head ----
     The wordmark is the thing a reader checks they are in the right place by,
     and at --step-2 it was smaller than the row names underneath it. */
  /* PINNED, AND OPAQUE, AND ABOVE THE ROWS. The panel scrolls under its own
     head, so the head needs a ground of its own and a z-index: the rows' own
     contents sit at z-index 1 so the photograph cannot paint over them, and
     without this the Motorsport card scrolled straight through the wordmark. */
  .lay-desk .drawer__head {
    position: sticky; top: 0; z-index: 2; background: var(--dr-bg);
    padding: 20px 14px 16px; row-gap: 5px;
  }
  /* ONE LINE, and the size is what makes it one. "Sport Daily Mail" at 32px
     needs about 290px and a 390 phone leaves the head 279 beside a 52px close
     control, so the wordmark wrapped to two lines and doubled the head. 28px
     fits with room, and nowrap means a longer masthead would ellipse rather
     than silently grow the panel's head again. */
  /* SIZED SO IT IS NEVER CUT. The head is one line - wordmark, then a round
     close control - and at the measured 82.5vw drawer that leaves 234px beside
     a 48px control. "Sport Daily Mail" measures 214px at 27px, so it fits with
     room and the ellipsis can never fire. It stays `nowrap` so a longer
     masthead would be caught by the width test rather than wrapping the head
     to two lines in silence. */
  .lay-desk .drawer__brand {
    font-size: 27px; line-height: 1.05; white-space: nowrap;
  }
  .lay-desk .drawer__strap {
    font-size: 11px; letter-spacing: 0.2em; opacity: 0.95;
  }
  .lay-desk .drawer__x {
    min-width: 48px; min-height: 48px; width: 48px; height: 48px; font-size: 26px;
  }

  /* ---- a row ----
     68px rather than 52: two lines of type at the target's sizes, with the
     picture given room to be a picture rather than a stripe. */
  .lay-desk .drawer__list { padding: 0 12px; gap: 8px; }
  .lay-desk .drawer__link {
    min-height: 74px; padding: 11px 12px; gap: 11px;
    border-radius: 14px; padding-inline-end: 25px; overflow: hidden;
  }
  /* The target's lead card is 1.08x a normal row (119 against a 110 pitch);
     84 against 74 keeps that relationship at the adapted scale. */
  .lay-desk .drawer__link[data-lead] { min-height: 84px; }
  /* 18px, not 19.5. "Darts & Snooker" is the longest name in the list AND it
     carries a NEW badge, which leaves it 160px: at 19.5 it needed 180 and
     ellipsed, and so did Football's descriptor. The target fits both on one
     line, so the target's name is not 19.5 either. */
  /* A DELIBERATE MOBILE ADAPTATION, not the target's own scale. The target is
     drawn on a canvas about 1060px wide: its drawer is 9.67 row-heights across,
     which at a 322px drawer would be a 33px row and a 7px title. The TARGET
     keeps the visual identity - the artwork, the gradients, the hierarchy, the
     order - and 390px usability sets the physical size. Every category name
     fits unellipsed at this size, including the three that carry a NEW badge. */
  .lay-desk .drawer__name { font-size: 17px; line-height: 1.15; }
  /* 9.5px, and the tracking down from .085 to .055em. The target's longest
     descriptor is "PREMIER LEAGUE • CHAMPIONS LEAGUE" — 33 characters into the
     206px a row leaves beside a 32px mark — and at 10.5/.085em it needed 208 of
     them and ellipsed, as did Transfers and Rugby. Measured, not guessed: every
     descriptor in the list now reports scrollWidth == clientWidth. */
  .lay-desk .drawer__sub { font-size: 9px; letter-spacing: 0.025em; }
  /* `.ico` FIRST, `.ico--mark` SECOND. Both selectors are three classes, so
     they have equal specificity and the later one wins — written the other way
     round, the stroke set's size silently sized the filled marks too. */
  .lay-desk .drawer__link .ico { width: 29px; height: 29px; }
  .lay-desk .drawer__link .ico--mark { width: 34px; height: 34px; }

  /* ---- the sheet's own icons ----
     Raster, from the approved asset sheet, so they are sized by the box rather
     than by a stroke and they keep their own colours. `object-fit: contain`
     because the cut files are not all the same aspect: a horse's head is wider
     than a bolt, and letting each sit inside one square box is what keeps the
     column of thirteen aligned. */
  .lay-desk .drawer__link .drawer__ic,
  .lay-desk .drawer__pref .drawer__ic {
    width: 34px; height: 34px; flex: none; object-fit: contain;
    position: relative; z-index: 1;
  }
  /* THREE OF THE SHEET'S ICONS ARE WHITE — the trophy, the magnifier and the
     checkered flag — and white on this panel's LIGHT card is invisible. The
     artwork is not altered; it is given an outline the same weight a hairline
     border would be, and only in the light scheme. */
  :root[data-theme="light"] .lay-desk .drawer__ic {
    filter: drop-shadow(0 0 1px rgb(0 0 0 / 0.55)) drop-shadow(0 1px 1px rgb(0 0 0 / 0.25));
  }
  /* THE CHEVRON IS A ROTATED CORNER, so `transform: scale()` REPLACED the
     rotation that makes it one and drew a square bracket. It is grown by its
     own box and stroke, with the rotation restated, which is the only way to
     change its size without destroying it. */
  .lay-desk .drawer__link::after {
    inset-inline-end: 12px; opacity: 0.55;
    width: 9px; height: 9px; margin-top: -5px;
    border-right-width: 2.4px; border-top-width: 2.4px;
    transform: rotate(45deg);
  }

  /* ---- the photograph ----
     Right-hand half of the card, cropped per row by the inline
     background-position, and faded out before it reaches the label by a mask
     rather than an overlay: a mask fades the PICTURE, so the card's own
     background - white in light mode, near-black in dark - stays the ground
     under the text and the treatment works in both schemes without a second
     set of colours. The mask is listed with its unprefixed property second so
     the WebKit-only build of it does not win.

     Inert: pointer-events none, aria-hidden in the markup, and it sits under
     everything because the glyph and the label are the row. */
  .lay-desk .drawer__art {
    position: absolute; inset-block: 0; inset-inline-end: 0; width: 80%;
    background-size: cover; background-repeat: no-repeat;
    opacity: 0.72; pointer-events: none; z-index: 0;
    -webkit-mask-image: linear-gradient(to right, transparent, rgb(0 0 0 / 0.45) 36%, #000 100%);
    mask-image: linear-gradient(to right, transparent, rgb(0 0 0 / 0.45) 36%, #000 100%);
  }
  /* A light card needs the picture quieter: dark ink on a photograph is the
     harder of the two, and this panel follows the reader's chosen scheme. */
  .lay-desk .drawer__link .ico,
  .lay-desk .drawer__link .ico--mark,
  .lay-desk .drawer__txt,
  .lay-desk .drawer__new { position: relative; z-index: 1; }
  .lay-desk .drawer__link::after { z-index: 1; }
  /* Three pixels off the badge's gap, because "Darts & Snooker" wanted 167 of
     the 166 a badge row leaves it. One pixel is still an ellipsis. */
  /* EVERY PIXEL HERE IS A PIXEL "Darts & Snooker" DOES NOT HAVE. A badge row
     leaves the name 143px and that name wants 162 at 17.5px; the badge was the
     cheapest place to find the difference, because it is read as a marker
     rather than as a word. */
  .lay-desk .drawer__new {
    margin-inline-end: 3px; padding: 2px 6px; font-size: 9px; line-height: 13px;
  }

  /* ---- the lead row ----
     Red first, picture second: the montage is a texture under the red rather
     than a photograph beside it, which is what the target draws. */
  .lay-desk .drawer__link[data-lead] .drawer__art {
    opacity: 0.32; mix-blend-mode: luminosity;
  }

  /* ---- the appearance control ----
     Moon, label, switch - the switch to the right, which is an `order` rather
     than a different document for the other three publications. */
  /* ABOVE THE ROWS, EXPLICITLY. The row contents above are lifted to z-index 1
     so the photograph cannot paint over them, and that put them over this
     panel too: the pinned control is sticky with `z-index: auto`, so the Golf
     card showed straight through "Dark mode". It is the one thing in the panel
     that overlays, so it is the one thing that needs to say so. */
  /* NOT PINNED, ON THIS TITLE. The panel's control used to hover over the rows
     so it was reachable without scrolling; the target draws it as the LAST CARD
     in a long scroll, and this is a reproduction. Static also removes the
     overlap that made it sit on top of whichever row happened to be under it.
     The other three publications keep the sticky control they had. */
  .lay-desk .drawer__pref { position: static; z-index: 2; margin-top: 4px; }
  /* TOOLS is a divider as much as a heading in the target: it separates the
     sports from the two utilities under them, so it takes air above it and the
     list below starts clear rather than continuing the sports. */
  .lay-desk .drawer__group {
    margin: 20px 0 9px; padding: 0 26px;
    font-size: 11px; letter-spacing: 0.2em;
  }
  .lay-desk .drawer__pref { padding: 9px 13px calc(var(--space) * 0.6); }
  /* ONE LINE, always: the label does not wrap and the switch keeps its place
     at the end, so "Dark mode" can never break across two rows. */
  .lay-desk .drawer__pref .tmode { min-height: 64px; gap: 12px; border-radius: 14px; padding: 0 14px; }
  .lay-desk .drawer__pref .tmode--glyph .ico,
  .lay-desk .drawer__pref .tmode--glyph .drawer__ic { width: 28px; height: 28px; order: 0; flex: none; }
  .lay-desk .drawer__pref .tmode--glyph .tmode__label { order: 1; font-size: 18px; white-space: nowrap; }
  .lay-desk .drawer__pref .tmode--glyph .tmode__state { order: 2; margin-inline-start: auto; }
  .lay-desk .drawer__pref .tmode--glyph .tmode__mark { order: 3; }
}

/* ---------- the three views ---------- */
.tabs { border-bottom: var(--rule-w) solid var(--rule); background: var(--surface); }
.tabs__list { list-style: none; margin: 0; padding: 0; display: flex; }
.tabs__t {
  display: flex; align-items: center; justify-content: center; min-height: 48px;
  padding: 0 var(--space); font-family: var(--font-meta); font-size: var(--step-0);
  font-weight: var(--meta-weight); color: var(--muted);
  border-bottom: 3px solid transparent; flex: 1 1 0;
}
.tabs__t:hover { color: var(--ink); text-decoration: none; }
.tabs__t.is-on { color: var(--accent); border-bottom-color: var(--accent); }

/* ---- the desk's phone rail ----

   The reference's phone header carries a scrolling row of sections rather than
   three equal tabs. Three equal tabs plus eleven sections in one `flex: 1 1 0`
   row is what it was before this block: the row could not shrink below its
   content, so the PAGE grew to 1175px on a 390px screen and every line of every
   story went off the side. A rail scrolls; it does not widen its parent.

   `flex: 0 0 auto` on the chips, `min-width: 0` on the list, and the same
   hidden-scrollbar treatment the section chips already use lower down the page.
   The three views keep their equal share at the head of the rail, so the row a
   reader already knows is where it was. */
.tabs--rail .tabs__list {
  min-width: 0; overflow-x: auto; scrollbar-width: none;
  -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity;
}
.tabs--rail .tabs__list::-webkit-scrollbar { display: none; }
.tabs--rail .tabs__t {
  white-space: nowrap; scroll-snap-align: start; flex: 0 0 auto;
  min-height: 42px; padding: 0 13px; font-size: var(--step-n1);
  letter-spacing: 0.02em;
}
/* One size for the whole rail. The three views were set at --step-0 while the
   sections were set smaller, which made the first three items twice the weight
   of the rest of a row they are part of. */
.tabs--rail .tabs__t--sec { text-transform: uppercase; letter-spacing: 0.05em; }
.tabs__new {
  margin-left: 5px; padding: 0 4px; border-radius: 2px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 9px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
}

/* ---------- the bar along the bottom of a phone ----------
   Fixed, four cells, every one a real destination. The page reserves room
   for it so the last line of the footer is never sitting underneath. */
.bbar {
  position: fixed; inset: auto 0 0 0; z-index: 31;
  background: var(--surface); border-top: var(--border-w) solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  /* It slides, it does not fade: a half-transparent bar over body copy is
     harder to read past than a solid one. */
  transition: transform 180ms ease;
  will-change: transform;
}
/* Scrolling down means reading, and 55px of chrome across the foot of the
   screen is the last two lines of every paragraph. The bar leaves, and one
   upward flick brings it back - see bottomBarOnDemand in site.js. It is
   always present at the top of a page, at the bottom, and while the drawer
   is open, so nothing here removes a destination. */
.bbar.is-away { transform: translateY(calc(100% + 2px)); }
/* While the drawer is open the reader is navigating, and the bar belongs on
   screen. Stated here rather than in the script, so that navigation never
   depends on a script having run. */
.portal:has(.navtoggle:checked) .bbar.is-away { transform: none; }
@media (prefers-reduced-motion: reduce) { .bbar { transition: none; } }
.bbar__list { list-style: none; margin: 0; padding: 0; display: flex; }
.bbar__i {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  flex: 1 1 0; min-height: 54px; cursor: pointer; color: var(--muted);
  font-family: var(--font-meta); font-size: 10px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.bbar__i:hover, .bbar__i:focus-visible { color: var(--accent); text-decoration: none; }
.bbar li { display: flex; flex: 1 1 0; }

/* SENTENCE CASE AND AN ACTIVE CELL, both of which Reference B draws and neither
   of which this bar had: the labels were the meta scale's tracked-out capitals
   and every cell was the same colour, so the bar never said where you were. The
   mark hangs off `aria-current`, which the shell already emits, so the colour
   and the assistive name cannot drift apart — the fault the view tabs were
   fixed for once already.

   OUTSIDE THE PHONE BLOCK ON PURPOSE. These two lived under
   `max-width: 47.99rem` and the bar is drawn below 1024, so at 768 the same bar
   read "HOME RESULTS SEARCH MORE" with no cell marked while at 390 it read
   "Home Results Search More" with Home in the accent. One component, one
   treatment, at every width it appears at. */
.lay-desk .bbar__i { text-transform: none; letter-spacing: 0; font-weight: 600; }
.lay-desk .bbar__i[aria-current="page"] { color: var(--accent); }

/* ---------- what belongs to which width ---------- */
@media (max-width: 47.99rem) {
  /* The wordmark is the whole bar by this width — the block below hands it
     every column — so all that is left here is its own size. The strapline
     still comes off: at 390px it costs two lines and says nothing the
     wordmark has not already said. */
  .masthead__bar { min-height: 54px; }
  .brand { text-align: center; }
  .brand__name { font-size: min(var(--masthead-size), 22px); }
  .brand__tag { display: none; }
  /* Bigger, not smaller: on a phone the thumbnail is the only picture a
     secondary story gets, and at 88px it read as a placeholder chip. */
  .sidelist .compact { --thumb: 108px; }
  .sidelist > li { padding-bottom: calc(var(--stack-gap) * 0.6); }
  .sidelist { gap: calc(var(--stack-gap) * 0.6); }
}
@media (max-width: 61.99rem) {
  .nav { display: none; }              /* the drawer carries the same links */

  /* Below this width the masthead is the nameplate and nothing else.
     The burger and the search control each had a second, larger copy of
     themselves in the bar along the bottom — "More" opens the same drawer the
     burger opened, "Search" is the same /search/ destination — so the top of a
     phone screen carried two controls that only led where the thumb could
     already reach, and the wordmark was squeezed between them to do it. The
     bar is the primary navigation at this width; the masthead identifies the
     title. Desktop is untouched: above 62rem the bar is gone, so the search
     control there is the only one and it stays. */
  .burger, .masthead__acts { display: none; }

  /* ONE EXCEPTION, on the sports desk: the Live pill.
     The rule above removes controls that had a larger copy of themselves in
     the bottom bar, and by that test the pill looks like the Results cell. It
     is not. The cell is a destination; the pill carries the NUMBER of fixtures
     on right now, refreshed from the same live.json the rail polls, and a
     reader can read it without navigating anywhere. That is information the
     bottom bar does not have, which is why the reference puts it here.

     AND THE SEARCH GLYPH BESIDE IT, because the final mobile reference draws
     both: a magnifier next to the wordmark AND a Search cell in a bar of four.
     This went back and forth twice — glyph only with a three-cell bar, then
     cell only with no glyph — on the reasoning that one destination may have
     one control. The reference settles it: a header affordance and a primary
     navigation cell are different things to reach for, and the rule that
     matters is the one about ROWS, which is that a phone gets two navigation
     layers and not three. */
  .lay-desk .masthead__acts { display: flex; gap: 7px; align-items: center; }
  .lay-desk .masthead__acts > :not(.hlive):not(.hact--sm) { display: none; }
  .lay-desk .hlive { min-height: 32px; padding: 0 11px; font-size: 11px; }
  .lay-desk .hact--sm {
    min-height: 32px; width: 32px; padding: 0; justify-content: center;
    border-radius: 999px;
  }
  .lay-desk .hact--sm .hact__t { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  /* .masthead__bar zeroes .wrap's horizontal padding, and got away with it
     because the burger's own column stood in for the left inset and the search
     control's for the right. With both gone the wordmark sat hard against the
     viewport edge — invisible on the two titles that centre their nameplate,
     and a clipped capital on the one that does not. The page gutter, written
     the way .wrap writes it, so the nameplate lines up with the section bar,
     the ticker and the stories underneath it. */
  .masthead__bar { grid-template-columns: minmax(0, 1fr); }
  /* .lay-newspaper sets its own padding on this bar at a higher specificity,
     so it has to be named here or the broadsheet alone keeps the flush edge. */
  .masthead__bar,
  .lay-newspaper .masthead__bar { padding-inline: calc(var(--space) * 2); }
  /* .brand is placed in column 2 for the three-column desktop bar. With one
     column left it has to be told, or the grid opens an implicit second column
     and the wordmark sits outside the one real track. */
  .brand { grid-column: 1; }

  /* The checkbox is still the drawer's control and still keyboard-operable —
     the bar's "More" is a label bound to it — but with no burger left to sit
     under, its 44px transparent hit area at the top-left of the masthead would
     be a hamburger that cannot be seen and can still be tapped. Shrunk rather
     than removed: display:none would take it out of the tab order and leave
     the drawer unreachable without a pointer. */
  .navtoggle { width: 1px; height: 1px; }
  /* So its focus ring moves to the control the reader can actually see. The
     checkbox sits inside .masthead and the bar is a sibling of it, so this has
     to reach across the two from .portal rather than through a ~ combinator. */
  .portal:has(.navtoggle:focus-visible) .bbar__i--more {
    color: var(--accent); outline: 2px solid currentColor; outline-offset: -3px;
  }

  /* Clears the fixed bottom bar: 54px of cells plus its top border, rounded up
     so the last line of the footer is never sitting underneath it. */
  .portal { padding-bottom: 62px; }
}
@media (min-width: 62rem) {
  .burger, .tabs, .bbar { display: none; }
  .nav__more { display: flex; }
  .portal { padding-bottom: 0; }
  /* A nameplate that centres must stay centred when something is added beside
     Search.

     The bar is `auto minmax(0,1fr) auto`: burger, brand, actions. At desktop
     the burger is display:none so its track collapses, and the nameplate is
     centred within a column that runs from the left gutter to the actions -
     which is half the actions' width left of the page's true centre. That was
     already 50-54px before this change and became 102-107px once appearance
     joined Search.

     Symmetric tracks fix it: an empty one on the left the same size as the one
     holding the actions, and a content-sized brand between them. Bare `1fr` is
     `minmax(auto, 1fr)`, so the right-hand track can never be squeezed below
     what Search and Dark mode actually need.

     Scoped to the two titles that centre their nameplate. The sports desk sets
     its brand flush left on purpose and keeps the asymmetric grid it was drawn
     with. And this is a min-width block, so the phone's single-column bar is
     untouched. */
  .lay-wire .masthead__bar,
  .lay-newspaper .masthead__bar { grid-template-columns: 1fr auto 1fr; }
  .lay-wire .brand,
  .lay-newspaper .brand { grid-column: 2; }
  .lay-wire .masthead__acts,
  .lay-newspaper .masthead__acts { grid-column: 3; }

  /* The drawer's checkbox is a phone control and nothing at this width points
     at it any more. Left alone it was an opacity-0 44x44 hit area at the
     top-left corner of every desktop page that silently opened the side
     drawer, and a tab stop that did the same from the keyboard. The drawer
     markup stays - the phone needs it - but its control does not exist here.
     The 1px rule below 62rem is a different block and is untouched. */
  .navtoggle { display: none; }
}

/* The section bar's first desktop band, where it cannot yet afford its own
   padding.

   The bar wraps rather than scrolls - the min-width: 900px block turns it into
   a wrapping flex container, which also silently overrides the padding the
   62rem block sets for it - so when the links outgrow the track the last one
   drops onto a second row rather than the row scrolling. That is what the ten
   section publications do the moment the bar appears: at 992px Daily All In
   wants 896px of an 883px track and Sport Daily Mail 900px of 879px, so
   "Athletics & Cycling" and "US Sports" sat alone on a second line, and the
   bar was two rows tall until 1006px and 1014px respectively.

   For this one band the links keep the 11px padding they already use below it
   rather than the 14px they get above, which buys 40px across ten links and
   puts all ten back on one row with 17px and 9px to spare. Nothing scrolls,
   no section is hidden, and no label changes. At 1024px the track is wide
   enough for the full padding, so the band ends there and every wider
   viewport renders exactly as it did before. */
@media (min-width: 62rem) and (max-width: 63.99rem) {
  .nav__link { padding-left: 11px; padding-right: 11px; }
  .nav__link:first-child { padding-left: 0; }
}

/* ---------- the article page's two columns ----------
   The story keeps its reading measure; the continuation moves beside it
   rather than under it, which is what actually fills a wide viewport. The
   rail is a grid track, so it disappears with the aside when there is
   nothing to continue to. */
.artpage { display: grid; gap: var(--shell-gap); justify-content: center; }
.artpage__main, .artpage__side { min-width: 0; }
/* 80rem, not 62rem.
   The rail used to arrive at 992px, and it took its width out of the reading
   column: the body measure went 63 characters at 900px to FORTY at 992 — a
   wider screen giving a worse read — and only climbed back to 63 at about
   1279. Between those two the page was narrower for no reason a reader could
   see, because nothing else on it changed.

   A two-column layout can only ever give main less than one column does, so
   there is no breakpoint that avoids a step; what there is, is a breakpoint
   where the step is EXPLAINED. At 1280 the rail appearing is the reason the
   column narrowed. At 992 it was invisible. So the single column now runs to
   1279, where .art__body is already capped at --measure and holds a flat 63 /
   68 / 63 characters all the way up, and the two-column layout at 1280 and
   above is exactly what it was.

   1280 rather than something tighter because that is where the measure
   actually recovers on the widest of the three: Daily All In reads 57
   characters at 1150 and 1200, and only reaches 63 at 1279. */
@media (min-width: 80rem) {
  /* The main track is the reading measure PLUS a margin either side, and the
     lead plate uses that margin. A picture has no reading measure; the words
     do, and they keep theirs. --plate-push is per publication, so the
     broadsheet steps out less than the sports desk. */
  .artpage { grid-template-columns: minmax(0, auto) var(--rail-w); align-items: start; }
  .artpage__main { padding-inline: var(--plate-push); }
  .artpage__side { position: sticky; top: calc(var(--space) * 2); }
  .artpage__main .art__media,
  .artpage__main .art__media--full { margin-inline: calc(var(--plate-push) * -1); }
  /* The plate is the only thing that steps out. Pushing the headline out too
     gave the page three different left edges — headline, standfirst, picture —
     which reads as broken rather than as a wide plate. */
}
/* In a 21rem rail every continuation is a single column, whatever shape the
   variant gives it on a wide page. */
.artpage__side .desk__grid,
.artpage__side .paper-sub,
.artpage__side .wire__flow {
  display: grid; grid-template-columns: 1fr; gap: var(--stack-gap); columns: auto;
}
/* ...but between 992 and 1279 there is no rail. The side is the full width of
   the page there, and this rule was still stacking every continuation card in
   one column down the middle of it: Dayli Mail Today's article went from
   2003px to 4605px tall at 1024 — the same column of cards, three times the
   scroll, with half the page empty either side.

   Two columns, not auto-fill. At 1279 the side is ~1243px and auto-fill on
   --card-min would give four cards across, which is a front-page density
   arriving at the bottom of an article. Two keeps the cards the size they are
   on the front and the block half as tall.

   Bounded on BOTH sides deliberately. Below 62rem is the phone and tablet
   layout, which is one column today and stays one column. At 80rem the rail
   returns and the rule above takes over again untouched. */
@media (min-width: 62rem) and (max-width: 79.99rem) {
  .artpage__side .desk__grid,
  .artpage__side .paper-sub {
    grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--card-gap);
  }
  /* The wire's flow is multicol rather than a grid — it is one <ul> of ruled
     rows, and the rules have to run down both columns. `display: grid` with
     `columns: auto` above turns that off, so both are put back. The row rules
     and break-inside already apply from 900px. */
  .artpage__side .wire__flow {
    display: block; columns: 2; column-gap: calc(var(--space) * 5);
  }
}
.artpage__side .art__related { margin-top: 0; }

/* ================================================================== *
 * Phase 3 — the article page
 *
 * The structure is deliberately left alone: kicker, headline, standfirst,
 * byline, media, body, tags, related and the source attribution all keep
 * the markup they already had, because that markup carries the SEO and
 * the copyright attribution the sites depend on. What changes is how it
 * reads — measure, rhythm, and one reading treatment per publication.
 * ================================================================== */

/* The reading column. `--measure` is a per-publication token (700 / 620 /
   660px), so the broadsheet reads narrower than the international front
   without either of them hard-coding a width. */
.art__body { max-width: var(--measure); }
.art__body > p { margin: 0 0 1em; }
.art__head { max-width: var(--measure); }

/* ---------- /about/ is a site page, not a reading column ----------

   THE FAULT. .art above caps itself, its head and its body at --measure - the
   per-publication reading column, 700 / 620 / 660px - because .art was written
   for an article, and an article's job is one readable line length. /about/
   borrows .art for its typography and inherited that cap with it, so inside a
   --wrap of 1340 / 1200 / 1360px it was setting 620-700px of text and leaving
   548-668px of the grid empty. Measured: 50-54% of the available content width.

   THE FIX FILLS THE GRID WITHOUT LENGTHENING A SINGLE LINE, which is the whole
   point. The container stops capping itself so it spans the wrap the rest of the
   site uses, and the body sets in TWO columns - so the text occupies 1168-1328px
   while each column is 560 / 630 / 640px, at or below the measure it had before.
   Wider page, shorter lines. Stretching one column to the full width would have
   been the opposite trade and is what requirement 3 forbids.

   SCOPED TWICE OVER. By class, to .art--about, which only /about/ carries -
   404 is art--page art--404 and keeps the reading column it wants, and no
   article, front, section or tag page is touched. And by breakpoint: there is
   nothing here below 62rem, so a phone and a tablet render byte-identically to
   what they rendered before, measure, centring and all. Everything this changes
   is inside one media query and one class.

   No token, no colour and no type size is redefined, so dark mode, the theme
   toggle and the typographic hierarchy all carry over untouched. */
@media (min-width: 62rem) {
  .art--about,
  .art--about .art__head,
  .art--about .art__body { max-width: none; }

  .about__body {
    columns: 2;
    column-gap: calc(var(--space) * 6);
  }
  /* A heading must not be the last thing in a column with its section overleaf,
     and nothing that reads as one block may be split down the middle. Without
     these the source list and the headings break wherever the column happens to
     fill, which is what makes multi-column body text look accidental. */
  .about__body > h2,
  .about__body > h3 { break-after: avoid; break-inside: avoid; }
  .about__body > p,
  .about__body > ul,
  .about__body > ol,
  .about__body > blockquote { break-inside: avoid; }
}

.art__title {
  font-family: var(--font-display); font-weight: var(--display-weight);
  /* --lh-display, not --display-line: the latter is not a token this project
     emits, so the declaration was invalid and every article headline on all
     three sites inherited the BODY leading of 1.6 instead of the display
     leading of 1.0-1.06. A three-line headline was 60px of leading on 38px
     type. */
  letter-spacing: var(--display-tracking); line-height: var(--lh-display);
  text-wrap: balance;
}
.art__standfirst {
  font-size: var(--step-1); line-height: 1.45; color: var(--ink);
  max-width: var(--measure); margin: 0 0 var(--space);
}
/* The byline rule: who, when, and where it came from, on one line between
   two hairlines. It is the seam between the headline and the story. */
.art__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space);
  padding: calc(var(--space) * 0.75) 0;
  border-block: var(--rule-w) solid var(--rule);
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
  margin-bottom: var(--section-gap);
}

/* Captions and credits stay small, grey and directly beneath their image. */
.art figcaption, .media__caption {
  font-family: var(--font-meta); font-size: var(--step-n1); color: var(--faint);
  padding-top: 6px; max-width: var(--measure);
}

/* ---------- one reading treatment per publication ---------- */

/* Dayli Mail Today — the broadsheet. Serif body, a drop cap on the opening
   paragraph, and the tightest measure of the three. */
.lay-newspaper .art__body { font-family: var(--font-body); }
.lay-newspaper .art__body > p:first-of-type::first-letter {
  float: left; font-family: var(--font-display); font-size: 3.1em;
  line-height: 0.84; padding: 0.06em 0.09em 0 0; color: var(--ink);
}
@media (max-width: 30rem) {
  .lay-newspaper .art__body > p:first-of-type::first-letter { font-size: 2.6em; }
}

/* Sport Daily Mail — the results front. No drop cap; a heavier opening
   paragraph instead, which reads as a match-report intro. */
.lay-desk .art__body > p:first-of-type { font-size: var(--step-1); font-weight: 500; }

/* Daily All In — the international front. The widest measure and the most
   generous leading of the three. */
.lay-wire .art__body { line-height: 1.72; }

/* ---------- the continuation ----------
   It lives in the rail now, so it stacks. The list markers come off; the
   rule between rows is what separates them. */
.art__related ol, .art__related ul { list-style: none; padding: 0; margin: 0; }
.art__related ol > li, .art__related ul > li { border-top: var(--rule-w) solid var(--rule); }
.art__related ol > li:first-child, .art__related ul > li:first-child { border-top: 0; }

/* Long words and URLs must never push the column sideways. */
.art__body { overflow-wrap: break-word; }
.art__body pre, .art__body table { overflow-x: auto; max-width: 100%; }


/* ================================================================== *
 * Appearance: the control, and the few places a token cannot reach
 *
 * Every surface, rule and text tier in this stylesheet already reads
 * from a token, and src/generate/theme.js emits a second set of values
 * for those tokens under prefers-color-scheme and [data-theme="dark"].
 * So dark mode is almost entirely free: what follows is the control
 * itself, plus the handful of literal colours and baked-in images that
 * a variable could not have covered.
 * ================================================================== */

/* ---------- the control ---------- */
/* Pinned to the foot of the panel, the way the nameplate is pinned to its
   head. The section list is longer than a phone on every publication, so a
   control that simply sat at the end of it would be below the fold of a panel
   most readers never scroll. */
.drawer__pref {
  position: sticky; bottom: 0; margin-top: auto;
  padding: var(--space) var(--gutter);
  background: inherit; border-top: 1px solid rgb(127 127 127 / 0.45);
}
.tmode {
  display: flex; align-items: center; gap: var(--space); width: 100%;
  min-height: 48px; padding: 0; cursor: pointer;
  background: none; border: 0; color: inherit;
  font-family: var(--font-meta); font-size: var(--step-0); font-weight: 600;
  text-align: left;
}
.tmode__label { flex: 1 1 auto; min-width: 0; }
/* The state is a word, not a colour, and it is what aria-pressed announces. */
.tmode__state {
  flex: none; font-size: var(--step-n1); font-weight: 700;
  letter-spacing: var(--meta-tracking); text-transform: uppercase; opacity: 0.85;
}
/* A track and a knob. The knob MOVES, so the state is legible without relying
   on the fill colour - which is the same requirement as the printed word. */
.tmode__mark {
  flex: none; position: relative; width: 38px; height: 22px; border-radius: 11px;
  border: 1.5px solid currentColor; opacity: 0.85;
}
.tmode__mark::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 12px; height: 12px;
  border-radius: 50%; background: currentColor;
}
@media (prefers-reduced-motion: no-preference) {
  .tmode__mark::after { transition: transform 0.16s ease; }

/* ---- the masthead's copy of the appearance control ----

   The same button, the same hooks and the same words, shaped to read as the
   pair to the search pill rather than as a drawer row that escaped. It has to
   sit AFTER the base `.tmode` block: the two selectors have equal specificity,
   `.tmode` sets `width: 100%` and `min-height: 48px`, and placed earlier this
   lost on source order and rendered a 48px full-width control in a 38px bar.

   Metrics are `.hact`'s own at this breakpoint, not approximations of them, so
   Search and Dark mode are the same height on the same baseline. Below 62rem
   `.masthead__acts` is display:none, so this is desktop-only for free and the
   phone keeps its control in the drawer. */
.tmode--compact {
  width: auto; min-height: 38px; padding: 0 14px; gap: 8px;
  border: 1px solid currentColor; border-radius: 999px;
  font-size: var(--step-n1);
}
.tmode--compact:hover { background: rgb(255 255 255 / 0.14); }
/* The knob, scaled to the smaller control. */
.tmode--compact .tmode__mark { width: 30px; height: 17px; border-radius: 9px; }
.tmode--compact .tmode__mark::after { top: 2px; left: 2px; width: 10px; height: 10px; }
.tmode--compact[aria-pressed="true"] .tmode__mark::after { transform: translateX(13px); }
/* "Dark mode" is a word too many for a masthead pill. It stays in the button's
   accessible name - it is hidden from sight, not removed - and the STATE stays
   visible, so the control still never carries its state by colour alone. */
.tmode--compact .tmode__label {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.tmode--compact .tmode__state { opacity: 1; }
.lay-newspaper .tmode--compact { border-color: var(--border); }
}
.tmode[aria-pressed="true"] .tmode__mark { opacity: 1; }
.tmode[aria-pressed="true"] .tmode__mark::after { transform: translateX(16px); }
.tmode:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
/* The same phone density correction as the drawer above. */
@media (max-width: 61.99rem) {
  .drawer__pref { padding: 4px var(--gutter); }
  .tmode { min-height: 40px; }
}

/* ---------- what a token could not reach ---------- */

/* The masthead seam is white-at-18% so it works on both coloured bands. On the
   broadsheet, whose band is the page colour, it needs the ink rule in light and
   a lifted hairline in dark - the ink rule would vanish into a dark band. */
:root[data-theme="dark"] .lay-newspaper .masthead__band,
:root[data-theme="dark"] .lay-newspaper .nav { border-bottom-color: var(--rule); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lay-newspaper .masthead__band,
  :root:not([data-theme="light"]) .lay-newspaper .nav { border-bottom-color: var(--rule); }
}

/* The drawer in dark mode: exactly what each publication showed before.
 *
 * The panel's colours are tokens now, defaulting to the page's light surface,
 * so this block is the other half of that change rather than a new treatment.
 * Every value here is the one that was hard-coded before, restored.
 *
 * Daily All In keeps its nameplate green, which is what its panel has always
 * been; Sport Daily Mail keeps the five shades its restyle specified. Dayli
 * Mail Today is absent on purpose: its own `.lay-newspaper .drawer` rule sets
 * `background: var(--surface)` directly, at a higher specificity than the base
 * rule and in both schemes, so it was already correct and is untouched.
 *
 * The `.lay-desk` half is inside the phone query because that is where its
 * tokens are declared; outside it there is nothing for these to override.
 */
:root[data-theme="dark"] .drawer {
  --drawer-bg: var(--head-bg); --drawer-ink: var(--head-ink);
  --drawer-rule: rgb(127 127 127 / 0.45);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .drawer {
    --drawer-bg: var(--head-bg); --drawer-ink: var(--head-ink);
    --drawer-rule: rgb(127 127 127 / 0.45);
  }
}
@media (max-width: 61.99rem) {
  :root[data-theme="dark"] .lay-desk .drawer {
    /* NEAR-BLACK PANEL, CARDS RAISED OFF IT. The panel used to be #141619 and
       is now darker than that, because the rows are cards now and a card has
       to sit ON something: at #141619 under a #181B20 row the two were a
       point apart and the card edge was the only thing carrying the shape. */
    --dr-bg: #0D0F12; --dr-ink: #F2F3F5; --dr-ink-2: #C5C9CF;
    --dr-glyph: #D8DADF; --dr-rule: rgb(255 255 255 / 0.10);
    --dr-pref-label: #E2E4E8; --dr-pref-state: #B8BDC5;
    --dr-card: #181B20; --dr-card-edge: rgb(255 255 255 / 0.075);
    --dr-card-hover: #20242B;
    --dr-sub: #8E959F; --dr-group: #70777F;
    /* Not --accent. This title's dark accent is #FF4B54, and white on it is
       3.1:1 — under the 4.5 a 10px descriptor needs. A deeper red carries the
       same identity and clears it at 5.0:1. */
    --dr-lead: #D32F36;
  }
  /* The same thirteen, lightened for a near-black card. */
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="football"]      { --cat: #6FB1FF; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="analysis"]      { --cat: #8FB0FF; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="transfers"]     { --cat: #5FD08A; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="cricket"]       { --cat: #FF8A7A; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="rugby"]         { --cat: #B99BFF; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="tennis"]        { --cat: #D7E34F; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="motorsport"]    { --cat: #D6DAE0; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="golf"]          { --cat: #6FD3A8; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="us-sports"]     { --cat: #FFA96B; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="horse-racing"]  { --cat: #D8A06B; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="combat"]        { --cat: #FF7B74; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="darts-snooker"] { --cat: #C79BFF; }
  :root[data-theme="dark"] .lay-desk .drawer__link[data-cat="results"]       { --cat: #F0C45C; }
}
@media (max-width: 61.99rem) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lay-desk .drawer {
    /* NEAR-BLACK PANEL, CARDS RAISED OFF IT. The panel used to be #141619 and
       is now darker than that, because the rows are cards now and a card has
       to sit ON something: at #141619 under a #181B20 row the two were a
       point apart and the card edge was the only thing carrying the shape. */
    --dr-bg: #0D0F12; --dr-ink: #F2F3F5; --dr-ink-2: #C5C9CF;
    --dr-glyph: #D8DADF; --dr-rule: rgb(255 255 255 / 0.10);
    --dr-pref-label: #E2E4E8; --dr-pref-state: #B8BDC5;
    --dr-card: #181B20; --dr-card-edge: rgb(255 255 255 / 0.075);
    --dr-card-hover: #20242B;
    --dr-sub: #8E959F; --dr-group: #70777F;
    /* Not --accent. This title's dark accent is #FF4B54, and white on it is
       3.1:1 — under the 4.5 a 10px descriptor needs. A deeper red carries the
       same identity and clears it at 5.0:1. */
    --dr-lead: #D32F36;
  }
  /* The same thirteen, lightened for a near-black card. */
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="football"]      { --cat: #6FB1FF; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="analysis"]      { --cat: #8FB0FF; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="transfers"]     { --cat: #5FD08A; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="cricket"]       { --cat: #FF8A7A; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="rugby"]         { --cat: #B99BFF; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="tennis"]        { --cat: #D7E34F; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="motorsport"]    { --cat: #D6DAE0; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="golf"]          { --cat: #6FD3A8; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="us-sports"]     { --cat: #FFA96B; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="horse-racing"]  { --cat: #D8A06B; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="combat"]        { --cat: #FF7B74; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="darts-snooker"] { --cat: #C79BFF; }
  :root:not([data-theme="light"]) .lay-desk .drawer__link[data-cat="results"]       { --cat: #F0C45C; }
}

/* How far back a picture is seated in dark mode, per publication.
 *
 * The artwork is drawn at build time and cannot follow a token, so dark mode
 * dims it instead — the images only, never the whole page.
 *
 * One number could not do it, which is what this block originally assumed. The
 * wire and the desk draw on ink, so 0.86 was plenty and measures at 0% of
 * pixels above mid-grey. The broadsheet draws on paper: its thumbnails came out
 * at a mean luminance of 0.45 with 62% of their pixels above mid-grey, on a
 * page whose background is 0.006 — four near-white rectangles down a near-black
 * column, the brightest thing on the page and nothing to do with the story. */
:root { --art-dark: brightness(0.86) contrast(1.04); }
.lay-newspaper { --art-dark: brightness(0.62) contrast(1.08); }

:root[data-theme="dark"] .hero__media img,
:root[data-theme="dark"] .card__media img,
:root[data-theme="dark"] .compact__media img,
:root[data-theme="dark"] .feedrow__media img,
:root[data-theme="dark"] .art__media img { filter: var(--art-dark); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero__media img,
  :root:not([data-theme="light"]) .card__media img,
  :root:not([data-theme="light"]) .compact__media img,
  :root:not([data-theme="light"]) .feedrow__media img,
  :root:not([data-theme="light"]) .art__media img { filter: var(--art-dark); }
}

/* The stock dark-mode block this file shipped with predates the token system
   and would now fight it: it repainted body and .card directly, in colours no
   publication chose. The tokens carry the theme; this is retired. */

/* ------------------------------------------------------------------ *
 * WHOLE PHOTOGRAPHS IN THE HERO. FIXED FRAMES IN THE CARDS.
 *
 * THIS BLOCK USED TO NAME THE CARDS TOO, and that is what made the grids
 * ragged. Releasing a frame from its ratio and sizing it to the picture
 * (width: fit-content, height: auto, object-fit: contain, bounded by a
 * max-height) gives every card a DIFFERENT box: a portrait stops at its 320px
 * cap and narrows, a landscape fills the track and comes out half as tall. Four
 * peers in one row, four heights, four widths. Sport Daily Mail's "More Top
 * Stories" was the clearest case of it.
 *
 * The problem that block was written for was real, and it is not solved by
 * going back to 16:9: a portrait in a 16:9 box loses about two thirds of its
 * height. It is solved by the FRAME SHAPE plus the anchor. Peer cards now sit
 * in 4:3, which is a third taller than 16:9 for the same width, and the crop is
 * anchored by the shape and focus rules further up this file - is-portrait, the
 * per-layout anchors, the tall-file rule and an editor's own image_focus_y,
 * every one of which is still live and is what keeps a head in frame.
 *
 * WHAT STAYS ON THE WHOLE-PHOTOGRAPH IDIOM, and why it is only these two:
 *
 *   .hero__media   a front's lead is a designed one-off, not a peer. Nothing
 *                  lines up beside it, so a shape of its own costs nothing.
 *   .art__media    the article's own photograph, shown whole. Never named in
 *                  this block, before or now - its rules are above and this
 *                  change does not reach them.
 *
 * THIS IS THE ARTICLE PAGE'S OWN IDIOM, and it stays where it belongs.
 * .art__media has used width:auto/height:auto/max-height for its portraits
 * since the lead plate was fixed, the hero borrows it, and the cards no longer
 * do. The article rules are untouched and still sit above; this block has never
 * named .art__media and still does not.
 *
 * THE HERO FRAME SHRINKS TO THE PICTURE (width: fit-content) rather than
 * standing a portrait in the middle of a wide panel. In a card that would be
 * the ragged-row fault above; in a hero, which has nothing beside it to line up
 * with, it is simply the picture at its own shape.
 *
 * TALL PICTURES ARE BOUNDED, not cropped: --media-cap is a max-height per
 * context, so a 2:3 portrait is scaled down proportionally instead of making
 * the page unusably long. The width/height attributes are the file's own, so
 * the browser still reserves the right box before the image arrives.
 *
 * The inline object-position mediaHtml emits is inert on THIS frame, because
 * with both dimensions auto there is no crop to anchor. On the cards it is live
 * again, and it is the whole reason a 4:3 crop is safe to reinstate: an editor's
 * image_focus_y, and the tall-file rule below 0.70, both land on a frame that
 * now crops.
 *
 * One thing about how that value is produced DID have to change. focusY() read
 * a NULL image_focus_y as a stored 0 - Number(null) is 0 - so every card image
 * on all three sites carried an inline anchor of 0% and none of the anchors
 * below could ever apply. Inert under contain, decisive under cover.
 * ------------------------------------------------------------------ */
.hero__media {
  aspect-ratio: auto;
  height: auto;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero__media img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--media-cap, 320px);
  aspect-ratio: auto;
  object-fit: contain;
  display: block;
}

/* One cap, for the one frame that is still sized by its picture. The card caps
   are gone with the rules that needed them: a frame with a ratio takes its
   height from its width and has nothing to cap. */
.hero__media { --media-cap: min(64vh, 520px); }

@media (max-width: 47.99rem) {
  /* A phone screen is the constraint, not a number: a lead that takes more
     than half the first screen pushes the story off it. */
  .hero__media { --media-cap: min(52vh, 360px); }
}


/* ---------- the phone's first screen ----------
   Everything here is a MEASURED cut against the reference phone, which is a
   212x442 artboard screen — a 390x844 viewport at 1.84x — read band by band:

                       live   reference
     masthead bar       54        55
     tab rail           45        57
     score module      223       151
     hero start Y      335       263
     bottom nav         55        61

   The masthead was already at the reference's height and is not touched. The
   score module is the whole of the difference, and it is what pushed the hero
   down a screen.

   LAST IN THE FILE ON PURPOSE. Several of these selectors are the same
   specificity as rules in the density pass above, so source order is what
   decides them. */
/* THE SCORE MODULE: THREE BANDS OF CHROME ABOVE THE FIRST FIXTURE, NOW TWO.
   The reference gives this band 151px of a 390px screen. This was 223, and
   every one of the extra 72 was chrome above the first fixture: the label and
   the all-results link on one row, a scrolling chip row under them, and the
   odds chip under THAT, three bands deep before a score.
   The odds chip and the filters share a row instead. The chip keeps a column
   of its own rather than joining the scroller, so the one control here that is
   a business requirement can never be scrolled out of sight — it is pinned at
   the left of the row and the competitions scroll beside it. Nothing is
   removed and nothing is made less reachable; the three rows become two. */
@media (max-width: 47.99rem) {
  .lay-desk .scores__in { padding-block: 5px; }
  .lay-desk .scores__top {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 6px 10px; margin-bottom: 6px;
  }
  .lay-desk .scores__top .scores__label { grid-column: 1; grid-row: 1; }
  .lay-desk .scores__top .scores__all { grid-column: 2; grid-row: 1; justify-self: end; }
  .lay-desk .scores__top [data-odds] { grid-column: 1; grid-row: 2; }
  .lay-desk .scores__top .schips { grid-column: 2; grid-row: 2; }
  /* Both rows to a single compact line each. */
  .lay-desk .scores__label { font-size: 10px; }
  .lay-desk .scores__all { font-size: 11px; }
  .lay-desk .scores__top .schip { padding: 3px 9px; font-size: 10px; }
  /* The card: the competition label needs 20px of clearance above the crests,
     not 24, and the team name sits closer under them. */
  .lay-desk .scores .mcard { padding: 20px 10px 8px; }
  .lay-desk .scores .mcard__comp { top: 6px; }
  .lay-desk .scores .mcard__side { gap: 3px; }
  /* The two controls that were setting their rows' heights: a 30px tap target
     on the all-results link and a 36px odds chip. Both stay above the 24px a
     thumb needs, and neither is any longer the tallest thing in a row whose
     type is 10px. */
  .lay-desk .scores__all { min-height: 24px; }
  /* SCOPED TO THE MODULE, NOT TO THE HEADER ROW. This was written as
     `.scores__top [data-odds]` when the chip was a child of the header; the
     pass that moved it below the fixtures — where the reference puts it — left
     the selector behind, so it stopped matching and the chip went back to its
     full 36px. That was the whole of the 13px this module still stood above the
     reference by. 24px is kept deliberately: it is the WCAG 2.5.8 target size
     and this chip is a link. Nothing about the odds CTA's behaviour, its
     eligibility or its destination is touched here — only how tall it is. */
  .lay-desk .scores [data-odds] {
    min-height: 24px; padding: 2px 9px; font-size: 10px;
  }
  /* THE LAST SIXTEEN PIXELS, and they come from here rather than from the hero.
     The plate above is the reference's own 19:18 and is not negotiable; the
     module is what pays for it. Four from the band's rules, which are 3px of
     ink either side of a band that is already separated by its own background;
     nine from the two header rows; three from the rail's own padding. The
     module lands on the reference's 151 and the hero starts where the
     reference starts it. */
  .lay-desk .scores { border-block-width: 1px; }
  .lay-desk .scores__top { gap: 4px 10px; margin-bottom: 4px; }
  .lay-desk .scores__top .schip { padding: 2px 9px; }
  .lay-desk .scores__rail { padding-bottom: 0; }

  /* ---- REFERENCE B: the competition chips are not on the phone ----
     The new mobile reference has no filter row in this module at all: a live
     label and an all-results link, one fixture with the next peeking, and the
     odds row. The filter is a secondary control and it was taking a row of the
     first screen to be one. It is not lost — "See all live" goes to Results,
     which carries every fixture and the full filter — it is simply not the
     first thing a thumb meets. */
  .lay-desk .scores__top .schips { display: none; }
  .lay-desk .scores__top { grid-template-columns: minmax(0, 1fr) auto; }
  .lay-desk .scores__top .scores__label { grid-column: 1; grid-row: 1; }
  .lay-desk .scores__top .scores__all { grid-column: 2; grid-row: 1; justify-self: end; }
  .lay-desk .scores__top [data-odds] { grid-column: 1 / -1; grid-row: 2; }
  /* ONE FIXTURE, AND THE NEXT ONE PEEKING. The reference gives the main card
     289 of 390 and lets 78 of the next show, which is what says "swipe" without
     a control that has to be drawn. */
  .lay-desk .scores__rail .mcard { flex-basis: 289px; }

  /* ---- REFERENCE B: Top Stories is not in a box ----
     The reference runs the heading, a More News link and the rows straight down
     the page with hairlines between them. The panel's border, background and
     padding are desktop furniture; on a phone they wrap editorial content in a
     widget. */
  .lay-desk .fblock__side .panel,
  .lay-desk .fblock__third .panel {
    border: 0; background: none; border-radius: 0;
  }
  .lay-desk .fblock__side .panel__head,
  .lay-desk .fblock__third .panel__head { padding: 0 0 7px; }
  .lay-desk .fblock__side .panel__body,
  .lay-desk .fblock__third .panel__body { padding: 10px 0 0; }
  /* 18px, WHICH IS THE REFERENCE'S OWN BAND HEADING. Measured rather than
     eyeballed, and measured by cap height rather than by width, because the
     mockup is set in a different face and its letterforms are narrower: the
     reference's "Top Stories" has a 12.3px cap, which for a humanist sans is
     about 17.5px of type, against the 23.1px this was setting — a third larger
     than the thing it is meant to match. The rows under it are 14px, so the
     step down to them is still clear. */
  .lay-desk .fblock__side .panel__name,
  .lay-desk .fblock__third .panel__name { font-size: 18px; }
  /* Explore's heading is the same size as Top Stories' in the reference, and
     was the same 23.1px here. */
  .lay-desk .band--explore .band__name { font-size: 18px; }
  /* "More News" is sentence case beside the heading in the reference, not the
     meta scale's tracked-out capitals. The same correction the bottom bar's
     labels needed, and for the same reason: the uppercase meta idiom belongs to
     kickers and timestamps, not to a link a reader is meant to read as words. */
  .lay-desk .fblock__side .panel__head a,
  .lay-desk .fblock__third .panel__head a {
    text-transform: none; letter-spacing: 0; font-size: 12px;
  }
  /* ONE HAIRLINE BETWEEN ROWS, NOT TWO.
     `.sidelist > li` already carries a border-BOTTOM, so adding a border-top to
     `li + li` drew both, with the list's 11px gap between them — two rules
     where the reference has one, which the live capture shows once you know to
     look. The existing bottom border is the one that was there
     first, so it is the one that stays, and the last row loses it because
     nothing follows it to be divided from. */
  .lay-desk .fblock__side .sidelist > li {
    padding-bottom: 5px; border-bottom: 1px solid var(--rule);
  }
  .lay-desk .fblock__side .sidelist > li:last-child {
    padding-bottom: 0; border-bottom: 0;
  }
  /* Beating `.lay-desk .fblock__side .panel__body > .sidelist`, which is four
     classes and set the 11px this could not otherwise reach. */
  .lay-desk .fblock__side .panel__body > .sidelist { gap: 4px; }
  /* The reference's thumbnail is 114x63 of a 390px screen — a landscape still
     from the story, not a stamp. The desktop rail's 76px 4:3 is sized for a
     310px column and reads as a thumbnail when the row is the full width of a
     phone. */
  .lay-desk .fblock__side .sidelist .compact { --thumb: 112px; gap: 12px; }
  .lay-desk .fblock__side .compact__media.is-1x1 { aspect-ratio: 16 / 9; }
  .lay-desk .fblock__side .compact__title { font-size: 14px; }

  /* ---- THE THUMBNAIL IS 16:9, AND THE PASS THAT MADE IT 3:2 WAS WRONG ----
     That change was argued from a measurement of the mockup taken at the wrong
     scale: the screen was read as 920 image px wide when it is 890, with the
     left edge 15px out, which stretched every width read off it. Re-measured
     against a pixel grid pinned to the mockup's own content edge, the
     reference's thumbnail is 114x63 — 16:9, which is where this started. It is
     the SHORT element in the row, not the tall one, so the text column governs
     the row height and the picture sits inside it.

     The kicker and meta stay tight, which was the sound half of that pass. What
     cannot come off is the 24px floor under `.compact__cat`: it is a link, and
     that is the WCAG 2.5.8 target size. It is why these rows repeat every ~86px
     against the reference's 70 and cannot go lower without taking a tap target
     below its minimum. */
  .lay-desk .fblock__side .compact__cat {
    font-size: 10px; line-height: 1.4; padding: 0; margin: 0;
    text-transform: uppercase; letter-spacing: 0.06em;
  }
  .lay-desk .fblock__side .compact__meta { line-height: 1.35; }

  /* ---- REFERENCE B: Explore is a carousel of real cards ----
     Wide enough to read as photographs — two and a half of them across a 390px
     screen, with the next one peeking — rather than the ten-across desktop row
     shrunk onto a phone. */
  .lay-desk .tiles { grid-auto-columns: 150px; gap: 9px; }

  /* ---- the masthead, at the reference's own height ---- */
  /* THE GUTTER CAME OFF BY ACCIDENT. Compacting this bar to the reference's
     height was written as `padding: 7px 0`, and the 0 silently undid the
     `padding-inline` the block above sets for every publication — the one whose
     own comment explains that without it "the wordmark sat hard against the
     viewport edge". So the masthead alone had no left margin while every band
     under it kept one. Both numbers, named together, so trimming the height
     cannot drop the inset again. */
  .lay-desk .masthead__bar { min-height: 0; padding: 5px calc(var(--space) * 2); }
  /* AND THE WORDMARK SITS AT THAT GUTTER. `.brand` is centred for the two
     titles that centre their nameplate; this one does not, and the centring put
     the logo 45px in from a left edge the reference starts at. Its own 3px of
     vertical padding goes too — the bar's padding is the bar's job. */
  .lay-desk .masthead__bar .brand { text-align: left; padding: 0; }
  .lay-desk .brand__logo { --brand-logo-h: 27px; }
  .lay-desk .brand__tag { display: none; }

  /* ---- the section rail: 34px in the reference, 45 here ----
     The chips were sized as tap targets first and read as a row of buttons;
     the reference's are text with one pill on the active one. 32px of row
     still clears the 24px a thumb needs with the tap area the padding gives. */
  .lay-desk .tabs--rail .tabs__list { gap: 2px; }
  .lay-desk .tabs--rail .tabs__t {
    min-height: 32px; padding: 0 11px; font-size: 13px;
  }
  /* THE ACTIVE CHIP IS A RED PILL, which is the reference's own treatment and
     this title's accent. The underline it had was the desktop bar's idiom
     brought down to a row that is not the desktop bar. */
  .lay-desk .tabs--rail .tabs__t.is-on {
    background: var(--accent); color: var(--accent-ink);
    border-radius: 999px; box-shadow: none;
  }
  .lay-desk .tabs--rail .tabs__t.is-on::after { display: none; }

  /* ---- the bottom bar: 38px in the reference ----
     A 55px bar on an 844px screen is a twentieth of it standing on every page.
     The glyph and its label still stack, and the cell is still 44px of tappable
     height once the safe-area padding is counted. */
  .lay-desk .bbar__i { min-height: 38px; gap: 1px; font-size: 10px; }
  .lay-desk .bbar__i .ico { width: 19px; height: 19px; }
  /* SENTENCE CASE AND AN ACTIVE CELL, both of which the reference draws and
     neither of which this bar had: the labels were the meta scale's uppercase
     and every cell was the same colour, so the bar never said where you were. */

  /* The band heads lose the desktop rule on a phone. The reference runs
     "Top Stories" and a More News link over the rows with nothing drawn under
     them; a 3px accent rule under every heading is the desktop grid's idiom. */
  .lay-desk .fblock__side .panel__head,
  .lay-desk .fblock__third .panel__head { border-bottom: 0; }
  .lay-desk .band--explore .band__head { border-bottom-width: 1px; }
  /* And the rule ABOVE Top Stories goes with them. It says "the lead is
     finished, what follows is a list", which is true and is drawn for the
     other three titles; on this one the lead is now a full-bleed card with its
     own edge, so the 2px of near-white ink above the heading is a second
     divider for a division already made. */
  .lay-desk .fblock__side { border-top: 0; padding-top: 0; }
}
