/* JavaZone Planner — the whole stylesheet. No framework: design tokens are
   custom properties on :root and the components are written out by hand. Keep
   the "engineered timetable" look: mono times and room codes, a cool technical
   palette, generous but tight spacing.

   The fonts are served from this same origin (static/fonts/), not from Google,
   because the app is meant to run where there is no outbound internet — a CDN
   link there blocks first paint until it times out. assets.go rewrites the
   url() below to the font's content-hashed path at startup. */

/* inter · latin-ext */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(/static/fonts/inter-latin-ext.34b9c504.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* inter · latin */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(/static/fonts/inter-latin.3100e775.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* jetbrains-mono · latin-ext */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-latin-ext.db5ff4db.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* jetbrains-mono · latin */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/jetbrains-mono-latin.83c005d4.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* space-grotesk · latin-ext */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/space-grotesk-latin-ext.952dddb4.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* space-grotesk · latin */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/static/fonts/space-grotesk-latin.06408904.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --bg: #e7eaf0;
  --bg-grid: #dde1e9;
  --surface: #ffffff;
  --surface-2: #f4f6f9;
  --surface-3: #eceff4;
  --ink: #14171d;
  --ink-2: #565d6b;
  --ink-3: #8a91a0;
  --line: #d5dae2;
  --line-2: #c0c6d1;

  --go: #1f49d6;
  --go-ink: #12329c;
  --go-bg: #e7ecfd;
  --maybe: #a35a00;
  --maybe-bg: #f9ecd6;
  --clash: #c31d3c;
  --clash-bg: #fbe4e8;

  --fmt-pres: #3a4150;
  --fmt-light: #6d28d9;
  --fmt-light-bg: #efe8fd;
  --fmt-work: #0a7a53;
  --fmt-work-bg: #e0f4ec;

  --font-display: "Space Grotesk", system-ui, sans-serif;
  --font-body: Inter, system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --shadow-card: 0 1px 2px rgba(20, 23, 29, 0.06), 0 4px 16px rgba(20, 23, 29, 0.05);
  --shadow-panel: 0 12px 40px rgba(20, 23, 29, 0.18);
}

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

html, body { height: 100%; }

body {
  margin: 0;
  background-color: var(--bg);
  background-image:
    linear-gradient(var(--bg-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
  background-size: 28px 28px;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-family: var(--font-display); letter-spacing: -0.01em; }
a { color: var(--go); }
.mono { font-family: var(--font-mono); }
.muted { color: var(--ink-3); }
.grow { flex: 1; }

.app { min-height: 100%; display: flex; flex-direction: column; }
.main {
  flex: 1;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 22px 20px 60px;
}
/* htmx replaces this whole subtree on every pick. Chrome's scroll anchoring
   reacts to that by re-anchoring on content that no longer exists and jumps
   the viewport to the bottom of the page; excluding the swapped region from
   anchor selection keeps the reader where they were. Scoped here rather than
   on <body> so anchoring still works everywhere else. */
#view-body { overflow-anchor: none; }

.animate-fade { animation: fade 0.2s ease; }
@keyframes fade {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* ---- form controls ---------------------------------------------------- */
.input {
  width: 100%;
  padding: 10px 13px;
  border: 1px solid var(--line-2);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.input:focus {
  outline: none;
  border-color: var(--go);
  box-shadow: 0 0 0 4px rgba(31, 73, 214, 0.2);
}
.input-search { padding-left: 32px; }
textarea.input { resize: vertical; }

.select {
  appearance: none;
  padding: 8px 30px 8px 12px;
  border: 1px solid var(--line-2);
  border-radius: 7px;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M2 4l4 4 4-4' stroke='%23565d6b' stroke-width='1.5' fill='none' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.select:focus {
  outline: none;
  border-color: var(--go);
  box-shadow: 0 0 0 4px rgba(31, 73, 214, 0.2);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border: 1px solid var(--line-2);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s, border-color 0.15s;
}
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--go); border-color: var(--go); color: #fff; }
.btn-primary:hover { background: var(--go-ink); }
.btn-ghost { border-color: transparent; background: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--surface-3); color: var(--ink); }
.btn-lg { padding: 12px 20px; font-size: 15px; }

.checkline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  user-select: none;
}
.checkline input { width: 15px; height: 15px; accent-color: var(--go); }

/* ---- chips ------------------------------------------------------------ */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.5;
}
.chip-lang { font-family: var(--font-mono); text-transform: uppercase; background: var(--surface-3); color: var(--ink-2); border: 1px solid var(--line); }
.chip-duration { font-family: var(--font-mono); background: var(--go-bg); color: var(--go-ink); }
.chip-fmt-presentation { background: var(--surface-3); color: var(--fmt-pres); }
.chip-fmt-lightning-talk { background: var(--fmt-light-bg); color: var(--fmt-light); }
.chip-fmt-workshop { background: var(--fmt-work-bg); color: var(--fmt-work); }

/* ---- avatars ---------------------------------------------------------- */
.avatar {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 11.5px;
  flex: none;
}
.avatar-sm { width: 22px; height: 22px; font-size: 10px; }
.avatar-stack { border: 2px solid var(--surface); }
.avatar-stack + .avatar-stack { margin-left: -6px; }

.person-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px 3px 3px;
  border-radius: 999px;
  background: var(--surface-3);
  font-size: 12px;
  font-weight: 500;
}
.person-tag-maybe { opacity: 0.7; }

/* ---- top bar ---------------------------------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  padding: 12px 20px;
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 11px; }
.brand-mark {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  background: var(--ink);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  border-radius: 8px;
  flex: none;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-name { font-family: var(--font-display); font-weight: 600; font-size: 17px; letter-spacing: -0.02em; }
.brand-sub { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); text-transform: lowercase; }

.tabs {
  display: flex;
  gap: 3px;
  padding: 3px;
  background: var(--surface-3);
  border-radius: 9px;
}
.tab {
  padding: 7px 15px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
.tab:hover { color: var(--ink); }
.tab-active { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-card); }

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.user-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 11px 4px 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: inherit;
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
}
.user-btn:hover { background: var(--surface-2); }
.user-btn span { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.footer { border-top: 1px solid var(--line); padding: 16px 20px; }
.footer span {
  display: block;
  max-width: 1180px;
  margin: 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
}
.footer b { color: var(--maybe); }

/* ---- schedule --------------------------------------------------------- */
.filters {
  position: sticky;
  top: 60px;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 12px 14px;
  margin-bottom: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
}
.filters-search { position: relative; flex: 1; min-width: 260px; }
.filters-search .icon {
  position: absolute;
  left: 11px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-3);
  font-size: 15px;
  pointer-events: none;
}
.filters-selects { display: flex; flex-wrap: wrap; gap: 8px; }
.filters-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  width: 100%;
  padding-top: 2px;
  margin-top: 2px;
  border-top: 1px dashed var(--line);
}

/* Empty views get the same dashed, recessed placeholder as an empty row in a
   person's day — one idea at two scales. Left as bare centred text they read
   as a page that failed to render rather than a view that is legitimately
   empty, and the graph-paper background gives them nothing to sit on. */
.empty {
  max-width: 460px;
  margin: 44px auto;
  padding: 32px 28px;
  text-align: center;
  border: 1px dashed var(--line-2);
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 13.5px;
  line-height: 1.55;
}
.empty-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
  margin-bottom: 6px;
}

.day-head { display: flex; align-items: baseline; gap: 12px; margin: 28px 0 6px; }
.day-head:first-child { margin-top: 0; }
.day-head .dow { font-family: var(--font-display); font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.day-head .date { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-3); }
.day-head .count { margin-left: auto; font-size: 12.5px; color: var(--ink-3); }

.slot {
  display: grid;
  grid-template-columns: 74px 1fr;
  gap: 14px;
  padding: 16px 0;
  border-top: 1px solid var(--line);
}
.slot-time { position: relative; }
.slot-time .start { position: sticky; top: 128px; font-family: var(--font-mono); font-weight: 700; font-size: 16px; }
.slot-time .end { font-family: var(--font-mono); font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.slot-time .parallel { font-size: 11px; color: var(--ink-3); margin-top: 8px; }
.slot-time .parallel b { color: var(--clash); }
.slot-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 12px; }

/* ---- session card ----------------------------------------------------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 13px 14px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
  transition: transform 0.15s, border-color 0.15s;
}
.card:hover { transform: translateY(-1px); border-color: var(--line-2); }
.card-going { border-color: var(--go); box-shadow: 0 0 0 1px var(--go) inset, var(--shadow-card); }
.card-maybe { border-color: var(--maybe); }
.card-clash-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  border-radius: 10px 0 0 10px;
  background: repeating-linear-gradient(45deg, var(--clash) 0 5px, transparent 5px 10px);
}
.card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 9px; }
.card-where { margin-left: auto; font-family: var(--font-mono); font-size: 11.5px; font-weight: 500; color: var(--ink-2); }
.card-title {
  font-family: var(--font-display);
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.28;
  margin-bottom: 7px;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  color: inherit;
}
.card-title:hover { color: var(--go-ink); }
.card-speakers { font-size: 12.5px; color: var(--ink-2); margin-bottom: 11px; }
/* Kept as flowing text rather than a flex row: the talk title is long and
   would otherwise be squeezed into its own wrapping column. */
.card-warn {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--clash);
  margin: -4px 0 9px;
}
.card-warn b { font-weight: 600; }
.card-actions { margin-top: auto; display: flex; align-items: center; gap: 8px; }
.card-team { margin-left: auto; display: flex; align-items: center; }
.card-team .more { font-size: 11px; color: var(--ink-3); margin-left: 6px; }

.pickers { display: inline-flex; border: 1px solid var(--line-2); border-radius: 999px; overflow: hidden; }
.pick {
  padding: 5px 12px;
  border: 0;
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s;
}
.pick:hover { background: var(--surface-2); }
.pick + .pick { border-left: 1px solid var(--line-2); }
.pick-going-on { background: var(--go); color: #fff; }
.pick-going-on:hover { background: var(--go); }
.pick-maybe-on { background: var(--maybe); color: #fff; }
.pick-maybe-on:hover { background: var(--maybe); }

/* Radio inputs that drive the day/mode pickers: kept in the accessibility
   tree and focusable, but visually replaced by their label. */
.vh { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.vh:checked + .daytab { background: var(--ink); border-color: var(--ink); color: #fff; }
.vh:checked + .tab { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-card); }
.vh:focus-visible + .daytab,
.vh:focus-visible + .tab { outline: 2px solid var(--go); outline-offset: 2px; }
.hide-sm { display: inline; }

/* ---- day picker (timeline + team) ------------------------------------- */
.daytabs { display: flex; gap: 8px; flex-wrap: wrap; }
.daytab {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  line-height: 1.15;
  cursor: pointer;
  font: inherit;
}
.daytab:hover { border-color: var(--line-2); }
.daytab-active { background: var(--ink); border-color: var(--ink); color: #fff; }
.daytab .dow { display: block; font-family: var(--font-display); font-weight: 600; font-size: 14px; }
.daytab .date { font-family: var(--font-mono); font-size: 10.5px; opacity: 0.7; }

/* ---- timeline --------------------------------------------------------- */
.tl-stats { display: flex; flex-wrap: wrap; gap: 20px; align-items: center; margin: 18px 0 14px; }
.tl-stat { display: flex; flex-direction: column; }
.tl-stat .n { font-family: var(--font-display); font-size: 24px; font-weight: 700; letter-spacing: -0.02em; line-height: 1; }
.tl-stat .n.clash { color: var(--clash); }
.tl-stat .label { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; }

.tl-frame {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
  padding: 8px 14px 8px 0;
  overflow-x: auto;
  overflow-y: hidden;
}
.tl-grid { position: relative; margin-left: 62px; }
.tl-hour { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line); }
.tl-hour .label {
  position: absolute;
  left: -62px;
  top: -8px;
  width: 52px;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
}
.tl-half { position: absolute; left: 0; right: 0; border-top: 1px dashed var(--surface-3); }

.tl-block {
  position: absolute;
  padding: 6px 9px;
  border: 1px solid;
  border-radius: 7px;
  overflow: hidden;
  cursor: pointer;
  text-align: left;
  font: inherit;
  transition: box-shadow 0.15s;
}
.tl-block:hover { box-shadow: var(--shadow-card); z-index: 10; }
.tl-going { background: var(--go-bg); border-color: var(--go); }
.tl-maybe { background: var(--maybe-bg); border-color: var(--maybe); border-style: dashed; }
.tl-block-clash { box-shadow: 0 0 0 2px var(--clash); z-index: 4; }
.tl-line { line-height: 1.2; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-line .when { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-2); }
.tl-line .title { font-family: var(--font-display); font-weight: 600; font-size: 12.5px; }
.tl-warn { position: absolute; top: 5px; right: 6px; color: var(--clash); font-size: 12px; }
.tl-note { position: absolute; bottom: 3px; right: 6px; color: var(--ink-2); font-size: 10px; line-height: 1; }

/* ---- team ------------------------------------------------------------- */
.team-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 18px; }
.team-list { display: flex; flex-direction: column; gap: 22px; }
.slot-group-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.slot-group-head .t { font-family: var(--font-mono); font-weight: 700; font-size: 14px; }
.slot-group-head .state { font-size: 11.5px; color: var(--ink-3); }
.slot-group-head .state.split { color: var(--maybe); }

.team-row { background: var(--surface); border: 1px solid var(--line); border-radius: 7px; margin-bottom: 6px; overflow: hidden; }
.team-row-main {
  display: grid;
  grid-template-columns: 130px 1fr auto;
  gap: 12px;
  align-items: center;
  padding: 10px 13px;
}
.team-row-room { font-family: var(--font-mono); font-size: 12px; color: var(--ink-2); }
.team-row-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13.5px;
  letter-spacing: -0.01em;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  color: inherit;
}
.team-row-title:hover { color: var(--go-ink); }
.team-row-people { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.team-row-notes {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 13px 10px;
  border-top: 1px solid var(--surface-3);
  font-size: 12px;
  color: var(--ink-2);
}
.team-row-notes b { color: var(--ink); font-weight: 500; }

.person-card { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow-card); overflow: hidden; }
.person-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 13px 15px; border-bottom: 1px solid var(--line); }
.person-head .name { font-family: var(--font-display); font-weight: 600; font-size: 15px; }
.person-head .summary { margin-left: auto; font-size: 12px; color: var(--ink-3); }
.person-head .summary b { color: var(--clash); }
.person-rows { padding: 6px 0; }
.person-row {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 7px 15px;
  font-size: 13px;
}
.person-row + .person-row { border-top: 1px solid var(--surface-3); }
.person-row .when { font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-2); }
.person-row-clash .when { color: var(--clash); }
.person-row .title {
  font-weight: 500;
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  color: inherit;
  font-size: 13px;
  font-family: inherit;
}
.person-row .title:hover { color: var(--go-ink); }
/* A person's empty day is drawn as an empty slot on the timetable, not as a
   gap with a sentence in it: dashed the way the timeline draws a tentative
   block, keeping the mono time column with nothing in it. (This only ever
   appears when the card has no rows at all, so it has no siblings to align
   with and is free to sit inset.) */
.empty-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 15px 6px;
  padding: 13px 14px;
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 13px;
}
.empty-row .no-time {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* ---- modal ------------------------------------------------------------ */
/* #modal is a native popover, so the browser puts it in the top layer, paints
   the ::backdrop behind it, and handles Escape and click-outside itself. A
   popover is display:none until shown, which is also what keeps the dialog out
   of the page before anything has been loaded into it.

   It must size to the card rather than to the viewport: light dismiss fires on
   a click *outside the popover's own box*, so a full-viewport popover would
   have no outside left to click, and only the ✕ and Escape would close it. The
   UA's inset:0 + margin:auto does the centring. */
#modal {
  /* Stated rather than left to the UA sheet, so a browser too old to know what
     a popover is hides the dialog instead of leaving an empty card sitting in
     the page. The :popover-open rule below is what reveals it. */
  display: none;
  width: min(680px, calc(100% - 32px));
  max-height: 86vh;
  margin: auto;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--ink);
  overflow: visible;
}
#modal:popover-open { display: block; }
#modal::backdrop { background: rgba(20, 23, 29, 0.4); backdrop-filter: blur(2px); }

/* The surface belongs on the scroll container, not on the card inside it.
   With it on the card, the scrollbar gutter fell outside the white box and
   read as a grey strip of backdrop that — being part of the popover — did not
   dismiss when clicked. Here the scrollbar runs down the card itself, inside
   the rounded corners. */
#modal-body {
  max-height: 86vh;
  overflow-y: auto;
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  overscroll-behavior: contain; /* don't hand the scroll back to the page behind */
}

/* A slim pill inset from the edge, floating on the card rather than filling a
   gutter beside it. This wants ::-webkit-scrollbar: the standard
   scrollbar-color paints a bar hard against the edge and gives no control over
   width or radius — and setting it makes Chrome ignore these rules entirely,
   so the standard properties have to be scoped to the engines that need them
   rather than declared alongside as a belt-and-braces fallback. */
#modal-body::-webkit-scrollbar { width: 12px; }
#modal-body::-webkit-scrollbar-track {
  background: transparent;
  margin: 14px 0; /* keeps the thumb clear of the rounded corners */
}
#modal-body::-webkit-scrollbar-thumb {
  background-color: var(--line-2);
  border-radius: 999px;
  border: 3px solid transparent; /* padding, via background-clip — a 6px pill */
  background-clip: content-box;
}
#modal-body::-webkit-scrollbar-thumb:hover { background-color: var(--ink-3); }

/* Firefox, which has no ::-webkit-scrollbar. */
@supports not selector(::-webkit-scrollbar) {
  #modal-body { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
  #modal-body:hover { scrollbar-color: var(--ink-3) transparent; }
}

.modal-card {
  position: relative;
  padding: 30px 32px;
}

/* While the next session's detail is in flight the dialog is already open, so
   fade the previous one rather than presenting it as the answer. */
#modal.htmx-request #modal-body { opacity: 0.35; transition: opacity 120ms ease; }
.modal-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 8px;
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: 14px;
  cursor: pointer;
}
.modal-close:hover { background: var(--line); }
.modal-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.modal-when { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-2); }
.modal-title { font-size: 24px; font-weight: 700; line-height: 1.15; margin-bottom: 14px; }
.modal-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 18px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
}
.modal-section { margin-top: 18px; }
.modal-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 7px;
}
.modal-people { display: flex; flex-wrap: wrap; gap: 6px; }
.modal-prose { font-size: 14.5px; line-height: 1.6; white-space: pre-wrap; }
.note-card { background: var(--surface-3); border-radius: 7px; padding: 8px 12px; font-size: 13px; }
.note-card + .note-card { margin-top: 8px; }
.note-card .who { display: flex; align-items: center; gap: 6px; font-weight: 500; color: var(--ink); margin-bottom: 4px; }
.note-card .what { color: var(--ink-2); white-space: pre-wrap; }
.note-form { margin-top: 12px; }
.note-form label { display: block; font-size: 12px; color: var(--ink-2); }
.note-form textarea { margin-top: 4px; }
.note-form .btn { margin-top: 8px; }
.speaker { padding: 12px 0; }
.speaker + .speaker { border-top: 1px solid var(--surface-3); }
.speaker .name { font-family: var(--font-display); font-weight: 600; font-size: 14.5px; }
.speaker .links { display: inline-flex; gap: 8px; margin-left: 8px; font-size: 12px; }
.speaker .bio { font-size: 13px; color: var(--ink-2); margin-top: 5px; white-space: pre-wrap; }

/* ---- login gate ------------------------------------------------------- */
.gate { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 24px; }
.gate-card {
  width: 100%;
  max-width: 460px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--shadow-panel);
  padding: 32px 32px 28px;
}
.gate-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 22px; }
.gate h1 { font-size: 30px; font-weight: 700; margin-bottom: 8px; }
.gate p { color: var(--ink-2); font-size: 14.5px; margin: 0 0 22px; }
.gate-row { display: flex; gap: 10px; }
.gate-back {
  margin-top: 12px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink-3);
  cursor: pointer;
}
.gate-back:hover { color: var(--ink-2); }
.gate-error { color: var(--clash); font-size: 13px; margin-top: 12px; }

.card-warn-inline { margin: 0; }
.team-count { color: var(--ink-3); font-size: 12.5px; }

/* ---- toast ------------------------------------------------------------ */
#toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%); z-index: 70; pointer-events: none; }
.toast {
  background: var(--ink);
  color: #fff;
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 13px;
  box-shadow: var(--shadow-panel);
  animation: toast-in 2.6s ease forwards;
}
@keyframes toast-in {
  0% { opacity: 0; transform: translateY(10px); }
  8%, 88% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(10px); }
}

/* htmx sets this while a request is in flight */
.htmx-request.btn, .htmx-request .btn { opacity: 0.55; }

/* ---- narrow screens --------------------------------------------------- */
@media (max-width: 640px) {
  .main { padding: 16px 14px 60px; }
  .topbar { padding: 12px 14px; }
  .tabs { order: 3; width: 100%; }
  .hide-sm { display: none; }
  .tab { flex: 1; text-align: center; }
  .slot { grid-template-columns: 56px 1fr; gap: 10px; }
  .slot-time .start { font-size: 14px; top: 132px; }
  .slot-cards { grid-template-columns: 1fr; }
  #modal { width: 100%; max-height: 100%; height: 100%; }
  #modal-body { max-height: 100%; height: 100%; border-radius: 0; }
  .modal-card { min-height: 100%; padding: 22px 18px; }
  .tl-grid { margin-left: 46px; }
  .tl-hour .label { left: -46px; width: 38px; font-size: 10px; }
  .team-row-main { grid-template-columns: 1fr; gap: 6px; }
  .team-row-people { justify-content: flex-start; }
  .person-row { grid-template-columns: 1fr; gap: 4px; }
  .footer span { font-size: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* Nobody needs the fade or the toast's slide if they've asked the system for
   less movement; the toast still appears and still leaves. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .toast { animation: toast-hold 2.6s step-end forwards; }
  @keyframes toast-hold { 0%, 88% { opacity: 1; } 100% { opacity: 0; } }
}
