/* ============================================================
   Kobi Hackenburg — academic website

   Reduced system:
   - 1 typeface (Inter), 3 weights (400 body / 500 emphasis / 600 headings)
   - 4 font sizes: display, heading, body (1rem), small (0.875rem,
     all metadata)
   - One column width for the whole page: prose, news, and the
     bibliography all share the same measure
   - Every link is the accent colour and underlines on hover. One
     treatment, no exceptions
   - No rules or dividers. An 8px ladder marks every break:
     16 entries / 24 items / 32 years / 48 groups / 64 sections
   ============================================================ */

:root {
  --bg: #ffffff;
  --ink: #1a1a1a;
  --gray: #6e6e73;
  /* One notch darker than --gray: solid glyphs read lighter than text. */
  --icon: var(--ink);
  --accent: #4f46e5;
  --accent-hover: #3730a3;
  --select: rgba(79, 70, 229, 0.12);

  --size-heading: 1.375rem;
  --size-body: 0.9375rem;
  --size-small: 0.875rem;
  --leading-body: 1.5;

  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --page-width: 52rem;
  --gutter: 1.5rem;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--size-body);
  line-height: var(--leading-body);
  font-feature-settings: "kern", "liga";
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--select);
}

/* ---------- Links ---------- */

/* Every link on the page gets this one treatment, with no exceptions:
   accent colour at rest, underline on hover.

   The 500 is compensation, not emphasis. Indigo on white is 6.3:1 where
   the body ink is 17.4:1, so at the same weight a link reads lighter
   than the sentence around it. Darkening the indigo would fix that but
   collapse it toward the body colour (9.9:1 on white, but only 1.8:1
   against the ink), so weight is the lever that adds density without
   giving up the colour. This is the job a variable-font grade axis
   does; Inter ships only wght and opsz, so weight it is. */
a {
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
  transition: color 0.12s ease;
}

/* A link that fills a heading keeps the heading's own weight. */
:is(h1, h2, h3, h4) a {
  font-weight: inherit;
}

a:hover {
  color: var(--accent-hover);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ---------- Page shell ---------- */

.page {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.section {
  margin-top: var(--space-8);
}

/* The gap below a heading lives on the heading rather than on whatever
   follows it. Components like .news-list and .pub-note reset their own
   margins, which silently ate the old `.section-title + *` rule and left
   those two sections noticeably tighter than the rest. */
.section-title {
  font-size: var(--size-heading);
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0 0 var(--space-3);
}

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

.hero {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: start;
  gap: var(--space-8);
  padding-top: var(--space-12);
}

/* The hero stack is two groups, not four evenly spaced items: the name and
   affiliations are one identity block, the icons and CV are one actions
   block. Margins here are deliberately uneven so the optical gaps land at
   roughly 20px inside a group and 32px between them.

   Note the icon row carries 9px of invisible tap padding above and below
   its glyphs, so the two margins touching it read ~9px larger than they
   are written. That is why .hero-role sits at 16px and .hero-cv at 4px
   rather than both matching .hero-name. */
.hero-name {
  font-size: clamp(1.9rem, 5vw, 2.4rem);
  font-weight: 600;
  line-height: var(--leading-body);
  letter-spacing: -0.025em;
  margin: 0 0 var(--space-1);
}

.hero-role {
  margin: 0 0 var(--space-4);
  line-height: var(--leading-body);
}

.role-line {
  display: block;
}

.hero-role .role-sep {
  display: none;
}

.hero-photo {
  /* Drops the photo's top edge to the cap height of the name. */
  margin-top: var(--space-2);
}

/* Taller than the text beside it on purpose. Top and right edges stay
   fixed (cap-height alignment + right column), so growing the size
   extends the photo down and left into the canvas. */
.hero-photo img {
  display: block;
  width: 230px;
  height: 230px;
  object-fit: cover;
}

.hero-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  /* Each icon carries its own tap padding; pull the row back so the
     first glyph still lines up with the text above it. */
  margin-left: -0.5625rem;
}

.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.5rem;
  color: var(--icon);
  transition: color 0.12s ease;
}

.icon-link:hover {
  color: var(--accent);
}

/* Sized per glyph so the rendered ink lands in a 15–18px band. The mail
   is a wide mark, so it sits shorter than the near-square ones. */
.icon {
  display: block;
}

.icon--mail {
  width: 1.375rem;
  height: 1.375rem;
}

.icon--scholar {
  width: 1.0625rem;
  height: 1.0625rem;
}

.icon--github {
  width: 1.125rem;
  height: 1.125rem;
}

.icon--x {
  width: 1.125rem;
  height: 1.125rem;
}

.hero-cv {
  margin: var(--space-1) 0 0;
}

/* ---------- About ---------- */

.about-body p {
  margin: 0;
}

.about-body p + p {
  margin-top: var(--space-4);
}

/* ---------- News ---------- */

.news-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.news-list li {
  display: grid;
  grid-template-columns: 6rem 1fr;
  gap: var(--space-4);
}

.news-list li + li {
  margin-top: var(--space-4);
}

.news-list li[hidden] {
  display: none;
}

/* Matching the body's line box puts the smaller date on the same
   baseline as the item it labels, with no magic offset. */
.news-date {
  font-size: var(--size-small);
  line-height: calc(var(--size-body) * var(--leading-body));
  color: var(--gray);
  font-variant-numeric: tabular-nums;
}

/* A button, so it has to opt into the link treatment by hand. */
.news-toggle {
  display: block;
  margin-top: var(--space-6);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--size-small);
  font-weight: 500;
  color: var(--accent);
  cursor: pointer;
}

.news-toggle:hover {
  color: var(--accent-hover);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

.news-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ---------- Featured publications ---------- */

.featured-pub + .featured-pub {
  margin-top: var(--space-6);
}

.featured-pub > :last-child {
  margin-bottom: 0;
}

.pub-venue {
  font-size: var(--size-small);
  color: var(--gray);
  margin: 0 0 var(--space-1);
}

/* The venue is the strongest scannable signal in the list. Weight makes
   it an anchor without spending colour on it. */
.venue-name {
  font-weight: 500;
  color: var(--ink);
}

.pub-title {
  font-size: var(--size-body);
  font-weight: 600;
  line-height: var(--leading-body);
  margin: 0 0 var(--space-1);
}

.pub-authors {
  font-size: var(--size-small);
  color: var(--ink);
  line-height: var(--leading-body);
  margin: 0 0 var(--space-2);
}

.pub-authors strong {
  font-weight: 600;
}

.pub-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-size: var(--size-small);
  margin: 0 0 var(--space-2);
}

/* In the featured section, indent links and press beneath the title so
   the metadata reads as subordinate rather than part of the same block. */
.featured-pub .pub-links,
.featured-pub .pub-press {
  padding-left: var(--space-6);
}

.pub-links a::before,
.extra-links a::before {
  content: "[";
}

.pub-links a::after,
.extra-links a::after {
  content: "]";
}

.pub-press {
  font-size: var(--size-small);
  color: var(--gray);
  line-height: var(--leading-body);
  margin: 0;
}

/* ---------- All publications ---------- */

.pub-note {
  font-size: var(--size-small);
  color: var(--gray);
  margin: 0;
}

/* The note is a key for reading the entries rather than content in its own
   right, so it tucks under the heading. Without these two rules it sits
   roughly midway between the heading and the first group, and the gap below
   it matches the major group break, which reads as a section of its own. */
.section-title:has(+ .pub-note) {
  margin-bottom: var(--space-1);
}

.pub-note + .pub-group {
  margin-top: var(--space-6);
}

.pub-group {
  font-size: var(--size-body);
  font-weight: 600;
  margin: var(--space-12) 0 var(--space-3);
}

.pub-year {
  font-size: var(--size-small);
  font-weight: 600;
  color: var(--gray);
  margin: var(--space-8) 0 var(--space-3);
}

/* A heading straight after another heading stays tight. */
.pub-group + .pub-year {
  margin-top: var(--space-3);
}

.pub-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Hanging indent: each entry's first line starts at the margin and its
   continuations indent, so entry boundaries stay scannable in a dense
   block of references. */
.pub-list li {
  font-size: var(--size-small);
  line-height: var(--leading-body);
  padding-left: var(--space-6);
  text-indent: calc(-1 * var(--space-6));
}

.pub-list li + li {
  margin-top: var(--space-4);
}

.extra-links {
  white-space: nowrap;
}

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

.site-footer {
  margin-top: var(--space-16);
}

.footer-inner {
  max-width: var(--page-width);
  margin: 0 auto;
  padding: 0 var(--gutter) var(--space-12);
  font-size: var(--size-small);
}

.footer-meta {
  margin: 0;
  color: var(--gray);
  text-align: center;
}

/* ---------- Responsive ---------- */

/* The hero breaks first: the name and the photo stop fitting side by
   side well before the rest of the layout runs out of room. */
@media (max-width: 46rem) {
  .hero {
    grid-template-columns: 1fr;
    gap: var(--space-6);
    padding-top: var(--space-8);
  }

  .hero-photo {
    order: -1;
    margin-top: 0;
  }

  .hero-photo img {
    width: 154px;
    height: 154px;
  }
}

/* The news date column only needs to fold once the body text beside it
   is squeezed. */
@media (max-width: 34rem) {
  .news-list li {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .news-date {
    line-height: var(--leading-body);
  }
}

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

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  a,
  .icon-link {
    transition: none;
  }
}
