/* =====================================================================
   Landing page — the public front door.

   Token-only, like every sheet except tokens.css: the landing wears the
   product's exact identity (same ground, same teal, same mono voice) so
   the page someone signs in FROM and the page they land ON are visibly
   the same product. Marketing gets more air, not different clothes:
   the spacing steps up, the palette does not.
   ===================================================================== */

.ld-page {
  min-height: 100vh;
  background:
    radial-gradient(1100px 500px at 15% -5%, var(--page-bloom-1), var(--page-bg-fade) 60%),
    radial-gradient(900px 460px at 90% 12%, var(--page-bloom-2), var(--page-bg-fade) 55%),
    var(--color-bg);
  background-attachment: fixed;
  color: var(--color-text);
  font-family: var(--font-body);
}

.ld-page section,
.ld-top,
.ld-foot-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding-left: var(--sp-5);
  padding-right: var(--sp-5);
}

/* ---- shared voice ------------------------------------------------- */

.ld-eyebrow {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-accent);
  margin: 0 0 var(--sp-2);
}

.ld-page h1 {
  font-size: clamp(var(--fs-display), 4.6vw, 46px);
  font-weight: var(--font-heading-weight);
  letter-spacing: -0.02em;
  line-height: 1.08;
  margin: 0 0 var(--sp-4);
  text-wrap: balance;
}

.ld-page h2 {
  font-size: var(--fs-2xl);
  font-weight: var(--font-heading-weight);
  letter-spacing: -0.01em;
  margin: 0 0 var(--sp-4);
  text-wrap: balance;
}

.ld-page h3 {
  font-size: var(--fs-body);
  font-weight: 500;
  margin: 0 0 var(--sp-2);
}

.ld-page p { line-height: 1.6; }

/* ---- top bar ------------------------------------------------------ */

.ld-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-top: var(--sp-4-5);
  padding-bottom: var(--sp-4-5);
}

.ld-brand { display: flex; align-items: baseline; gap: var(--sp-2); }
.ld-brand-mark { color: var(--color-accent); font-size: var(--fs-lg); }
.ld-brand-name { font-weight: 600; font-size: var(--fs-body); }
.ld-brand-sub {
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim-2);
}

.ld-top-nav { display: flex; align-items: center; gap: var(--sp-4-5); }
.ld-top-nav a {
  color: var(--dim);
  text-decoration: none;
  font-size: var(--fs-sm-2);
  transition: color var(--t-fast) var(--ease);
}
.ld-top-nav a:hover { color: var(--color-text); }

/* ---- buttons ------------------------------------------------------ */

.ld-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-2-5) var(--sp-4-5);
  border-radius: var(--radius-md);
  font-size: var(--fs-md-2);
  font-weight: 500;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.ld-btn:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }

.ld-btn-primary {
  background: var(--color-accent-800);
  color: var(--color-accent-200);
  box-shadow: inset 0 0 0 1px var(--accent-ring-soft);
}
.ld-btn-primary:hover {
  background: var(--color-accent-700);
  color: var(--color-accent-100);
}

.ld-btn-ghost {
  color: var(--dim);
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.ld-btn-ghost:hover { color: var(--color-text); box-shadow: inset 0 0 0 1px var(--accent-ring-soft); }

/* ---- hero --------------------------------------------------------- */

.ld-hero {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--sp-8);
  align-items: center;
  padding-top: var(--sp-8);
  padding-bottom: var(--sp-8);
}

.ld-lede {
  color: var(--dim);
  font-size: var(--fs-lg);
  max-width: 34em;
  margin: 0 0 var(--sp-6);
}

.ld-cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.ld-cta-note {
  font-family: var(--mono);
  font-size: var(--fs-xs-2);
  color: var(--dim-2);
  margin: var(--sp-3) 0 0;
}

.ld-hero-cards {
  display: grid;
  gap: var(--sp-3);
  align-content: start;
}

.ld-illustrative {
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim-2);
  margin: 0;
}

.ld-kpi {
  background: var(--panel);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: var(--sp-3-5) var(--sp-4);
  display: grid;
  gap: var(--sp-05);
}
.ld-kpi-label {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}
.ld-kpi-value {
  font-family: var(--mono);
  font-size: var(--fs-kpi);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.ld-kpi-unit { font-size: var(--fs-lg); color: var(--dim); }
.ld-kpi-sample { font-size: var(--fs-xs-2); color: var(--dim-2); }

/* ---- the live demo ------------------------------------------------
   The one section on this page whose subject is a MOVING PICTURE, and the
   only layout family here that is not a row of cards. That is deliberate:
   it sits directly under the hero, it is the page's proof rather than
   another claim, and a card grid around it would file the product's one
   irreducible difference next to five paragraphs about denominators.

   The frame is the page's own panel vocabulary at the next radius up —
   `--panel`, a 1px inset hairline, `--radius-lg` — so a live 3D viewer
   reads as a component of this page rather than as an embed dropped onto
   it. Nothing glows and nothing floats: the picture inside is the loud
   part, and a frame competing with it would be the frame winning.
   ------------------------------------------------------------------- */

.ld-demo { padding-top: var(--sp-8); padding-bottom: var(--sp-6); }

.ld-demo-lede {
  color: var(--dim);
  font-size: var(--fs-base);
  max-width: 52em;
  margin: 0 0 var(--sp-5);
}

.ld-demo-stage { margin: 0; }

/* THE ONE RULE THAT PREVENTS A LAYOUT SHIFT. The frame reserves its box from
   the first painted pixel — an aspect ratio, not a height the content
   decides — so the poster arriving, and then a 3D viewer arriving on top of
   it, move nothing on the page beneath.

   3/2 AND NOT 16/9, and that is a measurement. The viewer stacks a top bar,
   a round strip, two five-man scoreboards and a transport block; at 1040
   wide, 16/9 gives it 585px and the second scoreboard is cut through its
   fourth row, which reads as a rendering fault rather than as a crop. 3/2
   gives 693px, where nine of the ten names clear the transport bar. The
   tenth needs about 760px, which is more of a laptop screen than a section
   under a hero can honestly ask for.

   `max-height` is the other half of the same thought: on a short laptop a
   693px frame plus the section's own heading is more than the screen, and a
   demo whose bottom edge you never see is a demo whose Play control is off
   screen. Capping the height and leaving the width alone changes the ratio
   rather than the size, which the viewer inside handles by being fluid and
   the poster handles with `object-fit`. */
.ld-demo-frame {
  position: relative;
  aspect-ratio: 3 / 2;
  max-height: 78vh;
  margin-inline: auto;
  overflow: hidden;
  background: var(--panel);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 0 0 1px var(--line);
}

/* A SCRIM, and only while the poster is what is on screen. The play control
   is a filled accent button sitting on a screenshot of a dark analysis tool,
   and a dark button on a dark picture is a contrast problem however good the
   button's own colours are. This pushes the middle of the frame down half a
   stop so the control reads at a glance, and lifts off with the poster —
   there is nothing over the live viewer, ever. */
.ld-demo-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(60% 60% at 50% 50%,
              color-mix(in srgb, var(--color-bg) 74%, transparent),
              color-mix(in srgb, var(--color-bg) 16%, transparent) 70%,
              transparent 100%);
  transition: opacity var(--t-enter) var(--ease);
  /* Generated content paints after every child, so without this the scrim
     would sit on top of the button it exists to make readable. Two values,
     used nowhere else on this page, and both are declared right here rather
     than in a scale nobody would find. */
  z-index: 1;
}
.ld-demo-stage.is-loading .ld-demo-frame::after { opacity: 0; }

.ld-demo-poster,
.ld-demo-live {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
}

.ld-demo-poster { object-fit: cover; object-position: center; }

/* The iframe sits ON the poster and fades in over it when the viewer has
   booted, which is why the poster is still underneath rather than removed:
   the swap is one opacity change on an element that was already there, so
   there is no frame in which the box is empty. Until then the frame is not
   in the layout at all (`visibility`), because a 0-opacity iframe still
   takes pointer events and would swallow the click on the play control. */
.ld-demo-live {
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--t-enter) var(--ease);
}
.ld-demo-stage.is-loading .ld-demo-live { visibility: visible; }
.ld-demo-stage.is-live .ld-demo-live { opacity: 1; }
.ld-demo-stage.is-live .ld-demo-poster { opacity: 0; }

.ld-demo-poster { transition: opacity var(--t-enter) var(--ease); }

/* THE PLAY CONTROL. A link that the enhancement upgrades, so it is styled as
   the page's own ghost button rather than as a media-player chrome overlay:
   this is the landing page's language, not the viewer's, and the viewer's
   language starts at the edge of the frame. */
.ld-demo-play {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2-5);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-md);
  /* `.ld-btn-primary`'s exact three declarations, not a lookalike. The page has
     one filled button and this is it, standing somewhere else. Its separation
     from the picture behind comes from the scrim above rather than from a drop
     shadow, which would have been the page's only one. */
  background: var(--color-accent-800);
  color: var(--color-accent-200);
  box-shadow: inset 0 0 0 1px var(--accent-ring-soft);
  font-size: var(--fs-md-2);
  font-weight: 500;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.ld-demo-play:hover {
  background: var(--color-accent-700);
  color: var(--color-accent-100);
}
.ld-demo-play:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 3px; }
.ld-demo-play-mark { display: inline-flex; }
.ld-demo-play-mark svg { fill: currentColor; }

/* Visible until the demo is actually starting, and then gone. NOT hidden as
   soon as the script decides it will handle the start: on a tall screen the
   whole frame can be on view without a scroll ever happening, and a poster
   with its only affordance removed in anticipation of a scroll that never
   comes is a dead end. The button costs a moment on screen during a normal
   scroll-through, which is what a poster with a play button looks like
   everywhere else on the web.

   The state lives in one class on the stage rather than in an inline style
   the script writes, so every rule that reads it is in this file. */
.ld-demo-stage.is-loading .ld-demo-play { display: none; }

/* The caption carries a DISCLOSURE ("the names are replaced"), not a footnote,
   so it takes `--dim` rather than the `--dim-2` this page gives its quiet
   labels. The mono meta beside it is a label and takes the quieter one. */
.ld-demo-note {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1-5) var(--sp-3);
  margin: var(--sp-3) 0 0;
  color: var(--dim);
  font-size: var(--fs-xs-2);
  line-height: 1.5;
}
.ld-demo-meta {
  font-family: var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim-2);
}

/* THE KEYBOARD'S WAY IN, and the reason it is permanent.
   The frame carries `tabindex="-1"` so that tabbing down this page does not
   drop a reader into a forty-control 3D viewer they then have to tab back out
   of. That is the right call for a marketing page and it leaves a hole: once
   the demo has started by itself, the play control is gone and a keyboard-only
   reader has no route to the viewer at all. This link is that route, it is in
   the tab order from first paint, and it is useful to everybody else too —
   the viewer with the whole window is better than the viewer in a frame. */
.ld-demo-open {
  color: var(--color-accent);
  text-decoration: none;
  box-shadow: inset 0 -1px 0 var(--accent-ring-soft);
  transition: box-shadow var(--t-fast) var(--ease);
}
.ld-demo-open:hover { box-shadow: inset 0 -1px 0 var(--color-accent); }
.ld-demo-open:focus-visible { outline: 2px solid var(--accent-ring); outline-offset: 2px; }
/* The desktop sentence only appears where it is true, which is the same
   discipline the rest of this product applies to a note about a state. */
.ld-demo-desk { display: none; }

/* ---- doctrine ----------------------------------------------------- */

.ld-doctrine { padding-top: var(--sp-8); padding-bottom: var(--sp-6); }

.ld-doctrine-grid,
.ld-feature-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3-5);
}

.ld-tenet,
.ld-feature {
  background: var(--panel);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: var(--sp-4-5);
}
.ld-tenet p, .ld-feature p { color: var(--dim); font-size: var(--fs-sm-2); margin: 0; }
.ld-tenet-mark { color: var(--color-accent); font-family: var(--mono); }

/* ---- solo / team doors -------------------------------------------- */

.ld-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3-5);
  padding-top: var(--sp-6);
  padding-bottom: var(--sp-6);
}

.ld-door {
  background: linear-gradient(128deg, var(--panel-2), var(--panel) 65%);
  border-radius: var(--radius-lg);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: var(--sp-6);
}
.ld-door p { color: var(--dim); font-size: var(--fs-base); margin: 0; }

/* ---- features ----------------------------------------------------- */

.ld-features { padding-top: var(--sp-6); padding-bottom: var(--sp-6); }

/* ---- pricing ------------------------------------------------------ */

.ld-pricing { padding-top: var(--sp-6); padding-bottom: var(--sp-6); }

.ld-pricing-note {
  color: var(--dim);
  font-size: var(--fs-base);
  max-width: 44em;
  margin: 0 0 var(--sp-5);
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent-wash);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--accent-ring-soft);
}

.ld-tier-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3-5);
}

.ld-tier {
  background: var(--panel);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: var(--sp-4-5);
  display: grid;
  align-content: start;
  gap: var(--sp-2);
}
.ld-tier[data-tier="teams"] { box-shadow: inset 0 0 0 1px var(--accent-ring-soft); }
.ld-tier-lede { color: var(--dim); font-size: var(--fs-sm-2); margin: 0; }
.ld-tier ul {
  margin: 0;
  padding-left: var(--sp-4-5);
  color: var(--dim);
  font-size: var(--fs-sm-2);
  display: grid;
  gap: var(--sp-1-5);
}
.ld-tier-price {
  font-family: var(--mono);
  font-size: var(--fs-xs-2);
  color: var(--dim-2);
  margin: var(--sp-2) 0 0;
}

/* ══ THE LEAGUE, THE PIPELINE AND THE SCHEDULE ═══════════════════════════
   Three sections that share one job: turning the page's claims into things a
   visitor can check. They are also the page's densest markup, and the rules
   below are the only ones here that style DATA rather than prose.

   ONE NEW IDEA IN THE TYPE, AND IT IS THE PRODUCT'S OWN: numerals are mono and
   tabular everywhere a column of them appears. That is not decoration and it is
   not "technical-looking" — a proportional 1 in a points column is narrower
   than a proportional 8, and ten rows of that do not line up. `--mono` with
   `font-variant-numeric: tabular-nums` is what the product's own tables use and
   what the hero's KPI values above already use.

   NO EYEBROWS ON THESE THREE. Every section above this point opens with a mono
   caps label, and these do not: what sits where the label would is a line that
   carries FACTS (the competition and its span, a connector's state, a stage's
   place in a sequence). Same voice, same scale, same colour — doing work. Where
   there was nothing true to say in that slot, the heading carries the section on
   its own.
   ════════════════════════════════════════════════════════════════════════ */

.ld-league,
.ld-pipe,
.ld-sched { padding-top: var(--sp-6); padding-bottom: var(--sp-6); }

.ld-league-lede,
.ld-pipe-lede {
  color: var(--dim);
  font-size: var(--fs-body);
  /* The measure this page keeps everywhere: ~65-75 characters. */
  max-width: 54ch;
  margin: 0 0 var(--sp-6);
}

/* ---- the league: table beside the rail ----------------------------- */

/* 7fr/4fr rather than 2/1: the table has four columns and the widest club name
   in a real Norwegian division is "Mango's Disipler", which needs the room. The
   rail is a list of three short blocks and reads fine narrow. */
.ld-league-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: var(--sp-8);
  align-items: start;
}

.ld-table-wrap { margin: 0; min-width: 0; }

.ld-table {
  width: 100%;
  border-collapse: collapse;
  /* `fixed` so the two number columns cannot be widened by a long club name
     pushing them around; the percentages below then hold across every row. */
  table-layout: fixed;
}

/* A caption, and it is the table's own heading rather than a paragraph above
   it: a screen reader announcing this table says which competition it is and
   how much of it there is, in that order, before reading a single row. */
/* NOT `display: grid`. A caption that is given a non-table display box stops
   being laid out against the table's width and shrink-to-fits inside the first
   column instead, which wraps "GG Arena · 1. divisjon" one word to a line. The
   two lines are stacked by making the CHILDREN blocks, which leaves the caption
   itself a caption. */
.ld-table-cap {
  caption-side: top;
  text-align: left;
  padding-bottom: var(--sp-3);
}
.ld-table-name,
.ld-table-basis { display: block; }
.ld-table-name {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--color-text);
  margin-bottom: var(--sp-05);
}
.ld-table-basis {
  font-family: var(--mono);
  font-size: var(--fs-xs-2);
  font-variant-numeric: tabular-nums;
  color: var(--dim-2);
}

.ld-table thead th {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim-2);
  text-align: left;
  padding: 0 var(--sp-2) var(--sp-2);
  border-bottom: 1px solid var(--line-2);
}
.ld-th-pos { width: 2.4rem; }
.ld-th-num { width: 4.2rem; text-align: right; }

.ld-table tbody td {
  padding: var(--sp-2-5) var(--sp-2);
  /* ONE hairline per row and it is the bottom one. A row with a border top AND
     bottom is the doubled rule that makes a ten-row table look like a ledger
     printout; the last row's is removed below so the table does not end on a
     line with nothing under it. */
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}
.ld-table tbody tr:last-child td { border-bottom: 0; }

.ld-td-pos,
.ld-td-num {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--dim);
}
.ld-td-num { text-align: right; }
.ld-td-pts { color: var(--color-text); font-size: var(--fs-md); }
.ld-td-pos { color: var(--dim-2); }

/* Name and form on one line, the bar spanning under both. Stacked in three
   lines instead, ten rows came to 650px and the table stopped being scannable —
   which is the whole job of a standings table. */
.ld-td-team {
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
}
.ld-td-name {
  grid-column: 1;
  font-size: var(--fs-sm-2);
  /* A long club name truncates rather than wrapping a row to two lines: the
     table's rhythm is the thing a reader scans, and one double-height row in
     ten breaks it. The full name is in the DOM for anyone who needs it. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The share-of-leader bar, under the name where it reads as an underline rather
   than as a chart. 2px: any taller and it competes with the points column for
   the same fact. */
.ld-td-bar {
  grid-column: 1 / -1;
  grid-row: 2;
  display: block;
  height: 2px;
  background: var(--line);
  border-radius: 1px;
  overflow: hidden;
}
.ld-td-bar > span {
  display: block;
  height: 100%;
  width: var(--bar);
  background: var(--color-accent-700);
  border-radius: inherit;
}

/* ---- the form strip ------------------------------------------------ */

.ld-form { grid-column: 2; grid-row: 1; display: flex; gap: 3px; }
.ld-form-m {
  font-family: var(--mono);
  font-size: var(--fs-micro-2);
  font-weight: 600;
  line-height: 1;
  width: 13px;
  height: 13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 2px;
  /* Colour is never the only carrier: the letter IS the mark, and the wash
     behind it is the second reading. A colour-blind reader loses nothing, and
     the aria-label on the strip spells the whole sequence anyway. */
  background: var(--panel-3);
  color: var(--dim-2);
}
.ld-form-m[data-mark="W"] { background: var(--accent-wash-4); color: var(--color-accent-300); }
.ld-form-m[data-mark="D"] { background: var(--panel-3); color: var(--dim); }

/* ---- the connector rail -------------------------------------------- */

.ld-conns { min-width: 0; }
.ld-conns-head {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim-2);
  margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line-2);
}
.ld-conn-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }

/* No card. Three bordered boxes stacked in a narrow column would be three
   nested rectangles inside a section that already has a table beside it; the
   separation these need is space, which they have. */
.ld-conn { display: grid; gap: var(--sp-1-5); }
.ld-conn-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: 0;
}
.ld-conn-name { font-size: var(--fs-sm-2); font-weight: 500; }

/* The state, as a word. `Live` takes the accent because it is the page's one
   affirmative state and the accent is this product's yes; `Coming` is dim,
   which is the honest weight for a thing that is not here. */
.ld-conn-state {
  font-family: var(--mono);
  font-size: var(--fs-micro-2);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 2px var(--sp-1-5);
  border-radius: var(--radius-sm);
  white-space: nowrap;
  background: var(--panel-3);
  color: var(--dim-2);
}
.ld-conn[data-state="live"] .ld-conn-state {
  background: var(--accent-wash-3);
  color: var(--color-accent-300);
}
.ld-conn-scopes {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  color: var(--dim-2);
  margin: 0;
}
.ld-conn-note {
  font-size: var(--fs-xs-2);
  color: var(--dim);
  line-height: 1.55;
  margin: 0;
}
/* The one that is not here yet reads quieter than the two that are, all the way
   through and not only in its badge. */
.ld-conn[data-state="coming"] .ld-conn-name { color: var(--dim); }

/* ---- the pipeline -------------------------------------------------- */

/* A numbered sequence, which is the one case a number earns its place: these
   four things happen in this order and the order is the content. The counter is
   drawn rather than left to the list marker so it can sit ON the rule that
   connects the stages. */
/* The stages beside the narrow crop. The crop's column is sized in `px` and not
   in `fr` because it holds an IMAGE with a fixed pixel width (454), and the one
   thing this layout must not do is scale a screenshot of 11px type. Everything
   else takes what is left. */
.ld-pipe-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 454px;
  gap: var(--sp-8);
  align-items: start;
  margin-bottom: var(--sp-6);
}

.ld-stages {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: stage;
  display: grid;
  gap: var(--sp-5);
}
.ld-stage {
  counter-increment: stage;
  position: relative;
  padding-left: var(--sp-8);
}
.ld-stage::before {
  content: counter(stage);
  position: absolute;
  left: 0;
  top: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--accent-ring-soft);
  background: var(--accent-wash);
  color: var(--color-accent-300);
  font-family: var(--mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}
.ld-stage h3 { margin: 0 0 var(--sp-1-5); font-size: var(--fs-sm-2); font-weight: 500; }
.ld-stage p {
  margin: 0;
  color: var(--dim);
  font-size: var(--fs-xs-2);
  line-height: 1.6;
}

/* ---- the two crops -------------------------------------------------- */

.ld-shot { margin: 0; display: grid; gap: var(--sp-2-5); }
/* `picture` is an inline box by default and would leave a descender gap under
   the image it wraps; the grid child that matters is the IMG. */
.ld-shot picture { display: block; }
/* NEITHER CAPTURE IS EVER SHOWN WIDER THAN IT WAS TAKEN. `width: 100%` alone
   would stretch the 454px side crop to 860px the moment the layout stacks it,
   which is a blurred screenshot of sharp 11px type — the exact failure the two
   separate captures exist to prevent. The cap is the file's own pixel width, so
   each image downscales into a narrow column and stops at 1:1 in a wide one.
   Left-aligned in the leftover space rather than centred: it lines up with the
   caption under it and with the text above. */
.ld-shot-wide img { max-width: 100%; }
.ld-shot-side img { max-width: 454px; }
.ld-shot img { justify-self: start; }
.ld-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  /* Elevation declared ONCE, and it is the line. A 1px inset border under a
     soft drop shadow is the ghost-card look; these are screenshots of a dark
     product on a dark page and what they need is an edge, not a lift. */
  box-shadow: inset 0 0 0 1px var(--line-2);
}
.ld-shot figcaption {
  color: var(--dim-2);
  font-size: var(--fs-xs-2);
  line-height: 1.55;
}

/* ---- the schedule --------------------------------------------------- */

.ld-sched-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: var(--sp-8);
  align-items: start;
}
.ld-sched-main { min-width: 0; }

.ld-sched-state {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim-2);
  margin: 0 0 var(--sp-2-5);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line-2);
}
.ld-sched-why {
  margin: 0 0 var(--sp-6);
  color: var(--dim);
  font-size: var(--fs-sm-2);
  line-height: 1.6;
  max-width: 60ch;
}
.ld-sched-recent {
  font-family: var(--mono);
  font-size: var(--fs-label-2);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim-2);
  margin: 0 0 var(--sp-2);
}
.ld-sched-aside {
  margin: 0;
  color: var(--dim-2);
  font-size: var(--fs-xs-2);
  line-height: 1.6;
  padding-left: var(--sp-4);
  /* The page's one rule used as an aside marker, at 1px. Anything thicker is
     the coloured left-border callout, which this product does not have. */
  border-left: 1px solid var(--line-2);
}

.ld-fixtures { list-style: none; margin: 0; padding: 0; display: grid; }
.ld-fixture {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2-5) 0;
  border-bottom: 1px solid var(--line);
}
.ld-fixture:last-child { border-bottom: 0; }
.ld-fx-date {
  font-family: var(--mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--dim-2);
}
.ld-fx-teams {
  font-size: var(--fs-sm-2);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ld-fx-v { color: var(--dim-2); padding: 0 var(--sp-05); }
.ld-fx-score {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

/* ---- FAQ ---------------------------------------------------------- */

.ld-faq { padding-top: var(--sp-6); padding-bottom: var(--sp-8); }
.ld-faq dl { margin: 0; display: grid; gap: var(--sp-3); max-width: 46em; }
.ld-qa {
  background: var(--panel);
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--line);
  padding: var(--sp-4) var(--sp-4-5);
}
.ld-qa dt { font-weight: 500; margin-bottom: var(--sp-2); }
.ld-qa dd { margin: 0; color: var(--dim); font-size: var(--fs-sm-2); line-height: 1.6; }

/* ---- footer ------------------------------------------------------- */

.ld-foot { border-top: 1px solid var(--line); }
.ld-foot-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-top: var(--sp-5);
  padding-bottom: var(--sp-6);
}
.ld-foot-brand { color: var(--dim-2); font-size: var(--fs-sm-2); }
.ld-foot-nav { display: flex; gap: var(--sp-4); }
.ld-foot-nav a {
  color: var(--dim);
  font-size: var(--fs-sm-2);
  text-decoration: none;
}
.ld-foot-nav a:hover { color: var(--color-text); }

/* ---- the stats showcase: wide pictures, narrow prose ---------------- */

/* THE ONE SECTION THAT BREAKS THE PAGE'S COLUMN, and it is the pictures that
   earn it. Every other section on this page is 1080px wide because 1080 is a
   comfortable measure for prose. These three captures are 1329px of 11px type,
   and inside a 1040px measure they are drawn at 0.78 and every number in them
   is a little harder to read than it needs to be. So the SECTION widens to fit
   its evidence at 1:1 and the prose inside it is capped back to a measure,
   which is the opposite of the usual mistake (widening a container and letting
   the paragraphs run to 150 characters with it). */
.ld-page section.ld-stats { max-width: 1400px; }

/* 68ch and not 65: this section's prose is unusually dense with figures and
   club names, and the readings below want to hold on one line at desktop. */
.ld-stats-intro,
.ld-stats-more { max-width: 68ch; }

.ld-stats-fixture {
  font-family: var(--mono);
  font-size: var(--fs-xs-2);
  font-variant-numeric: tabular-nums;
  color: var(--dim-2);
  margin: var(--sp-3) 0 0;
}

.ld-stats-lede {
  color: var(--dim);
  font-size: var(--fs-md-2);
  margin: 0;
}

.ld-exhibits {
  list-style: none;
  margin: var(--sp-8) 0 0;
  padding: 0;
  display: grid;
  gap: var(--sp-8);
}

/* A LEDGER ENTRY, not a card. Each exhibit opens on a hairline and the reading
   sits under it, which keeps three screenshots from reading as three floating
   tiles. No panel, no shadow, no radius on the row itself: the elevation in
   this section belongs to the pictures. */
.ld-exhibit {
  display: grid;
  gap: var(--sp-2);
  border-top: 1px solid var(--line-2);
  padding-top: var(--sp-4);
}

/* 46ch holds the longest of the three readings on ONE line at desktop, which
   is the shape they are written for: each is a claim the picture under it
   settles, and a claim broken over two lines with a full stop stranded on the
   second reads as a paragraph that ran out of room. `balance` handles the
   narrow widths, where two lines are unavoidable and should be even. */
.ld-ex-reading {
  font-size: var(--fs-xl);
  font-weight: var(--font-heading-weight);
  letter-spacing: -0.01em;
  margin: 0 0 var(--sp-2);
  max-width: 46ch;
  text-wrap: balance;
}

.ld-ex-figure { margin: 0; display: grid; gap: var(--sp-2-5); }

/* A SCROLL REGION AT EVERY WIDTH, and `min-width` is the whole mechanism.

   The image is `width: 100%` of whatever measure it is given, and never allowed
   below 1040px. On a wide screen the measure is larger than the floor, nothing
   scrolls, and the capture is drawn at up to its own 1329px — 1:1, which is why
   the section is 1400 wide. On a phone the measure is ~350px, the floor wins,
   and the reader pans a picture whose type is still at 0.78 of the size it was
   captured at.

   The alternative was the <picture> pair the pipeline section uses, and it does
   not work here: that section's panel REFLOWS below the product's breakpoint,
   so a second capture shows a phone reader a layout they would really get. A
   25-cell matrix has no phone layout to capture. It is a wide table, and the
   product's own answer to a wide table is `table_scroll` — a region that pans.
   This is that answer, on a public page. */
.ld-ex-frame {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--radius-md);
}
.ld-ex-frame:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 3px;
}
.ld-ex-frame img {
  display: block;
  width: 100%;
  min-width: 1040px;
  max-width: 1329px;
  height: auto;
  border-radius: var(--radius-md);
  /* The same edge the pipeline crops carry, and declared for the same reason:
     these are screenshots of a dark product on a dark page, and what separates
     them from the ground is a line rather than a lift. */
  box-shadow: inset 0 0 0 1px var(--line-2);
}

.ld-ex-figure figcaption {
  color: var(--dim-2);
  font-size: var(--fs-xs-2);
  line-height: 1.55;
  max-width: 68ch;
}

.ld-stats-more {
  color: var(--dim-2);
  font-size: var(--fs-sm-2);
  margin: var(--sp-6) 0 0;
}

/* ---- 390px -------------------------------------------------------- */

@media (max-width: 760px) {
  .ld-hero { grid-template-columns: minmax(0, 1fr); padding-top: var(--sp-6); }
  .ld-doctrine-grid,
  .ld-feature-grid,
  .ld-tier-grid,
  .ld-split { grid-template-columns: minmax(0, 1fr); }
  .ld-top-nav a:not(.ld-btn) { display: none; }
  .ld-foot-inner { flex-direction: column; align-items: flex-start; }

  /* THE THREE NEW SECTIONS AT 390. All four grids collapse to one column, and
     the gap comes down with them: `--sp-8` between stacked blocks is the gap
     that was separating COLUMNS, and kept vertically it reads as three
     unrelated things rather than one section. */
  .ld-league-grid,
  .ld-sched-grid,
  .ld-pipe-body { grid-template-columns: minmax(0, 1fr); }
  .ld-league-grid,
  .ld-sched-grid,
  .ld-pipe-body { gap: var(--sp-6); }

  /* The table keeps all four columns rather than scrolling sideways or hiding
     one. Measured at 390: the two number columns are fixed and narrow, the
     position column is 2.4rem, and what is left for a club name is ~150px —
     which the name column already truncates into. A horizontally scrolling
     table on a marketing page is a table most phone readers never see the right
     half of, and dropping the W-L column would leave a standings table that
     cannot be checked. Tightening the cell padding buys the room instead. */
  .ld-table tbody td,
  .ld-table thead th { padding-left: var(--sp-1); padding-right: var(--sp-1); }
  .ld-th-num { width: 3.4rem; }
  .ld-th-pos { width: 1.9rem; }

  /* The aside stops being an aside when it is no longer beside anything: the
     left rule reads as a quote marker in a column of its own. */
  .ld-sched-aside { padding-left: 0; border-left: 0; padding-top: var(--sp-4); border-top: 1px solid var(--line-2); }

  /* A date column sized for "25 May" beside a fixture that now has the whole
     width: the score can sit tight to the right and the teams take the rest. */
  .ld-fixture { grid-template-columns: 3.6rem minmax(0, 1fr) auto; gap: var(--sp-2-5); }

  /* Full-bleed poster on a phone: a 3D map inside a 350px column with 20px of
     margin either side is a stamp. The frame is already out of the layout by
     here — see the 900px block below, which is where that decision lives. */
  .ld-demo-frame {
    aspect-ratio: 4 / 3;
    max-height: none;
    margin-inline: calc(var(--sp-5) * -1);
    border-radius: 0;
    box-shadow: inset 0 1px 0 var(--line), inset 0 -1px 0 var(--line);
  }
}

/* ── WHERE THE SIDE CROP STOPS FITTING BESIDE THE STAGES ───────────────────
   980, and like the demo's 900 it is the SECTION's own breakpoint rather than
   the page's 760. The reason is arithmetic rather than taste: the crop's column
   is a fixed 454px because it holds a 454px image, so below about 980 the
   stages are left under 300px and their three-line paragraphs start running to
   six. The image cannot shrink without blurring the 11px type that is the whole
   point of showing it, so the LAYOUT gives way first.
   ────────────────────────────────────────────────────────────────────────── */

@media (max-width: 980px) {
  .ld-pipe-body { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
}

/* Below 900 the wide figure is showing the PHONE capture (see the <picture> in
   landing.html), which was taken of a 378px-wide panel. Given the whole measure
   it would be drawn at over twice the size it was rendered at — legible, but a
   screenshot blown up until its buttons are the size of the body text around
   them. Capped at 560, where it is still a downscale of the 756px file. */
@media (max-width: 900px) {
  .ld-shot-wide img { max-width: 560px; }
}

/* ── WHERE THE EMBED STOPS BEING WORTH SHOWING ─────────────────────────────
   900px, and it is the section's OWN breakpoint rather than the page's 760.
   The page breaks at 760 because its card rows go single-column there; this
   is a different question with a different answer, and forcing one number to
   serve both would mean picking whichever is wrong for one of them.

   Swept with the real viewer inside the real frame
   (tools/qa_landing_demo.py, which prints this table on every run):

       768px  frame 713x475   chrome 271px   map 204px  (43%)  no scoreboards
       900px  frame 845x563   chrome 231px   map 332px  (59%)  no scoreboards
      1024px  frame 969x646   chrome 205px   map 441px  (68%)  scoreboards
      1440px  frame 1040x693  chrome 205px   map 488px  (70%)  scoreboards

   The viewer folds its transport from a row into a stacked block on the way
   down, and by 768 that block plus the top bar and round strip is 271px of a
   475px frame: the round is a band behind an overlay and the HUD is the
   picture. That is the broken hero the phone rule exists to prevent, one
   breakpoint up. At 900 the map still has 59% of the frame, which holds.

   Taking the frame out of the LAYOUT rather than hiding it visually is what
   makes this the bandwidth rule too: an element with no box is never
   `isIntersecting`, so the observer in landing-demo.js never fires and not one
   byte of the 10 MB map is fetched below this width.

   What replaces it is not an apology. The viewer at 390x780 is genuinely fine
   given the whole screen (shot 04 in handover-shots/landing-demo) — it drops
   its side boards, keeps a compact top bar and leaves the map ~420px. So the
   poster carries the argument and the control hands over the whole screen.
   ────────────────────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .ld-demo-live { display: none; }
  .ld-demo-desk { display: inline; }
}

@media (prefers-reduced-motion: reduce) {
  .ld-btn { transition: none; }
  /* The demo does not FADE in for a visitor who asked for no animation. It
     still runs when they press the control — the replay is the content, not
     decoration — but arriving is instant. landing-demo.js takes the second
     half of this: no observer, so nothing starts until they ask. */
  .ld-demo-live,
  .ld-demo-poster { transition: none; }
}

/* ══ WIDE VIEWPORTS ══════════════════════════════════════════════════════
   The same 1600px breakpoint the product's shell uses (see tokens.css for
   why 1600). At 2560 this page was the worse of the two: a 1080px column
   centred in 2560 is 1480px of margin, 58% of the screen.

   The column grows to 1320px — `--main-max`'s own design value, so the
   page someone signs in FROM and the page they land ON share one measure,
   which is the sentence at the top of this file applied to a width. It is
   also where this page's card vocabulary stops: the sections are 3-up card
   rows, and at 1320 a card is about 415px and the hero's illustrative KPI
   about 515px. Rendered at 1800 for comparison, the same KPI card is 715px
   around a 29px number and the tenets become 570px bands with their right
   third empty — which is the exact failure `components.css` refuses for
   the product's own KPI grid. Wider than this is not a cap change, it is a
   different composition for those rows, and that is the operator's call.

   `min(calc(100% - 520px), 1320px)` rather than a flat 1320: 520 is the
   margin this page already has at 1600px, so the expression equals the
   pinned 1080 exactly AT the breakpoint and grows from there, reaching
   1320 at 1840. Resizing across 1600 moves nothing.
   ════════════════════════════════════════════════════════════════════════ */

@media (min-width: 1600px) {
  .ld-page section,
  .ld-top,
  .ld-foot-inner {
    max-width: min(calc(100% - 520px), 1320px);
  }

  /* The one section whose vocabulary genuinely supports another column. A
     Q&A list is a list — five entries fall 2/2/1 with the odd one ending a
     row, which is what a two-column list looks like, not the hole in a
     designed grid. The `46em` cap comes off because it was the MEASURE of
     a single column and the columns now carry it themselves: each lands at
     about 620px of text, inside the same 65-75ch this page keeps
     everywhere else. */
  .ld-faq dl {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: none;
  }
}
