/* hartman-sarah.com — mobile-first.
   Colours are the darker end of the original Wix palette ramp, chosen so white
   text clears WCAG AA: blue 6.87:1, green 7.60:1, mint 5.30:1.
   The original used these hues at 0.6 alpha over a bright photo, which is the
   contrast bug this rebuild fixes. */

:root {
  --blue:  #116089;
  --green: #046134;
  --mint:  #1A7A57;
  --ink:   #333333;   /* 12.63:1 on white */
  --paper: #ffffff;
  --rule:  #d8dee3;

  --sans: "Open Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --display: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --measure: 68ch;
  --gutter: clamp(1rem, 4vw, 3rem);
}

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

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

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

body {
  margin: 0;
  font-family: var(--sans);
  /* Was 15px/1.1em — too small and too tight to read on a phone. */
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
}

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

a { color: var(--blue); }
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: 0.75rem 1rem;
  background: var(--paper);
  color: var(--blue);
  z-index: 100;
}
.skip-link:focus {
  left: 0;
}

/* Visually hidden but still available to assistive tech (clip-based pattern,
   not display:none, which would remove it from the accessibility tree too).
   General-purpose utility class; kept even though the footer's hidden
   "Footer" heading (its original use) was removed as redundant — the
   <footer> landmark role is already announced by assistive tech. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---- header ---- */

.site-header {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem var(--gutter);
  align-items: center;
  justify-content: space-between;
  padding: 1rem var(--gutter);
  border-bottom: 1px solid var(--rule);
}

.site-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.site-title a { color: var(--ink); text-decoration: none; }

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.95rem;
}
.nav a { color: var(--ink); text-decoration: none; }
.nav a:hover, .nav a:focus { color: var(--blue); text-decoration: underline; }

/* ---- hero ---- */

.hero { position: relative; isolation: isolate; }

.hero__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Scrim, so the h1 is legible regardless of what the photo is doing behind it.
   0.55 is measured, not chosen by eye. Sampling rice-paddies.jpg pixel by pixel
   and compositing black at each alpha, then computing white-on-backdrop ratios
   for the mobile crop region (a narrow centre column, the worst case, which is
   exactly where the original site failed):

     alpha   median   p99    p99.9   brightest
     0.00     4.83    1.12    1.01     1.00     <- the bug: white on bare photo
     0.40     9.78    3.16    2.86     2.85
     0.50    11.64    4.37    4.00     4.00     <- still under 4.5 on highlights
     0.55    12.71    5.21    4.81     4.81     <- AA on every pixel

   At 0.55 even the single brightest pixel in the frame clears 4.5:1, so the h1
   passes AA no matter how the photo crops. Lowering this re-introduces the bug on
   the highlights. If the hero photo is ever swapped, re-run the measurement. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(0, 0, 0, 0.55);
}

.hero__inner {
  padding: clamp(3rem, 12vw, 7rem) var(--gutter);
  text-align: center;
}

.hero h1 {
  margin: 0 0 clamp(1.5rem, 5vw, 2.5rem);
  font-family: var(--display);
  font-weight: 800;
  /* Was a fixed 70px, which overflowed narrow screens. */
  font-size: clamp(2rem, 6vw, 4.375rem);
  line-height: 1.1;
  color: var(--paper);
  text-transform: none;
}

.hero__cards {
  display: grid;
  gap: 1rem;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  max-width: 60rem;
}

.card {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 5.5rem;
  padding: 1.25rem 1rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.5vw, 1.875rem);
  letter-spacing: 0.05em;
  /* Fully opaque — the fix. Translucent fills made contrast photo-dependent. */
  color: var(--paper);
  text-decoration: none;
  border-bottom: 6px solid rgba(255, 255, 255, 0.35);
}
.card--blue  { background: var(--blue); }
.card--green { background: var(--green); }
.card--mint  { background: var(--mint); }
/* Darken, don't brighten: white text on these fills already sits close to
   the 4.5:1 AA floor (mint is the tightest, at 5.30:1). Brightening any of
   them pushes the fill toward white and erodes that margin — brightness(1.15)
   on mint measured 4.21:1, below AA. Darkening only widens the gap. */
.card:hover, .card:focus { filter: brightness(0.88); }
.card:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(0, 0, 0, 0.6);
}

/* ---- sections ---- */

main > section { padding: clamp(2.5rem, 8vw, 5rem) var(--gutter); }
main > section + section { border-top: 1px solid var(--rule); }

h2 {
  margin: 0 0 1.5rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.75rem, 5vw, 3.5rem);
  line-height: 1.15;
  color: var(--blue);
}

h3 {
  margin: 2.5rem 0 1rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.5vw, 1.4rem);
  letter-spacing: 0.06em;
  color: var(--blue);
}

p { max-width: var(--measure); }

.lede { font-size: 1.15em; }

.about__grid { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }
.about__figure { margin: 0; }
.about__figure img { width: 100%; border-radius: 2px; }

.education ul { padding-left: 0; list-style: none; }
.education li { margin-bottom: 1rem; }

/* Was a single undifferentiated wall of 15px text — the worst readability
   problem on the old site. Now spaced, semantic lists. */
.pub-list {
  max-width: var(--measure);
  margin: 0;
  padding-left: 0;
  list-style: none;
}
.pub-list > li {
  margin-bottom: 1.5rem;
  padding-left: 1rem;
  border-left: 3px solid var(--rule);
}
.pub-list a.doi { display: inline-block; margin-top: 0.25rem; font-size: 0.9em; word-break: break-word; }

.contact__langs { font-weight: 700; }
.contact__email a { font-size: 1.15em; }

/* ---- footer ---- */

.site-footer {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem var(--gutter);
  align-items: center;
  justify-content: space-between;
  padding: 2rem var(--gutter);
  border-top: 1px solid var(--rule);
}
.social { display: inline-flex; gap: 0.5rem; align-items: center; color: var(--blue); }
.copyright { margin: 0; font-size: 0.9rem; }

/* ---- breakpoints ---- */

@media (min-width: 48em) {          /* 768px */
  .hero__cards { grid-template-columns: repeat(3, 1fr); }
  .about__grid { grid-template-columns: 3fr 2fr; align-items: start; }
}

@media (min-width: 64em) {          /* 1024px */
  main > section { padding-inline: clamp(3rem, 8vw, 8rem); }
  .site-header { padding-inline: clamp(3rem, 8vw, 8rem); }
}

@media print {
  .site-header, .hero__bg, .skip-link { display: none; }
  body { color: #000; }
  .hero h1, .card { color: #000 !important; }
  .hero::after { display: none; }
}
