/* JetBrains Mono for the second labels around the orbit. It is the one face
   on the page that is actually fetched: the rest of the site runs on faces the
   machine already has, and the labels are two digits at 10px, so the whole
   subset is tiny. Open source, so unlike Helvetica Now Display it can be
   served rather than only named. */
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400&display=swap");

/* ------------------------------------------------------------------
   Nachiket Palkar, portfolio v2
   Case study system. Mirrors the extremepresent.com inner-page grid:
   6 columns, 20px margin/gutter, sharp tiles, one floating nav.
   ------------------------------------------------------------------ */

:root{
  --margin:20px;
  --gutter:20px;
  --columns:6;

  --color-bg:#f9f9f9;
  --color-fg:#000;
  --color-muted:#757575;
  --color-placeholder:#d9d9d9;
  --chip:rgba(222,222,222,.5);

  /* Helvetica Neue first, ahead of the system font. On a Mac this is a real
     choice rather than the OS default; everywhere else the stack falls through
     to the system face, since no Helvetica ships there and Arial is a poor
     stand-in at this line height. */
  --font-base:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,system-ui,Arial,sans-serif;
  --font-mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  /* The clock is set in Helvetica Now Display, as the reference sets its own
     time. That face is licensed from Monotype and is not on any free CDN, so
     it is named first and the site's existing Helvetica stack stands behind
     it: anyone with it installed sees it, everyone else sees Helvetica Neue,
     which is the same skeleton a generation earlier. */
  --font-clock:"Helvetica Now Display","Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,system-ui,Arial,sans-serif;
  /* The seconds are set apart from the time they surround: a mono face, so the
     sixty labels hold the same width and the ring reads as even. */
  --font-sec:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  --fs-ui:16px;
  --fs-body:18px;
  --fs-large:32px;

  /* Two line heights, not one. .95 is display leading: it is what makes the
     32px lines lock together, and it is wrong for anything you actually read
     more than two lines of. */
  --lh-body:.95;
  --lh-copy:1.35;

  /* Tracking in em, so it scales with the size. Negative tracking belongs to
     display type — the gaps grow with the point size — and small text needs
     none of it. A flat px value did the opposite: least effect at 32px, most
     at 14px. */
  --tr-display:-.022em;
  --tr-copy:-.006em;


  --pad-ui:16px;
  --radius:12px;

  /* Motion. One curve does everything, after design.cash.app: their whole
     site runs on cubic-bezier(0.215, 0.61, 0.355, 1) — easeOutCubic — with
     transforms at 0.6s and smaller changes at 0.3s. --ease-inout is the curve
     they reserve for clip-path reveals, which is what the aperture is. */
  --ease:cubic-bezier(0.215, 0.61, 0.355, 1);
  --ease-inout:cubic-bezier(0.77, 0, 0.175, 1);
  --dur-s:.3s;
  --dur-m:.6s;

  --noise:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='2' numOctaves='8' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.35 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

*,*::before,*::after{box-sizing:border-box}

html,body{
  margin:0;
  padding:0;
  background:var(--color-bg);
  color:var(--color-fg);
  font-family:var(--font-base);
  font-weight:500;
  font-size:var(--fs-ui);
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

.shell{padding:var(--margin)}

.grid{
  display:grid;
  grid-template-columns:repeat(var(--columns),1fr);
  gap:var(--gutter);
}

.col-1{grid-column-end:span 1}
.col-2{grid-column-end:span 2}
.col-3{grid-column-end:span 3}
.col-4{grid-column-end:span 4}
.col-5{grid-column-end:span 5}
.col-6{grid-column-end:span 6}

/* ---------- intro ---------- */

.intro-copy{
  margin:0;
  font-size:var(--fs-large);
  line-height:var(--lh-body);
  letter-spacing:var(--tr-display);
}
.intro-copy p{margin:0}

/* The intro block spans five columns because the 32px line wants that width.
   The copy underneath it does not: it holds its own measure inside the same
   column rather than following it out to the edge. */
/* Copy runs the full five-column width, as the reference does — measured on
   extremepresent.com/works/spek at 1440: body copy 1163px wide, the same
   col-5 span as the title. A narrower measure reads better in isolation but
   leaves the fold's right half empty, which is not the layout. The leading
   below is what carries the long line instead. */
.body{
  margin-top:20px;
  font-size:var(--fs-body);
}
/* Body copy runs Regular. The site is Medium everywhere else — titles, nav,
   meta labels — so the 400 is what separates reading text from chrome now that
   it is only 2px larger than the UI size. */
.body p{
  margin:0 0 20px;
  font-size:var(--fs-body);
  font-weight:400;
  line-height:var(--lh-copy);
  letter-spacing:var(--tr-copy);
}
.body p:last-child{margin-bottom:0}

/* Info page. It used to run every paragraph at 32px, which made it the one
   page on the site that ignored the site's own hierarchy — every case study
   leads with one 32px line and steps down to .body. Now it does the same: the
   opening paragraph carries the voice, the rest is reading copy. With only one
   display paragraph left, .95 is the right leading again. */
.intro-copy--info > p{margin:0 0 20px}
.intro-copy--info > p:last-child{margin-bottom:0}

/* The links are a row of 16px chips, not a paragraph. They need a clear break
   from the copy above rather than the 20px that separates two paragraphs. */
.intro-copy--info .contact-links{margin-top:40px}

.contact-links{
  display:flex;
  flex-wrap:wrap;
  gap:2px;
  margin:0;
}

.intro-copy a.contact-link{
  display:inline-flex;
  align-items:center;
  padding:var(--pad-ui);
  border-radius:var(--radius);
  background:#efefef;
  font-size:var(--fs-ui);
  line-height:var(--lh-body);
  /* A chip is chrome at 16px. Without this it inherits the 32px display
     tracking from .intro-copy, which lands at -4.4% and closes the letters up. */
  letter-spacing:normal;
  color:var(--color-fg);
  text-decoration:none;
  border:0;
  transition:opacity var(--dur-s) var(--ease);
}
.intro-copy a.contact-link:hover{opacity:.5}

/* A portrait pinned to the bottom-right column, over everything. */
.intro-copy a,.body a{
  color:inherit;
  border-bottom:1px solid;
  text-decoration:none;
  transition:opacity var(--dur-s) var(--ease);
}
.intro-copy a:hover,.body a:hover{opacity:.5}

/* ---------- meta ---------- */

.meta{
  margin:40px 0 200px;
}

.meta-row{
  display:grid;
  grid-template-columns:repeat(var(--columns),minmax(0,1fr));
  column-gap:var(--gutter);
  /* Both taken from the reference: 16px / 500 / 1.4, label in col 1, value
     spanning cols 2-3. Leave the 500 — it is what the reference runs. */
  line-height:1.4;
  font-weight:500;
}

/* The info page runs its meta lower and spaces the rows out. */
.meta--info{margin:200px 0 0}
.meta--info .meta-row + .meta-row{margin-top:40px}

.meta-label{
  grid-column:1 / span 1;
  margin:0;
  color:var(--color-muted);
}

.meta-value{
  grid-column:2 / span 2;
  margin:0;
}
.meta-value p{margin:0}

/* Links in a meta value were taking the browser's default blue underline,
   which every Next and Contact link in a case footer had been wearing. Same
   treatment as the info page's: the page's own ink, with a rule under it. */
.meta-value a{
  color:inherit;
  text-decoration:none;
  border-bottom:1px solid;
  transition:opacity var(--dur-s) var(--ease);
}
.meta-value a:hover{opacity:.5}

/* Grouped entries in a meta value (a job, a degree) sit apart from the next. */
.meta-value div + div{margin-top:22px}

/* ---------- gallery ---------- */

.gallery{
  margin-top:20px;
  align-items:start;
}

.gallery .tile{
  position:relative;
  display:block;
  overflow:hidden;
  border-radius:0;
}

.gallery .tile img,
.gallery .tile video{
  display:block;
  width:100%;
  height:auto;
  border-radius:0;
}

/* Two cuts of one clip in a single tile. The wide cut is a 16:9 monitor shot;
   at 343px the bezel, stand and desk around it leave the page itself a strip,
   so below the breakpoint the tile swaps to a square framing of the same hero.
   Exactly one is ever displayed, and display:none keeps the other out of the
   viewport observer, so only one decoder is ever running. */
.gallery .tile .media--narrow{display:none}

/* A bento, measured off extremepresent.com/works/blank: a white card the size
   of a media tile — 690x690, 40px of padding, 18px radius — with the copy
   sitting top-left and the rest of the square deliberately left empty. In a
   half-width slot it stays a square; full width it takes the height it needs. */
.text-block{
  background:#fff;
  padding:40px;
  border-radius:18px;
  font-size:var(--fs-body);
  font-weight:400;
  line-height:var(--lh-copy);
  letter-spacing:var(--tr-copy);
}
/* A title on each block of commentary, in the same mono the meta rows and the
   about list use, so it reads as another label on the page rather than as a
   second voice. Set from the paragraph it introduces: a reader scanning the
   gallery gets the point of each one without reading it. */
.text-label{
  margin:0 0 20px;
  font-family:var(--font-mono);
  font-size:12px;
  line-height:1.3;
  letter-spacing:.02em;
  text-transform:uppercase;
  color:var(--color-muted);
}

.col-3 .text-block{aspect-ratio:1 / 1}

/* Forces a new row. Without it the grid's auto-flow pulls the paragraph that
   belongs to the slide above up beside the next, unrelated picture. */
.gallery .tile--row{grid-column-start:1}

/* A paragraph sharing a row with a 690px square is a tenth of its height, so
   top-aligning it strands ~550px of empty column beside a block of copy. Sitting
   it on the row's middle gives the pair a shared centre line instead. */
.gallery .tile--mid{align-self:center}

/* A slot waiting on a real asset. Keeps the grid honest until one lands. */
.placeholder{
  background:var(--color-placeholder);
  aspect-ratio:1 / 1;
  padding:20px;
}
/* Two shapes only: a square in the narrow slots and a 16:9 landscape in the
   wide ones. The 3:4 portrait that used to fill col-3 made a third silhouette
   for no reason — with one square and one rectangle the galleries read as a
   system rather than as an assortment. */
.placeholder--square{aspect-ratio:1 / 1}
.placeholder--wide{aspect-ratio:16 / 9}
.placeholder__label{color:var(--color-muted)}

/* ---------- about ---------- */

/* The info page's left half, built to quynh.moe/about's right-hand panel:
   a 72px display line over label and value rows, no running prose. Measured
   on it at 1440: title 72/600 with -1.44px of tracking on a 72px line, labels
   12px mono uppercase at 60 per cent ink, values 14px regular on 19.6, and a
   value that qualifies the line above it (a company under a year) dropped to
   the same 60 per cent. Long lists run in two sub-columns rather than down one
   long leg, as theirs do. */
.about{display:flex;flex-direction:column}

/* 32px, broken to two lines, and set in the value column rather than flush
   with the labels. That indent is the reference's: its title starts at x=958
   at 1440, which is exactly where its values start, not where its labels do.
   Line height 1, as theirs is (72 on 72). */
.about-title{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:var(--gutter);
  margin:0 0 64px;
  font-size:32px;
  font-weight:600;
  line-height:1;
  letter-spacing:-.02em;
}
.about-title > span,
.about-title::after{grid-column:2 / span 2}

.about-list{margin:0;display:flex;flex-direction:column;gap:40px}

/* Label left, values right, in the same proportion the reference holds: its
   label sits 32px into an 823px panel and its values start at 42 per cent
   across. One column to two is the nearest thing on this grid. */
.about-row{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:var(--gutter);
}

.about-label{
  grid-column:1;
  font-family:var(--font-mono);
  font-size:12px;
  line-height:1.3;
  text-transform:uppercase;
  color:var(--color-muted);
}

.about-value{
  grid-column:2 / span 2;
  margin:0;
  font-size:14px;
  font-weight:400;
  line-height:1.4;
}
.about-value p{margin:0}
.about-value p + p{margin-top:0}

/* The rows are lists, so their lines stack tight. The Info row is the one that
   is prose: once it ran past a single line per paragraph the three of them read
   as one block. One line of air, which keeps it on the same 20px rhythm as
   everything else in the column.

   20px literally, not var(--lh-body): that custom property is the unitless
   1.??-style multiplier the type uses (.95), so var() here would have resolved
   to 0.95px. 20px is the line box these rows actually render at, measured. */
.about-value--prose p + p{margin-top:20px}
.about-value .is-muted{color:var(--color-muted)}

/* The portrait, placed as the reference places its own: last in the Info row,
   left-aligned with the values, 180 by 220, cropped to cover from 50% 30% so
   the face sits in the upper third rather than the middle. Sharp corners and
   no shadow, as theirs has. The 60px above it is the gap it leaves after the
   Info copy; the 32px it leaves before the next label is the list's own row
   gap, near enough. */
.about-photo{
  display:block;
  width:180px;
  height:220px;
  margin-top:60px;
  object-fit:cover;
  /* 50% 50%, not the 30% this used to carry. That pull upward was for a wide
     shot of hands at a desk, where the subject sat high in a frame much wider
     than the slot. The photograph here is cropped to 540x660, which is the
     slot's own 180/220 exactly, so cover has nothing left to trim and the
     position has nothing left to choose. */
  object-position:50% 50%;
  border-radius:0;
}

/* A list of names is a list, not a paragraph: two columns so it reads across
   rather than running the panel's whole height. */
.about-value--split{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:0 var(--gutter);
}

.about-value a{
  color:inherit;
  text-decoration:none;
  border-bottom:1px solid;
  transition:opacity var(--dur-s) var(--ease);
}
.about-value a:hover{opacity:.5}

/* ---------- bento ---------- */

/* The layout of quynh.moe, measured on it at 1440: two cards side by side,
   8px apart, 8px of radius, each a screen tall and clipping its own content,
   32px of padding inside, and only one of the pair scrolling. Their page is
   near-black with the cards in off-white; ours keeps the page as it is and
   lifts the cards to white, which is the same move at this contrast.

   The split is theirs exactly: 703 to 977, read off .panels rather than
   inferred from the rendered 593/823. Mirrored, though: the reading takes the
   wide column and the clock the narrow one, which is the opposite of the
   reference's assignment but the right one here, since this panel holds a
   whole CV and theirs holds a menu.

   A screen tall and no taller: the info page is one screen that never scrolls.
   Everything there is to read, the about list and then the frames below it,
   is inside the left card and travels within it. */
.bento{
  display:grid;
  grid-template-columns:977fr 703fr;
  gap:8px;
  height:calc(100dvh - (2 * var(--margin)));
}
.bento + .bento{margin-top:8px}

/* The reference separates its cards from the page by contrast: near-black
   field, off-white cards. Ours cannot borrow that without repainting the site,
   and white on #f9f9f9 is too close to read as a card at all. The shadow the
   photographs already use does the same job here: the card lifts off the page
   rather than being cut out of a darker one. */
.panel{
  position:relative;
  /* A grid item's minimum width is its content's by default, and the carousel
     inside this one is a 5,500px track. Without this the column sizes itself
     to the track and takes the page with it. */
  min-width:0;
  background:#fff;
  border-radius:8px;
  overflow:hidden;
  padding:32px;
  box-shadow:0 1px 2px rgba(0,0,0,.06),0 8px 20px rgba(0,0,0,.08);
}

/* One card of the pair takes the scroll, the other stays where it is. The
   bars are hidden because the card's own edge already says where the content
   stops. overscroll-behavior holds the wheel inside the card at either end,
   so reaching the bottom of the reading does not start dragging the page. */
.panel--scroll{
  overflow-y:auto;
  overscroll-behavior:contain;
  scrollbar-width:none;
  /* Proximity, not mandatory: the about list above is a long read and should
     stop wherever it is let go. Only the section below it claims a position,
     and only once you are already near it. The 32 is the card's own padding,
     so "end" means the card's inside edge rather than its outside one. */
  scroll-snap-type:y proximity;
  scroll-padding-bottom:32px;
}
.panel--scroll::-webkit-scrollbar{display:none}

/* With the bars hidden there is nothing left to say the card holds more than
   it shows, so the content goes progressively out of focus towards the bottom
   edge rather than being washed out by a white gradient. Nothing is tinted:
   what is under the strip stays its own colour and simply loses its edges,
   which a photograph survives far better than it survives being faded.

   One blur cannot be progressive: backdrop-filter takes a single radius for
   the whole element. Six do. Each layer blurs the backdrop by twice the one
   above it and is masked to fade in over its own sixth of the strip, so every
   band carries all the layers above it plus its own and the radius climbs
   0.4 to 12.8 down the strip without a visible step between bands.

   It is sticky so it rides the scrollport rather than the content, and it has
   to be able to go away: left on, it would leave the last frames of the
   carousel permanently out of focus once you reached them. .is-at-end is set
   from script when the scroll runs out. */
.panel-blur{
  position:sticky;
  bottom:-32px;
  z-index:1;
  height:140px;
  margin:-140px -32px 0;
  pointer-events:none;
  transition:opacity var(--dur-s) var(--ease);
}
.panel--scroll.is-at-end > .panel-blur{opacity:0}

.panel-blur > div{
  position:absolute;
  inset:0;
}
.panel-blur > div:nth-child(1){
  backdrop-filter:blur(.4px);-webkit-backdrop-filter:blur(.4px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 0%,#000 16.7%);
  mask-image:linear-gradient(to bottom,transparent 0%,#000 16.7%);
}
.panel-blur > div:nth-child(2){
  backdrop-filter:blur(.8px);-webkit-backdrop-filter:blur(.8px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 16.7%,#000 33.3%);
  mask-image:linear-gradient(to bottom,transparent 16.7%,#000 33.3%);
}
.panel-blur > div:nth-child(3){
  backdrop-filter:blur(1.6px);-webkit-backdrop-filter:blur(1.6px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 33.3%,#000 50%);
  mask-image:linear-gradient(to bottom,transparent 33.3%,#000 50%);
}
.panel-blur > div:nth-child(4){
  backdrop-filter:blur(3.2px);-webkit-backdrop-filter:blur(3.2px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 50%,#000 66.7%);
  mask-image:linear-gradient(to bottom,transparent 50%,#000 66.7%);
}
.panel-blur > div:nth-child(5){
  backdrop-filter:blur(6.4px);-webkit-backdrop-filter:blur(6.4px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 66.7%,#000 83.3%);
  mask-image:linear-gradient(to bottom,transparent 66.7%,#000 83.3%);
}
.panel-blur > div:nth-child(6){
  backdrop-filter:blur(12.8px);-webkit-backdrop-filter:blur(12.8px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 83.3%,#000 100%);
  mask-image:linear-gradient(to bottom,transparent 83.3%,#000 100%);
}


/* The clock does not scroll at all: its card is a screen tall and holds one
   thing, so it simply stays while the reading passes beside it. */
.panel--clock{display:flex;flex-direction:column;font-family:var(--font-clock)}

/* ---------- clock ---------- */

/* The orbit clock from quynh.moe. Their bundle is minified and unlicensed, so
   this is written here rather than lifted, but the behaviour and the numbers
   are theirs, read off their own source rather than guessed at from pixels:

     60 ticks, 6 degrees apart, one per elapsed second, cleared at the minute.
     Rays are quadratic curves, not straight lines. Each one bends on a spring
     driven by wind, by the drag of the ring turning, by a kick when it is born
     and by the pointer. A bright pulse travels along every curve. The ring
     does not rotate at a constant rate, it steps once a second on an ease.

   The tuning is theirs verbatim: width .5, gap 6, damping 14, inertia 1.2,
   pluck 260, wind 18, mouse radius 250, mouse force 2400, pulse speed .8,
   pulse width .3, pulse alpha .8, max bend 60. */
/* Inside its card the clock has no height of its own to claim: the card is
   already a screen tall, so the location sits at the top and the ring takes
   the middle on auto margins. */
/* Centred over the card, which is also centred over the ring, since the orbit
   sits on auto margins. The reference runs its own location flush left, but
   its clock is left-aligned in a wider panel; here the ring is in the middle
   of the card and a flush-left label pulls against it. */
/* The card's own header: where it is on the left, what time it is there on
   the right. Both in the mono face the second labels use rather than the
   clock's display face, so the line reads as a caption on the instrument
   rather than as part of it. */
.clock-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--gutter);
}

.clock-place,
.clock-zone{
  margin:0;
  font-family:var(--font-sec);
  font-size:12px;
  line-height:var(--lh-body);
  letter-spacing:.02em;
  text-transform:uppercase;
  color:var(--color-muted);
  white-space:nowrap;
}
.clock-zone{text-align:right}

/* Held to the reference's own size rather than stretched to the column. Its
   panel is 529px across and the ring sits at 207, which is the 0.391 the rest
   of this is built on. Letting a 690px half-column set the size gave a 270px
   ring: the same drawing, half again as big, and reading as a diagram rather
   than as a clock. Left-aligned in the column, as the reference's sits at the
   left edge of its panel. */
.orbit{
  position:relative;
  width:100%;
  max-width:529px;
  aspect-ratio:1 / 1;
  margin:auto;
}

.orbit-lines{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  display:block;
}

/* Each second's label. Script writes transform, opacity and blur every frame,
   so there is nothing to animate from here.

   The size is handed down by resize(), because sixty labels have to share one
   circumference: at the desktop radius that works out above 10px and the
   label stays at 10, and on a phone, where the ring is a third of the size,
   holding 10px would have every numeral overlapping its neighbours. */
.orbit-sec{
  position:absolute;
  left:0;
  top:0;
  font-family:var(--font-sec);
  font-size:var(--orbit-sec-fs,10px);
  line-height:1;
  color:rgba(0,0,0,.55);
  white-space:nowrap;
  pointer-events:none;
  will-change:transform,opacity;
}

/* The time sits at the centre of the ring. 44px, weight 600, line-height 1.1,
   tracking -0.01em, in seven character cells with the two spaces around the
   colon included, as the reference sets it. */
.clock-time{
  position:absolute;
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
  margin:0;
  font-family:var(--font-clock);
  font-size:44px;
  font-weight:600;
  line-height:1.1;
  letter-spacing:-.01em;
  white-space:nowrap;
  font-variant-numeric:tabular-nums;
  z-index:1;
}

/* Each character is a masked cell so a glyph can leave through the top while
   the next arrives through the bottom. 1.24em reproduces their 55px box on a
   44px face. */
.clock-ch{
  position:relative;
  display:inline-block;
  overflow:hidden;
  height:1.24em;
  vertical-align:top;
}

/* The cell takes its width from an invisible in-flow copy, because the two
   glyphs that animate are both out of flow and stacked on the same point. */
.clock-ch-sizer{display:block;visibility:hidden;user-select:none;-webkit-user-select:none}

.clock-ch-in{
  position:absolute;
  left:0;
  top:0;
  width:100%;
  will-change:transform;
}

/* ---------- marquee ---------- */

/* A strip of frames under the cards, outside the bento and carrying none of
   its chrome. It runs on its own rather than waiting to be scrolled.

   The track holds the set twice and travels exactly half its own width, which
   puts the second copy where the first began and makes the loop seamless. The
   gap is a margin on each frame rather than a gap on the track, because a
   track gap adds one extra space that -50% does not account for and the loop
   jumps by it every pass. */
/* The title now sits above the strip rather than inside a card, so it is the
   page's own 32px display line, centred over the frames it introduces. */
.marquee-title{
  /* The block sits between a screen-tall card and a strip of photographs, and
     at 80 it read as a caption attached to the card above it. 160 and 80 give
     it its own stretch of page: the same 200 the case studies put before a
     footer, split so the title leads the copy and the copy leads the strip. */
  margin:160px 0 28px;
  font-size:32px;
  font-weight:600;
  line-height:1;
  letter-spacing:-.02em;
  text-align:center;
}

/* Wider than a strict reading measure, narrower than the page. 720 is about
   80 characters at this size; it runs long for centred text, but the copy is
   three sentences and the extra width is what stops it reading as a caption
   under the title. */
.marquee-copy{
  max-width:720px;
  margin:0 auto 80px;
  font-size:14px;
  font-weight:400;
  line-height:var(--lh-copy);
  letter-spacing:var(--tr-copy);
  text-align:center;
}

/* ---------- the strips ---------- */

/* The section is exactly one screenful of the card: the card's height less its
   own padding, with the title, the copy and the two rows centred in it.
   Scrolled to, it fills the view on its own with nothing of the about list
   showing above it and nothing cut off below. 200 above it is the break that
   says the list has finished and something else has started; at 96 it read as
   the next row of the list with a bigger gap. */
.beyond{
  /* min, not a fixed height: on a short window the title, the copy and two
     220px rows add up to more than a fold, and a fixed height would centre
     them and clip both ends. It fills the fold wherever it fits in one. */
  min-height:calc(100dvh - (2 * var(--margin)) - 64px);
  margin-top:200px;
  display:flex;
  flex-direction:column;
  justify-content:center;
  scroll-snap-align:end;
}

.panel--scroll .marquee-title{margin:0 0 24px}
.panel--scroll .marquee-copy{margin-bottom:64px}

/* Centred across the whole card, deliberately off the about list's two-column
   grid. Everything above it answers a label on the left; this does not, and
   sitting it in the value column made it read as one more answer. Centred, it
   reads as the card changing subject. */
.panel--scroll .marquee-title,
.panel--scroll .marquee-copy{text-align:center}
.panel--scroll .marquee-copy{max-width:720px;margin-left:auto;margin-right:auto}

/* Blurred at both ends, so the frames come into focus as they arrive and go
   out of it as they leave rather than being cut off by an edge. The strips are
   on the strip, not the track, so they stay put while the track runs under
   them.

   Inside the card the row runs out to the card's own edges rather than
   stopping at its 32px padding, so the blur sits against the edge. */
.marquee{
  position:relative;
  overflow:hidden;
  margin:0 -32px;
  /* The fade as well as the blur. The blur strips take the edge off a frame
     before it is readable; this carries what is left of it out to nothing, so
     a frame does not reach the card's edge still solid. 8% of the row is about
     the same band the blur covers, so the two resolve together. The mask is on
     the row, not the track, so it stays put while the track runs under it, and
     it takes the blur strips out at the very edge along with everything else. */
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 8%,#000 92%,transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 8%,#000 92%,transparent 100%);
}

/* The same six-layer stack the card's foot uses, turned on its side and held
   against the ends of the row. 72 is a little under half a portrait frame,
   which is enough for one to sharpen before it is readable. They never fade
   out: there is always more row running in from either side. */
.marquee > .panel-blur{
  position:absolute;
  top:0;
  bottom:0;
  left:auto;
  right:auto;
  width:72px;
  height:auto;
  margin:0;
  z-index:2;
}
.marquee > .panel-blur--left{left:0}
.marquee > .panel-blur--right{right:0}

/* Written out per layer rather than as one rule over the set: the base stack's
   own `.panel-blur > div:nth-child(n)` carries a vertical mask and outranks a
   plain `.panel-blur--left > div`, so a single rule here silently lost and the
   ends masked top to bottom instead of end to end. */
.panel-blur--left > div:nth-child(1){
  -webkit-mask-image:linear-gradient(to left,transparent 0%,#000 16.7%);
  mask-image:linear-gradient(to left,transparent 0%,#000 16.7%);
}
.panel-blur--right > div:nth-child(1){
  -webkit-mask-image:linear-gradient(to right,transparent 0%,#000 16.7%);
  mask-image:linear-gradient(to right,transparent 0%,#000 16.7%);
}
.panel-blur--left > div:nth-child(2){
  -webkit-mask-image:linear-gradient(to left,transparent 16.7%,#000 33.3%);
  mask-image:linear-gradient(to left,transparent 16.7%,#000 33.3%);
}
.panel-blur--right > div:nth-child(2){
  -webkit-mask-image:linear-gradient(to right,transparent 16.7%,#000 33.3%);
  mask-image:linear-gradient(to right,transparent 16.7%,#000 33.3%);
}
.panel-blur--left > div:nth-child(3){
  -webkit-mask-image:linear-gradient(to left,transparent 33.3%,#000 50%);
  mask-image:linear-gradient(to left,transparent 33.3%,#000 50%);
}
.panel-blur--right > div:nth-child(3){
  -webkit-mask-image:linear-gradient(to right,transparent 33.3%,#000 50%);
  mask-image:linear-gradient(to right,transparent 33.3%,#000 50%);
}
.panel-blur--left > div:nth-child(4){
  -webkit-mask-image:linear-gradient(to left,transparent 50%,#000 66.7%);
  mask-image:linear-gradient(to left,transparent 50%,#000 66.7%);
}
.panel-blur--right > div:nth-child(4){
  -webkit-mask-image:linear-gradient(to right,transparent 50%,#000 66.7%);
  mask-image:linear-gradient(to right,transparent 50%,#000 66.7%);
}
.panel-blur--left > div:nth-child(5){
  -webkit-mask-image:linear-gradient(to left,transparent 66.7%,#000 83.3%);
  mask-image:linear-gradient(to left,transparent 66.7%,#000 83.3%);
}
.panel-blur--right > div:nth-child(5){
  -webkit-mask-image:linear-gradient(to right,transparent 66.7%,#000 83.3%);
  mask-image:linear-gradient(to right,transparent 66.7%,#000 83.3%);
}
.panel-blur--left > div:nth-child(6){
  -webkit-mask-image:linear-gradient(to left,transparent 83.3%,#000 100%);
  mask-image:linear-gradient(to left,transparent 83.3%,#000 100%);
}
.panel-blur--right > div:nth-child(6){
  -webkit-mask-image:linear-gradient(to right,transparent 83.3%,#000 100%);
  mask-image:linear-gradient(to right,transparent 83.3%,#000 100%);
}

.marquee-track{
  display:flex;
  width:max-content;
  /* The duration is the row's own half-width divided by the pace, 23px a
     second. The two rows hold different photographs and therefore different
     widths, so each carries its own figure rather than sharing one: at a
     single duration the longer row would run visibly faster than the shorter.
     Change a set and these have to change with it. */
  animation:marquee var(--dur) linear infinite;
}

/* A fixed height and a free width, so frames of different shapes can sit in
   the same strip: at 220 tall a portrait takes 165px and a 16:9 takes 391, and
   neither has to be cropped to agree with its neighbours. The loop does not
   care, because both halves hold the same frames in the same order and
   therefore come out the same width whatever those widths are.

   The gap is a margin on each frame, not a gap on the track: a track gap adds
   one space more than there are frames and the -50% the loop travels does not
   account for it, so the seam lands short and the strip jumps every pass.

   Not lazy, and that is load bearing. A frame that has not decoded yet
   measures zero, so the second half would come out narrower than the first.
   Every frame carries its intrinsic width and height in the markup, which
   reserves the right box before the file arrives rather than after. */
.marquee img{
  display:block;
  height:220px;
  width:auto;
  margin-right:8px;
  border-radius:8px;
}

/* The second row runs the other way, and starts the set a different frame
   along, so the two strips never sit in step with each other. Nothing else
   about it differs: same height, same gap, same pace, same loop arithmetic. */
.marquee + .marquee{margin-top:8px}
/* Measured, not estimated: 10701px and 8070px of frames, each over 23px a
   second. The two rows hold different photographs and differ by a third in
   width, which is exactly why each carries its own figure.

   These figures are the desktop row's width. The phone breakpoint shortens
   every frame from 220 tall to 140, so the rows come out about a third
   narrower while the duration stays put, and the same seconds over less
   distance is a slower strip. Measured on the live site at 375: 15.8px a
   second against the 23 above, which is slow enough to read as stopped. The
   breakpoint carries its own figures for that reason. */
.beyond .marquee{--dur:465s}
.beyond .marquee--reverse{--dur:351s}
.marquee--reverse .marquee-track{animation-direction:reverse}

@keyframes marquee{to{transform:translateX(-50%)}}

@media (prefers-reduced-motion:reduce){
  .marquee-track{animation:none}
  .marquee{overflow-x:auto}
}

/* ---------- nav ---------- */

.nav{
  position:fixed;
  top:50%;
  left:50%;
  transform:translate(-50%,-50%);
  width:calc((100vw - (2 * var(--margin)) - (5 * var(--gutter))) / var(--columns));
  /* Clamps measured off extremepresent.com: one column is the target, but below
     a certain viewport that column is too narrow to hold "Extreme Present" on
     one line, and on a very wide screen it stops being a chip and starts being
     a panel. 200/300 is where the reference holds it. */
  min-width:200px;
  max-width:300px;
  display:flex;
  flex-direction:column;
  gap:2px;
  z-index:2;
}

.nav-row{display:flex;gap:2px}

.nav-item{
  position:relative;
  display:inline-flex;
  align-items:center;
  border-radius:var(--radius);
  background:var(--chip);
  backdrop-filter:blur(20px);
  -webkit-backdrop-filter:blur(20px);
  padding:var(--pad-ui);
  text-align:left;
  border:0;
  cursor:pointer;
  color:inherit;
  text-decoration:none;
  transition:background var(--dur-m) var(--ease),backdrop-filter var(--dur-m) var(--ease),-webkit-backdrop-filter var(--dur-m) var(--ease);
}

.nav-item--full{width:100%}
.nav-item--half{flex:1 1 0;min-width:0}

.nav-item--icon{
  flex:1 1 0;
  aspect-ratio:1/1;
  align-self:start;
  padding:0;
  justify-content:center;
  overflow:hidden;
}

.nav-item--circle{border-radius:999px}

/* This used to sit inside the phone breakpoint, because the grid did too. Now
   that the cluster divides in place at every width it has to apply at every
   width, or a desktop paints the button over its own bubbles and the circle
   reads as an empty grey disc with nothing in it.

   The glass disc gets out of the way while the cluster is out. The four bubbles
   fill the space it occupied, and two overlapping discs of nearly the same grey
   only muddied each other. It keeps its own background and backdrop-filter
   transition, so it dissolves as the mass divides rather than cutting. The
   element stays hit-testable, so clicking anywhere in the old circle closes. */
.nav-item--circle.is-open{
  background:transparent;
  backdrop-filter:blur(0px);
  -webkit-backdrop-filter:blur(0px);
}


/* The reel is a button, not a link: nothing for a host router to hijack. */
button.nav-item{font:inherit;appearance:none;-webkit-appearance:none}

div.nav-item{cursor:default}

.nav-item__thumb{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
  border-radius:inherit;
  pointer-events:none;
  /* Short enough to read as a cut, matching the reference reel, but not a
     hard swap: stills strobe when they change with no ramp at all. */
  transition:opacity .12s linear;
}

/* The reel slot holds two stacked thumbs and crossfades between them. */
.nav-item--reel{position:relative}

.nav-item-label{
  display:block;
  font-weight:500;
  font-size:var(--fs-ui);
  line-height:var(--lh-body);
  color:var(--color-fg);
  white-space:nowrap;
  transition:opacity var(--dur-s) var(--ease);
}

.nav-item-label--mono{font-family:var(--font-mono)}

.nav-item:hover .nav-item-label{opacity:.25}

.nav-item.is-active .nav-item-label,
.nav-item.is-active:hover .nav-item-label{opacity:.2}

/* Reading a case study: the nav recedes so it stops sitting on the copy, and
   comes back on scroll up. Hover deliberately does not bring it back. */
.nav.is-hidden .nav-item{
  background:rgba(239,239,239,0);
  backdrop-filter:blur(0px);
  -webkit-backdrop-filter:blur(0px);
}

/* Hidden, it is also untouchable. The chips kept their hit area while invisible,
   so the middle of the page showed a pointer cursor and would take a click for a
   nav nobody could see. */
.nav.is-hidden{pointer-events:none}
.nav.is-hidden .nav-item-label,
.nav.is-hidden .nav-item__thumb{opacity:0}

/* The reel's thumbs carry inline opacity from the crossfade, which would beat
   the rule above. Fade the slot itself so the picture goes with the chips. */
.nav.is-hidden .nav-item--reel{opacity:0;transition:opacity var(--dur-m) var(--ease)}
.nav-item--reel{transition:opacity var(--dur-m) var(--ease)}

/* ---------- social bubbles ---------- */

/* Two stacked layers. The lower one is nothing but plain circles and carries
   the goo filter; the upper one holds the real links and stays unfiltered so
   the labels are never blurred. Both are anchored on the @ button's centre. */
.nav-social,
.nav-social-links{
  position:absolute;
  width:0;
  height:0;
  pointer-events:none;
}

/* Above the chips, not behind them. The cluster divides inside the button's own
   footprint, so behind the glass it would be washed out and the necks all but
   invisible. z-index 2 lifts the goo layer above .nav-item, which is 1; the
   cross is in .nav-social-links, the layer above this one. */
.nav-social{z-index:2}
.nav-social-links{z-index:4}
.nav-row{position:relative}
.nav-row,
.nav-item{z-index:1}

/* One filtered layer per bubble, each holding a copy of the root and that
   bubble alone. A filter merges everything inside its own layer, so a single
   shared layer welded neighbouring bubbles to each other; split this way each
   bubble can only ever join the big circle. The root copies are identical and
   sit on top of one another, so they read as one. */
.nav-social-pair{
  position:absolute;
  left:0;
  top:0;
  width:0;
  height:0;
}
/* The filter is assigned per layer from script, because each neck's blur is
   animated on its own clock. */

.nav-goo,
.nav-bubble{
  position:absolute;
  border-radius:999px;
  will-change:transform;
}

.nav-goo{
  width:var(--bubble);
  height:var(--bubble);
  margin-left:calc(var(--bubble) / -2);
  margin-top:calc(var(--bubble) / -2);
  background:#dedede;
}

/* The mass the others split out of, sized to the @ button. It scales rather
   than fades: under a hard alpha threshold a fading shape does not fade, it
   disappears the instant its alpha crosses the cut. Scaling keeps the edge
   crisp the whole way, and at scale 0 there is nothing painted — which is what
   lets the filter come off at the end without anything visibly changing. */
.nav-goo--root{
  width:var(--root);
  height:var(--root);
  margin-left:calc(var(--root) / -2);
  margin-top:calc(var(--root) / -2);
}

.nav-bubble{
  width:var(--bubble);
  height:var(--bubble);
  margin-left:calc(var(--bubble) / -2);
  margin-top:calc(var(--bubble) / -2);
  display:flex;
  align-items:center;
  justify-content:center;
  font-family:var(--font-mono);
  /* The bubble is derived from the measured button, so it is never the 32px
     the old arc used: 51px on a desktop, 82px on a phone. 14px of label sits
     in either without looking lost. */
  font-size:14px;
  font-weight:500;
  line-height:1;
  letter-spacing:normal;
  color:var(--color-fg);
  text-decoration:none;
  border:0;
  /* Its own disc, matching the goo circles exactly. The goo layer sits behind
     the chips so the root blob cannot cover the button, which means a bubble
     crossing the reel thumbnail would otherwise lose its disc behind the photo
     and leave the label floating on the image. This layer is above everything,
     so the label always has ground under it. The neck still comes from the
     filtered layer beneath. */
  background:#dedede;
  padding:0;
  cursor:pointer;
  opacity:0;
  transition:opacity var(--dur-s) var(--ease);
}
.nav-social-links.is-open .nav-bubble,
.nav-social-links.is-open .nav-close{pointer-events:auto}
.nav-close{pointer-events:none}

/* A bubble with no destination yet. It looks exactly like the others: the only
   difference is the cursor, since a row of identical discs with one of them
   greyed reads as a colour mistake rather than as a state. */
.nav-bubble[aria-disabled="true"]{cursor:default}

.nav-bubble:hover{opacity:.5}

/* Open, the @ becomes a close cross. Drawn as two bars rather than set as a
   glyph: at this size a typographic multiplication sign is thin and sits off
   the optical centre, and the bars can carry the quarter-turn cleanly. */
.nav-close{
  position:absolute;
  /* left/top are set from script; the layer's origin is the button's centre. */
  left:0;
  top:0;
  width:15px;
  height:15px;
  margin:-7.5px 0 0 -7.5px;
  padding:0;
  border:0;
  border-radius:999px;
  background:none;
  appearance:none;
  -webkit-appearance:none;
  cursor:pointer;
  opacity:0;
  transform:rotate(-90deg) scale(.6);
  transition:opacity var(--dur-s) var(--ease),transform var(--dur-m) var(--ease);
}

/* The bars are a fixed size, centred, so the element around them can grow into
   a disc without stretching the mark. */
.nav-close::before,
.nav-close::after{
  content:"";
  position:absolute;
  left:50%;
  top:50%;
  width:15px;
  height:1.5px;
  margin:-.75px 0 0 -7.5px;
  background:var(--color-fg);
}
.nav-close::before{transform:rotate(45deg)}
.nav-close::after{transform:rotate(-45deg)}

/* In the grid the cross is the sixth circle, not a mark floating in the middle
   of the button, so it takes a disc like its neighbours and scales up from
   nothing with them. */
.nav-social-links.is-grid .nav-close{
  width:var(--bubble);
  height:var(--bubble);
  margin:calc(var(--bubble) / -2) 0 0 calc(var(--bubble) / -2);
  background:#dedede;
  transform:rotate(-90deg) scale(0);
}
.nav-social-links.is-grid.is-open .nav-close{transform:rotate(0deg) scale(1)}

/* The two swap on the same curve and in the same direction, so it reads as one
   mark turning into the other rather than a dissolve. */
.nav-item--circle .nav-item-label{
  transition:opacity var(--dur-s) var(--ease),transform var(--dur-m) var(--ease);
}
.nav-item--circle.is-open .nav-item-label,
.nav-item--circle.is-open:hover .nav-item-label{
  opacity:0;
  transform:rotate(90deg) scale(.5);
}
.nav-social-links.is-open .nav-close{opacity:1;transform:rotate(0deg) scale(1)}

/* ---------- mobile ---------- */

/* The parts of the phone dock, built by the script. On a desktop the head, the
   cross and the scrim are not rendered at all, and the wrapper the chips were
   moved into is display:contents, which hands them straight back to the nav's
   own flex flow. The cluster is then exactly what it was before any of this. */
.nav-head,
.nav-panel-close,
.nav-scrim{display:none}

.nav-body{display:contents}

@media (max-width:800px){
  /* The panel. Inset by the page margin on three sides, its full size the
     whole time, parked one height plus that margin below the bottom edge and
     brought up on transform alone. One direction, bottom to top.

     It used to be one box morphing out of the pill: width, height and corner
     radius easing together. That grew from the middle outward, which is two
     directions at once and read as a mask being cut rather than a panel
     arriving. Nothing about the box changes now except where it is, which is
     also the one property a browser can move without touching layout. */
  .nav{
    position:fixed;
    top:auto;
    left:var(--margin);
    right:var(--margin);
    bottom:calc(var(--margin) + env(safe-area-inset-bottom,0px));
    width:auto;
    min-width:0;
    max-width:none;
    height:auto;
    z-index:40;
    display:block;
    padding:0;
    overflow:hidden;
    border-radius:26px;
    background:var(--chip);
    backdrop-filter:blur(20px);
    -webkit-backdrop-filter:blur(20px);
    box-shadow:0 8px 28px rgba(0,0,0,.18);
    transform:translateY(calc(100% + var(--margin) + env(safe-area-inset-bottom,0px)));
    pointer-events:none;
    transition:transform .52s cubic-bezier(.22,1,.3,1);
  }

  /* The chips. An ordinary column now: the panel is never a different size
     from this, so there is nothing to hold them clear of. */
  .nav-body{
    display:flex;
    flex-direction:column;
    gap:2px;
    padding:var(--margin);
  }

  /* The pill. Outside the panel, because the panel is off-screen when closed
     and takes its contents with it. Black, with the reference's own mono caps
     at 11px and its 0.88px of tracking, and 18px of air either side. */
  .nav-head{
    display:inline-flex;
    position:fixed;
    left:50%;
    bottom:calc(var(--margin) + env(safe-area-inset-bottom,0px));
    transform:translateX(-50%);
    z-index:41;
    align-items:center;
    justify-content:center;
    height:52px;
    padding:0 18px;
    border:0;
    border-radius:999px;
    background:#000;
    color:#fff;
    cursor:pointer;
    white-space:nowrap;
    box-shadow:0 8px 28px rgba(0,0,0,.18);
    transition:opacity var(--dur-s) var(--ease);
  }

  .nav-head .nav-item-label{
    font-size:11px;
    letter-spacing:.88px;
    text-transform:uppercase;
    /* .nav-item-label sets its own colour, which beat the white inherited from
       the black pill and left the label black on black. */
    color:inherit;
  }

  /* The cross, centred above the panel rather than inside it. Its offset is the
     panel's own height, which the script publishes as --nav-h, and it eases on
     the same curve so the two travel together. */
  .nav-panel-close{
    display:block;
    position:fixed;
    left:50%;
    bottom:calc(var(--margin) + env(safe-area-inset-bottom,0px) + var(--nav-h,52px) + 14px);
    transform:translateX(-50%);
    z-index:41;
    width:32px;
    height:32px;
    padding:0;
    border:0;
    /* Its own black disc, matching the pill. Out here the cross is over the
       page rather than on the panel, and a bare mark took the page's luck: a
       white one vanished against the clock, a dark one against a photograph.
       A disc reads on either. */
    border-radius:999px;
    background:#000;
    color:#fff;
    cursor:pointer;
    opacity:0;
    pointer-events:none;
    transition:opacity var(--dur-s) var(--ease),bottom .52s cubic-bezier(.22,1,.3,1);
  }

  /* currentColor, not var(--color-fg): the homepage never defines that
     variable, so the bars came out transparent there and the cross was a 24px
     patch of nothing. The button inherits the page's ink either way. */
  .nav-panel-close::before,
  .nav-panel-close::after{
    content:"";
    position:absolute;
    left:9px;
    top:15px;
    width:14px;
    height:1.5px;
    background:currentColor;
  }

  .nav-panel-close::before{transform:rotate(45deg)}
  .nav-panel-close::after{transform:rotate(-45deg)}

  /* The dock floats over the page, so the page has to stop short of it: the
     pill is 52 tall and 16 off the bottom, and the copy used to run straight
     under it. This is the "move the text above the button" of it. */
  main{padding-bottom:84px}

  /* The overlay, at the reference's own 34%, one layer under the panel, with a
     little blur of its own on top of the dim. 6px: enough to take the detail
     out of the page behind without turning it to soup, and small enough that
     the panel's own 20px still reads as the sharper layer. The reference has
     no blur here at all, so this is a deviation from it.

     It sits below the panel, so the panel's backdrop samples the blurred
     result rather than being caught inside it. At opacity 0 the element does
     not render and the filter costs nothing. */
  .nav-scrim{
    display:block;
    position:fixed;
    inset:0;
    z-index:39;
    background:rgba(0,0,0,.34);
    backdrop-filter:blur(6px);
    -webkit-backdrop-filter:blur(6px);
    opacity:0;
    pointer-events:none;
    touch-action:none;
    transition:opacity var(--dur-s) var(--ease);
  }

  /* Open: the panel comes up, the page behind it dims, the pill it came out of
     gets out of the way, and the cross arrives. */
  body.nav-is-open .nav{transform:translateY(0);pointer-events:auto}
  body.nav-is-open .nav-scrim{opacity:1;pointer-events:auto}
  body.nav-is-open .nav-head{opacity:0;pointer-events:none}
  body.nav-is-open .nav-panel-close{opacity:1;pointer-events:auto}

  /* Pinned, the cluster is the @ slot's contents rather than something you
     opened, so the control for closing it has nothing to do. */
  body.nav-social-pinned .nav-close{display:none}

  /* The goo goes with it. That layer exists to animate the pinch-apart: blobs
     blurred together and cut at a hard alpha, which is what makes separation
     read as a membrane breaking. Nothing separates here, and the merged mass
     sat behind the chips as a halo wider than they are. Its cross keeps a blob
     of its own too, so hiding the cross alone left a bump below the bottom
     row. The chips carry their own discs, so none of this is load-bearing.
     Keyed off the panel rather than the pin, so there is no frame of it. */
  body.nav-is-open .nav-social{display:none}

  /* blur(0px) is not "no filter". It still establishes a backdrop root, so the
     panel's own 20px blur stops dead at this element's edge and the page shows
     through sharp inside it, while everything around it stays blurred. Clipped
     to a 999px radius that reads as a big circle sitting behind the four
     links, which is what it was. There is no background involved, which is why
     every check of background-color came back clean.

     none removes the root. The rule at the top level keeps blur(0px) because
     on a desktop it has to transition, and a filter cannot animate to none. */
  body.nav-is-open .nav-item--circle.is-open{
    backdrop-filter:none;
    -webkit-backdrop-filter:none;
    /* And no transition on the way there. .nav-item eases background over .6s,
       so the chip did not vanish, it dissolved: a grey disc sitting behind the
       four links and fading out over half a second, measured from .318 alpha
       down to zero. That was the circle animating on open. In the panel the
       chip is replaced by the links on the same frame, so there is nothing for
       an ease to carry. */
    transition:none;
  }

  /* The scroll-away is for a nav that sits on the copy. This one does not: it
     is a pill in the corner of the screen, and it stays, so each thing the
     scrolled-away state does has to be undone here.

     :not(.is-open) matters more than it looks. This selector carries three
     classes, so it outweighs .nav-item--circle.is-open, which is the rule that
     empties the @ chip while its four links are out. Without the exclusion the
     chip repainted its grey disc the moment the nav picked up is-hidden, which
     is as soon as you scroll: that was the big circle behind the four social
     circles, and it only ever appeared on a page that had been scrolled. */
  .nav.is-hidden{pointer-events:auto}
  .nav.is-hidden .nav-item:not(.is-open){background:var(--chip)}

  /* :not(.is-open) again, for the same reason as the background above. This
     selector carries three classes, so without the exclusion it outweighs
     .nav-item--circle.is-open .nav-item-label, which is the rule that takes the
     @ out of the chip while its four links are out. The @ came back the moment
     the nav picked up is-hidden, which is as soon as you scroll, and sat in the
     middle of the four bubbles. */
  .nav.is-hidden .nav-item:not(.is-open) .nav-item-label,
  .nav.is-hidden .nav-item__thumb{opacity:1}
  .nav.is-hidden .nav-item--reel{opacity:1}

  /* The margin and the chrome size step down; the reading type does not.
     Measured on extremepresent.com/works/spek at 375: the lead line is 32px and
     the body copy 24px, exactly what they are at 1440. Only the meta drops, to
     14px. We had been shrinking the intro to 22/16, which is the one place the
     page stopped looking like the reference on a phone. */
  /* Reading type does step down after all. 18px set solid against a 343px
     measure, inside a card that spends 80 of those pixels on its own inset,
     left too few words per line for the leading to hold them together. 14px
     matches the chrome and buys back the line. */
  :root{--margin:16px;--gutter:16px;--fs-ui:14px;--fs-body:14px}

  /* The text block loses its card down here. At full-bleed width the white
     panel, the 18px radius and the 40px inset turn a paragraph into a boxed
     aside with most of its tile given over to empty margin. On the page
     background with nothing around it, it is simply text, which is what it
     is. The square is dropped with it: forced on a short paragraph at this
     width it opens a half-tile of nothing underneath. */
  .text-block{
    background:none;
    padding:0;
    border-radius:0;
  }
  .col-3 .text-block{aspect-ratio:auto}
  /* The 20px above was set against a 24px line inside a 40px-padded card. Down
     here the card is gone and the line is 19px, so the same gap went from 0.88
     of a line to 1.11 and the label stopped reading as part of the paragraph
     it introduces. 10px puts it back under the desktop proportion. */
  .text-label{margin-bottom:10px}

  .intro-copy{grid-column:1 / span 6}

  .meta{margin-bottom:80px}
  .meta--info{margin:60px 0 0}
  .meta-label{grid-column:1 / span 2}
  .meta-value{grid-column:3 / span 4}

  /* One column, so the grid's two columns become one list in document order.
     A row written as [asset | block] would stack asset then block and a row
     written the other way round would stack block then asset, which read as
     two pictures followed by two unattached blocks. --o is written onto each
     tile by hand: the position it takes down here, with a block always ahead
     of the picture it describes. It is read only inside this breakpoint, so
     the two-column layout above is untouched. */
  .gallery .tile{grid-column:1 / -1;order:var(--o,0)}
  .gallery{margin-bottom:64px}

  .gallery .tile .media--wide{display:none}
  .gallery .tile .media--narrow{display:block}

  /* The split is a desktop idea. Down here the copy and the clock stack, and
     the orbit is capped so it does not take a whole screen on the way past:
     at 343px the labels would be 10px type on a 134px radius, which is a ring
     of noise around a clock nobody can read. */
  /* The pair stops being a pair and becomes a stack, each card taking its own
     height instead of a screen's worth, and nothing scrolls inside anything:
     on a phone the page itself is the scroll. */
  .bento{
    grid-template-columns:1fr;
    height:auto;
    gap:16px;
  }
  .bento + .bento{margin-top:16px}
  .panel{padding:20px}
  .panel--scroll{overflow:visible}
  /* The strip still runs to the card's edges, but the card's padding is 20
     down here rather than 32. */
  .marquee{margin-left:-20px;margin-right:-20px}
  /* No fold to fit down here: the page scrolls and the section takes the
     height it needs. */
  .beyond{min-height:0;margin-top:120px;display:block}
  .panel--scroll .marquee-copy{margin-bottom:40px}
  /* Nothing scrolls inside the card down here, so there is nothing to blur.
     The rows keep their own end strips: they are still running. */
  .panel--scroll > .panel-blur{display:none}
  .marquee > .panel-blur{width:48px}
  /* The reference's compact clock, measured: the ring is given the room
     rather than shrunk, and the face sits at 40px. 320 is as wide as the
     card's content box gets on the phones this breakpoint covers. */
  /* The space belongs to the ring, not to the card: the place line stays where
     it was at the top and the instrument gets room to sit in, clear of the
     label above it and of the card's own edge below. The second labels reach
     about 4px outside the orbit box, so the clear space is 4px less than it
     reads here. */
  .orbit{max-width:320px;margin:112px auto 92px}
  .clock-head{gap:16px}
  .clock-time{font-size:40px}

  .about-title{font-size:32px;margin-bottom:40px;grid-template-columns:1fr}
  .about-title > span{grid-column:1}
  .about-row{grid-template-columns:1fr;gap:8px}
  .about-label,.about-value{grid-column:1}
  .about-list{gap:32px}

  .marquee-title{margin:100px 0 20px}
  .marquee-copy{margin-bottom:48px}
  /* Two columns, not four: a quarter of a 343px card is 80px of photograph.
     The wall takes a fixed height down here, since the section is no longer a
     fold it has to fill. */
  .marquee img{height:140px;margin-right:16px}

  /* 7355px and 5594px of half-width at this size, measured on the live site,
     each over the same 23px a second the desktop rows run at. */
  .beyond .marquee{--dur:320s}
  .beyond .marquee--reverse{--dur:243s}

  /* Performance Lab's videos are screen recordings of a 1440-wide dashboard
     sitting in a monitor mockup, and at 343px the mockup's bezel, stand and
     desk eat a third of the tile while the dashboard itself becomes illegible.
     1.4 is the measured reciprocal of how much of the frame the screen fills
     (~71%), so the screen grows to the full tile and nothing inside it is cut.
     The tile already clips, and the layout box is unchanged, so the row heights
     stay as they were.

     A tile with its own square cut is exempt: that cut is already framed for
     this width, so scaling it would blow up a frame that is correct and crop
     the edges off it. The compensation is only for the 16:9 cuts that have no
     narrow sibling. */
  .gallery--screens .tile video:not(.media--narrow){transform:scale(1.4)}


  .case-footer{margin-top:80px}

  /* The nav used to stay what it is on desktop down here, fixed and centred in
     the viewport at three columns wide. It is the bottom sheet now, sized by
     the rules above, so the column arithmetic that used to set its width would
     only shrink the sheet back to a chip. */

}
