﻿:root {
  --paper: #f6f4ef;
  --paper-panel: #efebe3;
  --ink: #1b1b1f;
  --ink-soft: #55534c;
  --gold: #9c7a3c;
  --line: rgba(27, 27, 31, 0.1);

  --font-display: "Fraunces", serif;
  --font-sans: "IBM Plex Sans", sans-serif;

  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 40px;
  --space-5: 64px;
  --space-6: 96px;
  --space-7: 128px;

  --header-h: 84px;

  /* Hero: how far the photo slides right on hover, and the matching gap left
     of the name / right of the photo once the reveal has settled. */
  --hero-shift: 40px;
  --hero-inset: 40px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
}

body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

a { color: inherit; }

img { max-width: 100%; }

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: var(--header-h);
  padding: 0 var(--space-5);
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.site-nav a {
  font-family: var(--font-sans);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
  padding-bottom: 5px;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}

.site-nav a:hover,
.site-nav a.active {
  color: var(--ink);
  border-bottom-color: var(--gold);
}

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.nav-toggle span {
  display: block;
  height: 1px;
  background: var(--ink);
}

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

.hero {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.3fr 0.7fr;
  column-gap: var(--space-4);
  align-items: center;
  overflow: hidden;
  cursor: pointer;
}

.hero-text {
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-4) var(--hero-inset);
  overflow: hidden;
}

.reveal-stack {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  max-width: 100%;
}

.name {
  flex: 0 0 auto;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  font-size: clamp(2.4rem, 5.6vw, 5rem);
  line-height: 0.96;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.name > span { display: block; }

.bio-wrap {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 0;
  margin-left: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  transition: max-width 0.6s cubic-bezier(0.22, 1, 0.36, 1),
              margin-left 0.6s cubic-bezier(0.22, 1, 0.36, 1),
              opacity 0.4s ease 0.15s;
}

/* max-width is what animates, so it has to stay close to the width the bio
   actually ends up at. An oversized value (it was 1000px) spends most of the
   half-second travelling through sizes the text never reaches - nothing appears
   to happen, and then it snaps. 400px is about the real width, so the open and
   close are both an even, unhurried glide. */
.hero:hover:not(.collapsed) .bio-wrap,
.hero.pinned:not(.collapsed) .bio-wrap {
  max-width: 400px;
  margin-left: 180px;
  opacity: 1;
  pointer-events: auto;
}

.reveal-rule {
  width: 64px;
  height: 1px;
  margin: 0 0 var(--space-2);
  background: var(--gold);
  flex: 0 0 auto;
}

/* The paragraph keeps one fixed width and the wrapper simply uncovers it.
   Letting it follow the wrapper instead means the text re-wraps on every frame
   of the reveal, and because it is justified the word gaps stretch and snap the
   whole way - which is what made the animation look elastic. Laid out once, it
   is only ever wiped into view. */
.bio {
  width: 360px;
  max-width: none;
  flex: 0 0 auto;
  margin: 0;
  font-size: 1.1rem;
  line-height: 1.65;
  color: var(--ink-soft);
  /* Flush down both edges, but never split a word across lines - no hyphens.
     text-wrap: pretty lets the browser look ahead over the whole paragraph and
     choose kinder line breaks, which keeps the word spacing even without them. */
  text-align: justify;
  hyphens: manual;
  -webkit-hyphens: manual;
  text-wrap: pretty;
  overflow-wrap: normal;
  word-break: normal;
}

.hero-photo {
  position: relative;
  min-width: 0;
  min-height: 0;
  /* Shift + inset, so once shifted the photo sits --hero-inset from the right
     edge - the same gap the name has on the left. Nothing gets clipped. */
  margin: var(--space-4) calc(var(--hero-shift) + var(--hero-inset)) var(--space-4) 0;
  overflow: hidden;
  background: var(--paper-panel);
  transform: translateX(0);
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.hero:hover:not(.collapsed) .hero-photo,
.hero.pinned:not(.collapsed) .hero-photo {
  transform: translateX(var(--hero-shift));
}

.hero-photo img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center 22%;
  filter: grayscale(1) contrast(1.05) brightness(1.02);
  transition: filter 0.6s ease;
}

.hero:hover:not(.collapsed) .hero-photo img,
.hero.pinned:not(.collapsed) .hero-photo img {
  filter: grayscale(0) contrast(1.02) brightness(1.01);
}

/* ---------- Interior pages ---------- */

.page {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6) var(--space-3);
  text-align: center;
  overflow: auto;
}

.page-inner { max-width: 560px; }

.page-inner h1 {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  white-space: nowrap;
}

.page-rule {
  width: 48px;
  height: 1px;
  margin: 0 auto var(--space-4);
  background: var(--gold);
}

.page-top {
  align-items: flex-start;
  padding-top: var(--space-6);
  padding-bottom: var(--space-6);
}

.page-compact {
  padding-top: var(--space-5);
  padding-bottom: var(--space-5);
}

.wide-inner {
  max-width: 720px;
  width: 100%;
  text-align: left;
}

.wide-inner h1 {
  text-align: center;
}

/* ---------- Research: papers ---------- */

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

.paper-section:first-of-type { margin-top: var(--space-5); }

.section-label {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-2);
}

.paper {
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--line);
}

.paper:last-child { border-bottom: none; }

.paper-title {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1.4;
  color: var(--ink);
}

.paper-title:hover { color: var(--gold); }

.jmp-tag {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}

.paper-coauthors {
  margin: 4px 0 0;
  font-size: 0.85rem;
  font-style: italic;
  color: var(--ink-soft);
}

.paper-coauthors a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 0.25s ease;
}

.paper-coauthors a:hover {
  color: var(--gold);
}

.paper-abstract {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.5s ease, opacity 0.4s ease, margin-top 0.5s ease;
}

.paper.open .paper-abstract {
  max-height: 900px;
  opacity: 1;
  margin-top: var(--space-3);
}

.paper-abstract p {
  margin: 0 0 var(--space-2);
  font-size: 0.92rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.paper-abstract p:last-child { margin-bottom: 0; }

.paper-links {
  margin-top: var(--space-2);
  display: flex;
  gap: var(--space-3);
}

.paper-links a {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--gold);
}

.paper-presentations {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
}

.paper-presentations li {
  font-size: 0.8rem;
  color: var(--ink-soft);
  line-height: 1.6;
}

/* ---------- Teaching ---------- */

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

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

.course-simple-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.98rem;
}

.course-simple-list li:last-child { border-bottom: none; }

.course-info {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.course-code {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--ink);
  flex: 0 0 auto;
}

.course-name {
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.course-term {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.placeholder-note {
  color: var(--ink-soft);
  font-size: 0.95rem;
  line-height: 1.7;
}

.teaching-note {
  margin: var(--space-2) 0 0;
  font-size: 0.85rem;
  font-weight: 600;
  font-style: italic;
  color: var(--ink-soft);
}

/* ---------- Contact ---------- */

.contact-inner {
  max-width: 660px;
}

.contact-intro {
  margin: var(--space-3) 0 0;
  font-size: 0.95rem;
  font-style: italic;
  color: var(--ink-soft);
}

.contact-grid {
  margin: var(--space-4) auto 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 190px));
  justify-content: center;
  gap: var(--space-3);
}

.contact-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: var(--space-3) var(--space-2);
  background: #fff;
  border: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transform: translateY(0);
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.contact-card:hover {
  transform: translateY(-4px);
  border-color: var(--gold);
  box-shadow: 0 10px 24px rgba(27, 27, 31, 0.08);
}

.contact-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--paper-panel);
  color: var(--gold);
  transition: background 0.25s ease;
}

.contact-card:hover .contact-icon {
  background: var(--paper);
}

.contact-icon svg {
  width: 22px;
  height: 22px;
}

.contact-label {
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
}

.contact-value {
  font-family: var(--font-display);
  font-size: 0.95rem;
  line-height: 1.4;
  text-align: center;
  color: var(--ink);
  white-space: nowrap;
}

.contact-address {
  font-size: 0.78rem;
  line-height: 1.6;
  text-align: center;
  color: var(--ink-soft);
}

.contact-card.copied {
  border-color: var(--gold);
}

.contact-card.copied .contact-value {
  color: var(--gold);
}

.contact-card-static,
.contact-card-pending {
  cursor: default;
}

.contact-card-static:hover {
  transform: none;
  border-color: var(--line);
  box-shadow: none;
}

.contact-card-static:hover .contact-icon {
  background: var(--paper-panel);
}

.contact-card-pending:hover {
  transform: none;
  border-color: var(--line);
  box-shadow: none;
}

.contact-card-pending:hover .contact-icon {
  background: var(--paper-panel);
}

.contact-pending {
  font-family: var(--font-sans);
  font-size: 0.85rem;
  color: var(--ink-soft);
}

/* ---------- CV ---------- */

/* Reclaim the generous interior-page padding for the document itself. */
.cv-page {
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
}

.cv-inner {
  max-width: 820px;
  width: 100%;
}

/* Shaped like a US Letter page so "view=Fit" lands page 1 whole, edge to edge,
   with no grey bars - scrolling then moves on to page 2. */
.cv-viewer {
  width: 100%;
  aspect-ratio: 8.5 / 11;
  margin: var(--space-3) auto;
  border: 1px solid var(--line);
  background: #fff;
}

.cv-viewer object {
  display: block;
  width: 100%;
  height: 100%;
}

.cv-fallback {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-4) var(--space-3);
  color: var(--ink-soft);
  font-size: 0.9rem;
}

.cv-actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
}

.btn-solid,
.btn-outline-link {
  display: inline-block;
  padding: 12px 28px;
  font-family: var(--font-sans);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--gold);
  transition: background 0.25s ease, color 0.25s ease;
}

.btn-solid {
  background: var(--gold);
  color: var(--paper);
}

.btn-solid:hover { background: #86682f; border-color: #86682f; }

.btn-outline-link {
  background: none;
  color: var(--gold);
}

.btn-outline-link:hover {
  background: var(--gold);
  color: var(--paper);
}

.btn-outline {
  display: inline-block;
  margin-top: var(--space-2);
  padding: 12px 28px;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  pointer-events: none;
  background: none;
  font-family: var(--font-sans);
}

/* ---------- Student portal ---------- */

.portal-inner { max-width: 420px; }

.portal-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-4);
  text-align: left;
}

.portal-form[hidden],
#portal-status[hidden] {
  display: none;
}

.portal-form h2 {
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.3rem;
  letter-spacing: 0.02em;
}

.portal-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.portal-form input {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  padding: 10px 12px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink);
}

.portal-form input:focus {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}

.portal-form .btn-outline,
#sign-out.btn-outline {
  pointer-events: auto;
  cursor: pointer;
  align-self: center;
}

.portal-hint {
  margin: 0;
  text-align: center;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.portal-form button[type="submit"][disabled] {
  opacity: 0.55;
  cursor: default;
}

.portal-error {
  margin: 0;
  min-height: 1.1em;
  font-size: 0.82rem;
  color: #a33b3b;
  text-align: center;
}

.portal-switch {
  margin: 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.portal-switch a { color: var(--gold); }

#portal-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.portal-greeting-line {
  margin: 0;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

#portal-status .btn-outline {
  pointer-events: auto;
  cursor: pointer;
}

.courses-heading {
  margin: var(--space-3) 0 0;
  font-family: var(--font-display);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.course-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
}

.course-card {
  display: block;
  padding: var(--space-3);
  border: 1px solid var(--line);
  text-align: left;
  text-decoration: none;
  color: inherit;
  background: #fff;
  transform: scale(1);
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.course-card:hover {
  transform: scale(1.04);
  border-color: var(--gold);
  box-shadow: 0 6px 18px rgba(27, 27, 31, 0.08);
}

.course-card h3 {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.course-card p {
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.course-card.locked {
  cursor: default;
  background: var(--paper-panel);
  opacity: 0.7;
}

.course-card.locked:hover {
  transform: none;
  border-color: var(--line);
  box-shadow: none;
}

.course-lock {
  margin-top: 6px !important;
  font-size: 0.72rem !important;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold) !important;
}

.course-lock[hidden] { display: none; }

/* ---------- Course materials ---------- */

.material-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
}

.material-card {
  display: block;
  padding: var(--space-3);
  border: 1px solid var(--line);
  background: #fff;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

.material-card:hover {
  border-color: var(--gold);
  box-shadow: 0 6px 18px rgba(27, 27, 31, 0.08);
}

.material-card h3 {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0.02em;
}

.material-card p {
  margin: 0;
  font-size: 0.82rem;
  color: var(--ink-soft);
}

/* ---------- Course chapters ---------- */

.chapter-intro {
  margin: 0 0 var(--space-4);
  font-size: 0.88rem;
}

.unit { margin-bottom: var(--space-5); }

.unit-label {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-2);
  line-height: 1.6;
}

.chapter-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.chapter-item { display: block; }

.chapter {
  display: grid;
  grid-template-columns: 68px 1fr auto;
  align-items: baseline;
  gap: var(--space-2);
  width: 100%;
  margin: 0;
  padding: var(--space-3);
  background: #fff;
  border: 1px solid var(--line);
  border-left: 2px solid transparent;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transform: translateY(0);
  box-shadow: 0 0 0 rgba(27, 27, 31, 0);
  transition: transform 0.22s ease, box-shadow 0.22s ease,
              border-color 0.22s ease, background 0.22s ease;
}

/* Lifts off the page and the title thickens under the pointer. */
.chapter:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(27, 27, 31, 0.1);
  border-color: var(--line);
  border-left-color: var(--gold);
  background: #fffdf9;
}

.chapter:hover .chapter-title,
.chapter[aria-expanded="true"] .chapter-title {
  font-weight: 600;
}

.chapter:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Small chevron that turns as the chapter opens. */
.chapter-caret {
  align-self: center;
  width: 8px;
  height: 8px;
  border-right: 1.5px solid var(--gold);
  border-bottom: 1.5px solid var(--gold);
  transform: rotate(45deg);
  transition: transform 0.25s ease;
}

.chapter[aria-expanded="true"] {
  border-left-color: var(--gold);
  background: #fffdf9;
}

.chapter[aria-expanded="true"] .chapter-caret {
  transform: rotate(-135deg);
}

.chapter-panel {
  padding: var(--space-2) var(--space-3) var(--space-3);
  border: 1px solid var(--line);
  border-top: none;
  background: var(--paper-panel);
}

.chapter-panel[hidden] { display: none; }

.chapter-note {
  margin: 0;
  font-size: 0.85rem;
  font-style: italic;
  color: var(--ink-soft);
}

.file-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.file-card {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
  padding: 10px var(--space-2);
  background: #fff;
  border: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.file-card:hover {
  border-color: var(--gold);
  background: #fffdf9;
}

.file-title { font-size: 0.92rem; }

.file-meta {
  flex: 0 0 auto;
  font-size: 0.76rem;
  color: var(--ink-soft);
  white-space: nowrap;
}

.chapter-no {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  color: var(--gold);
  white-space: nowrap;
}

.chapter-title {
  font-size: 0.98rem;
  line-height: 1.5;
  color: var(--ink);
}

.chapter-meta {
  font-size: 0.8rem;
  color: var(--ink-soft);
  white-space: nowrap;
}

.unit-exam {
  margin: var(--space-3) 0 0;
  padding: var(--space-2) var(--space-3);
  background: var(--paper-panel);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

@media (max-width: 700px) {
  .chapter {
    grid-template-columns: 1fr;
    gap: 4px;
  }

  /* No hover on a touch screen, so the lift would never be seen; a pressed
     state is the equivalent that does work. */
  .chapter:hover {
    transform: none;
    box-shadow: none;
    background: #fff;
  }

  .chapter:active {
    border-left-color: var(--gold);
    background: #fffdf9;
  }
}

/* ---------- Site report (admin only) ---------- */

.report-inner {
  max-width: 900px;
  width: 100%;
  text-align: left;
}

.report-inner h1 { text-align: center; }

.report-remember {
  flex-direction: row !important;
  align-items: center;
  gap: 8px !important;
  text-transform: none !important;
  letter-spacing: 0 !important;
}

.report-remember input { width: auto; }

.report-range {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-4) 0 var(--space-3);
}

.report-range label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.report-range select {
  font-family: var(--font-sans);
  font-size: 0.95rem;
  padding: 9px 12px;
  border: 1px solid var(--line);
  background: #fff;
  color: var(--ink);
}

.report-range .btn-outline {
  margin-top: 0;
  pointer-events: auto;
  cursor: pointer;
  padding: 10px 20px;
}

.report-totals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.report-stat {
  padding: var(--space-3);
  background: #fff;
  border: 1px solid var(--line);
  text-align: center;
}

.report-stat span {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.9rem;
  line-height: 1.1;
  color: var(--ink);
}

.report-stat small {
  display: block;
  margin-top: 4px;
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.report-heading {
  margin: var(--space-5) 0 var(--space-2);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--space-2);
}

.report-note {
  margin: 0 0 var(--space-2);
  font-size: 0.85rem;
  font-style: italic;
  color: var(--ink-soft);
}

/* Wide tables scroll inside their own box rather than stretching the page. */
.report-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  background: #fff;
}

.report-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.report-table th,
.report-table td {
  padding: 9px 12px;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}

.report-table th {
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--paper-panel);
}

.report-table tbody tr:last-child td { border-bottom: none; }

.report-chart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 160px;
  padding: var(--space-2);
  overflow-x: auto;
  background: #fff;
  border: 1px solid var(--line);
}

.report-bar {
  flex: 1 0 22px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  height: 100%;
  gap: 5px;
}

.report-bar-fill {
  width: 100%;
  min-height: 2px;
  background: var(--gold);
  opacity: 0.75;
}

.report-bar small {
  font-size: 0.62rem;
  color: var(--ink-soft);
  white-space: nowrap;
}

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

.site-footer {
  flex: 0 0 auto;
  padding: var(--space-3);
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  border-top: 1px solid var(--line);
}

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

/* Narrower desktops: the reveal gap + bio no longer fit beside the name. */
@media (max-width: 1400px) {
  .hero:hover:not(.collapsed) .bio-wrap,
  .hero.pinned:not(.collapsed) .bio-wrap {
    margin-left: var(--space-5);
  }
}

/* Small screens OR any touch device (tablets included). Touch has no hover, so
   these devices get the stacked, scrollable layout rather than the desktop one. */
/* Tablets get the two-column layout, but their photo column is narrow and very
   tall. Left to fill it, object-fit:cover would slice the sides off the
   portrait, so here the box keeps the photograph's own proportions and sits
   centred instead. Wider screens are untouched. */
@media (min-width: 701px) and (max-width: 1100px) {
  .site-nav { gap: var(--space-3); }

  /* The desktop insets are a big bite out of a narrow tablet column and leave
     the portrait tiny. Smaller values here; the two gaps still match. */
  .hero {
    --hero-shift: 16px;
    --hero-inset: 24px;
  }

  .hero-photo {
    height: auto;
    aspect-ratio: 2003 / 3004;
    align-self: center;
  }

  /* Less room beside the name here, so the revealed bio is narrower. */
  .hero:hover:not(.collapsed) .bio-wrap,
  .hero.pinned:not(.collapsed) .bio-wrap {
    max-width: 260px;
    margin-left: var(--space-3);
  }

  /* Matches the narrower wrapper above, so the text is neither clipped nor
     re-flowed while the reveal runs. */
  .bio {
    width: 260px;
    font-size: 1rem;
  }
}

/* Touch behaviour, independent of width - a tablet needs these while still
   getting the full desktop layout. */
@media (hover: none), (pointer: coarse) {
  /* iOS Safari zooms the whole page in when a focused field is under 16px.
     Sizing the inputs at exactly 16px keeps sign-in from jumping about. */
  .portal-form input { font-size: 16px; }

  /* There is no pointer to hover with, so main.js drives the reveal instead. */
  .hero { cursor: default; }
}

/* Stacking is about how much room there is, not about touch - a tablet is wide
   enough for the real two-column layout even though it has a touch screen.
   700px keeps iPads (768 and 820 wide in portrait) out of here, while the
   max-height arm still catches a phone held sideways, which is wide but far too
   short for a full-height hero. */
@media (max-width: 700px), (max-height: 520px) {
  html, body { height: auto; }
  body { overflow: visible; }

  .site-header { padding: 0 var(--space-3); }

  .site-nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    padding: 0 var(--space-3);
    max-height: 0;
    overflow: hidden;
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    transition: max-height 0.35s ease, padding 0.35s ease;
  }

  .site-nav.open {
    max-height: 420px;
    padding: var(--space-3);
  }

  /* Touch targets: a 21px-tall link is hard to hit with a thumb. Padding takes
     each menu row to ~45px without changing how it looks. */
  .site-nav a {
    display: block;
    width: 100%;
    padding: 12px 0;
    font-size: 0.82rem;
  }

  .site-nav { gap: 0; }

  .nav-toggle {
    display: flex;
    align-items: center;
    width: 44px;
    height: 44px;
    margin-left: -6px;
  }

  .nav-toggle span { width: 26px; }

  /* Small print is harder to read on a phone than on a monitor. */
  .site-footer { font-size: 0.78rem; }
  .contact-label { font-size: 0.8rem; }
  .jmp-tag,
  .course-lock { font-size: 0.76rem !important; }

  .hero {
    flex: none;
    grid-template-columns: 1fr;
    overflow: visible;
  }

  .hero-text { overflow: visible; }

  .page { overflow: visible; }

  /* The photograph is 2003x3004, i.e. 2:3 portrait. A fixed 320px-tall box was
     nearly square and object-fit:cover threw away a third of the picture (and
     70% of it on a tablet). Matching the box to the photo's own proportions
     means nothing is cropped at all. */
  .hero-photo {
    order: -1;
    height: auto;
    width: 100%;
    max-width: min(74vw, 340px);
    aspect-ratio: 2003 / 3004;
    margin: var(--space-3) auto;
  }

  .hero-text { padding: var(--space-5) var(--space-3); }

  /* No hover here, so the bio is shown permanently instead of on reveal. */
  .hero { cursor: default; }

  .reveal-stack {
    flex-direction: column;
    width: 100%;
  }

  /* ----- Phone opening: the pieces arrive one after another -----
     The layout is unchanged; each element simply lifts into place on a short
     delay. Appearance order is name, gold rule, photograph, then the bio -
     which is deliberately not the same as their order down the page. */
  .name,
  .reveal-rule,
  .hero-photo,
  .bio {
    animation: hero-arrive 0.65s cubic-bezier(0.22, 1, 0.36, 1) both;
  }

  .name        { animation-delay: 0.10s; }
  .reveal-rule { animation-delay: 0.35s; }
  .hero-photo  { animation-delay: 0.60s; }
  .bio         { animation-delay: 0.85s; }

  @keyframes hero-arrive {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
  }

  /* Respect a reader who has asked their phone for less movement. */
  @media (prefers-reduced-motion: reduce) {
    .name,
    .reveal-rule,
    .hero-photo,
    .bio {
      animation: none;
    }
  }

  /* These must repeat the ":not(.collapsed)" of the desktop rules they are
     overriding. Without it the desktop selectors are more specific and win even
     here, which pushed the bio 180px to the right and slid the photo sideways
     the moment the page was scrolled. */
  .bio-wrap,
  .hero:hover:not(.collapsed) .bio-wrap,
  .hero.pinned:not(.collapsed) .bio-wrap {
    flex: 0 0 auto;
    align-items: center;
    max-width: 440px;
    width: 100%;
    margin-left: 0;
    margin-top: var(--space-4);
    opacity: 1;
    overflow: visible;
    pointer-events: auto;
    transition: none;
  }

  .bio {
    width: 100%;
    font-size: 1rem;
  }

  .hero-photo,
  .hero:hover:not(.collapsed) .hero-photo,
  .hero.pinned:not(.collapsed) .hero-photo {
    transform: none;
  }

  /* No hover on a touch screen, so the black-and-white-into-colour reveal is
     driven by main.js instead: it adds .revealed once the photo scrolls into
     view. The picture is still seen in black and white first. */
  .hero-photo img {
    filter: grayscale(1) contrast(1.05) brightness(1.02);
    transition: filter 1.1s ease;
  }

  .hero-photo.revealed img {
    filter: grayscale(0) contrast(1.02) brightness(1.01);
  }
}

/* Phones: contact cards go one per row rather than two. */
@media (max-width: 560px) {
  .contact-grid { grid-template-columns: minmax(0, 280px); }
  .page-inner h1 { white-space: normal; }
  .contact-value { white-space: normal; }
}
