*{ box-sizing:border-box; }
html{ scroll-behavior:smooth; }
body{ margin:0; background:#faf8f3; -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; }
::selection{ background:#e7d9cf; }

/* Self-hosted CJK subset — generated per-deploy by font-pipeline/subset-fonts.mjs.
   CJK-only unicode-range, so the English view never requests it; until the files
   exist the page falls back to system Songti SC / SimSun (works behind the GFW). */
@font-face{ font-family:'NotoSerifSCSubset'; src:url('/fonts/NotoSerifSC-400.woff2') format('woff2'); font-weight:400 500; font-display:swap; unicode-range:U+2E80-9FFF,U+3400-4DBF,U+F900-FAFF,U+3000-303F,U+FF00-FFEF; }
@font-face{ font-family:'NotoSerifSCSubset'; src:url('/fonts/NotoSerifSC-600.woff2') format('woff2'); font-weight:600 700; font-display:swap; unicode-range:U+2E80-9FFF,U+3400-4DBF,U+F900-FAFF,U+3000-303F,U+FF00-FFEF; }

input[type=range]{ -webkit-appearance:none; appearance:none; height:3px; background:#c9c1b0; border-radius:3px; accent-color:#b06a4f; }
input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; appearance:none; width:16px; height:16px; border-radius:50%; background:#1c1a17; cursor:pointer; border:3px solid #faf8f3; box-shadow:0 0 0 1px #b9b1a0; }
input[type=range]::-moz-range-thumb{ width:14px; height:14px; border-radius:50%; background:#1c1a17; cursor:pointer; border:3px solid #faf8f3; }

/* Responsive layer — base design is inline (paints immediately); these only reflow at small widths. */
@media (max-width: 680px){
  .lz-main{ padding-left:20px !important; padding-right:20px !important; padding-bottom:72px !important; }
  .lz-hero{ padding-top:48px !important; gap:28px !important; }
  .lz-name{ font-size:38px !important; }
  .lz-h2{ font-size:22px !important; }
  .lz-navlinks{ gap:14px !important; }
  .lz-clf, .lz-low{ flex:1 1 100% !important; min-width:0 !important; }
}
/* Five nav links + the language toggle need ~400px; a 375px phone gives the
   nav 327px. Below 560px the wordmark drops out (the 40px hero name sits
   right below it) and the link row scrolls horizontally rather than wrapping
   or hiding anything — so a sixth link costs nothing. The right-edge fade is
   applied only when the row actually overflows; chrome.js sets
   data-scrollable, since CSS can't ask whether an element is scrollable. */
@media (max-width: 560px){
  .lz-brand{ display:none !important; }
  .lz-navlinks{
    overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch;
    scrollbar-width:none; padding-right:2px;
  }
  .lz-navlinks::-webkit-scrollbar{ display:none; }
  .lz-navlinks[data-scrollable="1"]{
    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 22px),transparent);
    mask-image:linear-gradient(to right,#000 calc(100% - 22px),transparent);
  }
}

@media (max-width: 460px){
  .lz-main{ padding-left:16px !important; padding-right:16px !important; }
  .lz-hero{ padding-top:40px !important; }
  .lz-name{ font-size:33px !important; }
  .lz-navlinks{ gap:11px !important; }
  .lz-navlinks a{ font-size:11px !important; }
  .lz-barlabel{ width:82px !important; }
  .lz-pair{ gap:10px !important; }
  .lz-collapse{ font-size:9px !important; }
  .lz-news-row{ flex-direction:column !important; gap:2px !important; }
  .lz-news-date{ width:auto !important; }
}
@media (max-width: 360px){
  .lz-barlabel{ width:70px !important; font-size:10px !important; }
  .lz-navlinks{ gap:8px !important; }
}

/* Homepage teaser filmstrip — six frames, sampled where the class collapse
   happens rather than at even intervals. Collapses to three columns on
   narrow screens so the frames stay large enough to read. */
@media (max-width: 560px){
  .lz-strip{ grid-template-columns:repeat(3,1fr) !important; }
}

/* Exhibit pages: prose stays at reading width, figures may run wider. */
.lz-article{ max-width:940px; margin:0 auto; padding:0 24px 96px; }
.lz-prose{ max-width:720px; }
@media (max-width: 680px){
  .lz-article{ padding-left:20px !important; padding-right:20px !important; padding-bottom:72px !important; }
}
@media (max-width: 460px){
  .lz-article{ padding-left:16px !important; padding-right:16px !important; }
}

/* /playground cards — thumbnail beside the text, stacked on narrow screens. */
.lz-exhibit:hover .lz-exhibit-thumb{ border-color:#b06a4f; }
@media (max-width: 460px){
  .lz-exhibit{ flex-direction:column !important; gap:14px !important; }
  .lz-exhibit-thumb{ width:100% !important; height:180px !important; }
}

/* The scale is anchored to a single row of frames, so it is only drawn when
   the strip is one row. Below 560px it wraps to 3x2 and the marks aren't
   rendered at all, leaving this plain rule as the separator. */
.lz-axis-plain{ display:none; }
@media (max-width: 560px){
  .lz-axis-plain{ display:block; }
}

/* The featured exhibit's title is the only link out of the teaser, so it needs
   to read as one on hover. Both states live here rather than on the element:
   an inline `color` would outrank the :hover rule and nothing would change. */
.lz-featured a{ color:inherit; text-decoration:none; transition:color 140ms ease; }
.lz-featured a:hover{ color:#b06a4f; }

/* Same reasoning for the writeup CTA: its colour lives here, not inline. */
.lz-readmore{ color:#1c1a17; text-decoration:none; transition:color 140ms ease; }
.lz-readmore:hover{ color:#b06a4f; }

/* Affiliation ticker: each name links out. Colour and underline live here, not
   inline, or the inline value would outrank :hover and nothing would change. */
.lz-aff{ color:#46423a; text-decoration:none; border-bottom:1px solid #c9c1b0; padding-bottom:1px;
         transition:color 140ms ease, border-color 140ms ease; }
.lz-aff:hover{ color:#b06a4f; border-bottom-color:#b06a4f; }

/* Inline links inside running text (news entries). Colour is inherited so the
   link sits in its sentence; only the underline marks it until hover. */
.lz-tlink{ color:inherit; text-decoration:none; border-bottom:1px solid #c9c1b0; padding-bottom:1px;
           transition:color 140ms ease, border-color 140ms ease; }
.lz-tlink:hover{ color:#b06a4f; border-bottom-color:#b06a4f; }

/* The nav is sticky, so an anchor jump would otherwise park the target's first
   line underneath it. Hold every jump target clear by the nav's height plus
   the same breathing room the hero has under the nav. */
main > *[id], main[id]{ scroll-margin-top:113px; }
@media (max-width: 680px){
  main > *[id], main[id]{ scroll-margin-top:96px; }
}
