/* ==========================================================================
   directory.kiarashs.ir — a reading list of PDFs, links, tools and datasets.

   One stylesheet, no framework, no web fonts. The page ships every entry in
   the HTML, so it reads fine with JavaScript switched off; everything below
   that depends on JS is scoped under `.js`.
   ========================================================================== */

/* --- Design tokens -------------------------------------------------------
   The light palette is defined on a bare :root so it is never trapped inside
   a media query. Dark mode redefines the same names twice: once for the
   system preference, once for an explicit toggle, so the toggle wins in
   both directions. */

:root {
  color-scheme: light;

  --bg: #f4f5f8;
  --bg-tint: #e9ecf5;
  --surface: #ffffff;
  --surface-2: #f7f8fb;
  --surface-hover: #ffffff;

  --text: #14161c;
  --text-soft: #4a4f5c;
  --text-faint: #7c8291;

  --line: #e2e5ec;
  --line-strong: #cdd2dd;

  --accent: #4f5bd5;
  --accent-hover: #3f4ac2;
  --accent-soft: rgba(79, 91, 213, 0.1);
  --accent-ring: rgba(79, 91, 213, 0.35);
  --accent-contrast: #ffffff;

  --mark: #ffe28a;
  --mark-text: #3a2c00;

  --shadow-sm: 0 1px 2px rgba(16, 20, 34, 0.05);
  --shadow-md: 0 6px 18px -6px rgba(16, 20, 34, 0.16), 0 2px 6px -2px rgba(16, 20, 34, 0.08);
  --shadow-lg: 0 18px 42px -14px rgba(16, 20, 34, 0.28);

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  --header-h: 60px;
  --gutter: clamp(16px, 4vw, 32px);
  --page: 1220px;

  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: #0a0c11;
    --bg-tint: #12161f;
    --surface: #141821;
    --surface-2: #1a1f2a;
    --surface-hover: #1a1f2a;

    --text: #eef0f6;
    --text-soft: #b3b9c8;
    --text-faint: #7f8798;

    --line: #232936;
    --line-strong: #333b4c;

    --accent: #8e9bff;
    --accent-hover: #a5afff;
    --accent-soft: rgba(142, 155, 255, 0.14);
    --accent-ring: rgba(142, 155, 255, 0.45);
    --accent-contrast: #0a0c11;

    --mark: #6b5a12;
    --mark-text: #ffeaa8;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 8px 22px -8px rgba(0, 0, 0, 0.7), 0 2px 6px -2px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 22px 50px -18px rgba(0, 0, 0, 0.8);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0a0c11;
  --bg-tint: #12161f;
  --surface: #141821;
  --surface-2: #1a1f2a;
  --surface-hover: #1a1f2a;

  --text: #eef0f6;
  --text-soft: #b3b9c8;
  --text-faint: #7f8798;

  --line: #232936;
  --line-strong: #333b4c;

  --accent: #8e9bff;
  --accent-hover: #a5afff;
  --accent-soft: rgba(142, 155, 255, 0.14);
  --accent-ring: rgba(142, 155, 255, 0.45);
  --accent-contrast: #0a0c11;

  --mark: #6b5a12;
  --mark-text: #ffeaa8;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 8px 22px -8px rgba(0, 0, 0, 0.7), 0 2px 6px -2px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 22px 50px -18px rgba(0, 0, 0, 0.8);
}

/* --- Base ---------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

/* A single soft wash behind the header area. Fixed, so it never scrolls
   into the card grid and never causes a horizontal scrollbar. */
body::before {
  content: "";
  position: fixed;
  inset: 0 0 auto 0;
  height: 420px;
  background:
    radial-gradient(70ch 340px at 15% -10%, var(--accent-soft), transparent 70%),
    radial-gradient(60ch 300px at 88% -20%, var(--bg-tint), transparent 72%);
  pointer-events: none;
  z-index: 0;
}

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

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

button { font: inherit; color: inherit; }

.container {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 600;
  transition: top 0.15s var(--ease);
}
.skip-link:focus { top: 12px; color: var(--accent-contrast); }

/* --- Header -------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--header-h);
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}

@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .site-header { background: var(--bg); }
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--text);
  white-space: nowrap;
}
.brand:hover { color: var(--text); }
.brand-mark {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 9px;
  background: linear-gradient(140deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #14b8c4));
  color: #fff;
  box-shadow: var(--shadow-sm);
  flex: none;
}
.brand-mark svg { width: 17px; height: 17px; }
.brand-text { font-size: 0.98rem; }

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-inline-start: auto;
}

/* --- Icon buttons -------------------------------------------------------- */

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease),
              border-color 0.15s var(--ease), transform 0.15s var(--ease);
}
.icon-btn:hover {
  color: var(--text);
  border-color: var(--line-strong);
  background: var(--surface-hover);
}
.icon-btn:active { transform: scale(0.96); }
.icon-btn svg { width: 18px; height: 18px; }

/* The theme button swaps which glyph is visible; the other stays in the DOM
   so the label a screen reader announces always matches what is shown. */
.theme-btn [data-theme-icon] { display: none; }
:root:not([data-theme]) .theme-btn [data-theme-icon="system"],
:root[data-theme="light"] .theme-btn [data-theme-icon="light"],
:root[data-theme="dark"] .theme-btn [data-theme-icon="dark"] { display: block; }

/* --- Hero ---------------------------------------------------------------- */

.hero {
  position: relative;
  z-index: 1;
  padding-block: clamp(30px, 6vw, 56px) clamp(18px, 3vw, 26px);
}

.hero h1 {
  margin: 0;
  font-size: clamp(1.9rem, 1.2rem + 3vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  font-weight: 700;
}
.hero h1 .accent {
  background: linear-gradient(100deg, var(--accent), color-mix(in srgb, var(--accent) 45%, #14b8c4));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero p {
  margin: 14px 0 0;
  max-width: 62ch;
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.1rem);
  color: var(--text-soft);
}

.hero-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}
.hero-stats li {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  font-size: 0.85rem;
  color: var(--text-soft);
}
.hero-stats b {
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* --- Search + controls --------------------------------------------------- */

.toolbar {
  position: sticky;
  top: var(--header-h);
  z-index: 20;
  padding-block: 12px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
@supports not (background: color-mix(in srgb, red 50%, blue)) {
  .toolbar { background: var(--bg); }
}

.toolbar-inner {
  display: flex;
  gap: 10px;
  align-items: center;
}

.search {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}
.search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  translate: 0 -50%;
  width: 18px; height: 18px;
  color: var(--text-faint);
  pointer-events: none;
}
.search input {
  width: 100%;
  height: 48px;
  padding: 0 108px 0 44px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.search input::placeholder { color: var(--text-faint); }
.search input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-ring);
}
.search input::-webkit-search-cancel-button { display: none; }

.search-hint {
  position: absolute;
  right: 12px;
  top: 50%;
  translate: 0 -50%;
  display: flex;
  gap: 4px;
  pointer-events: none;
}
.search-hint kbd {
  padding: 3px 7px;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--text-faint);
  font-family: inherit;
  font-size: 0.72rem;
  line-height: 1.2;
}
.search input:not(:placeholder-shown) ~ .search-hint { display: none; }

.search-clear {
  position: absolute;
  right: 10px;
  top: 50%;
  translate: 0 -50%;
  display: none;
  width: 30px; height: 30px;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-soft);
  cursor: pointer;
}
.search-clear:hover { color: var(--text); background: var(--line); }
.search input:not(:placeholder-shown) ~ .search-clear { display: grid; }
.search-clear svg { width: 14px; height: 14px; }

/* View switch (grid / list) */
.view-switch {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  flex: none;
}
.view-switch button {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.view-switch button:hover { color: var(--text); }
.view-switch button[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
}
.view-switch svg { width: 18px; height: 18px; }

@media (max-width: 640px) {
  .view-switch { display: none; }
}

/* --- Category tabs ------------------------------------------------------- */

.tabs {
  display: flex;
  gap: 6px;
  /* overflow-x: auto makes the computed overflow-y "auto" too, so this bar
     clips on both axes. Without the top padding, :hover's translateY(-1px)
     lifted each pill 1px outside the content box and sheared off the top of
     its border. The negative margin keeps the bar where it was. */
  margin-block: 0 22px;
  padding-top: 4px;
  margin-top: 0;
  padding-bottom: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  display: inline-flex;
  text-decoration: none;
  align-items: center;
  gap: 8px;
  flex: none;
  scroll-snap-align: start;
  padding: 9px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-soft);
  font-size: 0.92rem;
  font-weight: 550;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background 0.16s var(--ease), color 0.16s var(--ease),
              border-color 0.16s var(--ease), transform 0.16s var(--ease);
}
.tab:hover {
  color: var(--text);
  border-color: var(--line-strong);
  transform: translateY(-1px);
}
.tab svg { width: 17px; height: 17px; flex: none; }

.tab[aria-current="page"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
  box-shadow: var(--shadow-md);
}
.tab[aria-current="page"] .tab-count {
  background: color-mix(in srgb, var(--accent-contrast) 22%, transparent);
  color: var(--accent-contrast);
}

.tab-count {
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
}

/* --- Search results summary --------------------------------------------- */

.results-bar {
  display: none;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 20px;
  padding: 11px 16px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--text);
  font-size: 0.92rem;
}
.results-bar[data-visible] { display: flex; }
.results-bar b { font-variant-numeric: tabular-nums; }
.results-bar button {
  margin-inline-start: auto;
  padding: 4px 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--accent);
  font-size: 0.85rem;
  cursor: pointer;
}
.results-bar button:hover { background: var(--surface); }

/* While a search is running the tab bar is a filter summary, not a selector:
   the results already span every category, so the selected pill steps back
   and empty categories are greyed out. */
.tabs[data-searching] .tab[aria-current="page"] {
  background: var(--surface);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: var(--shadow-sm);
}
.tabs[data-searching] .tab[aria-current="page"] .tab-count {
  background: var(--accent-soft);
  color: var(--accent);
}
.tabs[data-searching] .tab[data-empty] { opacity: 0.45; }

/* --- Notice -------------------------------------------------------------- */

.notice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 22px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text-soft);
  font-size: 0.92rem;
}
/* Out of the way once a search is running: the results belong directly
   under the tab bar. */
.is-searching .notice { display: none; }
.notice svg { width: 19px; height: 19px; flex: none; margin-top: 2px; color: var(--accent); }
.notice p { margin: 0; }

/* --- Panels and the card grid -------------------------------------------- */

main { position: relative; z-index: 1; padding-bottom: 64px; }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  /* Cards stretch to the height of their row, which grid has already sized to
     the tallest one. Setting align-items: start here saves no height at all —
     the row is that tall regardless — and only leaves a gap under the shorter
     cards, so every row ends up ragged. Leave this on the grid default. */
  gap: 12px;
  margin: 0 0 34px;
  padding: 0;
  list-style: none;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 15px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform 0.16s var(--ease), box-shadow 0.16s var(--ease),
              border-color 0.16s var(--ease);
}
.card:has(.card-info) .card-title { padding-right: 26px; }
.card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  box-shadow: var(--shadow-md);
}
.card:hover, .card:focus-within { z-index: 5; }
.js .card[hidden] { display: none; }
.js .group[hidden] { display: none; }

.card-title {
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--text);
}
a.card-title::after {
  /* Stretches the primary link over the whole card. Secondary pills sit
     above it via z-index so they stay clickable. */
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
a.card-title:hover { color: var(--accent); }

/* --- The (i) button and its popover --------------------------------------
   Hover and focus are pure CSS, so the description is reachable with
   JavaScript off. directory.js only adds tap-to-toggle and Escape. */

.card-info {
  position: absolute;
  top: 10px;
  right: 10px;
  /* Above the title's stretched ::after, which otherwise swallows the hover. */
  z-index: 2;
}

.info-btn {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-faint);
  cursor: help;
  transition: background 0.14s var(--ease), color 0.14s var(--ease);
}
.info-btn svg { width: 15px; height: 15px; }
.info-btn:hover,
.info-btn:focus-visible,
.card-info.is-open .info-btn {
  background: var(--accent-soft);
  color: var(--accent);
}

.popover {
  position: absolute;
  top: calc(100% + 7px);
  right: -4px;
  z-index: 40;
  width: max-content;
  max-width: min(288px, 72vw);
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
  box-shadow: var(--shadow-lg);
  font-size: 0.83rem;
  font-weight: 400;
  line-height: 1.5;
  text-align: start;
  white-space: normal;

  opacity: 0;
  visibility: hidden;
  translate: 0 -4px;
  transition: opacity 0.14s var(--ease), translate 0.14s var(--ease),
              visibility 0.14s var(--ease);
}
.popover::before {
  /* Bridges the gap so the pointer can travel button -> popover. */
  content: "";
  position: absolute;
  inset: -9px 0 auto 0;
  height: 9px;
}

.card-info:hover .popover,
.info-btn:focus-visible ~ .popover,
.card-info.is-open .popover {
  opacity: 1;
  visibility: visible;
  translate: 0;
}

/* A card near the right edge would push its popover off screen; the grid
   never puts a card flush to the viewport, but narrow screens can. */
@media (max-width: 480px) {
  .popover { right: -4px; max-width: min(280px, calc(100vw - 48px)); }
}

.card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 2px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: 0.735rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.badge svg { width: 12px; height: 12px; flex: none; }
.badge-pdf { background: var(--accent-soft); color: var(--accent); }

.pill {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-soft);
  font-size: 0.775rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background 0.14s var(--ease), color 0.14s var(--ease),
              border-color 0.14s var(--ease);
}
.pill:hover {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  color: var(--accent);
}
.pill svg { width: 12px; height: 12px; flex: none; opacity: 0.65; }

/* Multi-link entries ------------------------------------------------------
   The card holds the full list of links in the markup: that is the whole
   no-JS fallback. With JS the list is hidden and the card opens a modal
   showing the same links. */

button.card-title {
  border: 0;
  padding: 0;
  background: none;
  text-align: start;
  font: inherit;
  font-size: 0.98rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--text);
  cursor: pointer;
}
button.card-title::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.card-multi:hover button.card-title { color: var(--accent); }

.card-links {
  /* Hidden by default: these links belong in the modal. The list stays in the
     markup as the no-JavaScript fallback, and .no-js is cleared by an inline
     script in <head> before first paint, so it never flashes. */
  display: none;
  flex-direction: column;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
}
.card-links li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 8px;
}
.card-links .link-note { color: var(--text-soft); }
/* Once the modal exists the inline copy is redundant. */
.no-js .card-multi .card-links { display: flex; }

/* Solid rather than tinted: at a glance this has to read as a different kind
   of thing from the muted "PDF" / hostname badges, not as another one of them. */
.badge-count {
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 600;
}
.badge-count svg { opacity: 0.85; }

/* And the card itself looks like a small stack of sheets. Drawn with offset
   box-shadows rather than a pseudo-element so it costs no layout: the cards
   stay flush with their row, which is the whole point of the grid alignment. */
.card-multi {
  box-shadow: var(--shadow-sm),
              6px -6px 0 -1px var(--surface),
              6px -6px 0 0 var(--line-strong);
}
.card-multi:hover {
  box-shadow: var(--shadow-md),
              6px -6px 0 -1px var(--surface),
              6px -6px 0 0 color-mix(in srgb, var(--accent) 55%, var(--line-strong));
}

/* --- The link modal ------------------------------------------------------ */

.link-modal {
  width: min(560px, calc(100vw - 32px));
  max-height: min(78vh, 720px);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.link-modal::backdrop {
  background: rgba(10, 12, 17, 0.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.link-modal[open] { display: flex; flex-direction: column; }

.link-modal-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 18px 18px 12px;
  border-bottom: 1px solid var(--line);
}
.link-modal-head h2 {
  flex: 1;
  margin: 0;
  font-size: 1.05rem;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.link-modal-head .icon-btn { width: 32px; height: 32px; flex: none; }
.link-modal-head .icon-btn svg { width: 15px; height: 15px; }

.link-modal-note {
  margin: 0;
  padding: 12px 18px 0;
  color: var(--text-soft);
  font-size: 0.88rem;
}

.link-modal-list {
  margin: 0;
  padding: 10px 10px 14px;
  list-style: none;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.link-modal-list li { display: block; }
.link-modal-list a {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-weight: 550;
  font-size: 0.93rem;
  transition: background 0.14s var(--ease);
}
.link-modal-list a:hover,
.link-modal-list a:focus-visible { background: var(--surface-2); color: var(--accent); }
.link-modal-list .link-note {
  flex: 1 1 100%;
  color: var(--text-soft);
  font-weight: 400;
  font-size: 0.84rem;
  line-height: 1.45;
}
.link-modal-list .badge { margin-inline-start: auto; }

@media (prefers-reduced-motion: no-preference) {
  .link-modal[open] { animation: modal-in 0.16s var(--ease); }
  @keyframes modal-in {
    from { opacity: 0; transform: translateY(6px) scale(0.98); }
  }
}

/* The panel blurb sits under each section heading. */
.panel-blurb {
  margin: -6px 0 16px;
  color: var(--text-soft);
  font-size: 0.92rem;
}
.js .panel-blurb { display: none; }
.js .panel[data-searching] .panel-blurb { display: none; }


/* --- Tags, pins and dates ------------------------------------------------- */

.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tag {
  /* Above the card title's stretched ::after, which would otherwise take the
     click before the tag ever sees it. */
  position: relative;
  z-index: 1;
  display: inline-block;
  padding: 2px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: 0.73rem;
  line-height: 1.5;
  white-space: nowrap;
}
.tag::before { content: "#"; opacity: 0.55; }
.tag:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: var(--accent-soft);
  color: var(--accent);
}

.badge-pin {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
  font-weight: 600;
}
.badge-date {
  background: transparent;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* A pinned card reads as lifted out of the ordinary run of the list. */
.card.is-pinned {
  border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
}
.card.is-pinned::before {
  content: "";
  position: absolute;
  inset-inline: 14px;
  top: -1px;
  height: 2px;
  border-radius: 0 0 2px 2px;
  background: var(--accent);
}

.card-meta {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.82rem;
}

/* --- Sort control --------------------------------------------------------- */

.sort-control {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  height: 46px;
  padding-inline: 12px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text-soft);
}
.sort-control:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-ring);
}
.sort-icon { width: 17px; height: 17px; flex: none; }
.sort-control select {
  appearance: none;
  border: 0;
  padding: 0 22px 0 8px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
}
.sort-control select:focus { outline: none; }
.sort-control::after {
  content: "";
  position: absolute;
  right: 14px;
  width: 7px; height: 7px;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  rotate: 45deg;
  translate: 0 -2px;
  pointer-events: none;
}
/* The native menu is drawn by the OS, so its options need explicit colours
   or a dark theme leaves them black-on-black on some platforms. */
.sort-control option { background: var(--surface); color: var(--text); }

@media (max-width: 720px) {
  .sort-control { display: none; }
}

/* Compact list view ------------------------------------------------------- */

.view-list .cards { grid-template-columns: 1fr; gap: 0; }
.view-list .card {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  padding: 11px 14px;
  border-radius: 0;
  border-width: 0 0 1px;
  box-shadow: none;
  background: transparent;
}
.view-list .cards > .card:first-child {
  border-top: 1px solid var(--line);
  border-top-left-radius: var(--radius);
  border-top-right-radius: var(--radius);
}
.view-list .cards > .card:last-child {
  border-bottom-left-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
}
.view-list .card:hover {
  transform: none;
  background: var(--surface);
  border-color: var(--line);
}
.view-list .card-title { flex: 1 1 320px; }
.view-list .card-links { display: none; }
.view-list .card-tags { order: 5; }
.view-list .card-meta { flex: 1 1 100%; order: 4; }
.view-list .card-info { position: static; order: 4; }
.view-list .card-info .popover { right: 0; }
.view-list .card:has(.card-info) .card-title { padding-right: 0; }
.view-list .card-foot { margin-top: 0; padding-top: 0; }


.hero-section { padding-block: clamp(22px, 4vw, 38px) 8px; }
.hero-section h1 { font-size: clamp(1.6rem, 1.2rem + 1.8vw, 2.2rem); }
.hero-count {
  margin: 6px 0 0;
  color: var(--text-faint);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.section-empty {
  padding: 48px 24px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  text-align: center;
  color: var(--text-soft);
}
.section-empty p { margin: 0; }
.section-empty-hint { margin-top: 8px !important; font-size: 0.88rem; color: var(--text-faint); }
.section-empty code {
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--surface-2);
  font-size: 0.92em;
}

/* --- Search hits that live on another page -------------------------------- */

.elsewhere { margin-top: 8px; }
.elsewhere > h2 {
  margin: 0 0 12px;
  font-size: 0.95rem;
  font-weight: 650;
  color: var(--text-soft);
  letter-spacing: -0.01em;
}
.elsewhere .badge { text-transform: capitalize; }

/* --- Courses -------------------------------------------------------------- */

.course-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
  margin: 0 0 40px;
  padding: 0;
  list-style: none;
}
.course-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform 0.16s var(--ease), box-shadow 0.16s var(--ease),
              border-color 0.16s var(--ease);
}
.course-card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  box-shadow: var(--shadow-md);
}
.js .course-card[hidden] { display: none; }
.course-title {
  font-size: 1.05rem;
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--text);
  text-wrap: balance;
}
.course-title::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.course-card:hover .course-title { color: var(--accent); }
.course-meta {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.85rem;
}
.course-desc {
  margin: 0;
  color: var(--text-soft);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* One course ---------------------------------------------------------------- */

.course-head { padding-block: clamp(18px, 3vw, 30px) 6px; }
.crumb { margin: 0 0 10px; font-size: 0.85rem; }
.course-head h1 {
  margin: 0;
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.1rem);
  line-height: 1.15;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.course-head .course-meta { margin-top: 8px; font-size: 0.92rem; }
.course-head .course-desc { margin-top: 10px; max-width: 62ch; }
.course-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}
.course-links .pill { padding: 6px 14px; font-size: 0.85rem; }

.course-empty {
  margin: 24px 0 40px;
  padding: 40px 24px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  text-align: center;
  color: var(--text-soft);
}

/* A course can run to dozens of items, so the modules are listed up front and
   anchor down the page rather than making the reader scroll to find them. */
.module-index {
  margin: 24px 0 32px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.module-index-head {
  margin: 0 0 10px;
  color: var(--text-faint);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
.module-index ol {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 2px 20px;
  margin: 0;
  padding: 0 0 0 1.2em;
  font-size: 0.92rem;
}
.module-index li { color: var(--text-faint); }
.module-index a { color: var(--text-soft); }
.module-index a:hover { color: var(--accent); }

.module { margin-bottom: 34px; scroll-margin-top: calc(var(--header-h) + 20px); }
.module > h2 {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 6px;
  font-size: 1.08rem;
  font-weight: 650;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.module-n {
  display: grid;
  place-items: center;
  width: 28px; height: 28px;
  flex: none;
  border-radius: 9px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.module-summary {
  margin: 0 0 12px 40px;
  color: var(--text-soft);
  font-size: 0.9rem;
}

.materials {
  margin: 0 0 0 40px;
  padding: 0;
  list-style: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.material {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.material:last-child { border-bottom: 0; }
.material:hover { background: var(--surface-2); }
.material > a {
  flex: 1 1 260px;
  color: var(--text);
  font-weight: 550;
  font-size: 0.94rem;
}
.material:hover > a { color: var(--accent); }
.material-note {
  flex: 1 1 100%;
  order: 3;
  color: var(--text-soft);
  font-size: 0.85rem;
}
.material-kind {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.73rem;
  font-weight: 550;
  white-space: nowrap;
}
.material-kind svg { width: 12px; height: 12px; }

@media (max-width: 560px) {
  .module-summary, .materials { margin-left: 0; }
}

/* Empty state ------------------------------------------------------------- */

.empty {
  display: none;
  padding: 56px 24px;
  text-align: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text-soft);
}
.empty svg { width: 34px; height: 34px; color: var(--text-faint); }
.empty h2 { margin: 12px 0 6px; font-size: 1.1rem; color: var(--text); }
.empty p { margin: 0; font-size: 0.93rem; }
.empty[data-visible] { display: block; }

/* Search highlighting ----------------------------------------------------- */

mark {
  padding: 0 1px;
  border-radius: 3px;
  background: var(--mark);
  color: var(--mark-text);
}

/* The ?h= deep link keeps working: the matched card gets a lasting ring. */
.card.is-flagged {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

/* --- Footer -------------------------------------------------------------- */

.site-footer {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-block: 26px;
  color: var(--text-soft);
  font-size: 0.9rem;
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* --- Back to top --------------------------------------------------------- */

.to-top {
  position: fixed;
  right: max(18px, env(safe-area-inset-right));
  bottom: max(18px, env(safe-area-inset-bottom));
  z-index: 25;
  width: 42px; height: 42px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-soft);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  translate: 0 8px;
  transition: opacity 0.2s var(--ease), translate 0.2s var(--ease),
              visibility 0.2s var(--ease), color 0.15s var(--ease);
}
.to-top[data-visible] { opacity: 1; visibility: visible; translate: 0; }
.to-top:hover { color: var(--accent); }
.to-top svg { width: 18px; height: 18px; }

/* --- Motion preferences -------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .card:hover, .tab:hover { transform: none; }
}

/* --- Print --------------------------------------------------------------- */

@media print {
  .site-header, .toolbar, .tabs, .to-top, .notice { display: none !important; }
  body::before { display: none; }
  .panel[hidden] { display: block !important; }
  .js .panel-head { display: flex !important; }
  .card { break-inside: avoid; box-shadow: none; }
}
