/* =========================================================================
   Carologistics — site stylesheet

   Hand-written, self-contained, ~1 file. No Bootstrap, no Font Awesome, no
   web fonts, no CDN: the site makes zero third-party requests, which is what
   keeps it GDPR-clean on RWTH infrastructure.

   Contents
     1. Design tokens
     2. Reset and base elements
     3. Layout primitives
     4. Buttons, icons, links
     5. Header and navigation
     6. Homepage sections
     7. Interior pages and prose
     8. Components (roster, gallery, video, alerts)
     9. Footer
   ========================================================================= */

/* ---------------------------------------------------- 1. Design tokens --- */

:root {
  color-scheme: light dark;

  /* Brand. The deep red is taken from the team's competition shirts. */
  --brand: #8c2332;
  --brand-strong: #6d1b26;
  --brand-soft: #f8eef0;
  --on-brand: #ffffff;

  /* Neutrals */
  --bg: #ffffff;
  --bg-alt: #f7f5f4;
  --bg-sunken: #efeceb;
  --surface: #ffffff;
  --border: #e4dfdc;
  --border-strong: #cfc8c4;
  --text: #17161a;
  --text-muted: #5e5955;
  --text-faint: #6b655f;

  /* Always-dark surfaces (hero, stat band, closing band).
     `--brand` flips to a dark red in light mode, which is invisible on these:
     the hero eyebrow measured 2.07:1 and the stat rules 1.89:1. Anything
     brand-coloured that sits on a dark surface must use --brand-on-dark,
     which does not flip. (Solid brand buttons are fine either way: they carry
     their own background.) */
  --brand-on-dark: #e77f8f;
  --dark-bg: #17151a;
  --dark-bg-2: #221d24;
  --dark-text: #f6f3f1;
  --dark-muted: #b3aaa6;
  --dark-border: #38323a;

  /* Type: system stack only — nothing is downloaded. */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* Fluid type scale */
  --step--1: clamp(0.83rem, 0.81rem + 0.10vw, 0.89rem);
  --step-0: clamp(1rem, 0.97rem + 0.15vw, 1.09rem);
  --step-1: clamp(1.2rem, 1.14rem + 0.30vw, 1.38rem);
  --step-2: clamp(1.44rem, 1.33rem + 0.55vw, 1.75rem);
  --step-3: clamp(1.73rem, 1.54rem + 0.95vw, 2.22rem);
  --step-4: clamp(2.07rem, 1.76rem + 1.55vw, 2.81rem);
  --step-5: clamp(2.49rem, 2.00rem + 2.45vw, 3.58rem);

  /* Space */
  --space-2xs: 0.375rem;
  --space-xs: 0.625rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: clamp(4rem, 3rem + 5vw, 7rem);

  /* Shape and depth */
  --radius-s: 8px;
  --radius-m: 14px;
  --radius-l: 22px;
  --radius-pill: 999px;

  --shadow-s: 0 1px 2px rgb(23 22 26 / 0.05), 0 2px 8px rgb(23 22 26 / 0.05);
  --shadow-m: 0 2px 4px rgb(23 22 26 / 0.05), 0 12px 28px rgb(23 22 26 / 0.09);
  --shadow-l: 0 4px 8px rgb(23 22 26 / 0.06), 0 24px 56px rgb(23 22 26 / 0.14);

  --medal-silver: #9aa0a6;
  --medal-bronze: #b98b52;

  /* One container for the whole site — header, footer, homepage bands and
     interior pages all share these edges, so nothing is ever inset relative to
     the nav above it.
     Line length is handled separately, by --measure on text-level elements
     only (see .prose). Capping the container instead is what left interior
     body copy floating 144px inside the nav on both sides. */
  --wrap: 76rem;
  /* Reading measure, ~68 characters at the body size. In rem, not ch: ch
     resolves against each element's own font-size, so a heading would have
     come out twice as wide as the paragraph under it. */
  --measure: 46rem;
  --ease: cubic-bezier(0.22, 0.68, 0.35, 1);
  --header-h: 4.5rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --brand: #e77f8f;
    --medal-silver: #c3c8ce;
    --medal-bronze: #d6a56a;
    --brand-strong: #f3a1ad;
    --brand-soft: #2b1b1f;
    --on-brand: #241015;

    --bg: #131215;
    --bg-alt: #191719;
    --bg-sunken: #0e0d0f;
    --surface: #1c1a1e;
    --border: #302c32;
    --border-strong: #453f47;
    --text: #f2efec;
    --text-muted: #a9a19d;
    --text-faint: #9a918c;

    --shadow-s: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-m: 0 2px 4px rgb(0 0 0 / 0.3), 0 12px 28px rgb(0 0 0 / 0.45);
    --shadow-l: 0 4px 8px rgb(0 0 0 / 0.35), 0 24px 56px rgb(0 0 0 / 0.55);
  }
}

/* ------------------------------------------ 2. Reset and base elements --- */

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

* {
  margin: 0;
}

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

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.018em;
  text-wrap: balance;
}

p,
li {
  text-wrap: pretty;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: var(--brand);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

a:hover {
  color: var(--brand-strong);
}

button {
  font: inherit;
  color: inherit;
}

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

::selection {
  background: var(--brand);
  color: var(--on-brand);
}

hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: var(--space-l) 0;
}

code,
pre,
kbd {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

code {
  background: var(--bg-sunken);
  border-radius: 5px;
  padding: 0.15em 0.4em;
}

pre {
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  padding: var(--space-s);
  overflow-x: auto;
}

pre code {
  background: none;
  padding: 0;
}

.skip-link {
  position: absolute;
  left: var(--space-s);
  top: var(--space-s);
  z-index: 100;
  transform: translateY(-200%);
  background: var(--brand);
  color: var(--on-brand);
  padding: 0.7em 1.2em;
  border-radius: var(--radius-s);
  font-weight: 600;
  text-decoration: none;
  transition: transform 0.2s var(--ease);
}

.skip-link:focus {
  transform: translateY(0);
  color: var(--on-brand);
}

@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;
  }
}

/* --------------------------------------------- 3. Layout primitives ------ */

.wrap {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}

@media (min-width: 48rem) {
  .wrap {
    width: min(100% - 4rem, var(--wrap));
  }
}

/* The header's inner bar is not a .wrap, so it needs the same sizing spelled
   out to land on the shared edges. */
.site-header__inner {
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}

@media (min-width: 48rem) {
  .site-header__inner {
    width: min(100% - 4rem, var(--wrap));
  }
}

.section {
  padding-block: var(--space-2xl);
}

.section--alt {
  background: var(--bg-alt);
  border-block: 1px solid var(--border);
}

.section__head {
  margin-bottom: var(--space-xl);
}

.section__head--center {
  margin-inline: auto;
  text-align: center;
}

.section__title {
  font-size: var(--step-4);
  margin-top: var(--space-2xs);
}

.section__lead {
  color: var(--text-muted);
  font-size: var(--step-1);
  margin-top: var(--space-s);
}

.eyebrow {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--brand);
}

/* ------------------------------------- 4. Buttons, icons, links ---------- */

.icon {
  width: 1.15em;
  height: 1.15em;
  flex: none;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.8em 1.5em;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--brand);
  color: var(--on-brand);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.18s var(--ease), border-color 0.18s var(--ease),
    transform 0.18s var(--ease), box-shadow 0.18s var(--ease), color 0.18s var(--ease);
}

.btn:hover {
  background: var(--brand-strong);
  color: var(--on-brand);
  transform: translateY(-1px);
  box-shadow: var(--shadow-m);
}

.btn:active {
  transform: translateY(0);
  box-shadow: none;
}

.btn .icon {
  transition: transform 0.18s var(--ease);
}

.btn:hover .icon-arrow {
  transform: translateX(3px);
}

.btn--sm {
  padding: 0.55em 1.1em;
  font-size: var(--step--1);
}

.btn--ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--border-strong);
}

.btn--ghost:hover {
  background: var(--bg-alt);
  color: var(--text);
  border-color: var(--text-faint);
}

.btn--invert {
  background: var(--dark-text);
  color: var(--dark-bg);
}

.btn--invert:hover {
  background: #ffffff;
  color: var(--dark-bg);
}

.btn--on-dark {
  color: var(--dark-text);
  border-color: rgb(255 255 255 / 0.28);
}

.btn--on-dark:hover {
  background: rgb(255 255 255 / 0.1);
  color: var(--dark-text);
  border-color: rgb(255 255 255 / 0.5);
}

/* ------------------------------------ 5. Header and navigation ----------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

@supports (backdrop-filter: blur(10px)) {
  .site-header {
    backdrop-filter: saturate(1.6) blur(12px);
  }
}

@supports not (backdrop-filter: blur(10px)) {
  .site-header {
    background: var(--bg);
  }
}

.site-header.is-scrolled {
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-s);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  min-height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  flex: none;
  color: var(--text);
  text-decoration: none;
  font-weight: 700;
  white-space: nowrap;
}

/* `a:hover` (0,1,1) outranks `.brand` (0,1,0), which turned the wordmark
   brand-pink on hover while the tagline stayed grey. Pin both. */
.brand:hover,
.brand:hover .brand__name {
  color: var(--text);
}

.brand__mark {
  width: 2.5rem;
  height: 2.5rem;
  object-fit: contain;
}

@media (prefers-color-scheme: dark) {
  /* The logo is a black line drawing; invert it so it reads on dark. */
  .brand__mark {
    filter: invert(1);
  }
}

.brand__text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.brand__name {
  font-size: var(--step-1);
  letter-spacing: -0.02em;
}

.brand__tag {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  background: var(--surface);
  cursor: pointer;
}

.nav-toggle .icon {
  width: 1.4rem;
  height: 1.4rem;
}

.nav-toggle .icon-close,
.nav-toggle[aria-expanded="true"] .icon-menu {
  display: none;
}

.nav-toggle[aria-expanded="true"] .icon-close {
  display: block;
}

.site-nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  list-style: none;
  padding: 0;
}

.site-nav__list a:not(.btn) {
  display: block;
  /* Tight horizontal padding: the nav has to fit the container, which is now
     sized as the reading measure rather than the other way round. */
  padding: 0.5em 0.6em;
  border-radius: var(--radius-s);
  color: var(--text-muted);
  font-weight: 600;
  font-size: var(--step--1);
  text-decoration: none;
  transition: color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.site-nav__list a:not(.btn):hover {
  color: var(--text);
  background: var(--bg-alt);
}

.site-nav__list a[aria-current="page"] {
  color: var(--brand);
  background: var(--brand-soft);
}

.site-nav__cta {
  margin-left: var(--space-2xs);
}

.site-nav__cta .btn {
  white-space: nowrap;
}

/* Small screens: the list collapses into a panel under the header. */
@media (max-width: 59.99rem) {
  .site-nav {
    position: fixed;
    inset: var(--header-h) 0 auto 0;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-l);
    padding: var(--space-s) 1.25rem var(--space-m);
    transform: translateY(-125%);
    visibility: hidden;
    transition: transform 0.28s var(--ease), visibility 0.28s;
  }

  .nav-open .site-nav {
    transform: translateY(0);
    visibility: visible;
  }

  .site-nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .site-nav__list a:not(.btn) {
    padding: 0.85em 0.6em;
    font-size: var(--step-0);
    border-bottom: 1px solid var(--border);
    border-radius: 0;
  }

  .site-nav__cta {
    margin: var(--space-s) 0 0;
  }

  .site-nav__cta .btn {
    width: 100%;
    padding: 0.8em 1.5em;
    font-size: var(--step-0);
  }

  .nav-open {
    overflow: hidden;
  }
}

@media (min-width: 60rem) {
  .nav-toggle {
    display: none;
  }
}

/* ------------------------------------------ 6. Homepage sections --------- */

/* The homepage bands are wide, but running text still has to read at a sane
   length. Rather than capping the prose and leaving a ragged right edge that
   does not line up with the band above, the intro puts its heading and its
   text side by side, so both columns fill the band. */
.is-home .section--intro .wrap {
  display: grid;
  gap: var(--space-m);
}

@media (min-width: 56rem) {
  .is-home .section--intro .wrap {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
    gap: var(--space-xl);
    align-items: start;
  }

  .is-home .section--intro .section__head {
    margin-bottom: 0;
    position: sticky;
    top: calc(var(--header-h) + 2rem);
  }
}

/* Section leads sit above full-width card grids, where a shorter measure
   reads as deliberate rather than misaligned. */
.is-home .section__lead,
.is-home .supporters__lead {
  max-width: 40rem;
}


.hero {
  position: relative;
  background: var(--dark-bg);
  color: var(--dark-text);
  padding-block: clamp(3rem, 2rem + 6vw, 6rem);
  overflow: hidden;
}

/* Soft brand glow behind the copy, drawn in CSS — no image request. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    75% 90% at 18% 38%,
    color-mix(in srgb, var(--brand-on-dark) 42%, transparent),
    transparent 70%
  );
  opacity: 0.5;
  pointer-events: none;
}

.hero__inner {
  position: relative;
  display: grid;
  gap: var(--space-xl);
  align-items: center;
}

@media (min-width: 62rem) {
  .hero__inner {
    /* Text column gets the larger share: at --wrap it otherwise came out
       ~368px, too narrow for the two buttons to sit side by side. */
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: var(--space-m);
  }
}

.hero .eyebrow {
  color: var(--brand-on-dark);
}

.hero__title {
  font-size: var(--step-5);
  margin-top: var(--space-s);
  letter-spacing: -0.03em;
}

.hero__lead {
  margin-top: var(--space-m);
  max-width: 34rem;
  font-size: var(--step-1);
  color: var(--dark-muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-top: var(--space-l);
}

.hero .btn--ghost {
  color: var(--dark-text);
  border-color: rgb(255 255 255 / 0.28);
}

.hero .btn--ghost:hover {
  background: rgb(255 255 255 / 0.1);
  color: var(--dark-text);
  border-color: rgb(255 255 255 / 0.5);
}

.hero__figure {
  position: relative;
  margin: 0;
}

/* No forced ratio: the hero photo keeps its own proportions, so nobody gets
   cropped out of the frame. width/height on the <img> reserve the space. */
.hero__figure img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-l);
}

.hero__figure figcaption {
  display: flex;
  align-items: center;
  gap: 0.5em;
  margin-top: var(--space-s);
  font-size: var(--step--1);
  color: var(--dark-muted);
}

.hero__figure figcaption .icon {
  color: var(--brand-on-dark);
  width: 1.25em;
  height: 1.25em;
}

@media (min-width: 62rem) {
  .hero__figure figcaption {
    position: absolute;
    left: var(--space-s);
    right: var(--space-s);
    bottom: var(--space-s);
    margin: 0;
    padding: 0.7em 1em;
    border-radius: var(--radius-m);
    background: color-mix(in srgb, var(--dark-bg) 78%, transparent);
    backdrop-filter: blur(8px);
    color: var(--dark-text);
  }
}

/* Stat band */

.stats {
  background: var(--dark-bg-2);
  color: var(--dark-text);
  padding-block: var(--space-l);
}

.stats__grid {
  display: grid;
  /* 11rem, not 13rem: four columns have to fit inside --wrap (4 x 13rem plus
     gaps overflowed it and dropped the fourth stat onto its own row). */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-m);
  margin: 0;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding-left: var(--space-s);
  border-left: 2px solid color-mix(in srgb, var(--brand-on-dark) 70%, transparent);
}

.stat__label {
  order: 2;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dark-text);
}

.stat__value {
  order: 1;
  margin: 0;
  font-size: var(--step-4);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
}

.stat__detail {
  order: 3;
  margin: 0;
  font-size: var(--step--1);
  color: var(--dark-muted);
}

/* Card grid */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-m);
  list-style: none;
  padding: 0;
}

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-m);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-s);
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease),
    border-color 0.22s var(--ease);
}

.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-m);
  border-color: var(--border-strong);
}

.card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-s);
  background: var(--brand-soft);
  color: var(--brand);
}

.card__icon .icon {
  width: 1.4rem;
  height: 1.4rem;
}

.card__title {
  font-size: var(--step-1);
  /* `balance` splits these short titles at odd places ("Competing / in the
     Smart Manufacturing League"); `pretty` only fixes the last line. */
  text-wrap: pretty;
}

.card__body {
  color: var(--text-muted);
  flex: 1;
}

.card__link {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  gap: 0.4em;
  font-size: var(--step--1);
  font-weight: 700;
  text-decoration: none;
}

.card__link:hover {
  text-decoration: underline;
}

.card__link .icon {
  width: 1em;
  height: 1em;
  transition: transform 0.18s var(--ease);
}

.card__link:hover .icon-arrow {
  transform: translateX(3px);
}

/* Awards timeline */

.timeline {
  display: flex;
  flex-direction: column;
  gap: var(--space-l);
}

/* The year sits above its group rather than in a left column. A left column
   pushed every card inward, so the cards shared neither a left nor a right
   edge with the body text above them, which read as broken alignment. */
.timeline__year {
  display: block;
}

.timeline__year + .timeline__year {
  margin-top: var(--space-l);
}

.timeline__marker {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin-bottom: var(--space-s);
  font-size: var(--step-2);
  font-weight: 800;
  color: var(--text-faint);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.timeline__marker::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.timeline__items {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  align-items: start;
  gap: var(--space-s);
  list-style: none;
  padding: 0;
  margin: 0;
}

/* One competition event: heading, then its results. */

.event {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: var(--space-s);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-m);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.event:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-m);
}

.event:has(.result--first) {
  border-left-color: var(--brand);
}

.event:has(.result--second) {
  border-left-color: var(--medal-silver);
}

.event:has(.result--third) {
  border-left-color: var(--medal-bronze);
}

/* A win outranks a lower placement in the same event. */
.event:has(.result--first) {
  border-left-color: var(--brand);
}

.event--cancelled,
.event--upcoming {
  background: none;
  border-style: dashed;
  border-left-style: dashed;
}

.event--cancelled:hover,
.event--upcoming:hover {
  transform: none;
  box-shadow: none;
}

.event__head {
  display: flex;
  align-items: center;
  gap: var(--space-s);
}

.event__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  flex: none;
  padding: 4px;
  border-radius: var(--radius-s);
  background: #ffffff;
}

.event__logo img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  object-fit: contain;
}

.event__name {
  font-size: var(--step-0);
  line-height: 1.3;
}

.event__meta {
  margin-top: 0.15rem;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.event__meta abbr {
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

.event__note {
  font-size: var(--step--1);
  color: var(--text-faint);
}

.event__plain {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-faint);
}

.result-list {
  display: grid;
  gap: 0.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.result {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

.result__badge {
  display: inline-flex;
  flex: none;
  width: 1.1rem;
  justify-content: center;
  padding-top: 0.15em;
}

.result__badge .icon {
  width: 1rem;
  height: 1rem;
  color: var(--brand);
}

.result--second .result__badge .icon {
  color: var(--medal-silver);
}

.result--third .result__badge .icon {
  color: var(--medal-bronze);
}

.result__badge--plain::before {
  content: "";
  width: 5px;
  height: 5px;
  margin-top: 0.5em;
  border-radius: 50%;
  background: var(--border-strong);
}

.result__title {
  display: block;
  font-weight: 600;
  font-size: var(--step-0);
  line-height: 1.35;
}

.result--first .result__title {
  color: var(--text);
}

.result__note {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--text-faint);
}

.section__more {
  margin-top: var(--space-l);
}

/* Academic contributions */

/* Two columns once the container is wide enough. In one full-width column the
   card text ran to about 134 characters a line; two columns bring it back to a
   readable measure and use the space the cards are sitting in. */
.contrib-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(28rem, 1fr));
  gap: var(--space-m);
  list-style: none;
  padding: 0;
  margin-block: var(--space-m);
}

.contrib {
  padding: var(--space-m);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.contrib:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-s);
}

.contrib__tag {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--brand);
}

.contrib__title {
  margin-top: 0.3rem;
  font-size: var(--step-2);
}

.contrib__subtitle {
  margin-top: 0.1rem;
  font-size: var(--step-0);
  color: var(--text-muted);
}

.contrib__body {
  margin-top: var(--space-xs);
}

.contrib__venue {
  margin-top: var(--space-2xs);
  font-size: var(--step--1);
  font-style: italic;
  color: var(--text-faint);
}

.contrib__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  list-style: none;
  padding: 0;
  margin-top: var(--space-s);
}

.contrib__links a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  gap: 0.35em;
  font-size: var(--step--1);
  font-weight: 700;
  text-decoration: none;
}

.contrib__links a:hover {
  text-decoration: underline;
}

.contrib__links .icon {
  width: 0.95em;
  height: 0.95em;
}

/* Supporters, grouped: academic institutions, current, past. The three tiers
   are deliberately weighted differently — past supporters should read as an
   acknowledgement, not as a current endorsement. */

.supporters + .supporters {
  margin-top: var(--space-l);
}

.supporters__title {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-bottom: var(--space-xs);
  border-bottom: 1px solid var(--border);
}

.supporters__lead {
  margin-top: var(--space-xs);
  font-size: var(--step--1);
  color: var(--text-muted);
}

.supporters__grid {
  display: grid;
  /* auto-fill, not auto-fit: with a single current supporter, auto-fit would
     stretch that one tile across the entire row. */
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--space-m);
  list-style: none;
  padding: 0;
  margin-top: var(--space-m);
}

.supporter {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  text-align: center;
}

.supporter > a {
  display: block;
  width: 100%;
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius-m);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.supporter > a:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-m);
}

.supporter__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 6rem;
  padding: var(--space-s);
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
}

.supporter__logo img {
  max-height: 100%;
  width: auto;
  object-fit: contain;
}

/* Used where we have no logo asset. Sits on the page background rather than a
   white plate, so it does not masquerade as a supplied logo. */
.supporter__logo--text {
  background: var(--surface);
  color: var(--text);
  font-size: var(--step-1);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.supporter__detail {
  font-size: var(--step--1);
  color: var(--text-faint);
}

.supporter__detail--name {
  color: var(--text-muted);
  font-weight: 600;
}

/* Past supporters are acknowledged, not advertised: smaller and slightly
   dimmed, brightening on hover. They keep the white plate — these logos are
   dark-on-light artwork and would be invisible on a transparent tile in dark
   mode. */
.supporters__grid--past {
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: var(--space-s);
}

.supporters__grid--past .supporter__logo {
  height: 4rem;
  font-size: var(--step-0);
}

/* Dim the artwork, not the plate: fading the whole tile greys the white
   background against the dark page and reads as "disabled" rather than
   "past". Hierarchy comes from the smaller tile instead. */
.supporters__grid--past .supporter__logo img {
  opacity: 0.7;
  transition: opacity 0.2s var(--ease);
}

.supporters__grid--past .supporter > a:hover .supporter__logo img {
  opacity: 1;
}

/* Closing call to action */

.cta {
  background: var(--dark-bg);
  color: var(--dark-text);
  padding-block: var(--space-2xl);
}

.cta__inner {
  display: grid;
  gap: var(--space-l);
  align-items: center;
}

@media (min-width: 56rem) {
  .cta__inner {
    grid-template-columns: minmax(0, 1.4fr) auto;
    gap: var(--space-xl);
  }
}

.cta__title {
  font-size: var(--step-3);
}

.cta__lead {
  margin-top: var(--space-s);
  color: var(--dark-muted);
  max-width: 40rem;
}

.cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
}

/* ------------------------------ 7. Interior pages and prose -------------- */

.page-header {
  background: var(--bg-alt);
  border-bottom: 1px solid var(--border);
  padding-block: var(--space-l);
}

.page-header__title {
  font-size: var(--step-4);
  margin-top: var(--space-2xs);
}

.page-header__lead {
  margin-top: var(--space-xs);
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: var(--measure);
  /* Short sentence: balance it rather than leaving a two-word orphan line. */
  text-wrap: balance;
}

.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  padding: 0;
  font-size: var(--step--1);
  color: var(--text-faint);
}

.breadcrumbs li + li::before {
  content: "/";
  margin-right: 0.5rem;
  color: var(--border-strong);
}

.breadcrumbs a {
  color: var(--text-muted);
  text-decoration: none;
}

.breadcrumbs a:hover {
  color: var(--brand);
}

.page__body {
  padding-block: var(--space-l) var(--space-2xl);
}

/* Two page shapes, each matching what the page is made of.
   Component pages (Team, Competitions, Publications, Research) are a single
   column: their rosters and card grids already fill the container.
   Text pages (Software, Hardware) pair the reading column with a contents rail,
   so the reading column is anchored on the left by the logo above it and the
   rail is anchored on the right by the nav button. */
@media (min-width: 64rem) {
  .page__body--railed {
    display: grid;
    grid-template-columns: minmax(0, var(--measure)) minmax(0, 1fr);
    gap: var(--space-2xl);
    align-items: start;
  }

  .page-rail {
    justify-self: end;
    width: min(100%, 15rem);
    position: sticky;
    top: calc(var(--header-h) + 2rem);
  }
}

.page-toc__heading {
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--space-2xs);
}

.page-toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--step--1);
}

/* Nested levels step in by one notch; deeper than that is not worth showing. */
.page-toc ul ul {
  padding-left: 0.85rem;
}

.page-toc li + li,
.page-toc ul ul {
  margin-top: 0.35rem;
}

.page-toc a {
  display: block;
  /* Tap target: 24px minimum per WCAG 2.5.8, met by the padding plus line-height. */
  padding-block: 0.2rem;
  color: var(--text-muted);
  text-decoration: none;
  border-left: 2px solid var(--border);
  padding-left: 0.75rem;
  margin-left: -0.75rem;
}

.page-toc a:hover,
.page-toc a:focus-visible {
  color: var(--brand);
  border-left-color: var(--brand);
}

/* Below the rail breakpoint the contents list would just repeat the headings
   the reader is about to scroll past. */
@media (max-width: 63.999rem) {
  .page-rail {
    display: none;
  }
}

/* Line length is capped here rather than on the container. Running text stops
   at --measure and stays left-aligned; components (anything carrying a class —
   rosters, timelines, galleries, card grids) fill the whole container. So every
   left edge lines up with the nav's logo, and every component's right edge
   lines up with the nav's button.
   Headings are deliberately not capped: they are short, and their rules read as
   section dividers that should run the full width of whatever column they are
   in. */
.prose > :where(p, ul, ol, dl, blockquote):not([class]) {
  max-width: var(--measure);
}

.prose > * + * {
  margin-top: var(--space-s);
}

/* Block components need more air than a paragraph does. */
.prose > * + .timeline,
.prose > * + .roster,
.prose > * + .gallery,
.prose > * + .contrib-list {
  margin-top: var(--space-l);
}

/* Scoped with `>` so that headings inside components (e.g. .roster__heading)
   keep their own styling. */
.prose > h2 {
  font-size: var(--step-3);
  margin-top: var(--space-xl);
  padding-top: var(--space-s);
  border-top: 1px solid var(--border);
}

.prose > h3 {
  font-size: var(--step-2);
  margin-top: var(--space-l);
}

.prose > h4 {
  font-size: var(--step-1);
  margin-top: var(--space-m);
}

.prose > h1 {
  font-size: var(--step-4);
  margin-top: var(--space-l);
}

/* Markdown lists only. Component lists (.pub-list, .contrib-list, .roster__grid,
   .result-list, .alumni-table, …) carry a class and set their own padding — the
   old `.prose ol` selector outranked their `padding: 0` and indented them all. */
.prose :where(ul, ol):not([class]) {
  padding-left: 1.35em;
}

.prose :where(ul, ol):not([class]) > li + li {
  margin-top: 0.35em;
}

.prose blockquote {
  padding: var(--space-s) var(--space-m);
  border-left: 3px solid var(--brand);
  background: var(--bg-alt);
  border-radius: 0 var(--radius-m) var(--radius-m) 0;
  color: var(--text-muted);
}

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}

.prose th,
.prose td {
  padding: 0.6em 0.8em;
  border-bottom: 1px solid var(--border);
  text-align: left;
}

/* Figures, in prose and via the figure-responsive shortcode. */

.figure {
  margin-block: var(--space-l);
}

.figure img {
  width: 100%;
  border-radius: var(--radius-m);
  border: 1px solid var(--border);
  background: var(--bg-alt);
}

.figure figcaption {
  margin-top: var(--space-xs);
  font-size: var(--step--1);
  color: var(--text-faint);
}

/* Figures are never cropped. Several of the hardware photos are portrait
   (up to 1400x1866); forcing them into a landscape box cut the robots in
   half. Tall images are capped by height instead and centred. */
.figure img {
  max-height: 34rem;
  width: auto;
  max-width: 100%;
  margin-inline: auto;
}

.centered {
  text-align: center;
}

.centered .figure {
  margin-inline: auto;
}

.link--external .icon,
.link--mail .icon {
  display: inline;
}

.link-list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--space-xs);
}

.link-list a {
  display: block;
  padding: var(--space-s);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  background: var(--surface);
  text-decoration: none;
  color: var(--text);
}

.link-list a:hover {
  border-color: var(--brand);
}

.link-list__title {
  display: block;
  font-weight: 700;
}

.link-list__desc {
  display: block;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.notfound {
  padding-block: var(--space-2xl);
  text-align: center;
}

.notfound__title {
  font-size: var(--step-4);
  margin-top: var(--space-2xs);
}

.notfound__lead {
  margin-inline: auto;
  margin-top: var(--space-s);
  max-width: 34rem;
  color: var(--text-muted);
}

.notfound .hero__actions {
  justify-content: center;
}

/* -------------------------------------------------- 8. Components -------- */

/* Team roster */

.roster {
  margin-top: var(--space-xl);
}

.roster:first-of-type {
  margin-top: var(--space-m);
}

.roster__heading {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-bottom: var(--space-xs);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-m);
}

.roster__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.6em;
  padding: 0.1em 0.5em;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  color: var(--text-muted);
  font-size: 0.85em;
  letter-spacing: 0;
}

.roster__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-s);
  list-style: none;
  padding: 0;
}

.person {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-s);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-m);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease),
    border-color 0.2s var(--ease);
}

.person:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-m);
  border-color: var(--border-strong);
}

.person__photo {
  width: 3.5rem;
  height: 3.5rem;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
}

.person__photo--initials {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(140deg, var(--brand), var(--brand-strong));
  color: var(--on-brand);
  font-weight: 700;
  font-size: var(--step-0);
  letter-spacing: 0.02em;
}

.person__name {
  font-size: var(--step-0);
}

.person__role {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--brand);
}

.person__meta,
.person__since {
  font-size: var(--step--1);
  color: var(--text-faint);
  line-height: 1.45;
}

/* Lead team photo, at the top of the team page.

   --photo-w is set inline by the team_photo shortcode from the source file's
   real pixel width, so the image is shown at most 1:1 and never upscaled into
   softness. It centres in the container when it is narrower than that. */
.team-photo {
  margin: 0 0 var(--space-xl);
}

.team-photo img {
  display: block;
  width: 100%;
  max-width: min(100%, var(--photo-w, 100%));
  height: auto;
  margin-inline: auto;
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-m);
}

.team-photo figcaption {
  margin-top: var(--space-xs);
  font-size: var(--step--1);
  color: var(--text-faint);
  text-align: center;
}

/* Team photo gallery (competitions page) */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--space-m);
  margin-block: var(--space-l);
}

.gallery__item {
  margin: 0;
}

/* The team photos span 4:3, 3:2 and 16:9. Cropping them all to one ratio cut
   people out of the group shots, so each photo is letterboxed inside a
   uniform tile instead: the grid stays even and every photo stays whole. */
.gallery__frame {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-m);
  border: 1px solid var(--border);
  background: var(--bg-sunken);
  transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.gallery__frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.gallery__item:hover .gallery__frame {
  transform: translateY(-3px);
  box-shadow: var(--shadow-m);
}

.gallery__item figcaption {
  margin-top: var(--space-2xs);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
}

/* Alumni table: dense, scannable list of former members. */

.alumni-table {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--border);
}

.alum {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.1rem var(--space-s);
  align-items: baseline;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--border);
}

@media (min-width: 42rem) {
  .alum {
    grid-template-columns: minmax(0, 16rem) 7rem 6rem minmax(0, 1fr);
    align-items: center;
  }
}

.alum__name {
  font-weight: 600;
}

.alum__years,
.alum__inst,
.alum__lead {
  font-size: var(--step--1);
  color: var(--text-faint);
}

.alum__years {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

@media (min-width: 42rem) {
  .alum__years {
    text-align: left;
  }
}

.alum__inst abbr {
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

.alum__lead {
  color: var(--brand);
  font-weight: 600;
}

/* Video embeds — nothing loads until the visitor asks. */

.video-embed {
  margin-block: var(--space-l);
  border-radius: var(--radius-m);
  overflow: hidden;
  background: var(--dark-bg-2);
  aspect-ratio: 16 / 9;
}

.video-embed__placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  height: 100%;
  padding: var(--space-m);
  text-align: center;
  color: var(--dark-text);
  background: radial-gradient(
      circle at 50% 35%,
      color-mix(in srgb, var(--brand-on-dark) 32%, transparent),
      transparent 60%
    ),
    var(--dark-bg-2);
}

.video-embed__icon .icon {
  width: 3rem;
  height: 3rem;
  stroke-width: 1.2;
  color: var(--dark-text);
  opacity: 0.85;
}

.video-embed__title {
  font-weight: 700;
  font-size: var(--step-1);
}

.video-embed__notice {
  max-width: 34rem;
  font-size: var(--step--1);
  color: var(--dark-muted);
}

.video-embed .btn {
  margin-top: var(--space-2xs);
}

.video-embed__fallback {
  color: var(--dark-text);
  border-color: rgb(255 255 255 / 0.28);
}

.video-embed__fallback:hover {
  background: rgb(255 255 255 / 0.1);
  color: var(--dark-text);
}

/* When JS is available the button is the primary action, so quieten the link. */
.video-embed__fallback.is-secondary {
  border-color: transparent;
  color: var(--dark-muted);
  padding-block: 0.2em;
}

.video-embed.is-loaded {
  aspect-ratio: 16 / 9;
}

.video-embed iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* Alerts */

.alert {
  padding: var(--space-s) var(--space-m);
  border-radius: var(--radius-m);
  border: 1px solid var(--border);
  background: var(--bg-alt);
}

.alert--warning {
  border-color: #d9a441;
  background: color-mix(in srgb, #d9a441 12%, var(--bg));
}

.alert--danger {
  border-color: var(--brand);
  background: var(--brand-soft);
}

/* ---------------------------------------------------- 9. Footer ---------- */

.site-footer {
  background: var(--bg-sunken);
  border-top: 1px solid var(--border);
  padding-block: var(--space-xl) var(--space-m);
  font-size: var(--step--1);
}

.site-footer__grid {
  display: grid;
  gap: var(--space-l);
}

@media (min-width: 48rem) {
  .site-footer__grid {
    grid-template-columns: minmax(0, 2fr) repeat(2, minmax(0, 1fr));
    gap: var(--space-xl);
  }
}

.brand--footer {
  margin-bottom: var(--space-s);
  gap: 1rem;
}

/* The footer has room for a proper logo, unlike the header bar. */
.brand--footer .brand__mark {
  width: 5rem;
  height: 5rem;
}

.brand--footer .brand__name {
  font-size: var(--step-2);
}

.site-footer__address {
  color: var(--text-muted);
  line-height: 1.7;
}

.social-list {
  display: flex;
  gap: var(--space-2xs);
  list-style: none;
  padding: 0;
  margin-top: var(--space-s);
}

.social-list a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--text-muted);
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease),
    background-color 0.18s var(--ease), transform 0.18s var(--ease);
}

.social-list a:hover {
  color: var(--brand);
  border-color: var(--brand);
  background: var(--brand-soft);
  transform: translateY(-2px);
}

.social-list .icon {
  width: 1.25rem;
  height: 1.25rem;
}

.site-footer__heading {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--space-xs);
}

.site-footer__nav ul {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.4rem;
}

.site-footer__nav a {
  display: inline-block;
  padding-block: 0.2rem;
  color: var(--text-muted);
  text-decoration: none;
}

.site-footer__nav a:hover {
  color: var(--brand);
  text-decoration: underline;
}

.site-footer__bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  align-items: center;
  justify-content: space-between;
  margin-top: var(--space-xl);
  padding-top: var(--space-s);
  border-top: 1px solid var(--border);
  color: var(--text-faint);
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  list-style: none;
  padding: 0;
}

.site-footer__legal a {
  display: inline-block;
  padding-block: 0.2rem;
  color: var(--text-muted);
  text-decoration: none;
}

.site-footer__legal a:hover {
  color: var(--brand);
  text-decoration: underline;
}

.site-footer__note {
  margin-top: var(--space-s);
  font-size: 0.78rem;
  color: var(--text-faint);
  max-width: 44rem;
}

/* ------------------------------------------------------------- print ---- */

@media print {
  .site-header,
  .site-footer,
  .cta,
  .nav-toggle,
  .skip-link {
    display: none;
  }

  body {
    color: #000;
    background: #fff;
  }
}

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

.pub-count {
  font-size: var(--step--1);
  color: var(--text-faint);
  margin-bottom: var(--space-m);
}

.pub-list {
  display: grid;
  gap: var(--space-s);
  list-style: none;
  padding: 0;
  margin: 0;
}

.pub {
  padding: var(--space-s);
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-m);
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease),
    border-color 0.2s var(--ease);
}

.pub:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-m);
  border-left-color: var(--brand);
}

.pub__title {
  font-size: var(--step-0);
  line-height: 1.35;
}

.pub__authors {
  margin-top: 0.3rem;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.pub__authors strong {
  color: var(--text);
  font-weight: 700;
}

.pub__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.45rem;
  font-size: var(--step--1);
  color: var(--text-faint);
}

.pub__kind {
  padding: 0.1em 0.55em;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.pub__kind--conference,
.pub__kind--journal {
  background: var(--brand-soft);
  color: var(--brand);
}

.pub__note {
  margin-top: 0.4rem;
  font-size: var(--step--1);
  font-style: italic;
  color: var(--text-faint);
}

.pub__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  list-style: none;
  padding: 0;
  margin-top: 0.55rem;
}

.pub__links a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  gap: 0.3em;
  font-size: var(--step--1);
  font-weight: 600;
  text-decoration: none;
  word-break: break-word;
}

.pub__links a:hover {
  text-decoration: underline;
}

.pub__links .icon {
  width: 0.9em;
  height: 0.9em;
}
