/* ============================================================
   AnalyticsDev — style.css
   Single stylesheet. No build step. Edit directly.

   COLOUR TOKENS — update these to change the whole site theme
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;700&family=IBM+Plex+Sans:wght@300;400;600;700&display=swap');

:root {
  --color-bg:         #ffffff;
  --color-text:       #111827;
  --color-text-muted: #6b7280;
  --color-accent:     #111827;
  --color-accent-hl:  #15803d;   /* signal green — CTA buttons & highlights, legible on white */
  --color-border:     #e5e7eb;
  --color-surface:    #f9fafb;
  --color-gold:       #ca8a04;   /* Gold Partner badge */
  --color-urgent:     #a16207;   /* deep gold — the one price with a deadline */
}

/* ============================================================
   RESET & BASE
   ============================================================ */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: var(--color-text);
  background: var(--color-bg);
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: var(--color-accent);
  text-decoration: underline;
}

a:hover {
  color: var(--color-accent-hl);
}

/* ============================================================
   TYPOGRAPHY
   ============================================================ */

h1, h2, h3, h4 {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  line-height: 1.2;
}

h1 { font-size: clamp(2.5rem, 6vw, 4rem); }
h2 { font-size: clamp(1.5rem, 3vw, 2rem); margin-bottom: 1rem; }
h3 { font-size: 1.125rem; }

.text-muted {
  color: var(--color-text-muted);
  font-size: 0.9rem;
}

/* ============================================================
   LAYOUT
   ============================================================ */

.container {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 1.5rem;
}

section {
  padding: 4rem 0;
}

section + section {
  border-top: 1px solid var(--color-border);
}

/* ============================================================
   NAVIGATION
   ============================================================ */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  padding: 0.75rem 0;
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.nav-logo {
  display: flex;
  align-items: center;
  text-decoration: none;
}

.nav-logo img {
  height: 32px;
  width: auto;
}

.nav-links {
  display: flex;
  list-style: none;
  gap: 2rem;
}

.nav-links a {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 0.875rem;
  text-decoration: none;
  color: var(--color-text);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.nav-links a:hover {
  color: var(--color-accent-hl);
}

/* Mobile nav toggle */
.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.25rem;
  flex-direction: column;
  gap: 5px;
}

.nav-toggle span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--color-text);
  border-radius: 2px;
  transition: opacity 0.2s;
}

/* ============================================================
   BUTTONS
   ============================================================ */

.btn {
  display: inline-block;
  padding: 0.75rem 1.75rem;
  border-radius: 4px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 0.9375rem;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  white-space: nowrap;
}

.btn-primary {
  background: var(--color-accent-hl);
  color: #ffffff;
  border: 2px solid var(--color-accent-hl);
}

.btn-primary:hover {
  background: #166534;
  border-color: #166534;
  color: #ffffff;
}

.btn-secondary {
  background: transparent;
  color: var(--color-text);
  border: 2px solid var(--color-text);
}

.btn-secondary:hover {
  background: var(--color-text);
  color: var(--color-bg);
}

.btn-group {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
}

/* ============================================================
   HERO SECTION
   ============================================================ */

/* The hero shares the page's white ground — it is the first page of the
   printed programme, not a separate surface. With no dark field to carry
   it, the weight comes from the wordmark and the greyscale speaker strip,
   and the structure from the same hairlines every section below uses.
   The hero declares no colour tokens of its own: it reads straight from
   :root, so it can never drift from the rest of the page. */
.hero {
  /* Bottom padding lives here so the archive hero (no split/roster)
     gets a floor too. Inner blocks add space above it, never below. */
  padding: 4.5rem 0 3rem;
  border-top: none;
  background: var(--color-bg);
  color: var(--color-text);
}

/* Left column carries the wordmark and the ask; right column carries
   the facts. Splitting them gives the hero a focal point it lacked. */
.hero-split {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 3.5rem;
  align-items: start;
  padding-bottom: 3rem;
}

/* Reads as a path / identifier, not a label */
.hero-eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-bottom: 1.5rem;
}

/* The wordmark set as a monospace identifier. The weight break names
   the two halves of the audience: analysts who write code. */
.hero h1 {
  font-family: 'IBM Plex Mono', monospace;
  font-size: clamp(2.75rem, 7vw, 4.5rem);
  font-weight: 300;
  letter-spacing: -0.045em;
  line-height: 1;
  color: var(--color-text);
  margin-bottom: 1.5rem;
}

.hero h1 .wordmark-dev {
  font-weight: 700;
}

.hero-tagline {
  font-size: 1.0625rem;
  color: var(--color-text-muted);
  max-width: 40ch;
  margin-bottom: 2.25rem;
  line-height: 1.65;
}

/* --- Facts panel — the event as a properties readout --- */

.hero-panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  overflow: hidden;
}

.hero-panel-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.75rem;
  color: var(--color-accent-hl);
  padding: 0.75rem 1.125rem;
  border-bottom: 1px solid var(--color-border);
}

.hero-panel-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent-hl);
  flex: none;
}

/* Key/value facts as a description list: two columns, hairline-ruled */
.hero-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8125rem;
}

.hero-facts dt,
.hero-facts dd {
  padding: 0.6875rem 0;
}

.hero-facts dt {
  color: var(--color-text-muted);
  white-space: nowrap;
  padding-left: 1.125rem;
  padding-right: 1rem;
}

.hero-facts dd {
  color: var(--color-text);
  text-align: right;
  padding-right: 1.125rem;
}

/* Rule spans the full row: skip the first pair */
.hero-facts dt:not(:first-of-type),
.hero-facts dt:not(:first-of-type) + dd {
  border-top: 1px solid var(--color-border);
}

/* The one number with urgency gets the warm accent */
.hero-facts dd.is-early {
  color: var(--color-urgent);
}

.venue-tba {
  color: var(--color-text-muted);
  font-style: italic;
}

/* --- Buttons --- */
/* No hero overrides: on the shared white ground the hero's Register
   button is the site's primary button, unmodified. */

.hero .btn:focus-visible,
.hero-link-quiet:focus-visible {
  outline: 2px solid var(--color-accent-hl);
  outline-offset: 3px;
}

/* One ask gets a button. The secondary route stays a quiet link so the
   hierarchy reads at a glance and the pair never wraps into a stack. */
.hero-link-quiet {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  text-decoration: none;
  /* One step darker than the section hairline: on white, --color-border
     leaves the underline invisible and the link stops reading as a link. */
  border-bottom: 1px solid #d1d5db;
  padding-bottom: 2px;
  transition: color 0.15s, border-color 0.15s;
}

.hero-link-quiet:hover {
  color: var(--color-text);
  border-bottom-color: var(--color-text);
}

/* Deliberate stack, not an accidental wrap: the ask, then the aside */
.hero .btn-group {
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
}

/* --- Archive hero (2026/) shares .hero ---
   Its button and stats now inherit the site rules unchanged; only the
   date/venue line needs hero-specific styling. */

/* Date/venue line on the archive page — the panel's flat cousin */
.hero-meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.875rem;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-accent-hl);
  border-radius: 0 4px 4px 0;
  padding: 0.625rem 1.125rem;
  display: inline-block;
  margin-bottom: 2rem;
}

/* --- Speaker contact sheet — the floor of the hero ---
   Greyscale unifies seven headshots shot in seven different rooms;
   hover resolves one back to full colour. On the white ground this band
   is the darkest mass in the hero, so it does the anchoring the dark
   field used to — and staying uncoloured leaves the Register button as
   the only saturated thing in the hero. */

.hero-speakers {
  border-top: 1px solid var(--color-border);
  padding-top: 2.25rem;
}

/* Label left, controls right — the arrows sit in the header rather than
   floating over the photos, so nothing covers a face. */
.hero-speakers-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.hero-speakers-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.hero-speakers-nav {
  display: flex;
  gap: 0.375rem;
  flex: none;
}

/* Square and hairline-ruled: the same vocabulary as the facts panel,
   not a pair of floating circular arrows borrowed from a slideshow. */
.carousel-btn {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.875rem;
  line-height: 1;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.carousel-btn:hover:not(:disabled) {
  color: var(--color-text);
  border-color: var(--color-text);
}

.carousel-btn:focus-visible {
  outline: 2px solid var(--color-accent-hl);
  outline-offset: 2px;
}

/* Play/pause icons: one shape shows at a time, driven by the nav's
   data-playing state. Drawn rather than set as glyphs so they can't
   arrive as emoji on someone's machine. */
.carousel-btn svg {
  width: 10px;
  height: 10px;
  fill: currentColor;
  display: block;
}

.hero-speakers-nav[data-playing="true"] .icon-play,
.hero-speakers-nav[data-playing="false"] .icon-pause {
  display: none;
}

/* Scroll-snap does the carousel: native touch swipe, native keyboard
   scrolling, and snap points that always land a tile flush to the left
   edge. The JS only drives the arrows and their disabled states. */
.hero-speakers-track {
  --tiles: 4;            /* max per row; breakpoints step this down */
  --tile-gap: 1rem;

  display: flex;
  gap: var(--tile-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* The arrows are the affordance; a scrollbar here would sit between
     the photos and their captions and break the record. */
  scrollbar-width: none;
}

.hero-speakers-track::-webkit-scrollbar {
  display: none;
}

/* The track is keyboard-scrollable, so it must show focus */
.hero-speakers-track:focus-visible {
  outline: 2px solid var(--color-accent-hl);
  outline-offset: 4px;
}

/* Exactly --tiles across the track, gaps subtracted — never a fraction
   of a tile peeking, which the arrows would then have to explain. */
.hero-speaker-tile {
  flex: 0 0 calc((100% - (var(--tiles) - 1) * var(--tile-gap)) / var(--tiles));
  scroll-snap-align: start;
}

.hero-speaker-frame {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 3px;
  background: var(--color-surface);
  /* Hairline over the photo: several headshots were shot against white
     walls and would otherwise bleed into the page. An inward outline
     draws above the image without changing the tile's box — an inset
     box-shadow would be painted under it. */
  outline: 1px solid rgba(17, 24, 39, 0.12);
  outline-offset: -1px;
}

.hero-speaker-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Contrast only, no brightness cut: the source photos vary from very
     dark to blown-out, and contrast is what makes them read as one set. */
  filter: grayscale(1) contrast(1.08);
  transition: filter 0.45s ease;
}

.hero-speaker-tile:hover .hero-speaker-photo {
  filter: grayscale(0) contrast(1);
}

/* Left-aligned mono captions read as a data table, not a yearbook.
   Three stacked lines — who, what they do, where — rather than one
   run-on line: the line break separates them and the @ marks where the
   affiliation starts, with no separator to break at an awkward point.
   At four across, every name and title fits on one line, so the three
   rows stay level across the track without a min-height reserve. */
.hero-speaker-name {
  display: block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--color-text);
  margin-top: 0.75rem;
}

.hero-speaker-role,
.hero-speaker-org {
  display: block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.6875rem;
  line-height: 1.45;
  color: var(--color-text-muted);
}

.hero-speaker-role {
  margin-top: 0.25rem;
}

@media (prefers-reduced-motion: reduce) {
  .hero-speaker-photo {
    transition: none;
  }

  /* The arrows jump the track instead of animating it. scrollBy() with
     no explicit behavior defers to this property, so the preference is
     handled here rather than duplicated in the script. */
  .hero-speakers-track {
    scroll-behavior: auto;
  }

  /* Autoplay never starts under this preference, so there is nothing
     for a pause control to pause. */
  [data-carousel-toggle] {
    display: none;
  }
}

/* ============================================================
   SECTION INTRO (used below headings in announcement mode)
   ============================================================ */

.section-intro {
  color: var(--color-text-muted);
  font-size: 0.9375rem;
  margin-bottom: 2rem;
  margin-top: -0.5rem;
}

/* ============================================================
   ABOUT SECTION
   ============================================================ */

/* Names the community this event belongs to, set as a namespace path —
   the same device as the hero eyebrow, one level up. */
.about-parent {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-bottom: 0.75rem;
}

.about-parent a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--color-border);
}

.about-parent a:hover {
  color: var(--color-accent-hl);
  border-bottom-color: currentColor;
}

/* The segment you are already on — no link, full contrast */
.about-parent-current {
  color: var(--color-text);
}

.about-text {
  font-size: 1.0625rem;
  line-height: 1.8;
  max-width: 700px;
  margin-bottom: 2rem;
}

/* Format tags styled as schema/type tokens — monospace, compact, no uppercase shouting */
.format-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
}

.format-tag {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  font-size: 0.8rem;
  letter-spacing: 0;
  padding: 0.3rem 0.7rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  color: var(--color-text);
}

/* Format cards — expanded from token pills to brief descriptions */
.format-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin-top: 0.5rem;
}

.format-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 1rem 1.25rem;
}

.format-card-name {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 0.875rem;
  color: var(--color-text);
  margin-bottom: 0.4rem;
}

.format-card-desc {
  font-size: 0.8375rem;
  color: var(--color-text-muted);
  line-height: 1.5;
}

/* ============================================================
   AUDIENCE / WHO ATTENDS SECTION
   ============================================================ */

.audience-qualifier-line {
  font-size: 0.9375rem;
  color: var(--color-text-muted);
  margin-bottom: 0.75rem;
}

.audience-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.audience-tool {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8rem;
  padding: 0.25rem 0.625rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  color: var(--color-text);
}

/* ============================================================
   PROGRAMME SECTION
   ============================================================ */

.programme-date {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.9375rem;
  color: var(--color-text-muted);
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--color-border);
}

.programme-list {
  list-style: none;
}

.programme-item {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 1rem;
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--color-border);
  align-items: start;
}

.programme-item:first-child {
  border-top: 1px solid var(--color-border);
}

.programme-time {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.875rem;
  color: var(--color-accent-hl);
  font-weight: 500;
  padding-top: 0.1rem;
}

.programme-desc {
  font-size: 0.9375rem;
  line-height: 1.5;
}

.programme-desc strong {
  display: block;
  font-family: 'IBM Plex Sans', sans-serif;
}

.programme-item--multistream .programme-desc {
  color: var(--color-text);
}

.multistream-note {
  display: inline-block;
  margin-top: 0.35rem;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  font-style: italic;
}

/* Concurrent streams grid */
.streams-wrapper {
  padding: 0.75rem 0 0;
}

.streams-rotation {
  margin-bottom: 1.25rem;
}

.streams-rotation-time {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8rem;
  color: var(--color-accent-hl);
  font-weight: 500;
  margin-bottom: 0.625rem;
  display: block;
}

.streams-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.75rem;
}

/* Left-edge accent mirrors the VS Code/Grafana "active panel" pattern —
   familiar to anyone who works in technical tooling */
.stream-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 2px solid var(--color-accent-hl);
  border-radius: 0 4px 4px 0;
  padding: 0.75rem;
}

.stream-label {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-hl);
  margin-bottom: 0.35rem;
}

.stream-speaker {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 0.875rem;
  margin-bottom: 0.2rem;
}

.stream-session {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  line-height: 1.4;
}

.streams-break {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0;
  color: var(--color-text-muted);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.8rem;
}

.streams-break::before,
.streams-break::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

@media (max-width: 640px) {
  .streams-grid {
    grid-template-columns: 1fr;
  }
}

/* ============================================================
   SPEAKERS SECTION
   ============================================================ */

/* The cards carry the hero contact sheet's vocabulary down the page:
   the same 4/5 frame, the same greyscale that resolves on hover, mono
   captions, and a square hairline control borrowed from the carousel
   arrows. What is new here is the drawer — a card can be opened. */

.speakers-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  /* Each card sizes to its own content. Without this, grid stretches a
     row to its tallest member, so opening one drawer inflated every
     neighbour into a tall empty box. */
  align-items: start;
  margin-bottom: 3rem;
}

.speaker-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--color-bg);
  transition: border-color 0.2s ease;
}

/* focus-within so keyboard users get the same edge as the mouse */
.speaker-card:hover,
.speaker-card:focus-within {
  border-color: var(--color-text);
}

/* The hairline below is the same move the hero frame makes: several of
   these portraits are cut out on white and would otherwise run straight
   into the caption with no edge at all. */
.speaker-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  filter: grayscale(1) contrast(1.08);
  transition: filter 0.45s ease;
}

/* Colour is the reward: hovering resolves a portrait, and an open card
   stays resolved — so an opened card is legible as open from across the
   grid, not just by its own marker. */
.speaker-card:hover .speaker-photo,
.speaker-card:has(.speaker-details[open]) .speaker-photo {
  filter: grayscale(0) contrast(1);
}

/* Placeholder when no image is present */
.speaker-photo-placeholder {
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--color-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  font-size: 2rem;
}

.speaker-info {
  display: flex;
  flex-direction: column;
  /* No bottom padding: the drawer supplies the card's bottom edge */
  padding: 0.875rem 1rem 0;
}

.speaker-name {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin-bottom: 0.25rem;
}

/* Mono, and two lines reserved: the longest titles ("Senior MarTech
   Consultant · MohrStade") wrap and the short ones do not, so without
   the reserve the drawer rule lands at a different height in every card
   of a row. */
.speaker-role {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  min-height: 3em;
  margin-bottom: 0;
}

/* CSS-only expand for bio + session. The negative margin pulls the rule
   out to the card's edges so it reads as a drawer front rather than an
   indented divider. */
.speaker-details {
  border-top: 1px solid var(--color-border);
  margin: 0.5rem -1rem 0;
  padding: 0 1rem;
}

.speaker-details summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  cursor: pointer;
  padding: 0.625rem 0;
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  list-style: none;
  user-select: none;
  transition: color 0.15s ease;
}

.speaker-details summary:hover,
.speaker-details[open] summary {
  color: var(--color-text);
}

.speaker-details summary:focus-visible {
  outline: 2px solid var(--color-accent-hl);
  outline-offset: 2px;
}

/* The same square hairline button as the carousel arrows. Two drawn
   bars rather than a glyph: on open the vertical bar collapses into the
   horizontal one, so plus becomes minus in one movement and no font has
   to be trusted to render an arrow. */
.speaker-details summary::after {
  content: '';
  flex: none;
  width: 18px;
  height: 18px;
  border: 1px solid var(--color-border);
  border-radius: 3px;
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: center, center;
  background-size: 7px 1px, 1px 7px;
  transition: background-size 0.25s ease, border-color 0.15s ease;
}

.speaker-details summary:hover::after {
  border-color: var(--color-text);
}

.speaker-details[open] summary::after {
  background-size: 7px 1px, 1px 0;
  border-color: var(--color-text);
}

.speaker-details summary::-webkit-details-marker {
  display: none;
}

.speaker-bio,
.speaker-session {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--color-text);
}

.speaker-bio {
  padding-bottom: 0.75rem;
}

.speaker-session {
  padding-bottom: 1rem;
}

/* The one saturated mark in the section, on the one line that says what
   this person is actually giving the room. */
.speaker-session-label {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-accent-hl);
  margin-bottom: 0.25rem;
}

/* The drawer slides rather than snapping, where the browser can do it
   without a wrapper element or script. Guarded: where ::details-content
   is unsupported the drawer simply opens instantly, as before. */
@supports selector(::details-content) {
  .speaker-details {
    interpolate-size: allow-keywords;
  }

  .speaker-details::details-content {
    block-size: 0;
    overflow: hidden;
    transition:
      block-size 0.3s ease,
      content-visibility 0.3s allow-discrete;
  }

  .speaker-details[open]::details-content {
    block-size: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .speaker-photo,
  .speaker-details summary::after {
    transition: none;
  }

  @supports selector(::details-content) {
    .speaker-details::details-content {
      transition: none;
    }
  }
}

.programme-directors {
  border-top: 1px solid var(--color-border);
  padding-top: 1.5rem;
}

.programme-directors-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: 0.5rem;
}

/* Still used by the 2026 archive page, which lists the pair as one line
   with no portraits. */
.programme-directors-names {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 0.9375rem;
}

/* Two directors, side by side. Deliberately not the speaker card: these
   two run the day rather than appear on it, so the portrait sits beside
   the text instead of on top of it and the pair reads as a footer to the
   speaker grid rather than two more entries in it. */
.director-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem;
  margin-top: 1rem;
}

.director-card {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 1.25rem;
  align-items: start;
}

/* Square, and the same grayscale-until-engaged treatment the speaker
   portraits get, so the two photo styles agree across the section. */
.director-photo {
  width: 96px;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-surface);
  filter: grayscale(1) contrast(1.08);
  transition: filter 0.45s ease;
}

.director-card:hover .director-photo,
.director-card:has(.director-details[open]) .director-photo {
  filter: grayscale(0) contrast(1);
}

.director-name {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin-bottom: 0.25rem;
}

/* The underline is dropped to the muted hairline the rest of the page
   uses, so a linked name still sits level with an unlinked one. */
.director-name a,
.director-bio a {
  color: var(--color-text);
  text-decoration-color: var(--color-border);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease, color 0.15s ease;
}

.director-name a:hover,
.director-bio a:hover {
  color: var(--color-accent-hl);
  text-decoration-color: currentColor;
}

.director-role {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  margin-bottom: 0.625rem;
}

.director-lead {
  font-size: 0.8125rem;
  line-height: 1.65;
}

/* Same drawer as the speaker cards, minus their negative margin: there is
   no card edge here for the rule to run out to. */
.director-details {
  margin: 0.5rem 0 0;
  padding: 0;
}

.director-bio p,
.director-bio li {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--color-text);
}

.director-bio p {
  padding-bottom: 0.75rem;
}

/* Selector carries the .director-bio p above it, so the shared paragraph
   padding is overridden without reaching for !important. */
.director-bio p.director-bio-label {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-accent-hl);
  padding-bottom: 0.25rem;
}

.director-bio-list {
  list-style: none;
  padding-bottom: 0.75rem;
}

.director-bio-list li {
  position: relative;
  padding-left: 1rem;
}

.director-bio-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 5px;
  height: 1px;
  background: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .director-photo {
    transition: none;
  }
}

/* ============================================================
   SPONSORS / PARTNERS SECTION
   ============================================================ */

.sponsor-tier {
  margin-bottom: 2.5rem;
}

.sponsor-tier-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
}

.sponsor-tier--gold .sponsor-tier-label {
  color: var(--color-gold);
}

.sponsor-tier--supporting .sponsor-tier-label {
  color: var(--color-text-muted);
}

.sponsor-logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2rem;
}

.sponsor-logo-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  transition: opacity 0.15s;
}

.sponsor-logo-link:hover {
  opacity: 0.75;
}

.sponsor-tier--gold .sponsor-logo-link img,
.sponsor-tier--gold .sponsor-logo-placeholder {
  height: 60px;
}

.sponsor-tier--supporting .sponsor-logo-link img,
.sponsor-tier--supporting .sponsor-logo-placeholder {
  height: 36px;
}

/* Placeholder when logo file not yet added */
.sponsor-logo-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 1.25rem;
  border: 2px dashed var(--color-border);
  border-radius: 4px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.sponsor-cta {
  margin-top: 1rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.sponsor-cta a {
  color: var(--color-text);
  font-weight: 600;
}

/* ============================================================
   PROGRAMME TBA STATE
   ============================================================ */

.programme-tba {
  padding: 1.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-accent-hl);
  border-radius: 4px;
  font-size: 0.9375rem;
  color: var(--color-text-muted);
}

.programme-tba a {
  color: var(--color-text);
  font-weight: 600;
}

/* Placeholder speaker card — no drawer to open, so it stays quiet:
   dashed edge, no hover, and bottom padding standing in for the drawer
   the announced cards carry. */
.speaker-card--placeholder {
  border-style: dashed;
  background: var(--color-surface);
}

.speaker-card--placeholder:hover,
.speaker-card--placeholder:focus-within {
  border-color: var(--color-border);
}

.speaker-card--placeholder .speaker-photo-placeholder {
  background: var(--color-surface);
  color: var(--color-border);
  font-size: 3rem;
  font-weight: 300;
}

/* Stands in for the drawer the announced cards carry, so a closed row
   containing a placeholder still has one flat bottom edge. */
.speaker-card--placeholder .speaker-info {
  padding-bottom: 2.9375rem;
}

.speaker-card--placeholder .speaker-name {
  color: var(--color-text-muted);
}

/* ============================================================
   ARCHIVE SECTION
   ============================================================ */

.archive-list {
  list-style: none;
}

.archive-list li {
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.9375rem;
}

.archive-list li:first-child {
  border-top: 1px solid var(--color-border);
}

.archive-list a {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  text-decoration: none;
  color: var(--color-text);
}

.archive-list a:hover {
  color: var(--color-accent-hl);
}

.archive-empty {
  color: var(--color-text-muted);
  font-style: italic;
  font-size: 0.9375rem;
}

/* ============================================================
   EVENT STATS (archive pages)
   ============================================================ */

.event-stats {
  display: flex;
  gap: 2.5rem;
  margin-top: 2rem;
  flex-wrap: wrap;
}

.event-stat-value {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 2rem;
  color: var(--color-text);
  display: block;
  line-height: 1;
}

.event-stat-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 0.25rem;
  display: block;
}

/* ============================================================
   FOOTER
   ============================================================ */

.site-footer {
  border-top: 1px solid var(--color-border);
  padding: 2rem 0;
  margin-top: 0;
}

.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.footer-copy {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
}

.footer-links {
  display: flex;
  gap: 1.5rem;
  list-style: none;
  flex-wrap: wrap;
}

.footer-links a {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  text-decoration: none;
}

.footer-links a:hover {
  color: var(--color-text);
}

/* ============================================================
   ARCHIVE PAGE BANNER
   ============================================================ */

.archive-banner {
  position: sticky;
  top: 0;
  z-index: 101;
  background: #fef9c3;
  border-bottom: 2px solid #fbbf24;
  padding: 0.75rem 0;
  text-align: center;
}

.archive-banner p {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 0.875rem;
  color: #92400e;
}

.archive-banner a {
  color: #92400e;
  font-weight: 700;
}

.event-passed {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 1rem;
  color: var(--color-text-muted);
  border: 2px solid var(--color-border);
  border-radius: 4px;
  padding: 0.75rem 1.5rem;
  display: inline-block;
}

/* ============================================================
   RESPONSIVE — TABLET (≤768px)
   ============================================================ */

@media (max-width: 768px) {
  .speakers-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  /* Half a container is not enough width for a 96px portrait plus a
     readable measure, so the two directors stack instead. */
  .director-grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  /* Facts panel drops below the wordmark rather than beside it */
  .hero-split {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .hero-panel {
    max-width: 420px;
  }

  .hero-speakers-track {
    --tiles: 3;
  }

  .footer-inner {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ============================================================
   RESPONSIVE — MOBILE (≤640px)
   ============================================================ */

@media (max-width: 640px) {
  /* Nav collapse */
  .nav-toggle {
    display: flex;
  }

  .nav-links {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    flex-direction: column;
    gap: 0;
    padding: 0.5rem 0;
  }

  .nav-links.is-open {
    display: flex;
  }

  .nav-links li {
    border-bottom: 1px solid var(--color-border);
  }

  .nav-links a {
    display: block;
    padding: 0.75rem 1.5rem;
  }

  .site-nav {
    position: relative;
  }

  /* Two across from here down: at three, a tile is under 150px and the
     longer job titles wrap, which knocks their @affiliation line out of
     step with the neighbouring captions. */
  .hero-speakers-track {
    --tiles: 2;
  }

  /* Hero */
  .btn-group {
    flex-direction: column;
    align-items: flex-start;
  }

  .btn {
    width: 100%;
    text-align: center;
  }

  /* Format grid */
  .format-grid {
    grid-template-columns: 1fr;
  }

  /* Programme */
  .programme-item {
    grid-template-columns: 90px 1fr;
    gap: 0.5rem;
  }

  .programme-time {
    font-size: 0.8125rem;
  }
}

/* ============================================================
   RESPONSIVE — SMALL MOBILE (≤480px)
   ============================================================ */

@media (max-width: 480px) {
  .speakers-grid {
    grid-template-columns: 1fr;
  }

  /* Portrait moves above the text: beside it, the bio measure drops to
     roughly thirty characters and the paragraphs turn into a column of
     two-word lines. */
  .director-card {
    grid-template-columns: 1fr;
    gap: 0.875rem;
  }

  /* One card per row: there is nothing left to line up with, so drop the
     reserved second title line rather than leave a gap under every name. */
  .speaker-role {
    min-height: 0;
  }

  /* A full-width 4/5 portrait is nearly a screen tall here, and there are
     a dozen of them. Square keeps the same crop the frame always had
     while halving the scroll. */
  .speaker-photo,
  .speaker-photo-placeholder {
    aspect-ratio: 1 / 1;
  }

  /* One step down so "Nicolas Hinternesch" still clears a single line
     in a half-width tile and the caption rows stay level. */
  .hero-speaker-name {
    font-size: 0.75rem;
  }

  .hero-speaker-role,
  .hero-speaker-org {
    font-size: 0.625rem;
  }

  /* Below roughly 430px even the stepped-down title can wrap, so reserve
     two lines here and the @affiliation stays level either way. */
  .hero-speaker-role {
    min-height: 2.9em;
  }

  section {
    padding: 2.5rem 0;
  }

  .hero {
    padding: 3rem 0 2.5rem;
  }

  .hero-split {
    padding-bottom: 2.5rem;
  }
}
