/* =========================================================
   site.css

   As little as there can be: one column, one size of type, ink for
   what matters and grey for the rest. The only pictures are the ones
   that come up beside a row as you point at it (peek.js), each page's
   Monet among them. Geist Serif for everything.
   Light only, in Claude's palette: ivory paper, warm near-black ink,
   warm greys, and each page's painting's colour for what you point at.
   ========================================================= */

/* ---------------------------------------------------------
   1. Tokens
   Geist Serif throughout, Vercel's open serif from the geist package
   on jsDelivr (it isn't on Google Fonts), preloaded in each page's
   head. It comes in one face, so nothing here asks it for a bolder
   weight or an italic it would have to fake.
   --------------------------------------------------------- */

@font-face {
  font-family: "Geist Serif";
  src: url("https://cdn.jsdelivr.net/npm/geist@1.9.0/dist/fonts/geist-serif/GeistSerifVF.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --color-bg: #f5f4ed;
  --color-bg-alt: #ebe9df;
  --color-fg: #141413;
  --color-muted: #6f6d66;
  --color-quiet: #8d8a81;
  --color-faint: #a3a198;
  --color-border: #e0ddd0;
  --color-border-hover: #cdc9ba;
  /* no colour of its own: what you point at goes to ink, and a row
     you point at takes a wash of warm grey */
  --color-accent: var(--color-fg);
  --color-wash: #ecebe3;
  --color-underline: #cdc9ba;
  --color-mat: #ffffff;
  --color-scrim: rgba(245, 244, 237, 0.82);
  --shadow-lift: 0 1px 2px rgba(20, 20, 19, 0.06), 0 24px 48px -24px rgba(20, 20, 19, 0.3);
  --shadow-card:
    0 0 0 0.5px rgba(20, 20, 19, 0.06),
    0 1px 2px rgba(20, 20, 19, 0.06),
    0 18px 40px -18px rgba(20, 20, 19, 0.36);

  --font-display: "Geist Serif", "Iowan Old Style", Georgia, serif;
  --font-sans: "Geist Serif", "Iowan Old Style", Georgia, serif;

  --size: 1rem;
  --sheet: 36rem;
  --col: 10.5rem;
  --row-pad: 0.75rem;
  --gap: 5rem;
  --peek-w: clamp(11rem, 15vw, 14.5rem);
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='%23000' stroke-width='1.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 8 8 2M3.2 2H8v4.8'/%3E%3C/svg%3E");

  --measure: 36rem;
  --pad-x: clamp(1.25rem, 5vw, 5rem);
  --pad-y: clamp(2.5rem, 10vh, 7rem);

  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 2.25rem;
  --space-lg: 3.5rem;
  --space-xl: 5.5rem;

  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --transition-fast: 0.15s ease;
  --transition-base: 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  color-scheme: light dark;
}

/* Dark: the same page at night. A warm near-black for the paper and
   a warm near-white for the ink, the greys stepped the same way, so
   everything keeps its place in the order of what to read first. It
   follows the system unless Light or Dark is picked in the footer
   (theme.js, which sets data-theme on <html>). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-bg: #1c1b19;
    --color-bg-alt: #262522;
    --color-fg: #f1efe7;
    --color-muted: #a5a299;
    --color-quiet: #827f77;
    --color-faint: #5f5d57;
    --color-border: #302f2b;
    --color-border-hover: #403e39;
    --color-wash: #272623;
    --color-underline: #4a4843;
    --color-mat: #2a2926;
    --color-scrim: rgba(28, 27, 25, 0.86);
    --shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.3), 0 24px 48px -24px rgba(0, 0, 0, 0.6);
    --shadow-card:
      0 0 0 0.5px rgba(241, 239, 231, 0.08),
      0 1px 2px rgba(0, 0, 0, 0.3),
      0 18px 40px -18px rgba(0, 0, 0, 0.7);
  }
}

:root[data-theme="dark"] {
  --color-bg: #1c1b19;
  --color-bg-alt: #262522;
  --color-fg: #f1efe7;
  --color-muted: #a5a299;
  --color-quiet: #827f77;
  --color-faint: #5f5d57;
  --color-border: #302f2b;
  --color-border-hover: #403e39;
  --color-wash: #272623;
  --color-underline: #4a4843;
  --color-mat: #2a2926;
  --color-scrim: rgba(28, 27, 25, 0.86);
  --shadow-lift: 0 1px 2px rgba(0, 0, 0, 0.3), 0 24px 48px -24px rgba(0, 0, 0, 0.6);
  --shadow-card:
    0 0 0 0.5px rgba(241, 239, 231, 0.08),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 18px 40px -18px rgba(0, 0, 0, 0.7);
  color-scheme: dark;
}

:root[data-theme="light"] {
  color-scheme: light;
}

/* The names music.css and site.js were written against */
:root {
  --bg: var(--color-bg);
  --fg: var(--color-fg);
  --fg-2: var(--color-fg);
  --gray: var(--color-muted);
  --faint: var(--color-faint);
  --line: var(--color-border);
  --hover: var(--color-bg-alt);
  --print: var(--color-mat);
  --shadow: var(--shadow-lift);

  --serif: var(--font-display);
  --sans: var(--font-sans);
  --mono: var(--font-sans);

  --small: 0.875rem;
  --text: 1.03rem;
  --heading: 1.5rem;
  --name: 2rem;
  --display: 2.75rem;

  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s6: 1.5rem;
  --s8: 2rem;
  --s12: 3rem;
  --s16: 4rem;

  --pad: 0.625rem;
  --fast: var(--transition-fast);
}

/* ---------------------------------------------------------
   2. Base
   --------------------------------------------------------- */

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

/* Solid ink, with the paper's colour for the text */
::selection {
  background: var(--color-fg);
  color: var(--color-bg);
}

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

/* One size of type for everything. What matters is in ink, the rest
   in grey. */
body {
  font-family: var(--font-sans);
  font-size: var(--size);
  font-weight: 400;
  line-height: 1.55;
  font-kerning: normal;
  font-variant-ligatures: common-ligatures;
  font-variant-numeric: oldstyle-nums proportional-nums;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  hanging-punctuation: first;
  -webkit-font-smoothing: antialiased;
  color: var(--color-fg);
  background: var(--color-bg);
}

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

ul, ol {
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

h1, h2, h3, h4, h5, h6 {
  font-size: inherit;
  font-weight: 400;
  line-height: inherit;
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

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

[hidden] {
  display: none !important;
}

.nowrap {
  white-space: nowrap;
}

.skip {
  position: absolute;
  left: 1rem;
  top: -3rem;
  z-index: 60;
  padding: 0.3rem 0.8rem;
  background: var(--color-fg);
  color: var(--color-bg);
}

.skip:focus {
  top: 0.75rem;
}

/* The one link style: in ink among the grey, always underlined so a
   link reads as one at a glance; the line is a soft tint of the ink
   and darkens to the ink itself when you point at it */
.page p a,
.about__text a,
.contact__text a,
.contact__address,
.project-item__link,
.project-item__title a,
.photos__links a {
  color: var(--color-fg);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  text-underline-offset: 0.2em;
  transition: color var(--transition-fast), text-decoration-color var(--transition-fast);
}

.page p a:hover,
.about__text a:hover,
.contact__text a:hover,
.contact__address:hover,
.project-item__link:hover,
.project-item__title a:hover,
.photos__links a:hover {
  text-decoration-color: currentColor;
}

/* Links that leave the site carry a small arrow, drawn rather than
   set, so it is the same everywhere; a link to a page of its own on
   the site (a paper's page) can ask for one with --arrow */
.project-item__title a[target="_blank"]::after,
.project-item__link[target="_blank"]::after,
.project-item__link--arrow::after,
a.index__row[target="_blank"] .index__note::after,
.reach__row[target="_blank"] .reach__name::after,
.photos__links a::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.5em;
  margin-left: 0.28em;
  vertical-align: 0.12em;
  background-color: var(--color-quiet);
  -webkit-mask: var(--arrow) center / contain no-repeat;
  mask: var(--arrow) center / contain no-repeat;
  transition: background-color var(--transition-fast), transform var(--transition-fast);
}

.project-item__title a[target="_blank"]:hover::after,
.project-item__link[target="_blank"]:hover::after,
.project-item__link--arrow:hover::after,
a.index__row[target="_blank"]:hover .index__note::after,
.reach__row[target="_blank"]:hover .reach__name::after,
.photos__links a:hover::after {
  background-color: currentColor;
  transform: translate(0.08em, -0.08em);
}

/* ---------------------------------------------------------
   3. The sheet: one narrow column down the middle
   --------------------------------------------------------- */

.sheet {
  display: flex;
  justify-content: center;
  min-height: 100svh;
  padding: var(--pad-y) var(--pad-x) 2.25rem;
}

.sheet__page {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--sheet);
  min-width: 0;
}

/* ---------------------------------------------------------
   4. Masthead
   --------------------------------------------------------- */

.masthead {
  display: flex;
  flex-direction: column;
}

.masthead__name {
  align-self: flex-start;
  color: var(--color-fg);
  transition: color var(--transition-fast);
}

.masthead__role {
  color: var(--color-quiet);
}

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

/* One line where it fits; where it has to wrap, balance evens the
   rows out rather than leaving one link on its own */
.masthead__nav {
  text-wrap: balance;
}

/* the space between the links in the markup counts too */
.masthead__nav-link {
  display: inline-block;
  margin-right: 0.45rem;
  color: var(--color-quiet);
  transition: color var(--transition-fast);
}

.masthead__nav-link:last-child {
  margin-right: 0;
}

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

/* the page you're on, in ink */
.masthead__nav-link.active {
  color: var(--color-fg);
}

.kbar-open {
  padding: 0;
  line-height: inherit;
  text-align: left;
  white-space: nowrap;
}

.kbar-open kbd {
  margin-left: 0.35em;
  font-family: var(--font-sans);
  font-size: 0.85em;
  color: var(--color-faint);
}

@media (hover: none) {
  .kbar-open kbd {
    display: none;
  }
}

/* ---------------------------------------------------------
   5. The page
   --------------------------------------------------------- */

.page {
  flex: 1;
  padding: var(--gap) 0 calc(var(--gap) * 1.25);
}

/* The nav already says, in ink, which page this is */
.page-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.section-label,
.writing__heading {
  display: block;
  color: var(--color-muted);
}

.section-label {
  margin: var(--gap) 0 0.6rem;
}

.section-label:first-child {
  margin-top: 0;
}

/* The line a page opens with */
.music__lede {
  margin-bottom: calc(var(--gap) * 0.6);
  color: var(--color-muted);
}

.music__empty {
  color: var(--color-muted);
}

/* ---------------------------------------------------------
   6. Rows
   The home page's index and every page's entries: a name in ink on
   the left, a line or two in grey beside it. The row you point at
   takes a wash of the page's colour, at once and gone at once, and
   peek.js brings up its picture beside the cursor.
   --------------------------------------------------------- */

.index,
.projects__list,
.reach {
  display: flex;
  flex-direction: column;
  margin: 0 calc(var(--row-pad) * -1);
}

.index__row,
.project-item,
.reach__row {
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  column-gap: 1.5rem;
  width: 100%;
  padding: 0.3rem var(--row-pad);
  border-radius: 6px;
  text-align: left;
  color: var(--color-muted);
  -webkit-tap-highlight-color: transparent;
}

.index__name,
.reach__name,
.project-item__title {
  color: var(--color-fg);
}

.index__note kbd {
  margin-left: 0.4em;
  font-family: var(--font-sans);
  font-size: 0.85em;
  color: var(--color-faint);
}

.reach__handle {
  overflow-wrap: anywhere;
}

@media (hover: hover) and (pointer: fine) {
  .index__row:hover,
  .index__row.is-on,
  .project-item:hover,
  .project-item.is-on,
  .reach__row:hover {
    background: var(--color-wash);
  }
}

/* entries: the name and its role on the left, the rest beside them */
.projects__list {
  gap: 0.15rem;
}

.project-item {
  padding-top: 0.6rem;
  padding-bottom: 0.65rem;
}

.project-item__role {
  color: var(--color-quiet);
}

/* the name on the left; its role, in a quieter grey, heads what is
   said about it on the right */
.project-item > *,
.project-item__role {
  grid-column: 2;
}

.project-item__header {
  display: contents;
}

.project-item__title {
  grid-column: 1;
  grid-row: 1 / span 12;
}

.project-item__description + .project-item__description {
  margin-top: 0.4rem;
}

/* the sentence a long entry opens with (Research), in ink: what the
   paper is, for anyone who reads no further */
.project-item__lead {
  color: var(--color-fg);
}

.project-item__link {
  justify-self: start;
  margin-top: 0.15rem;
}

.project-item__links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.9rem;
  margin-top: 0.15rem;
}

.project-item__links .project-item__link {
  margin-top: 0;
}

.project-item__link--disabled {
  cursor: default;
  opacity: 0.55;
  pointer-events: none;
}

/* An entry's facts (Education), set across the whole entry: each
   label under the entry's name, in the quieter grey, and what it says
   under the line beside the name. Lists one to a line, so each course
   or role reads on its own. */
.facts {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  gap: 0.55rem 1.5rem;
  margin-top: 0.8rem;
}

.facts dt {
  color: var(--color-quiet);
}

.facts dd {
  min-width: 0;
  color: var(--color-muted);
}

/* A long list (Oakton's coursework) shows its first lines and keeps
   the rest folded under a line of quieter text, like Show all on the
   music page. A <details>, so it opens with no script and from the
   keyboard. Open, the line moves to the foot of the list (it is the
   first thing in a <details>, so it is placed there) and reads Show
   fewer. */
.facts__more > summary {
  position: relative;
  display: block;
  width: fit-content;
  margin-top: 0.3rem;
  color: var(--color-quiet);
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--transition-fast);
}

.facts__more > summary::-webkit-details-marker {
  display: none;
}

/* room round the words for a finger */
.facts__more > summary::after {
  content: "";
  position: absolute;
  inset: -0.5rem -0.75rem;
}

@media (hover: hover) {
  .facts__more > summary:hover {
    color: var(--color-fg);
  }
}

.facts__more[open] {
  position: relative;
  padding-bottom: 1.75em;
  padding-bottom: calc(1lh + 0.3rem);
}

.facts__more[open] > summary {
  position: absolute;
  left: 0;
  bottom: 0;
}

.facts__more:not([open]) .facts__fewer,
.facts__more[open] .facts__all {
  display: none;
}

/* ---------------------------------------------------------
   7. Home
   --------------------------------------------------------- */

.page--home {
  --col: 7.5rem;
  padding-top: calc(var(--gap) * 0.8);
}

/* prose: the column's width, about seventy-five characters to the
   line, so the text fills the column it's centred in; and more air
   between lines than the lists have */
.about__text,
.contact__text,
.music__lede {
  line-height: 1.65;
}

.about__text {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  color: var(--color-muted);
}

.page--home .index {
  margin-top: calc(var(--gap) * 0.8);
}

.page--home .index + .index {
  margin-top: calc(var(--gap) * 0.5);
}

.index__by::before {
  content: "\00a0\00b7\00a0";
}

.index__by:empty::before {
  content: none;
}

/* ---------------------------------------------------------
   8. Photographs
   --------------------------------------------------------- */

.photos__grid {
  columns: 3;
  column-gap: 0.35rem;
}

.photo-item {
  break-inside: avoid;
  margin-bottom: 0.35rem;
  cursor: zoom-in;
  overflow: hidden;
  background: var(--color-bg-alt);
}

.photo-item img {
  display: block;
  width: 100%;
  height: auto;
}

.photo-item img:focus {
  outline: none;
}

.photo-item img:focus-visible {
  outline: 1.5px solid var(--color-accent);
  outline-offset: -2px;
}

.photos__links {
  display: flex;
  gap: 1.25rem;
  margin-top: 2rem;
}

/* Full-screen viewer */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: var(--color-scrim);
  animation: fade var(--transition-base);
}

.lightbox[hidden] {
  display: none;
}

@keyframes fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.lightbox__img {
  display: block;
  max-width: min(72rem, 100%);
  max-height: 88vh;
  box-shadow: var(--shadow-lift);
}

.lightbox__close {
  position: absolute;
  top: 1.1rem;
  right: 1.5rem;
  color: var(--color-muted);
  transition: color var(--transition-fast);
}

.lightbox__close:hover {
  color: var(--color-fg);
}

/* ---------------------------------------------------------
   9. Contact and resume
   --------------------------------------------------------- */

.contact__text {
  margin-bottom: 1.25rem;
  color: var(--color-muted);
}

.contact__text em {
  font-style: normal;
}

.contact__mail {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 1rem;
  margin-bottom: var(--gap);
}

.contact__copy {
  color: var(--color-quiet);
  transition: color var(--transition-fast);
}

.contact__copy:hover,
.contact__copy.is-done {
  color: var(--color-accent);
}

.contact__elsewhere .writing__heading {
  margin-bottom: 0.3rem;
  color: var(--color-quiet);
}

.rows__hl {
  display: none;
}

.resume__frame {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
  box-shadow: var(--shadow-lift);
}

/* the sheet is a link to the PDF */
.resume__sheet {
  display: block;
}

/* clear of the sheet and the shadow under it */
.resume__download {
  display: inline-block;
  margin-top: 1.75rem;
}

/* ---------------------------------------------------------
   10. Footer
   --------------------------------------------------------- */

.colophon__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
}

.colophon__inner .social {
  margin-left: auto;
}

/* Light, Dark, System: three words in the footer's grey, the one in
   use in ink. Only where the script is there to make them work. */
.theme-toggle {
  display: inline-flex;
  gap: 0.75rem;
}

html:not(.js) .theme-toggle {
  display: none;
}

.theme-toggle__option {
  padding: 0;
  color: var(--color-quiet);
  transition: color var(--transition-fast);
}

.theme-toggle__option:hover,
.theme-toggle__option[aria-pressed="true"] {
  color: var(--color-fg);
}

.colophon__meta {
  color: var(--color-quiet);
}

.colophon__meta a {
  transition: color var(--transition-fast);
}

.colophon__meta a:hover {
  color: var(--color-fg);
}

/* The ways to reach me: small, in the nav's grey, set in the column
   like a line of text. On the home page under the line about me; on
   the others, in the footer. Each glyph's own edge lines up with the
   text, the round it lights up in reaching past it. */
.social {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin: 0 -0.5rem;
}

.masthead .social {
  align-self: flex-start;
  margin-top: 0.55rem;
}

.social a {
  display: grid;
  place-items: center;
  width: 1.85rem;
  height: 1.85rem;
  border-radius: 999px;
  color: var(--color-quiet);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.social a:hover {
  color: var(--color-fg);
  background: var(--color-wash);
}

.social svg {
  width: 0.85rem;
  height: 0.85rem;
  fill: currentColor;
}

/* ---------------------------------------------------------
   11. Music and fragrance rows
   --------------------------------------------------------- */

.label {
  font-family: var(--font-display);
  font-size: inherit;
  font-weight: 400;
  line-height: inherit;
  color: var(--color-fg);
}

.music .sub {
  color: var(--color-muted);
}

.music p {
  text-wrap: pretty;
}

.plays {
  list-style: none;
}

.play {
  display: grid;
  grid-template-columns: 1.75rem 2.5rem minmax(0, 1fr) auto;
  column-gap: 0.85rem;
  align-items: center;
  padding: 0.4rem 0;
}

.plays--log .play {
  grid-template-columns: 4.5rem 2.5rem minmax(0, 1fr);
}

.play__n,
.play__count {
  color: var(--color-faint);
  font-variant-numeric: tabular-nums;
}

.play--now .play__n {
  color: var(--color-accent);
}

.play__count {
  text-align: right;
  white-space: nowrap;
}

.play__art {
  width: 2.5rem;
  height: 2.5rem;
  object-fit: cover;
  background: var(--color-bg-alt);
}

.plays--artists .play__art {
  border-radius: 50%;
}

.play__name {
  display: block;
  overflow-wrap: anywhere;
  transition: color var(--transition-fast);
}

.play__by {
  display: block;
  color: var(--color-muted);
}

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

.scent {
  list-style: none;
}

.scent .play {
  grid-template-columns: minmax(0, 1fr) auto;
  margin: 0 calc(var(--row-pad) * -1);
  padding: 0.45rem var(--row-pad);
  border-radius: 8px;
  cursor: pointer;
  list-style: none;
}

.scent .play__text {
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  column-gap: 1.5rem;
}

.scent .play::-webkit-details-marker {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .scent .play:hover {
    background: var(--color-wash);
  }
}

.scent__toggle::before {
  content: "+";
  color: var(--color-faint);
}

.scent details[open] .scent__toggle::before {
  content: "\2013";
}

.scent__info {
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  gap: 0.15rem 1.5rem;
  padding: 0.2rem 0 1rem;
}

.scent__info dt {
  color: var(--color-faint);
}

.scent__info dd {
  color: var(--color-muted);
}

/* ---------------------------------------------------------
   11b. The picture beside the rows (peek.js)
   --------------------------------------------------------- */

.peek {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 40;
  width: var(--peek-w);
  aspect-ratio: 4 / 3;
  border-radius: 6px;
  overflow: hidden;
  background: var(--color-bg-alt);
  box-shadow: var(--shadow-card);
  opacity: 0;
  transition: opacity 0.16s ease;
  pointer-events: none;
  will-change: transform, opacity;
  backface-visibility: hidden;
}

.peek.is-on {
  opacity: 1;
}

.peek__img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  will-change: transform;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

/* ---------------------------------------------------------
   12. Search
   --------------------------------------------------------- */

/* Search reads like the site, not like a window over it: the page
   fades away into the paper, and in its place, at the column's
   width and where the name would be, the line you type in and the
   results as rows, a name in ink with a line in grey, the one you're
   on taking the wash. One size of type, no frame, no icon, no key
   hints; Escape or a click outside closes it. */
.kbar {
  position: fixed;
  inset: 0;
  width: min(calc(var(--sheet) + var(--row-pad) * 2), calc(100% - var(--pad-x) * 2 + var(--row-pad) * 2));
  max-height: calc(100svh - var(--pad-y) * 2);
  margin: var(--pad-y) auto auto;
  padding: 0;
  overflow: hidden;
  border: 0;
  background: var(--color-bg);
  color: var(--color-fg);
  font: inherit;
}

.kbar[open] {
  display: flex;
  flex-direction: column;
  animation: kbar-in 0.2s var(--ease);
}

@keyframes kbar-in {
  from { opacity: 0; transform: translateY(0.4rem); }
  to { opacity: 1; transform: none; }
}

.kbar::backdrop {
  background: var(--color-bg);
  animation: fade 0.2s var(--ease);
}

.kbar__field {
  flex: none;
  padding: 0.3rem var(--row-pad) 1.1rem;
}

.kbar__icon {
  display: none;
}

.kbar__input {
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-fg);
  font: inherit;
  font-weight: 500;
  outline: none;
}

.kbar__input::placeholder {
  color: var(--color-quiet);
  font-weight: 400;
}

.kbar__list {
  flex: 1;
  overflow-y: auto;
  padding-bottom: 1rem;
  overscroll-behavior: contain;
}

.kbar__group {
  padding: 1rem var(--row-pad) 0.3rem;
  color: var(--color-quiet);
}

.kbar__group:first-child {
  padding-top: 0;
}

.kbar__item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.4rem var(--row-pad);
  border-radius: 6px;
  cursor: pointer;
}

.kbar__item[aria-selected="true"] {
  background: var(--color-wash);
}

.kbar__thumb {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  object-fit: cover;
  border-radius: 4px;
  background: var(--color-bg-alt);
}

.kbar__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.kbar__title,
.kbar__snip {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.kbar__title {
  color: var(--color-fg);
}

.kbar__snip {
  color: var(--color-muted);
}

/* what matched: underlined, the rest of the line left alone */
.kbar mark {
  background: none;
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--color-underline);
  text-underline-offset: 0.2em;
}

.kbar__kind {
  flex: none;
  color: var(--color-quiet);
}

.kbar__empty {
  padding: 0 var(--row-pad);
  color: var(--color-muted);
}

.kbar__foot {
  display: none;
}

/* An entry arrived at from search or a link: marked for a moment */
.is-target {
  animation: target 2s ease;
}

@keyframes target {
  0%, 30% { background: var(--color-bg-alt); box-shadow: 0 0 0 0.6rem var(--color-bg-alt); }
  100% { background: transparent; box-shadow: 0 0 0 0.6rem transparent; }
}

/* ---------------------------------------------------------
   13. Narrower screens
   --------------------------------------------------------- */

@media (max-width: 40em) {
  :root {
    --col: 6.5rem;
    --gap: 3.25rem;
    --pad-x: 1.5rem;
  }

  .social a {
    width: 2.3rem;
    height: 2.3rem;
  }

  .social {
    margin: 0 -0.72rem;
  }

  .masthead .social {
    margin-top: 0.4rem;
  }

  .photos__grid {
    columns: 2;
  }

  .project-item,
  .scent .play__text,
  .scent__info {
    grid-template-columns: minmax(0, 1fr);
  }

  .project-item > *,
  .project-item__role,
  .project-item__title {
    grid-column: 1;
    grid-row: auto;
  }

  .facts {
    grid-template-columns: 5.5rem minmax(0, 1fr);
    column-gap: 1rem;
  }

  /* On a phone the sheet's words are too small to read, so the way to
     the PDF comes before it rather than after */
  .page--resume {
    display: flex;
    flex-direction: column;
  }

  .resume__download {
    order: -1;
    align-self: flex-start;
    margin: 0 0 1.25rem;
  }

  .scent__info dt {
    margin-top: 0.35rem;
  }
}

/* On a touch screen each entry keeps a place at its top right for its
   picture, which keeps to the entry at the reading line. The words run
   round the place, as round a picture set into a column. */
@media (hover: none) {
  :root {
    --peek-w: clamp(5.75rem, 25vw, 8.5rem);
  }

  .index__row,
  .project-item {
    display: flow-root;
    padding-top: 0.55rem;
    padding-bottom: 0.6rem;
  }

  /* The home page's rows are a line or two, shorter than any picture.
     A place for the picture inside each one held the rows with pictures
     far apart and left the ones without close together, so its lists
     keep a margin down their right instead, the same for every row,
     and the picture sits in that, level with its row (peek.js). The
     rows are then as far apart as their words make them. */
  .index__row {
    padding: 0.65rem calc(var(--row-pad) + var(--peek-w) + 1rem) 0.7rem var(--row-pad);
  }

  .project-item::before {
    content: "";
    float: right;
    width: var(--peek-w);
    height: calc(var(--peek-w) * 0.75);
    margin: 0.2rem 0 0.35rem 1rem;
  }

  .project-item[data-img="none"]::before {
    content: none;
  }

  .index__name,
  .index__note,
  .project-item__title,
  .project-item__role {
    display: block;
  }

  .project-item__header {
    display: block;
    margin-bottom: 0.2rem;
  }

  /* the facts start under the picture's place, at the column's width */
  .facts {
    clear: both;
  }

  .project-item__link {
    display: inline-block;
  }
}

/* On a tablet the column is wide enough for the entries to keep that
   margin as well. A short entry was held open by its picture's place,
   and so stood further from the next than the others; and the words
   now share one right edge rather than stepping in round a place that
   is empty for every entry but one. */
@media (hover: none) and (min-width: 64em) {
  .project-item {
    padding-right: calc(var(--row-pad) + var(--peek-w) + 1.5rem);
  }

  .project-item::before {
    content: none;
  }
}

/* ---------------------------------------------------------
   14. The opening (intro.js, home page only)
   Held back until it plays; then each letter of the name is a
   cut-out of the painting until it settles, when the painting in it
   gives way to ink.
   --------------------------------------------------------- */

html.intro .masthead__name,
html.intro .masthead__role,
html.intro .masthead .social,
html.intro .page > *,
html.intro .colophon {
  opacity: 0;
}

.intro__word {
  white-space: nowrap;
}

/* Each letter's box holds room round its glyph (taken back by the
   negative margin, so the name sets exactly as plain text): the
   painting only fills a letter's own box, and a serif's letters
   reach past theirs. */
.intro__ch {
  display: inline-block;
  box-sizing: content-box;
  padding: 0.14em 0.16em;
  margin: -0.14em -0.16em;
  text-align: center;
  white-space: pre;
  color: transparent;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  opacity: 0;
  transform: translateY(0.16em);
  filter: blur(0.14em) saturate(1.45) contrast(1.12);
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    filter 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    color 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.intro__ch.is-on {
  opacity: 1;
  transform: none;
  filter: blur(0) saturate(1.45) contrast(1.12);
}

/* settled: the painting gives way to ink */
.intro__ch.is-set {
  color: var(--color-fg);
  filter: none;
}

/* ---------------------------------------------------------
   15. Motion
   --------------------------------------------------------- */

/* No transitions at all, rather than very short ones: a transition of
   any length, on every property of every element, holds a change made
   from script back for a frame, so a script that sets a size and then
   measures (the specimen's name fitted to the page) measured the size
   it had before. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
  }
}

/* Going from page to page. The head of the page holds its place, the
   name not moving at all, while what's under it changes in place; the
   page itself goes up and away quickly, and the new one rises into its
   place and settles. Where a browser can't carry a page across like
   this, the new page still rises in as it opens (.arrive, set in the
   head). */
@view-transition {
  navigation: auto;
}

.masthead {
  view-transition-name: masthead;
}

.page {
  view-transition-name: page;
}

.colophon {
  view-transition-name: colophon;
}

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

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.2s;
}

::view-transition-old(page) {
  animation: page-out 0.2s cubic-bezier(0.4, 0, 1, 1) both;
}

::view-transition-new(page) {
  animation: page-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.08s both;
}

::view-transition-old(colophon) {
  animation: page-out 0.2s cubic-bezier(0.4, 0, 1, 1) both;
}

::view-transition-new(colophon) {
  animation: page-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.16s both;
}

@keyframes page-out {
  to { opacity: 0; transform: translateY(-0.5rem); }
}

@keyframes page-in {
  from { opacity: 0; transform: translateY(1rem); }
}

.arrive .page {
  animation: page-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.arrive .colophon {
  animation: page-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) 0.08s both;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ---------------------------------------------------------
   16. Koi (koi.js, home page only)
   On a wide window the whole window is their pond, drawn behind
   everything (the paper is painted first, then the koi, then the
   words); on a narrow one, a pond at the foot of the page, above the
   copyright. Never in the way of a pointer, and held back with the
   rest of the page until the opening has played.
   --------------------------------------------------------- */

.koi {
  pointer-events: none;
  transition: opacity 1.4s ease;
}

.koi--side {
  z-index: -1;
}

.koi--pond {
  height: 15rem;
  margin-bottom: 1.25rem;
}

html.intro .koi,
html.intro-play .koi {
  opacity: 0;
}
