/* ------------------------------------------------------------------
   Marco Graziaplena — dark portfolio
   Monument Grotesk Mono is first in the stack: once it is installed
   locally it takes over on its own, no CSS change needed.
------------------------------------------------------------------ */

@import url('https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');

:root {
  --bg: #0A0A0A;

  /* one ink for every piece of text — hierarchy comes from
     size, weight and tracking, never from opacity */
  --ink: rgba(255, 255, 255, 0.92);

  --rule: rgba(255, 255, 255, 0.16);
  --slot: rgba(255, 255, 255, 0.055);

  --mono: 'Monument Grotesk Mono Variable', 'Space Mono', ui-monospace, monospace;

  --t-title: clamp(22px, 2.6vw, 34px);
  --t-body: 12px;
  --t-meta: 10px;

  --pad: 24px;
  --gap: 6px;
  --header-h: 52px;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

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

html { background: var(--bg); }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  padding-top: var(--header-h);
}

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

/* casual-download deterrent: no long-press save sheet on iOS, no
   accidental text-selection drag on media — paired with the
   contextmenu/drag prevention in site.js */
img, video {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* ---------------- page loader ---------------- */
/* A brief entrance beat on the heaviest pages, giving autoplay video
   a moment's head start before the grid is visible. Counts up for a
   minimum stretch so it never flashes uselessly on a fast connection,
   but never blocks longer than a few seconds even if something stalls
   — see the matching logic in site.js. */
.loader {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  transition: opacity 0.5s ease;
}
.loader.done { opacity: 0; pointer-events: none; }
.loader-mark {
  font-size: var(--t-meta);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.55;
}
.loader-pct {
  font-size: clamp(28px, 4vw, 40px);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
@media (prefers-reduced-motion: reduce) {
  .loader { transition: opacity 0.01s; }
}

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

header {
  position: fixed;
  top: 0; left: 0; right: 0;
  min-height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 0 var(--pad);
  background: var(--bg);
  border-bottom: 1px solid var(--rule);
  z-index: 100;
  font-size: var(--t-meta);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

header .mark {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
header .mark img {
  display: block;
  height: 18px;
  width: auto;
}

header .right { display: flex; align-items: center; gap: 22px; }

header .contact { display: flex; gap: 18px; }
header .contact a { border-bottom: 1px solid transparent; transition: border-color 0.2s; }
header .contact a:hover { border-color: var(--ink); }

header .sep { width: 1px; height: 12px; background: var(--rule); }

header nav { display: flex; align-items: center; gap: 20px; }
header nav a { border-bottom: 1px solid transparent; transition: border-color 0.2s; }
header nav a:hover,
header nav a[aria-current='page'] { border-color: var(--ink); }

/* the odd one out — tilted and bold so it reads as a side door */
header nav a.trash {
  font-weight: 700;
  display: inline-block;
  transform: rotate(-5deg);
  transform-origin: center;
  transition: transform 0.25s var(--ease), border-color 0.2s;
}
header nav a.trash:hover { transform: rotate(-5deg) scale(1.08); }

/* ---------------- index list ---------------- */

.index { padding: 0 var(--pad); position: relative; z-index: 1; }

.row {
  display: grid;
  grid-template-columns: 44px 1fr 150px 60px;
  gap: 16px;
  align-items: baseline;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
  transition: opacity 0.28s ease, transform 0.4s var(--ease);
}

.row .num { font-size: var(--t-meta); }
.row .title {
  font-size: var(--t-title);
  letter-spacing: -0.045em;
  line-height: 1.05;
  text-transform: uppercase;
}
.row .client,
.row .year { font-size: var(--t-meta); letter-spacing: 0.05em; }
.row .year { text-align: right; }

/* dim siblings while one row is hovered — interaction, not hierarchy */
.index:hover .row { opacity: 0.3; }
.index:hover .row:hover { opacity: 1; transform: translateX(6px); }

/* ---------------- hover preview (index page) ---------------- */

.preview {
  position: fixed;
  top: 50%;
  right: var(--pad);
  width: 34vw;
  max-width: 460px;
  transform: translateY(calc(-50% + var(--py, 0px)));
  pointer-events: none;
  z-index: 20;   /* above the list, so no row text shows through */
}

/* The frame has no fixed ratio: it takes the shape of whatever media
   is currently showing, so a 16:9 clip and a 4:5 still each appear
   uncropped at their own proportions. */
.preview-frame {
  position: relative;
  overflow: hidden;
  background: var(--bg);   /* opaque: nothing bleeds through the frame */
  border: 1px solid var(--rule);
  clip-path: inset(100% 0 0 0);
  transition: clip-path 0.55s var(--ease);
}
.preview.on .preview-frame { clip-path: inset(0 0 0 0); }

.preview-media {
  display: block;
  min-height: 60px;
  transform: scale(1.14);
  transition: transform 0.8s var(--ease);
}
.preview.on .preview-media { transform: scale(1); }
.preview-media img,
.preview-media video {
  display: block;
  width: 100%;
  height: auto;
  animation: previewFade 0.35s var(--ease);
}
@keyframes previewFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.preview-meta {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 8px;
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.4s ease 0.18s, transform 0.5s var(--ease) 0.18s;
}
.preview.on .preview-meta { opacity: 1; transform: none; }

/* ---------------- project page: split layout ---------------- */
/* Left third is pinned and never scrolls — it holds the title, lede,
   captions and metadata. Right two-thirds is an independent scroll
   area holding the media, each shown at its own natural ratio. */

.project-split {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) 2fr;
  height: calc(100vh - var(--header-h));
}

.project-info {
  border-right: 1px solid var(--rule);
  padding: 40px var(--pad) 24px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
}

.project-info-top h1 {
  font-size: clamp(26px, 3vw, 44px);
  font-weight: 400;
  letter-spacing: -0.05em;
  line-height: 0.98;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.project-info-top .lede { max-width: 40ch; margin-bottom: 24px; }

.project-captions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}
.project-captions .caption { margin: 0; }

.caption {
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.meta {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px 20px;
}
.meta dt {
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 4px;
  opacity: 0.55;
}
.meta dd { font-size: var(--t-meta); line-height: 1.5; }
.meta .notes { grid-column: 1 / -1; max-width: 46ch; }
.meta .notes p + p { margin-top: 10px; }

.pager {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.pager a { border-bottom: 1px solid transparent; transition: border-color 0.2s; }
.pager a:hover { border-color: var(--ink); }

/* right pane: the scrollable media stream */
.media-stream {
  overflow-y: auto;
  height: 100%;
  padding: 40px var(--pad) 120px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  -webkit-overflow-scrolling: touch;
}

.media-row { display: grid; gap: var(--gap); }
.media-row.cols-2 { grid-template-columns: 1fr 1fr; }
.media-row.cols-3 { grid-template-columns: repeat(3, 1fr); }

/* media shown at its own intrinsic ratio — width fills the row,
   height follows naturally, nothing is cropped or force-fitted */
.media-stream img,
.media-stream video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--slot);
  border: 1px solid var(--rule);
  cursor: zoom-in;
}

/* variant: justified mosaic that fills the pane with no scrolling.
   Column widths are computed in site.js from each file's true aspect
   ratio, so a 16:9 stays 16:9 and a 4:3 stays 4:3 — each column's
   stack is solved to land exactly on the pane height, and the
   columns sit side by side filling the width. Nothing is cropped,
   nothing is letterboxed. */
.media-stream.justified {
  overflow: hidden;
  height: 100%;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: center;
  gap: var(--gap);
}
.j-col {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}
.media-stream.justified img,
.media-stream.justified video {
  display: block;
  background: var(--slot);
  border: 1px solid var(--rule);
  cursor: zoom-in;
}
.media-row.cols-4 { grid-template-columns: repeat(4, 1fr); }

/* ---------------- lightbox (project pages + trash can) ---------------- */

.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.94);
  z-index: 500;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 6vh 6vw;
  cursor: zoom-out;
}
.lightbox.on { display: flex; }
.lightbox-stage {
  cursor: default;
  max-width: 100%;
  max-height: 100%;
}
.lightbox-stage img,
.lightbox-stage video {
  display: block;
  max-width: 88vw;
  max-height: 88vh;
  width: auto;
  height: auto;
  object-fit: contain;
}
.lightbox-close {
  position: absolute;
  top: 18px;
  right: var(--pad);
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s;
}
.lightbox-close:hover { border-color: var(--ink); }

/* ---------------- info page ---------------- */

/* Desktop: everything fits in one screen, no scroll. A 4-column grid
   — photo+bio wider on the left, then employment / education /
   contact each in their own column — with the CTA closing the page
   at the bottom. */
.info {
  height: calc(100vh - var(--header-h));
  overflow: hidden;
  padding: 48px var(--pad) 36px;
  display: flex;
  flex-direction: column;
}
.info-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr 1fr;
  gap: 48px;
  flex: 1;
  min-height: 0;
}
.info h1 {
  font-size: var(--t-title);
  font-weight: 400;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  margin-bottom: 20px;
}
.info .profile-pic {
  display: block;
  width: 130px;
  height: auto;
  border: 1px solid var(--rule);
  background: var(--slot);
  margin-bottom: 20px;
}
.info p { margin-bottom: 14px; max-width: 42ch; }
.info section { margin-top: 26px; padding-top: 16px; border-top: 1px solid var(--rule); }
.info .info-col > section:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.info .line { display: grid; grid-template-columns: 100px 1fr; gap: 12px; padding: 6px 0; }
.info .line span:first-child { font-size: var(--t-meta); letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.55; }
.info a.link { border-bottom: 1px solid var(--rule); }
.info a.link:hover { border-color: var(--ink); }

/* the call-to-action button, shared look for both placements */
.info .cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--t-meta);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border: 1px solid var(--rule);
  padding: 14px 24px;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}
.info .cta:hover { border-color: var(--ink); background: var(--slot); }
.info .cta-desktop { margin-top: 32px; align-self: flex-start; }
.info .cta-mobile { display: none; }

/* ---------------- index marquee ---------------- */
/* A continuously scrolling strip closing the index. Only finished
   pieces go in here — no live footage, no wireframes or turntables:
   this is the showreel, not the making-of. The track holds two
   identical copies of the set, and the animation shifts it by exactly
   one copy's width plus one gap, so the loop is seamless. */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--rule);
  padding: var(--pad) 0 calc(var(--pad) * 1.5);
  margin-top: 40px;
}
.marquee-track {
  display: flex;
  gap: var(--gap);
  width: max-content;
  animation: marqueeScroll 90s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }

.marquee-set {
  display: flex;
  gap: var(--gap);
}
.marquee-set img,
.marquee-set video {
  display: block;
  height: 200px;
  width: auto;
  flex: none;
  background: var(--slot);
  border: 1px solid var(--rule);
  cursor: zoom-in;
}

@keyframes marqueeScroll {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-50% - var(--gap) / 2)); }
}

@media (prefers-reduced-motion: reduce) {
  /* no auto-scroll; the strip becomes a normal swipeable row */
  .marquee { overflow-x: auto; }
  .marquee-track { animation: none; }
}

/* ---------------- trash can ---------------- */

.trash-head {
  padding: 64px var(--pad) 36px;
  display: grid;
  grid-template-columns: 1fr minmax(260px, 36%);
  gap: 40px;
  align-items: end;
  border-bottom: 1px solid var(--rule);
}
.trash-head h1 {
  font-size: clamp(30px, 5vw, 64px);
  font-weight: 700;
  letter-spacing: -0.06em;
  line-height: 0.98;
  text-transform: uppercase;
  transform: rotate(-2deg);
  transform-origin: left center;
}
.trash-head p { max-width: 44ch; }

/* Justified rows, laid out in site.js. Width is the constraint here
   (these panes scroll), so each row is scaled to fill the width exactly
   while every item keeps its true aspect ratio. Reading order runs
   left to right, which is what keeps clusters together — CSS
   multi-column would have split them down the columns instead. */
.rows {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}
.board {
  padding: var(--gap) var(--pad) 100px;
}
.b-row {
  display: flex;
  gap: var(--gap);
}

/* While a container's geometry is being solved it stays invisible
   (but still occupies space, so the page doesn't jump). The class is
   added by site.js and removed once laid out — doing it from script
   rather than in the stylesheet means a visitor with JS disabled
   still sees everything, just unjustified. */
.pending { visibility: hidden; }

/* long project pages: a scrolling pane of labelled clusters */
.media-stream.clusters {
  display: block;
  overflow-y: auto;
  height: 100%;
}
.cluster-label {
  font-size: var(--t-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 56px 0 14px;
}
.cluster-label:first-child { margin-top: 0; }

/* sub-groups within a labelled section: visually separated by dead
   space, no text of their own — the black gap between them is the
   only divider */
.media-stream.clusters .rows,
.media-stream.clusters .grid-3,
.media-stream.clusters .grid-3-1 {
  margin-bottom: 40px;
}

/* a single hero item sitting above a row — e.g. the official poster
   above the rest of a set. Bare element, not a .cell: sizes to its
   own natural ratio like everything else in a cluster. */
.hero-media {
  display: block;
  width: 100%;
  height: auto;
  background: var(--slot);
  border: 1px solid var(--rule);
  cursor: zoom-in;
  margin-bottom: var(--gap);
}

/* fixed 3-column grid, for a set meant to read as one block
   rather than as a justified run */
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
}
.grid-3 .cell,
.grid-3-1 .cell {
  width: auto !important;
  height: auto !important;
}
.grid-3 .cell img,
.grid-3 .cell video,
.grid-3-1 .cell img,
.grid-3-1 .cell video {
  width: 100%;
  height: auto;
  object-fit: initial;
}

/* same idea, but collapses to one column on mobile — for a set that
   should read as a dense block on desktop and a simple stack on phones */
.grid-3-1 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
}

.cell {
  position: relative;
  background: var(--slot);
  border: 1px solid var(--rule);
  overflow: hidden;
  cursor: zoom-in;
  flex: none;
  transition: transform 0.25s var(--ease), border-color 0.25s ease, box-shadow 0.25s ease;
}
/* Hover lift. These selectors are deliberately more specific than
   `[data-reveal].seen { transform: none }` further down the sheet:
   at equal specificity the later rule would win and cancel the
   scale on every cell that also carries a reveal. */
.b-row .cell:hover,
.grid-3 .cell:hover,
.board .cell:hover {
  transform: scale(1.12);
  z-index: 5;
  border-color: var(--ink);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.6);
}

/* project panes use bare media rather than .cell wrappers, so they
   need their own hover — scaled less, since these sit edge to edge */
.media-stream img,
.media-stream video {
  position: relative;
  transition: transform 0.25s var(--ease), border-color 0.25s ease, box-shadow 0.25s ease;
}
.media-stream img:hover,
.media-stream video:hover {
  transform: scale(1.06);
  z-index: 5;
  border-color: var(--ink);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.6);
}
.cell img, .cell video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------------- scroll reveal ---------------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s ease, transform 0.6s var(--ease);
}
[data-reveal].seen { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .preview-frame, .preview-media, .preview-meta { transition-duration: 0.01s; }
  .row, header nav a.trash, .cell { transition: none; }
}

/* ---------------- responsive ---------------- */

@media (max-width: 900px) {
  header .contact, header .sep { display: none; }
}

@media (max-width: 800px) {
  :root {
    --pad: 16px;
    --header-h: 46px;
    --t-title: 20px;
  }

  header { gap: 12px; }
  header .mark { font-size: 9px; }
  header nav { gap: 14px; }

  /* index rows: number and title only, tapped rather than hovered */
  .row {
    grid-template-columns: 28px 1fr;
    gap: 10px;
    padding: 16px 0;
  }
  .row .client, .row .year { display: none; }
  .index:hover .row { opacity: 1; }        /* no dimming without a cursor */
  .index:hover .row:hover { transform: none; }
  .preview { display: none; }

  /* project pages: one scrolling column — a pinned info pane doesn't
     work at phone heights, and neither does a fit-to-viewport mosaic */
  .project-split { display: block; height: auto; }
  .project-info {
    position: static;
    height: auto;
    overflow: visible;
    border-right: none;
    border-bottom: 1px solid var(--rule);
    padding: 28px var(--pad) 22px;
  }
  .project-info-top h1 { font-size: 30px; }
  .meta { grid-template-columns: 1fr; gap: 14px; }

  .media-stream,
  .media-stream.clusters {
    height: auto;
    overflow: visible;
    padding: 20px var(--pad) 70px;
  }

  /* every layout engine collapses to a single column. align-items
     and justify-content are reset here too: the desktop rule needs
     flex-start/center for variable-width columns, but left alone on
     mobile they shrink a wrapped group (like .mg2) to its own
     content width and center it — that's the stray black margin. */
  .media-stream.justified {
    height: auto;
    overflow: visible;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
  }
  .j-col { width: 100%; }
  .media-stream.justified img,
  .media-stream.justified video { width: 100% !important; height: auto !important; }

  .cell img, .cell video { height: auto; }

  /* grid-3 stays three columns on mobile too (Branding, The Role,
     Time Crash Visuals all read better dense than stacked) */
  .grid-3 { grid-template-columns: repeat(3, 1fr); }

  /* grid-3-1 is the one exception: three columns on desktop, a
     plain stack on phones */
  .grid-3-1 { grid-template-columns: 1fr; }

  /* Hello Kitty: the hand-authored .j-col groups become mini-grids —
     the video trio at 3 columns, each image pair at 2. Stacking three
     2-column pairs reads identically to one continuous 2-column run. */
  .j-col {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gap);
  }
  .j-col:first-child { grid-template-columns: repeat(3, 1fr); }

  /* Mobile-only grouping utilities. Neutral on desktop (no rule
     outside this query), so wrapping a subset of media in one of
     these never affects the desktop justified layouts. */
  .mg2, .mg3, .mg4, .mg5 {
    display: grid !important;
    gap: var(--gap);
  }
  .mg2 { grid-template-columns: repeat(2, 1fr); }
  .mg3 { grid-template-columns: repeat(3, 1fr); }
  .mg4 { grid-template-columns: repeat(4, 1fr); }
  .mg5 { grid-template-columns: repeat(5, 1fr); }

  .trash-head { grid-template-columns: 1fr; gap: 16px; padding: 36px var(--pad) 24px; }
  .board { padding: var(--gap) var(--pad) 70px; }

  /* Info reverts to the original single, scrolling column: the
     no-scroll grid is a desktop-only trick, there isn't the height
     to pull it off on a phone. */
  .info {
    height: auto;
    overflow: visible;
    display: block;
    padding: 36px var(--pad) 60px;
    max-width: 720px;
  }
  .info-grid { display: block; }
  .info-col { margin: 0; }
  .info .info-col > section:first-child {
    margin-top: 48px;
    padding-top: 24px;
    border-top: 1px solid var(--rule);
  }
  .info p { max-width: 62ch; }
  .info .line { grid-template-columns: 1fr; gap: 2px; padding: 10px 0; }

  /* the CTA swaps position: after the intro on mobile, not at the
     very end of the page */
  .info .cta-mobile { display: inline-flex; margin: 28px 0 8px; }
  .info .cta-desktop { display: none; }

  /* hover states are meaningless on touch and leave elements stuck
     in their :hover appearance after a tap */
  .b-row .cell:hover,
  .grid-3 .cell:hover,
  .grid-3-1 .cell:hover,
  .board .cell:hover,
  .media-stream img:hover,
  .media-stream video:hover {
    transform: none;
    box-shadow: none;
    border-color: var(--rule);
  }
  .cell, .media-stream img, .media-stream video { cursor: default; }

  .pager { padding-top: 14px; }
  .marquee { margin-top: 24px; }
  .marquee-set img, .marquee-set video { height: 120px; }
  .lightbox { padding: 4vh 4vw; }
  .lightbox-stage img, .lightbox-stage video { max-width: 92vw; max-height: 80vh; }
}

/* ---------------- desktop type scale ---------------- */
/* Mobile keeps its own compact sizing untouched, above. This is the
   one change scoped the other way: everything reads about 30-40%
   larger from tablet width up, where there's room to spare and the
   text was cramped at the old sizes. */
@media (min-width: 801px) {
  :root {
    --t-title: clamp(27px, 3.2vw, 42px);
    --t-body: 15px;
    --t-meta: 12px;
  }
  .project-info-top h1 { font-size: clamp(32px, 3.7vw, 54px); }
  .trash-head h1 { font-size: clamp(37px, 6.1vw, 78px); }
  .info .line { grid-template-columns: 115px 1fr; }
}
