/* ===================================================================
   Nicholas Niemen — portfolio site
   Shared stylesheet for index.html / projects.html / about.html
=================================================================== */

@font-face {
  font-family: 'Maxeville Test';
  src: url('fonts/SuisseIntl-Medium.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Suisse';
  src: url('fonts/SuisseIntl-Bold.otf') format('opentype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --navy: #332A22;
  /* grid lines switched off: was "1px solid var(--navy)". Every border in
     this file uses --line, so putting that back brings them all back. */
  --line: 0 solid transparent;
  --header-h: 30px;
  --font-main: 'Maxeville Test', -apple-system, BlinkMacSystemFont, sans-serif;
  --cursor-arrow: url("/cursor/cursor.png") 0 0, auto;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  color: var(--navy);
  background: #ffffff;
  font-family: var(--font-main);
  font-weight: 700;
  -webkit-font-smoothing: antialiased;
  cursor: var(--cursor-arrow);
}

a, .cell.filled {
  cursor: var(--cursor-arrow);
}

/* Fades in the page's main content only — the header is a sibling of
   main on every page (not a descendant), so it's excluded and stays
   fully visible immediately rather than fading in with the rest. */
main {
  opacity: 0;
  animation: page-fade-in 1.2s ease forwards;
}

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

@media (prefers-reduced-motion: reduce) {
  main {
    animation: none;
    opacity: 1;
  }
}

/* ---------- Projects page (simple list) ---------- */

/* Big list of project titles, newest first. Hovering (or focusing) one
   highlights it in green and shows its photo, 2x2 squares in size,
   top right (see projects.js, which sets the photo's size). */
.project-list {
  list-style: none;
  margin: 0;
  /* starts a bit underneath the header */
  padding: clamp(48px, 12vw, 170px) 0 96px 0;
  position: relative;
  z-index: 1;
  line-height: 1.08;
}

/* Font size for the big titles: the project list here, and the title on
   each project's own page. */
.project-list,
.project-title {
  --display-size: clamp(1.15rem, 2.4vw, 2.2rem);
  font-size: var(--display-size);
}

/* 4+ squares across: the photo only takes up the right-hand half or
   less, so the titles can be a bit bigger without running into it. */
@media (min-width: 1100px) {
  .project-list,
  .project-title {
    --display-size: clamp(1.6rem, 2.9vw, 2.4rem);
  }
}

/* 2 squares across, photo is 1 square (the right-hand half): the
   longest title has to stay inside the left half. */
@media (min-width: 701px) and (max-width: 799px) {
  .project-list,
  .project-title {
    --display-size: clamp(1rem, 3.6vw, 1.8rem);
  }
}

/* Phones: no hover photo (there's no hover on a touch screen anyway),
   so the titles can use the full width and be bigger. */
@media (max-width: 700px) {
  .project-preview {
    display: none;
  }
  .project-list,
  .project-title {
    --display-size: clamp(1.4rem, 6.7vw, 2rem);
  }
}

/* The green highlight box is one line-height tall; the margin below is
   the extra space between titles. */
.project-list li {
  margin: 0 0 0.37em 0;
}

.project-list a {
  display: block;
  width: fit-content;
  /* 12px on the left lines the titles up with "Projects" in the header
     (the highlight box still starts at the page edge). */
  padding: 0 0.27em 0 12px;
  color: var(--navy);
  text-decoration: none;
}

.project-list a:hover,
.project-list a:focus-visible {
  background: #06FF00;
  outline: none;
}

/* A square on the right-hand side, directly under the header. It's as
   big as fits without running into the titles, up to the full height of
   the screen (projects.js sets the size). Sits behind the list and
   ignores the mouse, so a long title that runs under it can't make it
   flicker. */
.project-preview {
  position: fixed;
  top: var(--header-h);
  right: 0;
  z-index: 0;
  pointer-events: none;
}

.project-preview-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the lines on the photo's left edge and underneath it, like on the
     About page — part of the photo, so they only show while it does */
  border-left: var(--line);
  border-bottom: var(--line);
  opacity: 0;
  transition: opacity 0.2s ease;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

.project-preview-image.is-visible {
  opacity: 1;
}

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

.project-year {
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 0.5em;
  margin-left: 6px;
  vertical-align: text-top;
  opacity: 0.85;
}

a { color: inherit; }

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

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-h);
  z-index: 100;
  background: #ffffff;
  border-bottom: var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px;
}

.site-header .brand {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 10pt;
  text-decoration: none;
  transition: opacity 0.2s ease;
  white-space: nowrap;
}

.site-header nav a {
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 10pt;
  text-decoration: none;
  transition: opacity 0.2s ease;
  padding: 0;
}

.site-header nav a:hover,
.site-header .brand:hover {
  opacity: 0.6;
}

.site-header nav a:focus-visible,
.site-header .brand:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 3px;
}


main {
  margin-top: var(--header-h);
  min-height: calc(100vh - var(--header-h));
}

/* ---------- The square grid ---------- */

.grid {
  display: grid;
  width: 100%;
  border-left: var(--line);
  /* How far each photo sits inside its square (the cells use this
     too). Change it to make the photos smaller (bigger number) or
     larger (smaller number). */
  --photo-inset: 9%;
  /* How far down the grid starts, measured from the header. Bigger
     number = the photos start lower; 0 = right under the header. */
  --grid-offset: 60px;
  margin-top: var(--grid-offset);
}

.cell {
  position: relative;
  aspect-ratio: 1 / 1;
  border-right: var(--line);
  border-bottom: var(--line);
  overflow: hidden;
}

.cell.filled {
  display: block;
  text-decoration: none;
}

.cell.filled:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: -4px;
}

/* The photo sits a little inside its square instead of filling it, so
   neighbouring photos don't touch at the corners. It's placed with an
   inset from each edge (no padding), so the photo is never cropped
   differently — it's just a smaller square. Change --photo-inset to
   make the photos smaller (bigger number) or larger (smaller number). */

.cell.filled img {
  position: absolute;
  inset: var(--photo-inset);
  width: calc(100% - 2 * var(--photo-inset));
  height: calc(100% - 2 * var(--photo-inset));
  object-fit: cover;
  display: block;
  cursor: var(--cursor-arrow);
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

/* Placeholder swatch shown until a real photo is dropped in.
   Swap this for an <img> once you have real project photography —
   see the PROJECTS array at the top of grid.js */
.cell .thumb-fallback {
  position: absolute;
  inset: var(--photo-inset, 0);
  width: auto;
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 10%;
  font-family: var(--font-main);
  font-weight: 700;
  font-size: clamp(0.65rem, 1.1vw, 0.95rem);
  color: rgba(255, 255, 255, 0.92);
  letter-spacing: 0.01em;
  line-height: 1.3;
}

/* Hover: a photo that links to a project fades to 60%. The extra photos
   that aren't tied to a project are plain divs (not links), so they
   stay exactly as they are. Change the 0.6 to make the photo lighter
   or darker on hover. */
a.cell.filled img,
a.cell.filled .thumb-fallback {
  transition: opacity 0.2s ease;
}

a.cell.filled:hover img,
a.cell.filled:focus-visible img,
a.cell.filled:hover .thumb-fallback,
a.cell.filled:focus-visible .thumb-fallback {
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  a.cell.filled img,
  a.cell.filled .thumb-fallback {
    transition: none;
  }
  .site-header nav a,
  .site-header .brand {
    transition: none;
  }
}

/* ---------- Individual project page ---------- */

/* Same idea as the Projects page: text on the left, and a square photo
   pinned to the right, under the header. If the project has more than
   one photo they're stacked in a column inside that square, and you
   scroll through them (see project.js) — only the photos scroll, the
   text stays where it is. project.js sets --image-size: as tall as the
   screen, as long as the text keeps some room. */
.project-page {
  position: relative;
}

.project-image {
  position: fixed;
  top: var(--header-h);
  right: 0;
  z-index: 0;
  width: var(--image-size, 50vw);
  height: var(--image-size, 50vw);
  margin: 0;
  padding: 0;
  /* the lines on the photo's left edge and underneath it, like on the
     About page */
  border-left: var(--line);
  border-bottom: var(--line);
  overflow: hidden;
  cursor: var(--cursor-arrow);
}

/* The scrolling column of photos. Each photo is exactly as big as the
   square, and scrolling settles on one photo at a time. The scrollbar
   is hidden to keep the page clean. */
.project-gallery {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  /* when you reach the last photo, the page behind doesn't start to
     scroll */
  overscroll-behavior: contain;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.project-gallery::-webkit-scrollbar {
  display: none;
}

.project-gallery:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: -4px;
}

/* Each photo has a square slot the size of the whole square, and the
   photo fills it. To leave some air around the photos, give
   --photo-inset (all four sides) or --photo-inset-bottom (bottom only)
   a value above 0%. */
.project-gallery {
  --photo-inset: 0%;
  --photo-inset-bottom: 0%;
}

.project-photo {
  position: relative;
  width: 100%;
  height: 100%;
  scroll-snap-align: start;
}

.project-photo img {
  position: absolute;
  inset: var(--photo-inset) var(--photo-inset) var(--photo-inset-bottom)
    var(--photo-inset);
  display: block;
  width: calc(100% - 2 * var(--photo-inset));
  height: calc(100% - var(--photo-inset) - var(--photo-inset-bottom));
  object-fit: cover;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

/* Title, short description and (if the project has any) the longer
   write-up. Starts a bit underneath the header, like the list on the
   Projects page. It's set in from the left edge of the page by the same
   amount as the text on the About page, and by that same amount from
   the image on the right, so the text box has equal space on both
   sides. */
.project-text {
  --inset: clamp(24px, 5vw, 64px);
  position: relative;
  z-index: 1;
  width: calc(100% - var(--image-size, 50vw));
  padding: clamp(48px, 12vw, 170px) var(--inset) 96px var(--inset);
}

/* On wide screens the text starts a bit higher up than the 12vw rule
   above would put it (that would be 170px on a big screen). Change the
   numbers here to move it up or down. */
@media (min-width: 1100px) {
  .project-text {
    padding-top: clamp(48px, 8vw, 120px);
  }
}

.project-title {
  /* How much bigger than the titles in the Projects list (1 = same
     size). Change this one number to make the title larger or smaller. */
  --title-scale: 1.25;
  font-size: calc(var(--display-size) * var(--title-scale));
  margin: 0 0 0.6em 0;
  font-family: var(--font-main);
  font-weight: 700;
  line-height: 1.08;
  overflow-wrap: break-word;
}

/* The short description and the longer write-up get the same text size
   and the same maximum width, so they wrap at exactly the same point.
   The short description is a step bigger (in em) inside that. */
.project-desc,
.project-more {
  font-size: clamp(0.85rem, 1vw, 0.95rem);
  /* fills the space between the two insets, up to a sensible line
     length on very wide screens */
  max-width: 46rem;
}

/* white-space: pre-line lets a literal \n inside "desc" / "details" in
   grid.js show up as a real line break, while still wrapping normally
   otherwise */
.project-desc p {
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 1.4em;
  line-height: 1.3;
  margin: 0;
  white-space: pre-line;
}

/* Longer write-up — a touch smaller and looser than the short
   description, since it's for reading rather than skimming. */
.project-more {
  margin-top: 2.5rem;
}

.project-more:empty {
  display: none;
}

/* The box itself keeps the shared size (so its maximum width matches
   the short description's); the text inside is a bit smaller. */
/* A link inside the short description or the longer write-up (from
   "[text](slug)" in grid.js — see project.js). Same hover behaviour
   as the header links: fades to 60% when hovered/focused. */
.project-link {
  color: inherit;
  text-decoration: none;
  transition: opacity 0.2s ease;
}

.project-link:hover,
.project-link:focus-visible {
  opacity: 0.6;
}

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

.project-more p {
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 0.9em;
  line-height: 1.5;
  margin: 0 0 1em 0;
  white-space: pre-line;
}

.project-more p:last-child {
  margin-bottom: 0;
}

/* Phones (700px wide or less): the photos aren't pinned any more. They
   come after all the text, full width and square, one under the other,
   and scroll with the page — so they never cover any text. */
@media (max-width: 700px) {
  .project-image {
    position: relative;
    top: auto;
    right: auto;
    display: flex;
    flex-direction: column;
    width: calc(100% + 2 * var(--inset));
    height: auto;
    /* a gap above it, under the text; the negative side margins cancel
       the text's side padding (--inset), so it runs edge to edge */
    margin: 48px calc(-1 * var(--inset)) 0 calc(-1 * var(--inset));
    border-left: 0;
    border-top: var(--line);
    border-bottom: var(--line);
    overflow: visible;
  }

  .project-gallery {
    position: static;
    overflow: visible;
    scroll-snap-type: none;
  }

  .project-photo {
    height: auto;
    aspect-ratio: 1 / 1;
  }

  /* no padding underneath: the photo goes right down to the bottom of
     the page */
  .project-text {
    /* space between the text and the left / right edge of the screen */
    --inset: 25px;
    width: auto;
    padding: clamp(48px, 12vw, 170px) var(--inset) 0 var(--inset);
  }

  .project-more {
    margin-top: 32px;
  }

  /* keep the lines a comfortable length on wider phones / tablets */
  .project-desc,
  .project-more {
    max-width: 60ch;
  }
}

/* ---------- About page ---------- */

body.about-page {
  overflow: hidden;
  height: 100vh;
}

.about-main {
  padding-top: 0;
  height: calc(100vh - var(--header-h));
  overflow: hidden;
}

.about-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  border-left: var(--line);
  height: 100%;
}

.about-text {
  border-right: var(--line);
  border-bottom: var(--line);
  padding: clamp(24px, 5vw, 64px);
}

.about-portrait {
  border-right: var(--line);
  border-bottom: var(--line);
}

.about-portrait {
  background: white;
  display: flex;
  align-items: flex-end;
}

.about-portrait {
  font-family: var(--font-main);
  font-weight: 700;
  font-size: 0.8rem;
}

.about-text {
  display: flex;
  flex-direction: column;
  gap: 20px;
  justify-content: flex-start;
  overflow-y: auto;
}

/* Vertically centres the text when there's room, but (unlike
   justify-content: center) never clips the top of it when there isn't —
   the text just scrolls instead. */
.about-text > :first-child { margin-top: auto; }
.about-text > :last-child { margin-bottom: auto; }

.about-text p {
  font-size: clamp(0.9rem, 1vw, 1.05rem);
  line-height: 1.2;
  /* The text box: wider than before (was 46ch). Set in rem rather than ch
     so the small "Publications" line gets the same width as the
     paragraphs above it. */
  max-width: 36rem;
  margin: 0;
}

.about-text p.publications {
  font-size: 8pt;
  line-height: 1.4;
  color: #7C736B;
}

.about-text .publications a {
  color: inherit;
  text-decoration: none;
  transition: opacity 0.2s ease;
}

.about-text .publications a:hover,
.about-text .publications a:focus-visible {
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .about-text .publications a {
    transition: none;
  }
}

.about-text .contact-list {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.about-text .contact-list a {
  font-family: var(--font-main);
  font-weight: 700;
  text-decoration: none;
  transition: opacity 0.2s ease;
}

.about-text .contact-list a:hover,
.about-text .contact-list a:focus-visible {
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .about-text .contact-list a {
    transition: none;
  }
}

@media (max-width: 700px) {
  .about-grid {
    grid-template-columns: 1fr;
    /* Text takes only the height it actually needs; the portrait fills
       whatever is left (never less than 220px, in which case the text
       scrolls instead). */
    grid-template-rows: minmax(0, auto) minmax(220px, 1fr);
  }
  .about-portrait {
    aspect-ratio: auto;
    min-height: 0;
  }

  /* Smaller text that uses the full width, so it takes up less height
     and leaves more room for the portrait. */
  .about-text {
    padding: 40px;
    gap: 14px;
  }
  .about-text p {
    font-size: 0.8rem;
    max-width: none;
  }
  .about-text br {
    display: none; /* let the text flow across the full width */
  }
  .about-text .contact-list {
    margin-top: 6px;
    font-size: 0.8rem;
  }
}
