/* ==========================================================================
   Connect 2026 - Content Library listing shell                    T-25..T-28
   --------------------------------------------------------------------------
   Eight listings share one shell: Articles (p2), News (p4), Event Q&A (p6),
   In-depth (p8), Webinars (p15), Filmed Interviews (p17), Audio (p19), plus
   Magazine and Reports which have no artboard.

   THE SHELL - measured on p2:

     libraryTabs
     title            36px SemiBold navy
     intro            19px Medium muted
     FILTER BY TOPIC  full 1256px width, ABOVE the grid, chips 27px on 2 rows
     ------------------------------------------ grid starts here
     content 743  |  gutter 60  |  rail 452
       hero card        744 x 419 image (16:9)
       3-up cards       235 x 132 each, 20px gaps   (235*3 + 20*2 = 745)
       headline rows    8-10 of them
       pagination
     rail
       skyscraper 453 x 1358
       Forthcoming Events card 452 x 557

   THE CHIPS ARE FULL WIDTH. They run x=36 to x=541pt, which is the container,
   not the 743px content column. Putting them inside the grid is wrong and
   costs a row of chips.

   WHAT DIFFERS PER LISTING - all measured, none inferred:

     News (p4)        NO topic filter at all. Hero has no author line either,
                      matching the News reader which has no byline.
     Event Q&A (p6)   3-up images are 235x145, not 235x132.
     In-depth (p8)    title reads "In-depth (Connect Plus)" and the hero
                      carries a 204x51 Connect Plus badge.
     Webinars (p15)   video hero - 161px play circle centred on the image.
     Interviews (p17) identical to Webinars.
     Audio (p19)      horizontal hero (image left, text right) and a 4-UP
                      grid of smaller cards, not 3-up.

   DEPENDS ON: tokens.css, shell.css, components/card.css, chip.css, tabs.css
   ========================================================================== */

/*
   26px below the rule under the tabs.

   THIS WAS 43, and 43 was a box measured against an ink reading. The old note
   said "measured on p6, rule at 383.8 and the H1 top at 427.1" - 427.1 is
   where the LETTERS start, and a 34.8px heading in a 40px line box carries
   about 5px of leading and shoulder above its cap height. So the box wanted
   ~38 and got 43, and every listing sat that much low. Reported by the test
   team as "content library and <tab> title has bit extra space".

   Re-measured ink-to-ink at 4x on three boards, tabs rule to H1 cap top:

       p15 webinars 30.6    p17 filmed 30.6    p8 in-depth 25.8*

   (*p8's "In-depth (Connect Plus)" opens with a parenthesis that reaches
   above cap height, which is why it reads 5px tighter - the same reason the
   original 43 came out wrong.)

   30.6 of ink, less the ~4.6 of leading above the caps, is 26 of box.

   NOTE the margin shorthand. The pages carry cn-mt-6 on this element and it
   has never done anything: listing.css loads after shell.css, so this
   shorthand resets margin-top to 0 at equal specificity. The spacing has to
   live here, not on a utility class.
*/
.cn-listing__title {
  margin: 26px 0 var(--cn-space-1);
  font-size: var(--cn-text-h1);
  font-weight: var(--cn-fw-semibold);
  line-height: var(--cn-lh-tight);
  color: var(--cn-ink);
}

/*
   62ch capped the line at 755px and wrapped the standfirst onto two lines.
   p6 sets it on ONE: the sentence measures 879.4px at 19.2px, running from
   x=86.4 to x=965.8 - wider than the 743 content column, because this sits
   above the grid and can use the container.
*/
.cn-listing__intro {
  margin: 0;
  /*
     84ch, not 74. This is a one-sentence deck, not body copy, and p4 draws it
     on a single line. Measured at 1440: the sentence needs 990px and 74ch
     capped it at 901px, so it wrapped two words early while 1304px of column
     sat unused. 84ch is 1023px - it fits with headroom and still wraps on a
     narrower viewport, where the column is the real constraint.
  */
  max-width: 84ch;
  font-size: var(--cn-text-author);
  font-weight: var(--cn-fw-medium);
  line-height: var(--cn-lh-body);
  color: var(--cn-ink-muted);
}

/*
   THE GAP ABOVE THE GRID DEPENDS ON WHETHER CHIPS PRECEDE IT.

     p6 (Event Q&A)  chips bottom 579.6 -> hero top 623.6  = 44px
     p4 (News)       intro  ~486       -> hero top 494.4   =  8px

   News has no chip row at all, so the 44px measured from a chipped listing
   left its hero 56px too low. Keyed off the chips themselves rather than a
   new class, so any listing gets the right one without being told.
*/
.cn-listing__grid { margin-top: var(--cn-space-2); }
/*
   44, not 48. Measured on p8, p15 and p17 and identical on all three: the
   chip row's last ink ends and the hero and the rail advert both begin
   44.4px later. --cn-space-12 resolves to 48 at 1440, which is the 4px the
   test team called out as "space between advert ad space and page is a bit
   extra" - the advert is the thing that makes it visible, because it is the
   one block on the row with a hard edge at the top.
*/
.cn-chips + .cn-listing__grid { margin-top: 44px; }

/* Hero card then the 3-up row then the headline list, each measured. */
.cn-listing__hero  { margin-bottom: var(--cn-space-12); }
.cn-listing__cards { margin-bottom: var(--cn-space-12); }

/*
   Event Q&A's 3-up stills are 235x145 rather than 235x132 - a 1.62 ratio
   instead of 16:9, because the event artwork is squarer than a photo.

   SCOPED TO THE 3-UP ONLY. p6's hero measures 743.6 x 418.3, which is 16:9,
   exactly as on p2 - only the three cards below it are taller. An unscoped
   rule catches the hero as well and makes it 60px too tall.
*/
.cn-listing--qa .cn-listing__cards .cn-card__image { aspect-ratio: 235 / 145; }

/*
   Audio's hero is horizontal - artwork left, text right - where every other
   listing stacks them. Measured on p19: text starts at x=142.3pt, so the
   artwork occupies 36 to ~139pt, about 255px of the 743.
*/
/*
   HOLD THE HERO'S OWN LAYOUT AGAINST THE LEGACY STYLESHEET.

   The Audio listing hero rendered as three siblings in a ROW - image 300,
   eyebrow 50, title 307 - at 1440, and at 375 it squeezed to image 148,
   eyebrow 44, title 122, one word per line. Not a mobile bug: it was wrong at
   every width, and only mobile made it obvious.

   card.css sets .cn-card { display: block }. Something in the site's global
   stylesheet, which head.jsp loads alongside this module, overrides it with
   display:flex and gap:15px - neither value exists anywhere in connect2026/
   (grepped), and 15px is not on our spacing scale. It wins on the Audio
   listing because that is the one hero whose card carries no second class to
   out-specify it.

   So the layout is asserted rather than assumed. Two classes beat one, and a
   hero that stacks is what p2, p4, p6, p8, p15 and p17 all draw.

   NOT a fix to the legacy sheet: that file is shared with the current site and
   is not ours to change three weeks before this one replaces it.
*/
.cn-listing__hero .cn-card--hero {
  display: block;
}

/*
   p19's hero is the genuine exception - image left, text right - and it opts
   in through --horizontal rather than inheriting a row layout by accident.

   MEASURED on p19 at 4x (1 crop px = 0.6 real):

     image      240 x 240, SQUARE - not the 16:9 banner every other hero uses
     gap        16 to the text column
     text       eyebrow, then a three-line 34.8 title, TOP-ALIGNED with the
                image edge - the eyebrow sits on the image's top line
     byline     none

   This was 255fr 468fr with align-items:center, which is neither of those
   numbers and centred the text against the image, and - the real problem -
   it let the grid auto-place: media in (1,1), eyebrow in (1,2), title in
   (2,1), UNDER the image. The image has to own column 1 for every row the
   text needs.
*/
.cn-listing__hero--horizontal .cn-card,
.cn-listing__hero--horizontal .cn-card--hero {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  grid-auto-rows: max-content;
  column-gap: var(--cn-space-4);
  align-items: start;
}
.cn-listing__hero--horizontal .cn-card__media {
  grid-column: 1;
  grid-row: 1 / span 4;
  margin: 0;
}
.cn-listing__hero--horizontal .cn-card__type,
.cn-listing__hero--horizontal .cn-card__title,
.cn-listing__hero--horizontal .cn-card__author { grid-column: 2; }

/* Square, as every audio image on p19 is - hero and cards alike. */
.cn-listing__hero--horizontal .cn-card__image { aspect-ratio: 1 / 1; }

/* The eyebrow sits on the image's top edge; the hero's 45px stand-off is
   for a title UNDER a banner, which this is not. */
.cn-listing__hero--horizontal .cn-card__media + .cn-card__type { margin-top: 0; }

/*
   THE FOUR-UP CARDS, which only the Audio listing has.

   MEASURED on p19: images 168 x 168 square; title pitch 24.0px on the
   nose, which is --cn-text-card (20px) at the 1.2 line-height, running to
   FIVE lines; 25px between cards, so 4 x 168 + 3 x 24 = 744 fills the
   column exactly. The three-up card's 24px title with its four-line clamp
   was landing here unchanged and truncating every real headline at four
   lines in a 168px column.
*/
/* The variable, not column-gap: .cn-grid--4's auto-fit floor is computed from
   --cn-grid-gap, and a gap the formula does not know about would push four
   columns to three at exactly the width they are meant to fit. Same pattern
   .cn-grid--divided uses. */
.cn-listing__cards.cn-grid--4 {
  --cn-grid-gap: var(--cn-space-6);
  /* 168, the measured card. The grid's default floor is 170, and 4 x 170 plus
     three 24px gaps is 752 - eight pixels over the 744 column, so auto-fit
     gave three columns of 232. At 168 it is 744 exactly. */
  --cn-grid-floor: 168px;
}
.cn-listing__cards.cn-grid--4 .cn-card__image { aspect-ratio: 1 / 1; }

/*
   FOUR COLUMNS, COUNTED - NOT INFERRED FROM THE ARITHMETIC.          D-21

   4 x 168 + 3 x 24 is 744, and at 1280 the main column beside the rail is
   743. auto-fit is given a sum that needs one pixel more than it has, so it
   drops a column - and because the cards are then wider than the floor it
   does not land on three, it lands on two: a 2 x 2 block with half the
   column empty, at the one width most laptops actually open.

   Sizing that fits "exactly" is sizing that fails on any rounding, and this
   one had two sources of it - the rail's clamp() and the board's fractional
   container. Above 864, where shell.css says the ladder is clean, the count
   is what the design fixes (four), so it is stated rather than computed;
   minmax(0, 1fr) lets the columns be whatever that leaves. Below 864 the
   stacked rungs in shell.css still own the layout - 2-up to 768, 1-up under
   it - so this must not reach them.
*/
@media (min-width: 864px) {
  .cn-listing__cards.cn-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.cn-listing__cards.cn-grid--4 .cn-card__title {
  font-size: var(--cn-text-card);
  -webkit-line-clamp: 5;
  min-height: 6em;           /* five 1.2 lines - the same floor-equals-ceiling rule as the 3-up */
}

/*
   A THIRD ROW PITCH. card.css documents two - 107 in a rail, 78 in a column -
   and the listing is neither: p2 and p6 both step a uniform 113 between
   eyebrows across all eight rows.

   Two things make it uniform. The pitch is 17 eyebrow + 8 + two 28.8 lines +
   29 chrome, so titles are clamped to two lines; without that a one-line
   headline collapses the row to 79 and the list comes out ragged, which is
   what the dummy content showed. And the extra 4px of padding over the rail
   value is what separates 107 from 113.
*/
/*
   THE 3-UP CARD TITLES GET FOUR LINES, not two.

   Re-measured on the artboards rather than assumed: p4 draws its card title on
   FOUR lines (tops at 1323.9, 1352.7, 1381.5, 1410.3) and p6 does the same
   (1453.1, 1481.9, 1510.7, 1539.5). A two-line clamp was cutting real
   headlines - "Citi Closes in on Trillion Dollar Green Finance Goal" needs
   four in a 235px card and was showing two, and every one of the three cards
   on the News listing was truncated.

   AND THE FLOOR IS FOUR LINES TOO, not two.

   A floor of two under a ceiling of four still lets one card's title run to
   115px while its neighbour's stops at 58, and everything below the title -
   the byline, the bottom of the card - then sits 57px out of step across the
   row. Measured on the In-depth listing: three cards 253, 372 and 421 tall,
   with ~170px of white under the first before the headline rows begin. The
   artboards never show that because their three mock titles all happen to
   wrap to exactly four.

   So the floor matches the ceiling and the title block is one fixed height,
   which is what p4, p6 and p8 all draw. 4.8em is four 1.2 lines of the
   title's own size.

   A row where every headline is short now reserves four lines of white - but
   uniformly, and a tidy airy row beats a ragged tight one. What this cannot
   fix is a card whose record has no author at all: that card still ends a
   byline short of its neighbours, and the answer to that is in the CRM.
*/
.cn-listing__cards .cn-card__title {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 4.8em;
}

/*
   ONE MORE LINE OF DEFENCE ON THE ROW ITSELF. The grid defaults to
   align-items:stretch, but .cn-listing__cards sets start - so the cards keep
   their own heights and only their tops line up. That is correct while the
   card has no background or border to show a ragged bottom edge; if one is
   ever added, this is the line to revisit.
*/

/*
   THE RULE SITS ABOVE THE ROW ON A LISTING, not below it.

   card.css puts it below, which is right for the rail lists it was measured
   on (p3, p7) - there the rule closes the row it belongs to. p6 is the other
   way round. Measured, rules at:

     1658.3  1772.2  1886.8  1999.7  2110.2  2223.2  2336.1  2450.7

   and the eight eyebrows at 1684, 1799, 1912, 2022, 2136, 2248, 2363, 2472 -
   so every rule sits ~26px ABOVE an eyebrow, there is one over the first row,
   and there is none under the last. A bottom border gives the opposite of
   that: nothing above row one, and a stray rule under row eight.

   It is also nearly black, not the light --cn-border grey and not navy. The
   artboards draw 0.25pt BLACK - sampled rgb(0,0,0) on p4 and rgb(67,67,67) on
   p6, the same line with more antialiasing.

   --cn-ink-body, NOT --cn-ink. Despite the names, --cn-ink is #001c64 navy
   and --cn-ink-body is the #1d1d1b near-black. This rule was navy until the
   News listing made it obvious against p4's black.
*/
.cn-listing__grid .cn-headline-row {
  /* 16, not 24: the same air over the eyebrow as the ~16 the board leaves
     between the title and the rule (see below) - asked for as equal. */
  padding-top: var(--cn-space-4);
  border-top: 1px solid var(--cn-ink-body);
  border-bottom: 0;
}

.cn-listing__grid .cn-headline-row__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /*
     NO FLOOR. THE CONSTANT IS THE GAP ABOVE THE RULE, NOT THE ROW PITCH.

     This carried min-height: 2.4em on the reasoning that "a one-line title
     collapses its row to 83 against the other rows' 111 and the list steps
     unevenly - which is what the artboard never does". The artboard never does
     it because all eight of its mock titles happen to wrap to two lines, and a
     floor was inferred from that. Reported from the test server: a one-line
     headline sat with a whole empty line of white under it before its rule,
     while two-line rows looked right - so the floor was buying an even pitch
     and paying for it with a hole.

     Re-measured at 4x on p2, p6 and p8, ink to rule, on all eight rows of
     each:

       p2   16.8  16.2  16.8  16.8  16.8  16.8  16.2
       p6   16.8  16.2  16.8  16.8  16.8  16.8  16.2
       p8   16.8  16.2  16.8  16.8  16.8  16.8  16.2

     The rule is a constant ~16.5px below the last line of the title on every
     row of every board. The pitch varies only because the content does not.
     So the title takes the height its text needs, and the row below carries
     the gap - which gives a one-line row the same 16.5px a two-line row has,
     and the shorter pitch that follows from it.
  */
}

/*
     The measured gap, as padding rather than a margin: the rule is the NEXT
     row's border-top, so this is the space between this title and it. ~12px of
     box leaves ~16px of ink-to-rule once the line box's own descender space is
     counted, which is the board's number.
*/
.cn-listing__grid .cn-headline-row { padding-bottom: var(--cn-space-3); }

/*
   The listing rail steps 40px between blocks, not the 32 that reader.css sets
   for every rail. Measured on p6: the skyscraper ends at 1981.4 and the
   Forthcoming Events card starts at 2020.9.

   Scoped to the listing, because 32 is right where it was measured (the
   reader rails on p3 and p7) and this is a different screen.
*/
.cn-listing__grid .cn-rail > * + * { margin-top: 40px; }

/*
   EMPTY AND ERROR STATES.

   Not in any artboard - the design only ever draws a full listing. But a
   filter that matches nothing is a normal thing for a reader to do, and the
   page used to answer it with a dozen invented articles, so this had to
   exist. Sized to hold the fold open rather than collapsing the grid, which
   would drop the rail up beside the chips.
*/
.cn-listing__empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--cn-space-5);
  min-height: 320px;
  padding: var(--cn-space-12) 0;
}

.cn-listing__empty-lede {
  margin: 0;
  font-size: var(--cn-text-section);
  font-weight: var(--cn-fw-semibold);
  line-height: var(--cn-lh-tight);
  color: var(--cn-ink);
}

.cn-listing__empty .cn-body { margin: 0; max-width: 52ch; }

/* Pagination sits centred under the list - "< 1 >" at x=180.5pt on p2. */
.cn-listing__pagination {
  display: flex;
  justify-content: center;
  margin-top: var(--cn-space-10);
}

/* ------------------------------------------------------- pagination ---- */
/*
   T-18. p2 draws "< 1 >" centred at 24px Poppins-Medium - the same size as a
   headline row title, not small print. Every listing artboard carries it.

   The control renders even when there is one page, because the brief asks for
   exactly that: "the difference is there is a bottom of the page". An empty
   space where the pagination should be reads as a page that failed to load.
*/
.cn-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--cn-space-4);
  font-size: var(--cn-text-section);
  font-weight: var(--cn-fw-medium);
  line-height: 1;
}

.cn-pagination__step,
.cn-pagination__page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--cn-tab-h);
  min-height: var(--cn-tab-h);
  border-radius: var(--cn-radius-pill);
  color: var(--cn-ink);
  transition: background var(--cn-dur) var(--cn-ease),
              color var(--cn-dur) var(--cn-ease);
}

a.cn-pagination__step:hover,
a.cn-pagination__page:hover { color: var(--cn-cyan); }

/*
   NO CYAN PILL, and no marker of any kind. Sampled directly off p6 at y=2568:
   "< 1 >" is navy #001c64 text on white, and there is no fill behind it at
   all - the only non-white pixels in that whole row are the navy glyphs.

   This does not contradict the tabs and chips, which really are white on
   cyan. Pagination simply is not a pill in this design; it was inheriting the
   pill treatment from its neighbours.

   Only ONE number renders - the page you are on - so there is nothing to
   distinguish it from. See the note in pagination.tag.
*/
.cn-pagination__page.is-current {
  background: none;
  color: var(--cn-navy);
}

/*
   Disabled arrows stay in the layout so the row does not shift as you page.
   aria-hidden in the markup, so they are skipped rather than announced.
*/
.cn-pagination__step.is-disabled {
  color: var(--cn-ink-faint);
  cursor: default;
}

/* =========================================================== RESPONSIVE == */
@media (max-width: 767px) {
  /* The horizontal hero cannot hold two columns on a phone. */
  /*
     STACKED ON A PHONE: image, then the text on its own line below it - the
     test team's "text should be in new line" on the audio listing. The
     image keeps its square and takes the full column.
  */
  .cn-listing__hero--horizontal .cn-card,
  .cn-listing__hero--horizontal .cn-card--hero {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--cn-space-4);
  }
  .cn-listing__hero--horizontal .cn-card__media { grid-column: 1; grid-row: auto; }
  .cn-listing__hero--horizontal .cn-card__type,
  .cn-listing__hero--horizontal .cn-card__title,
  .cn-listing__hero--horizontal .cn-card__author { grid-column: 1; }
  .cn-listing__grid,
  .cn-listing__hero,
  .cn-listing__cards { margin-bottom: var(--cn-space-8); }
}

/*
   Tap floor for the pager. Lives here rather than in shell.css's
   pointer:coarse block because .cn-pagination__page sets min-height above at
   the same specificity, and this file loads later - a rule in shell.css can
   never win it. Verified on a touch viewport: it was staying at 34px.
*/
@media (pointer: coarse) {
  .cn-pagination__page,
  .cn-pagination__step {
    min-width: 44px;
    min-height: 44px;
  }
}
