/* ============================================================
   Useful Words — editorial reference styles
   A bilingual EN / ZH companion. One-handed, portrait-first.
   ============================================================ */

/* --- Reset (modern, minimal) --- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { line-height: 1.5; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* Fraunces is self-hosted as a variable woff2 (italic + roman, latin
   only — ~270 KB total). Preloaded in the HTML so it has a head start
   on the page paint, and using font-display: block here so the
   editorial type is the first thing the user sees (it's the
   signature). IBM Plex Sans and Noto Sans/Serif TC stay on Google
   Fonts with font-display: optional. */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 400 600;
  font-display: optional;
  src: url("../fonts/Fraunces-normal-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fraunces";
  font-style: italic;
  font-weight: 400 600;
  font-display: optional;
  src: url("../fonts/Fraunces-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
img, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: none; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

/* --- Tokens — Apple HIG semantic colors (light mode default) --- */
:root {
  color-scheme: light dark;

  /* Backgrounds */
  --bg:               #ffffff;            /* systemBackground */
  --bg-grouped:       #f2f2f7;            /* systemGroupedBackground */
  --bg-secondary:     #f2f2f7;            /* secondarySystemBackground */
  --bg-tertiary:      #ffffff;            /* tertiarySystemBackground */
  /* Card surface — pure white in light gives meaningful contrast
     against the off-white body; in dark we keep the subtle lift
     from secondary so the coloured borders still do the heavy
     lifting and the card doesn't pop too aggressively. */
  --card-bg:          #ffffff;

  /* Labels (foreground) — alphas raised slightly from iOS native values
     so secondary text on white meets WCAG AA contrast (4.5:1). */
  --label:            rgba(0, 0, 0, 1);
  --label-2:          rgba(60, 60, 67, 0.74);   /* ~4.7:1 on white */
  --label-3:          rgba(60, 60, 67, 0.55);   /* decorative use only */
  --label-4:          rgba(60, 60, 67, 0.18);

  /* Separators */
  --separator:        rgba(60, 60, 67, 0.29);
  --separator-opaque: #c6c6c8;

  /* Fills (for chips, controls) */
  --fill:             rgba(120, 120, 128, 0.20);
  --fill-2:           rgba(120, 120, 128, 0.16);
  --fill-3:           rgba(118, 118, 128, 0.12);
  --fill-4:           rgba(116, 116, 128, 0.08);

  /* Apple HIG system colors — one per topic, deepened from native
     values so 12–13px tinted text passes 4.5:1 contrast on white.
     JS sets `--tint` to the active topic's value so the whole UI
     re-tints as the user moves between topics. */
  --tint-society-culture:    #3634A3;  /* systemIndigo */
  --tint-education-learning: #7D3AA6;  /* systemPurple */
  --tint-environment:        #1F7A36;  /* systemGreen */
  --tint-technology-media:   #0a6bd6;  /* systemBlue */
  --tint-health-lifestyle:   #C4143A;  /* systemPink */
  --tint-work-economy:       #BD4F00;  /* systemOrange */
  --tint-concepts:           #006E9A;  /* systemTeal */
  --tint-transitions:        #7F6545;  /* systemBrown accessible — calm, connecting */

  --tint:              var(--tint-society-culture);  /* default; JS overrides */
  --tint-on:           #ffffff;
  --tint-soft:         color-mix(in srgb, var(--tint), transparent 85%);

  /* Human (forhuman.ca) brand terracotta — used as a stable accent
     for the wordmark in both the masthead and the topbar. Picked the
     deeper of forhuman.ca's two terracotta shades so it clears
     WCAG AA (4.5:1) on white when used as small text. */
  --brand-terracotta:  #A0603F;

  /* Search match highlight */
  --hl:               rgba(255, 204, 0, 0.42);  /* systemYellow tint */

  /* Legacy alias names used through the stylesheet — pointed to new tokens */
  --paper:            var(--bg);
  --paper-2:          var(--bg-secondary);
  --paper-tint:       var(--bg);
  --ink:              var(--label);
  --ink-2:            var(--label-2);
  --ink-mute:         var(--label-3);
  --rule:             var(--separator);
  --rule-soft:        var(--separator);
  --accent:           var(--tint);
  --accent-2:         var(--tint);
  --accent-soft:      var(--tint-soft);

  /* Type — webfont first; if the optional load doesn't finish in time
     the page sits permanently on the system fallback for this session */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-sans:    "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
  --font-zh-serif: "Noto Serif TC", "Songti TC", "PMingLiU", serif;
  --font-zh-sans:  "Noto Sans TC", "PingFang TC", "Heiti TC", sans-serif;

  /* Geometry */
  --max-w:        680px;
  --pad-x:        20px;
  --topbar-h:     52px;
  --tabbar-h:     58px;
  --radius:       14px;

  /* Motion */
  --ease:         cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:               #000000;            /* systemBackground dark */
    --bg-grouped:       #000000;
    --bg-secondary:     #1c1c1e;            /* secondarySystemBackground dark */
    --bg-tertiary:      #2c2c2e;            /* tertiarySystemBackground dark */
    --card-bg:          #1c1c1e;            /* matches --bg-secondary — subtle lift on black */

    --label:            rgba(255, 255, 255, 1);
    --label-2:          rgba(235, 235, 245, 0.60);
    --label-3:          rgba(235, 235, 245, 0.30);
    --label-4:          rgba(235, 235, 245, 0.18);

    --separator:        rgba(84, 84, 88, 0.65);
    --separator-opaque: #38383a;

    --fill:             rgba(120, 120, 128, 0.36);
    --fill-2:           rgba(120, 120, 128, 0.32);
    --fill-3:           rgba(118, 118, 128, 0.24);
    --fill-4:           rgba(118, 118, 128, 0.18);

    /* Dark-mode tints — brightened from Apple's standard system
       colours so each clears 4.5:1 contrast on bg-tertiary (the card
       surface category headings sit on). Still recognisable as their
       systemColor cousins. */
    --tint-society-culture:    #9D9CFF;   /* brighter indigo */
    --tint-education-learning: #D78EFF;   /* brighter purple */
    --tint-environment:        #30D158;   /* systemGreen dark */
    --tint-technology-media:   #5BA8FF;   /* brighter blue */
    --tint-health-lifestyle:   #FF6080;   /* brighter pink */
    --tint-work-economy:       #FF9F0A;   /* systemOrange dark */
    --tint-concepts:           #64D2FF;   /* systemTeal dark */
    --tint-transitions:        #CFA37A;   /* brown — replaces gray */

    --tint:              var(--tint-society-culture);
    --tint-on:           #ffffff;
    --tint-soft:         color-mix(in srgb, var(--tint), transparent 78%);
    --brand-terracotta:  #D08B62;   /* slightly brighter for dark */

    --hl:               rgba(255, 214, 10, 0.36);  /* systemYellow dark */
  }
}

/* --- Page --- */
/* Grouped iOS-style background so the rounded cards stand out. */
html { background: var(--bg-grouped); }
body {
  font-family: var(--font-sans);
  color: var(--label);
  background: var(--bg-grouped);
  min-height: 100dvh;
  /* Bottom stack on mobile, top→bottom: chips (when visible) → tabbar
     → topbar (brand + search). All in the thumb zone. */
  padding-bottom: calc(var(--topbar-h) + var(--tabbar-h) + env(safe-area-inset-bottom));
  transition: padding-bottom 0.2s var(--ease);
}
body.chips-visible {
  padding-bottom: calc(var(--topbar-h) + var(--tabbar-h) + 148px + env(safe-area-inset-bottom) + 32px);
}

/* --- Skip links --- */
.skip {
  position: absolute;
  left: -9999px;
  top: 8px;
  background: var(--label);
  color: var(--bg);
  padding: 8px 12px;
  border-radius: 8px;
  z-index: 100;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
}
.skip:focus { left: 8px; }
.skip + .skip:focus { left: 180px; }

/* ============================================================
   Topbar — sticky search
   ============================================================ */
.topbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 28;  /* below tabbar (30) and chips (35) */
  display: flex;
  align-items: center;
  gap: 10px;
  height: calc(var(--topbar-h) + env(safe-area-inset-bottom));
  padding: 0 var(--pad-x) env(safe-area-inset-bottom);
  background: color-mix(in oklab, var(--bg) 86%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-top: 0.5px solid var(--separator);
}

/* Random-entry shuffler. Lives at the bottom-left of the viewport as
   its own fixed element — no pill, no border. A die emoji sits in
   the middle, golden sun rays radiate behind it and rotate slowly,
   and the die jitters periodically as if being shaken in a hand.
   On mobile it tucks left of the transitions chips bubble (which is
   narrowed accordingly); on desktop it sits in the bottom-left
   corner inside the sidebar zone. */
.btn-random {
  --glow-color: rgba(242, 161, 0, 0.5);
  position: fixed;
  left: 12px;
  bottom: calc(var(--topbar-h) + var(--tabbar-h) + env(safe-area-inset-bottom) + 12px);
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  z-index: 36;  /* above chips (35), tabbar (30), topbar (28) */
  -webkit-tap-highlight-color: transparent;
}

.btn-random__glow {
  position: absolute;
  inset: -10px;  /* let the glow bleed past the tap target */
  border-radius: 50%;
  background: radial-gradient(circle, var(--glow-color) 0%, transparent 65%);
  animation: btn-random-pulse 2.6s ease-in-out infinite;
  pointer-events: none;
}

.btn-random__die {
  position: relative;
  font-size: 24px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Modern OSes render emoji with their colour glyphs; this nudges
     monochrome fallbacks to stay legible. */
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  animation: btn-random-shake 4.2s ease-in-out infinite;
  z-index: 1;
}

.btn-random:hover .btn-random__glow { animation-duration: 1.4s; }
.btn-random:hover .btn-random__die { animation-duration: 0.6s; }
.btn-random:active .btn-random__die { transform: scale(0.92); }
.btn-random:focus-visible {
  outline: 2px solid var(--label);
  outline-offset: 4px;
  border-radius: 50%;
}

/* Soft golden breathe — opacity + scale pulse together so the glow
   feels alive without rotating. */
@keyframes btn-random-pulse {
  0%, 100% { opacity: 0.55; transform: scale(0.92); }
  50%      { opacity: 1;    transform: scale(1.12); }
}

/* Shake idles for most of the cycle then bursts into a chaotic
   jitter — translation + rotation on irregular intervals so it
   doesn't read as a clean sinusoid. */
@keyframes btn-random-shake {
  0%, 70%, 100% { transform: translate(0, 0) rotate(0deg); }
  72% { transform: translate(-1px, 1px) rotate(-9deg); }
  75% { transform: translate(2px, -1px) rotate(7deg); }
  77% { transform: translate(-2px, -1px) rotate(-6deg); }
  80% { transform: translate(1px, 2px) rotate(10deg); }
  82% { transform: translate(-2px, 0) rotate(-8deg); }
  85% { transform: translate(1px, -2px) rotate(5deg); }
  87% { transform: translate(-1px, 1px) rotate(-4deg); }
  90% { transform: translate(0, -1px) rotate(2deg); }
  93% { transform: translate(1px, 0) rotate(-1deg); }
}

@media (prefers-color-scheme: dark) {
  .btn-random {
    --glow-color: rgba(255, 201, 60, 0.45);
  }
}

@media (min-width: 760px) {
  /* Desktop: anchor to the bottom-left corner, inside the sidebar zone. */
  .btn-random {
    left: 16px;
    bottom: 16px;
  }
}

.topbar__brand {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  flex-shrink: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 17px;
  letter-spacing: -0.01em;
  font-variation-settings: "opsz" 14, "SOFT" 50;
}
.topbar__brand-name { color: var(--brand-terracotta); }

/* Search — iOS rounded field on systemFill background */
.search {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  padding: 0 10px 0 12px;
  background: var(--fill-3);
  border: 0;
  border-radius: 10px;
  transition: background 0.15s var(--ease);
}
.search:focus-within {
  background: var(--fill);
  /* Neutral focus ring — never borrows a section tint. --label flips
     between near-black (light) and white (dark), so the ring is
     high-contrast on either fill regardless of which topic is current. */
  box-shadow: inset 0 0 0 3px var(--label);
  outline: none;
}
.search__icon { color: var(--label-2); flex-shrink: 0; }
.search:focus-within .search__icon { color: var(--label); }
.search__input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  font-size: 15px;
  color: var(--ink);
  min-width: 0;
}
.search__input::placeholder { color: var(--ink-mute); opacity: 0.9; }
.search__input::-webkit-search-cancel-button { display: none; }
.search__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  color: var(--ink-mute);
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
.search__clear:hover { color: var(--ink); background: var(--accent-soft); }

/* ============================================================
   Content
   ============================================================ */
.content {
  position: relative;
  z-index: 1;
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--pad-x);
}

/* --- Masthead --- */
.masthead {
  padding: 48px 0 28px;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 28px;
}
.masthead__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  font-size: clamp(44px, 13vw, 78px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  font-variation-settings: "opsz" 100, "SOFT" 30;
  color: var(--brand-terracotta);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.masthead__title-zh {
  font-family: var(--font-zh-serif);
  font-style: normal;
  font-weight: 500;
  font-size: 0.5em;
  color: var(--label-2);
  letter-spacing: 0.04em;
}
.masthead__sub {
  margin-top: 18px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 38ch;
}

/* ============================================================
   Landing topic grid — visual index of all topics with their tints
   ============================================================ */
.topics {
  margin: 32px 0 12px;
}
.topics__header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 4px 14px;
}
.topics__heading {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 22px;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--label);
  font-variation-settings: "opsz" 60, "SOFT" 40;
}
.topics__heading-zh {
  font-family: var(--font-zh-serif);
  font-size: 14px;
  color: var(--label-2);
  letter-spacing: 0.02em;
}

.topics__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  /* Reserve height so JS rendering 8 cards doesn't push later
     content down (eliminates a big chunk of CLS). */
  min-height: 460px;
}
@media (min-width: 680px) {
  .topics__grid { min-height: 130px; }
}

.topic-card {
  position: relative;
  display: flex;
  align-items: center;
  padding: 14px 16px;
  background: var(--card-bg);
  border: 2px solid var(--tint);
  border-radius: 14px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s var(--ease), background 0.18s var(--ease), color 0.18s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.topic-card:hover,
.topic-card:focus-visible {
  background: var(--tint);
  outline: none;
}
.topic-card:hover .topic-card__en,
.topic-card:focus-visible .topic-card__en {
  color: var(--bg);
}
.topic-card:hover .topic-card__zh,
.topic-card:focus-visible .topic-card__zh {
  color: color-mix(in srgb, var(--bg), transparent 12%);
}
.topic-card:active {
  transform: scale(0.985);
}

.topic-card__text {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.topic-card__en {
  font-family: var(--font-sans);
  font-size: 17px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--label);
  transition: color 0.18s var(--ease);
}
.topic-card__zh {
  font-family: var(--font-zh-sans);
  font-size: 13px;
  color: var(--label-2);
  letter-spacing: 0.02em;
  transition: color 0.18s var(--ease);
}

/* Wider viewports: 4 columns instead of 2 */
@media (min-width: 680px) {
  .topics__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Onboarding hint — small, dismissable once user interacts */
.hint {
  margin: 14px 4px 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--label-2);
  transition: opacity 0.35s var(--ease), max-height 0.35s var(--ease), margin-top 0.35s var(--ease);
}
.hint[hidden] { display: none; }
.hint--dismissed {
  opacity: 0;
  max-height: 0;
  margin-top: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Word of the day — daily entry surfaced as a single tappable card.
   The card itself is the link; topic name appears as a small inline
   tag at the bottom. No eyebrow / button-link footer. */
.wod {
  margin: 22px 0 0;
  /* Reserve approximate post-render height. */
  min-height: 210px;
}
.wod[hidden] { display: none; }
.wod__heading {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--label);
  margin: 0 4px 12px;
  font-variation-settings: "opsz" 60, "SOFT" 40;
}
.wod__heading span {
  font-family: var(--font-zh-serif);
  font-style: normal;
  font-weight: 500;
  font-size: 14px;
  color: var(--label-2);
  letter-spacing: 0.02em;
  margin-left: 6px;
}
.wod__card {
  display: block;
  padding: 14px 16px 16px;
  background: var(--card-bg);
  border: 2px solid var(--wod-tint, var(--tint));
  border-radius: 14px;
  color: inherit;
  text-decoration: none;
  transition: background 0.18s var(--ease), color 0.18s var(--ease), transform 0.15s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.wod__card:hover,
.wod__card:focus-visible {
  background: var(--wod-tint, var(--tint));
  outline: none;
}
.wod__card:hover .wod__word,
.wod__card:hover .wod__def,
.wod__card:hover .wod__topic,
.wod__card:focus-visible .wod__word,
.wod__card:focus-visible .wod__def,
.wod__card:focus-visible .wod__topic {
  color: var(--bg);
}
.wod__card:hover .wod__pos,
.wod__card:hover .wod__def-zh,
.wod__card:hover .wod__topic-name,
.wod__card:focus-visible .wod__pos,
.wod__card:focus-visible .wod__def-zh,
.wod__card:focus-visible .wod__topic-name {
  color: color-mix(in srgb, var(--bg), transparent 12%);
}
.wod__card:active {
  transform: scale(0.99);
}
.wod__word-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.wod__word {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 500;
  font-size: 26px;
  line-height: 1.05;
  letter-spacing: -0.018em;
  color: var(--label);
  font-variation-settings: "opsz" 28, "SOFT" 40;
}
.wod__pos {
  font-family: var(--font-sans);
  font-style: italic;
  font-size: 13px;
  color: var(--label-2);
}
.wod__def {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.5;
  color: var(--label);
  margin-top: 6px;
}
.wod__def-zh {
  font-family: var(--font-zh-sans);
  font-size: 13px;
  color: var(--label-2);
  margin-top: 2px;
}
.wod__topic {
  display: inline-block;
  margin-top: 10px;
  font-size: 12px;
  font-weight: 500;
  color: var(--label-2);
  letter-spacing: 0.01em;
}
.wod__topic-name {
  color: var(--wod-tint, var(--tint));
  font-weight: 600;
}

/* Recent words — shows when user has navigated to specific entries */
.recent {
  margin: 26px 0 -6px;
}
.recent__header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 4px 12px;
}
.recent__heading {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--label);
  font-variation-settings: "opsz" 60, "SOFT" 40;
}
.recent__heading-zh {
  font-family: var(--font-zh-serif);
  font-size: 13px;
  color: var(--label-2);
  letter-spacing: 0.02em;
}
.recent__list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.recent-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--bg-tertiary);
  border: 0.5px solid var(--separator);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  color: var(--label);
  text-decoration: none;
  font-variation-settings: "opsz" 14, "SOFT" 50;
  transition: background 0.15s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.recent-chip:hover {
  background: color-mix(in srgb, var(--bg-tertiary), var(--tint) 6%);
}
.recent-chip__pos {
  font-family: var(--font-sans);
  font-style: italic;
  font-size: 11px;
  color: var(--label-2);
  letter-spacing: 0.02em;
}

/* Per-topic intro line under the section title */
.section__intro {
  margin: 0 4px 12px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--label-2);
  max-width: 56ch;
}
.section__intro--zh {
  font-size: 13px;
  margin-top: -8px;
  color: var(--label-2);
}

/* Search summary — appears while a query is active */
.search-summary {
  margin: 18px 4px 4px;
  font-size: 13px;
  color: var(--label-2);
  font-feature-settings: "tnum";
}
.search-summary[hidden] { display: none; }
.search-summary strong {
  color: var(--label);
  font-weight: 600;
}

/* --- Section --- */
/* --- Topic section (= primary page) --- */
.section {
  scroll-margin-top: 16px;
  padding-top: 12px;
  margin-top: 18px;
  /* Virtualize off-screen sections so the browser doesn't pay to lay
     them out until the user scrolls them into view. Reduces CLS by
     reserving space upfront. */
  content-visibility: auto;
  contain-intrinsic-size: 0 4000px;
}

.section__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 8px 4px 16px;
  position: relative;
}
.section__title {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(34px, 8.5vw, 50px);
  line-height: 1;
  letter-spacing: -0.015em;
  font-variation-settings: "opsz" 100, "SOFT" 30;
  color: var(--section-tint, var(--label));
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
}
.section__title-zh {
  font-family: var(--font-zh-serif);
  font-style: normal;
  font-weight: 500;
  font-size: 0.46em;
  color: var(--label-2);
  letter-spacing: 0.04em;
}
.section__count {
  font-family: var(--font-sans);
  font-feature-settings: "tnum";
  font-size: 13px;
  color: var(--label-2);
  white-space: nowrap;
  flex-shrink: 0;
}

/* --- Category card: a grouped rounded container of entries
   (iOS-style "Settings"-app feel). Border + heading colour pick up
   the parent topic's tint so each card carries its topic identity
   even when looked at in isolation. --- */
.category {
  scroll-margin-top: 16px;
  background: var(--card-bg);
  border-radius: 14px;
  margin: 14px 0 0;
  overflow: hidden;  /* clips hairline dividers + active highlights */
  border: 2px solid var(--cat-tint, var(--separator));
}
.category__header {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  padding: 14px 16px 10px;
  border-bottom: 0.5px solid var(--separator);
  background: transparent;
}
.category__name {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.04em;
  line-height: 1.1;
  color: var(--cat-tint, var(--label-2));
  text-transform: uppercase;
}
.category__name-zh {
  font-family: var(--font-zh-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 12px;
  color: var(--label-2);
  letter-spacing: 0.02em;
}
.category__count {
  margin-left: auto;
  font-size: 12px;
  color: var(--label-2);
  font-feature-settings: "tnum";
}

/* --- Chips column: a vertical bubble that floats above the
   transitions tab when the transitions section is dominant. Shows
   ~2.5 pills so the user knows there are more categories to scroll.
   Tail points at the active primary tab. Bubble + tail share one
   filter:drop-shadow so they read as a single shape. --- */
.chips {
  position: fixed;
  /* 12 (gutter) + 48 (die width) + 12 (gap) = 72px. Matches the
     "equal gap" placement of the die: same gap from screen edge,
     from tabbar above, and between die and bubble. */
  left: 72px;
  right: 12px;
  bottom: calc(var(--topbar-h) + var(--tabbar-h) + env(safe-area-inset-bottom) + 12px);
  z-index: 35;

  background: var(--bg-secondary);
  border: 0;
  border-radius: 18px;
  filter:
    drop-shadow(0 14px 30px rgba(0, 0, 0, 0.18))
    drop-shadow(0 4px 10px rgba(0, 0, 0, 0.10));

  opacity: 0;
  pointer-events: none;
  transform: translateY(6px);
  transition:
    opacity 0.2s var(--ease),
    transform 0.2s var(--ease);
}
@media (prefers-color-scheme: dark) {
  .chips {
    background: var(--bg-tertiary);
    filter:
      drop-shadow(0 14px 30px rgba(0, 0, 0, 0.65))
      drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45));
  }
}
.chips[hidden] { display: none; }
.chips.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: none;
}

.chips__list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px;
  /* ~2.5 pills visible — clear "more below" affordance. */
  max-height: 116px;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scroll-padding-block: 8px;
  -ms-overflow-style: none;
  scrollbar-width: none;
  border-radius: inherit;
}
.chips__list::-webkit-scrollbar { display: none; }

/* Bubble tail — clean CSS triangle, same color as the bubble. */
.chips::after {
  content: "";
  position: absolute;
  bottom: -8px;
  left: var(--chevron-x, 50%);
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 8px solid var(--bg-secondary);
  transform: translateX(-50%);
  pointer-events: none;
  transition: left 0.28s var(--ease);
}
@media (prefers-color-scheme: dark) {
  .chips::after { border-top-color: var(--bg-tertiary); }
}

.chip {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 36px;
  padding: 7px 12px;
  border-radius: 10px;
  border: 0;
  background: transparent;
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 13px;
  line-height: 1.3;
  color: var(--label);
  white-space: normal;
  text-align: left;
  scroll-snap-align: start;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
}
.chip:hover { background: var(--fill-3); }
.chip:active { background: var(--fill-2); }
.chip[aria-current="true"] {
  /* Transitions tint (systemBrown) for the active chip; flip text
     to black in dark mode where the brown variant is lighter. */
  background: var(--tint);
  color: #fff;
}
@media (prefers-color-scheme: dark) {
  .chip[aria-current="true"] { color: #000; }
}

/* ============================================================
   Entry — the dictionary card
   ============================================================ */
.entries { display: block; }
.entry {
  display: block;
  padding: 16px 16px 18px;
  border-bottom: 0.5px solid var(--separator);
  scroll-margin-top: 16px;
  position: relative;
}
.entry:last-child { border-bottom: 0; }
.entry.is-target {
  animation: flash 1.4s var(--ease);
}
/* Gold flash — matches the die's halo so a "you landed here" cue
   reads as the same visual family as the shuffler that often brings
   you here. Independent of the section tint so the cue doesn't morph
   with topic. */
@keyframes flash {
  0%   { background: transparent; }
  18%  { background: rgba(242, 161, 0, 0.18); }
  100% { background: transparent; }
}
@media (prefers-color-scheme: dark) {
  @keyframes flash {
    0%   { background: transparent; }
    18%  { background: rgba(255, 201, 60, 0.16); }
    100% { background: transparent; }
  }
}

.entry__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin-bottom: 6px;
}
.entry__word {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(24px, 6vw, 30px);
  line-height: 1.05;
  letter-spacing: -0.018em;
  color: var(--label);
  font-variation-settings: "opsz" 28, "SOFT" 40;
}
.entry__pos {
  font-family: var(--font-sans);
  font-style: italic;
  font-size: 13px;
  color: var(--label-2);
  letter-spacing: 0.02em;
  line-height: 1.1;
  align-self: flex-end;
  margin-bottom: 4px;
}
.entry__ipa {
  font-family: var(--font-sans);
  font-style: normal;
  font-size: 13px;
  font-weight: 400;
  color: var(--label-2);
  letter-spacing: 0.01em;
  line-height: 1.1;
  align-self: flex-end;
  margin-bottom: 4px;
}
.entry__collocations {
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--label);
}
.entry__collocations-label {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 13px;
  color: var(--label-2);
  margin-right: 6px;
}
.entry__word--mark { color: var(--tint); }

.entry__def { margin: 4px 0 6px; }
.entry__def-en {
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
}
.entry__def-zh {
  font-family: var(--font-zh-sans);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
  margin-top: 2px;
}

.entry__examples {
  margin-top: 12px;
  padding-left: 14px;
  border-left: 2px solid var(--rule-soft);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.entry__example { display: block; }
.entry__example-en {
  font-family: var(--font-sans);
  font-style: italic;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-2);
}
.entry__example-zh {
  font-family: var(--font-zh-sans);
  font-size: 14px;
  line-height: 1.55;
  color: var(--ink-2);
  margin-top: 1px;
}

/* Cross-references (see also + also useful for) sit in a "metadata
   footer" below the entry's main content. A hairline rule + smaller,
   muted scale demotes them so the eye reads them as supplementary
   navigation rather than core lexical info. */
.entry__see {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 0.5px solid var(--separator);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}
.entry__see-label {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 400;
  color: var(--label-2);
  margin-right: 2px;
}
.see-chip {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: transparent;
  font-size: 12px;
  color: var(--ink);
  font-style: italic;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14, "SOFT" 50;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}
.see-chip:hover, .see-chip:focus-visible {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

/* "Also Tagged Here" — at the bottom of each topic, a small surface
   listing words living in OTHER topics that are tagged with this
   one. Discoverability cross-reference. */
.tagged-here {
  margin-top: 18px;
  padding: 14px 16px 16px;
  background: var(--card-bg);
  border: 0.5px solid var(--separator);
  border-radius: 14px;
}
.tagged-here__heading {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.1;
  color: var(--label-2);
  margin-bottom: 10px;
}
.tagged-here__zh {
  font-family: var(--font-zh-sans);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.02em;
  text-transform: none;
  margin-left: 6px;
  color: var(--label-2);
}
.tagged-here__list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.tagged-chip {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 12px;
  border-radius: 999px;
  background: transparent;
  border: 0.5px solid var(--separator);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  color: var(--label);
  text-decoration: none;
  font-variation-settings: "opsz" 14, "SOFT" 50;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.tagged-chip:hover {
  background: color-mix(in srgb, var(--bg-tertiary), var(--also-tint, var(--tint)) 8%);
  border-color: var(--also-tint, var(--tint));
}

/* "Also useful for…" — soft cross-reference under entries whose
   meaning meaningfully spans multiple topics. The link picks up
   each target topic's tint as an underline color. */
.entry__also-in {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 0.5px solid var(--separator);
  font-size: 12px;
  line-height: 1.9;  /* allow pills room to breathe inline */
  color: var(--label-2);
}
/* When the see-also block is directly above, the entry already has
   its hairline footer; tuck the also-useful row in tighter and skip
   a second divider so the cross-ref area reads as one unit. */
.entry__see + .entry__also-in {
  margin-top: 6px;
  padding-top: 0;
  border-top: 0;
}
.entry__also-link {
  display: inline-flex;
  align-items: center;
  padding: 1px 9px;
  border: 2px solid var(--also-tint, var(--tint));
  border-radius: 999px;
  background: transparent;
  color: var(--label);
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.entry__also-link:hover, .entry__also-link:focus-visible {
  background: var(--also-tint, var(--tint));
  color: var(--bg);
  outline: none;
}

/* Search highlight */
mark.hl {
  background: var(--hl);
  color: inherit;
  padding: 0 2px;
  border-radius: 2px;
}

/* Hidden entries during filter */
.entry[hidden], .category[hidden], .section[hidden] { display: none; }

/* Empty state */
.empty {
  text-align: center;
  padding: 80px 20px 40px;
}
.empty__title {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 36px;
  line-height: 1;
  color: var(--ink);
  font-variation-settings: "opsz" 60;
}
.empty__sub {
  margin-top: 10px;
  color: var(--ink-2);
  font-size: 14px;
}

/* Colophon */
.colophon {
  margin-top: 60px;
  padding: 28px 0 20px;
  border-top: 1px solid var(--rule);
  text-align: center;
  font-size: 13px;
  color: var(--ink-2);
}
.colophon a {
  color: var(--ink-2);
  border-bottom: 1px solid var(--rule);
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.colophon a:hover,
.colophon a:focus-visible {
  color: var(--brand-terracotta);
  border-color: var(--brand-terracotta);
  outline: none;
}
.colophon__meta {
  margin-top: 6px;
  font-size: 12px;
}

/* ============================================================
   Bottom tab bar — the thumb-zone nav (iOS UITabBar feel)
   ============================================================ */
/* The bottom primary nav holds 8 tabs but on a 390-wide viewport
   only 4-5 fit. The scrollable area + edge fade gradient + the
   half-cut next tab together signal "scroll for more". */
.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--topbar-h) + env(safe-area-inset-bottom));
  z-index: 30;
  display: flex;
  align-items: stretch;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 12px;
  height: var(--tabbar-h);
  padding: 0;
  background: color-mix(in oklab, var(--bg) 86%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-top: 0.5px solid var(--separator);
  -ms-overflow-style: none;
  scrollbar-width: none;
  /* Mask the leading/trailing edges so the next tab fades in/out
     rather than being chopped off — clearer scroll affordance. */
  mask-image: linear-gradient(to right, transparent 0, black 16px, black calc(100% - 16px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0, black 16px, black calc(100% - 16px), transparent 100%);
}
.tabbar::-webkit-scrollbar { display: none; }

/* Hidden by default — mobile uses the dropup chips bubble. The
   @media (min-width: 760px) block below turns it into a nested
   sidebar sub-list. */
.tab-subnav { display: none; }


.tab {
  position: relative;
  flex: 0 0 auto;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0 12px;
  min-width: 74px;  /* lets 5 tabs peek into a 390-wide viewport */
  color: var(--label-2);
  font-family: var(--font-sans);
  transition: color 0.15s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.tab__en {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 12px;
  line-height: 1;
  letter-spacing: -0.005em;
}
.tab__zh {
  font-family: var(--font-zh-sans);
  font-style: normal;
  font-weight: 400;
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.04em;
  opacity: 0.85;
}
.tab:hover { color: var(--label); }
.tab[aria-current="true"] {
  color: var(--tint);
}
.tab[aria-current="true"]::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translateX(-50%);
  width: 22px;
  height: 2px;
  background: var(--tint);
  border-radius: 2px;
}

/* Tint dot — only shown in the desktop sidebar layout (≥760 px).
   On mobile the active state is signalled by the underline above
   and the dot would be clutter. */
.tab__dot {
  display: none;
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: var(--tab-tint, var(--label-2));
  flex-shrink: 0;
}

/* ============================================================
   Desktop / landscape — left sidebar instead of bottom stack.
   Vertical real estate is precious on landscape; horizontal is
   plentiful. Move the brand + search + topics into a fixed left
   sidebar, drop the dropup chips overlay, and slide main content
   to the right of the sidebar.
   ============================================================ */
@media (min-width: 760px) {
  :root {
    --pad-x: 36px;
    --max-w: 720px;
    --sidebar-w: 248px;
  }

  body {
    padding-bottom: 0;
  }
  body.chips-visible { padding-bottom: 0; }

  /* One continuous sidebar surface for the brand + search + topics —
     painted via a body::before so the background and the right
     border don't get broken at the seam between the topbar and the
     tabbar inside it. */
  body::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    background: var(--bg-grouped);
    border-right: 0.5px solid var(--separator);
    z-index: 27;
    pointer-events: none;
  }

  /* Sidebar surface — brand + search at top, topic list below */
  .topbar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: auto;
    width: var(--sidebar-w);
    height: auto;
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
    padding: 22px 18px 14px;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: 0;
    border-right: 0;
    z-index: 28;
  }
  .topbar__brand {
    font-size: 20px;
    font-weight: 700;  /* qualifies as "large text" for AA contrast */
  }
  .topbar__brand-name { font-size: 20px; font-weight: 700; }
  .search {
    width: 100%;
    height: 36px;
  }

  /* Tab list — vertical, scrollable if needed, stacked below the
     brand + search on the sidebar. */
  .tabbar {
    position: fixed;
    top: 124px;  /* below brand + search */
    left: 0;
    right: auto;
    bottom: 0;
    width: var(--sidebar-w);
    height: auto;
    flex-direction: column;
    align-items: stretch;
    overflow-x: hidden;
    overflow-y: auto;
    scroll-snap-type: none;
    padding: 4px 10px 24px;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: 0;
    border-right: 0;
    mask-image: none;
    -webkit-mask-image: none;
    z-index: 28;
  }
  .tab {
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    min-width: 0;
    border-radius: 10px;
    scroll-snap-align: none;
  }
  /* Desktop sidebar hover: full saturated tint fill, text flips to bg.
     Matches the topic-card / WotD / see-chip hover language. Wins over
     the aria-current resting state via source order + combined selector. */
  .tab:hover, .tab:focus-visible,
  .tab[aria-current="true"]:hover, .tab[aria-current="true"]:focus-visible {
    background: var(--tab-tint, var(--tint));
    color: var(--bg);
    outline: none;
  }
  /* Focus-only refinement: keyboard users get an inset bg-coloured ring
     inside the saturated fill so focus is distinct from hover. Layered
     after the combined selector above so the outline wins for :focus-visible. */
  .tab:focus-visible,
  .tab[aria-current="true"]:focus-visible {
    outline: 2px solid var(--bg);
    outline-offset: -4px;
  }
  /* Flip the dot so it remains visible against the saturated fill */
  .tab:hover .tab__dot,
  .tab:focus-visible .tab__dot {
    background: var(--bg);
    box-shadow: none;
  }
  .tab__dot { display: block; }

  /* Nested sub-list under "transitions" — surfaces the 7 sub-categories
     in the sidebar so the desktop user gets the same affordance the
     mobile dropup chips provide. Hidden by default (mobile uses the
     bubble); revealed only at the desktop breakpoint. A subtle left
     guide line + indent communicates the hierarchy. */
  .tab-subnav {
    display: flex;
    flex-direction: column;
    margin: 2px 0 6px 22px;
    padding-left: 10px;
    border-left: 0.5px solid var(--separator);
  }
  .tab-subnav__link {
    display: block;
    padding: 5px 10px;
    border-radius: 8px;
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--label-2);
    text-decoration: none;
    transition: color 0.15s var(--ease), background 0.15s var(--ease);
    -webkit-tap-highlight-color: transparent;
  }
  .tab-subnav__link:hover,
  .tab-subnav__link:focus-visible {
    color: var(--bg);
    background: var(--tint-transitions);
    outline: none;
  }
  .tab-subnav__link[aria-current="true"] {
    color: var(--tint-transitions);
    font-weight: 500;
  }
  .tab-subnav__link[aria-current="true"]:hover,
  .tab-subnav__link[aria-current="true"]:focus-visible {
    color: var(--bg);
  }
  .tab__en {
    font-size: 14px;
    line-height: 1.1;
  }
  .tab__zh {
    font-size: 11px;
    line-height: 1.1;
    margin-left: auto;
  }
  /* Active state: 2px coloured border (matches topic-card / WotD rest
     state) instead of the previous 14% bg tint, which read as barely
     visible. box-shadow inset draws the border without changing tab
     size, so toggling active/inactive doesn't reflow. Hover still wins
     and fills the tab fully (combined selector above). */
  .tab[aria-current="true"] {
    background: transparent;
    color: var(--label);
    box-shadow: inset 0 0 0 2px var(--tab-tint, var(--label-2));
  }
  .tab[aria-current="true"]::before { content: none; }

  /* Page content sits to the right of the sidebar */
  main.content {
    margin-left: var(--sidebar-w);
    max-width: 820px;
    padding-left: 40px;
    padding-right: 40px;
  }

  /* Wider topic grid */
  .topics__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* Drop the bubble chips on desktop — sidebar is the topic nav */
  .chips { display: none !important; }
}

@media (min-width: 1100px) {
  :root {
    --max-w: 780px;
    --sidebar-w: 280px;
  }
  main.content { max-width: 880px; padding-left: 56px; padding-right: 56px; }
}

/* Prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Print */
@media print {
  .topbar, .tabbar, .chips, .skip, .search { display: none !important; }
  body { background: white; padding: 0; }
  .content { max-width: none; padding: 24px; }
  .entry { break-inside: avoid; }
}
