/* Landing page: hero, the lazy-susan menu, and the panel it zooms into.
   Shared tokens and elements are in base.css. */

.theme-switch {
  position: absolute;
  top: 16px;
  right: var(--gutter);
  z-index: 2;
}

/* The main screen fits the window: hero and turntable size to its height
   and sit centered in it, with the footer at the bottom. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

.page {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  justify-content: center;
  width: min(100%, 1080px);
  margin: 0 auto;
  padding: clamp(24px, 5vh, 72px) var(--gutter) 0;
}

.colophon {
  padding-block: 8px 16px;
}

/* Hero */

/* Name, tagline and links, with the photo beside them. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, auto) auto;
  justify-content: start;
  align-items: center;
  gap: 48px;
  margin-bottom: clamp(16px, 4vh, 56px);
}

.hero__photo {
  width: clamp(120px, min(17vw, 22vh), 216px);
  height: auto;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
}

/* Sized to its text, so it morphs cleanly into the breadcrumb. */
.hero__name {
  width: fit-content;
  margin: 0;
  font: 500 clamp(2.375rem, min(7vw, 8.5vh), 4.75rem) / 1 var(--font-ui);
  font-stretch: 118%;
  letter-spacing: -0.02em;
}

.hero__tagline {
  max-width: 52ch;
  margin: 0.9rem 0 0;
  color: var(--ink-soft);
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  line-height: 1.5;
}

/* Pulled left by the gap between each 44px target and its glyph, so the
   first icon lines up with the name. */
.hero__links {
  margin: 1.1rem 0 0 -11px;
}

/* Panels. Without JavaScript they are a grid of cards; with it they stand
   around a turntable (.is-ring) that spins one panel to the front. */

.lobes__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.lobe {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 208px;
  border-radius: 6px;
  color: var(--ink);
}

/* The glass: the whole card in the grid, each front face on the turntable.
   Every blurred layer is re-blurred each frame the network animates behind
   it, so blur is kept to these panels; other surfaces use opaque fills. */
.lobes:not(.is-ring) .lobe,
.is-ring .lobe__face {
  padding: 24px 28px 22px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--glass);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  overflow: hidden;
  transition: border-color 160ms ease;
}

:root[data-low-power] .lobes:not(.is-ring) .lobe,
:root[data-low-power] .is-ring .lobe__face {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--glass-solid);
}

.is-ring .lobe:hover .lobe__face,
.is-ring .lobe[data-front] .lobe__face {
  border-color: var(--rule-strong);
}

.lobes:not(.is-ring) .lobe__face {
  display: contents;
}

.lobes:not(.is-ring) .lobe__face--back {
  display: none;
}

/* Turntable. The scene holds the perspective; the grid becomes the ring,
   which lazy-susan.js rotates, and each panel has a front and a back face.
   Until the script measures it, the geometry below places the panels the
   same way (panel i at i of --n turns, --front at the front), so the first
   paint is already the turntable. --ring-gap and --ring-tilt are read by
   lazy-susan.js too. */

/* Panels keep their full size where the window has the height, and shrink
   (keeping their shape) where it does not. */
.lobes.is-ring {
  --lobe-h: clamp(200px, 28vh, 252px);
  --lobe-w: clamp(260px, min(40vw, var(--lobe-h) * 1.8), 456px);
  --ring-top: clamp(64px, 10vh, 104px);
  --ring-gap: 18px;
  --ring-tilt: -9deg;
  --radius: calc((var(--lobe-w) / 2 + var(--ring-gap)) / tan(180deg / var(--n)));
  position: relative;
  height: calc(var(--ring-top) + var(--lobe-h) + var(--radius) * 0.16 + 64px);
  /* Bleed into the gutters so side panels are clipped by the screen edge, not the column. */
  margin-inline: calc(var(--gutter) * -1);
  perspective: 1300px;
  perspective-origin: 50% 0;
  overflow-x: clip;
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
}

.is-ring .lobes__grid {
  display: block;
  position: absolute;
  top: var(--ring-top);
  left: 50%;
  width: var(--lobe-w);
  height: var(--lobe-h);
  margin-left: calc(var(--lobe-w) / -2);
  transform-style: preserve-3d;
  transform: translateZ(calc(var(--radius) * -1)) rotateX(var(--ring-tilt)) rotateY(calc(var(--front, 0) * -360deg / var(--n)));
}

.is-ring.is-dragging .lobes__grid {
  cursor: grabbing;
}

.is-ring .lobe {
  --depth: calc((cos((var(--i) - var(--front, 0)) * 360deg / var(--n)) + 1) / 2);
  position: absolute;
  inset: 0;
  min-height: 0;
  transform: rotateY(calc(var(--i) * 360deg / var(--n))) translateZ(var(--radius));
  transform-style: preserve-3d;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-drag: none;
}

/* The front panel opens on a click anywhere; the others turn to the front. */
.is-ring .lobe {
  cursor: pointer;
}

.is-ring .lobe__face--back {
  pointer-events: none;
}

.is-ring .lobe__face {
  position: absolute;
  inset: 0;
  /* Panels shrink on short windows; their contents tighten to match (below). */
  container: lobe / size;
  display: flex;
  flex-direction: column;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* Panels fade toward the back of the turntable. */
  opacity: calc(0.3 + 0.7 * var(--depth, 1));
}

.is-ring .lobe__face--back {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* Labels sit high, so the front panel does not cover the one at the back. */
  align-items: center;
  justify-content: flex-start;
  gap: 16px;
  padding-top: 30px;
  transform: rotateY(180deg);
  color: var(--ink-soft);
  font: 600 2rem/1.2 var(--font-ui);
}

/* The front panel carries the colormap as a colorbar along its foot. */
.is-ring .lobe__face--front::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 3px;
  background: var(--colorbar);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 240ms ease-out;
}

.is-ring .lobe[data-front] .lobe__face--front::after {
  transform: scaleX(1);
}

.lobes__controls {
  position: absolute;
  bottom: 0;
  left: 50%;
  display: flex;
  gap: 12px;
  transform: translateX(-50%);
}

.lobes__step {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--glass-solid);
  color: var(--ink);
  cursor: pointer;
}

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

/* Panel face: icon and title, the newest item, then the count and the way in. */

.lobe__head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
}

/* The icon takes the accent on the panel at the front, as the colorbar does. */
.lobe__icon {
  color: var(--ink-soft);
  font-size: 2.5rem;
  line-height: 1;
  transition: color 160ms ease;
}

.lobe__face--back .lobe__icon {
  font-size: 2.75rem;
}

.lobe:hover .lobe__face--front .lobe__icon,
.lobe[data-front] .lobe__icon,
.lobes:not(.is-ring) .lobe__icon {
  color: var(--link);
}

.lobe__title {
  font: 600 2.5rem/1.05 var(--font-ui);
  letter-spacing: -0.02em;
}

.lobe__example {
  display: block;
  margin-top: 18px;
  padding: 10px 14px 11px;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: color-mix(in srgb, var(--ink) 4%, transparent);
  color: var(--ink);
  text-decoration: none;
  transition: border-color 160ms ease;
}

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

.lobe__example-title {
  display: block;
  overflow: hidden;
  font: 600 1.0625rem/1.4 var(--font-ui);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lobe__example:hover .lobe__example-title {
  color: var(--link);
}

.lobe__example-detail {
  display: -webkit-box;
  overflow: hidden;
  color: var(--ink-soft);
  font-size: 0.9375rem;
  line-height: 1.4;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.lobe__example--about .lobe__example-detail {
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

.lobe__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: auto 0 0;
  padding-top: 14px;
}

.lobe__meta {
  color: var(--ink-soft);
  font: 500 0.875rem/1.2 var(--font-ui);
  font-variant-numeric: tabular-nums;
}

.lobe__years {
  white-space: nowrap;
}

.lobe__more {
  flex: none;
  font: 600 0.9375rem/1.2 var(--font-ui);
}

/* Zoom: a panel opened in place. The name sits in the breadcrumb above it,
   and the rest of the page stays behind, hidden, until it closes. */

.zoom {
  width: min(100%, 1080px);
  margin: 0 auto;
  padding: clamp(48px, 9vh, 88px) var(--gutter) 0;
}

:root[data-zoomed] {
  overflow: hidden;
}

/* With the turntable running, the bio is only shown zoomed in, so the main
   screen keeps one height from the first paint on. */
:root[data-turntable]:not([data-zoomed]) .zoom {
  display: none;
}

:root[data-zoomed] .page,
:root[data-zoomed] .colophon {
  visibility: hidden;
}

:root[data-zoomed] .theme-switch {
  position: fixed;
}

:root[data-zoomed] .zoom {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  padding: 0 var(--gutter) clamp(16px, 3vh, 32px);
}

/* One line: a long page title is cut short rather than wrapping. */
.crumbs ol {
  display: flex;
  align-items: baseline;
  margin: 0;
  /* Clear of the theme switch. */
  padding: 20px 150px 20px 0;
  list-style: none;
}

.crumbs li {
  display: flex;
  flex: none;
  align-items: baseline;
  white-space: nowrap;
}

.crumbs .crumbs__item {
  flex: 0 1 auto;
  min-width: 0;
}

.crumbs li + li::before {
  content: "/";
  margin: 0 12px;
  color: var(--rule-strong);
  font: 400 1rem/1 var(--font-ui);
}

.crumbs__home {
  color: var(--ink);
  font: 500 1.375rem/1 var(--font-ui);
  font-stretch: 118%;
  letter-spacing: -0.02em;
  text-decoration: none;
}

.crumbs__section a {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  color: var(--ink-soft);
  font: 500 1rem/1.2 var(--font-ui);
  text-decoration: none;
}

.crumbs__home:hover,
.crumbs__section a:hover,
.crumbs__section a[aria-current] {
  color: var(--ink);
}

.crumbs__icon {
  color: var(--link);
}

.crumbs__item span {
  overflow: hidden;
  min-width: 0;
  max-width: 48ch;
  color: var(--ink);
  font: 500 1rem/1.2 var(--font-ui);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: var(--glass-solid);
}

.sheet:focus {
  outline: none;
}

:root[data-zoomed] .sheet {
  overflow: auto;
  overscroll-behavior: contain;
}

/* A page in the sheet scrolls inside its frame. */
:root[data-zoomed] .sheet:has(> .sheet__frame:not([hidden])) {
  overflow: hidden;
}

.sheet__list {
  padding: clamp(20px, 3vw, 36px) clamp(20px, 4vw, 48px) 40px;
}

.sheet__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: transparent;
  transition: opacity 160ms ease;
}

.sheet__frame.is-loading {
  opacity: 0;
}

/* A profile elsewhere, above a section's list. */
.sheet__elsewhere {
  max-width: 76ch;
  margin: 0 auto 20px;
  font: 600 0.9375rem/1.3 var(--font-ui);
}

.sheet__elsewhere i {
  margin-right: 8px;
  font-size: 1.125rem;
  vertical-align: -0.1em;
}

.entries {
  margin: 0 auto;
  max-width: 76ch;
  padding: 0;
  list-style: none;
}

.entry {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr);
  column-gap: 16px;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
}

.entry:first-child {
  border-top: 0;
  padding-top: 0;
}

/* Undated lists (projects) have no year column. */
.entry:not(:has(.entry__year)) {
  grid-template-columns: minmax(0, 1fr);
}

.entry__year {
  padding-top: 0.15em;
  color: var(--ink-soft);
  font: 500 0.875rem/1.5 var(--font-ui);
  font-variant-numeric: tabular-nums;
}

.entry__title {
  color: var(--ink);
  font-weight: 500;
  line-height: 1.4;
  text-decoration-color: var(--rule-strong);
}

.entry__title:hover {
  color: var(--link);
  text-decoration-color: currentColor;
}

.entry__detail {
  margin: 2px 0 0;
  color: var(--ink-soft);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* The bio */

.sheet__about {
  padding: clamp(24px, 4vw, 44px);
}

.sheet__about-text {
  max-width: var(--measure);
  margin: 0 auto;
}

.sheet__about-text > :first-child {
  margin-top: 0;
}

.sheet__about-text h2 {
  margin: 2rem 0 0.5rem;
  font: 600 1.25rem/1.3 var(--font-ui);
}

.sheet__about-text ul {
  padding-left: 1.1em;
}

.sheet__about-text li + li {
  margin-top: 0.4em;
}

.sheet__about-text strong {
  font-weight: 600;
}

/* Zooming in morphs the name into the breadcrumb and the front panel into
   the sheet (home.js starts the view transition). The root opts out, so the
   network keeps running underneath while the rest fades. */

:root {
  view-transition-name: none;
}

:root:not([data-zoomed]) .hero__name,
:root[data-zoomed] .crumbs__home {
  view-transition-name: site-name;
}

:root:not([data-zoomed]) .lobe[data-front] .lobe__face--front,
:root[data-zoomed] .sheet {
  view-transition-name: panel;
}

:root:not([data-zoomed]) .hero__tagline { view-transition-name: tagline; }
:root:not([data-zoomed]) .hero__links { view-transition-name: hero-links; }
:root:not([data-zoomed]) .hero__photo { view-transition-name: hero-photo; }
:root:not([data-zoomed]) .lobes { view-transition-name: turntable; }
:root[data-zoomed] .crumbs__section { view-transition-name: crumb-section; }
:root[data-zoomed] .crumbs__item { view-transition-name: crumb-item; }

::view-transition-group(*) {
  animation-duration: 420ms;
  animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* The panel's content does not stretch into the sheet's; it fades out early. */
::view-transition-old(panel) {
  animation-duration: 160ms;
}

/* Narrow screens: two columns of compact cards without JavaScript. */

@media (max-width: 860px) {
  .lobes__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }
}

@media (max-width: 600px) {
  /* The photo sits beside the name, with the tagline and links below. */
  .hero {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name photo" "tagline tagline" "links links";
    gap: 12px 16px;
  }

  .hero__text {
    display: contents;
  }

  .hero__name { grid-area: name; }
  .hero__tagline { grid-area: tagline; margin: 0; }
  .hero__links { grid-area: links; margin: 0 0 0 -11px; }

  .hero__photo {
    grid-area: photo;
    width: 64px;
  }

  /* The theme switch moves to the foot of the screen, beside a shorter
     footer, leaving the top to the name and photo. Zoomed in, it stays
     at the top, clear of the sheet. */
  .theme-switch {
    top: auto;
    bottom: 12px;
  }

  :root[data-zoomed] .theme-switch {
    top: 16px;
    bottom: auto;
  }

  .colophon__built {
    display: none;
  }

  /* The breadcrumb drops below the theme switch. */
  .crumbs ol {
    padding: 64px 0 16px;
  }
}

@media (max-width: 520px) {
  /* One card per row: two columns are too narrow for the titles. */
  .lobes:not(.is-ring) .lobes__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .lobes:not(.is-ring) .lobe {
    min-height: 0;
    padding: 16px 16px 14px;
  }

  .lobes.is-ring {
    --lobe-w: 264px;
    --lobe-h: clamp(188px, 26vh, 212px);
    --ring-top: clamp(56px, 9vh, 80px);
    height: calc(var(--ring-top) + var(--lobe-h) + var(--radius) * 0.16 + 56px);
  }

  .page {
    padding-top: clamp(16px, 4vh, 72px);
  }

  .hero {
    margin-bottom: clamp(12px, 3vh, 56px);
  }

  .is-ring .lobe__face {
    padding: 18px 18px 16px;
  }

  .lobe__head {
    gap: 12px;
  }

  .lobe__icon {
    font-size: 1.875rem;
  }

  .lobe__title {
    font-size: 1.875rem;
  }

  .lobe__example {
    margin-top: 12px;
    padding: 8px 12px 9px;
  }

  .lobe__example-title {
    font-size: 1rem;
  }

  .lobe__example-detail {
    font-size: 0.875rem;
  }


  .entry {
    grid-template-columns: 2.75rem minmax(0, 1fr);
    column-gap: 12px;
  }
}

/* Short panels, on short windows: tighter type and spacing, and a one-line
   example, so the contents still fit. Heights are inside the padding; a
   full-size panel has 206px, a full-size phone panel 178px. */
@container lobe (max-height: 179px) and (min-width: 280px) {
  .lobe__head {
    gap: 12px;
  }

  .lobe__icon,
  .lobe__title {
    font-size: 2rem;
  }

  .lobe__example {
    margin-top: 12px;
    padding: 8px 12px 9px;
  }

  .lobe__example-detail {
    -webkit-line-clamp: 1;
    line-clamp: 1;
  }

  .lobe__example--about .lobe__example-detail {
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }
}

@container lobe (max-height: 160px) {
  .lobe__icon,
  .lobe__title {
    font-size: 1.75rem;
  }

  .lobe__example {
    margin-top: 10px;
  }

  .lobe__example-detail {
    -webkit-line-clamp: 1;
    line-clamp: 1;
  }

  .lobe__foot {
    padding-top: 10px;
  }
}

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