/* ==========================================================================
   charlx.com — one stylesheet for the whole domain
   --------------------------------------------------------------------------
   Pure white, black text, flat. Reference: retro.app and apple.com.

   This file replaces the previous studio.css + huxle.css pair. They were two
   deliberately different skins — a dark instrument panel and a warm-paper
   specimen sheet — and once both became white and black, keeping them apart
   only created two places for the same colour to drift. The colour tokens now
   exist once.

   Rules, without exception:

     1. No glow. Nothing emits light: no coloured halos, no shadow bloom, no
        pulsing, no gradients. Separation is hairlines and one #F5F5F7 band.
     2. The only colour anywhere is Huxle's colour pool. Everything else is
        black, white, or a grey between them. That is also why white is right
        behind a colour swatch: a neutral surround is what you judge a colour
        against.
     3. System typefaces, so nothing is downloaded. The studio is set in
        -apple-system (SF Pro). The Huxle pages carry `class="huxle"` on <body>
        and ask for SF Pro Rounded — the face the app itself uses, and now the
        only thing tying the site's look to the product. On engines that don't
        expose it the two families render identically; that is acceptable, so
        nothing is built on the difference.

   Committed to a single light appearance. There is no dark variant: white is
   the design, not a mode.

   Contrast, measured with tools/contrast.py — every pair that exists here:
     #000000 on #FFFFFF  21.00:1     #000000 on #F5F5F7  19.29:1
     #6E6E73 on #FFFFFF   5.07:1     #6E6E73 on #F5F5F7   4.66:1
     #FFFFFF on #000000  21.00:1     #FFFFFF on #333336  12.59:1
   Apple's own secondary grey #86868B is 3.62:1 on white and fails AA, so it is
   deliberately not used.
   ========================================================================== */

:root {
  --paper: #FFFFFF;
  --tint:  #F5F5F7;
  --ink:   #000000;
  --ink-2: #6E6E73;
  --hair:  #D2D2D7;
  --hover: #333336;

  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
          system-ui, sans-serif;
  /* "SF Pro Rounded" listed before ui-rounded: the generic keyword resolves
     on Apple platforms but is ignored by some engines, in which case the
     named family is the next best chance. Where neither resolves, this
     falls through to the studio's face and the two page families simply
     look the same — a soft distinction, not a load-bearing one. */
  --round: "SF Pro Rounded", ui-rounded, -apple-system, system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --gut: 22px;
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100svh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
/* The app is drawn in SF Pro Rounded. Its own pages follow. */
body.huxle { font-family: var(--round); }

/* Traditional Chinese. The stack names the Taiwanese system faces first —
   PingFang TC is the iOS/macOS default and is what the app renders in.
   Chinese has no descenders and sets denser than Latin, so it wants a little
   more leading and slightly looser tracking than the English pages. */
:root:lang(zh-Hant), html[lang^="zh"] body {
  font-family: "PingFang TC", "Heiti TC", "Noto Sans TC",
               "Microsoft JhengHei", -apple-system, system-ui, sans-serif;
}
html[lang^="zh"] body { line-height: 1.75; }
html[lang^="zh"] h1 { line-height: 1.24; letter-spacing: -.01em; }
html[lang^="zh"] h2 { line-height: 1.3; letter-spacing: -.005em; }
html[lang^="zh"] .lede { line-height: 1.7; letter-spacing: 0; }
/* text-wrap: balance/pretty are tuned for spaced scripts and can leave a
   single orphaned character on a line in Chinese. */
html[lang^="zh"] h1, html[lang^="zh"] h2, html[lang^="zh"] p { text-wrap: initial; }

/* Small labels. 11px uppercase Latin in a mono face is legible because the
   forms are simple and the tracking opens them up. A Chinese glyph at 10-11px
   has to resolve far more strokes in the same box, and the .18em tracking that
   helps Latin caps just scatters it. Every label class steps up, and the
   tracking comes down. Measured: 42 instances were under 12px. */
html[lang^="zh"] .eyebrow,
html[lang^="zh"] .mono          { font-size: 13px; letter-spacing: .06em; }
html[lang^="zh"] .mast-nav a,
html[lang^="zh"] .bar nav a     { font-size: 13px; letter-spacing: .04em; }
html[lang^="zh"] .meter-cell dt { font-size: 12px; letter-spacing: .05em; }
html[lang^="zh"] .meter-mode    { font-size: 12px; letter-spacing: .06em; }
html[lang^="zh"] .specs dt,
html[lang^="zh"] .facts dt      { font-size: 12px; letter-spacing: .05em; }
html[lang^="zh"] .spec-tier     { font-size: 12px; letter-spacing: .05em; }
html[lang^="zh"] .foot a,
html[lang^="zh"] .foot span     { font-size: 12px; letter-spacing: .05em; }
html[lang^="zh"] .fine          { font-size: 15px; }
html[lang^="zh"] .strip-note    { font-size: 15px; }
html[lang^="zh"] .gallery figcaption { font-size: 14px; }
/* The Latin parts of a mixed line (CharlX Studio, iPhone, hex codes) keep the
   mono face; only the size moves. */
html[lang^="zh"] .specs dt      { width: 130px; }

.wrap { width: 100%; max-width: 1000px; margin: 0 auto; padding: 0 var(--gut); }
.wrap-narrow { max-width: 720px; }
.wrap-wide { max-width: 1000px; }

/* --- Type ----------------------------------------------------------------- */
h1 {
  font-size: clamp(38px, 7.4vw, 78px);
  font-weight: 700; line-height: 1.04;
  letter-spacing: -.035em; text-wrap: balance;
}
h2 {
  font-size: clamp(28px, 4.4vw, 44px);
  font-weight: 700; line-height: 1.08;
  letter-spacing: -.028em; text-wrap: balance;
}
h3 { font-size: 19px; font-weight: 600; line-height: 1.3; letter-spacing: -.012em; }
p { text-wrap: pretty; }

/* Measure. Running text was 99-132ch at desktop against a 60-75ch target; the
   legal and support pages, the ones people actually read, were the worst.
   35em serves both scripts: Latin averages ~0.5em per character, so 35em is
   ~70 characters; a Chinese glyph is a full em, so the same 35em is ~35
   characters. Structural blocks (strip, card grids, tables) stay full width. */
.measure, main > .wrap > p, .legal p, .legal li,
.qa .ans, .block > p, ol.steps li, .ship p, .card p {
  max-width: 35em;
}
.mid p, .mid .lede { max-width: 26em; }
.meter-note { max-width: 30em; margin-inline: auto; }

/* Huxle's pages are denser and more numerous, so their headings run smaller. */
body.huxle h1 { font-size: clamp(32px, 6vw, 54px); letter-spacing: -.03em; }
body.huxle h2 { font-size: clamp(24px, 3.4vw, 33px); letter-spacing: -.022em; }

.eyebrow, .mono {
  font-family: var(--mono); font-size: 11px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink-2);
}

.lede {
  font-size: clamp(19px, 2.3vw, 23px);
  line-height: 1.45; letter-spacing: -.012em;
  color: var(--ink-2); margin-top: 20px;
}
body.huxle .lede { font-size: clamp(17px, 2vw, 20px); margin-top: 16px; }

.fine { font-size: 14px; color: var(--ink-2); line-height: 1.5; margin-top: 12px; }

a { color: var(--ink); text-underline-offset: 3px; text-decoration-color: var(--hair); }
a:hover { text-decoration-color: var(--ink); }

:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 3px; }

.sr { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* Skip link. Off-screen until focused — the first Tab on any page reaches it,
   so a keyboard user isn't walked through the whole nav on all 15 pages. */
.skip {
  position: absolute; left: 10px; top: 10px; z-index: 100;
  transform: translateY(-200%);
  background: var(--ink); color: var(--paper);
  padding: 13px 20px; border-radius: 10px;
  font-size: 15px; font-weight: 500; text-decoration: none;
}
.skip:focus { transform: translateY(0); }
main:focus { outline: none; }

/* --- Chrome ---------------------------------------------------------------
   Opaque white, not translucent — a blur behind a white page is an effect with
   nothing to show through it.
   ------------------------------------------------------------------------- */
.masthead, .bar {
  position: sticky; top: 0; z-index: 20;
  background: var(--paper);
  border-bottom: 1px solid var(--hair);
}
/* The bar is one row at every width. Giving the nav links their 44px tap
   height made the row wider, which wrapped the wordmark onto two lines at
   390px — so the gaps and label sizes tighten on small screens instead. */
.masthead .wrap, .bar .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; min-height: 54px; flex-wrap: nowrap;
}
.mark-txt, .brand span { white-space: nowrap; }
.mast-nav a, .bar nav a, .lang a, .lang > span { white-space: nowrap; }

.mark { text-decoration: none; display: inline-flex; align-items: center; min-height: 44px; }
.mark-txt {
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink);
}
.brand { display: flex; align-items: center; gap: 9px; text-decoration: none; min-height: 44px; }
.brand img { width: 26px; height: 26px; border-radius: 6px; display: block; }
.brand span { font-weight: 700; letter-spacing: -.018em; font-size: 18px; }

.mast-nav, .bar nav { display: flex; align-items: center; gap: 14px; flex-wrap: nowrap; }
/* The anchors used to be 26px tall — the bare text box. The padding here is
   what makes the tap area 44px without changing how the bar looks. */
.mast-nav a, .bar nav a {
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-2); text-decoration: none;
  display: inline-flex; align-items: center;
  min-height: 44px; padding-inline: 4px;
}
.mast-nav a:hover, .bar nav a:hover, .bar nav a[aria-current="page"] { color: var(--ink); }

/* Language switch. Reads as one control, not two links.
   Was rendering at 26x19 — the smallest target on the site, and the one a
   Chinese-speaking visitor needs first. Both halves are now 44px tall. */
.lang { display: flex; align-items: center; gap: 2px; }
.lang a, .lang > span {
  font-family: var(--mono); font-size: 13px; letter-spacing: .08em;
  text-decoration: none; color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 34px; padding-inline: 6px;
}
.lang a:hover { color: var(--ink); }
.lang [aria-current="true"] { color: var(--ink); font-weight: 500; }
.lang i { font-style: normal; color: var(--hair); }

@media (max-width: 440px) {
  .masthead .wrap, .bar .wrap { gap: 6px; }
  .mast-nav, .bar nav { gap: 4px; }
  .mast-nav a, .bar nav a { font-size: 11px; letter-spacing: .05em; padding-inline: 3px; }
  .mark-txt { font-size: 11px; letter-spacing: .1em; }
  .brand span { font-size: 16px; }
  .lang a, .lang > span { min-width: 30px; padding-inline: 3px; font-size: 12px; }
}
/* English labels are longer than the Chinese ones, so the smallest phones need
   one more step down. The 44px tap height never changes — only the type does. */
@media (max-width: 360px) {
  .mast-nav a, .bar nav a { font-size: 10px; letter-spacing: .03em; padding-inline: 2px; }
  .mark-txt { font-size: 10px; letter-spacing: .06em; }
  .brand span { font-size: 15px; }
  .brand img { width: 22px; height: 22px; }
  .lang a, .lang > span { min-width: 27px; padding-inline: 2px; font-size: 11px; }
  .lang i { display: none; }
}

/* Below ~340px the wordmark, three nav links and the language switch genuinely
   do not fit on one line — English labels are the long case. Wrapping to two
   rows there is honest; squeezing the type any further is not. */
@media (max-width: 344px) {
  .masthead .wrap, .bar .wrap { flex-wrap: wrap; justify-content: center; row-gap: 0; }
  .mast-nav, .bar nav { flex-wrap: wrap; justify-content: center; }
  .masthead .wrap > *, .bar .wrap > * { min-height: 0; }
  .mark, .brand { min-height: 34px; }
}


/* --- Bands ---------------------------------------------------------------- */
.band { padding-block: clamp(60px, 9vw, 118px); }
.band-hero { padding-block: clamp(56px, 8vw, 104px) clamp(30px, 5vw, 52px); text-align: center; }
.band-tint { background: var(--tint); }

.band-hero .eyebrow { display: block; margin-bottom: 20px; }
.band-hero .lede { margin-inline: auto; max-width: 32ch; }

.mid { text-align: center; max-width: 48ch; margin-inline: auto; }
.mid .eyebrow { display: block; margin-bottom: 16px; }
.mid p { color: var(--ink-2); margin-top: 14px; }

/* Huxle's pages are documents rather than a single pitch, so they run as one
   left-aligned column with a lighter rhythm. */
main { padding-block: clamp(30px, 6vw, 52px) clamp(40px, 7vw, 68px); }
body.huxle .band { padding-block: 0; }
.block { margin-top: clamp(40px, 6vw, 64px); }
.block > h2 + p { color: var(--ink-2); margin-top: 12px; }

/* --- Buttons -------------------------------------------------------------- */
.row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.row-mid { justify-content: center; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 500; text-decoration: none;
  border-radius: 980px; padding: 13px 26px; border: 1px solid transparent;
}
body.huxle .btn { font-weight: 600; }
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--hover); }
.btn-ghost { border-color: var(--ink); color: var(--ink); }
.btn-ghost:hover { background: var(--ink); color: var(--paper); }

/* ==========================================================================
   Studio (/)
   ========================================================================== */

/* --- The meter ------------------------------------------------------------
   A paint chip. A large flat patch of the true colour, its measurements set in
   mono underneath, and the twelve as a selectable strip. On white the patch is
   the only saturated thing in view, which is the whole point.
   ------------------------------------------------------------------------- */
.meter { max-width: 560px; margin: 46px auto 0; text-align: left; }

.meter-field {
  height: 300px; border-radius: 20px;
  background: var(--swatch, #C24A38);
  /* An inset hairline rather than a border: a grey border would sit between
     the eye and the colour it is meant to be judging. */
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.07);
}

.meter-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; margin-top: 22px;
}
.meter-name { font-size: 34px; font-weight: 700; letter-spacing: -.028em; line-height: 1; }
.meter-mode {
  font-family: var(--mono); font-size: 11px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-2); white-space: nowrap;
}
.meter-why { color: var(--ink-2); font-size: 16px; margin-top: 12px; }

.meter-vals {
  display: grid; grid-template-columns: repeat(2, 1fr);
  border-top: 1px solid var(--hair); margin-top: 22px;
}
.meter-cell { padding: 13px 0; border-bottom: 1px solid var(--hair); }
.meter-cell:nth-child(odd) { padding-right: 14px; }
.meter-cell:nth-child(even) { padding-left: 14px; border-left: 1px solid var(--hair); }
.meter-cell dt {
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--ink-2);
}
.meter-cell dd {
  font-family: var(--mono); font-size: 17px;
  font-variant-numeric: tabular-nums; color: var(--ink); margin-top: 4px;
}
.meter-cell-wide { grid-column: 1 / -1; padding-left: 0; padding-right: 0; border-left: 0; }

/* Twelve in one row put each chip at 25x30 with a 4px gap — under the 44px
   platform target and under the 8px adjacent-target minimum. Six across in two
   rows gives ~48x44 at 375px and ~87x44 at full width, and it rhymes with the
   six-chip strip used everywhere else. */
.meter-chips { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; margin-top: 20px; }
.chip {
  appearance: none; border: 0; border-radius: 9px; height: 44px;
  cursor: pointer; padding: 0; background: var(--c);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.07);
}
.chip[aria-pressed='true'] { box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--ink); }

.meter-note { color: var(--ink-2); font-size: 14px; margin-top: 24px; text-align: center; }

@media (max-width: 520px) {
  .meter-field { height: 220px; }
  .meter-name { font-size: 27px; }
}

/* --- Shipping -------------------------------------------------------------- */
.ship { display: grid; grid-template-columns: 1fr; gap: 36px; align-items: center; margin-top: 44px; }
.ship-icon { width: 76px; height: 76px; border-radius: 18px; display: block; }
.ship-title { font-size: clamp(30px, 4.2vw, 40px); font-weight: 700;
              letter-spacing: -.03em; line-height: 1; margin-top: 20px; }
.ship-sub { color: var(--ink-2); font-size: 15px; margin-top: 10px; }
.ship p { color: var(--ink-2); margin-top: 20px; max-width: 46ch; }

.specs { border-top: 1px solid var(--hair); margin-top: 26px; }
.specs div { display: flex; gap: 16px; padding: 11px 0; border-bottom: 1px solid var(--hair); }
.specs dt {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-2);
  width: 116px; flex: none; padding-top: 3px;
}
.specs dd { font-size: 15.5px; }

.shots { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.shots img { width: 100%; height: auto; display: block; border-radius: 14px; border: 1px solid var(--hair); }

@media (min-width: 840px) { .ship { grid-template-columns: 1fr 360px; gap: 64px; } }

/* --- Claims ---------------------------------------------------------------- */
.claims { display: grid; grid-template-columns: 1fr; margin-top: 44px; }
.claim { padding: 26px 0; border-top: 1px solid var(--hair); }
.claim:last-child { border-bottom: 1px solid var(--hair); }
.claim .eyebrow { display: block; margin-bottom: 12px; }
.claim h3 { margin-bottom: 10px; }
.claim p { color: var(--ink-2); font-size: 15.5px; max-width: 46ch; }

@media (min-width: 800px) {
  .claims { grid-template-columns: repeat(3, 1fr); column-gap: 34px; }
  .claim { border-bottom: 1px solid var(--hair); }
}

/* --- Contact --------------------------------------------------------------- */
.mailto {
  display: inline-flex; align-items: center; min-height: 44px; margin-top: 10px;
  font-size: clamp(21px, 3.4vw, 32px); font-weight: 700;
  letter-spacing: -.028em; color: var(--ink); text-decoration: none;
  border-bottom: 2px solid var(--hair); padding-bottom: 3px;
}
.mailto:hover { border-bottom-color: var(--ink); }

/* ==========================================================================
   Huxle (/huxle/)
   ========================================================================== */

/* --- The strip ------------------------------------------------------------
   Straight from color_pool (migration 077). If the pool changes this changes
   with it — a stranger who installs must see the colours we advertised, and
   the old site once showed six that had been deleted.
   ------------------------------------------------------------------------- */
.strip { display: flex; gap: 8px; margin: 28px 0 10px; }
.strip div {
  flex: 1; height: 64px; border-radius: 12px;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.07);
}
.strip-note { font-size: 14px; color: var(--ink-2); }

/* --- Steps ---------------------------------------------------------------- */
ol.steps { margin-top: 28px; padding: 0; list-style: none; counter-reset: step; }
ol.steps li {
  counter-increment: step; position: relative;
  padding: 0 0 18px 40px; font-size: 16.5px; line-height: 1.45;
}
ol.steps li::before {
  content: counter(step); position: absolute; left: 0; top: 0;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--hair);
  font-family: var(--mono); font-size: 12px;
  display: flex; align-items: center; justify-content: center; color: var(--ink-2);
}

/* --- Cards ---------------------------------------------------------------- */
.cards { display: grid; grid-template-columns: 1fr; gap: 0; margin-top: 24px; }
.card { padding: 22px 0; border-top: 1px solid var(--hair); }
.card:last-child { border-bottom: 1px solid var(--hair); }
.card h3 { margin-bottom: 8px; }
@media (min-width: 700px) {
  .cards-2 { grid-template-columns: repeat(2, 1fr); column-gap: 34px; }
  .cards-2 .card { border-bottom: 1px solid var(--hair); }
}

/* --- Colour specimens (/huxle/colors) -------------------------------------
   Each swatch carries its own caption, so the ink is chosen per colour and
   hardcoded from measurement in pool.js — five of the twelve need white and
   seven need black, and no single lightness threshold splits them correctly.
   Assuming one "contrasting ink" is exactly the bug that shipped in the app.
   ------------------------------------------------------------------------- */
.specimens { display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 28px; }
@media (min-width: 640px) { .specimens { grid-template-columns: repeat(2, 1fr); } }

.spec { display: flex; flex-direction: column; }
.spec-patch {
  padding: 16px; min-height: 132px; border-radius: 14px;
  display: flex; flex-direction: column; justify-content: space-between;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.07);
}
.spec-name { font-size: 23px; font-weight: 700; letter-spacing: -.018em; }
.spec-vals {
  font-family: var(--mono); font-size: 12px; letter-spacing: .05em;
  font-variant-numeric: tabular-nums; display: flex; flex-wrap: wrap; gap: 4px 14px;
}
.spec-body { padding: 14px 2px 0; }
.spec-tier {
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-2);
}
.spec-why { font-size: 15px; margin-top: 8px; color: var(--ink-2); }

/* --- Q&A (/huxle/support) -------------------------------------------------- */
.qa { margin-top: 26px; border-top: 1px solid var(--hair); }
.qa details { border-bottom: 1px solid var(--hair); }
.qa summary {
  cursor: pointer; padding: 17px 30px 17px 0; position: relative;
  font-weight: 600; font-size: 17px; list-style: none; letter-spacing: -.01em;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
  content: '+'; position: absolute; right: 4px; top: 15px;
  font-size: 20px; font-weight: 400; color: var(--ink-2); line-height: 1;
}
.qa details[open] summary::after { content: '−'; }
.qa .ans { padding: 0 0 20px; color: var(--ink-2); font-size: 16px; }
.qa .ans p + p { margin-top: 12px; }

/* --- Legal ---------------------------------------------------------------- */
.legal { font-size: 16.5px; }
.legal h2 { margin-top: 36px; }
.legal h2 + p, .legal h2 + ul { margin-top: 12px; }
.legal p + p, .legal p + ul, .legal ul + p { margin-top: 12px; }
.legal ul { padding-left: 22px; }
.legal li + li { margin-top: 6px; }
.legal .updated { color: var(--ink-2); font-size: 14px; margin-top: 8px; }
/* An address or URL that IS the whole line is a target, not prose, so it gets
   a 44px height. Marked with a class rather than :only-child — that selector
   ignores text nodes, so it also matched links sitting inside a sentence and
   inflated their line box. */
a.target {
  display: inline-flex; align-items: center; min-height: 44px;
}

/* --- Press ---------------------------------------------------------------- */
.facts { border-top: 1px solid var(--hair); margin-top: 24px; }
.facts div {
  display: grid; grid-template-columns: 1fr; gap: 2px;
  padding: 13px 0; border-bottom: 1px solid var(--hair);
}
.facts dt {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-2);
}
.facts dd { font-size: 16px; }
@media (min-width: 620px) {
  .facts div { grid-template-columns: 210px 1fr; gap: 18px; align-items: baseline; }
}

.gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; margin-top: 24px; }
@media (min-width: 700px) { .gallery { grid-template-columns: repeat(3, 1fr); } }
.gallery img {
  width: 100%; height: auto; display: block; border-radius: 12px;
  border: 1px solid var(--hair);
}
.gallery figcaption { font-size: 13px; color: var(--ink-2); margin-top: 8px; }

/* --- Not found (/404, /zh/404) ---------------------------------------------
   The whole domain is seven pages per language, so the not-found page prints
   all of them instead of offering one way home. A list this short is a real
   answer; a "go to the homepage" button makes the visitor start over.
   ------------------------------------------------------------------------- */
.map { border-top: 1px solid var(--hair); margin-top: 10px; }
.map a {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 1px 14px;
  padding: 11px 0; min-height: 44px;
  border-bottom: 1px solid var(--hair); text-decoration: none;
}
.map-t { font-size: 17px; font-weight: 600; letter-spacing: -.012em; }
.map-d { font-size: 15px; color: var(--ink-2); }
/* Wide enough for two columns, the titles line up and the list reads as an
   index rather than a ragged pile. Same 210px label column as .facts. */
@media (min-width: 620px) {
  .map a { display: grid; grid-template-columns: 210px 1fr; gap: 18px; align-items: baseline; }
}
.map a:hover .map-t {
  text-decoration: underline; text-decoration-color: var(--ink);
  text-underline-offset: 3px;
}
html[lang^="zh"] .map-t { letter-spacing: 0; }

/* --- Footer ---------------------------------------------------------------- */
.foot { border-top: 1px solid var(--hair); margin-top: clamp(44px, 7vw, 78px); }
.foot .wrap {
  display: flex; flex-wrap: wrap; gap: 4px 20px;
  justify-content: space-between; align-items: center;
  padding-block: 18px 30px;
}
.foot a, .foot span {
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-2); text-decoration: none;
}
/* The footer links were 17px tall. Same treatment as the header nav: padding
   makes the target, not the type size. */
.foot a { display: inline-flex; align-items: center; min-height: 44px; padding-inline: 2px; }
.foot-links { gap: 6px 16px; }
.foot a:hover { color: var(--ink); }
.foot-links { display: flex; flex-wrap: wrap; gap: 18px; }
