/* ==========================================================================
   USRSE'26 program schedule
   Styles the markup generated by scripts/build-program.js
   (_includes/program-schedule.html).

   The accent is the US-RSE brand purple (#741755, --us-rse-main) and does
   four jobs: the day rule, the time-rail tick, the plenary field, and the
   session-type eyebrow. At 10.5:1 on white it passes WCAG AA at body sizes,
   so one swatch serves fields and small text alike. The neutrals mirror the
   theme: #4a4a4a body, #363636 titles, #dbdbdb hairlines. Muted is #757575 —
   the theme's #7a7a7a nudged one step darker because the raw swatch is 4.3:1
   on white, which fails WCAG AA at the 14px sizes it's used at here.

   The include renders inside the theme's Bulma `.content` wrapper, whose
   typography hits the generated h2/h3/p/ol/li at up to (0,2,1) specificity
   (`.content h3:not(:first-child)`, `.content ol:not([type])`, …) — more
   than any one-class rule here can muster. The reset block below re-zeroes
   those at matching specificity (this sheet loads after the theme, so ties
   land here). CONVENTION: component rules create space with padding, which
   `.content` never sets, so nothing below has to out-rank the reset.
   ========================================================================== */

.program {
  --program-accent: var(--us-rse-main);
  --program-ink: #4a4a4a;
  --program-strong: #363636;
  --program-muted: #757575;
  --program-hairline: #dbdbdb;
  --program-wash: #f4ecf1;

  /* Every session carries the same left inset so all titles share one hard
     left edge; only the plenary's background fills it. */
  --session-inset: 0.9rem;

  /* Time rail: labels are right-aligned against the gutter, so the track
     only needs to clear the worst-case label ("10:30am–12pm" at semibold
     15px measures ~100px). */
  --rail: 8.5rem;

  /* Gutter track owns the spine and tick; text and marker never share
     space. Spine is centered, so the body starts 18px clear of it. */
  --gutter: 2.25rem;

  --tick-size: 11px;
  --tick-top: 0.38rem;   /* offset from slot content top to the tick,
                            centering it on the title's first line */
  --slot-pad-y: 0.9rem;

  /* Cap on the talk label column. Each session sizes the column to its
     widest label, up to this — BIRD OF A FEATHER wraps beyond it. */
  --talk-gutter: 5.25rem;

  color: var(--program-ink);
}

/* --------------------------------------------------------------------------
   Theme neutralization — see the header comment. Bare variants cover the
   include rendering outside a `.content` wrapper.
   -------------------------------------------------------------------------- */

.content .program :is(h2, h3, p),
.program :is(h2, h3, p) {
  margin: 0;
}

.content .program ol,
.program ol {
  margin: 0;
  padding-left: 0;
  list-style: none;
}

.content .program li + li,
.program li + li {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
   Day pills — in-page jump nav to each day's section
   -------------------------------------------------------------------------- */

.program-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;   /* label sits on the pill text baseline */
  gap: 0.5rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--program-hairline);
}

.program-nav__label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--program-muted);
}

.program-nav__pill {
  padding: 0.3rem 1rem;
  border: 1px solid var(--program-hairline);
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--program-strong);
}

.program-nav__pill:hover,
.program-nav__pill:focus-visible {
  border-color: var(--program-accent);
  color: var(--program-accent);
}

/* --------------------------------------------------------------------------
   Day header — the accent day rule
   -------------------------------------------------------------------------- */

.program-day {
  margin-top: 2.75rem;
  scroll-margin-top: 5rem;   /* pill anchors clear the fixed navbar */
}

.program-nav + .program-day {
  margin-top: 1.75rem;
}

/* Two classes out-rank the theme's `.content h2` (size, weight, color). */
.program .program-day__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  padding-bottom: 0.45rem;
  border-bottom: 3px solid var(--program-accent);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--program-strong);
}

/* Provisional-schedule note, pushed to the far end of the day rule. */
.program-day__draft {
  margin-left: auto;
  padding-left: 1rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--program-muted);
}

/* --------------------------------------------------------------------------
   Slots — time / gutter / body. The tick has its own grid track: the spine
   and tick are positioned off .slot, not .slot__time, so a font swap can
   never push text into the marker.
   -------------------------------------------------------------------------- */

.slot {
  position: relative;
  display: grid;
  grid-template-columns: var(--rail) var(--gutter) minmax(0, 1fr);
  padding: var(--slot-pad-y) 0;
}

.slot + .slot {
  border-top: 1px solid var(--program-hairline);
}

/* Spine, centered in the gutter track */
.slot::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--rail) + var(--gutter) / 2);
  width: 2px;
  margin-left: -1px;
  background: var(--program-hairline);
}

/* The spine terminates at the last tick of each day rather than trailing
   past the final session. */
.program-day__slots > .slot:last-child::before {
  bottom: auto;
  height: calc(var(--slot-pad-y) + var(--tick-top) + var(--tick-size) / 2);
}

/* Tick — accent dot with a 3px white ring so the spine doesn't run
   visibly through it. Alignment rides --tick-top so compressed rows and
   the mobile breakpoint set their own value instead of drifting. */
.slot::after {
  content: "";
  position: absolute;
  top: calc(var(--slot-pad-y) + var(--tick-top));
  left: calc(var(--rail) + var(--gutter) / 2);
  width: var(--tick-size);
  height: var(--tick-size);
  margin-left: calc(var(--tick-size) / -2);
  border-radius: 50%;
  background: var(--program-accent);
  box-shadow: 0 0 0 3px #fff;
}

.slot__time {
  grid-column: 1;
  font-size: 0.9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
}

.slot__body {
  grid-column: 3;
  min-width: 0;
}

/* --------------------------------------------------------------------------
   Sessions — one line of title + room, the type eyebrow tucked beneath.
   The shared inset keeps every title on the same x, plenary or not. On
   sessions with no background it's invisible; on the plenary it's what
   the wash fills.
   -------------------------------------------------------------------------- */

.session {
  padding-left: var(--session-inset);
}

.session + .session {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--program-hairline);
}

/* Two classes out-rank the theme's `.content h3` (size, weight, color). */
.program .session__title {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--program-strong);
}

/* Inline after the title; em-sized so it tracks the muted rows' smaller
   titles too. */
.session__room {
  font-size: 0.9em;
  font-weight: 400;
  font-style: italic;
  color: var(--program-muted);
}

.session__eyebrow {
  padding-top: 0.2rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--program-accent);
}

/* Session chair, tucked next to the format on the eyebrow line — same
   size, but normal case and muted so the name doesn't read as a label. */
.session__chair {
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--program-muted);
}

.session__info {
  padding-top: 0.3rem;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--program-muted);
}

.session__talks {
  padding-top: 0.4rem;
}

/* Sessions that label events form a shared two-column grid whose label
   column hugs the session's widest label (capped at --talk-gutter), so a
   PAPER/TALK session indents titles ~3rem, not worst-case width, and a
   mixed session still aligns every title. Formatless sessions never form
   the grid — their titles stay on the session's left edge. No list
   marker either way — the aligned labels are the rhythm. */
.session__talks:has(.talk__format) {
  display: grid;
  grid-template-columns: fit-content(var(--talk-gutter)) minmax(0, 1fr);
  column-gap: 0.75rem;
}

.talk {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: 0.75rem;
  align-items: baseline;
  padding: 0.35rem 0;
  font-size: 0.9375rem;
  line-height: 1.4;
}

/* Each labeled row spans both tracks and aligns its label/title to the
   session's shared columns via subgrid. The fixed-gutter line before it
   is the fallback for browsers without subgrid; without :has() at all,
   rows are plain single-column — cosmetic degradation only. */
.session__talks:has(.talk__format) .talk {
  grid-column: 1 / -1;
  grid-template-columns: var(--talk-gutter) minmax(0, 1fr);
  grid-template-columns: subgrid;
}

/* Format label — quiet muted tag, sized like the session eyebrow so the
   two label systems read as one family. Long labels (BIRD OF A FEATHER)
   wrap inside the gutter, still right-aligned. */
.talk__format {
  grid-column: 1;
  text-align: right;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--program-muted);
}

/* The title (span when unlinked, anchor when linked) always occupies the
   last column — the text column when the gutter exists, the whole row
   when it doesn't — so sessions mixing labeled and unlabeled events keep
   one shared title edge. */
.talk > .talk__title,
.talk > .talk__link {
  grid-column: -2 / -1;
}

/* Abstract deep link — body-colored text over a quiet underline that
   turns accent on hover; the wrapped title keeps its weight. Two classes
   out-rank the theme's `.content a` color. */
.program .talk__link {
  color: var(--program-strong);
  text-decoration: underline;
  text-decoration-color: #b5b5b5;   /* the theme's grey-light */
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

.program .talk__link:hover,
.program .talk__link:focus-visible {
  text-decoration-color: var(--program-accent);
  text-decoration-thickness: 2px;
}

/* --------------------------------------------------------------------------
   Plenary field. The accent bar is an inset box-shadow, not a border — a
   border would push the text 3px right of the common edge; a shadow paints
   inside the box and costs no layout width. The field's top padding is
   cancelled by an equal negative margin so the title stays on the same
   baseline (and tick line) as every other session title.
   -------------------------------------------------------------------------- */

.session--plenary {
  --plenary-pad-top: 0.7rem;
  background: var(--program-wash);
  box-shadow: inset 3px 0 0 var(--program-accent);
  border-radius: 0 3px 3px 0;
  padding: var(--plenary-pad-top) 1rem 0.75rem var(--session-inset);
  margin-top: calc(-1 * var(--plenary-pad-top));
}

/* --------------------------------------------------------------------------
   Breaks, meals, registration — compressed, muted rows so the four-track
   blocks dominate the page. Muted rows also mute the tick; only real
   sessions carry the accent.
   -------------------------------------------------------------------------- */

.slot--break {
  --slot-pad-y: 0.55rem;
  --tick-top: 0.3rem;
  --tick-size: 9px;
}

.slot--break::after {
  background: #b5b5b5;   /* the theme's grey-light */
}

.slot--break .slot__time {
  font-size: 0.875rem;
  color: var(--program-muted);
}

.slot--break .session__title,
.session--muted .session__title {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--program-muted);
}

/* --------------------------------------------------------------------------
   Mobile — below 40rem the time label stacks above the body, so the
   plenary hoist is cancelled (it would slide the field under the time
   label) and the rail collapses to a slim spine at the left edge.
   -------------------------------------------------------------------------- */

@media (max-width: 40rem) {
  .slot {
    grid-template-columns: 1.5rem minmax(0, 1fr);
    --tick-top: 0.35rem;
  }

  .slot::before,
  .slot::after {
    left: 0.75rem;
  }

  .slot__time {
    grid-column: 2;
    text-align: left;
  }

  .slot__body {
    grid-column: 2;
    margin-top: 0.4rem;
  }

  .session--plenary {
    margin-top: 0;
  }
}

/* --------------------------------------------------------------------------
   Print — clears both the wash and the bar, so a printed plenary is plain
   text with just the eyebrow, matching the unshaded program PDF layout.
   -------------------------------------------------------------------------- */

@media print {
  .program {
    color: #000;
  }

  .program-nav {
    display: none;
  }

  .session--plenary {
    background: none;
    box-shadow: none;
    margin-top: 0;
    padding-top: 0;
  }

  .slot::before,
  .slot::after {
    display: none;
  }

  .slot {
    grid-template-columns: var(--rail) 1rem minmax(0, 1fr);
  }
}
