/* SOURCE-FORMATTED — DO NOT HAND-MINIFY.
   Phase 2A.1: this stylesheet is kept expanded on purpose — one selector per
   line in a selector list, one declaration per line, two-space indent inside
   @media. It was semi-minified, which made every change unreviewable: a
   one-property fix and a wholesale rewrite produced the same diff. Minify at
   deploy, never in source. Source order is also load-bearing here; several
   rules depend on later-wins cascade, so do not reorder or merge selectors. */

@import url('/assets/css/cinematic-foundation.css?v=c4bfe18fa517e50f');

/* ---------------------------------------------------------------------------
   Cinematic work archive.

   Cascade contract: every unqualified rule lives ABOVE the media queries in
   this file. Adding a "final pass" block at the bottom silently defeats the
   tablet and phone layouts (this file used to ship a 3-up .project-grid and a
   47px .card-heading h3 below the breakpoints, which is why 681-980px rendered
   3-up and phone headings never reached 11vw). Keep new work in the section it
   belongs to.
--------------------------------------------------------------------------- */

:root {
  --paper: #f5ebdc;
  --wine: #47121d;
  --rule: rgba(23,19,16,.22);
  /* Measured height of the fixed header, published by cinematic-work.js. It is
     a page-local token on purpose: --header-h is a shared chrome token and this
     page must not redefine it for everyone. Falls back to the chrome token,
     then to a literal, so the bar still parks correctly with JS off. */
  --work-header-h: var(--header-h,72px);
}

* {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}
body {
  background: var(--cream);
  color: var(--ink);
  font: 16px/1.45 Inter,sans-serif;
  margin: 0;
}
a {
  color: inherit;
}
.skip-link {
  align-items: center;
  background: var(--ink);
  color: var(--paper);
  display: flex;
  left: 10px;
  min-height: 44px;
  padding: 10px 14px;
  position: fixed;
  top: 10px;
  transform: translateY(-150%);
  z-index: 200;
}
.skip-link:focus {
  transform: none;
}

/* Header ------------------------------------------------------------------ */
.archive-header {
  align-items: center;
  background: rgba(7,7,8,.82);
  border-bottom: 1px solid rgba(247,239,226,.12);
  color: var(--paper);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  left: 0;
  padding: 20px var(--edge);
  position: fixed;
  right: 0;
  top: 0;
  z-index: 50;
  backdrop-filter: blur(14px);
}
.archive-header a {
  text-decoration: none;
}
.archive-header nav {
  align-items: center;
  display: flex;
  font-size: 12px;
  gap: 28px;
}
/* 44px in BOTH axes: chrome-universal sets the height, but "Work" is only 33px
   wide at the shared 13-14px nav size. The [href] is a specificity weight, not a
   filter — chrome-universal's `.archive-header :is(nav,...) a` scores (0,2,1),
   so a plain `.archive-header nav a` (0,1,2) would lose. */
.archive-header nav a[href] {
  align-items: center;
  display: inline-flex;
  justify-content: center;
  min-width: 44px;
}
.archive-header nav a[aria-current=page] {
  text-decoration: underline;
  text-underline-offset: 6px;
}
.mark {
  align-items: center;
  display: inline-flex;
  font: 700 13px Syne,sans-serif;
  min-height: 44px;
}

/* Archive shell ----------------------------------------------------------- */
.archive {
  border-top: 0;
  padding: 0 var(--edge) 110px;
}
.kicker {
  font: 13px/1.35 ui-monospace,monospace;
  letter-spacing: .09em;
  text-transform: uppercase;
}

.archive-intro {
  background: var(--cream);
  border-bottom: 1px solid var(--wine);
  color: var(--ink);
  isolation: isolate;
  margin: 0 calc(var(--edge)*-1) 52px;
  min-height: 56svh;
  overflow: hidden;
  padding: 96px var(--edge) clamp(72px,8vh,96px);
  position: relative;
}
.archive-intro::before {
  background: radial-gradient(circle at center,rgba(71,18,29,.13),transparent 46%),repeating-radial-gradient(circle at center,transparent 0 72px,rgba(71,18,29,.16) 73px 74px);
  content: "";
  inset: 0;
  opacity: .82;
  pointer-events: none;
  position: absolute;
}
.archive-intro>* {
  position: relative;
}
.archive-intro .kicker {
  color: rgba(23,19,16,.62);
}
.archive-intro .page-return {
  margin: 0 0 clamp(44px,5vw,72px);
}
.page-return a {
  align-items: center;
  display: inline-flex;
  min-height: 44px;
  text-decoration: none;
}

.archive-heading {
  align-items: end;
  display: grid;
  grid-template-columns: repeat(12,1fr);
  margin-bottom: 0;
}
.archive-heading>div {
  grid-column: 1/8;
}
.archive-heading h2 {
  font: 700 clamp(60px,8vw,122px)/.82 Syne,sans-serif;
  letter-spacing: -.075em;
  margin: 12px 0 0;
}
.archive-heading>p {
  color: rgba(23,19,16,.76);
  font-size: clamp(16px,1.25vw,19px);
  grid-column: 9/-1;
  margin: 0;
  max-width: 38ch;
}

/* Filter bar --------------------------------------------------------------
   .archive must never take `overflow: hidden` — a clipping ancestor makes
   position:sticky inert. Use `overflow-x: clip`, which clips without creating
   a scroll container, so the bar keeps sticking. */
.filter-bar {
  align-items: center;
  background: rgba(238,226,208,.94);
  border-bottom: 1px solid var(--ink);
  border-top: 1px solid var(--ink);
  display: flex;
  gap: 22px;
  margin-bottom: 34px;
  padding: 10px 0;
  position: sticky;
  top: var(--work-header-h,72px);
  z-index: 20;
  backdrop-filter: blur(14px);
}
.filters {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: inline proximity;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar {
  display: none;
}
.filters button {
  background: transparent;
  border: 1px solid transparent;
  color: inherit;
  cursor: pointer;
  font: 13px/1 ui-monospace,monospace;
  letter-spacing: .05em;
  min-height: 48px;
  padding: 0 17px;
  scroll-snap-align: start;
  text-transform: uppercase;
  white-space: nowrap;
}
.filters button[aria-pressed=true] {
  background: var(--wine);
  color: var(--paper);
}
.filters button:focus-visible,
.project-card a:focus-visible,
.archive-header a:focus-visible,
.archive-close a:focus-visible,
.page-return a:focus-visible {
  outline: 2px solid var(--wine);
  outline-offset: 4px;
}
/* Scroll affordance for the chip row, at every width where it overflows.
   cinematic-work.js toggles .of-l / .of-r from the row's real scroll metrics. */
.filter-bar.of-r .filters {
  -webkit-mask-image: linear-gradient(90deg,#000 calc(100% - 56px),transparent);
  mask-image: linear-gradient(90deg,#000 calc(100% - 56px),transparent);
}
.filter-bar.of-l .filters {
  -webkit-mask-image: linear-gradient(90deg,transparent,#000 40px);
  mask-image: linear-gradient(90deg,transparent,#000 40px);
}
.filter-bar.of-l.of-r .filters {
  -webkit-mask-image: linear-gradient(90deg,transparent,#000 40px,#000 calc(100% - 56px),transparent);
  mask-image: linear-gradient(90deg,transparent,#000 40px,#000 calc(100% - 56px),transparent);
}
.result-count {
  font: 12px/1.2 ui-monospace,monospace;
  letter-spacing: .06em;
  margin: 0 0 0 auto;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Card grid --------------------------------------------------------------- */
.project-grid {
  column-gap: clamp(18px,2.3vw,36px);
  display: grid;
  grid-template-columns: repeat(3,minmax(0,1fr));
  row-gap: clamp(58px,7vw,100px);
}
.project-card {
  border-top: 1px solid var(--ink);
  min-width: 0;
  padding-top: 13px;
}
.project-card[hidden] {
  display: none;
}
.project-card a {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
}
.project-card figure {
  aspect-ratio: 16/10;
  background: var(--card);
  margin: 0 0 22px;
  overflow: hidden;
  position: relative;
}
.project-card img,
.project-card video {
  height: 100%;
  object-fit: cover;
  width: 100%;
}
.project-card video {
  display: block;
}
.project-card figure.live-card iframe {
  border: 0;
  height: 200%;
  left: 0;
  pointer-events: none;
  position: absolute;
  top: 0;
  transform: scale(.5);
  transform-origin: top left;
  width: 200%;
}
.hen-card {
  background: #222;
}
.hen-card img {
  object-position: center top;
}
.card-heading {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
}
.card-heading>span {
  font: 12px/1.35 ui-monospace,monospace;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.card-heading h3 {
  font: 700 clamp(32px,3.25vw,54px)/.92 Syne,sans-serif;
  letter-spacing: -.055em;
  margin: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.card-heading h3.compact-title {
  font-size: clamp(28px,2.85vw,48px);
  letter-spacing: -.065em;
}
.project-card p {
  font-size: clamp(16px,1.1vw,17px);
  margin: 13px 0 22px;
  max-width: 46ch;
}
/* The card itself is the link; .route only needs a 44px band so the visible
   affordance is never the small part of the target. */
.route {
  align-items: center;
  color: var(--wine);
  display: inline-flex;
  font-size: 14px;
  font-weight: 600;
  margin-top: auto;
  min-height: 44px;
  text-decoration: underline;
  text-underline-offset: 6px;
}
.status {
  background: var(--paper);
  color: var(--ink);
  font: 12px/1.2 ui-monospace,monospace;
  left: 10px;
  letter-spacing: .08em;
  padding: 8px 10px;
  position: absolute;
  text-transform: uppercase;
  top: 10px;
}

.project-card:nth-child(1) {
  --card: #8258d8;
}
.project-card:nth-child(2) {
  --card: #236d72;
}
.project-card:nth-child(3) {
  --card: #8c293e;
}
.project-card:nth-child(4) {
  --card: #735db5;
}
.project-card:nth-child(5) {
  --card: #d18a23;
}
.project-card:nth-child(6) {
  --card: #7655b8;
}
.project-card:nth-child(7) {
  --card: #315da9;
}
.project-card:nth-child(8) {
  --card: #d75536;
}
.project-card:nth-child(9) {
  --card: #9f5542;
}
.project-card:nth-child(10) {
  --card: #3e7c43;
}
.project-card:nth-child(11) {
  --card: #25211e;
}
.project-card:nth-child(12) {
  --card: #9a765a;
}
.project-card:nth-child(13) {
  --card: #242a55;
}
.project-card:nth-child(14) {
  --card: #51545a;
}

/* Archive previews are intentionally still; HandiWork is the sole moving card. */
.project-card img {
  transition: none;
}
.project-card a:hover img,
.project-card a:focus-visible img,
.project-card a:hover video,
.project-card a:focus-visible video {
  filter: none;
  transform: none;
}

/* Closing panel ----------------------------------------------------------- */
.archive-close {
  background: var(--wine);
  color: var(--paper);
  display: grid;
  grid-template-columns: repeat(12,1fr);
  min-height: 62svh;
  padding: 90px var(--edge) 44px;
}
.archive-close>.kicker {
  grid-column: 1/-1;
}
.archive-close h2 {
  align-self: center;
  font: 700 clamp(62px,9vw,140px)/.77 Syne,sans-serif;
  grid-column: 1/10;
  letter-spacing: -.08em;
  margin: 0;
}
.archive-close h2 em {
  /* The `font:` shorthand resets line-height to `normal`, which threw the Bodoni
     half of this headline to ~1.3 leading while the Syne half above it sat at
     .77. Restate the leading the shorthand wiped out. */
  font: 400 1em Bodoni,serif;
  line-height: .82;
}
.archive-close>div {
  align-self: end;
  display: flex;
  flex-direction: column;
  gap: 14px;
  grid-column: 10/-1;
}
.archive-close a {
  align-items: center;
  display: inline-flex;
  font-size: 16px;
  font-weight: 600;
  min-height: 44px;
  text-underline-offset: 6px;
}

/* The footer is a direct child of <body> (it must sit outside <main> to be
   exposed as the contentinfo landmark), so it no longer needs to cancel
   .archive's inline padding. The negative inline margin it inherited from
   that position pushed it past both viewport edges. */
.archive-footer {
  align-items: center;
  /* The footer lives outside <main> so it registers as the contentinfo
     landmark, which took it out of .archive-close and left it sitting on the
     cream body ground as a beige band bolted under a dark panel. It carries
     the closing panel's own colours so the two read as one block. */
  background: var(--wine);
  color: var(--paper);
  display: grid;
  font-size: 12px;
  gap: 20px;
  grid-template-columns: 1fr auto 1fr;
  margin: 44px 0 0;
  padding: 25px var(--edge);
}
.archive-footer nav {
  display: flex;
  gap: 22px;
}
.archive-footer nav a {
  align-items: center;
  display: inline-flex;
  justify-content: center;
  min-height: 44px;
  min-width: 44px;
}
.archive-footer>span:last-child {
  text-align: right;
}

/* ------------------------------------------------------------------------- */
/* Breakpoints. Nothing unqualified may follow this line.                     */
/* ------------------------------------------------------------------------- */

@media (max-width:980px) {
  .project-grid {
    grid-template-columns: repeat(2,minmax(0,1fr));
  }
  .archive-heading>div {
    grid-column: 1/8;
  }
  .archive-heading>p {
    grid-column: 8/-1;
  }
}

/* The bottom nav bar is switched to fixed by chrome-universal at 760px, so its
   surface and the space it reserves have to start at 760px too. */
@media (max-width:760px) {
  body {
    padding-bottom: 62px;
  }
  /* chrome-universal pins this bar and adds the safe-area insets; the dark
     surface (and therefore the paper link colour) is this page's business. */
  .archive-header nav {
    background: rgba(23,19,16,.92);
    bottom: 12px;
    display: flex;
    gap: 0;
    justify-content: center;
    left: 12px;
    padding: 3px;
    position: fixed;
    right: 12px;
    z-index: 40;
  }
  .archive-header nav a[href] {
    color: var(--paper);
    flex: 1 1 auto;
    min-height: 44px;
    padding: 0 8px;
  }
  .archive-footer {
    padding-bottom: 88px;
  }
}

@media (max-width:680px) {
  /* overflow-x:clip, never hidden: hidden turns every ancestor into a scroll
     container and kills the sticky filter bar. */
  html,
  body {
    max-width: 100%;
    overflow-x: clip;
  }
  .archive-header {
    padding-block: 14px;
  }

  .archive {
    overflow-x: clip;
    padding: 0 18px 80px;
  }
  .archive-intro {
    margin-bottom: 40px;
    min-height: 62svh;
    padding: 82px 18px 62px;
  }
  .archive-intro .page-return {
    margin-bottom: 54px;
  }
  .archive-heading {
    display: block;
  }
  .archive-heading h2 {
    font-size: 14vw;
  }
  .archive-heading>p {
    margin-top: 28px;
  }

  .filter-bar {
    flex-wrap: wrap;
    gap: 0;
    margin-inline: -18px;
    padding-left: 18px;
  }
  .filters {
    padding-right: 6px;
    width: 100%;
  }
  .filters button {
    font-size: 12px;
    letter-spacing: .04em;
    min-height: 46px;
    padding-inline: 14px;
  }
  /* The only confirmation a filter applied, so it stays visible on phones. */
  .result-count {
    margin: 0;
    padding: 2px 18px 4px 0;
    width: 100%;
  }

  .project-grid {
    grid-template-columns: 1fr;
    row-gap: 52px;
  }
  .project-card figure {
    aspect-ratio: 16/10;
  }
  .card-heading h3 {
    font-size: 11vw;
  }
  .card-heading h3.compact-title {
    font-size: 10vw;
  }

  .archive-close {
    display: flex;
    flex-direction: column;
    min-height: 68svh;
  }
  .archive-close h2 {
    font-size: 16vw;
    margin: auto 0;
  }
  .archive-close>div {
    align-items: flex-start;
  }
  .archive-footer {
    grid-template-columns: 1fr;
  }
  .archive-footer nav {
    flex-wrap: wrap;
    order: -1;
  }
  .archive-footer>span:last-child {
    text-align: left;
  }
}

@media (prefers-reduced-motion:reduce) {
  html {
    scroll-behavior: auto;
  }
  .project-card img,
  .project-card video {
    transition: none;
  }
  .filters {
    scroll-behavior: auto;
  }
}

/* ---------------------------------------------------------------------------
   Lightbridge card = the app, not a bare shader.
   The card shows the Lightbridge interface with the live Fractal Glow source
   playing inside its canvas panel, matching the landing-page dock so the work
   index reads "this is an application" at a glance.

   The interface capture is 2800x1524 (~1.837:1) and the card figure is 4:3, so
   the shell is sized to the figure's HEIGHT and shifted left: that fills the
   frame with no letterbox bars while keeping the canvas panel fully visible.
   The screen rectangle below is measured from the capture, so both the image
   and the iframe scale together and stay registered at every width.
   --------------------------------------------------------------------------- */
.project-card figure.lightbridge-dock {
  background: #0b0b10;
  overflow: hidden;
  position: relative;
}
.lightbridge-dock__inner {
  aspect-ratio: 2800/1524;
  display: block;
  height: 100%;
  left: -15%;
  position: absolute;
  top: 0;
}
.lightbridge-dock__shell {
  display: block;
  height: 100%;
  object-fit: fill;
  width: 100%;
}
/* Canvas panel of the capture, as a fraction of the shell. */
.project-card figure.lightbridge-dock .lightbridge-dock__screen {
  background: #050508;
  border: 0;
  height: 38%;
  left: 21.4%;
  pointer-events: none;
  position: absolute;
  top: 3.2%;
  transform: none;
  width: 60.9%;
  z-index: 2;
}
.lightbridge-dock__screen:not([src]),
.lightbridge-dock__screen[src="about:blank"] {
  visibility: hidden;
}

@media (max-width:680px) {
  /* Phones get a crop of the canvas panel itself (see the <picture> source), so
     the inner sits flush and no offset is needed -- the shader never hydrates at
     this width, and a zoomed-out full UI is unreadable on a 320px card. */
  .lightbridge-dock__inner {
    aspect-ratio: auto;
    height: 100%;
    left: 0;
    width: 100%;
  }
  .lightbridge-dock__shell {
    object-fit: cover;
  }
}

/* Orbricks card: poster beneath the gated live embed.
   The iframe mounts only on capable devices; without a shell behind it the
   figure rendered as a flat colour block on every phone, since the iframe was
   the figure's only child. Mirrors the Lightbridge dock treatment. */
.project-card figure.orbricks-card { background: #0a1f18; overflow: hidden; position: relative; }
.orbricks-card__shell {
  display: block;
  height: 100%;
  inset: 0;
  object-fit: cover;
  position: absolute;
  width: 100%;
}
.project-card figure.orbricks-card iframe { position: absolute; z-index: 1; }
.project-card figure.orbricks-card iframe:not([src]),
.project-card figure.orbricks-card iframe[src="about:blank"] { visibility: hidden; }

/* ---------------------------------------------------------------------------
   PHASE 0 — phone quality pass (visual, not metric).
   Everything below is phone-only and is deliberately the LAST block in the
   file so it wins on source order over the 680/760 blocks above without
   needing !important. Nothing here changes palette or typeface.
   --------------------------------------------------------------------------- */
@media (max-width: 680px) {
  /* 1. The archive hero reserved 62svh but only used ~355px of it, so a phone
        opened on 170px of empty paper before the first control. Let the section
        size to its content and keep a deliberate — not accidental — rhythm. */
  .archive-intro {
    /* The intro's own rule plus the sticky bar's rule left an orphan 34px
       stripe of paper between two hairlines. Let the two meet instead. */
    border-bottom: 0;
    margin-bottom: 0;
    min-height: 0;
    padding: 84px 18px 44px;
  }
  .archive-intro .page-return {
    margin-bottom: 34px;
  }
  .archive-heading > p {
    margin-top: 20px;
  }

  /* 2. The result count sat directly on the chip row's baseline. Give the two
        rows of the sticky bar a real gap so they read as two lines, not one
        collided one. */
  .filter-bar {
    padding-bottom: 8px;
    row-gap: 4px;
  }
  .result-count {
    color: rgba(23, 19, 16, .62);
    padding-top: 6px;
  }

  /* 3. The fixed bottom bar was rgba(...,.92) with no backdrop filter, so bright
        card art read straight through the labels. Opaque enough to be a surface. */
  .archive-header nav {
    background: rgba(23, 19, 16, .97);
    box-shadow: 0 6px 24px rgba(23, 19, 16, .28);
  }

  /* 4. The closing panel's CTA links kept `align-self: end` from the 12-column
        desktop layout. Inside the phone's column flex that is the CROSS axis, so
        both links shrink-wrapped and pinned themselves to the right edge while
        the headline above them stayed left. */
  .archive-close > div {
    align-self: stretch;
  }

  /* 5. The footer's 44px top margin let the cream body ground show as a stripe
        between two panels that are both wine — it read as a failed render.
        Turn the reserve into padding inside the wine block. */
  .archive-footer {
    margin-top: 0;
    padding-top: 44px;
  }
}
