/* ==========================================================================
   Nichula S. Wasalathilaka — shared site stylesheet
   Design language: minimalist editorial academic.
   White ground, black type, one restrained deep-red accent, generous space.
   Consumed by index.html, publications.html and gallery.html.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
  --bg: #ffffff;
  --text: #101010;
  --muted: #5f6672;
  --light-muted: #858b95;
  --border: #e4e7eb;
  --border-strong: #d2d7dd;
  --accent: #b51217;
  --accent-hover: #991015;
  --soft-accent: #f8eded;
  --soft-bg: #f7f8f9;
  --map-fill: #eceff2;

  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;

  --content-max: 1360px;
  --gutter: clamp(1.25rem, 3vw, 2rem);
  --radius: 3px;

  /* Height of the sticky .site-header. Anything that has to clear it when
     scrolled to — see .pub-section's scroll-margin-top — reads this. */
  --header-h: 65px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --speed: 0.2s;
}

/* --------------------------------------------------------------------------
   2. Reset / base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The UA rule for [hidden] is display:none, but any author `display` on the
   same element outranks it. Several components here are laid out with
   display:flex/grid *and* toggled through the `hidden` property from
   JavaScript (the publications filter, the gallery filter strip, the
   "no publications in this category" note), so without this the attribute is
   silently inert and a filtered-out row stays on screen. */
[hidden] {
  display: none !important;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  font-feature-settings: "kern" 1, "liga" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1,
h2,
h3,
h4,
p,
figure,
ul,
ol {
  margin: 0;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

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

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

button {
  font: inherit;
  color: inherit;
}

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

[id] {
  scroll-margin-top: 5.5rem;
}

.visually-hidden {
  position: absolute;
  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;
  top: 0;
  left: 0;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  background: var(--text);
  color: #ffffff;
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-120%);
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline-offset: -2px;
}

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

/* --------------------------------------------------------------------------
   3. Header / navigation
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 4rem;
}

.brand {
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.017em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}

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

.nav-toggle {
  display: none;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.75rem;
  margin-right: -0.75rem;
  background: none;
  border: 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}

.nav-toggle__bars {
  position: relative;
  display: block;
  width: 18px;
  height: 1.5px;
  background: currentColor;
}

.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
  width: 18px;
  height: 1.5px;
  background: currentColor;
}

.nav-toggle__bars::before {
  top: -5.5px;
}

.nav-toggle__bars::after {
  top: 5.5px;
}

.site-nav__list {
  display: flex;
  align-items: center;
  gap: 1.875rem;
}

.site-nav__link {
  position: relative;
  display: inline-block;
  padding: 0.3rem 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}

.site-nav__link:hover {
  color: var(--text);
}

.site-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.1rem;
  height: 1.5px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.site-nav__link[aria-current="page"] {
  color: var(--text);
  font-weight: 600;
}

.site-nav__link[aria-current="page"]::after {
  transform: scaleX(1);
}

/* Nav entry whose target asset does not exist yet. */
.site-nav__link.is-unavailable {
  color: var(--light-muted);
  cursor: default;
}

/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.625rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--speed) var(--ease),
    border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
}

.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.btn--outline {
  background: var(--bg);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn--outline:hover {
  border-color: var(--text);
}

.btn--quiet {
  padding-inline: 0.35rem;
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
}

.btn--quiet:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

.btn.is-unavailable {
  background: var(--bg);
  border-color: var(--border);
  color: var(--light-muted);
  cursor: default;
}

.btn__note {
  font-weight: 500;
  font-size: 0.75rem;
}

.btn__arrow {
  font-size: 1.05em;
  line-height: 1;
}

/* --------------------------------------------------------------------------
   5. Section furniture
   -------------------------------------------------------------------------- */
.kicker {
  display: block;
  color: var(--accent);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1.4;
}

.column-heading {
  margin: 0 0 1.375rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--text);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
}

.section-more {
  margin-top: 1.75rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

.section-more a {
  color: var(--text);
  text-decoration-color: var(--border-strong);
}

.section-more a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(240px, 29vw, 380px);
  gap: clamp(2.5rem, 7vw, 7rem);
  align-items: center;
  padding-block: 3.5rem 2rem;
}

.hero__copy {
  min-width: 0;
}

.hero__kicker {
  margin-bottom: 1.125rem;
}

.hero__name {
  margin: 0;
  font-size: clamp(2.125rem, 3.4vw, 3.125rem);
  font-weight: 700;
  letter-spacing: -0.032em;
  line-height: 1.05;
}

.hero__identity {
  margin: 1rem 0 0;
  max-width: 32rem;
  font-size: clamp(1.0625rem, 1.45vw, 1.3125rem);
  font-weight: 500;
  line-height: 1.34;
  letter-spacing: -0.014em;
  color: var(--text);
}

.hero__bio {
  margin: 1.125rem 0 0;
  max-width: 38rem;
  font-size: 0.9688rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem;
  margin-top: 1.875rem;
}

.hero__portrait {
  margin: 0;
  justify-self: end;
  width: 100%;
}

.hero__portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 38%;
  border-radius: var(--radius);
  background: var(--soft-bg);
}

/* --------------------------------------------------------------------------
   7. Research visual strip
   -------------------------------------------------------------------------- */
.tiles {
  padding-bottom: 2rem;
}

.tiles__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}

.tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: 2px;
  background: var(--soft-bg);
  color: #ffffff;
  text-decoration: none;
  isolation: isolate;
}

.tile img {
  width: 100%;
  aspect-ratio: 8 / 5;
  object-fit: cover;
  transition: transform 0.5s var(--ease);
}

.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.78) 0%,
    rgba(0, 0, 0, 0.5) 22%,
    rgba(0, 0, 0, 0.07) 52%,
    rgba(0, 0, 0, 0) 72%
  );
}

.tile__caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 1.25rem 1.25rem 1.15rem;
}

.tile__title {
  font-size: 1.1875rem;
  font-weight: 650;
  letter-spacing: -0.018em;
  line-height: 1.2;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
}

.tile__subtitle {
  margin-top: 0.25rem;
  font-weight: 400;
  font-size: 0.75rem;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.88);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
}

.tile:hover img,
.tile:focus-visible img {
  transform: scale(1.035);
}

.tile:hover .tile__title,
.tile:focus-visible .tile__title {
  text-decoration: underline;
  text-underline-offset: 0.22em;
}

/* --------------------------------------------------------------------------
   8. Lower editorial columns
   -------------------------------------------------------------------------- */
.editorial {
  padding-block: 2.25rem 2.5rem;
  border-top: 1px solid var(--border);
}

.editorial__grid {
  display: grid;
  grid-template-columns: 44fr 29fr;
  gap: 1.75rem;
  align-items: start;
}

/* 8a. Selected papers ----------------------------------------------------- */
.papers li {
  display: grid;
  grid-template-columns: 105px minmax(0, 1fr);
  gap: 1.125rem;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--border);
}

.papers li:first-child {
  padding-top: 0;
}

.papers li:last-child {
  border-bottom: 0;
}

.paper__thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: left center;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--bg);
}

.paper__body {
  min-width: 0;
}

.paper__title {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

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

.paper__title a:hover {
  color: var(--accent);
}

.paper__authors {
  margin-top: 0.4rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--muted);
}

.paper__authors strong {
  color: var(--text);
  font-weight: 600;
}

.paper__venue {
  margin-top: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  color: var(--accent);
}

.paper__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 0.6rem;
}

.paper__links a {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
}

.paper__links a::after {
  content: " \2197";
  font-weight: 400;
}

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

/* 8b. Recent updates ------------------------------------------------------ */
.updates li {
  padding: 1.125rem 0;
  border-bottom: 1px solid var(--border);
}

.updates li:first-child {
  padding-top: 0;
}

.updates li:last-child {
  border-bottom: 0;
}

.update__date {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--light-muted);
  font-variant-numeric: tabular-nums;
}

.update__text {
  display: block;
  font-size: 0.8438rem;
  line-height: 1.52;
  color: var(--text);
}

.update__text em {
  font-style: normal;
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   10. Footer
   -------------------------------------------------------------------------- */
.site-footer {
  padding-block: 2rem 2.75rem;
  border-top: 1px solid var(--border);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem 2.5rem;
}

.site-footer__name {
  font-size: 0.8125rem;
  font-weight: 600;
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.375rem;
  font-size: 0.75rem;
}

.site-footer__links a {
  color: var(--muted);
  text-decoration-color: var(--border-strong);
}

.site-footer__links a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

.site-footer__links .is-unavailable {
  color: var(--light-muted);
}

.site-footer__copy {
  font-size: 0.6875rem;
  color: var(--light-muted);
}

/* --------------------------------------------------------------------------
   11. Responsive
   -------------------------------------------------------------------------- */

/* 1280 laptop */
@media (max-width: 1280px) {
  .editorial__grid {
    gap: 2.75rem;
  }
}

/* 1024 tablet landscape */
@media (max-width: 1080px) {
  .hero {
    gap: 2.5rem;
    padding-block: 3rem 3.5rem;
  }

  .editorial__grid {
    grid-template-columns: minmax(0, 62fr) minmax(0, 38fr);
    gap: 2rem 2.25rem;
  }

  .papers li {
    grid-template-columns: 105px minmax(0, 1fr);
  }
}

/* 768 tablet portrait */
@media (max-width: 860px) {
  .site-header__inner {
    flex-wrap: wrap;
  }

  .nav-toggle {
    display: inline-flex;
  }

  .site-nav {
    display: none;
    flex-basis: 100%;
    border-top: 1px solid var(--border);
  }

  .site-nav.is-open {
    display: block;
  }

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

  .site-nav__link {
    display: block;
    padding: 0.7rem 0;
    font-size: 0.9375rem;
  }

  .site-nav__link::after {
    right: auto;
    width: 1.75rem;
    bottom: 0.4rem;
  }

  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
    padding-block: 2.5rem 3rem;
  }

  .hero__identity,
  .hero__bio {
    max-width: none;
  }

  /* Portrait sits centred at roughly two-thirds of the viewport: prominent
     without dominating, and clearly composed rather than dropped in. */
  .hero__portrait {
    justify-self: center;
    max-width: min(68vw, 280px);
    margin-top: 0.5rem;
  }

  .tiles {
    padding-bottom: 1.75rem;
  }

  .tiles__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
  }

  /* Full-width tiles would otherwise become 450px tall on a tablet. */
  .tile img {
    max-height: 232px;
  }

  .editorial {
    padding-block: 2rem 2.25rem;
  }

  .editorial__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
  }

  .papers li {
    grid-template-columns: 92px minmax(0, 1fr);
  }


  .site-footer__inner {
    align-items: flex-start;
  }
}

/* 430 / 390 / 360 phones */
@media (max-width: 480px) {
  .hero {
    padding-block: 2.25rem 2.5rem;
  }

  .hero__actions .btn {
    flex: 1 1 auto;
    justify-content: center;
  }

  .hero__actions .btn--quiet {
    flex-basis: 100%;
    justify-content: flex-start;
  }

  .hero__portrait {
    max-width: min(68vw, 264px);
  }

  .tile__caption {
    padding: 1.05rem 1.1rem 1rem;
  }

  .papers li {
    grid-template-columns: 82px minmax(0, 1fr);
    gap: 0.9rem;
    padding: 1.25rem 0;
  }

}

/* --------------------------------------------------------------------------
   12. 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;
    scroll-behavior: auto !important;
  }
}

@media print {
  .site-header,
  .skip-link,
  .tiles,
  .rnet__map {
    display: none;
  }

  body {
    color: #000;
  }
}

/* ==========================================================================
   13. Research page — UNUSED
   research.html was removed from the site; nothing loads these rules today.
   They are kept intact so the page can be restored without rebuilding its
   stylesheet. Safe to delete outright if the page is not coming back.

   A continuation of the homepage system rather than a second design: same
   tokens, same container, same header and footer. Nothing below redefines the
   palette or the type scale — it only adds the editorial compositions the
   research narrative needs.
   ========================================================================== */

/* Legacy anchor aliases: the removed research.html carried readable ids on its
   section elements plus these zero-height spans for the older anchor names. */
.anchor-alias {
  display: block;
  height: 0;
  overflow: hidden;
}

/* 13a. Research hero ------------------------------------------------------ */
.research-hero {
  padding-block: 3.5rem 0;
}

.research-hero__title {
  margin: 1.125rem 0 0;
  max-width: 30ch;
  font-size: clamp(2rem, 3.2vw, 2.9375rem);
  font-weight: 700;
  letter-spacing: -0.032em;
  line-height: 1.06;
}

.research-hero__lede {
  margin: 1.375rem 0 0;
  max-width: 62ch;
  font-size: 1rem;
  line-height: 1.62;
  color: var(--muted);
}

/* Quiet inline jump links — deliberately not buttons. */
.jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin-top: 1.625rem;
}

.jump__link {
  padding-bottom: 0.15rem;
  border-bottom: 1px solid var(--border-strong);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: color var(--speed) var(--ease),
    border-color var(--speed) var(--ease);
}

.jump__arrow {
  color: var(--light-muted);
}

.jump__link:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.jump__link:hover .jump__arrow {
  color: var(--accent);
}

/* 13b. Research-direction strip ------------------------------------------ */
/* The homepage .tile component, unchanged; only the outer spacing differs. */
.directions {
  padding-top: 3rem;
  padding-bottom: 0;
}

/* 13c. Major research section -------------------------------------------- */
.rsection {
  padding-top: 5.5rem;
}

.rsection + .rsection {
  padding-top: 6.25rem;
}

.rsection__head {
  max-width: 64ch;
}

.rsection__title {
  margin: 0.75rem 0 0;
  font-size: clamp(1.5rem, 2.25vw, 2.0625rem);
  font-weight: 700;
  letter-spacing: -0.028em;
  line-height: 1.12;
}

.rsection__note {
  margin: 0.625rem 0 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--light-muted);
}

.rsection__thesis {
  margin: 1.125rem 0 0;
  max-width: 64ch;
  font-size: 0.9688rem;
  line-height: 1.62;
  color: var(--muted);
}

/* 13d. Editorial split: text one side, figure the other ------------------ */
.rsplit {
  display: grid;
  grid-template-columns: minmax(0, 42fr) minmax(0, 57fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
  margin-top: 2.75rem;
}

/* Scientific Computing mirrors the composition: figure left, text right. */
.rsplit--mirror {
  grid-template-columns: minmax(0, 57fr) minmax(0, 42fr);
}

.rsplit--mirror .rsplit__figure {
  order: -1;
}

.rsplit__body {
  min-width: 0;
}

/* 13e. Research figures --------------------------------------------------- */
/* No card, no border, no chrome. The figure is the object. */
.rfigure {
  margin: 0;
  min-width: 0;
}

.rfigure img {
  width: 100%;
  border-radius: 2px;
  background: var(--soft-bg);
}

.rfigure__cap {
  margin-top: 0.75rem;
  max-width: 80ch;
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--light-muted);
}

.rfigure--wide {
  margin-top: 2.5rem;
}

/* 13f. Project entries (Medical AI) --------------------------------------- */
.projects > * + * {
  margin-top: 1.75rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--border);
}

.project__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 650;
  letter-spacing: -0.012em;
  line-height: 1.32;
}

.project__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.7rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
}

.project__role {
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--light-muted);
}

.project__venue {
  color: var(--accent);
}

.project__desc {
  margin: 0.7rem 0 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--muted);
}

.project__subtitle {
  margin: 0.5rem 0 0;
  max-width: 46ch;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: -0.008em;
  color: var(--text);
}

.project__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.125rem;
  margin-top: 0.875rem;
  font-size: 0.75rem;
  font-weight: 600;
}

.project__links a {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
}

.project__links a:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* A link whose target does not exist yet: stated plainly, never faked. */
.project__links .is-unavailable {
  font-weight: 500;
  color: var(--light-muted);
}

/* 13g. Remote-sensing research threads ----------------------------------- */
.threads {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.25rem;
  margin-top: 3rem;
}

.thread {
  padding-top: 1.125rem;
  border-top: 1px solid var(--text);
}

.thread__question {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

.thread__work {
  margin: 0.875rem 0 0;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.42;
  color: var(--text);
}

.thread__venue {
  margin: 0.3rem 0 0;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--accent);
}

.thread__desc {
  margin: 0.7rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.58;
  color: var(--muted);
}

/* 13h. Quiet trailing link ------------------------------------------------ */
.aside-link {
  margin-top: 2.25rem;
  font-size: 0.8125rem;
  color: var(--muted);
}

.aside-link a {
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
}

.aside-link a:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* 13i. RespGeomLib process line ------------------------------------------ */
/* Typographic, not a flowchart: stages separated by thin arrows. */
.process {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.5rem;
  margin-top: 1.5rem;
  padding-top: 1.125rem;
  border-top: 1px solid var(--border);
  font-size: 0.75rem;
  font-weight: 600;
}

.process li {
  color: var(--text);
}

.process li::after {
  content: " \2192";
  margin-left: 0.45rem;
  font-weight: 400;
  color: var(--light-muted);
}

.process li:last-child::after {
  content: none;
}

/* 13j. Research principles ----------------------------------------------- */
.principles {
  padding-top: 5rem;
}

.principles__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.25rem;
  margin-top: 2rem;
}

.principle__title {
  margin: 0;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--text);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.principle__text {
  margin: 1.125rem 0 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--muted);
}

/* 13k. Publications CTA -------------------------------------------------- */
.pub-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem 2rem;
  margin-top: 5rem;
  padding-top: 1.5rem;
  padding-bottom: 3.5rem;
  border-top: 1px solid var(--border);
}

.pub-cta__text {
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: -0.012em;
}

.pub-cta__link {
  padding-bottom: 0.15rem;
  border-bottom: 1px solid var(--accent);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
}

.pub-cta__link:hover {
  color: var(--accent);
}

/* 13l. Research page — responsive ---------------------------------------- */

/* 1024 tablet landscape: the two-column splits and the three-column grids
   all collapse; each figure follows the prose it belongs to. */
@media (max-width: 1080px) {
  .rsplit,
  .rsplit--mirror {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }

  .rsplit--mirror .rsplit__figure {
    order: 0;
  }

  .threads,
  .principles__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem;
  }
}

/* 768 tablet portrait and below */
@media (max-width: 860px) {
  .research-hero {
    padding-block: 2.5rem 0;
  }

  .directions {
    padding-top: 2.25rem;
  }

  /* Match the homepage tile behaviour on small screens. */
  .directions .tile img {
    max-height: 232px;
  }

  .rsection {
    padding-top: 3.5rem;
  }

  .rsection + .rsection {
    padding-top: 3.75rem;
  }

  .rsplit {
    margin-top: 2rem;
  }

  .rfigure--wide {
    margin-top: 1.75rem;
  }

  .threads {
    margin-top: 2.25rem;
  }

  .principles {
    padding-top: 3.25rem;
  }

  .pub-cta {
    margin-top: 3.25rem;
    padding-bottom: 2.5rem;
  }
}

/* 430 / 390 / 360 phones */
@media (max-width: 480px) {
  .research-hero__title {
    font-size: 1.9375rem;
    letter-spacing: -0.026em;
  }

  /* The controlled break is a wide-screen typographic device only. */
  .research-hero__title br {
    display: none;
  }

  .research-hero__lede,
  .rsection__thesis {
    font-size: 0.9375rem;
  }

  .jump {
    gap: 0.5rem 1.25rem;
  }

  .pub-cta {
    display: block;
  }

  .pub-cta__link {
    display: inline-block;
    margin-top: 0.875rem;
  }
}

/* ==========================================================================
   14. Publications page
   The scholarly archive. Same tokens, same container, same header and footer
   as the homepage and the research page — this section only adds the row
   component the bibliography needs. Nothing here redefines the palette.
   ========================================================================== */

/* 14a. Hero ---------------------------------------------------------------- */
.pubs-hero {
  padding-block: 3.25rem 0;
}

/* Text left, venue feature right. The lede is what sets the left column's
   natural width, so the ratio is stated rather than left to content. */
.pubs-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr);
  gap: 2.5rem 3rem;
  align-items: center;
  max-width: 78rem;
}

.pubs-hero__title {
  margin: 1.125rem 0 0;
  font-size: clamp(2rem, 3.2vw, 2.9375rem);
  font-weight: 700;
  letter-spacing: -0.032em;
  line-height: 1.06;
}

/* Wide enough to hold the sentence on one line down to about 1100px, then
   wrap of its own accord. */
.pubs-hero__lede {
  margin: 1.0625rem 0 0;
  max-width: 34rem;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
}

/* 14b. Research-area navigation and sort ---------------------------------- */
/* The navigation is anchors to the three research sections, so it works
   without JavaScript and ships visible. Only the sort control is hidden until
   publications.js reveals it. Nothing on this page filters. */
/* A hairline turns the controls into the last line of the header rather than
   a toolbar floating between two sections. */
.pubs-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  max-width: 78rem;
  margin-top: 2.25rem;
  padding-top: 1.375rem;
  border-top: 1px solid var(--border);
}

/* --- Venue marks --------------------------------------------------------
   The two venues carrying accepted 2026 work, set straight on the page: no
   panel, no label, no caption. One hairline separates them and the marks are
   the only colour in the header. */

/* The block is only as wide as its widest line, so the marks and the caption
   share one centre while the block itself sits flush right. */
.venue-marks {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: max-content;
  max-width: 100%;
  margin-left: auto;
}

.venue-marks__list {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The two 1.125rem paddings put 36px between the marks with the hairline
   sitting exactly in the middle of that gap. */
.venue-marks__item {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding-inline: 1.125rem;
  padding-block: 0.3125rem;
}

.venue-marks__item:first-child {
  padding-left: 0;
}

.venue-marks__item:last-child {
  padding-right: 0;
}

.venue-marks__item + .venue-marks__item {
  border-left: 1px solid var(--border);
}

/* Both marks are given the same box and contained inside it, so they read at
   one height while keeping their own proportions and never being cropped. */
.venue-marks__logo {
  width: auto;
  max-width: 100%;
  height: 2.75rem;
  object-fit: contain;
  object-position: center;
}

.venue-marks__note {
  margin: 1rem 0 0;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}

.pubs-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.pubs-nav__link {
  padding: 0.375rem 0.8125rem;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--bg);
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease),
    border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.pubs-nav__link:hover {
  border-color: var(--text);
}

/* The section the reader is currently inside. */
.pubs-nav__link[aria-current="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  font-weight: 600;
}

.pubs-sort {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: var(--muted);
}

.pubs-sort select {
  padding: 0.375rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 0.8125rem;
  cursor: pointer;
}

/* 14c. Research sections --------------------------------------------------- */
/* Carries id="publication-list": the All control's target, deliberately above
   the first section heading so landing here is the "All" state rather than
   being indistinguishable from a click on Medical AI. */
.pubs-archive {
  padding-bottom: 4.5rem;
  scroll-margin-top: calc(var(--header-h) + 1rem);
}

.pub-sections {
  margin-top: 2.25rem;
}

/* A change of research area should read as a change of chapter, so the gap
   between sections is far larger than the gap between rows inside one. */
.pub-section + .pub-section {
  margin-top: 5rem;
}

/* Clears the sticky header when a section is jumped to, whether by the
   navigation above, a pasted #medical-ai link, or browser back/forward. */
.pub-section {
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
}

/* No card: a thin rule, a red number, the area, one line of description. */
.pub-section__head {
  padding-top: 1.125rem;
  border-top: 1px solid var(--border);
}

.pub-section__title {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 0.6875rem;
  font-size: 1.4375rem;
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.15;
  color: var(--text);
}

.pub-section__num {
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--accent);
}

.pub-section__lede {
  margin: 0.4375rem 0 0;
  font-size: 0.9063rem;
  line-height: 1.55;
  color: var(--muted);
}

.pub-list {
  display: grid;
  gap: 1rem;
  margin-top: 1.5rem;
}

/* One row per paper: teaser, then everything else. A single container and a
   single border — no inner cards, no boxed metadata, no button chrome.
   scroll-margin-top for the #pub-… deep links the homepage uses. */
.pub-item {
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
  display: grid;
  grid-template-columns: clamp(220px, 18vw, 244px) minmax(0, 1fr);
  gap: 1.625rem;
  padding: 1.375rem;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--bg);
  box-shadow: 0 1px 2px rgba(16, 16, 16, 0.025);
  transition: border-color var(--speed) var(--ease);
}

/* An archive, not a card deck: the row does not lift, scale or glow. Hover
   darkens the border and nothing else. */
.pub-item:hover {
  border-color: var(--border-strong);
}

.pub-item__figure {
  margin: 0;
}

/* contain, never cover: every teaser here is an architecture diagram or a
   qualitative panel where a crop would cost scientific meaning.

   No plate behind the image. The teasers carry a white ground of their own, so
   the letterbox that `contain` leaves is the same white as the row — the
   thumbnail reads as the artwork itself rather than as a tinted tile. The row
   already supplies the only border this needs. */
.pub-item__figure img {
  display: block;
  width: 100%;
  aspect-ratio: 5 / 3;
  object-fit: contain;
  border-radius: 5px;
}

.pub-item__body {
  display: flex;
  flex-direction: column;
  gap: 0.4375rem;
  min-width: 0;
}

/* 14d. Badge — at most one per row, and only where the record states it.
   This is the one place a pill is allowed: it is a metadata tag, not a
   control. Category is not shown here; that is what the filter bar is for. */
.pub-badge {
  align-self: start;
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.3;
  text-transform: uppercase;
}

.pub-badge--type {
  background: var(--soft-bg);
  border-color: var(--border);
  color: var(--muted);
}

/* 14e. Row content --------------------------------------------------------- */
.pub-item__title {
  margin: 0;
  font-size: 1.1875rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.25;
  color: var(--text);
}

.pub-item__authors {
  font-size: 0.9063rem;
  line-height: 1.5;
  color: var(--muted);
}

/* The site owner is emphasised by weight only — never by colour. nowrap so a
   long author list never splits the name across two lines. */
.pub-item__authors strong {
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
}

/* One continuous inline metadata line: logo, short name, full venue,
   location, status, separated by middle dots. Deliberately not a row of
   chips — nothing in here carries a box of its own. */
.pub-item__venue {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.1875rem 0.5rem;
  margin-top: 0.1875rem;
  font-size: 0.8438rem;
  line-height: 1.45;
  color: var(--muted);
}

/* Sized by the logo it holds rather than a fixed slot, so the venue text
   follows the mark instead of sitting in a second column. */
.pub-venue-brand {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
}

.pub-venue-brand img {
  max-width: 72px;
  max-height: 26px;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* A venue with no cleared logo file (MICCAI, Mercon) has no brand element at
   all: the line simply starts with the bold venue name. The boxed textual
   mark that used to stand in for the logo only restated that name, so it was
   a box carrying no information. */
.pub-venue-name {
  font-weight: 600;
  color: var(--text);
}

.pub-venue-detail::before,
.pub-venue-status::before {
  content: "\00b7";
  margin-right: 0.5rem;
  color: var(--light-muted);
}

.pub-venue-status {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--light-muted);
}

/* 14f. Action links — plain text plus a line glyph, never buttons. --------- */
.pub-item__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.125rem;
  margin-top: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

.pub-item__links a {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  color: var(--accent);
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}

.pub-item__links a:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

.pub-icon {
  flex: 0 0 auto;
  width: 0.875rem;
  height: 0.875rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 14g. Responsive ---------------------------------------------------------- */

/* Narrow desktop / tablet landscape: the teaser gives up width first. */
@media (max-width: 1080px) {
  .pub-item {
    grid-template-columns: 205px minmax(0, 1fr);
    gap: 1.25rem;
    padding: 1.25rem;
  }
}

/* Below ~1024 the venue feature would squeeze the lede, so the header
   becomes one column: text, then venues, then the controls. */
@media (max-width: 1024px) {
  .pubs-hero__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }

  .pubs-hero__lede {
    max-width: 44rem;
  }

  /* Stacked under the subtitle, the block centres rather than hugging right. */
  .venue-marks {
    margin-inline: auto;
  }
}

/* Tablet portrait and below: the row stacks. */
@media (max-width: 700px) {
  .pubs-hero {
    padding-block: 2.75rem 0;
  }

  .pubs-controls {
    margin-top: 1.75rem;
    padding-top: 1.125rem;
  }

  /* nowrap matters: a wrapping column container sizes each line to its
     widest item, so the scrolling nav strip below would stretch the whole
     control block to its content width and push the page sideways. */
  .pubs-controls {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0.6875rem;
  }

  /* One scrolling strip rather than four stacked rows. */
  .pubs-nav {
    flex-wrap: nowrap;
    min-width: 0;
    white-space: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  .pubs-nav::-webkit-scrollbar {
    display: none;
  }

  .pubs-nav__link {
    flex: 0 0 auto;
  }

  .pub-sections {
    margin-top: 2rem;
  }

  /* Still a clear chapter break, but a phone needs less of one. */
  .pub-section + .pub-section {
    margin-top: 3.5rem;
  }

  .pub-section__head {
    padding-top: 1rem;
  }

  .pub-section__title {
    font-size: 1.25rem;
    gap: 0.5625rem;
  }

  .pub-section__lede {
    font-size: 0.8438rem;
  }

  /* Stacked, in reading order: teaser, badge, title, authors, venue, links. */
  .pub-item {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.875rem;
    padding: 1.0625rem;
  }

  /* Fixed height instead of a fixed ratio: at 700px a full-width 5:3 teaser
     would stand taller than all the text beside it. Still `contain`, so no
     architecture diagram gets cropped on a phone. */
  .pub-item__figure img {
    aspect-ratio: auto;
    height: 190px;
  }

  .pub-item__title {
    font-size: 1.0625rem;
  }

  .pub-item__authors {
    font-size: 0.8438rem;
  }

  /* The venue line stops being one line: logo and short name lead, then the
     full venue name and the location/status wrap underneath rather than
     being squeezed. */
  .pub-item__venue {
    font-size: 0.8125rem;
    gap: 0.125rem 0.4375rem;
  }

  /* Full venue name and status each take their own line under the brand. */
  .pub-item__venue .pub-venue-detail,
  .pub-item__venue .pub-venue-status {
    flex: 0 0 100%;
  }

  /* A leading middle dot separates items along a line; at the start of one it
     is just a stray mark. */
  .pub-item__venue .pub-venue-detail::before,
  .pub-item__venue .pub-venue-status::before {
    content: none;
    margin-right: 0;
  }

  .pub-item__links {
    font-size: 0.8125rem;
  }

  .pubs-archive {
    padding-bottom: 4rem;
  }
}

@media (max-width: 520px) {
  .venue-marks__item {
    padding-inline: 1.0625rem;
  }

  .venue-marks__logo {
    height: 2.5rem;
  }
}

@media (max-width: 480px) {
  .pubs-hero__title {
    font-size: 1.9375rem;
    letter-spacing: -0.026em;
  }

  .pubs-hero__lede {
    font-size: 0.9375rem;
  }

  .pub-item__figure img {
    height: 168px;
  }

  .pub-item__links {
    gap: 0.25rem 1rem;
  }
}

/* ==========================================================================
   12. Gallery (gallery.html)
   Entries, per-entry scroll-snap swiper, and the shared lightbox.
   Same ground rules as the rest of the site: white, thin borders, one accent.
   ========================================================================== */

.gallery-hero {
  padding-block: 3.75rem 0;
}

.gallery-hero__title {
  margin: 1.125rem 0 0;
  font-size: clamp(2rem, 3.4vw, 3.125rem);
  font-weight: 700;
  letter-spacing: -0.032em;
  line-height: 1.06;
}

.gallery-hero__lede {
  margin: 1.0625rem 0 0;
  max-width: 52rem;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--muted);
}

.gallery {
  /* The mat behind a contained image — a shade cooler than white so a
     landscape poster reads as mounted rather than floating. */
  --mat: #f5f5f3;
  padding-block: 2.25rem 4.5rem;
}

/* --- Filters ------------------------------------------------------------ */

.gallery-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-bottom: 2.5rem;
}

.gallery-filter {
  padding: 0.375rem 0.8125rem;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--bg);
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease),
    border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.gallery-filter:hover {
  border-color: var(--text);
}

.gallery-filter[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
  font-weight: 600;
}

/* --- Grid --------------------------------------------------------------- */

/* Two entries today. The featured column is wider because the IGARSS entry
   carries three visuals and a poster; a third entry simply wraps onto a new
   row rather than forcing a denser grid. */
.gallery-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 3rem 2rem;
  max-width: 78rem;
  align-items: start;
}

.gallery-grid:empty {
  display: none;
}

.gitem {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  overflow: hidden;
  transition: border-color var(--speed) var(--ease);
}

.gitem:hover {
  border-color: var(--border-strong);
}

.gitem__media {
  border-bottom: 1px solid var(--border);
}

.gitem__body {
  padding: 1.125rem 1.25rem 1.375rem;
}

.gitem__category {
  margin: 0;
  color: var(--accent);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  line-height: 1.4;
  text-transform: uppercase;
}

.gitem__title {
  margin: 0.5rem 0 0;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.018em;
  line-height: 1.25;
}

.gitem__meta {
  margin: 0.4375rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--muted);
}

.gitem__subtitle {
  margin: 0.75rem 0 0;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.45;
  color: var(--text);
}

.gitem__caption {
  margin: 0.625rem 0 0;
  max-width: 58ch;
  font-size: 0.8438rem;
  line-height: 1.5;
  color: var(--muted);
}

.gitem__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.125rem;
  margin: 0.9375rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
}

.gitem__links a {
  color: var(--accent);
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}

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

.gitem__arrow {
  margin-left: 0.25rem;
}

/* --- Swiper ------------------------------------------------------------- */

.gswipe {
  position: relative;
  aspect-ratio: var(--frame, 3 / 2);
  background: var(--mat);
}

.gswipe__track {
  display: flex;
  height: 100%;
  margin: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}

.gswipe__track::-webkit-scrollbar {
  display: none;
}

.gswipe__slide {
  flex: 0 0 100%;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.gswipe__open {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

.gswipe__open.is-inert {
  cursor: default;
}

.gswipe__open img {
  width: 100%;
  height: 100%;
}

.gswipe__open img.is-contained {
  background: var(--mat);
}

.gswipe__arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  transform: translateY(-50%);
  border: 1px solid rgba(16, 16, 16, 0.08);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.86);
  color: var(--text);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--speed) var(--ease),
    background-color var(--speed) var(--ease);
}

.gswipe__arrow--prev {
  left: 0.625rem;
}

.gswipe__arrow--next {
  right: 0.625rem;
}

.gswipe__arrow svg {
  width: 0.8125rem;
  height: 0.8125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.gswipe:hover .gswipe__arrow,
.gswipe__arrow:focus-visible {
  opacity: 1;
}

.gswipe__arrow:hover {
  background: #ffffff;
}

.gswipe__arrow[disabled] {
  cursor: default;
  opacity: 0;
}

.gswipe:hover .gswipe__arrow[disabled] {
  opacity: 0.28;
}

.gswipe__dots {
  position: absolute;
  bottom: 0.6875rem;
  left: 50%;
  z-index: 2;
  display: flex;
  gap: 0.375rem;
  padding: 0.3125rem 0.5rem;
  transform: translateX(-50%);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.72);
}

.gswipe__dot {
  width: 0.4375rem;
  height: 0.4375rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(16, 16, 16, 0.26);
  cursor: pointer;
  transition: background-color var(--speed) var(--ease);
}

.gswipe__dot[aria-current="true"] {
  background: var(--accent);
}

/* --- Status and closing note -------------------------------------------- */

.gallery-status {
  margin: 0;
  font-size: 0.875rem;
  color: var(--muted);
}

.gallery-closing {
  margin: 3.5rem 0 0;
  padding-left: 0.875rem;
  border-left: 2px solid var(--accent);
  max-width: 40rem;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--muted);
}

/* --- Lightbox ----------------------------------------------------------- */

.glightbox {
  max-width: none;
  max-height: none;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}

.glightbox[open] {
  display: grid;
  place-items: center;
}

.glightbox::backdrop {
  background: rgba(12, 12, 14, 0.9);
}

.glightbox__shell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  width: 92vw;
  max-height: 88vh;
}

.glightbox__close {
  position: absolute;
  top: -0.375rem;
  right: 0;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  transform: translateY(-100%);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  color: #ffffff;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease);
}

.glightbox__close:hover {
  background: rgba(255, 255, 255, 0.16);
}

.glightbox__close svg {
  width: 0.8125rem;
  height: 0.8125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
}

.glightbox__stage {
  position: relative;
  min-height: 0;
}

.glightbox__track {
  display: flex;
  height: 74vh;
  margin: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}

.glightbox__track::-webkit-scrollbar {
  display: none;
}

.glightbox__slide {
  display: grid;
  flex: 0 0 100%;
  place-items: center;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.glightbox__slide img {
  max-width: 100%;
  max-height: 74vh;
  object-fit: contain;
}

.glightbox__arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  transform: translateY(-50%);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 50%;
  background: rgba(20, 20, 22, 0.6);
  color: #ffffff;
  cursor: pointer;
  transition: background-color var(--speed) var(--ease),
    opacity var(--speed) var(--ease);
}

.glightbox__arrow--prev {
  left: 0.5rem;
}

.glightbox__arrow--next {
  right: 0.5rem;
}

.glightbox__arrow:hover {
  background: rgba(40, 40, 44, 0.86);
}

.glightbox__arrow[disabled] {
  cursor: default;
  opacity: 0.25;
}

.glightbox__arrow svg {
  width: 0.875rem;
  height: 0.875rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.glightbox__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1.25rem;
  color: rgba(255, 255, 255, 0.72);
}

.glightbox__title {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: #ffffff;
}

.glightbox__caption {
  margin: 0;
  font-size: 0.8125rem;
}

.glightbox__count {
  margin: 0;
  margin-left: auto;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.55);
}

/* --- Gallery responsive -------------------------------------------------- */

/* 1024 tablet landscape — equal columns read better once the featured column
   would otherwise squeeze its caption. */
@media (max-width: 1080px) {
  .gallery-grid {
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem 1.5rem;
  }

  .gitem__title {
    font-size: 1.1875rem;
  }
}

/* 860 — single column, and the arrows give way to touch and dots. */
@media (max-width: 860px) {
  .gallery-hero {
    padding-block: 2.75rem 0;
  }

  .gallery-grid {
    grid-template-columns: 1fr;
    gap: 2rem;
    max-width: 34rem;
  }

  .gswipe__arrow {
    display: none;
  }

  .gallery-closing {
    margin-top: 2.75rem;
  }
}

@media (max-width: 480px) {
  .gallery-hero__title {
    font-size: 1.9375rem;
    letter-spacing: -0.026em;
  }

  .gallery-hero__lede {
    font-size: 0.9375rem;
  }

  .gitem__body {
    padding: 1rem 1rem 1.25rem;
  }

  .gitem__title {
    font-size: 1.125rem;
  }

  .gitem__meta,
  .gitem__caption {
    font-size: 0.8125rem;
  }

  .glightbox__track {
    height: 66vh;
  }

  .glightbox__slide img {
    max-height: 66vh;
  }
}

/* Smooth scrolling is opt-in; scroll-snap itself keeps working. */
@media (prefers-reduced-motion: reduce) {
  .gswipe__track,
  .glightbox__track {
    scroll-behavior: auto;
  }
}

/* =========================================================================
   BEYOND RESEARCH
   A personal coda below the academic archive on gallery.html. Deliberately
   quieter than everything above it: a warm off-white ground, five small
   polaroids on a loose route, and nothing that competes with the research
   work for attention.
   ========================================================================= */

.beyond {
  --paper: #ffffff;
  --paper-edge: #ece9e3;
  --ink: #333333;
  --route: #c9c6c0;

  margin-top: 5.5rem;
  padding-block: 3.25rem 5rem;
  background: #fbfaf7;
  border-top: 1px solid #f0ede7;
}

.beyond__inner {
  position: relative;
  max-width: 56rem;
}

/* --- Heading ------------------------------------------------------------ */

.beyond__head {
  position: relative;
  z-index: 1;
  max-width: 34rem;
  margin-bottom: 1.75rem;
}

.beyond__title {
  margin: 0.625rem 0 0;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.beyond__lede {
  margin: 0.5rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--muted);
}

/* Tiny outline horizon, drawn rather than imported. */
.beyond__mark {
  display: block;
  width: 4rem;
  height: 1.125rem;
  margin-top: 1.125rem;
  fill: none;
  stroke: var(--route);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --- Route -------------------------------------------------------------- */

/* The dashed line sits behind the opaque polaroids, so it reads as a route
   threading between them and never crosses a photograph. */
.beyond__route {
  position: absolute;
  z-index: 0;
  top: 9rem;
  left: var(--gutter);
  width: calc(100% - 2 * var(--gutter));
  height: 36rem;
  fill: none;
  stroke: var(--route);
  stroke-width: 1;
  stroke-dasharray: 4 6;
  stroke-linecap: round;
  pointer-events: none;
}

/* --- Scatter ------------------------------------------------------------ */

/* A 12-column bed the polaroids are placed into by hand: same mechanism as a
   grid, but the spans and the per-item offsets keep it from reading as one. */
.beyond__scatter {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1.25rem 1.5rem;
  align-items: start;
}

.bpolaroid {
  margin: 0;
  padding: 0.6875rem 0.6875rem 0;
  border: 1px solid var(--paper-edge);
  background: var(--paper);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.07);
  transform: rotate(var(--tilt, 0deg));
  transition: transform var(--speed) var(--ease);
}

/* Placement is keyed to the photograph, not to sibling order, so the
   composition cannot reshuffle if an item is added, removed or reordered.
   Each also states its own frame, so the row heights are reserved even if the
   data file ever stops supplying one. */

.beyond__scatter .bpolaroid--kayaking {
  --frame: 4 / 3;
  grid-column: 1 / span 4;
  grid-row: 1;
}

.beyond__scatter .bpolaroid--hill-country {
  --frame: 3 / 4;
  grid-column: 6 / span 3;
  grid-row: 1;
  margin-top: 2.25rem;
}

.beyond__scatter .bpolaroid--surfing {
  --frame: 3 / 4;
  grid-column: 10 / span 3;
  grid-row: 1;
  margin-top: 0.75rem;
}

.beyond__scatter .bpolaroid--mountain {
  --frame: 1.93 / 1;
  grid-column: 2 / span 5;
  grid-row: 2;
  margin-top: 0.75rem;
}

.beyond__scatter .bpolaroid--snorkeling {
  --frame: 4 / 3;
  grid-column: 8 / span 4;
  grid-row: 2;
  margin-top: 2.75rem;
}

.bpolaroid__open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

.bpolaroid__open.is-inert {
  cursor: default;
}

/* The box is reserved from the aspect ratio alone, so the row heights are
   final before any photograph has downloaded and nothing reflows on load. */
.bpolaroid__open img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: var(--frame, 4 / 3);
  object-fit: cover;
}

/* The thicker strip below the image is what makes it read as a polaroid. */
.bpolaroid__caption {
  padding: 0.75rem 0.25rem 0.875rem;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 0.875rem;
  line-height: 1.3;
  color: var(--ink);
  text-align: center;
}

/* Hover settles the tilt rather than animating anything. */
@media (hover: hover) {
  .bpolaroid:hover {
    transform: rotate(calc(var(--tilt, 0deg) * 0.25)) scale(1.015);
  }
}

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

/* --- Closing note ------------------------------------------------------- */

.beyond__note {
  position: relative;
  z-index: 1;
  margin: 2.25rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 0.8125rem;
  line-height: 1.75;
  color: var(--light-muted);
  text-align: right;
  white-space: pre-line;
}

/* --- Beyond research responsive ----------------------------------------- */

@media (max-width: 1024px) {
  .beyond__scatter {
    gap: 1.25rem 1.25rem;
  }

  .beyond__scatter .bpolaroid--hill-country {
    margin-top: 1.75rem;
  }

  .beyond__scatter .bpolaroid--snorkeling {
    margin-top: 2rem;
  }
}

/* Below 700 the collage is abandoned for a single staggered column — a
   five-across scatter at phone width would shrink every photo past reading. */
@media (max-width: 700px) {
  .beyond {
    margin-top: 4rem;
    padding-block: 3rem 3.5rem;
  }

  .beyond__route {
    display: none;
  }

  .beyond__scatter {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
  }

  /* Same left / right / left / right / centre stagger as before, keyed to the
     photograph rather than to sibling order.

     The row offsets set above are deliberately NOT reset here. They carry into
     the stacked column and add a little extra air above hill-country, surfing,
     mountain and snorkeling — which is how the approved build reads, so it is
     kept. Adding `margin-top: 0` to this rule evens the gaps out, if that is
     ever wanted. */
  .beyond__scatter .bpolaroid {
    width: 86%;
  }

  .beyond__scatter .bpolaroid--kayaking,
  .beyond__scatter .bpolaroid--surfing {
    align-self: flex-start;
  }

  .beyond__scatter .bpolaroid--hill-country,
  .beyond__scatter .bpolaroid--mountain {
    align-self: flex-end;
  }

  .beyond__scatter .bpolaroid--snorkeling {
    align-self: center;
  }

  .beyond__note {
    margin-top: 2.5rem;
    text-align: center;
  }
}

@media (max-width: 480px) {
  .beyond__title {
    font-size: 1.3125rem;
  }

  .beyond__scatter .bpolaroid {
    width: 92%;
  }

  .bpolaroid__caption {
    font-size: 0.8125rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bpolaroid {
    transition: none;
  }

  .bpolaroid:hover {
    transform: rotate(var(--tilt, 0deg));
  }
}
