/* ══════════════════════ THE PROGRAMME BOARD ═══════════════════════════════
   The whole conference, one column per day.

   Four days side by side on a desktop; a tab strip and a single column below
   lg, because four columns on a phone is four columns of nothing. The day
   switching is done by :checked on hidden radio inputs, so it works with
   scripting off — JavaScript only adds arrow-key navigation on top of it.

   Loaded by the homepage and the participant portal. Both use the same markup
   (app/views/public/_schedule-board.php), so the board a delegate sees signed
   in is the board they saw signed out.
   ────────────────────────────────────────────────────────────────────────── */

.pc-board { position: relative; }
.pc-board-radio { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }

/* ── The day tabs. Only rendered where the columns collapse to one. ─────── */
.pc-board-tabs { display: none; }

.pc-board-tab {
  flex: 1 1 0; min-width: 4.2rem; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: .05rem;
  padding: .6rem .35rem; border-radius: var(--radius-sm);
  border: 1.5px solid var(--line); background: var(--surface);
  transition: border-color .15s, background .15s, transform .15s;
  -webkit-tap-highlight-color: transparent;
}
.pc-board-tab:hover { border-color: var(--brand); }
.pc-board-tab:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.pc-board-tab-dow {
  font-size: .64rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.pc-board-tab-day { font-size: 1.35rem; font-weight: 800; line-height: 1; }
.pc-board-tab-mon {
  font-size: .6rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.pc-board-tab-count {
  font-size: .6rem; font-weight: 700; color: var(--muted);
  background: var(--surface-2); border-radius: 999px;
  padding: .05rem .4rem; margin-top: .15rem;
}
.pc-board-tab-now {
  font-size: .58rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: #fff; background: #15803d; border-radius: 999px;
  padding: .08rem .42rem; margin-top: .15rem;
}
.pc-board-tab.is-past { opacity: .55; }

/* ── The columns ────────────────────────────────────────────────────────── */
.pc-board-grid {
  display: grid; gap: .9rem;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}

/* min-width:0 matters: without it a long session title widens its own track
   and the four columns stop being equal. */
.pc-board-col { display: flex; flex-direction: column; gap: .55rem; min-width: 0; }

/* Capped and independently scrollable — this is the HOMEPAGE TEASER only.
   With a full programme this stopped being optional: the desktop grid
   stretches every column to the height of its tallest sibling, so one busy
   day (38 sessions on the real Pre-COP31 agenda) forced all four to 5,900px
   and dragged the whole homepage down with it — the board alone was half the
   page. Below 62em only one day shows at a time (see the narrow-screen rule
   further down), and that single column ran just as long on its own, so the
   cap applies there too rather than only above the four-column breakpoint.
   The scrollbar is the site's existing thin one (app.css), nothing extra to
   draw; the last card cut off at the bottom is the hint that there is more.

   Sized with svh, not vh: a phone's address bar hides and shows as the reader
   scrolls, and vh is measured against the TALLEST that gets, so a percentage
   height set while the bar is hidden overshoots the moment it reappears. svh
   is always the smallest the viewport gets, so the cap never promises more
   room than is reliably there.

   .pc-board-full turns this off completely — see below. */
.pc-board-col {
  max-height: min(34rem, 58svh);
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: .35rem;   /* room for the scrollbar so cards don't shift under it */
  /* Clears the sticky day heading, so a card brought into view by the
     keyboard lands below the heading instead of underneath it. */
  scroll-padding-top: 3rem;
}

/* The FULL programme — /programme and the portal's own programme page. That
   screen exists so a reader can browse every session; capping the exact
   thing they came to read, the way the homepage teaser must, would crop the
   one page where cropping is never right. _schedule-board.php adds this
   class in place of the cap whenever it is passed $boardCompact = false. */
.pc-board-full .pc-board-col {
  max-height: none;
  overflow: visible;
  padding-right: 0;
}

/* ── The full programme shows a day's first eight, then offers the rest ──────
   The compact board caps a column's HEIGHT and lets the reader scroll inside
   it. That was refused for this page — the programme must not be cropped — and
   the result was a 6,800px page, seven and a half screens, because four
   uncapped columns of up to forty sessions have nowhere to go but down.

   So this caps the COUNT instead. Eight sessions per day are shown and the
   rest are one button away, which is about two screens instead of seven and a
   half, and nothing is buried in a scrollbar inside a scrollbar.

   The hidden cards are still IN the document — display:none, not absent — so
   find-in-page, a screen reader's list of links and a crawler all still reach
   the whole programme. That is also why this is not lazy loading: every
   session is already on the page, all 130 of them inside 150 KB. The problem
   was length, not weight.

   nth-of-type counts among the anchors, and .pc-board-card is the only anchor
   that is a direct child of a column (.pc-board-more is a button), so neither
   the column head nor the scroll arrow throws the count off.

   The class is added by board.js, never by the server: with no JavaScript the
   page renders exactly as it does today, whole. */
.pc-board-col.is-clamped > .pc-board-card:nth-of-type(n + 9) { display: none; }

.pc-board-showall {
  flex: none;
  margin-top: .4rem;
  padding: .62rem .9rem;
  border: 1px dashed rgba(19,79,160,.3);
  border-radius: .6rem;
  background: transparent;
  color: #134FA0;
  font: inherit; font-size: .86rem; font-weight: 700;
  text-align: center; cursor: pointer;
  transition: background .16s ease, border-color .16s ease;
}
.pc-board-showall:hover,
.pc-board-showall:focus-visible {
  background: rgba(19,79,160,.06);
  border-style: solid;
  border-color: #134FA0;
}
.pc-board-showall:focus-visible { outline: 2px solid var(--reef-2); outline-offset: 2px; }
.pc-board-showall .bi { margin-right: .35rem; }

@media (prefers-reduced-motion: reduce) {
  .pc-board-showall { transition: none; }
}

/* ── "More below" ───────────────────────────────────────────────────────
   One per column, appearing only while board.js measures that day's list as
   genuinely scrollable and disappearing once the reader is within a few
   pixels of its true end — the same shape of affordance a chat thread uses
   for "jump to the newest message", pointed at the rest of the day's sessions
   instead. Built out of the identity, echoing .pc-totop (precop.css): same
   gradient, same drawn-ring, an arrow that nudges on hover. Rendered `hidden`
   by default and never un-hidden on .pc-board-full, where nothing overflows.

   position: sticky, not fixed or absolute: it has to float at the bottom of
   whichever CARDS are currently visible as the reader scrolls the column, and
   only sticky lets it do that while still being carried along by, and finally
   settling back into, its own place after the real last card — which is also
   the instant board.js hides it, so it never sits there as a dangling button
   once there is nothing left below. */
/* ── The arrow gets a LANE, rather than sitting on the text ────────────────
   It is sticky and opaque, so it floats over whichever card happens to be at
   the bottom of the scrolled column — and once each card carried an organiser,
   a two-line name like "The University of the South Pacific, School of Law and
   Social Sciences" ran under it and lost its tail. Measured at 1024: three
   separate cards with glyphs buried, up to 19px in.

   So the column reserves a strip on its right and the button is pulled out
   into it with a negative margin. Cards are a little narrower on the compact
   board; nothing is ever hidden underneath. Only the compact board needs this
   — board.js never un-hides the arrow on .pc-board-full, where nothing
   overflows. */
.pc-board:not(.pc-board-full) .pc-board-col { padding-right: 2.7rem; }
.pc-board:not(.pc-board-full) .pc-board-more { margin-right: -2.55rem; }

.pc-board-more {
  position: sticky; bottom: .5rem; align-self: flex-end; flex: none;
  width: 2.35rem; height: 2.35rem; padding: 0; border: 0; border-radius: 50%;
  cursor: pointer; z-index: 2;
  background: linear-gradient(140deg, var(--brand-2) 0%, var(--brand) 55%, var(--brand-deep) 100%);
  box-shadow: 0 8px 20px -8px rgba(0,48,144,.55);
  transition: transform .18s ease, box-shadow .18s ease;
}
.pc-board-more:hover, .pc-board-more:focus-visible {
  transform: translateY(2px);
  box-shadow: 0 10px 22px -8px rgba(0,48,144,.65), 0 0 0 5px rgba(0,160,80,.2);
}
.pc-board-more:focus-visible { outline: 2px solid var(--reef-2); outline-offset: 3px; }
.pc-board-more svg { width: 100%; height: 100%; display: block; }
.pc-board-more-ring { fill: none; stroke: rgba(255,255,255,.34); stroke-width: 1.4; }
.pc-board-more-arrow {
  fill: none; stroke: #fff; stroke-width: 2.1;
  stroke-linecap: round; stroke-linejoin: round;
}
.pc-board-more:hover .pc-board-more-arrow { animation: pcBoardMoreNudge .9s ease-in-out infinite; }

@keyframes pcBoardMoreNudge {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(2.5px); }   /* down, not up — .pc-totop nudges the other way */
}

@media (prefers-reduced-motion: reduce) {
  .pc-board-more { transition: none; }
  .pc-board-more:hover { transform: none; }
  .pc-board-more:hover .pc-board-more-arrow { animation: none; }
}

/* ── The day stays in sight ───────────────────────────────────────────────
   Scrolling a day's sessions used to carry its heading away with them, so a
   reader halfway down a column could no longer tell which day it was. The
   heading now sticks: on the capped board to the top of its own scrolling
   column, and on the full program to the top of the window, just under the
   site's bar (--pc-stick-top, measured by board.js). Its background is opaque,
   so the cards pass cleanly underneath. */
.pc-board-colhead {
  display: flex; align-items: baseline; gap: .4rem;
  padding: .5rem .7rem; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line);
  position: sticky; top: 0; z-index: 3;
}
.pc-board-full .pc-board-colhead { top: var(--pc-stick-top, 0px); }
.pc-board-colhead.is-today {
  background: color-mix(in srgb, var(--brand) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--brand) 45%, var(--line));
}
.pc-board-colday { font-weight: 800; font-size: .92rem; }
.pc-board-colmon {
  font-size: .66rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.pc-board-livedot {
  width: .5rem; height: .5rem; border-radius: 50%; background: #15803d;
  margin-left: auto; box-shadow: 0 0 0 3px color-mix(in srgb, #15803d 22%, transparent);
}

/* ── A session ──────────────────────────────────────────────────────────── */
.pc-board-card {
  position: relative; display: flex; flex-direction: column; gap: .18rem;
  padding: .7rem .8rem .7rem 1rem;
  border-radius: var(--radius-sm); text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--line);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
/* The pillar colour as a spine down the left edge rather than a wash across
   the card: at four columns a tinted background becomes a patchwork, and the
   session title stops being the thing you read first. */
.pc-board-card::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--tint, var(--brand));
}
.pc-board-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px -12px rgba(2, 24, 48, .35);
  border-color: color-mix(in srgb, var(--tint, var(--brand)) 55%, var(--line));
}
.pc-board-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.pc-board-time {
  font-size: .72rem; font-weight: 800; letter-spacing: .03em;
  color: var(--tint, var(--brand)); font-variant-numeric: tabular-nums;
}
.pc-board-dash { opacity: .5; margin: 0 .12rem; }
.pc-board-title { font-weight: 700; font-size: .88rem; line-height: 1.3; }

/* ── Who is running the session ───────────────────────────────────────────
   Clamped to two lines rather than cut to a character count in PHP: this same
   card renders about 313px wide inside .container on the homepage and about
   367px inside .pc-container-wide on /programme, so any one character limit
   would cut a name short on one page and waste a third of a line on the other.
   The organisers are long — a median of 39 characters and a maximum of 104 —
   and two lines holds the great majority of them whole. The full string is in
   the element's title attribute either way.

   max-height is the fallback for engines without -webkit-line-clamp: two lines
   of .7rem text at 1.25. It errs towards showing slightly less rather than
   letting a four-line organiser push the title out of a capped column. */
.pc-board-org {
  font-size: .7rem; line-height: 1.25; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; max-height: 1.75rem;
}

.pc-board-meta {
  display: flex; flex-wrap: wrap; gap: .1rem .6rem;
  font-size: .7rem; color: var(--muted); margin-top: .1rem;
}
.pc-board-meta i { margin-right: .2rem; }

/* The hotel, in the same colour as the spine — this is the thing that makes
   the spine decodable at all. Weighted, because on a board mixing two venues
   it is what a delegate scans for. */
.pc-board-venue { color: var(--tint, var(--brand)); font-weight: 700; }

.pc-board-state {
  align-self: flex-start; margin-top: .3rem;
  font-size: .62rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  border-radius: 999px; padding: .1rem .45rem;
  background: var(--surface-2); color: var(--muted);
}
.pc-board-state-register   { background: color-mix(in srgb, #15803d 15%, var(--surface)); color: #15803d; }
.pc-board-state-waitlist   { background: color-mix(in srgb, #b45309 16%, var(--surface)); color: #b45309; }
.pc-board-state-registered { background: color-mix(in srgb, var(--brand) 15%, var(--surface)); color: var(--brand); }

.pc-board-empty {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  padding: 1.4rem .8rem; border-radius: var(--radius-sm);
  border: 1px dashed var(--line); color: var(--muted);
  font-size: .76rem; text-align: center;
}
.pc-board-empty i { font-size: 1.1rem; opacity: .6; }

/* ── Narrow screens: a tab strip, and one day at a time ─────────────────── */
@media (max-width: 61.99em) {
  .pc-board-tabs { display: flex; gap: .4rem; margin-bottom: 1rem; }
  /* On the full program the tab strip is where the date is, so it is what
     stays in sight as the day's sessions scroll, just under the site's bar.
     Padding rather than margin below it, so the cards pass under an opaque
     strip instead of through a see-through gap. */
  .pc-board-full .pc-board-tabs {
    position: sticky; top: var(--pc-stick-top, 0px); z-index: 4;
    background: var(--bg); padding: .5rem 0; margin-bottom: .5rem;
  }

  .pc-board-grid { grid-template-columns: 1fr; }
  /* display:none rather than visibility, so a hidden day costs no height. */
  .pc-board-col { display: none; }
  .pc-board-colhead { display: none; }        /* the tab already carries the date */

  .pc-board-radio:nth-of-type(1):checked ~ .pc-board-grid .pc-board-col:nth-child(1),
  .pc-board-radio:nth-of-type(2):checked ~ .pc-board-grid .pc-board-col:nth-child(2),
  .pc-board-radio:nth-of-type(3):checked ~ .pc-board-grid .pc-board-col:nth-child(3),
  .pc-board-radio:nth-of-type(4):checked ~ .pc-board-grid .pc-board-col:nth-child(4),
  .pc-board-radio:nth-of-type(5):checked ~ .pc-board-grid .pc-board-col:nth-child(5),
  .pc-board-radio:nth-of-type(6):checked ~ .pc-board-grid .pc-board-col:nth-child(6),
  .pc-board-radio:nth-of-type(7):checked ~ .pc-board-grid .pc-board-col:nth-child(7),
  .pc-board-radio:nth-of-type(8):checked ~ .pc-board-grid .pc-board-col:nth-child(8) {
    display: flex;
  }

  .pc-board-radio:nth-of-type(1):checked ~ .pc-board-tabs .pc-board-tab:nth-child(1),
  .pc-board-radio:nth-of-type(2):checked ~ .pc-board-tabs .pc-board-tab:nth-child(2),
  .pc-board-radio:nth-of-type(3):checked ~ .pc-board-tabs .pc-board-tab:nth-child(3),
  .pc-board-radio:nth-of-type(4):checked ~ .pc-board-tabs .pc-board-tab:nth-child(4),
  .pc-board-radio:nth-of-type(5):checked ~ .pc-board-tabs .pc-board-tab:nth-child(5),
  .pc-board-radio:nth-of-type(6):checked ~ .pc-board-tabs .pc-board-tab:nth-child(6),
  .pc-board-radio:nth-of-type(7):checked ~ .pc-board-tabs .pc-board-tab:nth-child(7),
  .pc-board-radio:nth-of-type(8):checked ~ .pc-board-tabs .pc-board-tab:nth-child(8) {
    border-color: var(--brand);
    background: color-mix(in srgb, var(--brand) 12%, var(--surface));
  }

  .pc-board-card { padding: .8rem .9rem .8rem 1.1rem; }
  .pc-board-title { font-size: .95rem; }
}

@media (max-width: 29.99em) {
  .pc-board-tab { min-width: 0; padding: .5rem .2rem; }
  .pc-board-tab-day { font-size: 1.15rem; }
}

@media (prefers-reduced-motion: reduce) {
  .pc-board-card, .pc-board-tab { transition: none; }
  .pc-board-card:hover { transform: none; }
}

/* ── The colour key on /programme ─────────────────────────────────────────
   One line under the filter bar saying what the tints mean. Rendered from
   venues.colour, the same source the tiles read, so it cannot describe a
   colour the board is not using. */
.pc-prog-key {
  display: flex; flex-wrap: wrap; gap: .35rem 1.1rem;
  margin: -.6rem 0 1rem; font-size: .78rem; color: var(--muted);
}
.pc-prog-key-item { display: inline-flex; align-items: center; gap: .4rem; }
.pc-prog-key-dot {
  width: .7rem; height: .7rem; border-radius: 3px; flex: none;
  /* An outline as well as a fill: at .7rem a colour alone is hard to judge,
     and it keeps the swatch visible in high-contrast mode, where the fill is
     left as the real venue colour precisely so the key still works. */
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.25);
}
html[data-a11y-contrast="on"] .pc-prog-key { color: #fff !important; }
html[data-a11y-contrast="on"] .pc-prog-key-dot { box-shadow: inset 0 0 0 1px #fff; }
