/* ============================================================
   GunksFest — schedule page
   Loaded after css/style.css; reuses its :root palette and buttons.
   ============================================================ */

/* ---------- Page head ---------- */
.schedule-head {
  position: relative; isolation: isolate; overflow: hidden;
  color: #fff;
  padding: clamp(6rem, 12vw, 9rem) 0 clamp(3.5rem, 7vw, 5.5rem);
}
/* The photo sits on its own absolutely-positioned layer so js/main.js can
   translate it independently of the copy — that is the whole of the parallax.
   .section-bg in style.css already supplies the position, the fill and the
   z-index; this only names the picture and frames it. The shared
   `html.js .section-photo .section-bg` rule bleeds the layer 90px past the
   section top and bottom, so the photo can lag behind the scroll without ever
   pulling a section edge into view.

   Photo first, brand gradient underneath. If the file is missing the layer
   simply doesn't paint and the gradient carries the section on its own. */
.schedule-head .section-bg {
  background-image:
    url("../assets/img/2025-08-gunksfest-sarah-karbachinskiy-5350.jpg"),
    linear-gradient(165deg, var(--color-forest) 0%, var(--color-forest-dk) 100%);
  background-size: cover, auto;
  /* Crop is set by where the group lands, not by the horizon: high enough to
     show the whole group, heads down to feet on the ledge, which is the point
     of this picture. The trade is that the heads come up beside the headline
     rather than below it; they clear it horizontally, since the copy is
     left-aligned and the group is centre-right. Lower the percentage to buy
     the headline clean sky again, at the cost of cutting everyone off around
     the waist.

     Re-tuned when the layer gained its parallax bleed: `cover` fills the
     layer's box, and that box is now 180px taller than the section, so the
     same percentage no longer frames the same crop. */
  background-position: center 52%, center;
  background-repeat: no-repeat;
}
/* A summit photo, so the scrim can be lighter than a shaded one needs: enough
   to hold the copy, not so much that the sky and the valley stop being the
   point of the picture. Measured against the actual text band with the copy
   hidden — white on the lightest 10px patch is 5.8:1, clearing AA for body
   text with room to spare as the crop shifts across viewport widths. Going
   further (0.66 at the top) measures 4.8:1, which is too close to the 4.5
   line to be safe. */
.schedule-head-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(170deg, rgba(20,37,31,0.74) 0%, rgba(20,37,31,0.58) 45%, rgba(20,37,31,0.84) 100%);
}
.schedule-head .container { position: relative; z-index: 2; }
.schedule-head h1,
.schedule-head .eyebrow,
.schedule-head .lead { text-shadow: 0 2px 10px rgba(0,0,0,0.55); }
.schedule-head .lead strong { color: #fff; font-weight: 700; }
/* Four sentences now, so the last line kept stranding a single word. Ignored by
   browsers that don't support it, which just get the orphan back. */
.schedule-head .lead { text-wrap: pretty; }
/* No blend at the seams. See .page-schedule .rope-divider below for why. */
.schedule-head h1 {
  font-size: clamp(2.2rem, 6vw, 3.6rem);
  margin: 0 0 0.75rem;
  color: #fff;
}
.schedule-head .eyebrow { color: var(--color-accent-light); }
.schedule-head .lead { color: rgba(255, 255, 255, 0.9); margin-bottom: 0; }

/* Both sides of every seam on this page are dark, which is the condition the
   home page's dividers were built for: the feather band reads as shadow under
   the rope rather than as a band, and the join disappears. The shared rule in
   style.css does the positioning; the only thing overridden below is how far
   the band's lower half reaches. */
/* Nothing should paint over the blend, and the schedule must start below it. */
.page-schedule .rope-divider { z-index: 3; }
/* No offset on the lower divider: the shared rule in style.css already centres
   the rope on the join, and that is where it belongs.

   Measured rather than eyeballed, and worth keeping measured because the
   margin here depends on the photo below. It was worked out while a bright sky
   photo sat in the CTA, which made this join a hard luminance step (about 33
   to 122) that the feather band could tint but never erase — only the rope
   itself covered it. The photo below is darker now and the step is far
   gentler, but the geometry below is what holds either way, so swapping in
   another bright photo needs no rethink.

   Method, worth repeating if this ever needs re-checking: hide the divider,
   screenshot the bare strip, and average each row across the width. The seam
   is perfectly straight so it survives that averaging as a sharp row-to-row
   step; the rope waves, so its own edges smear away. Then sweep the offset and
   watch the residual step. Offsets from -11px to +3px all bottom out at the
   same floor — the seam is covered, and what's left is the rope's own top
   edge. Past +4 the residual climbs (25.9 at +10px) and sits exactly `offset`
   pixels above the rope's mid-line: that is the join, creeping out from under
   a rope that has been lowered off it.

   So a nudge here has a budget of roughly -11px to +3px, and 0 is the middle
   of it. Any nudge must ride on the whole divider rather than the rope alone,
   since the feather band has to travel with the rope to keep doing its half of
   the job — which is why the modifier class stays on the wrapper in
   clinics.html even with no declaration left in this rule. */

/* The lower divider uses the shared band from style.css, unmodified: 46px of
   fade either side of the seam. That symmetry is right whenever both sides of
   a join are dark, which is the case here — dark clinic list above, and a
   shaded forest photo below whose own top is nearly as dark as the band. The
   band is then read as shadow under the rope rather than as a band of its own.

   It was briefly trimmed to 18px on the underside, which mattered when a
   bright sky photo sat in the CTA: against sky those 46px smeared visibly out
   of the rope and washed out the top of the picture. That photo has since
   moved to the page head, so the reason went with it. If a bright photo ever
   comes back down here, that is the knob — `bottom: -18px; height: 64px` on
   .page-schedule .rope-divider--lower::before, with the gradient's peak kept
   on the seam. */

.schedule-section { position: relative; z-index: 1; }

/* ---------- Section shell ---------- */
/* The rope's feather band is rgba(20,37,31,·). Anchor this section's top and
   bottom on that exact colour (#14251f, the same ground the page already uses)
   and the band becomes invisible where it matters — which is the whole trick
   the home page relies on. The middle lifts slightly so 9000px of it isn't flat;
   the ends stay pinned so the seams still vanish. */
.schedule-section {
  background: linear-gradient(to bottom, #14251f 0%, #1b3128 22%, #1b3128 78%, #14251f 100%);
  padding-top: clamp(3.5rem, 7vw, 5rem);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- Controls ---------- */
.schedule-controls { margin: 0 0 2rem; display: grid; gap: 0.9rem; }

.day-tabs { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.day-tab {
  font: inherit; font-weight: 700; cursor: pointer;
  padding: 0.55rem 1.15rem; border-radius: 999px;
  border: 2px solid rgba(255,255,255,0.32);
  background: rgba(255,255,255,0.07); color: #fff;
  transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.day-tab:hover { border-color: var(--color-accent-light); background: rgba(255,255,255,0.16); }
.day-tab.is-active {
  background: #fff; border-color: #fff; color: var(--color-forest);
}

/* Second row: smaller, lighter pills so the day picker above stays the
   primary control and these read as a refinement of it. */
.filter-pills { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.filter-label {
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: rgba(255,255,255,0.62); margin-right: 0.2rem;
}
.filter-pill {
  font: inherit; font-size: 0.85rem; font-weight: 600; cursor: pointer;
  padding: 0.3rem 0.8rem; border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.28);
  background: transparent; color: rgba(255,255,255,0.85);
  transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.filter-pill:hover { border-color: var(--color-accent-light); color: #fff; }
.filter-pill.is-active {
  background: var(--color-accent-dk); border-color: var(--color-accent-dk); color: #fff;
}
.filter-clear {
  font: inherit; font-size: 0.85rem; cursor: pointer;
  padding: 0.3rem 0.5rem; border: 0; background: none;
  color: rgba(255,255,255,0.7); text-decoration: underline;
}
.filter-clear:hover { color: #fff; }

.day-tab:focus-visible, .filter-pill:focus-visible, .filter-clear:focus-visible {
  outline: 3px solid var(--color-accent-dk); outline-offset: 2px;
}

/* The "more to come" note. Sits between the controls and the list because it
   qualifies the list: it is the answer to "is this everything?", which is the
   question a half-published line-up invites. Bordered rather than boxed, so it
   reads as an aside on the schedule rather than as the alert that
   .schedule-status is. */
.schedule-upcoming {
  margin: 0 0 2rem;
  padding: 0.1rem 0 0.1rem 1rem;
  border-left: 3px solid var(--color-accent);
  color: rgba(255, 255, 255, 0.78);
  max-width: 60ch;
}
.schedule-upcoming strong { color: #fff; font-weight: 700; }

/* ---------- Status / empty states ---------- */
.schedule-loading, .schedule-none {
  color: rgba(255,255,255,0.72); font-style: italic; margin: 2rem 0;
}
.schedule-status {
  margin: 0 0 2rem; padding: 1.25rem 1.5rem;
  border-radius: var(--radius); background: var(--color-cream);
  border-left: 4px solid var(--color-accent-dk);
  box-shadow: var(--shadow); color: var(--color-ink-soft);
  max-width: 60ch;
}
.schedule-status strong { color: var(--color-forest); font-size: 1.1rem; }
.schedule-status.is-error { border-left-color: #b3452e; }

.schedule-updated {
  margin: 2.5rem 0 0; font-size: 0.85rem; color: rgba(255,255,255,0.6);
}

/* ---------- Day blocks ---------- */
.schedule-day + .schedule-day { margin-top: 3rem; }
/* Scoped to the section so it outranks `.section h2` in style.css, which would
   otherwise keep these forest green — invisible now the ground is dark. */
.schedule-section .schedule-day-title {
  font-size: clamp(1.4rem, 3.2vw, 1.9rem);
  color: #fff;
  text-shadow: 0 2px 10px rgba(0,0,0,0.45);
  margin: 0 0 1.1rem;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--color-leaf);
}

.session-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }

/* ---------- Session card ---------- */
.session {
  display: grid;
  grid-template-columns: 10.5rem 1fr auto;
  gap: 0.5rem 1.5rem;
  align-items: start;
  background: var(--color-cream);
  border-radius: var(--radius);
  border-left: 4px solid var(--color-leaf);
  box-shadow: var(--shadow);
  padding: 1.35rem 1.5rem;
}
.session.is-gone { border-left-color: var(--color-stone); }
.session.is-gone .session-title { color: var(--color-ink-soft); }

.session-when {
  font-family: var(--font-display);
  font-weight: 700; font-size: 0.95rem;
  color: var(--color-accent-darker);
  text-wrap: balance;
  padding-top: 0.15rem;
  font-variant-numeric: tabular-nums;
}
.session-anytime { color: var(--color-stone); font-weight: 600; }

.session-title { margin: 0 0 0.45rem; font-size: 1.2rem; color: var(--color-forest); }


.session-desc {
  color: var(--color-ink-soft); font-size: 0.95rem;
  position: relative; max-height: 5.4em; overflow: hidden;
}
.session-desc.is-open { max-height: none; }
/* Fade the cut-off edge, but only while collapsed. */
.session-desc.is-clamped:not(.is-open)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2em;
  background: linear-gradient(to bottom, rgba(255,255,255,0), var(--color-cream));
}
.session-more {
  font: inherit; font-size: 0.85rem; font-weight: 700; cursor: pointer;
  margin-top: 0.35rem; padding: 0.15rem 0; border: 0; background: none;
  color: var(--color-accent-dk); text-decoration: underline;
}
.session-more:hover { color: var(--color-accent-darker); }
.session-more:focus-visible { outline: 3px solid var(--color-accent-dk); outline-offset: 2px; }
.session-desc p { margin: 0 0 0.5rem; }
.session-desc p:last-child { margin-bottom: 0; }
.session-desc ul, .session-desc ol { margin: 0 0 0.5rem; padding-left: 1.2rem; }
/* Markdown headings from the pretix description land here — "Prerequisites:",
   "Required Gear:" and friends. Keep them quiet; the card title outranks them. */
.session-desc h4, .session-desc h5, .session-desc h6 {
  margin: 0.7rem 0 0.25rem; font-size: 0.95rem; color: var(--color-forest);
  font-family: var(--font-body); font-weight: 700;
}
.session-desc code {
  font-size: 0.9em; background: var(--color-sand-dk);
  padding: 0.1em 0.35em; border-radius: 4px;
}
.session-desc strong { color: var(--color-ink); }

.session-side {
  display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem;
  text-align: right; min-width: 8rem;
}
.session-price {
  margin: 0; font-family: var(--font-display); font-weight: 700;
  font-size: 1.15rem; color: var(--color-forest);
}
.session-price.is-included {
  font-size: 1rem;   /* one word now, so it can sit near price weight */
  color: var(--color-forest);   /* same green as "+$50" */
}

.session-badge {
  margin: 0; font-size: 0.78rem; font-weight: 700;
  padding: 0.18rem 0.6rem; border-radius: 999px; white-space: nowrap;
}
.session-badge.is-open { background: #e3f2e4; color: #1f5f22; }
.session-badge.is-low  { background: #fdf0d8; color: #8a5a08; }
.session-badge.is-gone { background: #ece9e4; color: #5c554b; }

/* ---------- Reveal-on-scroll, matching the home page cards ---------- */
html.js .session { opacity: 0; transform: translateY(14px); transition: opacity 0.5s ease, transform 0.5s ease; }
html.js .session.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js .session { opacity: 1; transform: none; transition: none; }
}

/* ---------- Narrow screens ---------- */
@media (max-width: 720px) {
  .session {
    grid-template-columns: 1fr;
    gap: 0.35rem;
    padding: 1.15rem 1.25rem;
  }
  .session-side {
    flex-direction: row; align-items: center; justify-content: flex-start;
    text-align: left; margin-top: 0.6rem; flex-wrap: wrap;
  }
  .session-when { font-size: 0.95rem; }
}

/* ---------- CTA photo background ---------- */
.schedule-cta {
  position: relative; isolation: isolate; overflow: hidden;
}
/* Same split as the head: photo on its own layer so it can parallax. */
.schedule-cta .section-bg {
  background-image:
    url("../assets/img/2025-08-gunksfest-chris-vultaggio-2097.JPG"),
    linear-gradient(165deg, var(--color-forest) 0%, var(--color-forest-dk) 100%);
  background-size: cover, auto;
  background-position: center 34%, center;   /* the demo and the ring of climbers around it */
  background-repeat: no-repeat;
}
.schedule-cta-scrim {
  position: absolute; inset: 0; z-index: 1;
  /* An even wash rather than a ramp. The ramp this replaced started at 0.30,
     which was right when the photo here was a sky: nothing bright sat high in
     the frame, so the top could stay open. A dappled forest has no such
     ordering — sunlit patches land wherever they land, including directly
     behind the heading — and against those the old top measured 2.7:1, well
     under the 4.5 AA needs. Averages hid it: the same scrim averaged 11.9:1
     across the whole text band, which is why the lightest patch is the number
     worth trusting. This wash measures 7.3:1 there. */
  background: linear-gradient(to bottom,
    rgba(20,37,31,0.78) 0%, rgba(20,37,31,0.70) 45%, rgba(20,37,31,0.90) 100%);
}
.schedule-cta .container { position: relative; z-index: 2; }
.schedule-cta h2, .schedule-cta .lead { text-shadow: 0 2px 10px rgba(0,0,0,0.55); }
