/* ==============================================================================
   EVENTS BLOCK
   ============================================================================== */

/* --event-tile is the side of the square every event starts with, the
   calendar or the icon. It is the fixed first column of each row and, in
   the timeline, the spine runs through its centre, so everything that
   lines up with the tile reads it from here. */
.block-events {
  --event-tile: 4.5rem;

  background: var(--paper-bg);
  border-radius: var(--radius-lg);
  padding: var(--spacing-lg) var(--spacing-md);
  box-shadow: var(--shadow-sm);
}

.events {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--spacing-lg);
}

/* minmax(0, 1fr) rather than 1fr: a long word or link in the text must
   wrap inside its column, never push the row wider than a 320 px phone. */
.event {
  display: grid;
  grid-template-columns: var(--event-tile) minmax(0, 1fr);
  column-gap: var(--spacing-md);
  align-items: start;
}

/* --------------------------------------------------------------------------
   The tile: a small calendar, or an icon for an event without a date
   -------------------------------------------------------------------------- */

/* Every tile is a cream page with the site's gold on top, the same in
   every skin and theme: Juan chose it on 2026-10-12 from a sheet of six
   (pure white read too bright on the red, the red tile too much like the
   card around it), and asked the icon tile to match. Its own small
   palette lives here rather than in tokens.css because nothing else uses
   it: ink the dark of the buttons, a muted rose-grey for the weekday
   (5.9:1 on the cream), the accent band with that same dark ink (9:1)
   and a rose-grey edge. */
.event__tile {
  --calendar-paper: #f1e6e1;
  --calendar-ink: #2b0f12;
  --calendar-muted: #6b4a4d;
  --calendar-band: var(--accent-blue);
  --calendar-band-ink: var(--accent-contrast);
  --calendar-edge: #c9a9a4;
  position: relative;
  z-index: 1;
  width: var(--event-tile);
  height: var(--event-tile);
  border-radius: var(--radius-md);
  border: 1px solid var(--calendar-edge);
  background: var(--calendar-paper);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.event__date {
  display: flex;
  flex-direction: column;
  text-align: center;
}

/* The band is the top of a desk calendar: the gold accent, the month in
   dark capitals. */
.event__band {
  min-height: 1.25rem;
  background: var(--calendar-band);
  color: var(--calendar-band-ink);
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1.25rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* tabular-nums keeps "11" and "13" the same width, so a column of tiles
   does not wobble from one day to the next. */
.event__day {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--calendar-ink);
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.event__weekday {
  padding-bottom: var(--spacing-xs);
  color: var(--calendar-muted);
  font-size: 0.75rem;
  line-height: 1.2;
}

/* A month without a day shows the month's short name big; capitalize
   turns "oct" into "Oct" without touching the ui.json text. */
.event__date--month .event__day {
  font-size: 1.3rem;
  text-transform: capitalize;
}

/* The icon tile is the same page with an empty band on top (the
   ::before, the band's own height) and the icon where the day number
   would be, in the same ink, so a list that mixes dated and undated
   events reads as one set of sheets. */
.event__icon {
  display: grid;
  grid-template-rows: 1.25rem 1fr;
  color: var(--calendar-ink);
}

.event__icon::before {
  content: "";
  background: var(--calendar-band);
}

.event__icon svg {
  width: 2.25rem;
  height: 2.25rem;
  place-self: center;
  fill: currentColor;
}

/* --------------------------------------------------------------------------
   The text beside the tile
   -------------------------------------------------------------------------- */

.event__body {
  min-width: 0;
  overflow-wrap: break-word;
}

.event__heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--spacing-xs) var(--spacing-sm);
}

.event__title {
  margin: 0;
  color: var(--text-primary);
  font-size: var(--font-size-lg);
  line-height: 1.3;
}

.event__time {
  color: var(--accent-blue);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.event__badge {
  padding: 0 var(--spacing-sm);
  border: 1px dashed var(--accent-blue);
  border-radius: var(--radius-full);
  color: var(--accent-blue);
  font-size: 0.8rem;
  font-weight: 600;
}

.event .prose {
  margin-top: var(--spacing-xs);
}

.event .prose > :first-child {
  margin-top: 0;
}

.event .prose > :last-child {
  margin-bottom: 0;
}

.event__link {
  display: inline-block;
  margin-top: var(--spacing-sm);
  color: var(--accent-blue);
}

/* --------------------------------------------------------------------------
   Timeline: the same rows along a spine, the tile as the node
   -------------------------------------------------------------------------- */

/* The rows touch (no gap) so each one's segment of the spine meets the
   next; the space between events is each row's own bottom padding. */
.block-events--timeline .events {
  gap: 0;
}

.block-events--timeline .events > li {
  position: relative;
  padding-bottom: var(--spacing-lg);
}

/* Each row draws its own stretch of the spine, through the centre of the
   tile column, so an upcoming event can draw its stretch dashed. */
.block-events--timeline .events > li::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--event-tile) / 2 - 1px);
  width: 2px;
  background: var(--border-color);
}

/* The spine ends at the last node instead of running past it. */
.block-events--timeline .events > li:last-child::before {
  bottom: auto;
  height: calc(var(--event-tile) / 2);
}

.block-events--timeline .is-upcoming::before {
  width: 0;
  background: none;
  border-left: 2px dashed var(--border-color);
}

/* What has not happened yet is drawn lighter: the same white page with a
   dashed edge, no shadow and the band outlined instead of filled. */
.block-events--timeline .is-upcoming .event__tile {
  border-style: dashed;
  box-shadow: none;
}

.block-events--timeline .is-upcoming .event__band {
  background: none;
  color: var(--calendar-muted);
  border-bottom: 1px dashed var(--calendar-edge);
}

/* The day's photo: under the text on a phone (the text column), opposite
   the text across the spine from a tablet up. A 4:3 box with the image
   covering it, so a vertical photo and a wide one take the same room. */
.event__photo {
  grid-column: 2;
  margin: var(--spacing-sm) 0 0;
}

.event__photo img {
  display: block;
  width: 100%;
  max-width: 20rem;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

/* A month marker sits in the text column on phones, with its own small
   node on the spine. */
.events__month {
  display: grid;
  grid-template-columns: var(--event-tile) minmax(0, 1fr);
  column-gap: var(--spacing-md);
  align-items: center;
}

.events__month::after {
  content: "";
  position: absolute;
  top: 0.55rem;
  left: calc(var(--event-tile) / 2 - 0.4rem);
  width: 0.8rem;
  height: 0.8rem;
  border-radius: var(--radius-full);
  background: var(--accent-blue);
}

.events__month h3 {
  grid-column: 2;
  margin: 0;
  color: var(--accent-blue);
  font-size: 1rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* From a tablet up the spine moves to the middle and the events alternate
   on either side of it, the tile on the spine as the node. */
@media (min-width: 768px) {
  .block-events {
    --event-tile: 5rem;

    padding: var(--spacing-xl);
  }

  .block-events--timeline .events > li {
    grid-template-columns: minmax(0, 1fr) var(--event-tile) minmax(0, 1fr);
    column-gap: var(--spacing-lg);
  }

  .block-events--timeline .events > li::before {
    left: calc(50% - 1px);
  }

  .block-events--timeline .event__tile {
    grid-column: 2;
    grid-row: 1;
  }

  .block-events--timeline .event__body {
    grid-column: 3;
    grid-row: 1;
  }

  /* Every other event (counting events only, not the month markers
     between them) goes to the left of the spine, its text aligned
     towards it. */
  .block-events--timeline .event:nth-child(odd of .event) .event__body {
    grid-column: 1;
    text-align: right;
  }

  .block-events--timeline .event:nth-child(odd of .event) .event__heading {
    justify-content: flex-end;
  }

  /* The photo takes the column the text left free: right of the spine
     when the text is on the left, and the other way round, pushed
     against the spine so the pair reads as one row. */
  .block-events--timeline .event__photo {
    grid-column: 1;
    grid-row: 1;
    justify-self: end;
    margin: 0;
  }

  .block-events--timeline .event:nth-child(odd of .event) .event__photo {
    grid-column: 3;
    justify-self: start;
  }

  .events__month::after {
    content: none;
  }

  /* The marker is a label laid on the spine itself, opaque so the line
     passes behind it. */
  .events__month h3 {
    grid-column: 1 / -1;
    justify-self: center;
    position: relative;
    z-index: 1;
    padding: var(--spacing-xs) var(--spacing-md);
    border: 1px solid var(--accent-blue);
    border-radius: var(--radius-full);
    background: var(--paper-bg);
  }
}

/* --------------------------------------------------------------------------
   Reveal on scroll (static/js/timeline.js)
   -------------------------------------------------------------------------- */

/* Only when the script has said it is running (has-timeline-js on
   <html>) and the visitor has not asked for less motion: without either,
   nothing here applies and every event is simply there. Only opacity and
   transform move, which the browser animates without relayout. */
@media (prefers-reduced-motion: no-preference) {
  .has-timeline-js .block-events--timeline .event {
    transition: opacity 0.5s ease, transform 0.5s ease;
  }

  .has-timeline-js .block-events--timeline .event:not(.is-revealed) {
    opacity: 0;
    transform: translateY(1.5rem);
  }
}
