.network-help {
  font-size: 0.9rem;
  color: var(--fg-alt, #555);
  margin: 0.5rem 0 0.75rem;
}

#tutorial-network {
  background: var(--bg, #fff);
  border: 1px solid var(--rule, #dee2e6);
  border-radius: 0.5rem;
}

.network-controls {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin: 0.5rem 0 1.5rem;
  flex-wrap: wrap;
}

.network-controls button,
.network-controls select {
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: 0.35rem;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.9rem;
  cursor: pointer;
}

.filter-summary {
  font-size: 0.95rem;
  color: var(--fg-alt);
  margin: 0.5rem 0 0.75rem;
}

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.5rem 0 1.25rem;
}

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.65rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.82rem;
  cursor: pointer;
  user-select: none;
  line-height: 1.2;
}

.filter-chip[data-active="true"] {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}

.filter-chip .chip-count {
  font-size: 0.75rem;
  /* 0.7 opacity dropped this below WCAG AA against pastel chip
     backgrounds; 0.85 keeps the visual hierarchy without losing
     contrast. */
  opacity: 0.85;
}

.filter-chip .chip-swatch {
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.filter-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.filter-chip.is-empty {
  opacity: 0.45;
}

.filter-bar.label-bar {
  margin-top: -0.25rem;
}

#filter-reset {
  margin-left: auto;
  padding: 0.25rem 0.65rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: transparent;
  color: var(--fg-alt);
  font-size: 0.8rem;
  cursor: pointer;
}

#filter-reset:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.filter-summary {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.search-row {
  margin: 0.5rem 0 0.75rem;
}

.year-row {
  margin: 0.75rem 0 1.5rem;
  max-width: 32rem;
}

.year-label {
  display: block;
  font-size: 0.85rem;
  color: var(--fg-alt);
  margin-bottom: 0.5rem;
}

#year-readout {
  color: var(--fg);
  font-weight: 500;
  margin-left: 0.25rem;
}

/* Dual-handle year slider — two stacked native <input type=range> on a
   shared track. .range-fill spans the selected segment between handles. */
#year-slider .range-track {
  position: relative;
  height: 28px;
  background: linear-gradient(var(--rule), var(--rule)) center/100% 4px no-repeat;
  background-color: transparent;
  border-radius: 4px;
}

#year-slider .range-fill {
  position: absolute;
  top: 12px;
  height: 4px;
  background: var(--accent);
  border-radius: 4px;
  pointer-events: none;
}

#year-slider .range-input {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 28px;
  margin: 0;
  padding: 0;
  background: transparent;
  appearance: none;
  -webkit-appearance: none;
  pointer-events: none; /* track itself is decorative */
}

#year-slider .range-input::-webkit-slider-thumb {
  pointer-events: auto;
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--bg);
  border: 1.5px solid var(--accent);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  cursor: grab;
}

#year-slider .range-input::-moz-range-thumb {
  pointer-events: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--bg);
  border: 1.5px solid var(--accent);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  cursor: grab;
}

#year-slider .range-input:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
#year-slider .range-input:focus-visible::-moz-range-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

#year-slider .range-input::-webkit-slider-runnable-track,
#year-slider .range-input::-moz-range-track {
  background: transparent;
  border: none;
  height: 4px;
}

/* Autocomplete: title-only dropdown anchored under #overview-search.
   The wrap element pins position so .autocomplete-list overlays without
   shifting the page below it. */
.autocomplete-wrap {
  position: relative;
  width: 100%;
  max-width: 32rem;
}

.autocomplete-list {
  position: absolute;
  z-index: 10;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 0.25rem 0;
  list-style: none;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 0.4rem;
  box-shadow: var(--shadow-md, 0 6px 18px rgba(0, 0, 0, 0.08));
  max-height: 22rem;
  overflow-y: auto;
}

.autocomplete-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.7rem;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--fg);
}

.autocomplete-item.is-active,
.autocomplete-item:hover {
  background: var(--surface);
}

.autocomplete-item .autocomplete-pill {
  flex-shrink: 0;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.1rem 0.4rem;
  border-radius: 0.25rem;
}

.autocomplete-item .autocomplete-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.autocomplete-item .autocomplete-title mark {
  background: var(--accent-soft, rgba(255, 220, 100, 0.5));
  color: inherit;
  padding: 0;
  font-weight: 600;
}

#overview-search {
  width: 100%;
  max-width: 32rem;
  padding: 0.55rem 0.85rem;
  border: 1px solid var(--rule);
  border-radius: 0.4rem;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.95rem;
}

#overview-search:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.desc-snippet mark {
  background: var(--accent-soft, rgba(255, 220, 100, 0.4));
  color: inherit;
  padding: 0 0.1em;
  border-radius: 2px;
}

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

.tutorial-list-empty {
  padding: 1.5rem 1rem;
  text-align: center;
  color: var(--fg-alt);
  border: 1px dashed var(--rule);
  border-radius: 0.5rem;
}

.heatmap-wrapper {
  margin: 2rem 0 1.5rem;
  border: 1px solid var(--rule);
  border-radius: 0.5rem;
  padding: 0.75rem 1rem;
  background: var(--bg);
}

.heatmap-wrapper summary {
  cursor: pointer;
  font-weight: 500;
  font-size: 0.95rem;
  color: var(--fg);
  list-style: none;
}

.heatmap-wrapper summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 0.5rem;
  transition: transform 0.15s ease;
}

.heatmap-wrapper[open] summary::before {
  transform: rotate(90deg);
}

.heatmap-controls {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.85rem 0 0.5rem;
  font-size: 0.85rem;
  color: var(--fg-alt);
}

.heatmap-controls input[type="range"] {
  flex: 0 1 12rem;
}

#heatmap-n-readout {
  color: var(--fg);
  font-weight: 500;
}

.heatmap {
  margin-top: 0.5rem;
  overflow-x: auto;
}

.heatmap-empty {
  color: var(--fg-alt);
  font-style: italic;
  padding: 1rem;
}

.heatmap rect:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* All-tutorials nav: visually-hidden on desktop (screen-readers only),
   visible block layout on mobile where the network graph is hidden. */
.all-tutorials-nav {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.all-tutorials-nav details {
  margin: 0.4rem 0;
}

.all-tutorials-nav summary {
  cursor: pointer;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.all-tutorials-nav .nav-swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.all-tutorials-nav ul {
  list-style: none;
  padding-left: 1.4rem;
  margin: 0.35rem 0 0.75rem;
}

.all-tutorials-nav li {
  margin: 0.15rem 0;
}

.all-tutorials-nav .nav-empty {
  color: var(--fg-alt);
  font-style: italic;
}

/* Courses-specific: card head pairs the course pill with a lab-meta
   "Week N · Session M" tag so users can place each lab in its course
   structure at a glance. */
.tutorial-card .card-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

.tutorial-card .lab-meta {
  font-size: 0.75rem;
  color: var(--fg-alt);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* The courses overview has no year axis; the slider hides itself when
   minYear == maxYear, but we also drop the wrapper label for clarity. */
.year-row { display: none; }

/* Mobile: vis-network is unusable on a phone. Hide it and the heatmap;
   surface the linear nav and keep all other filters/search/list usable. */
@media (max-width: 768px) {
  #tutorial-network,
  .network-controls,
  .heatmap-wrapper {
    display: none;
  }

  .all-tutorials-nav {
    position: static;
    width: auto;
    height: auto;
    padding: 0.5rem 0;
    margin: 0.5rem 0 1.5rem;
    overflow: visible;
    clip: auto;
    white-space: normal;
    border: 0;
  }

  .all-tutorials-nav summary,
  .all-tutorials-nav a {
    /* WCAG 2.5.5 — minimum tap target. */
    min-height: 32px;
    line-height: 1.4;
    padding: 0.25rem 0;
  }

  .tutorial-list {
    grid-template-columns: 1fr;
  }

  #year-slider .range-input::-webkit-slider-thumb,
  #year-slider .range-input::-moz-range-thumb {
    width: 22px;
    height: 22px;
  }
}

.tutorial-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.tutorial-card {
  border: 1px solid var(--rule);
  border-radius: 0.5rem;
  padding: 0.85rem 1rem;
  background: var(--bg);
  color: var(--fg);
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.tutorial-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md, 0 6px 18px rgba(0,0,0,0.06));
  border-color: var(--accent);
}

.tutorial-card .topic-pill {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.45rem;
  border-radius: 0.3rem;
  margin-bottom: 0.4rem;
  color: #fff;
}

.tutorial-card h3 {
  font-size: 1rem;
  margin: 0.1rem 0 0.35rem;
  line-height: 1.3;
}

.tutorial-card h3 a {
  color: inherit;
  text-decoration: none;
}

.tutorial-card h3 a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.tutorial-card .desc {
  font-size: 0.85rem;
  color: var(--fg-alt);
  margin: 0 0 0.4rem;
}

.tutorial-card .tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.tutorial-card .tag {
  font-size: 0.72rem;
  padding: 0.1rem 0.4rem;
  border-radius: 0.25rem;
  background: var(--surface);
  color: var(--fg-alt);
  border: 1px solid var(--rule);
}

/* Download dropdown sitting alongside the network reset button. Plain
   <details> + <summary> — no JS, native disclosure semantics. */
.downloads-menu {
  display: inline-block;
  position: relative;
}
.downloads-menu > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--rule);
  border-radius: 0.35rem;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.9rem;
}
.downloads-menu > summary::-webkit-details-marker { display: none; }
.downloads-menu[open] > summary {
  border-color: var(--accent);
  color: var(--accent);
}
.downloads-menu ul {
  position: absolute;
  z-index: 5;
  margin-top: 0.35rem;
  padding: 0.5rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 0.35rem;
  list-style: none;
  min-width: 18rem;
  box-shadow: var(--shadow-md, 0 6px 18px rgba(0,0,0,0.08));
}
.downloads-menu li { font-size: 0.85rem; line-height: 1.5; }

/* Mobile fallback. Below 768px we hide the network and the heatmap —
   both rely on horizontal real estate that small screens don't have —
   and let the search box, chip bars, and article list carry the page.
   The article list is the canonical source of truth either way, so the
   page remains fully functional with no JS-driven viewport detection. */
@media (max-width: 768px) {
  #tutorial-network,
  .network-help,
  .network-controls,
  .heatmap-wrapper {
    display: none;
  }
  .tutorial-list {
    grid-template-columns: 1fr;
  }
  .filter-bar {
    /* Horizontal scroll on small screens beats a wrapped chip wall. */
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 0.25rem;
  }
  .filter-chip {
    flex-shrink: 0;
  }
}

/* Honour reduced-motion preference: drop hover lift on cards and the
   slow card transition. vis-network's physics is harder to gate from
   CSS — left as-is; the user's reader will still respect their OS
   setting for animations the page itself drives. */
@media (prefers-reduced-motion: reduce) {
  .tutorial-card,
  .tutorial-card:hover {
    transition: none;
    transform: none;
  }
}
