/* The drawing becomes an instrument: indexed projects, image inspection,
   section tracking and short mechanical transitions. Tokens: variables.css. */
[hidden] { display: none !important; }
html { scroll-padding-top: 8rem; }
[id] { scroll-margin-top: var(--space-xl); }
.reading-progress {
  position: fixed; inset: 0 0 auto; height: 3px;
  background: var(--color-primary); z-index: 110;
  transform: scaleX(0); transform-origin: left; pointer-events: none;
}
.nav-shell { transition: border-color var(--duration-fast); }
.has-scrolled .nav-shell { border-color: var(--color-primary); }
.nav-logo { transition: transform var(--duration-fast) var(--ease-standard); }
.nav-logo:hover { transform: translateX(var(--space-2xs)); }
.btn { position: relative; isolation: isolate; overflow: hidden; }
.btn::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--color-primary-dark); transform: translateY(102%);
  transition: transform 320ms var(--ease-standard);
}
.btn-primary:hover::before, .btn-primary:focus-visible::before { transform: translateY(0); }
.btn-secondary::before, .btn-light::before { background: var(--color-primary-light); }
.btn-secondary:hover::before, .btn-secondary:focus-visible::before,
.btn-light:hover::before, .btn-light:focus-visible::before { transform: translateY(0); }
.btn span[aria-hidden] { transition: transform 250ms var(--ease-standard); }
.btn:hover span[aria-hidden], .btn:focus-visible span[aria-hidden] { transform: translateX(var(--space-2xs)); }

/* First page: one title, two real detail views and the drawing's title block. */
.hero-sheet-label {
  display: flex; justify-content: space-between; gap: var(--space-md);
  margin-bottom: var(--space-xl); padding-bottom: var(--space-sm);
  border-bottom: var(--hair) solid var(--color-border);
  font-size: var(--text-sheet-label); font-weight: 600; letter-spacing: .06em;
  color: var(--color-primary); font-variant-numeric: tabular-nums;
}
.hero-sheet-label span:last-child { text-align: right; }
.hero-heading-line { overflow: hidden; padding-bottom: .08em; margin-bottom: -.08em; }
.heading-ink { display: inline-block; }
.hero-heading-line:last-child { color: var(--color-primary); }
.hero-visual::before, .hero-visual::after {
  content: ''; position: absolute; pointer-events: none; z-index: 4;
  width: var(--space-lg); height: var(--space-lg); border: var(--hair) solid var(--color-primary);
}
.hero-visual::before { right: calc(-1 * var(--space-xs)); top: calc(-1 * var(--space-xs)); border-width: var(--hair) var(--hair) 0 0; }
.hero-visual::after { left: calc(-1 * var(--space-xs)); bottom: calc(-1 * var(--space-xs)); border-width: 0 0 var(--hair) var(--hair); }
.hero-scroll-cue {
  display: inline-flex; align-items: center; gap: var(--space-md);
  margin-top: var(--space-lg); padding-block: var(--space-sm);
  font-size: var(--text-xs); color: var(--color-primary); font-weight: 600;
}
.hero-scroll-cue span { transition: transform 250ms var(--ease-standard); }
.hero-scroll-cue:hover span { transform: translateY(var(--space-2xs)); }
.chapter-index { display: none; }
@media (min-width: 1400px) {
  .chapter-index {
    position: fixed; right: var(--space-md); top: 50%; transform: translateY(-50%);
    width: auto; height: auto; overflow: visible; clip-path: none; z-index: 80;
    display: grid; gap: var(--space-2xs);
  }
  .chapter-index a { display: flex; justify-content: end; align-items: center; gap: var(--space-sm); min-height: 38px; }
  .chapter-index .chapter-name {
    position: absolute; right: 100%; margin-right: var(--space-xs); white-space: nowrap;
    padding: var(--space-2xs) var(--space-sm); background: var(--color-heading); color: var(--color-white);
    font-size: var(--text-xs); opacity: 0; transform: translateX(var(--space-xs));
    transition: opacity 180ms, transform 180ms;
  }
  .chapter-index a:hover .chapter-name, .chapter-index a:focus-visible .chapter-name { opacity: 1; transform: none; }
  .chapter-index .chapter-number {
    display: grid; place-items: center; width: 38px; height: 38px;
    background: var(--color-bg); border: var(--hair) solid var(--color-border);
    color: var(--color-body); font-size: var(--text-sheet-label); font-variant-numeric: tabular-nums;
    transition: color 180ms, background 180ms;
  }
  .chapter-index a[aria-current] .chapter-number { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-white); }
}

/* Project index and detail are a single instrument, with an honest no-JS list. */
.project-explorer { border: var(--hair) solid var(--color-border); background: var(--color-white); }
.explorer-index { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); border-bottom: var(--hair) solid var(--color-border); }
.explorer-index button {
  display: flex; gap: var(--space-sm); align-items: center; text-align: left;
  min-height: 88px; padding: var(--space-lg); border: 0; border-right: var(--hair) solid var(--color-border);
  background: var(--color-white); color: var(--color-heading); font-size: var(--text-sm); font-weight: 600;
  position: relative; transition: color 200ms, background 200ms;
}
.explorer-index button:last-child { border-right: 0; }
.explorer-index button::after {
  content: ''; position: absolute; inset: auto 0 0; height: 3px;
  background: var(--color-primary); transform: scaleX(0); transform-origin: left;
  transition: transform 350ms var(--ease-standard);
}
.explorer-index button:hover { background: var(--color-bg-secondary); }
.explorer-index button[aria-selected='true'] { background: var(--color-primary-light); color: var(--color-primary-dark); }
.explorer-index button[aria-selected='true']::after { transform: scaleX(1); }
.explorer-tab-number { align-self: flex-start; font-size: var(--text-sheet-label); color: var(--color-body); }
.explorer-tab-arrow { margin-left: auto; opacity: 0; transition: opacity 200ms, transform 200ms; transform: translate(-3px, 3px); }
.explorer-index button[aria-selected='true'] .explorer-tab-arrow { opacity: 1; transform: none; }
.explorer-panel { display: grid; grid-template-columns: 1.1fr 1fr; min-height: 490px; }
.explorer-panel + .explorer-panel { border-top: var(--hair) solid var(--color-border); }
.is-enhanced .explorer-panel { border-top: 0; }
.is-enhanced .explorer-panels { display: grid; }
.is-enhanced .explorer-panel { grid-area: 1 / 1; }
/* Reserve the largest translated panel so changing tabs never jumps the page.
   Hidden panels remain invisible and outside the accessibility tree. */
.is-enhanced .explorer-panel[hidden] { display: grid !important; visibility: hidden; pointer-events: none; }
/* That panel is display:grid + visibility:hidden, so it still generates a box
   and is therefore still "rendered" — which means a page transition captures
   its logo and morphs a blank snapshot into the destination hero. !important is
   required here: the name is emitted as an inline style by vt_logo_attr(). */
.is-enhanced .explorer-panel[hidden] .explorer-logo { view-transition-name: none !important; }
.explorer-visual {
  position: relative; overflow: hidden; min-height: 360px; display: grid; place-items: center;
  background-color: var(--color-bg-secondary);
  background-image: linear-gradient(var(--rule-major) 1px, transparent 1px), linear-gradient(90deg, var(--rule-major) 1px, transparent 1px);
  background-size: var(--mod-major) var(--mod-major);
  border-right: var(--hair) solid var(--color-border); isolation: isolate;
}
.explorer-logo { width: 65%; max-height: 180px; object-fit: contain; z-index: 1; }
.explorer-orbit { position: absolute; width: 65%; aspect-ratio: 1; border: var(--hair) solid var(--color-border); transform: rotate(45deg); }
.explorer-orbit::after { content: ''; position: absolute; inset: var(--space-lg); border: var(--hair) solid var(--color-border); }
.explorer-drawing-number {
  position: absolute; bottom: var(--space-lg); left: var(--space-lg); z-index: 2;
  padding: var(--space-xs) var(--space-sm); font-size: var(--text-sheet-label);
  background: var(--color-white); color: var(--color-heading); font-variant-numeric: tabular-nums;
}
.explorer-registration { position: absolute; right: var(--space-lg); top: var(--space-md); font-size: var(--text-xl); color: var(--color-heading); }
.explorer-copy { display: flex; flex-direction: column; align-items: start; padding: var(--space-2xl); }
.explorer-project-number { font-size: var(--text-sheet-index); line-height: 1; font-family: var(--font-display); color: var(--color-primary-light); margin-bottom: var(--space-lg); }
.explorer-copy h3 { font-size: var(--text-2xl); letter-spacing: -.035em; }
.explorer-copy p { max-width: 40ch; margin-bottom: var(--space-xl); }
.explorer-copy .btn { margin-top: auto; }

/* A photo's plus control is available to pointer, touch and keyboard alike. */
.photo-open { display: block; position: relative; width: 100%; height: 100%; padding: 0; border: 0; background: transparent; cursor: zoom-in; color: var(--color-white); }
.photo-open img { transition: transform 700ms var(--ease-standard); }
.photo-open:hover img, .photo-open:focus-visible img { transform: scale(1.035); }
.photo-open-mark {
  display: grid; place-items: center; position: absolute; bottom: var(--space-sm); right: var(--space-sm);
  width: 36px; height: 36px; background: var(--color-primary); color: var(--color-white);
  font-size: var(--text-xl); font-weight: 400; line-height: 1;
  transition: transform 250ms var(--ease-standard), background 250ms;
}
.photo-open:hover .photo-open-mark { transform: rotate(90deg); background: var(--color-heading); }
.photo-viewing { overflow: hidden; }
.photo-dialog {
  width: min(1100px, 94vw); max-width: none; max-height: 94dvh;
  padding: var(--space-lg); border: var(--hair) solid var(--color-border);
  background: var(--color-bg); color: var(--color-heading); overflow-y: auto;
}
.photo-dialog::backdrop { background: var(--color-modal-backdrop); }
.photo-dialog-bar, .photo-dialog-controls { display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg); }
.photo-dialog-bar { padding-bottom: var(--space-md); border-bottom: var(--hair) solid var(--color-border); font-size: var(--text-sm); font-weight: 600; }
.photo-dialog button { min-width: 44px; min-height: 44px; padding: var(--space-xs) var(--space-sm); color: var(--color-heading); background: var(--color-bg); border: var(--hair) solid var(--color-border); }
.photo-dialog button:hover { background: var(--color-primary-light); }
.photo-dialog button:disabled { opacity: .35; cursor: default; }
.photo-dialog figure { margin: var(--space-lg) 0; }
.photo-dialog figure img { width: 100%; height: min(62dvh, 680px); object-fit: contain; background: var(--color-bg-secondary); }
.photo-dialog figcaption { font-size: var(--text-sm); max-width: 75ch; margin-top: var(--space-md); }
.photo-dialog-controls { justify-content: center; font-variant-numeric: tabular-nums; }
.photo-dialog-bar button { display: inline-flex; align-items: center; gap: var(--space-lg); }

.experience-controls { display: flex; justify-content: end; background: var(--color-heading); padding: var(--space-md) var(--space-lg); }
.motion-toggle { display: flex; align-items: center; gap: var(--space-sm); min-height: 44px; padding: var(--space-xs) var(--space-md); background: transparent; border: var(--hair) solid var(--color-footer-text); color: var(--color-white); font-size: var(--text-xs); }
.motion-toggle svg { width: 20px; fill: none; stroke: currentColor; stroke-width: 1.5; }
.motion-toggle:focus-visible { outline-color: var(--color-white); }
.motion-toggle:disabled { opacity: .6; cursor: default; }

/* Default visible, even when the JS file cannot be loaded. */
.js .reveal, [data-stagger] > * { opacity: 1; transform: none; animation: none; }
.js .reveal { transition: none; }
html[data-motion='on'].motion-ready .reveal:not(.is-visible) { opacity: 0; transform: translateY(var(--space-lg)); }
html[data-motion='on'].motion-ready .reveal { transition: opacity 650ms var(--ease-standard), transform 650ms var(--ease-standard); }
html[data-motion='on'] .heading-ink { animation: ink-arrive 850ms var(--ease-standard) both; }
html[data-motion='on'] .hero-heading-line:nth-child(2) .heading-ink { animation-delay: 100ms; }
html[data-motion='on'] .hero-slogan, html[data-motion='on'] .hero-desc, html[data-motion='on'] .hero-actions { animation: panel-arrive 700ms var(--ease-standard) both; animation-delay: 180ms; }
html[data-motion='on'] .hero-desc { animation-delay: 260ms; }
html[data-motion='on'] .hero-actions { animation-delay: 340ms; }
html[data-motion='on'] .is-enhanced .explorer-panel:not([hidden]) .explorer-copy { animation: panel-arrive 500ms var(--ease-standard) both; }
html[data-motion='on'] .is-enhanced .explorer-panel:not([hidden]) .explorer-logo { animation: panel-arrive 600ms var(--ease-standard) both; }
html[data-motion='on'] .photo-dialog[open] { animation: panel-arrive 220ms var(--ease-standard); }
@keyframes ink-arrive { from { transform: translateY(110%); } to { transform: translateY(0); } }
@keyframes panel-arrive { from { opacity: 0; transform: translateY(var(--space-lg)); } to { opacity: 1; transform: translateY(0); } }
.dim--draw .dim-line { stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
.dim--draw .dim-cap { opacity: 1; animation: none; }
html[data-motion='on'] .dim--draw .dim-line { transform-origin: left center; animation: dimension-arrive 900ms var(--ease-standard) both; animation-delay: 350ms; }
@keyframes dimension-arrive { from { transform: scaleX(0); } to { transform: scaleX(1); } }

@media (max-width: 1100px) {
  .explorer-index button { padding: var(--space-md); gap: var(--space-xs); }
  .explorer-tab-arrow { display: none; }
  .explorer-copy { padding: var(--space-xl); }
}
@media (max-width: 900px) {
  .explorer-panel { grid-template-columns: 1fr; }
  .explorer-visual { min-height: 320px; border-right: 0; border-bottom: var(--hair) solid var(--color-border); }
  .explorer-copy { min-height: 370px; }
  .explorer-project-number { font-size: var(--text-3xl); }
  .hero-sheet-label { margin-bottom: var(--space-lg); }
}
@media (max-width: 640px) {
  .explorer-index { grid-template-columns: 1fr 1fr; }
  .explorer-index button { min-height: 64px; border-bottom: var(--hair) solid var(--color-border); }
  .explorer-index button:nth-child(2n) { border-right: 0; }
  .explorer-index button:last-child { grid-column: 1 / -1; border-bottom: 0; }
  .explorer-visual { min-height: 260px; }
  .explorer-copy { padding: var(--space-lg); min-height: 390px; }
  .explorer-copy h3 { font-size: var(--text-xl); }
  .hero-sheet-label { font-size: var(--text-sheet-label); }
  .photo-dialog { padding: var(--space-md); }
  .photo-dialog figure img { height: 48dvh; }
  .photo-open-mark { width: 30px; height: 30px; }
  .hero-photo--inset .photo-open-mark { width: 26px; height: 26px; bottom: var(--space-2xs); right: var(--space-2xs); }
}
@media (max-width: 860px) {
  .mobile-cta-bar { display: flex; background: var(--color-bg); backdrop-filter: none; box-shadow: none; }
}
/* Both OS preference and the in-page control remove nonessential motion. */
html[data-motion='off'] { scroll-behavior: auto; }
html[data-motion='off'] *, html[data-motion='off'] *::before, html[data-motion='off'] *::after { animation: none !important; transition: none !important; }
html[data-motion='off'] .js .reveal, html[data-motion='off'] .reveal { opacity: 1; transform: none; }
html[data-motion='off'] .dim-line { stroke-dashoffset: 0; }
html[data-motion='off'] .dim-cap { opacity: 1; }
html[data-motion='off'] .photo-open:hover img, html[data-motion='off'] .photo-open:focus-visible img { transform: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .js .reveal, html[data-motion='on'].motion-ready .reveal:not(.is-visible) { opacity: 1; transform: none; }
  .photo-open:hover img, .photo-open:focus-visible img { transform: none; }
}

/* ---------- The sheet becomes a live drawing surface ---------- */

/* A drafting crosshair. Decorative and inert: it never takes pointer events,
   never appears on touch or coarse pointers, and dies with the motion switch
   (which the OS reduced-motion preference also throws). */
.sheet-cursor { display: none; }
@media (hover: hover) and (pointer: fine) and (min-width: 1024px) {
  html[data-motion='on'] .sheet-cursor {
    display: block; position: fixed; inset: 0; z-index: 70;
    pointer-events: none; opacity: 0;
    transition: opacity 260ms var(--ease-standard);
  }
  html[data-motion='on'] .sheet-cursor.is-live { opacity: 1; }
  .sheet-cursor-x, .sheet-cursor-y {
    position: absolute; background: var(--color-primary); opacity: .22;
  }
  .sheet-cursor-x { left: 0; width: 100%; height: var(--hair); transform: translate3d(0, -1px, 0); }
  .sheet-cursor-y { top: 0; height: 100%; width: var(--hair); transform: translate3d(-1px, 0, 0); }
  /* The centre mark: a small open square, the way a drawing calls out a point. */

  .sheet-cursor-readout {
    position: absolute; padding: var(--space-2xs) var(--space-xs);
    background: var(--color-heading); color: var(--color-white);
    font-size: var(--text-sheet-label); font-weight: 600; letter-spacing: .06em;
    font-variant-numeric: tabular-nums; white-space: nowrap;
    transform: translate3d(calc(var(--tick) * 1.6), calc(var(--tick) * 1.6), 0);
  }
  /* Near the right edge the readout flips to the other side of the crosshair. */
  .sheet-cursor.is-flipped .sheet-cursor-readout {
    transform: translate3d(calc(-100% - var(--tick) * 1.6), calc(var(--tick) * 1.6), 0);
  }
  /* The photo viewer owns the screen while it is open. The modal sits in the
     top layer and would hide the crosshair anyway; these selectors have to
     outrank .is-live so the rule holds on its own terms too. */
  html[data-motion='on'] .photo-viewing .sheet-cursor,
  html[data-motion='on'] .photo-viewing .sheet-cursor.is-live { opacity: 0; }
}

/* Journey: the rule above each entry is drawn in, left to right, the way a
   line lands on a sheet. The faint border underneath stays put, so the list
   is fully ruled before any of this runs. */
.journey-item { position: relative; }
.journey-item::before {
  content: ''; position: absolute; top: -1px; left: 0; right: 0;
  height: var(--hair); background: var(--color-primary);
  transform: scaleX(0); transform-origin: left center;
}
html[data-motion='on'].motion-ready .journey-item.is-visible::before {
  transform: scaleX(1);
  transition: transform 900ms var(--ease-standard);
}
html[data-motion='on'].motion-ready .journey-item.is-visible .journey-year {
  animation: panel-arrive 620ms var(--ease-standard) both;
  animation-delay: 160ms;
}

/* Title block: each field is stamped in, one after the next. */
html[data-motion='on'].motion-ready .hero-title-block > div {
  animation: panel-arrive 560ms var(--ease-standard) both;
}
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(1) { animation-delay: 420ms; }
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(2) { animation-delay: 480ms; }
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(3) { animation-delay: 540ms; }
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(4) { animation-delay: 600ms; }
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(5) { animation-delay: 660ms; }
html[data-motion='on'].motion-ready .hero-title-block > div:nth-child(6) { animation-delay: 720ms; }

/* Explorer: the sheet number ticks over when the drawing changes. */
html[data-motion='on'] .is-enhanced .explorer-panel:not([hidden]) .explorer-drawing-number {
  animation: panel-arrive 420ms var(--ease-standard) both;
  animation-delay: 120ms;
}
html[data-motion='on'] .is-enhanced .explorer-panel:not([hidden]) .explorer-registration {
  animation: registration-lands 520ms var(--ease-standard) both;
}
@keyframes registration-lands {
  from { transform: rotate(-90deg) scale(.4); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* Every addition above is transform/opacity only and stops dead here. */
html[data-motion='off'] .sheet-cursor { display: none; }
html[data-motion='off'] .journey-item::before { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .sheet-cursor { display: none !important; }
  .journey-item::before { transform: scaleX(1); }
}

/* ---------- The pointer: a drafting pick box ---------- */

/* Its own layer, above the header the hairlines run beneath. Outside the
   crosshair's media query on purpose: the base rule must stay display:none
   for touch, narrow screens and no-JS alike. */
.sheet-pointer { display: none; }
@media (hover: hover) and (pointer: fine) and (min-width: 1024px) {
  html[data-motion='on'] .sheet-pointer {
    display: block; position: fixed; top: 0; left: 0; z-index: 200;
    pointer-events: none; opacity: 0;
    transition: opacity 200ms var(--ease-standard);
  }
  html[data-motion='on'] .sheet-pointer.is-live { opacity: 1; }
  /* Inside the photo viewer the real cursor is handed back (see below), so
     the drawn one must go -- outranking .is-live, not relying on the modal
     top layer to cover it. */
  html[data-motion='on'] .photo-viewing .sheet-pointer,
  html[data-motion='on'] .photo-viewing .sheet-pointer.is-live { opacity: 0; }
  /* One fixed 18px box. Every state below is a transform on it, never a
     change of width, height or margin -- nothing here touches layout. */
  .sheet-pointer-box {
    display: block; width: 18px; height: 18px; margin: -9px 0 0 -9px;
    border: var(--hair) solid var(--color-primary);
    transition: transform 180ms var(--ease-standard),
                background-color 180ms var(--ease-standard),
                border-color 180ms var(--ease-standard);
  }
  /* Over something you can act on, the box turns onto its corner and inks in. */
  .sheet-pointer.is-over-control .sheet-pointer-box {
    transform: rotate(45deg) scale(.62);
    background: var(--color-primary);
  }
  /* Over a photograph it opens up, the way a detail view is called out. */
  .sheet-pointer.is-over-photo .sheet-pointer-box {
    transform: scale(2.2);
    border-color: var(--color-white);
  }
  /* On navy and blue surfaces the pen inks white instead, so it never
     disappears into the primary button, the CTA band or the footer. */
  .sheet-pointer.is-on-dark .sheet-pointer-box { border-color: var(--color-white); }
  .sheet-pointer.is-on-dark.is-over-control .sheet-pointer-box { background: var(--color-white); }
  .sheet-pointer.is-on-dark.is-over-text .sheet-pointer-box {
    background: var(--color-white); border-color: var(--color-white);
  }
  /* Over running text it thins to a drafting pen. */
  .sheet-pointer.is-over-text .sheet-pointer-box {
    transform: scaleX(.055) scaleY(1.22);
    background: var(--color-heading); border-color: var(--color-heading);
  }

  /* Only now is the system cursor given up -- the class lands after the
     replacement is on screen, and comes off the moment the pointer leaves.
     The photo viewer is excluded: it sits in the top layer above this one,
     so inside it the real cursor must come back.
     Gated on data-motion='on' as well as the live class: when the motion
     switch goes off this rule must stop matching outright, or the drawn
     pointer disappears while the real one is still suppressed and the
     visitor is left with no cursor at all. */
  html[data-motion='on'].sheet-pointer-live body:not(.photo-viewing),
  html[data-motion='on'].sheet-pointer-live body:not(.photo-viewing) *,
  html[data-motion='on'].sheet-pointer-live body:not(.photo-viewing) a,
  html[data-motion='on'].sheet-pointer-live body:not(.photo-viewing) button { cursor: none !important; }
}

/* Every route back to a real cursor. */
html[data-motion='off'] .sheet-pointer { display: none; }
html[data-motion='off'] body, html[data-motion='off'] body * { cursor: auto !important; }
html[data-motion='off'] a, html[data-motion='off'] button { cursor: pointer !important; }
@media (prefers-reduced-motion: reduce) {
  .sheet-pointer { display: none !important; }
  body, body * { cursor: auto !important; }
  a, button { cursor: pointer !important; }
}

/* ---------- Cross-document page transitions ---------- */

/* The opt-in sits inside the media query so a reduced-motion visitor never
   captures a transition at all. It cannot be gated on data-motion, because
   @view-transition is an at-rule; the in-page switch cancels through
   skipTransition() in the inline head script instead.
   Worth knowing: the blanket kill-switches above do NOT reach any of this.
   `html[data-motion='off'] *` matches elements, and ::view-transition-group()
   is a pseudo-element on :root — so this @media wrapper is the only thing
   holding the reduced-motion guarantee for page transitions. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

/* A wash of the destination project's colour, showing behind the snapshots
   while they cross-fade. The colour is static — only opacity and transform are
   animated — so it can tint the change of identity without ever flashing.
   This is why the theme class lives on <html>: these pseudo-elements inherit
   from :root, and a theme on <body> would leave --accent unresolved here. */
::view-transition {
  background-color: color-mix(in srgb, var(--accent, var(--color-primary)) 12%, var(--color-bg));
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--duration-page-fade);
  animation-timing-function: var(--ease-standard);
}

/* Persistent chrome gets its own group rather than ghosting through the root
   cross-fade. The name is on .nav-shell rather than .site-header so the pill
   itself is the transitioned element — .site-header is sticky, and its offset
   differs by a few pixels between a scrolled page and a fresh one, which the
   default group animation resolves as a transform. Do not pin it: that snaps.
   .site-footer is deliberately left unnamed — it sits at the bottom of
   documents of different lengths, so naming it would animate a full-width
   snapshot between two unrelated offsets. */
.nav-shell { view-transition-name: nav-shell; }
.mobile-cta-bar { view-transition-name: mobile-cta; }
::view-transition-group(nav-shell),
::view-transition-group(mobile-cta) {
  animation-duration: var(--duration-page-fade);
  animation-timing-function: var(--ease-standard);
}

/* The drafting overlays are on screen under exactly the conditions a
   transition runs. Left unnamed they are baked into the root snapshot and a
   frozen crosshair drags across every navigation, so they drop out for the
   duration; experience.js repaints them on the next pointermove. */
.reading-progress { view-transition-name: reading-progress; }
.sheet-cursor { view-transition-name: sheet-cursor; }
.sheet-pointer { view-transition-name: sheet-pointer; }
::view-transition-group(reading-progress),
::view-transition-group(sheet-cursor),
::view-transition-group(sheet-pointer) { display: none; }

/* Muted by the head script for the duration of one navigation, so only the
   card that was actually activated takes part. !important is required: the
   name is an inline style from vt_logo_attr(). */
.vt-mute { view-transition-name: none !important; }

/* The project logo travels from the card that was clicked into the hero it
   opens. The per-element name is emitted by vt_logo_attr() (functions.php)
   from the logo's file path, which is the same string at both ends, so the two
   sides cannot drift apart. The class carries the shared styling. */
.project-media img,
.related-logo img,
.explorer-logo,
.page-title--logo img { view-transition-class: project-logo; }

::view-transition-group(.project-logo) {
  animation-duration: var(--duration-page-morph);
  animation-timing-function: var(--ease-standard);
}
/* .explorer-logo is a 65%-wide box with object-fit:contain, so its box aspect
   ratio is not the artwork's and its snapshot carries transparent letterbox.
   Letterboxing both snapshots inside the animating box keeps the morph true to
   the artwork whichever card it started from. */
::view-transition-old(.project-logo),
::view-transition-new(.project-logo) {
  block-size: 100%;
  object-fit: contain;
  animation-duration: var(--duration-page-morph);
  animation-timing-function: var(--ease-standard);
}

/* Ten overlapping, round-ended ribbons merge into one opaque liquid sheet.
   Only transforms move; the overscan covers the rounded edge at every ratio. */
.rookie-wipe { position:fixed; inset:0; z-index:10000; overflow:hidden; isolation:isolate; cursor:progress; }
.rookie-wipe-ribbon {
  position:absolute; left:-20vmax; width:calc(100% + 40vmax); height:12%;
  top:calc(var(--rookie-row) * 10% - 1%);
  border-radius:var(--radius-rookie-flow) 0 0 var(--radius-rookie-flow);
  background:var(--color-rookie-wipe); transform:translateX(110%); will-change:transform;
}
.rookie-departing .sheet-pointer, .rookie-departing .sheet-cursor { visibility:hidden; }
