/* ==========================================================================
   Connect 2026 - Event tile                                            T-13
   --------------------------------------------------------------------------
   Appears on Home (3x2 grid), Events (11 tiles), and at the foot of the
   Article and In-depth readers ("Events you may be interested in", 5 across).

   OPEN QUESTION - event brand colour has no data source.
   Each tile in the design is outlined in its event's brand colour: Climate
   Risk Europe green, Next Gen OpRisk Europe purple, Balance Sheet Management
   USA gold. Sampled from the artboards.

   The Event model (subscription/model/mapcrm/Event.java) has NO colour field.
   It carries `image` and `topImage` only. So this cannot be driven from data
   as things stand. Options, for the client:
     1. add a brand-colour field to the event record in the CMS  (BE work)
     2. keep a fixed slug -> colour map in the front end          (brittle)
     3. drop the coloured borders, use a neutral outline          (cheapest)

   Built for option 2 for now - `brand` maps to a class below. Default is a
   neutral border, so an unmapped event still renders correctly rather than
   breaking. Swapping to option 1 later means deleting the map, nothing else.

   DEPENDS ON: tokens.css
   ========================================================================== */

.cn-event-tile {
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  /*
     96 was a guess and ran 30 short. p1 measures 126.3, p3 measures 122.3 -
     the same component drawn 4px apart on two boards. Taking p1's value:
     Home is where six of these sit together, so a 4px error compounds there
     and nowhere else.
  */
  /*
     THE SAME SHAPE AS A BANNER TILE - 17 Sep 2026. With a 126px floor a
     typeset tile beside a banner one (231:120 at the column's width, so
     207px in a reader's four-up row) drew a row of two heights, and the
     row read as broken. Both are now 231:120: a typeset tile is exactly
     the box its banner would fill once the CRM has one, so uploading the
     banner changes the picture and nothing else on the page.
  */
  min-height: auto;          /* auto, not 0: a long name may still grow the box */
  aspect-ratio: 231 / 120;
  padding: var(--cn-space-4);
  background: var(--cn-surface);
  border: 2px solid var(--cn-border);
  border-radius: var(--cn-radius-card);
  transition: box-shadow var(--cn-dur) var(--cn-ease);
}

.cn-event-tile:hover { box-shadow: var(--cn-shadow-card); }

/* Same rule as .cn-event-thumb: with a banner, the banner IS the tile. The
   CRM's artwork already carries the outlined box, so the tile's own border
   and background go, and the picture is contained - never cropped - in the
   typeset tile's box. */
.cn-event-tile { position: relative; }
/*
   ONE SHAPE EVERYWHERE. With a banner the tile is the picture, at the
   board's 231:120 (the shape .cn-event-thumb draws on the Events page) - not
   the typeset tile's 126px floor, which at the reader foot's 150px-wide
   column drew a short banner with white above and below it, while the same
   banner on the Events page filled its box. min-height off, aspect-ratio on;
   border and padding off, since the artwork carries its own box.
*/
.cn-event-tile--banner {
  padding: 0;
  min-height: 0;
  aspect-ratio: 231 / 120;
  overflow: hidden;
  border: 0;
  border-radius: var(--cn-radius-card);
  background: transparent;
}
.cn-event-tile__banner {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.cn-event-tile--banner .cn-event-tile__mark,
.cn-event-tile--banner .cn-event-tile__body { visibility: hidden; }

/* The CeFPro Events lockup. An image in the design, not type. */
.cn-event-tile__mark {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  object-fit: contain;
}

.cn-event-tile__body { min-width: 0; }

.cn-event-tile__name {
  display: block;
  font-size: var(--cn-text-nav);
  font-weight: var(--cn-fw-semibold);
  line-height: var(--cn-lh-snug);
  color: var(--cn-ink);
}

/* Dates take the brand colour. Note the artboards set these in Verdana at
   3.7pt - clearly a placeholder; we use Poppins like everything else. */
.cn-event-tile__dates {
  display: block;
  margin-top: var(--cn-space-1);
  font-size: var(--cn-text-label);
  font-weight: var(--cn-fw-medium);
  color: var(--cn-ink-muted);
}

/* ========================================================= BRAND COLOURS == */
/*
   Sampled from artboard p21. Extend this list as brands are confirmed - and
   delete it entirely if the colour becomes a CMS field.
*/
.cn-event-tile--green  { border-color: #00a80c; }
.cn-event-tile--green  .cn-event-tile__dates { color: #00820a; }

.cn-event-tile--purple { border-color: #b430fc; }
.cn-event-tile--purple .cn-event-tile__dates { color: #8e14d4; }

.cn-event-tile--gold   { border-color: var(--cn-fam-gold); }
.cn-event-tile--gold   .cn-event-tile__dates { color: var(--cn-fam-gold-ink); }

.cn-event-tile--navy   { border-color: var(--cn-navy); }
.cn-event-tile--navy   .cn-event-tile__dates { color: var(--cn-navy); }

/* =========================================================== RESPONSIVE == */
/*
   T-40: tiles go 5 -> 3 -> 2 across via the shell grid ladder. At two across
   on a 375px screen each tile is roughly 160px wide, so the mark shrinks and
   the fixed min-height is dropped to let the name wrap to two lines.
*/
@media (max-width: 1279px) {
  .cn-event-tile { min-height: auto; }
  .cn-event-tile--banner { min-height: 0; }
}

@media (max-width: 767px) {
  .cn-event-tile {
    min-height: 0;
    gap: var(--cn-space-3);
    padding: var(--cn-space-3);
  }
  .cn-event-tile__mark  { width: 32px; height: 32px; }
  .cn-event-tile__name  { font-size: var(--cn-text-label); }
  .cn-event-tile__dates { font-size: var(--cn-text-tiny); }
}

/* ================================================ FORTHCOMING EVENTS === */
/*
   T-11. The rail card: 451.9 x 557 on p2 at x=890.4, white with a 1px
   border. The SAME card appears on p4, p5, p6, p7 and p8 - every listing
   rail and several readers - which is why it is a component rather than a
   block repeated per page.

   It is a SCREENSHOT in the artboard, not vector: no text layer, no vector
   fills, so its geometry was read off a render at 4x and its two off-palette
   colours are pixel samples (see --cn-date-chip in tokens.css). Structure is
   copied faithfully; colour is mapped onto the design system.

   DEPENDS ON: tokens.css, button.css
   ========================================================================== */

.cn-fce {
  display: flex;
  flex-direction: column;
  /*
     557 measured. min-height rather than height so a wrapped event name grows
     the card instead of spilling out of it; the CTA's margin-top:auto pins
     the button to the foot either way, which is where p2 and p6 draw it.
  */
  min-height: 557px;
  padding: var(--cn-space-8);
  background: var(--cn-surface);
  /*
     SQUARE, WITH A NEAR-BLACK RULE. Measured at 8x on p2, p6, p8, p16 and
     p18 - the five boards that draw this card - and identical on all five:
     452 x 558, corner radius 0, and a 1px border whose edge pixel samples
     rgb(0,0,0) (92,92,92 one pixel in, which is the antialiasing). It was
     shipping with the 12px card radius and the light --cn-border grey, so it
     read as a soft panel where the board draws a ruled box.

     --cn-ink-body, not --cn-ink: same reasoning as the listing row rules -
     the boards draw these hairlines in black, and --cn-ink is the navy.

     The ROUNDED things inside stay rounded: the date tiles (12px, light
     blue) and the button are both drawn that way on every board. The test
     team read those and reported "the corners in the PDF are curved" - the
     outer box is the one that is not.
  */
  border: 1px solid var(--cn-ink-body);
  border-radius: 0;
}

/* Small, letterspaced, muted - the quietest heading in the design. */
.cn-fce__heading {
  margin: 0 0 var(--cn-space-5);
  font-size: var(--cn-text-label);
  font-weight: var(--cn-fw-medium);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cn-ink-muted);
}

.cn-fce__list {
  margin: 0 0 var(--cn-space-6);
  padding: 0;
  list-style: none;
}

/*
   THE WHOLE ROW IS THE TARGET, not just the title.                     D-20

   The link was the name alone - 21px tall - with the date chip and the city
   line beside it doing nothing. On a phone that is well under the 44px
   everyone's guidelines ask for, and the two obvious things to press (the big
   bold date, the row itself) were the two that did not work.

   The anchor stays exactly where it is in the markup, so the reading order
   and what a screen reader announces are unchanged; its ::after is stretched
   over the row instead. `position: relative` here is what it stretches to.
*/
.cn-fce__row {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--cn-space-4);
  padding-block: var(--cn-space-4);
}

a.cn-fce__name::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* The row lights up as one, wherever the pointer is over it. */
.cn-fce__row:hover .cn-fce__name { color: var(--cn-cyan); }

/*
   The rule separates rows, so it belongs BETWEEN them - not under the last
   one, where it would sit directly above the button and read as a second
   border on the card.
*/
.cn-fce__row + .cn-fce__row { border-top: 1px solid var(--cn-border); }

/* ------------------------------------------------------- the date chip -- */
.cn-fce__date {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 54px;
  padding-block: var(--cn-space-2);
  background: var(--cn-date-chip);
  border-radius: var(--cn-radius-card);
  line-height: 1;
}

.cn-fce__month {
  font-size: var(--cn-text-tiny);
  font-weight: var(--cn-fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--cn-date-chip-ink);
}

.cn-fce__day {
  margin-top: var(--cn-space-1);
  font-size: var(--cn-text-h3);
  font-weight: var(--cn-fw-bold);
  color: var(--cn-ink);
  font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------- the text --- */
.cn-fce__body { min-width: 0; }

.cn-fce__name {
  display: block;
  font-size: var(--cn-text-card);
  font-weight: var(--cn-fw-semibold);
  line-height: var(--cn-lh-tight);
  color: var(--cn-ink);
  transition: color var(--cn-dur) var(--cn-ease);
}
a.cn-fce__name:hover,
a.cn-fce__name:focus-visible { color: var(--cn-cyan); }

.cn-fce__city {
  display: block;
  margin-top: var(--cn-space-1);
  font-size: var(--cn-text-meta);
  color: var(--cn-ink-muted);
}

/* Full width, and last in the card - margin-top:auto pins it to the bottom
   so two cards side by side line their buttons up even with different row
   counts. */
/*
   THIS BUTTON IS NOT THE STANDARD PILL.

   The card is drawn on p2 as a raster image in the rail, which is why no text
   or vector search finds it - it had to be rendered at 300dpi and measured in
   pixels. Doing that gives, in CSS pixels against the card's own 452x557:

       button        391.7 x 54.7
       side insets   31.8 / 28.4      (the card's own 32px padding)
       bottom inset  27.9
       corner radius ~9              (full width reached 16 render rows in)

   So it IS full width of the content box - 452 - 32x2 = 388, and the button
   measures 392. Two things differ from .cn-btn: it stands 55px tall rather
   than the standard 34, and its corners are a 9px radius, not the 999px pill.
   At 388px wide a pill reads as a slab anyway; the drawing uses a plain
   rounded rectangle.

   An earlier pass here mistook the Upcoming Events block on p1 - a 3-across
   panel with a 326x34 centred pill - for this component and sized the button
   to its label. Different component, different page.
*/
.cn-fce__cta {
  margin-top: auto;
  width: 100%;
  min-height: 55px;
  border-radius: 9px;
}

/* ============================================== EVENT TILE (p21) ======= */
/*
   p21's event and webinar grids: every tile is the event's own branded
   artwork - the CRM's Image Banner, the 1536 x 803 "event grid" file,
   which already carries the outlined rounded box, the lockup, the name and
   the dates in the event's colour. So the tile draws NOTHING of its own:
   no border, no background, no type. An earlier pass here put a 1px box and
   typeset name around the picture and got a box inside a box.

   THE SHAPE IS THE BOARD'S: 231 x 120 measured on p21. aspect-ratio rather
   than a fixed height, so in our 245-wide column the tile is 127 tall and a
   banner at that shape fills it exactly; contain, not cover, so a banner's
   own border is never cropped.

   NO BANNER: the CeFPro Connect mark, contained in a light outline at the
   same size - a placeholder that keeps the grid's rhythm instead of
   dropping the record.
*/
.cn-event-thumb {
  display: block;
  aspect-ratio: 231 / 120;
  border-radius: var(--cn-radius-card);
  overflow: hidden;
  text-decoration: none;
  transition: box-shadow var(--cn-dur) var(--cn-ease);
}

/* An EVENT banner is branded artwork with its own outlined box on a
   transparent ground: shown whole, on the page's white, nothing drawn
   around it - the same tile Home's Upcoming Events and the readers' foot
   draw. A WEBINAR picture is a stock photograph: it fills the rounded box
   and is cropped to it (cover), so the tile reads as a rounded picture. */
.cn-event-thumb__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.cn-event-thumb--webinar .cn-event-thumb__img { object-fit: cover; }

a.cn-event-thumb:hover { box-shadow: var(--cn-shadow-card); }

a.cn-event-thumb:focus-visible {
  outline: 2px solid var(--cn-cyan);
  outline-offset: 3px;
}

/* The placeholder: the mark at a third of the box, on a light outlined card. */
.cn-event-thumb--placeholder {
  background: var(--cn-surface);
  border: 1px solid var(--cn-border);
}
.cn-event-thumb--placeholder .cn-event-thumb__img {
  padding: 12% 22%;
  box-sizing: border-box;
}

/* ============================================= EVENT PHOTO STRIP ======= */
/*
   p21's two "event images on rotation" rows, wired to the CRM's event photo
   galleries. Four in view, 171.4 x 130.3 each on the artboard - the same box
   .cn-tbd--rotator reserved while this was a placeholder.

   NO JAVASCRIPT, and no timer. The track holds the list TWICE; when the first
   copy has scrolled exactly its own width, the second copy sits where the
   first began, so the animation can jump back to zero and nothing moves on
   screen. That is the whole loop - one transform, no state, no eighth JS file
   to deploy alongside the CSS.

   Translating -50% works because the two copies are identical in width, which
   they are: same cell count, same fixed cell width.

   ONE DURATION, NOT ONE PER CELL COUNT. Scaling the speed to the number of
   photos would need the count on the element, and the only inline style this
   codebase allows is --cn-topic-set. The strips ask the CRM for eight each,
   so 48s is 6s a picture at full strength; a gallery with fewer moves
   proportionally quicker, which is a nicer failure than a custom property
   smuggled onto every strip.

   The tag refuses to draw fewer than four, because below that the doubled
   track is narrower than the column and the loop shows its own end.
*/
.cn-photo-strip {
  --cn-photo-cell: 171px;
  --cn-photo-gap: var(--cn-space-5);
  /* One row of the artboard's rotation blocks: 130.3px at that cell width. */
  --cn-photo-h: 130px;

  overflow: hidden;
  /* The cells are a fixed width, so a narrow viewport scrolls rather than
     squashing them out of their measured ratio. */
  -webkit-overflow-scrolling: touch;
}

.cn-photo-strip__track {
  display: flex;
  gap: var(--cn-photo-gap);
  width: max-content;
  animation: cn-photo-roll 48s linear infinite;
}

/* Stop for anyone who wants to look at one. Focus-within as well as hover,
   so it also stops for a keyboard reader moving through the page. */
.cn-photo-strip:hover .cn-photo-strip__track,
.cn-photo-strip:focus-within .cn-photo-strip__track {
  animation-play-state: paused;
}

/*
   SQUARE, NOT ROUNDED. p21 draws the "event images on rotation" boxes with
   square corners; it is the event and webinar tiles beside them that are
   rounded. These were rounded and the tiles were read as the reverse.
*/
.cn-photo-strip__cell {
  flex: 0 0 var(--cn-photo-cell);
  width: var(--cn-photo-cell);
  height: var(--cn-photo-h);
  border-radius: 0;
  overflow: hidden;
  background: var(--cn-band-grey);
}

/*
   COVER, NOT CONTAIN. These are photographs of a room, not cover art or a
   logo - there is no edge that matters and no whitespace to preserve, so
   filling the cell is right where the magazine covers needed the opposite.
*/
.cn-photo-strip__cell img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@keyframes cn-photo-roll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/*
   REDUCED MOTION: no rotation at all, and the strip becomes an ordinary row
   the reader scrolls themselves. The duplicate cells are still in the DOM and
   would read as the gallery repeating, so they are dropped here rather than
   left as a stutter halfway along.
*/
@media (prefers-reduced-motion: reduce) {
  .cn-photo-strip { overflow-x: auto; }
  .cn-photo-strip__track { animation: none; }
  .cn-photo-strip__cell[aria-hidden="true"] { display: none; }
}

/* ============================================ EVENTS PAGE RHYTHM (p21) === */
/*
   The distances down p21's content column, measured (1pt = 2.4px). None of
   them is the shell's 48, so the page carries its own rather than cn-mt-12
   five times over:

     intro copy      ->  event tiles           28
     tile rows       ->  next row              31   (grid row-gap)
     tile columns    ->  next column           20   (grid column-gap)
     last tile       ->  photo strip           37
     strip           ->  "CeFPro webinars"     39
     heading         ->  webinar tiles         10
     webinar tiles   ->  second strip          32
     strip           ->  "CeFPro Academy"      33
     heading         ->  academy tiles         10
     academy tiles   ->  "You may be
                          interested in"       44
     heading         ->  the five cards         8
*/
/* Fixed pixels, not the fluid tokens: these are one board's measurements
   for one column, and the tokens with those values (space-7, -9, -11) do
   not exist. */
.cn-events__tiles      { margin-top: 28px; }
.cn-events__strip      { margin-top: 37px; }
.cn-events__strip--second { margin-top: 32px; }
.cn-events__webinars   { margin-top: 39px; }
.cn-events__academy    { margin-top: 33px; }
.cn-events__interested { margin-top: 44px; }

/* Heading to tiles: 10 on the two tile grids, 8 above the five cards -
   the heading's own 16 is overridden, nothing is added under it. */
.cn-events__webinars .cn-section-heading,
.cn-events__academy .cn-section-heading   { margin-bottom: 10px; }
.cn-events__interested .cn-section-heading { margin-bottom: var(--cn-space-2); }

/* 20 across, 31 down - the board's tile gutters, not the grid's default. */
.cn-events__grid {
  --cn-grid-gap: var(--cn-space-5);
  column-gap: var(--cn-space-5);
  row-gap: 31px;
}

@media (max-width: 767px) {
  .cn-events__grid { row-gap: var(--cn-space-4); }
}
