/* ============================================================================
   luding.phd — overrides on top of Dashmix (Bootstrap 5). Uses Bootstrap CSS
   custom properties (--bs-*) where possible so it tracks the active theme.
   ============================================================================ */

:root {
  --nav-h: 64px;
  --maxw: 1080px;          /* "1080p" content width with comfortable side margins */
  --gutter: 1.5rem;        /* shared left/right margin for nav, content, and footer */
  --toc-w: 250px;
  --page-h1-h: 4.5rem;     /* vertical space the full-width page H1 occupies (offsets the fixed TOC) */

  /* Brand primary — the ONE knob. Change this and the derived colors below follow.
     (xplay recolors the primary *classes* to terracotta but never sets the root
     --bs-primary token, so we set it here.) */
  --bs-primary: #c74433;
  --bs-primary-rgb: 199, 68, 51;   /* keep in sync with --bs-primary (Bootstrap's rgba() utilities) */
  --accent: var(--bs-primary);

  /* Derived from --bs-primary via color-mix so they track it automatically. */
  --primary-dark: color-mix(in srgb, var(--bs-primary) 75%, black);    /* ≈ #963327 (xplay .bg-primary-dark) */
  --primary-wash: color-mix(in srgb, var(--bs-primary) 12%, white);    /* light warm tint, ≈ #f4eae7 */

  /* Text links: Bootstrap colors <a> from --bs-link-color-rgb (the theme compiles this to a fixed
     terracotta triplet). Point it at the primary so links track the brand color — and recolor live
     when the editor updates --bs-primary-rgb. */
  --bs-link-color-rgb: var(--bs-primary-rgb);
  --bs-link-hover-color-rgb: var(--bs-primary-rgb);

  /* Site typeface: Source Sans 3 (Google Fonts), overriding the theme's default. */
  --bs-font-sans-serif: "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --bs-body-font-family: var(--bs-font-sans-serif);

  /* Bump the base body text size (Bootstrap default is 1rem). */
  --bs-body-font-size: 1.1rem;
}

html { scroll-behavior: smooth; }
body { font-family: var(--bs-font-sans-serif); }

/* Sticky-footer scaffold: footer sits at the bottom even on short pages. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main { flex: 1 0 auto; }

/* Text links track the brand color. The xplay theme hardcodes `a { color:#c74433 }` (and loads
   before this file), so the --bs-link-color-rgb override above can't win — we restate `a` here so
   links follow --bs-primary and recolor live in the editor. Nav/TOC set their own (more specific)
   colors and are unaffected; inverted bands keep white links (rule later in this file wins). */
a { color: var(--bs-primary); }
a:hover { color: var(--primary-dark); }

/* ===== Top nav: three zones via grid so the name stays truly centered ===== */
.site-nav {
  background: var(--bs-body-bg, #fff);
  border-bottom: 1px solid var(--bs-border-color, #e3e4e8);
}
.site-nav-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  height: var(--nav-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;                 /* sit content toward the bottom of the bar */
  padding: 0 var(--gutter) 0.4rem;  /* small bottom gap */
}
.nav-left {
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 1.1rem;
}
.nav-cv {
  position: relative;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--bs-body-color);
  font-size: 0.95rem;
}
.nav-me {
  position: relative;
  text-decoration: none;
  color: var(--bs-body-color);
  font-size: 0.95rem;
}
.nav-cv:hover,
.nav-me:hover { color: var(--accent); }

/* Optional FontAwesome icon on a nav link, rendered before the label. */
.nav-icon { margin-right: 0.4rem; }

/* Hover underline: a centered dot that grows into a 2px rule across the link.
   Animated with transform: scaleX (GPU-composited) rather than width to avoid
   layout thrash; rounded ends keep the small/early state reading as a dot. */
.nav-cv::after,
.nav-me::after,
.nav-right a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 1px;
  background: var(--accent);
  transform: scaleX(0);       /* hidden; grows from the center on hover */
  transform-origin: center;
  opacity: 0;
  transition: transform 0.28s ease, opacity 0.12s ease;
}
.nav-cv:hover::after,
.nav-me:hover::after,
.nav-right a:hover::after {
  transform: scaleX(1);
  opacity: 1;
}
/* Active page link (CV / Me): accent color + heavier weight. Deliberately
   distinct from the hover underline so the two states never read the same. */
.nav-cv.is-active,
.nav-me.is-active { color: var(--accent); font-weight: 700; }
.nav-name {
  justify-self: center;
  font-size: 2.1rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  color: var(--accent);
  white-space: nowrap;
}
.nav-right {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 1.4rem;
}
.nav-right a {
  position: relative;
  text-decoration: none;
  color: var(--bs-body-color);
  font-size: 0.95rem;
}
.nav-right a:hover { color: var(--accent); }

/* ===== Full-width section bands + a fixed TOC =====
   Each <section> is a full-width band; its padding centers content to --maxw and
   clears the fixed TOC on the left, so band backgrounds run full-width (including
   behind the TOC). The TOC is pinned and never scrolls. */
.cv { position: relative; }

/* Simple centered container (used by 404.html). */
.cv-container { max-width: var(--maxw); margin: 0 auto; padding: 2.25rem var(--gutter); }

/* Floating TOC card, pinned at the left (default) or right edge of the centered column. Its top
   clears the full-width page H1 above it (--page-h1-h). Alignment is set per page via has-toc-* on
   <main> (NavItem.TocAlignment). */
.cv-toc {
  position: fixed;
  top: calc(var(--nav-h) + 1px + var(--page-h1-h));
  left: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
  width: var(--toc-w);
  max-height: calc(100vh - var(--nav-h) - var(--page-h1-h) - 1rem);
  overflow: auto;
  background: var(--bs-body-bg, #fff);
  border-radius: 0.65rem;
  padding: 1rem;
  z-index: 5;
}
.has-toc-right .cv-toc {
  left: auto;
  right: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
}
/* Rectangular profile photo, ~ the combined height of the menu items below it. */
.toc-photo {
  width: 100%;
  height: 230px;
  margin-bottom: 1rem;
  border-radius: 0.4rem;
  object-fit: cover;          /* fill the frame without distortion */
  background: #dfe3e8;        /* shows only if the image fails to load */
}
.toc-list { display: flex; flex-direction: column; }
.toc-list a {
  position: relative;
  padding: 0.6rem 0.6rem;
  border-radius: 0.35rem;
  text-decoration: none;
  color: var(--bs-body-color);
  font-weight: 500;
  transition: color 0.2s ease, padding-left 0.22s ease;
}
/* Dot lives on every link but is hidden until active; it sits where the text
   normally begins (left: 0.6rem) so it pops in just left of the slid text. */
.toc-list a::before {
  content: "";
  position: absolute;
  left: 0.6rem;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 1px;                       /* near-sharp corners for a diamond */
  background: var(--accent);
  opacity: 0;
  transform: scale(0.3) rotate(45deg);      /* rotate the square into a diamond */
  transition: opacity 0.18s ease, transform 0.22s ease;
}
.toc-list a:hover {
  background: var(--bs-tertiary-bg, #f1f3f5);
  color: var(--accent);
}
/* Scroll-spy: the section the reader is currently "on" (see js/site.js).
   Text slides right to open a gap, and the accent dot fades/scales in. */
.toc-list a.active {
  color: var(--accent);
  font-weight: 600;
  padding-left: 1.55rem;
}
.toc-list a.active::before {
  opacity: 1;
  transform: scale(1) rotate(45deg);
}

/* Generic prosites admin shortcut: a small pill pinned to the very top-right corner, shown only
   to a logged-in user (rendered by _SiteScripts on every layout). Themed via --bs-primary. */
.ps-admin-btn {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 1500;                 /* above the sticky nav; below the edit-mode bar (2000) */
  padding: 0.3rem 0.7rem;
  background: var(--bs-primary);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  border-bottom-left-radius: 0.4rem;
  opacity: 0.85;
  transition: opacity 0.15s ease;
}
.ps-admin-btn:hover { opacity: 1; color: #fff; }

/* Full-width page H1, within the left/right margins (NOT cleared by the TOC — it sits above it).
   Style: large bold title with a short accent underline (accent-underline, left-aligned). */
.page-heading {
  padding: 1.75rem max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter))) 0;
}
.page-heading h1 {
  margin: 0;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.2;
}
.page-heading .page-heading-text {
  display: inline-block;
  padding-bottom: 0.35rem;
  border-bottom: 3px solid var(--accent);
}

/* Bands: full-width; padding centers content to --maxw with gutter margins. TOC clearance is added
   only when the page actually shows a floating TOC, on whichever side it's aligned (has-toc-*). */
.band {
  padding-block: 2.5rem;
  padding-left: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
  padding-right: max(var(--gutter), calc((100% - var(--maxw)) / 2 + var(--gutter)));
  scroll-margin-top: calc(var(--nav-h) + 1rem);
}
/* Clear the fixed TOC on its side (incl. 861–1080px where the column offset goes negative). */
.has-toc-left .band {
  padding-left: calc(max(var(--gutter), (100% - var(--maxw)) / 2 + var(--gutter)) + var(--toc-w) + 2.5rem);
}
.has-toc-right .band {
  padding-right: calc(max(var(--gutter), (100% - var(--maxw)) / 2 + var(--gutter)) + var(--toc-w) + 2.5rem);
}
.band-wash   { background: var(--primary-wash); }   /* warm terracotta wash, derived */
.band-invert { background: var(--primary-dark); color: #fdf6f5; }
.band-invert h2 { color: #fff; border-bottom-color: rgba(255, 255, 255, 0.55); }
/* On the dark (primary-dark) band, links are a light tint of the primary so they stay on-brand and
   readable, yet distinct from the near-white body text. */
.band-invert a { color: color-mix(in srgb, var(--bs-primary) 50%, white); }
.band-invert a:hover { color: #fff; }
.band-invert .muted { color: rgba(255, 255, 255, 0.8); }

/* Plain text links (prose/body) are underlined for clarity; styled .source-link chips are excluded
   (they keep their icon + hover underline). Applies in normal and inverted bands. */
.band a:not(.source-link) { text-decoration: underline; }

/* Stacked tagline parts (title / specialty / institution) read as one tight headline block. */
.cv-headline { line-height: 1.3; margin-bottom: 0.75rem; }

.cv-lead { margin: 0; }

.band h2 {
  display: inline-block;
  font-size: 1.5rem;
  margin: 0 0 1rem;
  padding-bottom: 0.35rem;
  border-bottom: 2px solid var(--accent);
}

/* Sub-heading (SubHeadingItem): a lighter <h3> to break up content within a section — no underline,
   no band; top margin separates it from the block above. */
.sub-heading {
  font-size: 1.15rem;
  font-weight: 600;
  margin: 1.5rem 0 0.6rem;
  color: var(--bs-body-color);
}
.sub-heading:first-child { margin-top: 0; }
.band-invert .sub-heading { color: #fff; }

.muted { color: var(--bs-secondary-color, #6b6b70); font-size: 0.9rem; }
.source-link { display: inline-flex; align-items: center; gap: 0.4rem; font-weight: 600; text-decoration: none; }
.source-link:hover { text-decoration: underline; }
.source-link i { font-size: 0.8em; }

/* Research: Google Scholar stat cards */
.cv-stats { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0 0 0.75rem; }
.stat {
  flex: 1 1 0;
  min-width: 110px;
  background: var(--bs-tertiary-bg, #f1f3f5);
  border-radius: 0.6rem;
  padding: 0.9rem 1rem;
  text-align: center;
}
.stat-num { display: block; font-size: 1.7rem; font-weight: 700; color: var(--accent); line-height: 1.1; }
.stat-label { font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--bs-secondary-color, #6b6b70); }

/* "Text" block: markdown paragraphs and/or lists. Trim outer margins so it sits flush in a band. */
.prose-text { margin: 0; }
.prose-text > :first-child { margin-top: 0; }
.prose-text > :last-child { margin-bottom: 0; }
.prose-text ul, .prose-text ol { margin: 0.5rem 0; padding-left: 1.2rem; }
.prose-text li { padding: 0.2rem 0; }

/* Education + Work History: vertical timeline */
.timeline {
  position: relative;
  list-style: none;
  margin: 0;
  padding-left: 1.5rem;
  border-left: 2px solid var(--bs-border-color, #e3e4e8);
}
/* Dashmix ships its own .timeline component whose ::before draws a 0.25rem bar at
   left:1.375rem (a second, thicker line beside the content). Class-name collision —
   kill that pseudo-element so only our border-left spine + dots remain. */
.timeline::before { content: none; }
.timeline-item { position: relative; padding: 0 0 1.5rem 0.4rem; }
.timeline-item:last-child { padding-bottom: 0; }
.timeline-item::before {
  content: "";
  position: absolute;
  left: calc(-1.5rem - 7px);
  top: 0.3rem;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bs-body-bg, #fff);
}
.tl-when { font-size: 0.8rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent); }
.tl-title { font-weight: 600; margin: 0.1rem 0 0; }
.tl-org { color: var(--bs-secondary-color, #6b6b70); }
/* Per-role responsibilities/accomplishments under a timeline entry. */
.tl-points {
  margin: 0.5rem 0 0;
  color: var(--bs-secondary-color, #6b6b70);
}
.tl-points ul { margin: 0; padding-left: 1.1rem; }
.tl-points li { margin-bottom: 0.25rem; }
.tl-points li:last-child { margin-bottom: 0; }
/* Optional institution logo beside a timeline entry: logo left, text right, the logo
   sized to roughly span the title + org lines. */
.tl-main { display: flex; gap: 0.85rem; align-items: flex-start; }
.tl-text { min-width: 0; flex: 1 1 auto; }
.tl-logo {
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  object-fit: contain;
  border-radius: 0.3rem;
  margin-top: 0.15rem;
}

/* Grants: timeline dot + a subtle full-width card. The year sits top-left inside
   the card (aligned with the dot), the role top-right; the amount anchors a
   footer row. Role vs amount are told apart by type, not color. */
.grant-list .timeline-item::before { top: 1.1rem; }   /* re-center dot on the in-card year */
.grant-card {
  padding: 0.85rem 1rem;
  background: var(--bs-tertiary-bg, #f8f9fa);
  border-radius: 0.5rem;
}
.grant-head {
  display: flex;
  justify-content: space-between;        /* year left, role hard right */
  align-items: baseline;
  gap: 1rem;
}
.grant-role {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;            /* label voice */
  color: var(--bs-secondary-color, #6b6b70);
}
.grant-title { margin: 0.35rem 0 0; font-weight: 700; font-size: 1.1rem; color: var(--bs-body-color); }
.grant-sponsor { margin: 0.15rem 0 0; color: var(--bs-secondary-color, #6b6b70); font-size: 0.95rem; }
.grant-desc { margin: 0.55rem 0 0; font-size: 0.98rem; line-height: 1.55; }
.grant-meta {
  margin-top: 0.85rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--bs-border-color, #dfe4f1);
  text-align: right;
}
.grant-amount {
  font-weight: 700;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;   /* figure voice */
  color: var(--bs-body-color);
}

/* Publications: title + venue + citation badge (no table) */
.pub-list { list-style: none; margin: 0; padding: 0; }
.pub {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--bs-border-color, #e3e4e8);
}
.pub:last-child { border-bottom: 0; }
.pub-body { flex: 1 1 auto; min-width: 0; }
.pub-title { font-weight: 600; margin: 0 0 0.15rem; }
.pub-meta { font-size: 0.9rem; color: var(--bs-secondary-color, #6b6b70); margin: 0; }
.pub-author-self { font-weight: 700; color: var(--bs-body-color); }
.pub-cite {
  flex: 0 0 auto;
  min-width: 64px;
  text-align: center;
  background: var(--bs-tertiary-bg, #f1f3f5);
  border-radius: 0.5rem;
  padding: 0.35rem 0.5rem;
}
.pub-cite .n { display: block; font-weight: 700; color: var(--accent); line-height: 1.1; }
.pub-cite .l { font-size: 0.65rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--bs-secondary-color, #6b6b70); }

/* Teaching: course chips */
.courses { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0 0; padding: 0; list-style: none; }
.course-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  background: var(--bs-tertiary-bg, #f1f3f5);
  border-radius: 2rem;
  padding: 0.4rem 0.9rem;
  font-size: 0.9rem;
}
.course-chip code { color: var(--accent); font-weight: 700; }
/* Breathing room for a note that follows the course chips (e.g. the reviewer line). */
.courses + .muted { margin-top: 1rem; }

/* ===== Footer ===== */
.site-footer {
  flex-shrink: 0;
  background: var(--bs-body-bg, #fff);
  border-top: 1px solid var(--bs-border-color, #e3e4e8);
}
.site-footer-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 1.25rem var(--gutter);
  color: var(--bs-secondary-color, #6b6b70);
  font-size: 0.9rem;
  text-align: center;
}

/* ===== About ("Me") page ===== */
/* Full-width like .cv (so the page transition treats both the same), with the
   readable content centered to --maxw by an inner wrapper. */
.about-inner { max-width: var(--maxw); margin: 0 auto; padding: 3rem var(--gutter); }
.about-head { display: flex; align-items: center; gap: 1.75rem; margin-bottom: 1.75rem; }
.about-photo {
  flex: 0 0 auto;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  object-fit: cover;
  background: #dfe3e8;
}
.about-name { margin: 0; font-size: 2.1rem; font-weight: 700; color: var(--accent); }
.about-tagline { margin: 0.3rem 0 0; font-weight: 600; color: var(--bs-secondary-color, #6b6b70); }
.about-page p + p { margin-top: 1rem; }

/* ===== Page-swap transition (CV <-> Me) via the View Transitions API =====
   A cross-fade: the outgoing page fades out while the incoming page fades in on
   top of it (it paints above, so it "bleeds" over the old one) with a small
   upward settle. No slide and no clipping, so the full-width bands fade at their
   natural full width. Nav + footer stay put. Unsupported browsers swap instantly. */
.cv,
.about-page { view-transition-name: page; }

@keyframes page-fade-out { to   { opacity: 0; } }
@keyframes page-fade-in  { from { opacity: 0; transform: translateY(10px); } }

/* Don't morph the group between the two pages' differing heights; let each
   snapshot sit at its natural size and just cross-fade. */
::view-transition-group(page) { animation: none; overflow: visible; }
::view-transition-old(page) { animation: page-fade-out 0.3s ease both; }
::view-transition-new(page) { animation: page-fade-in 0.42s cubic-bezier(0.2, 0, 0, 1) both; }

/* Nav + footer (the root snapshot) stay put. */
::view-transition-group(root) { animation: none; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(page), ::view-transition-new(page) { animation: none; }
}

/* ===== Responsive: un-pin the TOC to the top; bands drop the TOC clearance ===== */
@media (max-width: 860px) {
  .cv-toc {
    position: static;
    width: auto;
    max-height: none;
    overflow: visible;
    margin: 2.25rem var(--gutter) 0;
    text-align: center;             /* center the stacked photo + links on mobile */
  }
  .toc-photo { height: 200px; max-width: 240px; margin-left: auto; margin-right: auto; }
  .toc-list { align-items: center; }   /* center each link box in the column */
  /* Drop the TOC clearance on mobile (the has-toc-* rules out-specify a bare .band, so neutralize them too). */
  .band,
  .has-toc-left .band,
  .has-toc-right .band {
    padding-left: var(--gutter);
    padding-right: var(--gutter);
  }
  /* Mobile: give the name its own centered row above the menu items (left + right beneath it). */
  .site-nav-inner {
    height: auto;
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "name name"
      "left right";
    align-items: center;
    row-gap: 0.5rem;
    padding-top: 0.6rem;
  }
  .nav-name { grid-area: name; justify-self: center; font-size: 1.6rem; }
  .nav-left { grid-area: left; justify-self: start; gap: 0.8rem; }
  .nav-right { grid-area: right; justify-self: end; gap: 1rem; }
}
